From b7fed48b0b1ff1ccd08bb947c43603c60c676e6f Mon Sep 17 00:00:00 2001 From: "Kistner, Dominic" Date: Wed, 18 Mar 2020 11:41:40 +0100 Subject: [PATCH] =?UTF-8?q?NatGateway=20integration=20=E2=80=93=20step=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow users to bring their own public ip addresses and/or public ip ranges/prefixes which should be attached to the NatGateway. --- charts/internal/azure-infra/templates/main.tf | 21 +++++- charts/internal/azure-infra/values.yaml | 12 ++++ docs/usage-as-end-user.md | 2 +- hack/api-reference/api.md | 69 +++++++++++++++++++ pkg/apis/azure/types_infrastructure.go | 12 ++++ .../azure/v1alpha1/types_infrastructure.go | 14 ++++ .../azure/v1alpha1/zz_generated.conversion.go | 36 ++++++++++ .../azure/v1alpha1/zz_generated.deepcopy.go | 28 +++++++- pkg/apis/azure/validation/infrastructure.go | 25 +++++++ .../azure/validation/infrastructure_test.go | 43 ++++++++++++ pkg/apis/azure/zz_generated.deepcopy.go | 28 +++++++- pkg/internal/infrastructure/terraform.go | 37 ++++++++++ pkg/internal/infrastructure/terraform_test.go | 38 ++++++++++ 13 files changed, 361 insertions(+), 4 deletions(-) diff --git a/charts/internal/azure-infra/templates/main.tf b/charts/internal/azure-infra/templates/main.tf index 398a00cbc..2f6bfdecc 100644 --- a/charts/internal/azure-infra/templates/main.tf +++ b/charts/internal/azure-infra/templates/main.tf @@ -77,7 +77,20 @@ resource "azurerm_network_security_group" "workers" { #=============================================== #= NAT Gateway #=============================================== - +{{ if .Values.natGateway -}} +{{ range $index, $ip := .Values.natGateway.ipAddresses }} +data "azurerm_public_ip" "nat-ip-{{ $index }}" { + name = "{{ $ip.name }}" + resource_group_name = "{{ $ip.resourceGroup }}" +} +{{- end }} +{{ range $index, $ip := .Values.natGateway.ipAddressRanges }} +data "azurerm_public_ip_prefix" "nat-iprange-prefix-{{ $index }}" { + name = "{{ $ip.name }}" + resource_group_name = "{{ $ip.resourceGroup }}" +} +{{- end }} +{{ else -}} resource "azurerm_public_ip" "natip" { name = "{{ required "clusterName is required" .Values.clusterName }}-nat-ip" location = "{{ required "azure.region is required" .Values.azure.region }}" @@ -89,6 +102,7 @@ resource "azurerm_public_ip" "natip" { allocation_method = "Static" sku = "Standard" } +{{- end }} resource "azurerm_nat_gateway" "nat" { name = "{{ required "clusterName is required" .Values.clusterName }}-nat-gateway" @@ -99,7 +113,12 @@ resource "azurerm_nat_gateway" "nat" { resource_group_name = "${data.azurerm_resource_group.rg.name}" {{- end }} sku_name = "Standard" + {{ if .Values.natGateway -}} + public_ip_address_ids = [{{range $index, $ip := .Values.natGateway.ipAddresses}}{{if $index}},{{end}}"${data.azurerm_public_ip.nat-ip-{{ $index }}.id}"{{end}}] + public_ip_prefix_ids = [{{range $index, $ipRange := .Values.natGateway.ipAddressRanges}}{{if $index}},{{end}}"${data.azurerm_public_ip_prefix.nat-iprange-prefix-{{ $index }}.id}"{{end}}] + {{ else -}} public_ip_address_ids = ["${azurerm_public_ip.natip.id}"] + {{- end }} } resource "azurerm_subnet_nat_gateway_association" "nat-worker-subnet-association" { diff --git a/charts/internal/azure-infra/values.yaml b/charts/internal/azure-infra/values.yaml index 43e552153..37d29692f 100644 --- a/charts/internal/azure-infra/values.yaml +++ b/charts/internal/azure-infra/values.yaml @@ -15,6 +15,18 @@ create: # name: identity-name # resourceGroup: identity-resource-group +# natGateway: +# ipAddresses: +# - name: ip-name +# resourceGroup: ip-resource-group +# - name: ip-name +# resourceGroup: ip-resource-group +# ipAddressRanges: +# - name: ip-range-name +# resourceGroup: ip-range-resource-group +# - name: ip-range-name +# resourceGroup: ip-range-resource-group + resourceGroup: name: my-resource-group vnet: diff --git a/docs/usage-as-end-user.md b/docs/usage-as-end-user.md index 82ca06c27..5f10df09e 100644 --- a/docs/usage-as-end-user.md +++ b/docs/usage-as-end-user.md @@ -66,7 +66,7 @@ You can freely choose this CIDR and it is your responsibility to properly design In the `networks.serviceEndpoints[]` list you can specify the list of Azure service endpoints which shall be associated with the worker subnet. All available service endpoints and their technical names can be found in the (Azure Service Endpoint documentation](https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview). -The `networks.natGateway` section contains configuration for the Azure NatGateway which can be attached to the worker subnet of the Shoot cluster. The NatGateway is currently optional and can be enabled/disabled via the field `networks.natGateway.enabled`. If the NatGateway is not deployed then the outgoing traffic initiated within the Shoot cluster will be routed via cluster LoadBalancer (default behaviour, see [here](https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-outbound-connections#scenarios)). **Restrictions:** The NatGateway is currently only available for zoned clusters (`.zoned=true`, see [#43](https://github.com/gardener/gardener-extension-provider-azure/issues/43) for more details) and it will not be deployed zone-redundant yet. Furthermore, the Azure NatGateway is not yet generally available (GA) from Azure side, hence, you need to register your subscription to participate in the preview for NatGateway. +The `networks.natGateway` section contains configuration for the Azure NatGateway which can be attached to the worker subnet of the Shoot cluster. The NatGateway is currently optional and can be enabled/disabled via the field `networks.natGateway.enabled`. If the NatGateway is not deployed then the outgoing traffic initiated within the Shoot cluster will be routed via cluster LoadBalancer (default behaviour, see [here](https://docs.microsoft.com/en-us/azure/load-balancer/load-balancer-outbound-connections#scenarios)). Via `networks.natGateway.ipAddresses` and `networks.natGateway.ipAddressRanges` can own public ip addresses and/or public ip ranges/prefixes defined whose should be attached to the NatGateway. For each public ip addresses or public ip range/prefix need a `.name` (name of the Azure resource) and a `.resourceGroup` (resource group which contains the Azure resource) specified. **Restrictions:** The NatGateway is currently only available for zoned clusters (`.zoned=true`, see [#43](https://github.com/gardener/gardener-extension-provider-azure/issues/43) for more details) and it will not be deployed zone-redundant yet. Furthermore, the Azure NatGateway is not yet generally available (GA) from Azure side, hence, you need to register your subscription to participate in the preview for NatGateway. Via the `.zoned` boolean you can tell whether you want to use Azure availability zones or not. If you don't use zones then an availability set will be created and only basic load balancers will be used. diff --git a/hack/api-reference/api.md b/hack/api-reference/api.md index 5fca8d0bf..f337adb41 100644 --- a/hack/api-reference/api.md +++ b/hack/api-reference/api.md @@ -326,6 +326,47 @@ string +

AzureResourceReference +

+

+(Appears on: +NatGatewayConfig) +

+

+

AzureResourceReference contains information to identify a generic Azure resource.

+

+ + + + + + + + + + + + + + + + + +
FieldDescription
+name
+ +string + +
+

Name is the name of the referenced Azure resource.

+
+resourceGroup
+ +string + +
+

ResourceGroup is the resource group which contain the referenced Azure resource.

+

CloudControllerManagerConfig

@@ -774,6 +815,34 @@ bool

Enabled is an indicator if NAT gateway should be deployed.

+ + +ipAddresses
+ + +[]AzureResourceReference + + + + +(Optional) +

IPAddresses is a list of ip addresses which should be assigned to the NAT gateway.

+ + + + +ipAddressRanges
+ + +[]AzureResourceReference + + + + +(Optional) +

IPAddressRanges is a list of ip address ranges/prefixes which should be assigned to the NAT gateway.

+ +

NetworkConfig diff --git a/pkg/apis/azure/types_infrastructure.go b/pkg/apis/azure/types_infrastructure.go index 067d3c64e..8a8ce2bcf 100644 --- a/pkg/apis/azure/types_infrastructure.go +++ b/pkg/apis/azure/types_infrastructure.go @@ -33,6 +33,14 @@ type InfrastructureConfig struct { Zoned bool } +// AzureResourceReference contains information to identify a generic Azure resource. +type AzureResourceReference struct { + // Name is the name of the referenced Azure resource. + Name string + // ResourceGroup is the resource group which contain the referenced Azure resource. + ResourceGroup string +} + // ResourceGroup is azure resource group type ResourceGroup struct { // Name is the name of the resource group @@ -146,6 +154,10 @@ type VNetStatus struct { type NatGatewayConfig struct { // Enabled is an indicator if NAT gateway should be deployed. Enabled bool + // IPAddresses is a list of ip addresses which should be assigned to the NAT gateway. + IPAddresses []AzureResourceReference + // IPAddressRanges is a list of ip address ranges/prefixes which should be assigned to the NAT gateway. + IPAddressRanges []AzureResourceReference } // IdentityConfig contains configuration for the managed identity. diff --git a/pkg/apis/azure/v1alpha1/types_infrastructure.go b/pkg/apis/azure/v1alpha1/types_infrastructure.go index 4aae20dc3..07798b9b8 100644 --- a/pkg/apis/azure/v1alpha1/types_infrastructure.go +++ b/pkg/apis/azure/v1alpha1/types_infrastructure.go @@ -37,6 +37,14 @@ type InfrastructureConfig struct { Zoned bool `json:"zoned,omitempty"` } +// AzureResourceReference contains information to identify a generic Azure resource. +type AzureResourceReference struct { + // Name is the name of the referenced Azure resource. + Name string `json:"name"` + // ResourceGroup is the resource group which contain the referenced Azure resource. + ResourceGroup string `json:"resourceGroup"` +} + // ResourceGroup is azure resource group type ResourceGroup struct { // Name is the name of the resource group @@ -159,6 +167,12 @@ type VNetStatus struct { type NatGatewayConfig struct { // Enabled is an indicator if NAT gateway should be deployed. Enabled bool `json:"enabled"` + // IPAddresses is a list of ip addresses which should be assigned to the NAT gateway. + // +optional + IPAddresses []AzureResourceReference `json:"ipAddresses,omitempty"` + // IPAddressRanges is a list of ip address ranges/prefixes which should be assigned to the NAT gateway. + // +optional + IPAddressRanges []AzureResourceReference `json:"ipAddressRanges,omitempty"` } // IdentityConfig contains configuration for the managed identity. diff --git a/pkg/apis/azure/v1alpha1/zz_generated.conversion.go b/pkg/apis/azure/v1alpha1/zz_generated.conversion.go index 5525460a1..bcd70b22a 100644 --- a/pkg/apis/azure/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/azure/v1alpha1/zz_generated.conversion.go @@ -45,6 +45,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*AzureResourceReference)(nil), (*azure.AzureResourceReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_AzureResourceReference_To_azure_AzureResourceReference(a.(*AzureResourceReference), b.(*azure.AzureResourceReference), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*azure.AzureResourceReference)(nil), (*AzureResourceReference)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_azure_AzureResourceReference_To_v1alpha1_AzureResourceReference(a.(*azure.AzureResourceReference), b.(*AzureResourceReference), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*CloudControllerManagerConfig)(nil), (*azure.CloudControllerManagerConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_CloudControllerManagerConfig_To_azure_CloudControllerManagerConfig(a.(*CloudControllerManagerConfig), b.(*azure.CloudControllerManagerConfig), scope) }); err != nil { @@ -282,6 +292,28 @@ func Convert_azure_AvailabilitySet_To_v1alpha1_AvailabilitySet(in *azure.Availab return autoConvert_azure_AvailabilitySet_To_v1alpha1_AvailabilitySet(in, out, s) } +func autoConvert_v1alpha1_AzureResourceReference_To_azure_AzureResourceReference(in *AzureResourceReference, out *azure.AzureResourceReference, s conversion.Scope) error { + out.Name = in.Name + out.ResourceGroup = in.ResourceGroup + return nil +} + +// Convert_v1alpha1_AzureResourceReference_To_azure_AzureResourceReference is an autogenerated conversion function. +func Convert_v1alpha1_AzureResourceReference_To_azure_AzureResourceReference(in *AzureResourceReference, out *azure.AzureResourceReference, s conversion.Scope) error { + return autoConvert_v1alpha1_AzureResourceReference_To_azure_AzureResourceReference(in, out, s) +} + +func autoConvert_azure_AzureResourceReference_To_v1alpha1_AzureResourceReference(in *azure.AzureResourceReference, out *AzureResourceReference, s conversion.Scope) error { + out.Name = in.Name + out.ResourceGroup = in.ResourceGroup + return nil +} + +// Convert_azure_AzureResourceReference_To_v1alpha1_AzureResourceReference is an autogenerated conversion function. +func Convert_azure_AzureResourceReference_To_v1alpha1_AzureResourceReference(in *azure.AzureResourceReference, out *AzureResourceReference, s conversion.Scope) error { + return autoConvert_azure_AzureResourceReference_To_v1alpha1_AzureResourceReference(in, out, s) +} + func autoConvert_v1alpha1_CloudControllerManagerConfig_To_azure_CloudControllerManagerConfig(in *CloudControllerManagerConfig, out *azure.CloudControllerManagerConfig, s conversion.Scope) error { out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) return nil @@ -556,6 +588,8 @@ func Convert_azure_MachineImages_To_v1alpha1_MachineImages(in *azure.MachineImag func autoConvert_v1alpha1_NatGatewayConfig_To_azure_NatGatewayConfig(in *NatGatewayConfig, out *azure.NatGatewayConfig, s conversion.Scope) error { out.Enabled = in.Enabled + out.IPAddresses = *(*[]azure.AzureResourceReference)(unsafe.Pointer(&in.IPAddresses)) + out.IPAddressRanges = *(*[]azure.AzureResourceReference)(unsafe.Pointer(&in.IPAddressRanges)) return nil } @@ -566,6 +600,8 @@ func Convert_v1alpha1_NatGatewayConfig_To_azure_NatGatewayConfig(in *NatGatewayC func autoConvert_azure_NatGatewayConfig_To_v1alpha1_NatGatewayConfig(in *azure.NatGatewayConfig, out *NatGatewayConfig, s conversion.Scope) error { out.Enabled = in.Enabled + out.IPAddresses = *(*[]AzureResourceReference)(unsafe.Pointer(&in.IPAddresses)) + out.IPAddressRanges = *(*[]AzureResourceReference)(unsafe.Pointer(&in.IPAddressRanges)) return nil } diff --git a/pkg/apis/azure/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/azure/v1alpha1/zz_generated.deepcopy.go index a6a94b859..8beaa0068 100644 --- a/pkg/apis/azure/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/azure/v1alpha1/zz_generated.deepcopy.go @@ -40,6 +40,22 @@ func (in *AvailabilitySet) DeepCopy() *AvailabilitySet { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureResourceReference) DeepCopyInto(out *AzureResourceReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureResourceReference. +func (in *AzureResourceReference) DeepCopy() *AzureResourceReference { + if in == nil { + return nil + } + out := new(AzureResourceReference) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CloudControllerManagerConfig) DeepCopyInto(out *CloudControllerManagerConfig) { *out = *in @@ -332,6 +348,16 @@ func (in *MachineImages) DeepCopy() *MachineImages { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NatGatewayConfig) DeepCopyInto(out *NatGatewayConfig) { *out = *in + if in.IPAddresses != nil { + in, out := &in.IPAddresses, &out.IPAddresses + *out = make([]AzureResourceReference, len(*in)) + copy(*out, *in) + } + if in.IPAddressRanges != nil { + in, out := &in.IPAddressRanges, &out.IPAddressRanges + *out = make([]AzureResourceReference, len(*in)) + copy(*out, *in) + } return } @@ -352,7 +378,7 @@ func (in *NetworkConfig) DeepCopyInto(out *NetworkConfig) { if in.NatGateway != nil { in, out := &in.NatGateway, &out.NatGateway *out = new(NatGatewayConfig) - **out = **in + (*in).DeepCopyInto(*out) } if in.ServiceEndpoints != nil { in, out := &in.ServiceEndpoints, &out.ServiceEndpoints diff --git a/pkg/apis/azure/validation/infrastructure.go b/pkg/apis/azure/validation/infrastructure.go index 19bece2a7..533de934c 100644 --- a/pkg/apis/azure/validation/infrastructure.go +++ b/pkg/apis/azure/validation/infrastructure.go @@ -92,6 +92,20 @@ func ValidateInfrastructureConfig(infra *apisazure.InfrastructureConfig, nodesCI if !infra.Zoned && infra.Networks.NatGateway != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("networks", "natGateway"), infra.Networks.NatGateway, "NatGateway is currently only supported for zoned cluster")) } + if infra.Zoned && infra.Networks.NatGateway != nil { + if !infra.Networks.NatGateway.Enabled && (len(infra.Networks.NatGateway.IPAddresses) > 0 || len(infra.Networks.NatGateway.IPAddressRanges) > 0) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("networks", "natGateway"), infra.Networks.NatGateway, "NatGateway is not enabled but ip addresses or ip ranges are specified")) + } else { + ipAddressesField := fldPath.Child("networks", "natGateway", "ipAddresses") + for i, ip := range infra.Networks.NatGateway.IPAddresses { + allErrs = append(allErrs, validateAzureResourceReference(&ip, ipAddressesField.Index(i))...) + } + ipAddressRangesField := fldPath.Child("networks", "natGateway", "ipAddressRanges") + for i, ipRange := range infra.Networks.NatGateway.IPAddressRanges { + allErrs = append(allErrs, validateAzureResourceReference(&ipRange, ipAddressRangesField.Index(i))...) + } + } + } if infra.Identity != nil && (infra.Identity.Name == "" || infra.Identity.ResourceGroup == "") { allErrs = append(allErrs, field.Invalid(fldPath.Child("identity"), infra.Identity, "specifying an identity requires the name of the identity and the resource group which hosts the identity")) @@ -104,6 +118,17 @@ func ValidateInfrastructureConfig(infra *apisazure.InfrastructureConfig, nodesCI return allErrs } +func validateAzureResourceReference(ref *apisazure.AzureResourceReference, fieldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if ref.Name == "" { + allErrs = append(allErrs, field.Invalid(fieldPath, ref.Name, "name must be set")) + } + if ref.ResourceGroup == "" { + allErrs = append(allErrs, field.Invalid(fieldPath, ref.ResourceGroup, "resourceGroup must be set")) + } + return allErrs +} + // ValidateInfrastructureConfigUpdate validates a InfrastructureConfig object. func ValidateInfrastructureConfigUpdate(oldConfig, newConfig *apisazure.InfrastructureConfig, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} diff --git a/pkg/apis/azure/validation/infrastructure_test.go b/pkg/apis/azure/validation/infrastructure_test.go index cde8efab8..2dae7840d 100644 --- a/pkg/apis/azure/validation/infrastructure_test.go +++ b/pkg/apis/azure/validation/infrastructure_test.go @@ -289,6 +289,49 @@ var _ = Describe("InfrastructureConfig validation", func() { "Detail": Equal("NatGateway is currently only supported for zoned cluster"), })) }) + + It("should return an error using a NatGateway as it not enabled but ip addresses are configured", func() { + infrastructureConfig.Zoned = true + infrastructureConfig.Networks.NatGateway = &apisazure.NatGatewayConfig{ + Enabled: false, + IPAddresses: []apisazure.AzureResourceReference{{ + Name: "test-ip", + ResourceGroup: "test-rg", + }}, + } + errorList := ValidateInfrastructureConfig(infrastructureConfig, &nodes, &pods, &services, fldPath) + Expect(errorList).To(HaveLen(1)) + Expect(errorList).To(ConsistOfFields(Fields{ + "Type": Equal(field.ErrorTypeInvalid), + "Field": Equal("networks.natGateway"), + "Detail": Equal("NatGateway is not enabled but ip addresses or ip ranges are specified"), + })) + }) + + It("should return an error using a NatGateway as referenced ip is invalid", func() { + infrastructureConfig.Zoned = true + infrastructureConfig.Networks.NatGateway = &apisazure.NatGatewayConfig{ + Enabled: true, + IPAddresses: []apisazure.AzureResourceReference{{ + Name: "test-ip", + }}, + IPAddressRanges: []apisazure.AzureResourceReference{{ + ResourceGroup: "test-rg", + }}, + } + errorList := ValidateInfrastructureConfig(infrastructureConfig, &nodes, &pods, &services, fldPath) + Expect(errorList).To(HaveLen(2)) + Expect(errorList).To(ConsistOfFields(Fields{ + "Type": Equal(field.ErrorTypeInvalid), + "Field": Equal("networks.natGateway.ipAddresses[0]"), + "Detail": Equal("resourceGroup must be set"), + }, + Fields{ + "Type": Equal(field.ErrorTypeInvalid), + "Field": Equal("networks.natGateway.ipAddressRanges[0]"), + "Detail": Equal("name must be set"), + })) + }) }) }) diff --git a/pkg/apis/azure/zz_generated.deepcopy.go b/pkg/apis/azure/zz_generated.deepcopy.go index fd22039ad..2445e909c 100644 --- a/pkg/apis/azure/zz_generated.deepcopy.go +++ b/pkg/apis/azure/zz_generated.deepcopy.go @@ -40,6 +40,22 @@ func (in *AvailabilitySet) DeepCopy() *AvailabilitySet { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AzureResourceReference) DeepCopyInto(out *AzureResourceReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureResourceReference. +func (in *AzureResourceReference) DeepCopy() *AzureResourceReference { + if in == nil { + return nil + } + out := new(AzureResourceReference) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CloudControllerManagerConfig) DeepCopyInto(out *CloudControllerManagerConfig) { *out = *in @@ -332,6 +348,16 @@ func (in *MachineImages) DeepCopy() *MachineImages { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NatGatewayConfig) DeepCopyInto(out *NatGatewayConfig) { *out = *in + if in.IPAddresses != nil { + in, out := &in.IPAddresses, &out.IPAddresses + *out = make([]AzureResourceReference, len(*in)) + copy(*out, *in) + } + if in.IPAddressRanges != nil { + in, out := &in.IPAddressRanges, &out.IPAddressRanges + *out = make([]AzureResourceReference, len(*in)) + copy(*out, *in) + } return } @@ -352,7 +378,7 @@ func (in *NetworkConfig) DeepCopyInto(out *NetworkConfig) { if in.NatGateway != nil { in, out := &in.NatGateway, &out.NatGateway *out = new(NatGatewayConfig) - **out = **in + (*in).DeepCopyInto(*out) } if in.ServiceEndpoints != nil { in, out := &in.ServiceEndpoints, &out.ServiceEndpoints diff --git a/pkg/internal/infrastructure/terraform.go b/pkg/internal/infrastructure/terraform.go index 678ac048e..040d4f692 100644 --- a/pkg/internal/infrastructure/terraform.go +++ b/pkg/internal/infrastructure/terraform.go @@ -73,6 +73,7 @@ func ComputeTerraformerChartValues(infra *extensionsv1alpha1.Infrastructure, cli resourceGroupName = infra.Namespace identityConfig map[string]interface{} + natConfig map[string]interface{} azure = map[string]interface{}{ "subscriptionID": clientAuth.SubscriptionID, "tenantID": clientAuth.TenantID, @@ -136,6 +137,9 @@ func ComputeTerraformerChartValues(infra *extensionsv1alpha1.Infrastructure, cli if config.Networks.NatGateway != nil && config.Networks.NatGateway.Enabled { createNatGateway = true + if natValues := getNatGatewayValues(config.Networks.NatGateway); natValues != nil { + natConfig = *natValues + } } if config.Identity != nil && config.Identity.Name != "" && config.Identity.ResourceGroup != "" { @@ -162,6 +166,7 @@ func ComputeTerraformerChartValues(infra *extensionsv1alpha1.Infrastructure, cli "serviceEndpoints": config.Networks.ServiceEndpoints, }, }, + "natGateway": natConfig, "clusterName": infra.Namespace, "networks": map[string]interface{}{ "worker": config.Networks.Workers, @@ -171,6 +176,38 @@ func ComputeTerraformerChartValues(infra *extensionsv1alpha1.Infrastructure, cli }, nil } +func getNatGatewayValues(natConfig *api.NatGatewayConfig) *map[string]interface{} { + if natConfig == nil || !natConfig.Enabled { + return nil + } + if len(natConfig.IPAddresses) == 0 && len(natConfig.IPAddressRanges) == 0 { + return nil + } + var values = map[string]interface{}{} + if ipAddresses := resourceReferencesToValue(natConfig.IPAddresses); ipAddresses != nil { + values["ipAddresses"] = ipAddresses + } + if ipAddressRanges := resourceReferencesToValue(natConfig.IPAddressRanges); ipAddressRanges != nil { + values["ipAddressRanges"] = ipAddressRanges + } + return &values +} + +func resourceReferencesToValue(references []api.AzureResourceReference) []map[string]interface{} { + var count = len(references) + if count == 0 { + return nil + } + var result = make([]map[string]interface{}, count) + for _, ref := range references { + result = append(result, map[string]interface{}{ + "name": ref.Name, + "resourceGroup": ref.ResourceGroup, + }) + } + return result +} + // RenderTerraformerChart renders the azure-infra chart with the given values. func RenderTerraformerChart(renderer chartrenderer.Interface, infra *extensionsv1alpha1.Infrastructure, clientAuth *internal.ClientAuth, config *api.InfrastructureConfig, cluster *controller.Cluster) (*TerraformFiles, error) { diff --git a/pkg/internal/infrastructure/terraform_test.go b/pkg/internal/infrastructure/terraform_test.go index 025bd6654..73f5c5429 100644 --- a/pkg/internal/infrastructure/terraform_test.go +++ b/pkg/internal/infrastructure/terraform_test.go @@ -145,6 +145,7 @@ var _ = Describe("Terraform", func() { expectedCreateValues map[string]interface{} expectedOutputKeysValues map[string]interface{} expectedResourceGroupValues map[string]interface{} + expectedNatGatewayValues map[string]interface{} expectedIdentityValues map[string]interface{} ) @@ -187,6 +188,7 @@ var _ = Describe("Terraform", func() { "networks": map[string]interface{}{ "worker": config.Networks.Workers, }, + "natGateway": expectedNatGatewayValues, "outputKeys": expectedOutputKeysValues, } }) @@ -277,6 +279,42 @@ var _ = Describe("Terraform", func() { Expect(err).To(Not(HaveOccurred())) Expect(values).To(BeEquivalentTo(expectedValues)) }) + + It("should correctly compute terraform chart values with NatGateway with user assigned ip/ipranges", func() { + var ( + ipName = "test-ip-name" + ipResourceGroup = "test-ip-rg" + ipRangeName = "test-ip-range-name" + ipRangeResourceGroup = "test-ip-range-rg" + ) + config.Networks.NatGateway = &api.NatGatewayConfig{ + Enabled: true, + IPAddresses: []api.AzureResourceReference{{ + Name: ipName, + ResourceGroup: ipResourceGroup, + }}, + IPAddressRanges: []api.AzureResourceReference{{ + Name: ipRangeName, + ResourceGroup: ipRangeResourceGroup, + }}, + } + + expectedCreateValues["natGateway"] = true + natGatewayValues := map[string]interface{}{ + "ipAddresses": []map[string]interface{}{{ + "name": ipName, + "resourceGroup": ipResourceGroup, + }}, + "ipAddressRanges": []map[string]interface{}{{ + "name": ipRangeName, + "resourceGroup": ipRangeResourceGroup, + }}, + } + expectedValues["natGateway"] = natGatewayValues + values, err := ComputeTerraformerChartValues(infra, clientAuth, config, cluster) + Expect(err).To(Not(HaveOccurred())) + Expect(values).To(BeEquivalentTo(expectedValues)) + }) }) })