Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/kubernetes_cluster: making the aci_connector_linux & http_application_routing blocks cloud specific #6370

Merged
merged 4 commits into from
Apr 7, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions azurerm/internal/services/containers/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
"github.com/Azure/azure-sdk-for-go/services/containerregistry/mgmt/2018-09-01/containerregistry"
"github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2020-02-01/containerservice"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/common"
)

Expand All @@ -15,6 +16,8 @@ type Client struct {
ReplicationsClient *containerregistry.ReplicationsClient
ServicesClient *containerservice.ContainerServicesClient
WebhooksClient *containerregistry.WebhooksClient

Environment azure.Environment
}

func NewClient(o *common.ClientOptions) *Client {
Expand Down Expand Up @@ -48,5 +51,6 @@ func NewClient(o *common.ClientOptions) *Client {
WebhooksClient: &webhooksClient,
ReplicationsClient: &replicationsClient,
ServicesClient: &servicesClient,
Environment: o.Environment,
}
}
73 changes: 60 additions & 13 deletions azurerm/internal/services/containers/kubernetes_addons.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
package containers

import (
"fmt"
"strings"

"github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2020-02-01/containerservice"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
azureHelpers "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

const (
// note: the casing on these keys is important
aciConnectorKey = "aciConnectorLinux"
azurePolicyKey = "azurepolicy"
kubernetesDashboardKey = "kubeDashboard"
httpApplicationRoutingKey = "httpApplicationRouting"
omsAgentKey = "omsagent"
)

func SchemaKubernetesAddOnProfiles() *schema.Schema {
// The AKS API hard-codes which add-ons are supported in which environment
// as such unfortunately we can't just send "disabled" - we need to strip
// the unsupported addons from the HTTP response. As such this defines
// the list of unsupported addons in the defined region - e.g. by being
// omited from this list an addon/environment combination will be supported
var unsupportedAddonsForEnvironment = map[string][]string{
azure.ChinaCloud.Name: {
aciConnectorKey, // https://github.com/terraform-providers/terraform-provider-azurerm/issues/5510
httpApplicationRoutingKey, // https://github.com/terraform-providers/terraform-provider-azurerm/issues/5960
},
azure.USGovernmentCloud.Name: {
httpApplicationRoutingKey, // https://github.com/terraform-providers/terraform-provider-azurerm/issues/5960
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went digging through the Docs & AKS Engine to try and find a definitive list of which add-ons - but ended up with this based on then open issues

@jluk do you know if there's a document stating which add-ons are supported in which cloud environments?

Copy link

@jluk jluk Apr 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately not today.

@feiskyer to confirm the 2 missing addons in Azure China/Gov.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

func schemaKubernetesAddOnProfiles() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
MaxItems: 1,
Expand Down Expand Up @@ -107,7 +125,7 @@ func SchemaKubernetesAddOnProfiles() *schema.Schema {
"log_analytics_workspace_id": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: azure.ValidateResourceID,
ValidateFunc: azureHelpers.ValidateResourceID,
},
},
},
Expand All @@ -117,21 +135,21 @@ func SchemaKubernetesAddOnProfiles() *schema.Schema {
}
}

func ExpandKubernetesAddOnProfiles(input []interface{}) map[string]*containerservice.ManagedClusterAddonProfile {
func expandKubernetesAddOnProfiles(input []interface{}, env azure.Environment) (*map[string]*containerservice.ManagedClusterAddonProfile, error) {
disabled := containerservice.ManagedClusterAddonProfile{
Enabled: utils.Bool(false),
}

profiles := map[string]*containerservice.ManagedClusterAddonProfile{
// note: the casing on these keys is important
aciConnectorKey: &disabled,
azurePolicyKey: &disabled,
kubernetesDashboardKey: &disabled,
httpApplicationRoutingKey: &disabled,
omsAgentKey: &disabled,
}

if len(input) == 0 {
return profiles
return filterUnsupportedKubernetesAddOns(profiles, env)
}

profile := input[0].(map[string]interface{})
Expand All @@ -141,7 +159,7 @@ func ExpandKubernetesAddOnProfiles(input []interface{}) map[string]*containerser
if len(httpApplicationRouting) > 0 && httpApplicationRouting[0] != nil {
value := httpApplicationRouting[0].(map[string]interface{})
enabled := value["enabled"].(bool)
addonProfiles["httpApplicationRouting"] = &containerservice.ManagedClusterAddonProfile{
addonProfiles[httpApplicationRoutingKey] = &containerservice.ManagedClusterAddonProfile{
Enabled: utils.Bool(enabled),
}
}
Expand All @@ -156,7 +174,7 @@ func ExpandKubernetesAddOnProfiles(input []interface{}) map[string]*containerser
config["logAnalyticsWorkspaceResourceID"] = utils.String(workspaceId.(string))
}

addonProfiles["omsagent"] = &containerservice.ManagedClusterAddonProfile{
addonProfiles[omsAgentKey] = &containerservice.ManagedClusterAddonProfile{
Enabled: utils.Bool(enabled),
Config: config,
}
Expand All @@ -172,7 +190,7 @@ func ExpandKubernetesAddOnProfiles(input []interface{}) map[string]*containerser
config["SubnetName"] = utils.String(subnetName.(string))
}

addonProfiles["aciConnectorLinux"] = &containerservice.ManagedClusterAddonProfile{
addonProfiles[aciConnectorKey] = &containerservice.ManagedClusterAddonProfile{
Enabled: utils.Bool(enabled),
Config: config,
}
Expand All @@ -183,7 +201,7 @@ func ExpandKubernetesAddOnProfiles(input []interface{}) map[string]*containerser
value := kubeDashboard[0].(map[string]interface{})
enabled := value["enabled"].(bool)

addonProfiles["kubeDashboard"] = &containerservice.ManagedClusterAddonProfile{
addonProfiles[kubernetesDashboardKey] = &containerservice.ManagedClusterAddonProfile{
Enabled: utils.Bool(enabled),
Config: nil,
}
Expand All @@ -194,16 +212,45 @@ func ExpandKubernetesAddOnProfiles(input []interface{}) map[string]*containerser
value := azurePolicy[0].(map[string]interface{})
enabled := value["enabled"].(bool)

addonProfiles["azurepolicy"] = &containerservice.ManagedClusterAddonProfile{
addonProfiles[azurePolicyKey] = &containerservice.ManagedClusterAddonProfile{
Enabled: utils.Bool(enabled),
Config: nil,
}
}

return addonProfiles
return filterUnsupportedKubernetesAddOns(addonProfiles, env)
}

func filterUnsupportedKubernetesAddOns(input map[string]*containerservice.ManagedClusterAddonProfile, env azure.Environment) (*map[string]*containerservice.ManagedClusterAddonProfile, error) {
var filter = func(input map[string]*containerservice.ManagedClusterAddonProfile, key string) (*map[string]*containerservice.ManagedClusterAddonProfile, error) {
output := input
if v, ok := output[key]; ok {
if v.Enabled != nil && *v.Enabled {
return nil, fmt.Errorf("The addon %q is not supported for a Kubernetes Cluster located in %q", key, env.Name)
}

// otherwise it's disabled by default, so just remove it
delete(output, key)
}

return &output, nil
}

output := input
if unsupportedAddons, ok := unsupportedAddonsForEnvironment[env.Name]; ok {
for _, key := range unsupportedAddons {
out, err := filter(output, key)
if err != nil {
return nil, err
}

output = *out
}
}
return &output, nil
}

func FlattenKubernetesAddOnProfiles(profile map[string]*containerservice.ManagedClusterAddonProfile) []interface{} {
func flattenKubernetesAddOnProfiles(profile map[string]*containerservice.ManagedClusterAddonProfile) []interface{} {
// when the Kubernetes Cluster is updated in the Portal - Azure updates the casing on the keys
// meaning what's submitted could be different to what's returned..
var locateInProfile = func(key string) *containerservice.ManagedClusterAddonProfile {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func resourceArmKubernetesCluster() *schema.Resource {
"default_node_pool": SchemaDefaultNodePool(),

// Optional
"addon_profile": SchemaKubernetesAddOnProfiles(),
"addon_profile": schemaKubernetesAddOnProfiles(),

"api_server_authorized_ip_ranges": {
Type: schema.TypeSet,
Expand Down Expand Up @@ -485,6 +485,7 @@ func resourceArmKubernetesCluster() *schema.Resource {

func resourceArmKubernetesClusterCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Containers.KubernetesClustersClient
env := meta.(*clients.Client).Containers.Environment
ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d)
defer cancel()
tenantId := meta.(*clients.Client).Account.TenantId
Expand Down Expand Up @@ -524,7 +525,10 @@ func resourceArmKubernetesClusterCreate(d *schema.ResourceData, meta interface{}
}

addOnProfilesRaw := d.Get("addon_profile").([]interface{})
addonProfiles := ExpandKubernetesAddOnProfiles(addOnProfilesRaw)
addonProfiles, err := expandKubernetesAddOnProfiles(addOnProfilesRaw, env)
if err != nil {
return err
}

networkProfileRaw := d.Get("network_profile").([]interface{})
networkProfile, err := expandKubernetesClusterNetworkProfile(networkProfileRaw)
Expand Down Expand Up @@ -560,7 +564,7 @@ func resourceArmKubernetesClusterCreate(d *schema.ResourceData, meta interface{}
ManagedClusterProperties: &containerservice.ManagedClusterProperties{
APIServerAccessProfile: &apiAccessProfile,
AadProfile: azureADProfile,
AddonProfiles: addonProfiles,
AddonProfiles: *addonProfiles,
AgentPoolProfiles: agentProfiles,
DNSPrefix: utils.String(dnsPrefix),
EnableRBAC: utils.Bool(rbacEnabled),
Expand Down Expand Up @@ -622,6 +626,7 @@ func resourceArmKubernetesClusterCreate(d *schema.ResourceData, meta interface{}
func resourceArmKubernetesClusterUpdate(d *schema.ResourceData, meta interface{}) error {
nodePoolsClient := meta.(*clients.Client).Containers.AgentPoolsClient
clusterClient := meta.(*clients.Client).Containers.KubernetesClustersClient
env := meta.(*clients.Client).Containers.Environment
ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()
tenantId := meta.(*clients.Client).Account.TenantId
Expand Down Expand Up @@ -715,8 +720,12 @@ func resourceArmKubernetesClusterUpdate(d *schema.ResourceData, meta interface{}
if d.HasChange("addon_profile") {
updateCluster = true
addOnProfilesRaw := d.Get("addon_profile").([]interface{})
addonProfiles := ExpandKubernetesAddOnProfiles(addOnProfilesRaw)
existing.ManagedClusterProperties.AddonProfiles = addonProfiles
addonProfiles, err := expandKubernetesAddOnProfiles(addOnProfilesRaw, env)
if err != nil {
return err
}

existing.ManagedClusterProperties.AddonProfiles = *addonProfiles
}

if d.HasChange("api_server_authorized_ip_ranges") {
Expand Down Expand Up @@ -887,7 +896,7 @@ func resourceArmKubernetesClusterRead(d *schema.ResourceData, meta interface{})
d.Set("private_link_enabled", accessProfile.EnablePrivateCluster)
}

addonProfiles := FlattenKubernetesAddOnProfiles(props.AddonProfiles)
addonProfiles := flattenKubernetesAddOnProfiles(props.AddonProfiles)
if err := d.Set("addon_profile", addonProfiles); err != nil {
return fmt.Errorf("setting `addon_profile`: %+v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion website/allowed-subcategories
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
API Management
Analysis Services
App Configuration
App Platform
App Service (Web Apps)
Application Insights
Authorization
Expand Down Expand Up @@ -52,6 +51,7 @@ Redis
Search
Security Center
Service Fabric
Spring Cloud
Storage
Stream Analytics
Template
4 changes: 4 additions & 0 deletions website/docs/r/kubernetes_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,16 @@ A `addon_profile` block supports the following:

* `aci_connector_linux` - (Optional) A `aci_connector_linux` block. For more details, please visit [Create and configure an AKS cluster to use virtual nodes](https://docs.microsoft.com/en-us/azure/aks/virtual-nodes-portal).

-> **NOTE:** At this time ACI Connector's are not supported in Azure China.

* `azure_policy` - (Optional) A `azure_policy` block as defined below. For more details please visit [Understand Azure Policy for Azure Kubernetes Service](https://docs.microsoft.com/en-ie/azure/governance/policy/concepts/rego-for-aks)

-> **NOTE**: Azure Policy for Azure Kubernetes Service is currently in preview and not available to subscriptions that have not [opted-in](https://docs.microsoft.com/en-us/azure/governance/policy/concepts/rego-for-aks?toc=/azure/aks/toc.json) to join `Azure Policy` preview.

* `http_application_routing` - (Optional) A `http_application_routing` block as defined below.

-> **NOTE:** At this time HTTP Application Routing is not supported in Azure China or Azure US Government.

* `kube_dashboard` - (Optional) A `kube_dashboard` block as defined below.

* `oms_agent` - (Optional) A `oms_agent` block as defined below. For more details, please visit [How to onboard Azure Monitor for containers](https://docs.microsoft.com/en-us/azure/monitoring/monitoring-container-insights-onboard).
Expand Down