diff --git a/hack/docs/instancetypes_gen_docs.go b/hack/docs/instancetypes_gen_docs.go index f1366e3f4d10..682af2197b48 100644 --- a/hack/docs/instancetypes_gen_docs.go +++ b/hack/docs/instancetypes_gen_docs.go @@ -125,7 +125,7 @@ func main() { Zone: *ec2subnet.AvailabilityZone, } }) - instanceTypes, err := op.InstanceTypesProvider.List(ctx, &providerv1.KubeletConfiguration{}, nodeClass) + instanceTypes, err := op.InstanceTypesProvider.List(ctx, nodeClass) if err != nil { log.Fatalf("listing instance types, %s", err) } diff --git a/pkg/apis/crds/karpenter.k8s.aws_ec2nodeclasses.yaml b/pkg/apis/crds/karpenter.k8s.aws_ec2nodeclasses.yaml index 1de256a30958..ee7e1993c414 100644 --- a/pkg/apis/crds/karpenter.k8s.aws_ec2nodeclasses.yaml +++ b/pkg/apis/crds/karpenter.k8s.aws_ec2nodeclasses.yaml @@ -717,7 +717,7 @@ spec: type: object type: object served: true - storage: false + storage: true subresources: status: {} - name: v1beta1 @@ -1293,6 +1293,6 @@ spec: type: object type: object served: true - storage: true + storage: false subresources: status: {} diff --git a/pkg/apis/v1/ec2nodeclass.go b/pkg/apis/v1/ec2nodeclass.go index fda4c4c3e71a..4dac7e882417 100644 --- a/pkg/apis/v1/ec2nodeclass.go +++ b/pkg/apis/v1/ec2nodeclass.go @@ -21,7 +21,7 @@ import ( "github.com/samber/lo" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - corev1beta1 "sigs.k8s.io/karpenter/pkg/apis/v1beta1" + v1 "sigs.k8s.io/karpenter/pkg/apis/v1" ) // EC2NodeClassSpec is the top level specification for the AWS Karpenter Provider. @@ -186,7 +186,7 @@ type AMISelectorTerm struct { // KubeletConfiguration defines args to be used when configuring kubelet on provisioned nodes. // They are a subset of the upstream types, recognizing not all options may be supported. // Wherever possible, the types and names should reflect the upstream kubelet types. -// https://pkg.go.dev/k8s.io/kubelet/config/v1beta1#KubeletConfiguration +// https://pkg.go.dev/k8s.io/kubelet/config/v1#KubeletConfiguration // https://github.com/kubernetes/kubernetes/blob/9f82d81e55cafdedab619ea25cabf5d42736dacf/cmd/kubelet/app/options/options.go#L53 type KubeletConfiguration struct { // clusterDNS is a list of IP addresses for the cluster DNS server. @@ -395,6 +395,7 @@ const ( // EC2NodeClass is the Schema for the EC2NodeClass API // +kubebuilder:object:root=true +// +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" // +kubebuilder:printcolumn:name="Role",type="string",JSONPath=".spec.role",priority=1,description="" @@ -436,7 +437,7 @@ func (in *EC2NodeClass) InstanceProfileRole() string { func (in *EC2NodeClass) InstanceProfileTags(clusterName string) map[string]string { return lo.Assign(in.Spec.Tags, map[string]string{ fmt.Sprintf("kubernetes.io/cluster/%s", clusterName): "owned", - corev1beta1.ManagedByAnnotationKey: clusterName, + v1.ManagedByAnnotationKey: clusterName, LabelNodeClass: in.Name, }) } diff --git a/pkg/apis/v1/ec2nodeclass_conversion.go b/pkg/apis/v1/ec2nodeclass_conversion.go new file mode 100644 index 000000000000..f53902d57ca0 --- /dev/null +++ b/pkg/apis/v1/ec2nodeclass_conversion.go @@ -0,0 +1,173 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + + "github.com/aws/karpenter-provider-aws/pkg/apis/v1beta1" + "github.com/samber/lo" + "knative.dev/pkg/apis" +) + +func (in *EC2NodeClass) ConvertTo(ctx context.Context, to apis.Convertible) error { + v1beta1enc := to.(*v1beta1.EC2NodeClass) + v1beta1enc.ObjectMeta = in.ObjectMeta + + in.Spec.convertTo(&v1beta1enc.Spec) + in.Status.convertTo((&v1beta1enc.Status)) + return nil +} + +func (in *EC2NodeClassSpec) convertTo(v1beta1enc *v1beta1.EC2NodeClassSpec) { + v1beta1enc.SubnetSelectorTerms = lo.Map(in.SubnetSelectorTerms, func(subnet SubnetSelectorTerm, _ int) v1beta1.SubnetSelectorTerm { + return v1beta1.SubnetSelectorTerm{ + ID: subnet.ID, + Tags: subnet.Tags, + } + }) + v1beta1enc.SecurityGroupSelectorTerms = lo.Map(in.SecurityGroupSelectorTerms, func(sg SecurityGroupSelectorTerm, _ int) v1beta1.SecurityGroupSelectorTerm { + return v1beta1.SecurityGroupSelectorTerm{ + ID: sg.ID, + Name: sg.Name, + Tags: sg.Tags, + } + }) + v1beta1enc.AMISelectorTerms = lo.Map(in.AMISelectorTerms, func(ami AMISelectorTerm, _ int) v1beta1.AMISelectorTerm { + return v1beta1.AMISelectorTerm{ + ID: ami.ID, + Name: ami.Name, + Owner: ami.Owner, + Tags: ami.Tags, + } + }) + v1beta1enc.AMIFamily = in.AMIFamily + v1beta1enc.AssociatePublicIPAddress = in.AssociatePublicIPAddress + v1beta1enc.Context = in.Context + v1beta1enc.DetailedMonitoring = in.DetailedMonitoring + v1beta1enc.Role = in.Role + v1beta1enc.InstanceProfile = in.InstanceProfile + v1beta1enc.InstanceStorePolicy = (*v1beta1.InstanceStorePolicy)(in.InstanceStorePolicy) + v1beta1enc.Tags = in.Tags + v1beta1enc.UserData = in.UserData + v1beta1enc.MetadataOptions = (*v1beta1.MetadataOptions)(in.MetadataOptions) + v1beta1enc.BlockDeviceMappings = lo.Map(in.BlockDeviceMappings, func(bdm *BlockDeviceMapping, _ int) *v1beta1.BlockDeviceMapping { + return &v1beta1.BlockDeviceMapping{ + DeviceName: bdm.DeviceName, + RootVolume: bdm.RootVolume, + EBS: (*v1beta1.BlockDevice)(bdm.EBS), + } + }) +} + +func (in *EC2NodeClassStatus) convertTo(v1beta1enc *v1beta1.EC2NodeClassStatus) { + v1beta1enc.Subnets = lo.Map(in.Subnets, func(subnet Subnet, _ int) v1beta1.Subnet { + return v1beta1.Subnet{ + ID: subnet.ID, + Zone: subnet.Zone, + ZoneID: subnet.ZoneID, + } + }) + v1beta1enc.SecurityGroups = lo.Map(in.SecurityGroups, func(sg SecurityGroup, _ int) v1beta1.SecurityGroup { + return v1beta1.SecurityGroup{ + ID: sg.ID, + Name: sg.Name, + } + }) + v1beta1enc.AMIs = lo.Map(in.AMIs, func(ami AMI, _ int) v1beta1.AMI { + return v1beta1.AMI{ + ID: ami.ID, + Name: ami.Name, + Requirements: ami.Requirements, + } + }) + v1beta1enc.InstanceProfile = in.InstanceProfile + v1beta1enc.Conditions = in.Conditions +} + +func (in *EC2NodeClass) ConvertFrom(ctx context.Context, from apis.Convertible) error { + v1beta1enc := from.(*v1beta1.EC2NodeClass) + in.ObjectMeta = v1beta1enc.ObjectMeta + + in.Spec.convertFrom(&v1beta1enc.Spec) + in.Status.convertFrom((&v1beta1enc.Status)) + return nil +} + +func (in *EC2NodeClassSpec) convertFrom(v1beta1enc *v1beta1.EC2NodeClassSpec) { + in.SubnetSelectorTerms = lo.Map(v1beta1enc.SubnetSelectorTerms, func(subnet v1beta1.SubnetSelectorTerm, _ int) SubnetSelectorTerm { + return SubnetSelectorTerm{ + ID: subnet.ID, + Tags: subnet.Tags, + } + }) + in.SecurityGroupSelectorTerms = lo.Map(v1beta1enc.SecurityGroupSelectorTerms, func(sg v1beta1.SecurityGroupSelectorTerm, _ int) SecurityGroupSelectorTerm { + return SecurityGroupSelectorTerm{ + ID: sg.ID, + Name: sg.Name, + Tags: sg.Tags, + } + }) + in.AMISelectorTerms = lo.Map(v1beta1enc.AMISelectorTerms, func(ami v1beta1.AMISelectorTerm, _ int) AMISelectorTerm { + return AMISelectorTerm{ + ID: ami.ID, + Name: ami.Name, + Owner: ami.Owner, + Tags: ami.Tags, + } + }) + in.AMIFamily = v1beta1enc.AMIFamily + in.AssociatePublicIPAddress = v1beta1enc.AssociatePublicIPAddress + in.Context = v1beta1enc.Context + in.DetailedMonitoring = v1beta1enc.DetailedMonitoring + in.Role = v1beta1enc.Role + in.InstanceProfile = v1beta1enc.InstanceProfile + in.InstanceStorePolicy = (*InstanceStorePolicy)(v1beta1enc.InstanceStorePolicy) + in.Tags = v1beta1enc.Tags + in.UserData = v1beta1enc.UserData + in.MetadataOptions = (*MetadataOptions)(v1beta1enc.MetadataOptions) + in.BlockDeviceMappings = lo.Map(v1beta1enc.BlockDeviceMappings, func(bdm *v1beta1.BlockDeviceMapping, _ int) *BlockDeviceMapping { + return &BlockDeviceMapping{ + DeviceName: bdm.DeviceName, + RootVolume: bdm.RootVolume, + EBS: (*BlockDevice)(bdm.EBS), + } + }) +} + +func (in *EC2NodeClassStatus) convertFrom(v1beta1enc *v1beta1.EC2NodeClassStatus) { + in.Subnets = lo.Map(v1beta1enc.Subnets, func(subnet v1beta1.Subnet, _ int) Subnet { + return Subnet{ + ID: subnet.ID, + Zone: subnet.Zone, + ZoneID: subnet.ZoneID, + } + }) + in.SecurityGroups = lo.Map(v1beta1enc.SecurityGroups, func(sg v1beta1.SecurityGroup, _ int) SecurityGroup { + return SecurityGroup{ + ID: sg.ID, + Name: sg.Name, + } + }) + in.AMIs = lo.Map(v1beta1enc.AMIs, func(ami v1beta1.AMI, _ int) AMI { + return AMI{ + ID: ami.ID, + Name: ami.Name, + Requirements: ami.Requirements, + } + }) + in.InstanceProfile = v1beta1enc.InstanceProfile + in.Conditions = v1beta1enc.Conditions +} diff --git a/pkg/apis/v1/ec2nodeclass_conversion_test.go b/pkg/apis/v1/ec2nodeclass_conversion_test.go new file mode 100644 index 000000000000..70a60fcf1e52 --- /dev/null +++ b/pkg/apis/v1/ec2nodeclass_conversion_test.go @@ -0,0 +1,489 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1_test + +import ( + "github.com/awslabs/operatorpkg/status" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/samber/lo" + "k8s.io/apimachinery/pkg/api/resource" + "sigs.k8s.io/karpenter/pkg/test" + + . "github.com/aws/karpenter-provider-aws/pkg/apis/v1" + "github.com/aws/karpenter-provider-aws/pkg/apis/v1beta1" +) + +var _ = Describe("Convert v1 to v1beta1 EC2NodeClass API", func() { + var ( + v1ec2nodeclass *EC2NodeClass + v1beta1ec2nodeclass *v1beta1.EC2NodeClass + ) + + BeforeEach(func() { + v1ec2nodeclass = &EC2NodeClass{} + v1beta1ec2nodeclass = &v1beta1.EC2NodeClass{} + }) + + It("should convert v1 ec2nodeclass metadata", func() { + v1ec2nodeclass.ObjectMeta = test.ObjectMeta() + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1beta1ec2nodeclass.ObjectMeta).To(BeEquivalentTo(v1ec2nodeclass.ObjectMeta)) + }) + Context("EC2NodeClass Spec", func() { + It("should convert v1 ec2nodeclass subnet selector terms", func() { + v1ec2nodeclass.Spec.SubnetSelectorTerms = []SubnetSelectorTerm{ + { + Tags: map[string]string{"test-key-1": "test-value-1"}, + ID: "test-id-1", + }, + { + Tags: map[string]string{"test-key-2": "test-value-2"}, + ID: "test-id-2", + }, + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1ec2nodeclass.Spec.SubnetSelectorTerms { + Expect(v1beta1ec2nodeclass.Spec.SubnetSelectorTerms[i].Tags).To(Equal(v1ec2nodeclass.Spec.SubnetSelectorTerms[i].Tags)) + Expect(v1beta1ec2nodeclass.Spec.SubnetSelectorTerms[i].ID).To(Equal(v1ec2nodeclass.Spec.SubnetSelectorTerms[i].ID)) + } + }) + It("should convert v1 ec2nodeclass securitygroup selector terms", func() { + v1ec2nodeclass.Spec.SecurityGroupSelectorTerms = []SecurityGroupSelectorTerm{ + { + Tags: map[string]string{"test-key-1": "test-value-1"}, + ID: "test-id-1", + Name: "test-name-1", + }, + { + Tags: map[string]string{"test-key-2": "test-value-2"}, + ID: "test-id-2", + Name: "test-name-2", + }, + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1ec2nodeclass.Spec.SecurityGroupSelectorTerms { + Expect(v1beta1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].Tags).To(Equal(v1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].Tags)) + Expect(v1beta1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].ID).To(Equal(v1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].ID)) + Expect(v1beta1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].Name).To(Equal(v1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].Name)) + } + }) + It("should convert v1 ec2nodeclass ami selector terms", func() { + v1ec2nodeclass.Spec.AMISelectorTerms = []AMISelectorTerm{ + { + Tags: map[string]string{"test-key-1": "test-value-1"}, + ID: "test-id-1", + Name: "test-name-1", + Owner: "test-owner-1", + }, + { + Tags: map[string]string{"test-key-2": "test-value-2"}, + ID: "test-id-2", + Name: "test-name-2", + Owner: "test-owner-1", + }, + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1ec2nodeclass.Spec.AMISelectorTerms { + Expect(v1beta1ec2nodeclass.Spec.AMISelectorTerms[i].Tags).To(Equal(v1ec2nodeclass.Spec.AMISelectorTerms[i].Tags)) + Expect(v1beta1ec2nodeclass.Spec.AMISelectorTerms[i].ID).To(Equal(v1ec2nodeclass.Spec.AMISelectorTerms[i].ID)) + Expect(v1beta1ec2nodeclass.Spec.AMISelectorTerms[i].Name).To(Equal(v1ec2nodeclass.Spec.AMISelectorTerms[i].Name)) + Expect(v1beta1ec2nodeclass.Spec.AMISelectorTerms[i].Owner).To(Equal(v1ec2nodeclass.Spec.AMISelectorTerms[i].Owner)) + } + }) + It("should convert v1 ec2nodeclass associate public ip address ", func() { + v1ec2nodeclass.Spec.AssociatePublicIPAddress = lo.ToPtr(true) + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.AssociatePublicIPAddress)).To(BeTrue()) + }) + It("should convert v1 ec2nodeclass ami family", func() { + v1ec2nodeclass.Spec.AMIFamily = &AMIFamilyUbuntu + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.AMIFamily)).To(Equal(v1beta1.AMIFamilyUbuntu)) + }) + It("should convert v1 ec2nodeclass user data", func() { + v1ec2nodeclass.Spec.UserData = lo.ToPtr("test user data") + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.UserData)).To(Equal(lo.FromPtr(v1ec2nodeclass.Spec.UserData))) + }) + It("should convert v1 ec2nodeclass role", func() { + v1ec2nodeclass.Spec.Role = "test-role" + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1beta1ec2nodeclass.Spec.Role).To(Equal(v1ec2nodeclass.Spec.Role)) + }) + It("should convert v1 ec2nodeclass instance profile", func() { + v1ec2nodeclass.Spec.InstanceProfile = lo.ToPtr("test-instance-profile") + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.InstanceProfile)).To(Equal(lo.FromPtr(v1ec2nodeclass.Spec.InstanceProfile))) + }) + It("should convert v1 ec2nodeclass tags", func() { + v1ec2nodeclass.Spec.Tags = map[string]string{ + "test-key-tag-1": "test-value-tag-1", + "test-key-tag-2": "test-value-tag-2", + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1beta1ec2nodeclass.Spec.Tags).To(Equal(v1ec2nodeclass.Spec.Tags)) + }) + It("should convert v1 ec2nodeclass block device mapping", func() { + v1ec2nodeclass.Spec.BlockDeviceMappings = []*BlockDeviceMapping{ + { + EBS: &BlockDevice{ + DeleteOnTermination: lo.ToPtr(true), + Encrypted: lo.ToPtr(true), + IOPS: lo.ToPtr(int64(45123)), + KMSKeyID: lo.ToPtr("test-kms-id"), + SnapshotID: lo.ToPtr("test-snapshot-id"), + Throughput: lo.ToPtr(int64(4512433)), + VolumeSize: lo.ToPtr(resource.MustParse("54G")), + VolumeType: lo.ToPtr("test-type"), + }, + DeviceName: lo.ToPtr("test-device"), + RootVolume: true, + }, + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1ec2nodeclass.Spec.BlockDeviceMappings { + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].RootVolume).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].RootVolume)) + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].DeviceName).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].DeviceName)) + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.DeleteOnTermination).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.DeleteOnTermination)) + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.Encrypted).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.Encrypted)) + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.IOPS).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.IOPS)) + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.KMSKeyID).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.KMSKeyID)) + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.SnapshotID).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.SnapshotID)) + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.Throughput).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.Throughput)) + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.VolumeSize).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.VolumeSize)) + Expect(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.VolumeType).To(Equal(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.VolumeType)) + } + }) + It("should convert v1 ec2nodeclass instance store policy", func() { + v1ec2nodeclass.Spec.InstanceStorePolicy = lo.ToPtr(InstanceStorePolicyRAID0) + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(string(lo.FromPtr(v1beta1ec2nodeclass.Spec.InstanceStorePolicy))).To(Equal(string(lo.FromPtr(v1ec2nodeclass.Spec.InstanceStorePolicy)))) + }) + It("should convert v1 ec2nodeclass detailed monitoring", func() { + v1ec2nodeclass.Spec.DetailedMonitoring = lo.ToPtr(true) + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.DetailedMonitoring)).To(Equal(lo.FromPtr(v1ec2nodeclass.Spec.DetailedMonitoring))) + }) + It("should convert v1 ec2nodeclass metadata options", func() { + v1ec2nodeclass.Spec.MetadataOptions = &MetadataOptions{ + HTTPEndpoint: lo.ToPtr("test-endpoint"), + HTTPProtocolIPv6: lo.ToPtr("test-protocol"), + HTTPPutResponseHopLimit: lo.ToPtr(int64(54)), + HTTPTokens: lo.ToPtr("test-token"), + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.MetadataOptions.HTTPEndpoint)).To(Equal(lo.FromPtr(v1ec2nodeclass.Spec.MetadataOptions.HTTPEndpoint))) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.MetadataOptions.HTTPProtocolIPv6)).To(Equal(lo.FromPtr(v1ec2nodeclass.Spec.MetadataOptions.HTTPProtocolIPv6))) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.MetadataOptions.HTTPPutResponseHopLimit)).To(Equal(lo.FromPtr(v1ec2nodeclass.Spec.MetadataOptions.HTTPPutResponseHopLimit))) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.MetadataOptions.HTTPTokens)).To(Equal(lo.FromPtr(v1ec2nodeclass.Spec.MetadataOptions.HTTPTokens))) + }) + It("should convert v1 ec2nodeclass context", func() { + v1ec2nodeclass.Spec.Context = lo.ToPtr("test-context") + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1beta1ec2nodeclass.Spec.Context)).To(Equal(lo.FromPtr(v1ec2nodeclass.Spec.Context))) + }) + }) + Context("EC2NodeClass Status", func() { + It("should convert v1 ec2nodeclass subnet", func() { + v1ec2nodeclass.Status.Subnets = []Subnet{ + { + ID: "test-id", + Zone: "test-zone", + ZoneID: "test-zone-id", + }, + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1ec2nodeclass.Status.Subnets { + Expect(v1beta1ec2nodeclass.Status.Subnets[i].ID).To(Equal(v1ec2nodeclass.Status.Subnets[i].ID)) + Expect(v1beta1ec2nodeclass.Status.Subnets[i].Zone).To(Equal(v1ec2nodeclass.Status.Subnets[i].Zone)) + Expect(v1beta1ec2nodeclass.Status.Subnets[i].ZoneID).To(Equal(v1ec2nodeclass.Status.Subnets[i].ZoneID)) + } + }) + It("should convert v1 ec2nodeclass security group ", func() { + v1ec2nodeclass.Status.SecurityGroups = []SecurityGroup{ + { + ID: "test-id", + Name: "test-name", + }, + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1ec2nodeclass.Status.SecurityGroups { + Expect(v1beta1ec2nodeclass.Status.SecurityGroups[i].ID).To(Equal(v1ec2nodeclass.Status.SecurityGroups[i].ID)) + Expect(v1beta1ec2nodeclass.Status.SecurityGroups[i].Name).To(Equal(v1ec2nodeclass.Status.SecurityGroups[i].Name)) + } + }) + It("should convert v1 ec2nodeclass ami", func() { + v1ec2nodeclass.Status.AMIs = []AMI{ + { + ID: "test-id", + Name: "test-name", + }, + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1ec2nodeclass.Status.AMIs { + Expect(v1beta1ec2nodeclass.Status.AMIs[i].ID).To(Equal(v1ec2nodeclass.Status.AMIs[i].ID)) + Expect(v1beta1ec2nodeclass.Status.AMIs[i].Name).To(Equal(v1ec2nodeclass.Status.AMIs[i].Name)) + + } + }) + It("should convert v1 ec2nodeclass instance profile", func() { + v1ec2nodeclass.Status.InstanceProfile = "test-instance-profile" + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1beta1ec2nodeclass.Status.InstanceProfile).To(Equal(v1ec2nodeclass.Status.InstanceProfile)) + }) + It("should convert v1 ec2nodeclass conditions", func() { + v1ec2nodeclass.Status.Conditions = []status.Condition{ + { + Status: status.ConditionReady, + Reason: "test-reason", + }, + } + Expect(v1ec2nodeclass.ConvertTo(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1beta1ec2nodeclass.Status.Conditions).To(Equal(v1beta1ec2nodeclass.Status.Conditions)) + }) + }) +}) + +var _ = Describe("Convert v1beta1 to v1 EC2NodeClass API", func() { + var ( + v1ec2nodeclass *EC2NodeClass + v1beta1ec2nodeclass *v1beta1.EC2NodeClass + ) + + BeforeEach(func() { + v1ec2nodeclass = &EC2NodeClass{} + v1beta1ec2nodeclass = &v1beta1.EC2NodeClass{} + }) + + It("should convert v1beta1 ec2nodeclass metadata", func() { + v1beta1ec2nodeclass.ObjectMeta = test.ObjectMeta() + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1ec2nodeclass.ObjectMeta).To(BeEquivalentTo(v1beta1ec2nodeclass.ObjectMeta)) + }) + Context("EC2NodeClass Spec", func() { + It("should convert v1beta1 ec2nodeclass subnet selector terms", func() { + v1beta1ec2nodeclass.Spec.SubnetSelectorTerms = []v1beta1.SubnetSelectorTerm{ + { + Tags: map[string]string{"test-key-1": "test-value-1"}, + ID: "test-id-1", + }, + { + Tags: map[string]string{"test-key-2": "test-value-2"}, + ID: "test-id-2", + }, + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1beta1ec2nodeclass.Spec.SubnetSelectorTerms { + Expect(v1ec2nodeclass.Spec.SubnetSelectorTerms[i].Tags).To(Equal(v1beta1ec2nodeclass.Spec.SubnetSelectorTerms[i].Tags)) + Expect(v1ec2nodeclass.Spec.SubnetSelectorTerms[i].ID).To(Equal(v1beta1ec2nodeclass.Spec.SubnetSelectorTerms[i].ID)) + } + }) + It("should convert v1beta1 ec2nodeclass securitygroup selector terms", func() { + v1beta1ec2nodeclass.Spec.SecurityGroupSelectorTerms = []v1beta1.SecurityGroupSelectorTerm{ + { + Tags: map[string]string{"test-key-1": "test-value-1"}, + ID: "test-id-1", + Name: "test-name-1", + }, + { + Tags: map[string]string{"test-key-2": "test-value-2"}, + ID: "test-id-2", + Name: "test-name-2", + }, + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1beta1ec2nodeclass.Spec.SecurityGroupSelectorTerms { + Expect(v1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].Tags).To(Equal(v1beta1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].Tags)) + Expect(v1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].ID).To(Equal(v1beta1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].ID)) + Expect(v1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].Name).To(Equal(v1beta1ec2nodeclass.Spec.SecurityGroupSelectorTerms[i].Name)) + } + }) + It("should convert v1beta1 ec2nodeclass ami selector terms", func() { + v1beta1ec2nodeclass.Spec.AMISelectorTerms = []v1beta1.AMISelectorTerm{ + { + Tags: map[string]string{"test-key-1": "test-value-1"}, + ID: "test-id-1", + Name: "test-name-1", + Owner: "test-owner-1", + }, + { + Tags: map[string]string{"test-key-2": "test-value-2"}, + ID: "test-id-2", + Name: "test-name-2", + Owner: "test-owner-1", + }, + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1beta1ec2nodeclass.Spec.AMISelectorTerms { + Expect(v1ec2nodeclass.Spec.AMISelectorTerms[i].Tags).To(Equal(v1beta1ec2nodeclass.Spec.AMISelectorTerms[i].Tags)) + Expect(v1ec2nodeclass.Spec.AMISelectorTerms[i].ID).To(Equal(v1beta1ec2nodeclass.Spec.AMISelectorTerms[i].ID)) + Expect(v1ec2nodeclass.Spec.AMISelectorTerms[i].Name).To(Equal(v1beta1ec2nodeclass.Spec.AMISelectorTerms[i].Name)) + Expect(v1ec2nodeclass.Spec.AMISelectorTerms[i].Owner).To(Equal(v1beta1ec2nodeclass.Spec.AMISelectorTerms[i].Owner)) + } + }) + It("should convert v1beta1 ec2nodeclass associate public ip address ", func() { + v1beta1ec2nodeclass.Spec.AssociatePublicIPAddress = lo.ToPtr(true) + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.AssociatePublicIPAddress)).To(BeTrue()) + }) + It("should convert v1beta1 ec2nodeclass ami family", func() { + v1beta1ec2nodeclass.Spec.AMIFamily = &AMIFamilyUbuntu + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.AMIFamily)).To(Equal(v1beta1.AMIFamilyUbuntu)) + }) + It("should convert v1beta1 ec2nodeclass user data", func() { + v1beta1ec2nodeclass.Spec.UserData = lo.ToPtr("test user data") + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.UserData)).To(Equal(lo.FromPtr(v1beta1ec2nodeclass.Spec.UserData))) + }) + It("should convert v1beta1 ec2nodeclass role", func() { + v1beta1ec2nodeclass.Spec.Role = "test-role" + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1ec2nodeclass.Spec.Role).To(Equal(v1beta1ec2nodeclass.Spec.Role)) + }) + It("should convert v1beta1 ec2nodeclass instance profile", func() { + v1beta1ec2nodeclass.Spec.InstanceProfile = lo.ToPtr("test-instance-profile") + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.InstanceProfile)).To(Equal(lo.FromPtr(v1beta1ec2nodeclass.Spec.InstanceProfile))) + }) + It("should convert v1beta1 ec2nodeclass tags", func() { + v1beta1ec2nodeclass.Spec.Tags = map[string]string{ + "test-key-tag-1": "test-value-tag-1", + "test-key-tag-2": "test-value-tag-2", + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1ec2nodeclass.Spec.Tags).To(Equal(v1beta1ec2nodeclass.Spec.Tags)) + }) + It("should convert v1beta1 ec2nodeclass block device mapping", func() { + v1beta1ec2nodeclass.Spec.BlockDeviceMappings = []*v1beta1.BlockDeviceMapping{ + { + EBS: &v1beta1.BlockDevice{ + DeleteOnTermination: lo.ToPtr(true), + Encrypted: lo.ToPtr(true), + IOPS: lo.ToPtr(int64(45123)), + KMSKeyID: lo.ToPtr("test-kms-id"), + SnapshotID: lo.ToPtr("test-snapshot-id"), + Throughput: lo.ToPtr(int64(4512433)), + VolumeSize: lo.ToPtr(resource.MustParse("54G")), + VolumeType: lo.ToPtr("test-type"), + }, + DeviceName: lo.ToPtr("test-device"), + RootVolume: true, + }, + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1beta1ec2nodeclass.Spec.BlockDeviceMappings { + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].RootVolume).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].RootVolume)) + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].DeviceName).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].DeviceName)) + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.DeleteOnTermination).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.DeleteOnTermination)) + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.Encrypted).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.Encrypted)) + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.IOPS).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.IOPS)) + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.KMSKeyID).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.KMSKeyID)) + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.SnapshotID).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.SnapshotID)) + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.Throughput).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.Throughput)) + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.VolumeSize).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.VolumeSize)) + Expect(v1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.VolumeType).To(Equal(v1beta1ec2nodeclass.Spec.BlockDeviceMappings[i].EBS.VolumeType)) + } + }) + It("should convert v1beta1 ec2nodeclass instance store policy", func() { + v1beta1ec2nodeclass.Spec.InstanceStorePolicy = lo.ToPtr(v1beta1.InstanceStorePolicyRAID0) + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(string(lo.FromPtr(v1ec2nodeclass.Spec.InstanceStorePolicy))).To(Equal(string(lo.FromPtr(v1beta1ec2nodeclass.Spec.InstanceStorePolicy)))) + }) + It("should convert v1beta1 ec2nodeclass detailed monitoring", func() { + v1beta1ec2nodeclass.Spec.DetailedMonitoring = lo.ToPtr(true) + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.DetailedMonitoring)).To(Equal(lo.FromPtr(v1beta1ec2nodeclass.Spec.DetailedMonitoring))) + }) + It("should convert v1beta1 ec2nodeclass metadata options", func() { + v1beta1ec2nodeclass.Spec.MetadataOptions = &v1beta1.MetadataOptions{ + HTTPEndpoint: lo.ToPtr("test-endpoint"), + HTTPProtocolIPv6: lo.ToPtr("test-protocol"), + HTTPPutResponseHopLimit: lo.ToPtr(int64(54)), + HTTPTokens: lo.ToPtr("test-token"), + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.MetadataOptions.HTTPEndpoint)).To(Equal(lo.FromPtr(v1beta1ec2nodeclass.Spec.MetadataOptions.HTTPEndpoint))) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.MetadataOptions.HTTPProtocolIPv6)).To(Equal(lo.FromPtr(v1beta1ec2nodeclass.Spec.MetadataOptions.HTTPProtocolIPv6))) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.MetadataOptions.HTTPPutResponseHopLimit)).To(Equal(lo.FromPtr(v1beta1ec2nodeclass.Spec.MetadataOptions.HTTPPutResponseHopLimit))) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.MetadataOptions.HTTPTokens)).To(Equal(lo.FromPtr(v1beta1ec2nodeclass.Spec.MetadataOptions.HTTPTokens))) + }) + It("should convert v1beta1 ec2nodeclass context", func() { + v1beta1ec2nodeclass.Spec.Context = lo.ToPtr("test-context") + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(lo.FromPtr(v1ec2nodeclass.Spec.Context)).To(Equal(lo.FromPtr(v1beta1ec2nodeclass.Spec.Context))) + }) + }) + Context("EC2NodeClass Status", func() { + It("should convert v1beta1 ec2nodeclass subnet", func() { + v1beta1ec2nodeclass.Status.Subnets = []v1beta1.Subnet{ + { + ID: "test-id", + Zone: "test-zone", + ZoneID: "test-zone-id", + }, + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1beta1ec2nodeclass.Status.Subnets { + Expect(v1ec2nodeclass.Status.Subnets[i].ID).To(Equal(v1beta1ec2nodeclass.Status.Subnets[i].ID)) + Expect(v1ec2nodeclass.Status.Subnets[i].Zone).To(Equal(v1beta1ec2nodeclass.Status.Subnets[i].Zone)) + Expect(v1ec2nodeclass.Status.Subnets[i].ZoneID).To(Equal(v1beta1ec2nodeclass.Status.Subnets[i].ZoneID)) + } + }) + It("should convert v1beta1 ec2nodeclass security group ", func() { + v1beta1ec2nodeclass.Status.SecurityGroups = []v1beta1.SecurityGroup{ + { + ID: "test-id", + Name: "test-name", + }, + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1beta1ec2nodeclass.Status.SecurityGroups { + Expect(v1ec2nodeclass.Status.SecurityGroups[i].ID).To(Equal(v1beta1ec2nodeclass.Status.SecurityGroups[i].ID)) + Expect(v1ec2nodeclass.Status.SecurityGroups[i].Name).To(Equal(v1beta1ec2nodeclass.Status.SecurityGroups[i].Name)) + } + }) + It("should convert v1beta1 ec2nodeclass ami", func() { + v1beta1ec2nodeclass.Status.AMIs = []v1beta1.AMI{ + { + ID: "test-id", + Name: "test-name", + }, + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + for i := range v1beta1ec2nodeclass.Status.AMIs { + Expect(v1ec2nodeclass.Status.AMIs[i].ID).To(Equal(v1beta1ec2nodeclass.Status.AMIs[i].ID)) + Expect(v1ec2nodeclass.Status.AMIs[i].Name).To(Equal(v1beta1ec2nodeclass.Status.AMIs[i].Name)) + + } + }) + It("should convert v1beta1 ec2nodeclass instance profile", func() { + v1beta1ec2nodeclass.Status.InstanceProfile = "test-instance-profile" + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1ec2nodeclass.Status.InstanceProfile).To(Equal(v1beta1ec2nodeclass.Status.InstanceProfile)) + }) + It("should convert v1beta1 ec2nodeclass conditions", func() { + v1beta1ec2nodeclass.Status.Conditions = []status.Condition{ + { + Status: status.ConditionReady, + Reason: "test-reason", + }, + } + Expect(v1ec2nodeclass.ConvertFrom(ctx, v1beta1ec2nodeclass)).To(Succeed()) + Expect(v1ec2nodeclass.Status.Conditions).To(Equal(v1beta1ec2nodeclass.Status.Conditions)) + }) + }) +}) diff --git a/pkg/apis/v1/ec2nodeclass_validation_cel_test.go b/pkg/apis/v1/ec2nodeclass_validation_cel_test.go index 46207267293e..bfb9e7014d94 100644 --- a/pkg/apis/v1/ec2nodeclass_validation_cel_test.go +++ b/pkg/apis/v1/ec2nodeclass_validation_cel_test.go @@ -19,15 +19,15 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/samber/lo" - corev1 "k8s.io/api/core/corev1" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/corev1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/ptr" - corev1 "sigs.k8s.io/karpenter/pkg/apis/corev1" + corev1 "sigs.k8s.io/karpenter/pkg/apis/v1" coretest "sigs.k8s.io/karpenter/pkg/test" - corev1 "github.com/aws/karpenter-provider-aws/pkg/apis/corev1" + providerv1 "github.com/aws/karpenter-provider-aws/pkg/apis/v1" "github.com/aws/karpenter-provider-aws/pkg/test" . "github.com/onsi/ginkgo/v2" @@ -35,7 +35,7 @@ import ( ) var _ = Describe("CEL/Validation", func() { - var nc *corev1.EC2NodeClass + var nc *providerv1.EC2NodeClass BeforeEach(func() { if env.Version.Minor() < 25 { @@ -91,7 +91,7 @@ var _ = Describe("CEL/Validation", func() { } Expect(env.Client.Create(ctx, nc)).To(Not(Succeed())) nc.Spec.Tags = map[string]string{ - corev1.LabelNodeClass: "test", + providerv1.LabelNodeClass: "test", } Expect(env.Client.Create(ctx, nc)).To(Not(Succeed())) nc.Spec.Tags = map[string]string{ @@ -102,7 +102,7 @@ var _ = Describe("CEL/Validation", func() { }) Context("SubnetSelectorTerms", func() { It("should succeed with a valid subnet selector on tags", func() { - nc.Spec.SubnetSelectorTerms = []corev1.SubnetSelectorTerm{ + nc.Spec.SubnetSelectorTerms = []providerv1.SubnetSelectorTerm{ { Tags: map[string]string{ "test": "testvalue", @@ -112,7 +112,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should succeed with a valid subnet selector on id", func() { - nc.Spec.SubnetSelectorTerms = []corev1.SubnetSelectorTerm{ + nc.Spec.SubnetSelectorTerms = []providerv1.SubnetSelectorTerm{ { ID: "subnet-12345749", }, @@ -124,17 +124,17 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when no subnet selector terms exist", func() { - nc.Spec.SubnetSelectorTerms = []corev1.SubnetSelectorTerm{} + nc.Spec.SubnetSelectorTerms = []providerv1.SubnetSelectorTerm{} Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a subnet selector term has no values", func() { - nc.Spec.SubnetSelectorTerms = []corev1.SubnetSelectorTerm{ + nc.Spec.SubnetSelectorTerms = []providerv1.SubnetSelectorTerm{ {}, } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a subnet selector term has no tag map values", func() { - nc.Spec.SubnetSelectorTerms = []corev1.SubnetSelectorTerm{ + nc.Spec.SubnetSelectorTerms = []providerv1.SubnetSelectorTerm{ { Tags: map[string]string{}, }, @@ -142,7 +142,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a subnet selector term has a tag map key that is empty", func() { - nc.Spec.SubnetSelectorTerms = []corev1.SubnetSelectorTerm{ + nc.Spec.SubnetSelectorTerms = []providerv1.SubnetSelectorTerm{ { Tags: map[string]string{ "test": "", @@ -152,7 +152,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a subnet selector term has a tag map value that is empty", func() { - nc.Spec.SubnetSelectorTerms = []corev1.SubnetSelectorTerm{ + nc.Spec.SubnetSelectorTerms = []providerv1.SubnetSelectorTerm{ { Tags: map[string]string{ "": "testvalue", @@ -162,7 +162,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when the last subnet selector is invalid", func() { - nc.Spec.SubnetSelectorTerms = []corev1.SubnetSelectorTerm{ + nc.Spec.SubnetSelectorTerms = []providerv1.SubnetSelectorTerm{ { Tags: map[string]string{ "test": "testvalue", @@ -187,7 +187,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when specifying id with tags", func() { - nc.Spec.SubnetSelectorTerms = []corev1.SubnetSelectorTerm{ + nc.Spec.SubnetSelectorTerms = []providerv1.SubnetSelectorTerm{ { ID: "subnet-12345749", Tags: map[string]string{ @@ -200,7 +200,7 @@ var _ = Describe("CEL/Validation", func() { }) Context("SecurityGroupSelectorTerms", func() { It("should succeed with a valid security group selector on tags", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { Tags: map[string]string{ "test": "testvalue", @@ -210,7 +210,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should succeed with a valid security group selector on id", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { ID: "sg-12345749", }, @@ -218,7 +218,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should succeed with a valid security group selector on name", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { Name: "testname", }, @@ -230,17 +230,17 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when no security group selector terms exist", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{} + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{} Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a security group selector term has no values", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ {}, } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a security group selector term has no tag map values", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { Tags: map[string]string{}, }, @@ -248,7 +248,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a security group selector term has a tag map key that is empty", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { Tags: map[string]string{ "test": "", @@ -258,7 +258,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a security group selector term has a tag map value that is empty", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { Tags: map[string]string{ "": "testvalue", @@ -268,7 +268,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when the last security group selector is invalid", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { Tags: map[string]string{ "test": "testvalue", @@ -293,7 +293,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when specifying id with tags", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { ID: "sg-12345749", Tags: map[string]string{ @@ -304,7 +304,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when specifying id with name", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { ID: "sg-12345749", Name: "my-security-group", @@ -313,7 +313,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when specifying name with tags", func() { - nc.Spec.SecurityGroupSelectorTerms = []corev1.SecurityGroupSelectorTerm{ + nc.Spec.SecurityGroupSelectorTerms = []providerv1.SecurityGroupSelectorTerm{ { Name: "my-security-group", Tags: map[string]string{ @@ -326,7 +326,7 @@ var _ = Describe("CEL/Validation", func() { }) Context("AMISelectorTerms", func() { It("should succeed with a valid ami selector on tags", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { Tags: map[string]string{ "test": "testvalue", @@ -336,7 +336,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should succeed with a valid ami selector on id", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { ID: "ami-12345749", }, @@ -344,7 +344,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should succeed with a valid ami selector on name", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { Name: "testname", }, @@ -352,7 +352,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should succeed with a valid ami selector on name and owner", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { Name: "testname", Owner: "testowner", @@ -361,7 +361,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should succeed when an ami selector term has an owner key with tags", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { Owner: "testowner", Tags: map[string]string{ @@ -372,13 +372,13 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should fail when a ami selector term has no values", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ {}, } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a ami selector term has no tag map values", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { Tags: map[string]string{}, }, @@ -386,7 +386,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a ami selector term has a tag map key that is empty", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { Tags: map[string]string{ "test": "", @@ -396,7 +396,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when a ami selector term has a tag map value that is empty", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { Tags: map[string]string{ "": "testvalue", @@ -406,7 +406,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when the last ami selector is invalid", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { Tags: map[string]string{ "test": "testvalue", @@ -431,7 +431,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when specifying id with tags", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { ID: "ami-12345749", Tags: map[string]string{ @@ -442,7 +442,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when specifying id with name", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { ID: "ami-12345749", Name: "my-custom-ami", @@ -451,7 +451,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when specifying id with owner", func() { - nc.Spec.AMISelectorTerms = []corev1.AMISelectorTerm{ + nc.Spec.AMISelectorTerms = []providerv1.AMISelectorTerm{ { ID: "ami-12345749", Owner: "123456789", @@ -460,23 +460,23 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when AMIFamily is Custom and not AMISelectorTerms", func() { - nc.Spec.AMIFamily = &corev1.AMIFamilyCustom + nc.Spec.AMIFamily = &providerv1.AMIFamilyCustom Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) }) Context("Kubelet", func() { It("should fail on kubeReserved with invalid keys", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ KubeReserved: map[string]string{ - string(corev1.ResourcePods): "2", + string(v1.ResourcePods): "2", }, } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail on systemReserved with invalid keys", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ SystemReserved: map[string]string{ - string(corev1.ResourcePods): "2", + string(v1.ResourcePods): "2", }, } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) @@ -484,7 +484,7 @@ var _ = Describe("CEL/Validation", func() { Context("Eviction Signals", func() { Context("Eviction Hard", func() { It("should succeed on evictionHard with valid keys", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionHard: map[string]string{ "memory.available": "5%", "nodefs.available": "10%", @@ -497,7 +497,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should fail on evictionHard with invalid keys", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionHard: map[string]string{ "memory": "5%", }, @@ -505,7 +505,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail on invalid formatted percentage value in evictionHard", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionHard: map[string]string{ "memory.available": "5%3", }, @@ -513,7 +513,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail on invalid percentage value (too large) in evictionHard", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionHard: map[string]string{ "memory.available": "110%", }, @@ -521,7 +521,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail on invalid quantity value in evictionHard", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionHard: map[string]string{ "memory.available": "110GB", }, @@ -532,7 +532,7 @@ var _ = Describe("CEL/Validation", func() { }) Context("Eviction Soft", func() { It("should succeed on evictionSoft with valid keys", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionSoft: map[string]string{ "memory.available": "5%", "nodefs.available": "10%", @@ -553,7 +553,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should fail on evictionSoft with invalid keys", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionSoft: map[string]string{ "memory": "5%", }, @@ -564,7 +564,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail on invalid formatted percentage value in evictionSoft", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionSoft: map[string]string{ "memory.available": "5%3", }, @@ -575,7 +575,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail on invalid percentage value (too large) in evictionSoft", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionSoft: map[string]string{ "memory.available": "110%", }, @@ -586,7 +586,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail on invalid quantity value in evictionSoft", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionSoft: map[string]string{ "memory.available": "110GB", }, @@ -597,7 +597,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when eviction soft doesn't have matching grace period", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionSoft: map[string]string{ "memory.available": "200Mi", }, @@ -607,20 +607,20 @@ var _ = Describe("CEL/Validation", func() { }) Context("GCThresholdPercent", func() { It("should succeed on a valid imageGCHighThresholdPercent", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ ImageGCHighThresholdPercent: ptr.Int32(10), } Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should fail when imageGCHighThresholdPercent is less than imageGCLowThresholdPercent", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ ImageGCHighThresholdPercent: ptr.Int32(50), ImageGCLowThresholdPercent: ptr.Int32(60), } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when imageGCLowThresholdPercent is greather than imageGCHighThresheldPercent", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ ImageGCHighThresholdPercent: ptr.Int32(50), ImageGCLowThresholdPercent: ptr.Int32(60), } @@ -629,7 +629,7 @@ var _ = Describe("CEL/Validation", func() { }) Context("Eviction Soft Grace Period", func() { It("should succeed on evictionSoftGracePeriod with valid keys", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionSoft: map[string]string{ "memory.available": "5%", "nodefs.available": "10%", @@ -650,7 +650,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should fail on evictionSoftGracePeriod with invalid keys", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionSoftGracePeriod: map[string]metav1.Duration{ "memory": {Duration: time.Minute}, }, @@ -658,7 +658,7 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail when eviction soft grace period doesn't have matching threshold", func() { - nc.Spec.Kubelet = &corev1.KubeletConfiguration{ + nc.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionSoftGracePeriod: map[string]metav1.Duration{ "memory.available": {Duration: time.Minute}, }, @@ -669,7 +669,7 @@ var _ = Describe("CEL/Validation", func() { }) Context("MetadataOptions", func() { It("should succeed for valid inputs", func() { - nc.Spec.MetadataOptions = &corev1.MetadataOptions{ + nc.Spec.MetadataOptions = &providerv1.MetadataOptions{ HTTPEndpoint: aws.String("disabled"), HTTPProtocolIPv6: aws.String("enabled"), HTTPPutResponseHopLimit: aws.Int64(34), @@ -678,25 +678,25 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nc)).To(Succeed()) }) It("should fail for invalid for HTTPEndpoint", func() { - nc.Spec.MetadataOptions = &corev1.MetadataOptions{ + nc.Spec.MetadataOptions = &providerv1.MetadataOptions{ HTTPEndpoint: aws.String("test"), } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail for invalid for HTTPProtocolIPv6", func() { - nc.Spec.MetadataOptions = &corev1.MetadataOptions{ + nc.Spec.MetadataOptions = &providerv1.MetadataOptions{ HTTPProtocolIPv6: aws.String("test"), } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail for invalid for HTTPPutResponseHopLimit", func() { - nc.Spec.MetadataOptions = &corev1.MetadataOptions{ + nc.Spec.MetadataOptions = &providerv1.MetadataOptions{ HTTPPutResponseHopLimit: aws.Int64(-5), } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) }) It("should fail for invalid for HTTPTokens", func() { - nc.Spec.MetadataOptions = &corev1.MetadataOptions{ + nc.Spec.MetadataOptions = &providerv1.MetadataOptions{ HTTPTokens: aws.String("test"), } Expect(env.Client.Create(ctx, nc)).ToNot(Succeed()) @@ -704,17 +704,17 @@ var _ = Describe("CEL/Validation", func() { }) Context("BlockDeviceMappings", func() { It("should succeed if more than one root volume is specified", func() { - nodeClass := &corev1.EC2NodeClass{ + nodeClass := &providerv1.EC2NodeClass{ ObjectMeta: coretest.ObjectMeta(metav1.ObjectMeta{}), - Spec: corev1.EC2NodeClassSpec{ + Spec: providerv1.EC2NodeClassSpec{ AMIFamily: nc.Spec.AMIFamily, SubnetSelectorTerms: nc.Spec.SubnetSelectorTerms, SecurityGroupSelectorTerms: nc.Spec.SecurityGroupSelectorTerms, Role: nc.Spec.Role, - BlockDeviceMappings: []*corev1.BlockDeviceMapping{ + BlockDeviceMappings: []*providerv1.BlockDeviceMapping{ { DeviceName: aws.String("map-device-1"), - EBS: &corev1.BlockDevice{ + EBS: &providerv1.BlockDevice{ VolumeSize: resource.NewScaledQuantity(500, resource.Giga), }, @@ -722,7 +722,7 @@ var _ = Describe("CEL/Validation", func() { }, { DeviceName: aws.String("map-device-2"), - EBS: &corev1.BlockDevice{ + EBS: &providerv1.BlockDevice{ VolumeSize: resource.NewScaledQuantity(50, resource.Tera), }, @@ -734,17 +734,17 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nodeClass)).To(Succeed()) }) It("should succeed for valid VolumeSize in G", func() { - nodeClass := &corev1.EC2NodeClass{ + nodeClass := &providerv1.EC2NodeClass{ ObjectMeta: coretest.ObjectMeta(metav1.ObjectMeta{}), - Spec: corev1.EC2NodeClassSpec{ + Spec: providerv1.EC2NodeClassSpec{ AMIFamily: nc.Spec.AMIFamily, SubnetSelectorTerms: nc.Spec.SubnetSelectorTerms, SecurityGroupSelectorTerms: nc.Spec.SecurityGroupSelectorTerms, Role: nc.Spec.Role, - BlockDeviceMappings: []*corev1.BlockDeviceMapping{ + BlockDeviceMappings: []*providerv1.BlockDeviceMapping{ { DeviceName: aws.String("map-device-1"), - EBS: &corev1.BlockDevice{ + EBS: &providerv1.BlockDevice{ VolumeSize: resource.NewScaledQuantity(58, resource.Giga), }, RootVolume: false, @@ -755,17 +755,17 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nodeClass)).To(Succeed()) }) It("should succeed for valid VolumeSize in T", func() { - nodeClass := &corev1.EC2NodeClass{ + nodeClass := &providerv1.EC2NodeClass{ ObjectMeta: coretest.ObjectMeta(metav1.ObjectMeta{}), - Spec: corev1.EC2NodeClassSpec{ + Spec: providerv1.EC2NodeClassSpec{ AMIFamily: nc.Spec.AMIFamily, SubnetSelectorTerms: nc.Spec.SubnetSelectorTerms, SecurityGroupSelectorTerms: nc.Spec.SecurityGroupSelectorTerms, Role: nc.Spec.Role, - BlockDeviceMappings: []*corev1.BlockDeviceMapping{ + BlockDeviceMappings: []*providerv1.BlockDeviceMapping{ { DeviceName: aws.String("map-device-1"), - EBS: &corev1.BlockDevice{ + EBS: &providerv1.BlockDevice{ VolumeSize: resource.NewScaledQuantity(45, resource.Tera), }, RootVolume: false, @@ -776,24 +776,24 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nodeClass)).To(Succeed()) }) It("should fail if more than one root volume is specified", func() { - nodeClass := &corev1.EC2NodeClass{ + nodeClass := &providerv1.EC2NodeClass{ ObjectMeta: coretest.ObjectMeta(metav1.ObjectMeta{}), - Spec: corev1.EC2NodeClassSpec{ + Spec: providerv1.EC2NodeClassSpec{ AMIFamily: nc.Spec.AMIFamily, SubnetSelectorTerms: nc.Spec.SubnetSelectorTerms, SecurityGroupSelectorTerms: nc.Spec.SecurityGroupSelectorTerms, Role: nc.Spec.Role, - BlockDeviceMappings: []*corev1.BlockDeviceMapping{ + BlockDeviceMappings: []*providerv1.BlockDeviceMapping{ { DeviceName: aws.String("map-device-1"), - EBS: &corev1.BlockDevice{ + EBS: &providerv1.BlockDevice{ VolumeSize: resource.NewScaledQuantity(50, resource.Giga), }, RootVolume: true, }, { DeviceName: aws.String("map-device-2"), - EBS: &corev1.BlockDevice{ + EBS: &providerv1.BlockDevice{ VolumeSize: resource.NewScaledQuantity(50, resource.Giga), }, RootVolume: true, @@ -804,17 +804,17 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nodeClass)).To(Not(Succeed())) }) It("should fail VolumeSize is less then 1Gi/1G", func() { - nodeClass := &corev1.EC2NodeClass{ + nodeClass := &providerv1.EC2NodeClass{ ObjectMeta: coretest.ObjectMeta(metav1.ObjectMeta{}), - Spec: corev1.EC2NodeClassSpec{ + Spec: providerv1.EC2NodeClassSpec{ AMIFamily: nc.Spec.AMIFamily, SubnetSelectorTerms: nc.Spec.SubnetSelectorTerms, SecurityGroupSelectorTerms: nc.Spec.SecurityGroupSelectorTerms, Role: nc.Spec.Role, - BlockDeviceMappings: []*corev1.BlockDeviceMapping{ + BlockDeviceMappings: []*providerv1.BlockDeviceMapping{ { DeviceName: aws.String("map-device-1"), - EBS: &corev1.BlockDevice{ + EBS: &providerv1.BlockDevice{ VolumeSize: resource.NewScaledQuantity(1, resource.Milli), }, RootVolume: false, @@ -825,17 +825,17 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nodeClass)).To(Not(Succeed())) }) It("should fail VolumeSize is greater then 64T", func() { - nodeClass := &corev1.EC2NodeClass{ + nodeClass := &providerv1.EC2NodeClass{ ObjectMeta: coretest.ObjectMeta(metav1.ObjectMeta{}), - Spec: corev1.EC2NodeClassSpec{ + Spec: providerv1.EC2NodeClassSpec{ AMIFamily: nc.Spec.AMIFamily, SubnetSelectorTerms: nc.Spec.SubnetSelectorTerms, SecurityGroupSelectorTerms: nc.Spec.SecurityGroupSelectorTerms, Role: nc.Spec.Role, - BlockDeviceMappings: []*corev1.BlockDeviceMapping{ + BlockDeviceMappings: []*providerv1.BlockDeviceMapping{ { DeviceName: aws.String("map-device-1"), - EBS: &corev1.BlockDevice{ + EBS: &providerv1.BlockDevice{ VolumeSize: resource.NewScaledQuantity(100, resource.Tera), }, RootVolume: false, @@ -846,17 +846,17 @@ var _ = Describe("CEL/Validation", func() { Expect(env.Client.Create(ctx, nodeClass)).To(Not(Succeed())) }) It("should fail for VolumeSize that do not parse into quantity values", func() { - nodeClass := &corev1.EC2NodeClass{ + nodeClass := &providerv1.EC2NodeClass{ ObjectMeta: coretest.ObjectMeta(metav1.ObjectMeta{}), - Spec: corev1.EC2NodeClassSpec{ + Spec: providerv1.EC2NodeClassSpec{ AMIFamily: nc.Spec.AMIFamily, SubnetSelectorTerms: nc.Spec.SubnetSelectorTerms, SecurityGroupSelectorTerms: nc.Spec.SecurityGroupSelectorTerms, Role: nc.Spec.Role, - BlockDeviceMappings: []*corev1.BlockDeviceMapping{ + BlockDeviceMappings: []*providerv1.BlockDeviceMapping{ { DeviceName: aws.String("map-device-1"), - EBS: &corev1.BlockDevice{ + EBS: &providerv1.BlockDevice{ VolumeSize: &resource.Quantity{}, }, RootVolume: false, diff --git a/pkg/apis/v1beta1/ec2nodeclass.go b/pkg/apis/v1beta1/ec2nodeclass.go index b3395dd3a60d..58b0b67acc34 100644 --- a/pkg/apis/v1beta1/ec2nodeclass.go +++ b/pkg/apis/v1beta1/ec2nodeclass.go @@ -318,7 +318,6 @@ const ( // EC2NodeClass is the Schema for the EC2NodeClass API // +kubebuilder:object:root=true -// +kubebuilder:storageversion // +kubebuilder:resource:path=ec2nodeclasses,scope=Cluster,categories=karpenter,shortName={ec2nc,ec2ncs} // +kubebuilder:subresource:status type EC2NodeClass struct { diff --git a/pkg/apis/v1beta1/ec2nodeclass_conversion.go b/pkg/apis/v1beta1/ec2nodeclass_conversion.go new file mode 100644 index 000000000000..b10d91cace27 --- /dev/null +++ b/pkg/apis/v1beta1/ec2nodeclass_conversion.go @@ -0,0 +1,27 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + + "knative.dev/pkg/apis" +) + +// Since v1 is the hub conversion version, We will only need to implement conversion webhooks for v1 + +func (in *EC2NodeClass) ConvertTo(ctx context.Context, to apis.Convertible) error { return nil } + +func (in *EC2NodeClass) ConvertFrom(ctx context.Context, from apis.Convertible) error { return nil } diff --git a/pkg/cloudprovider/cloudprovider.go b/pkg/cloudprovider/cloudprovider.go index e2edbd152410..6af3f79fd45f 100644 --- a/pkg/cloudprovider/cloudprovider.go +++ b/pkg/cloudprovider/cloudprovider.go @@ -172,7 +172,7 @@ func (c *CloudProvider) GetInstanceTypes(ctx context.Context, nodePool *corev1.N return nil, fmt.Errorf("resolving node class, %w", err) } // TODO, break this coupling - instanceTypes, err := c.instanceTypeProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + instanceTypes, err := c.instanceTypeProvider.List(ctx, nodeClass) if err != nil { return nil, err } @@ -252,7 +252,7 @@ func (c *CloudProvider) resolveNodeClassFromNodePool(ctx context.Context, nodePo } func (c *CloudProvider) resolveInstanceTypes(ctx context.Context, nodeClaim *corev1.NodeClaim, nodeClass *providerv1.EC2NodeClass) ([]*cloudprovider.InstanceType, error) { - instanceTypes, err := c.instanceTypeProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + instanceTypes, err := c.instanceTypeProvider.List(ctx, nodeClass) if err != nil { return nil, fmt.Errorf("getting instance types, %w", err) } diff --git a/pkg/cloudprovider/suite_test.go b/pkg/cloudprovider/suite_test.go index d72bc8709909..07f28f91051f 100644 --- a/pkg/cloudprovider/suite_test.go +++ b/pkg/cloudprovider/suite_test.go @@ -1118,7 +1118,7 @@ var _ = Describe("CloudProvider", func() { createFleetInput := awsEnv.EC2API.CreateFleetBehavior.CalledWithInput.Pop() Expect(fake.SubnetsFromFleetRequest(createFleetInput)).To(ConsistOf("test-subnet-2")) }) - FIt("should launch instances into subnet with the most available IP addresses in-between cache refreshes", func() { + It("should launch instances into subnet with the most available IP addresses in-between cache refreshes", func() { awsEnv.SubnetCache.Flush() awsEnv.EC2API.DescribeSubnetsOutput.Set(&ec2.DescribeSubnetsOutput{Subnets: []*ec2.Subnet{ {SubnetId: aws.String("test-subnet-1"), AvailabilityZone: aws.String("test-zone-1a"), AvailabilityZoneId: aws.String("tstz1-1a"), AvailableIpAddressCount: aws.Int64(10), diff --git a/pkg/controllers/providers/instancetype/suite_test.go b/pkg/controllers/providers/instancetype/suite_test.go index 6a2a77d4c5fe..cd0b476f2cc3 100644 --- a/pkg/controllers/providers/instancetype/suite_test.go +++ b/pkg/controllers/providers/instancetype/suite_test.go @@ -87,7 +87,7 @@ var _ = Describe("InstanceType", func() { }) ExpectSingletonReconciled(ctx, controller) - instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, &providerv1.KubeletConfiguration{}, &providerv1.EC2NodeClass{ + instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, &providerv1.EC2NodeClass{ Status: providerv1.EC2NodeClassStatus{ Subnets: []providerv1.Subnet{ { @@ -121,7 +121,7 @@ var _ = Describe("InstanceType", func() { }) ExpectSingletonReconciled(ctx, controller) - instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, &providerv1.KubeletConfiguration{}, &providerv1.EC2NodeClass{ + instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, &providerv1.EC2NodeClass{ Status: providerv1.EC2NodeClassStatus{ Subnets: []providerv1.Subnet{ { @@ -156,14 +156,14 @@ var _ = Describe("InstanceType", func() { awsEnv.EC2API.DescribeInstanceTypesOutput.Set(&ec2.DescribeInstanceTypesOutput{}) awsEnv.EC2API.DescribeInstanceTypeOfferingsOutput.Set(&ec2.DescribeInstanceTypeOfferingsOutput{}) ExpectSingletonReconciled(ctx, controller) - _, err := awsEnv.InstanceTypesProvider.List(ctx, &providerv1.KubeletConfiguration{}, &providerv1.EC2NodeClass{}) + _, err := awsEnv.InstanceTypesProvider.List(ctx, &providerv1.EC2NodeClass{}) Expect(err).ToNot(BeNil()) }) It("should not update instance type offering date with response from the DescribeInstanceTypesOfferings API", func() { awsEnv.EC2API.DescribeInstanceTypesOutput.Set(&ec2.DescribeInstanceTypesOutput{}) awsEnv.EC2API.DescribeInstanceTypeOfferingsOutput.Set(&ec2.DescribeInstanceTypeOfferingsOutput{}) ExpectSingletonReconciled(ctx, controller) - _, err := awsEnv.InstanceTypesProvider.List(ctx, &providerv1.KubeletConfiguration{}, &providerv1.EC2NodeClass{}) + _, err := awsEnv.InstanceTypesProvider.List(ctx, &providerv1.EC2NodeClass{}) Expect(err).ToNot(BeNil()) }) }) diff --git a/pkg/providers/instancetype/instancetype.go b/pkg/providers/instancetype/instancetype.go index 0dc21de0f0a5..8266531e1d84 100644 --- a/pkg/providers/instancetype/instancetype.go +++ b/pkg/providers/instancetype/instancetype.go @@ -49,7 +49,7 @@ import ( type Provider interface { LivenessProbe(*http.Request) error - List(context.Context, *providerv1.KubeletConfiguration, *providerv1.EC2NodeClass) ([]*cloudprovider.InstanceType, error) + List(context.Context, *providerv1.EC2NodeClass) ([]*cloudprovider.InstanceType, error) UpdateInstanceTypes(ctx context.Context) error UpdateInstanceTypeOfferings(ctx context.Context) error } @@ -97,14 +97,14 @@ func NewDefaultProvider(region string, instanceTypesCache *cache.Cache, ec2api e } } -func (p *DefaultProvider) List(ctx context.Context, kc *providerv1.KubeletConfiguration, nodeClass *providerv1.EC2NodeClass) ([]*cloudprovider.InstanceType, error) { +func (p *DefaultProvider) List(ctx context.Context, nodeClass *providerv1.EC2NodeClass) ([]*cloudprovider.InstanceType, error) { p.muInstanceTypeInfo.RLock() p.muInstanceTypeOfferings.RLock() defer p.muInstanceTypeInfo.RUnlock() defer p.muInstanceTypeOfferings.RUnlock() - if kc == nil { - kc = &providerv1.KubeletConfiguration{} + if nodeClass.Spec.Kubelet == nil { + nodeClass.Spec.Kubelet = &providerv1.KubeletConfiguration{} } if len(p.instanceTypesInfo) == 0 { return nil, fmt.Errorf("no instance types found") @@ -122,7 +122,7 @@ func (p *DefaultProvider) List(ctx context.Context, kc *providerv1.KubeletConfig // Compute fully initialized instance types hash key subnetZonesHash, _ := hashstructure.Hash(subnetZones, hashstructure.FormatV2, &hashstructure.HashOptions{SlicesAsSets: true}) - kcHash, _ := hashstructure.Hash(kc, hashstructure.FormatV2, &hashstructure.HashOptions{SlicesAsSets: true}) + kcHash, _ := hashstructure.Hash(nodeClass.Spec.Kubelet, hashstructure.FormatV2, &hashstructure.HashOptions{SlicesAsSets: true}) blockDeviceMappingsHash, _ := hashstructure.Hash(nodeClass.Spec.BlockDeviceMappings, hashstructure.FormatV2, &hashstructure.HashOptions{SlicesAsSets: true}) key := fmt.Sprintf("%d-%d-%d-%016x-%016x-%016x-%s-%s", p.instanceTypesSeqNum, @@ -166,7 +166,7 @@ func (p *DefaultProvider) List(ctx context.Context, kc *providerv1.KubeletConfig // !!! Important !!! return NewInstanceType(ctx, i, p.region, nodeClass.Spec.BlockDeviceMappings, nodeClass.Spec.InstanceStorePolicy, - kc.MaxPods, kc.PodsPerCore, kc.KubeReserved, kc.SystemReserved, kc.EvictionHard, kc.EvictionSoft, + nodeClass.Spec.Kubelet.MaxPods, nodeClass.Spec.Kubelet.PodsPerCore, nodeClass.Spec.Kubelet.KubeReserved, nodeClass.Spec.Kubelet.SystemReserved, nodeClass.Spec.Kubelet.EvictionHard, nodeClass.Spec.Kubelet.EvictionSoft, amiFamily, p.createOfferings(ctx, i, allZones, p.instanceTypeOfferings[aws.StringValue(i.InstanceType)], nodeClass.Status.Subnets), ) }) diff --git a/pkg/providers/instancetype/suite_test.go b/pkg/providers/instancetype/suite_test.go index 8d56c246b720..6393e088b420 100644 --- a/pkg/providers/instancetype/suite_test.go +++ b/pkg/providers/instancetype/suite_test.go @@ -35,6 +35,7 @@ import ( "github.com/samber/lo" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/record" clock "k8s.io/utils/clock/testing" @@ -953,7 +954,7 @@ var _ = Describe("InstanceTypeProvider", func() { }) Context("Metrics", func() { It("should expose vcpu metrics for instance types", func() { - instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass) Expect(err).To(BeNil()) Expect(len(instanceTypes)).To(BeNumerically(">", 0)) for _, it := range instanceTypes { @@ -967,7 +968,7 @@ var _ = Describe("InstanceTypeProvider", func() { } }) It("should expose memory metrics for instance types", func() { - instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass) Expect(err).To(BeNil()) Expect(len(instanceTypes)).To(BeNumerically(">", 0)) for _, it := range instanceTypes { @@ -981,7 +982,7 @@ var _ = Describe("InstanceTypeProvider", func() { } }) It("should expose availability metrics for instance types", func() { - instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass) Expect(err).To(BeNil()) Expect(len(instanceTypes)).To(BeNumerically(">", 0)) for _, it := range instanceTypes { @@ -999,7 +1000,7 @@ var _ = Describe("InstanceTypeProvider", func() { } }) It("should expose pricing metrics for instance types", func() { - instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass) Expect(err).To(BeNil()) Expect(len(instanceTypes)).To(BeNumerically(">", 0)) for _, it := range instanceTypes { @@ -2321,14 +2322,22 @@ var _ = Describe("InstanceTypeProvider", func() { SystemReserved: map[string]string{string(v1.ResourceCPU): "1"}, EvictionHard: map[string]string{"memory.available": "5%"}, EvictionSoft: map[string]string{"nodefs.available": "10%"}, - MaxPods: aws.Int32(10), + EvictionSoftGracePeriod: map[string]metav1.Duration{ + "nodefs.available": metav1.Duration{Duration: time.Minute}, + }, + MaxPods: aws.Int32(10), } kubeletChanges := []*providerv1.KubeletConfiguration{ {}, // Testing the base case black EC2NodeClass {KubeReserved: map[string]string{string(v1.ResourceCPU): "20"}}, {SystemReserved: map[string]string{string(v1.ResourceMemory): "10Gi"}}, {EvictionHard: map[string]string{"memory.available": "52%"}}, - {EvictionSoft: map[string]string{"nodefs.available": "132%"}}, + { + EvictionSoft: map[string]string{"nodefs.available": "132%"}, + EvictionSoftGracePeriod: map[string]metav1.Duration{ + "nodefs.available": metav1.Duration{Duration: time.Minute}, + }, + }, {MaxPods: aws.Int32(20)}, } var instanceTypeResult [][]*corecloudprovider.InstanceType @@ -2345,10 +2354,10 @@ var _ = Describe("InstanceTypeProvider", func() { nodePool = sorted.DeepCopy() Expect(mergo.Merge(nodeClass.Spec.Kubelet, change, mergo.WithOverride, mergo.WithSliceDeepCopy)).To(BeNil()) // Calling the provider and storing the instance type list to the instancetype provider cache - _, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + _, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass) Expect(err).To(BeNil()) // We are making sure to pull from the cache - instancetypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + instancetypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass) Expect(err).To(BeNil()) sort.Slice(instancetypes, func(x int, y int) bool { return instancetypes[x].Name < instancetypes[y].Name @@ -2420,10 +2429,10 @@ var _ = Describe("InstanceTypeProvider", func() { nodeClass = sorted.DeepCopy() Expect(mergo.Merge(nodeClass, change, mergo.WithOverride)).To(BeNil()) // Calling the provider and storing the instance type list to the instancetype provider cache - _, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + _, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass) Expect(err).To(BeNil()) // We are making sure to pull from the cache - instanetypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass.Spec.Kubelet, nodeClass) + instanetypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass) Expect(err).To(BeNil()) sort.Slice(instanetypes, func(x int, y int) bool { return instanetypes[x].Name < instanetypes[y].Name @@ -2444,7 +2453,7 @@ var _ = Describe("InstanceTypeProvider", func() { go func() { defer wg.Done() defer GinkgoRecover() - instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, &providerv1.KubeletConfiguration{}, nodeClass) + instanceTypes, err := awsEnv.InstanceTypesProvider.List(ctx, nodeClass) Expect(err).ToNot(HaveOccurred()) // Sort everything in parallel and ensure that we don't get data races diff --git a/pkg/providers/launchtemplate/suite_test.go b/pkg/providers/launchtemplate/suite_test.go index 03be7764db23..c2067f2230c7 100644 --- a/pkg/providers/launchtemplate/suite_test.go +++ b/pkg/providers/launchtemplate/suite_test.go @@ -216,8 +216,8 @@ var _ = Describe("LaunchTemplate Provider", func() { }, NodeClassRef: &corev1.NodeClassReference{ Group: object.GVK(nodeClass2).Group, - Kind: object.GVK(nodeClass2).Kind, - Name: nodeClass2.Name, + Kind: object.GVK(nodeClass2).Kind, + Name: nodeClass2.Name, }, }, }, @@ -1423,7 +1423,6 @@ var _ = Describe("LaunchTemplate Provider", func() { ExpectNotScheduled(ctx, env.Client, pod) }) It("should override system reserved values in user data", func() { - ExpectApplied(ctx, env.Client, nodeClass) nodeClass.Spec.Kubelet = &providerv1.KubeletConfiguration{ SystemReserved: map[string]string{ string(v1.ResourceCPU): "2", @@ -1431,7 +1430,7 @@ var _ = Describe("LaunchTemplate Provider", func() { string(v1.ResourceEphemeralStorage): "10Gi", }, } - ExpectApplied(ctx, env.Client, nodePool) + ExpectApplied(ctx, env.Client, nodePool, nodeClass) pod := coretest.UnschedulablePod() ExpectProvisioned(ctx, env.Client, cluster, cloudProvider, prov, pod) ExpectScheduled(ctx, env.Client, pod) @@ -1448,7 +1447,6 @@ var _ = Describe("LaunchTemplate Provider", func() { }) }) It("should override kube reserved values in user data", func() { - ExpectApplied(ctx, env.Client, nodeClass) nodeClass.Spec.Kubelet = &providerv1.KubeletConfiguration{ KubeReserved: map[string]string{ string(v1.ResourceCPU): "2", @@ -1456,7 +1454,7 @@ var _ = Describe("LaunchTemplate Provider", func() { string(v1.ResourceEphemeralStorage): "10Gi", }, } - ExpectApplied(ctx, env.Client, nodePool) + ExpectApplied(ctx, env.Client, nodePool, nodeClass) pod := coretest.UnschedulablePod() ExpectProvisioned(ctx, env.Client, cluster, cloudProvider, prov, pod) ExpectScheduled(ctx, env.Client, pod) @@ -1473,7 +1471,6 @@ var _ = Describe("LaunchTemplate Provider", func() { }) }) It("should override kube reserved values in user data", func() { - ExpectApplied(ctx, env.Client, nodeClass) nodeClass.Spec.Kubelet = &providerv1.KubeletConfiguration{ EvictionHard: map[string]string{ "memory.available": "10%", @@ -1481,7 +1478,7 @@ var _ = Describe("LaunchTemplate Provider", func() { "nodefs.inodesFree": "5%", }, } - ExpectApplied(ctx, env.Client, nodePool) + ExpectApplied(ctx, env.Client, nodePool, nodeClass) pod := coretest.UnschedulablePod() ExpectProvisioned(ctx, env.Client, cluster, cloudProvider, prov, pod) ExpectScheduled(ctx, env.Client, pod) diff --git a/pkg/webhooks/webhooks.go b/pkg/webhooks/webhooks.go index feb627d89de1..76d2d2f140b2 100644 --- a/pkg/webhooks/webhooks.go +++ b/pkg/webhooks/webhooks.go @@ -22,12 +22,29 @@ import ( "knative.dev/pkg/controller" knativeinjection "knative.dev/pkg/injection" "knative.dev/pkg/webhook/resourcesemantics" + "knative.dev/pkg/webhook/resourcesemantics/conversion" "knative.dev/pkg/webhook/resourcesemantics/defaulting" "knative.dev/pkg/webhook/resourcesemantics/validation" + v1 "github.com/aws/karpenter-provider-aws/pkg/apis/v1" + "github.com/aws/karpenter-provider-aws/pkg/apis/v1beta1" "github.com/awslabs/operatorpkg/object" +) - "github.com/aws/karpenter-provider-aws/pkg/apis/v1beta1" +var ( + Resources = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ + object.GVK(&v1beta1.EC2NodeClass{}): &v1beta1.EC2NodeClass{}, + } + ConversionResource = map[schema.GroupKind]conversion.GroupKindConversion{ + object.GVK(&v1.EC2NodeClass{}).GroupKind(): { + DefinitionName: "ec2nodeclasses.karpenter.k8s.aws", + HubVersion: "v1", + Zygotes: map[string]conversion.ConvertibleObject{ + "v1": &v1.EC2NodeClass{}, + "v1beta1": &v1beta1.EC2NodeClass{}, + }, + }, + } ) func NewWebhooks() []knativeinjection.ControllerConstructor { @@ -57,6 +74,10 @@ func NewCRDValidationWebhook(ctx context.Context, _ configmap.Watcher) *controll ) } -var Resources = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ - object.GVK(&v1beta1.EC2NodeClass{}): &v1beta1.EC2NodeClass{}, +func NewCRDConversionWebhook(ctx context.Context, _ configmap.Watcher) *controller.Impl { + return conversion.NewConversionController(ctx, + "/conversion/karpenter.sh", + ConversionResource, + func(ctx context.Context) context.Context { return ctx }, + ) } diff --git a/test/pkg/debug/node.go b/test/pkg/debug/node.go index 1e030f42db10..170a23362940 100644 --- a/test/pkg/debug/node.go +++ b/test/pkg/debug/node.go @@ -29,7 +29,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/karpenter/pkg/apis/v1beta1" + corev1 "sigs.k8s.io/karpenter/pkg/apis/v1" nodeutils "sigs.k8s.io/karpenter/pkg/utils/node" ) @@ -58,7 +58,7 @@ func (c *NodeController) Reconcile(ctx context.Context, req reconcile.Request) ( func (c *NodeController) GetInfo(ctx context.Context, n *v1.Node) string { pods, _ := nodeutils.GetPods(ctx, c.kubeClient, n) - return fmt.Sprintf("ready=%s schedulable=%t initialized=%s pods=%d taints=%v", nodeutils.GetCondition(n, v1.NodeReady).Status, !n.Spec.Unschedulable, n.Labels[v1beta1.NodeInitializedLabelKey], len(pods), n.Spec.Taints) + return fmt.Sprintf("ready=%s schedulable=%t initialized=%s pods=%d taints=%v", nodeutils.GetCondition(n, v1.NodeReady).Status, !n.Spec.Unschedulable, n.Labels[corev1.NodeInitializedLabelKey], len(pods), n.Spec.Taints) } func (c *NodeController) Register(ctx context.Context, m manager.Manager) error { @@ -74,7 +74,7 @@ func (c *NodeController) Register(ctx context.Context, m manager.Manager) error }, }, predicate.NewPredicateFuncs(func(o client.Object) bool { - return o.GetLabels()[v1beta1.NodePoolLabelKey] != "" + return o.GetLabels()[corev1.NodePoolLabelKey] != "" }), )). WithOptions(controller.Options{MaxConcurrentReconciles: 10}). diff --git a/test/suites/integration/launch_template_test.go b/test/suites/integration/launch_template_test.go index 41f602105ad7..c39991a00448 100644 --- a/test/suites/integration/launch_template_test.go +++ b/test/suites/integration/launch_template_test.go @@ -21,7 +21,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" coretest "sigs.k8s.io/karpenter/pkg/test" - "github.com/aws/karpenter-provider-aws/pkg/apis/v1beta1" + providerv1 "github.com/aws/karpenter-provider-aws/pkg/apis/v1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -38,7 +38,7 @@ var _ = Describe("Launch Template Deletion", func() { Eventually(func(g Gomega) { output, _ := env.EC2API.DescribeLaunchTemplatesWithContext(env.Context, &ec2.DescribeLaunchTemplatesInput{ Filters: []*ec2.Filter{ - {Name: aws.String(fmt.Sprintf("tag:%s", v1beta1.LabelNodeClass)), Values: []*string{aws.String(nodeClass.Name)}}, + {Name: aws.String(fmt.Sprintf("tag:%s", providerv1.LabelNodeClass)), Values: []*string{aws.String(nodeClass.Name)}}, }, }) g.Expect(output.LaunchTemplates).To(HaveLen(0)) diff --git a/test/suites/integration/utilization_test.go b/test/suites/integration/utilization_test.go index 39a8bd3326aa..6ad9031617b3 100644 --- a/test/suites/integration/utilization_test.go +++ b/test/suites/integration/utilization_test.go @@ -27,7 +27,7 @@ import ( "github.com/samber/lo" - "github.com/aws/karpenter-provider-aws/pkg/apis/v1beta1" + providerv1 "github.com/aws/karpenter-provider-aws/pkg/apis/v1" "github.com/aws/karpenter-provider-aws/test/pkg/debug" . "github.com/onsi/ginkgo/v2" @@ -45,7 +45,7 @@ var _ = Describe("Utilization", Label(debug.NoWatch), Label(debug.NoEvents), fun }, corev1.NodeSelectorRequirementWithMinValues{ NodeSelectorRequirement: v1.NodeSelectorRequirement{ - Key: v1beta1.LabelInstanceCategory, + Key: providerv1.LabelInstanceCategory, Operator: v1.NodeSelectorOpExists, }, }, diff --git a/test/suites/nodeclaim/garbage_collection_test.go b/test/suites/nodeclaim/garbage_collection_test.go index 4da125047cc1..6b4b5973c316 100644 --- a/test/suites/nodeclaim/garbage_collection_test.go +++ b/test/suites/nodeclaim/garbage_collection_test.go @@ -25,10 +25,10 @@ import ( "github.com/samber/lo" v1 "k8s.io/api/core/v1" - corev1 "sigs.k8s.io/karpenter/pkg/apis/v1beta1" + corev1 "sigs.k8s.io/karpenter/pkg/apis/v1" coretest "sigs.k8s.io/karpenter/pkg/test" - "github.com/aws/karpenter-provider-aws/pkg/apis/v1beta1" + providerv1 "github.com/aws/karpenter-provider-aws/pkg/apis/v1" awserrors "github.com/aws/karpenter-provider-aws/pkg/errors" "github.com/aws/karpenter-provider-aws/pkg/utils" environmentaws "github.com/aws/karpenter-provider-aws/test/pkg/environment/aws" @@ -86,7 +86,7 @@ var _ = Describe("GarbageCollection", func() { Value: aws.String(nodePool.Name), }, { - Key: aws.String(v1beta1.LabelNodeClass), + Key: aws.String(providerv1.LabelNodeClass), Value: aws.String(nodeClass.Name), }, },