diff --git a/api/v1beta1/awscluster_conversion.go b/api/v1beta1/awscluster_conversion.go index ca199770ec..b6c835fa3e 100644 --- a/api/v1beta1/awscluster_conversion.go +++ b/api/v1beta1/awscluster_conversion.go @@ -48,6 +48,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error { if restored.Status.Bastion != nil { dst.Status.Bastion.InstanceMetadataOptions = restored.Status.Bastion.InstanceMetadataOptions dst.Status.Bastion.PlacementGroupName = restored.Status.Bastion.PlacementGroupName + dst.Status.Bastion.PrivateDNSName = restored.Status.Bastion.PrivateDNSName } dst.Spec.Partition = restored.Spec.Partition @@ -91,6 +92,7 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error { } dst.Spec.NetworkSpec.VPC.EmptyRoutesDefaultVPCSecurityGroup = restored.Spec.NetworkSpec.VPC.EmptyRoutesDefaultVPCSecurityGroup + dst.Spec.NetworkSpec.VPC.PrivateDNSHostnameTypeOnLaunch = restored.Spec.NetworkSpec.VPC.PrivateDNSHostnameTypeOnLaunch // Restore SubnetSpec.ResourceID field, if any. for _, subnet := range restored.Spec.NetworkSpec.Subnets { diff --git a/api/v1beta1/awsmachine_conversion.go b/api/v1beta1/awsmachine_conversion.go index 503f6d37a5..92a22d5a59 100644 --- a/api/v1beta1/awsmachine_conversion.go +++ b/api/v1beta1/awsmachine_conversion.go @@ -38,6 +38,7 @@ func (src *AWSMachine) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.Ignition = restored.Spec.Ignition dst.Spec.InstanceMetadataOptions = restored.Spec.InstanceMetadataOptions dst.Spec.PlacementGroupName = restored.Spec.PlacementGroupName + dst.Spec.PrivateDNSName = restored.Spec.PrivateDNSName return nil } @@ -85,6 +86,7 @@ func (r *AWSMachineTemplate) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.Template.Spec.Ignition = restored.Spec.Template.Spec.Ignition dst.Spec.Template.Spec.InstanceMetadataOptions = restored.Spec.Template.Spec.InstanceMetadataOptions dst.Spec.Template.Spec.PlacementGroupName = restored.Spec.Template.Spec.PlacementGroupName + dst.Spec.Template.Spec.PrivateDNSName = restored.Spec.Template.Spec.PrivateDNSName return nil } diff --git a/api/v1beta1/zz_generated.conversion.go b/api/v1beta1/zz_generated.conversion.go index 347e67fd35..030941fb4f 100644 --- a/api/v1beta1/zz_generated.conversion.go +++ b/api/v1beta1/zz_generated.conversion.go @@ -1411,6 +1411,7 @@ func autoConvert_v1beta2_AWSMachineSpec_To_v1beta1_AWSMachineSpec(in *v1beta2.AW out.SpotMarketOptions = (*SpotMarketOptions)(unsafe.Pointer(in.SpotMarketOptions)) // WARNING: in.PlacementGroupName requires manual conversion: does not exist in peer-type out.Tenancy = in.Tenancy + // WARNING: in.PrivateDNSName requires manual conversion: does not exist in peer-type return nil } @@ -2010,6 +2011,7 @@ func autoConvert_v1beta2_Instance_To_v1beta1_Instance(in *v1beta2.Instance, out out.Tenancy = in.Tenancy out.VolumeIDs = *(*[]string)(unsafe.Pointer(&in.VolumeIDs)) // WARNING: in.InstanceMetadataOptions requires manual conversion: does not exist in peer-type + // WARNING: in.PrivateDNSName requires manual conversion: does not exist in peer-type return nil } @@ -2285,6 +2287,7 @@ func autoConvert_v1beta2_VPCSpec_To_v1beta1_VPCSpec(in *v1beta2.VPCSpec, out *VP out.AvailabilityZoneUsageLimit = (*int)(unsafe.Pointer(in.AvailabilityZoneUsageLimit)) out.AvailabilityZoneSelection = (*AZSelectionScheme)(unsafe.Pointer(in.AvailabilityZoneSelection)) // WARNING: in.EmptyRoutesDefaultVPCSecurityGroup requires manual conversion: does not exist in peer-type + // WARNING: in.PrivateDNSHostnameTypeOnLaunch requires manual conversion: does not exist in peer-type return nil } diff --git a/api/v1beta2/awsmachine_types.go b/api/v1beta2/awsmachine_types.go index 83fed36893..1929c79e4d 100644 --- a/api/v1beta2/awsmachine_types.go +++ b/api/v1beta2/awsmachine_types.go @@ -160,6 +160,10 @@ type AWSMachineSpec struct { // +optional // +kubebuilder:validation:Enum:=default;dedicated;host Tenancy string `json:"tenancy,omitempty"` + + // PrivateDNSName is the options for the instance hostname. + // +optional + PrivateDNSName *PrivateDNSName `json:"privateDnsName,omitempty"` } // CloudInit defines options related to the bootstrapping systems where diff --git a/api/v1beta2/awsmachine_webhook.go b/api/v1beta2/awsmachine_webhook.go index cbf728fda4..2fe32083db 100644 --- a/api/v1beta2/awsmachine_webhook.go +++ b/api/v1beta2/awsmachine_webhook.go @@ -114,6 +114,17 @@ func (r *AWSMachine) ValidateUpdate(old runtime.Object) (admission.Warnings, err delete(cloudInit, "secureSecretsBackend") } + // allow changes to enableResourceNameDNSAAAARecord and enableResourceNameDNSARecord + if privateDNSName, ok := oldAWSMachineSpec["privateDnsName"].(map[string]interface{}); ok { + delete(privateDNSName, "enableResourceNameDnsAAAARecord") + delete(privateDNSName, "enableResourceNameDnsARecord") + } + + if privateDNSName, ok := newAWSMachineSpec["privateDnsName"].(map[string]interface{}); ok { + delete(privateDNSName, "enableResourceNameDnsAAAARecord") + delete(privateDNSName, "enableResourceNameDnsARecord") + } + if !cmp.Equal(oldAWSMachineSpec, newAWSMachineSpec) { allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "cannot be modified")) } diff --git a/api/v1beta2/awsmachine_webhook_test.go b/api/v1beta2/awsmachine_webhook_test.go index df8f876627..a2b6ecd607 100644 --- a/api/v1beta2/awsmachine_webhook_test.go +++ b/api/v1beta2/awsmachine_webhook_test.go @@ -273,7 +273,7 @@ func TestAWSMachineUpdate(t *testing.T) { wantErr bool }{ { - name: "change in providerid, cloudinit, tags and securitygroups", + name: "change in providerid, cloudinit, tags, securitygroups", oldMachine: &AWSMachine{ Spec: AWSMachineSpec{ ProviderID: nil, @@ -325,6 +325,10 @@ func TestAWSMachineUpdate(t *testing.T) { ID: ptr.To[string]("ID"), }, }, + PrivateDNSName: &PrivateDNSName{ + EnableResourceNameDNSAAAARecord: aws.Bool(true), + EnableResourceNameDNSARecord: aws.Bool(true), + }, }, }, wantErr: true, diff --git a/api/v1beta2/network_types.go b/api/v1beta2/network_types.go index 8b4ba3ac4e..7d70f411ce 100644 --- a/api/v1beta2/network_types.go +++ b/api/v1beta2/network_types.go @@ -335,6 +335,13 @@ type VPCSpec struct { // // +optional EmptyRoutesDefaultVPCSecurityGroup bool `json:"emptyRoutesDefaultVPCSecurityGroup,omitempty"` + + // PrivateDNSHostnameTypeOnLaunch is the type of hostname to assign to instances in the subnet at launch. + // For IPv4-only and dual-stack (IPv4 and IPv6) subnets, an instance DNS name can be based on the instance IPv4 address (ip-name) + // or the instance ID (resource-name). For IPv6 only subnets, an instance DNS name must be based on the instance ID (resource-name). + // +optional + // +kubebuilder:validation:Enum:=ip-name;resource-name + PrivateDNSHostnameTypeOnLaunch *string `json:"privateDnsHostnameTypeOnLaunch,omitempty"` } // String returns a string representation of the VPC. diff --git a/api/v1beta2/types.go b/api/v1beta2/types.go index 9e77923bbd..545c4f320c 100644 --- a/api/v1beta2/types.go +++ b/api/v1beta2/types.go @@ -232,6 +232,10 @@ type Instance struct { // InstanceMetadataOptions is the metadata options for the EC2 instance. // +optional InstanceMetadataOptions *InstanceMetadataOptions `json:"instanceMetadataOptions,omitempty"` + + // PrivateDNSName is the options for the instance hostname. + // +optional + PrivateDNSName *PrivateDNSName `json:"privateDnsName,omitempty"` } // InstanceMetadataState describes the state of InstanceMetadataOptions.HttpEndpoint and InstanceMetadataOptions.InstanceMetadataTags @@ -407,3 +411,17 @@ const ( // AmazonLinuxGPU is the AmazonLinux GPU AMI type. AmazonLinuxGPU EKSAMILookupType = "AmazonLinuxGPU" ) + +// PrivateDNSName is the options for the instance hostname. +type PrivateDNSName struct { + // EnableResourceNameDNSAAAARecord indicates whether to respond to DNS queries for instance hostnames with DNS AAAA records. + // +optional + EnableResourceNameDNSAAAARecord *bool `json:"enableResourceNameDnsAAAARecord,omitempty"` + // EnableResourceNameDNSARecord indicates whether to respond to DNS queries for instance hostnames with DNS A records. + // +optional + EnableResourceNameDNSARecord *bool `json:"enableResourceNameDnsARecord,omitempty"` + // The type of hostname to assign to an instance. + // +optional + // +kubebuilder:validation:Enum:=ip-name;resource-name + HostnameType *string `json:"hostnameType,omitempty"` +} diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index cd5ba0a0f9..60ce90eeb7 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -738,6 +738,11 @@ func (in *AWSMachineSpec) DeepCopyInto(out *AWSMachineSpec) { *out = new(SpotMarketOptions) (*in).DeepCopyInto(*out) } + if in.PrivateDNSName != nil { + in, out := &in.PrivateDNSName, &out.PrivateDNSName + *out = new(PrivateDNSName) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSMachineSpec. @@ -1465,6 +1470,11 @@ func (in *Instance) DeepCopyInto(out *Instance) { *out = new(InstanceMetadataOptions) **out = **in } + if in.PrivateDNSName != nil { + in, out := &in.PrivateDNSName, &out.PrivateDNSName + *out = new(PrivateDNSName) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Instance. @@ -1649,6 +1659,36 @@ func (in *NetworkStatus) DeepCopy() *NetworkStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PrivateDNSName) DeepCopyInto(out *PrivateDNSName) { + *out = *in + if in.EnableResourceNameDNSAAAARecord != nil { + in, out := &in.EnableResourceNameDNSAAAARecord, &out.EnableResourceNameDNSAAAARecord + *out = new(bool) + **out = **in + } + if in.EnableResourceNameDNSARecord != nil { + in, out := &in.EnableResourceNameDNSARecord, &out.EnableResourceNameDNSARecord + *out = new(bool) + **out = **in + } + if in.HostnameType != nil { + in, out := &in.HostnameType, &out.HostnameType + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PrivateDNSName. +func (in *PrivateDNSName) DeepCopy() *PrivateDNSName { + if in == nil { + return nil + } + out := new(PrivateDNSName) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RouteTable) DeepCopyInto(out *RouteTable) { *out = *in @@ -1912,6 +1952,11 @@ func (in *VPCSpec) DeepCopyInto(out *VPCSpec) { *out = new(AZSelectionScheme) **out = **in } + if in.PrivateDNSHostnameTypeOnLaunch != nil { + in, out := &in.PrivateDNSHostnameTypeOnLaunch, &out.PrivateDNSHostnameTypeOnLaunch + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VPCSpec. diff --git a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml index 8c9cdd638a..f5990b28fa 100644 --- a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml +++ b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml @@ -647,6 +647,18 @@ spec: is set. Mutually exclusive with IPAMPool. type: string type: object + privateDnsHostnameTypeOnLaunch: + description: PrivateDNSHostnameTypeOnLaunch is the type of + hostname to assign to instances in the subnet at launch. + For IPv4-only and dual-stack (IPv4 and IPv6) subnets, an + instance DNS name can be based on the instance IPv4 address + (ip-name) or the instance ID (resource-name). For IPv6 only + subnets, an instance DNS name must be based on the instance + ID (resource-name). + enum: + - ip-name + - resource-name + type: string tags: additionalProperties: type: string @@ -1096,6 +1108,26 @@ spec: description: PlacementGroupName specifies the name of the placement group in which to launch the instance. type: string + privateDnsName: + description: PrivateDNSName is the options for the instance hostname. + properties: + enableResourceNameDnsAAAARecord: + description: EnableResourceNameDNSAAAARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + AAAA records. + type: boolean + enableResourceNameDnsARecord: + description: EnableResourceNameDNSARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + A records. + type: boolean + hostnameType: + description: The type of hostname to assign to an instance. + enum: + - ip-name + - resource-name + type: string + type: object privateIp: description: The private IPv4 address assigned to the instance. type: string @@ -2244,6 +2276,18 @@ spec: is set. Mutually exclusive with IPAMPool. type: string type: object + privateDnsHostnameTypeOnLaunch: + description: PrivateDNSHostnameTypeOnLaunch is the type of + hostname to assign to instances in the subnet at launch. + For IPv4-only and dual-stack (IPv4 and IPv6) subnets, an + instance DNS name can be based on the instance IPv4 address + (ip-name) or the instance ID (resource-name). For IPv6 only + subnets, an instance DNS name must be based on the instance + ID (resource-name). + enum: + - ip-name + - resource-name + type: string tags: additionalProperties: type: string @@ -2706,6 +2750,26 @@ spec: description: PlacementGroupName specifies the name of the placement group in which to launch the instance. type: string + privateDnsName: + description: PrivateDNSName is the options for the instance hostname. + properties: + enableResourceNameDnsAAAARecord: + description: EnableResourceNameDNSAAAARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + AAAA records. + type: boolean + enableResourceNameDnsARecord: + description: EnableResourceNameDNSARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + A records. + type: boolean + hostnameType: + description: The type of hostname to assign to an instance. + enum: + - ip-name + - resource-name + type: string + type: object privateIp: description: The private IPv4 address assigned to the instance. type: string diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml index b30f43b245..a534305d72 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml @@ -1479,6 +1479,18 @@ spec: is set. Mutually exclusive with IPAMPool. type: string type: object + privateDnsHostnameTypeOnLaunch: + description: PrivateDNSHostnameTypeOnLaunch is the type of + hostname to assign to instances in the subnet at launch. + For IPv4-only and dual-stack (IPv4 and IPv6) subnets, an + instance DNS name can be based on the instance IPv4 address + (ip-name) or the instance ID (resource-name). For IPv6 only + subnets, an instance DNS name must be based on the instance + ID (resource-name). + enum: + - ip-name + - resource-name + type: string tags: additionalProperties: type: string @@ -1687,6 +1699,26 @@ spec: description: PlacementGroupName specifies the name of the placement group in which to launch the instance. type: string + privateDnsName: + description: PrivateDNSName is the options for the instance hostname. + properties: + enableResourceNameDnsAAAARecord: + description: EnableResourceNameDNSAAAARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + AAAA records. + type: boolean + enableResourceNameDnsARecord: + description: EnableResourceNameDNSARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + A records. + type: boolean + hostnameType: + description: The type of hostname to assign to an instance. + enum: + - ip-name + - resource-name + type: string + type: object privateIp: description: The private IPv4 address assigned to the instance. type: string diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclustertemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclustertemplates.yaml index a8dbe5cbb1..230bfe115a 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclustertemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclustertemplates.yaml @@ -1098,6 +1098,18 @@ spec: with IPAMPool. type: string type: object + privateDnsHostnameTypeOnLaunch: + description: PrivateDNSHostnameTypeOnLaunch is the + type of hostname to assign to instances in the subnet + at launch. For IPv4-only and dual-stack (IPv4 and + IPv6) subnets, an instance DNS name can be based + on the instance IPv4 address (ip-name) or the instance + ID (resource-name). For IPv6 only subnets, an instance + DNS name must be based on the instance ID (resource-name). + enum: + - ip-name + - resource-name + type: string tags: additionalProperties: type: string diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml index 3e62b70042..fea965aea4 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinepools.yaml @@ -690,6 +690,26 @@ spec: name: description: The name of the launch template. type: string + privateDnsName: + description: PrivateDNSName is the options for the instance hostname. + properties: + enableResourceNameDnsAAAARecord: + description: EnableResourceNameDNSAAAARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + AAAA records. + type: boolean + enableResourceNameDnsARecord: + description: EnableResourceNameDNSARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + A records. + type: boolean + hostnameType: + description: The type of hostname to assign to an instance. + enum: + - ip-name + - resource-name + type: string + type: object rootVolume: description: RootVolume encapsulates the configuration options for the root volume diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml index 10665df729..fca3f66245 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachines.yaml @@ -780,6 +780,25 @@ spec: description: PlacementGroupName specifies the name of the placement group in which to launch the instance. type: string + privateDnsName: + description: PrivateDNSName is the options for the instance hostname. + properties: + enableResourceNameDnsAAAARecord: + description: EnableResourceNameDNSAAAARecord indicates whether + to respond to DNS queries for instance hostnames with DNS AAAA + records. + type: boolean + enableResourceNameDnsARecord: + description: EnableResourceNameDNSARecord indicates whether to + respond to DNS queries for instance hostnames with DNS A records. + type: boolean + hostnameType: + description: The type of hostname to assign to an instance. + enum: + - ip-name + - resource-name + type: string + type: object providerID: description: ProviderID is the unique identifier as specified by the cloud provider. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml index aaaf3b378b..ebdee36d0b 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmachinetemplates.yaml @@ -734,6 +734,27 @@ spec: description: PlacementGroupName specifies the name of the placement group in which to launch the instance. type: string + privateDnsName: + description: PrivateDNSName is the options for the instance + hostname. + properties: + enableResourceNameDnsAAAARecord: + description: EnableResourceNameDNSAAAARecord indicates + whether to respond to DNS queries for instance hostnames + with DNS AAAA records. + type: boolean + enableResourceNameDnsARecord: + description: EnableResourceNameDNSARecord indicates whether + to respond to DNS queries for instance hostnames with + DNS A records. + type: boolean + hostnameType: + description: The type of hostname to assign to an instance. + enum: + - ip-name + - resource-name + type: string + type: object providerID: description: ProviderID is the unique identifier as specified by the cloud provider. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmanagedmachinepools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmanagedmachinepools.yaml index 628e15af71..a23aa9dabf 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmanagedmachinepools.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsmanagedmachinepools.yaml @@ -678,6 +678,26 @@ spec: name: description: The name of the launch template. type: string + privateDnsName: + description: PrivateDNSName is the options for the instance hostname. + properties: + enableResourceNameDnsAAAARecord: + description: EnableResourceNameDNSAAAARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + AAAA records. + type: boolean + enableResourceNameDnsARecord: + description: EnableResourceNameDNSARecord indicates whether + to respond to DNS queries for instance hostnames with DNS + A records. + type: boolean + hostnameType: + description: The type of hostname to assign to an instance. + enum: + - ip-name + - resource-name + type: string + type: object rootVolume: description: RootVolume encapsulates the configuration options for the root volume diff --git a/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_webhook.go b/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_webhook.go index 97baa68716..4b44508b65 100644 --- a/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_webhook.go +++ b/controlplane/eks/api/v1beta2/awsmanagedcontrolplane_webhook.go @@ -36,10 +36,11 @@ import ( ) const ( - minAddonVersion = "v1.18.0" - minKubeVersionForIPv6 = "v1.21.0" - minVpcCniVersionForIPv6 = "1.10.2" - maxClusterNameLength = 100 + minAddonVersion = "v1.18.0" + minKubeVersionForIPv6 = "v1.21.0" + minVpcCniVersionForIPv6 = "1.10.2" + maxClusterNameLength = 100 + hostnameTypeResourceName = "resource-name" ) // log is for logging in this package. @@ -93,6 +94,7 @@ func (r *AWSManagedControlPlane) ValidateCreate() (admission.Warnings, error) { allErrs = append(allErrs, r.validateKubeProxy()...) allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...) allErrs = append(allErrs, r.validateNetwork()...) + allErrs = append(allErrs, r.validatePrivateDNSHostnameTypeOnLaunch()...) if len(allErrs) == 0 { return nil, nil @@ -126,6 +128,7 @@ func (r *AWSManagedControlPlane) ValidateUpdate(old runtime.Object) (admission.W allErrs = append(allErrs, r.validateDisableVPCCNI()...) allErrs = append(allErrs, r.validateKubeProxy()...) allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...) + allErrs = append(allErrs, r.validatePrivateDNSHostnameTypeOnLaunch()...) if r.Spec.Region != oldAWSManagedControlplane.Spec.Region { allErrs = append(allErrs, @@ -389,6 +392,17 @@ func (r *AWSManagedControlPlane) validateDisableVPCCNI() field.ErrorList { return allErrs } +func (r *AWSManagedControlPlane) validatePrivateDNSHostnameTypeOnLaunch() field.ErrorList { + var allErrs field.ErrorList + + if r.Spec.NetworkSpec.VPC.IsIPv6Enabled() && r.Spec.NetworkSpec.VPC.PrivateDNSHostnameTypeOnLaunch != nil && *r.Spec.NetworkSpec.VPC.PrivateDNSHostnameTypeOnLaunch != hostnameTypeResourceName { + privateDNSHostnameTypeOnLaunch := field.NewPath("spec", "networkSpec", "vpc", "privateDNSHostnameTypeOnLaunch") + allErrs = append(allErrs, field.Invalid(privateDNSHostnameTypeOnLaunch, r.Spec.NetworkSpec.VPC.PrivateDNSHostnameTypeOnLaunch, fmt.Sprintf("only %s HostnameType can be used in IPv6 mode", hostnameTypeResourceName))) + } + + return allErrs +} + func (r *AWSManagedControlPlane) validateNetwork() field.ErrorList { var allErrs field.ErrorList diff --git a/exp/api/v1beta1/conversion.go b/exp/api/v1beta1/conversion.go index db54099fd3..91c852c1a2 100644 --- a/exp/api/v1beta1/conversion.go +++ b/exp/api/v1beta1/conversion.go @@ -51,6 +51,10 @@ func (src *AWSMachinePool) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.AvailabilityZoneSubnetType = restored.Spec.AvailabilityZoneSubnetType } + if restored.Spec.AWSLaunchTemplate.PrivateDNSName != nil { + dst.Spec.AWSLaunchTemplate.PrivateDNSName = restored.Spec.AWSLaunchTemplate.PrivateDNSName + } + return nil } @@ -95,6 +99,10 @@ func (src *AWSManagedMachinePool) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.AWSLaunchTemplate = restored.Spec.AWSLaunchTemplate } dst.Spec.AWSLaunchTemplate.InstanceMetadataOptions = restored.Spec.AWSLaunchTemplate.InstanceMetadataOptions + + if restored.Spec.AWSLaunchTemplate.PrivateDNSName != nil { + dst.Spec.AWSLaunchTemplate.PrivateDNSName = restored.Spec.AWSLaunchTemplate.PrivateDNSName + } } if restored.Spec.AvailabilityZoneSubnetType != nil { dst.Spec.AvailabilityZoneSubnetType = restored.Spec.AvailabilityZoneSubnetType diff --git a/exp/api/v1beta1/zz_generated.conversion.go b/exp/api/v1beta1/zz_generated.conversion.go index fe8b85def4..bc26142ba4 100644 --- a/exp/api/v1beta1/zz_generated.conversion.go +++ b/exp/api/v1beta1/zz_generated.conversion.go @@ -407,6 +407,7 @@ func autoConvert_v1beta2_AWSLaunchTemplate_To_v1beta1_AWSLaunchTemplate(in *v1be out.AdditionalSecurityGroups = *(*[]apiv1beta2.AWSResourceReference)(unsafe.Pointer(&in.AdditionalSecurityGroups)) out.SpotMarketOptions = (*apiv1beta2.SpotMarketOptions)(unsafe.Pointer(in.SpotMarketOptions)) // WARNING: in.InstanceMetadataOptions requires manual conversion: does not exist in peer-type + // WARNING: in.PrivateDNSName requires manual conversion: does not exist in peer-type return nil } diff --git a/exp/api/v1beta2/types.go b/exp/api/v1beta2/types.go index 04c824a419..68e6b24876 100644 --- a/exp/api/v1beta2/types.go +++ b/exp/api/v1beta2/types.go @@ -120,6 +120,10 @@ type AWSLaunchTemplate struct { // InstanceMetadataOptions defines the behavior for applying metadata to instances. // +optional InstanceMetadataOptions *infrav1.InstanceMetadataOptions `json:"instanceMetadataOptions,omitempty"` + + // PrivateDNSName is the options for the instance hostname. + // +optional + PrivateDNSName *infrav1.PrivateDNSName `json:"privateDnsName,omitempty"` } // Overrides are used to override the instance type specified by the launch template with multiple diff --git a/exp/api/v1beta2/zz_generated.deepcopy.go b/exp/api/v1beta2/zz_generated.deepcopy.go index 50c098b1e9..7c0b0defa0 100644 --- a/exp/api/v1beta2/zz_generated.deepcopy.go +++ b/exp/api/v1beta2/zz_generated.deepcopy.go @@ -122,6 +122,11 @@ func (in *AWSLaunchTemplate) DeepCopyInto(out *AWSLaunchTemplate) { *out = new(apiv1beta2.InstanceMetadataOptions) **out = **in } + if in.PrivateDNSName != nil { + in, out := &in.PrivateDNSName, &out.PrivateDNSName + *out = new(apiv1beta2.PrivateDNSName) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSLaunchTemplate. diff --git a/pkg/cloud/services/ec2/instances.go b/pkg/cloud/services/ec2/instances.go index 6164580009..9392736f99 100644 --- a/pkg/cloud/services/ec2/instances.go +++ b/pkg/cloud/services/ec2/instances.go @@ -238,6 +238,8 @@ func (s *Service) CreateInstance(scope *scope.MachineScope, userData []byte, use input.PlacementGroupName = scope.AWSMachine.Spec.PlacementGroupName + input.PrivateDNSName = scope.AWSMachine.Spec.PrivateDNSName + s.scope.Debug("Running instance", "machine-role", scope.Role()) s.scope.Debug("Running instance with instance metadata options", "metadata options", input.InstanceMetadataOptions) out, err := s.runInstance(scope.Role(), input) @@ -595,6 +597,7 @@ func (s *Service) runInstance(role string, i *infrav1.Instance) (*infrav1.Instan input.InstanceMarketOptions = getInstanceMarketOptionsRequest(i.SpotMarketOptions) input.MetadataOptions = getInstanceMetadataOptionsRequest(i.InstanceMetadataOptions) + input.PrivateDnsNameOptions = getPrivateDNSNameOptionsRequest(i.PrivateDNSName) if i.Tenancy != "" { input.Placement = &ec2.Placement{ @@ -865,6 +868,14 @@ func (s *Service) SDKToInstance(v *ec2.Instance) (*infrav1.Instance, error) { i.InstanceMetadataOptions = metadataOptions } + if v.PrivateDnsNameOptions != nil { + i.PrivateDNSName = &infrav1.PrivateDNSName{ + EnableResourceNameDNSAAAARecord: v.PrivateDnsNameOptions.EnableResourceNameDnsAAAARecord, + EnableResourceNameDNSARecord: v.PrivateDnsNameOptions.EnableResourceNameDnsARecord, + HostnameType: v.PrivateDnsNameOptions.HostnameType, + } + } + return i, nil } @@ -1053,3 +1064,15 @@ func getInstanceMetadataOptionsRequest(metadataOptions *infrav1.InstanceMetadata return request } + +func getPrivateDNSNameOptionsRequest(privateDNSName *infrav1.PrivateDNSName) *ec2.PrivateDnsNameOptionsRequest { + if privateDNSName == nil { + return nil + } + + return &ec2.PrivateDnsNameOptionsRequest{ + EnableResourceNameDnsAAAARecord: privateDNSName.EnableResourceNameDNSAAAARecord, + EnableResourceNameDnsARecord: privateDNSName.EnableResourceNameDNSARecord, + HostnameType: privateDNSName.HostnameType, + } +} diff --git a/pkg/cloud/services/ec2/launchtemplate.go b/pkg/cloud/services/ec2/launchtemplate.go index 0708fadf43..2a134c0f75 100644 --- a/pkg/cloud/services/ec2/launchtemplate.go +++ b/pkg/cloud/services/ec2/launchtemplate.go @@ -498,6 +498,7 @@ func (s *Service) createLaunchTemplateData(scope scope.LaunchTemplateScope, imag data.ImageId = imageID data.InstanceMarketOptions = getLaunchTemplateInstanceMarketOptionsRequest(scope.GetLaunchTemplate().SpotMarketOptions) + data.PrivateDnsNameOptions = getLaunchTemplatePrivateDNSNameOptionsRequest(scope.GetLaunchTemplate().PrivateDNSName) // Set up root volume if lt.RootVolume != nil { @@ -669,6 +670,14 @@ func (s *Service) SDKToLaunchTemplate(d *ec2.LaunchTemplateVersion) (*expinfrav1 } } + if v.PrivateDnsNameOptions != nil { + i.PrivateDNSName = &infrav1.PrivateDNSName{ + EnableResourceNameDNSAAAARecord: v.PrivateDnsNameOptions.EnableResourceNameDnsAAAARecord, + EnableResourceNameDNSARecord: v.PrivateDnsNameOptions.EnableResourceNameDnsARecord, + HostnameType: v.PrivateDnsNameOptions.HostnameType, + } + } + if v.IamInstanceProfile != nil { i.IamInstanceProfile = aws.StringValue(v.IamInstanceProfile.Name) } @@ -914,3 +923,15 @@ func getLaunchTemplateInstanceMarketOptionsRequest(spotMarketOptions *infrav1.Sp return launchTemplateInstanceMarketOptionsRequest } + +func getLaunchTemplatePrivateDNSNameOptionsRequest(privateDNSName *infrav1.PrivateDNSName) *ec2.LaunchTemplatePrivateDnsNameOptionsRequest { + if privateDNSName == nil { + return nil + } + + return &ec2.LaunchTemplatePrivateDnsNameOptionsRequest{ + EnableResourceNameDnsAAAARecord: privateDNSName.EnableResourceNameDNSAAAARecord, + EnableResourceNameDnsARecord: privateDNSName.EnableResourceNameDNSARecord, + HostnameType: privateDNSName.HostnameType, + } +} diff --git a/pkg/cloud/services/network/subnets.go b/pkg/cloud/services/network/subnets.go index 84766c4289..d2b1ee1c63 100644 --- a/pkg/cloud/services/network/subnets.go +++ b/pkg/cloud/services/network/subnets.go @@ -490,6 +490,22 @@ func (s *Service) createSubnet(sn *infrav1.SubnetSpec) (*infrav1.SubnetSpec, err record.Eventf(s.scope.InfraCluster(), "SuccessfulModifySubnetAttributes", "Modified managed Subnet %q attributes", *out.Subnet.SubnetId) } + if s.scope.VPC().PrivateDNSHostnameTypeOnLaunch != nil { + if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) { + if _, err := s.EC2Client.ModifySubnetAttributeWithContext(context.TODO(), &ec2.ModifySubnetAttributeInput{ + SubnetId: out.Subnet.SubnetId, + PrivateDnsHostnameTypeOnLaunch: s.scope.VPC().PrivateDNSHostnameTypeOnLaunch, + }); err != nil { + return false, err + } + return true, nil + }, awserrors.SubnetNotFound); err != nil { + record.Warnf(s.scope.InfraCluster(), "FailedModifySubnetAttributes", "Failed modifying managed Subnet %q attributes: %v", *out.Subnet.SubnetId, err) + return nil, errors.Wrapf(err, "failed to set subnet %q attribute private DNS Hostname type on launch", *out.Subnet.SubnetId) + } + record.Eventf(s.scope.InfraCluster(), "SuccessfulModifySubnetAttributes", "Modified managed Subnet %q attributes", *out.Subnet.SubnetId) + } + subnet := &infrav1.SubnetSpec{ // Preserve the original identifier. The AWS identifier `subnet-` is stored in the ResourceID field. ID: sn.ID,