@@ -2996,6 +2996,285 @@ func TestAWSMachineReconcilerReconcileDefaultsToLoadBalancerTypeClassic(t *testi
29962996 g .Expect (err ).To (BeNil ())
29972997}
29982998
2999+ func TestAWSMachineReconcilerReconcileDoesntAddSecurityGroupsToNonManagedNetworkInterfaces (t * testing.T ) {
3000+ g := NewWithT (t )
3001+
3002+ ns := "testns"
3003+
3004+ cp := & kubeadmv1beta1.KubeadmControlPlane {}
3005+ cp .SetName ("capi-cp-test-1" )
3006+ cp .SetNamespace (ns )
3007+
3008+ ownerCluster := & clusterv1.Cluster {
3009+ ObjectMeta : metav1.ObjectMeta {Name : "capi-test-1" , Namespace : ns },
3010+ Spec : clusterv1.ClusterSpec {
3011+ InfrastructureRef : clusterv1.ContractVersionedObjectReference {
3012+ Kind : "AWSCluster" ,
3013+ Name : "capi-test-1" , // assuming same name
3014+ APIGroup : infrav1 .GroupVersion .Group ,
3015+ },
3016+ ControlPlaneRef : clusterv1.ContractVersionedObjectReference {
3017+ Kind : "KubeadmControlPlane" ,
3018+ Name : cp .Name ,
3019+ APIGroup : kubeadmv1beta1 .GroupVersion .Group ,
3020+ },
3021+ },
3022+ Status : clusterv1.ClusterStatus {
3023+ Initialization : clusterv1.ClusterInitializationStatus {
3024+ InfrastructureProvisioned : ptr .To (true ),
3025+ },
3026+ },
3027+ }
3028+
3029+ awsCluster := & infrav1.AWSCluster {
3030+ ObjectMeta : metav1.ObjectMeta {
3031+ Name : "capi-test-1" ,
3032+ Namespace : ns ,
3033+ OwnerReferences : []metav1.OwnerReference {
3034+ {
3035+ APIVersion : clusterv1 .GroupVersion .String (),
3036+ Kind : "Cluster" ,
3037+ Name : ownerCluster .Name ,
3038+ UID : "1" ,
3039+ },
3040+ },
3041+ },
3042+ Spec : infrav1.AWSClusterSpec {
3043+ ControlPlaneLoadBalancer : & infrav1.AWSLoadBalancerSpec {
3044+ Scheme : & infrav1 .ELBSchemeInternetFacing ,
3045+ // `LoadBalancerType` not set (i.e. empty string; must default to attaching instance to classic LB)
3046+ },
3047+ NetworkSpec : infrav1.NetworkSpec {
3048+ Subnets : infrav1.Subnets {
3049+ infrav1.SubnetSpec {
3050+ ID : "subnet-1" ,
3051+ IsPublic : false ,
3052+ },
3053+ infrav1.SubnetSpec {
3054+ IsPublic : false ,
3055+ },
3056+ },
3057+ },
3058+ },
3059+ Status : infrav1.AWSClusterStatus {
3060+ Ready : true ,
3061+ Network : infrav1.NetworkStatus {
3062+ SecurityGroups : map [infrav1.SecurityGroupRole ]infrav1.SecurityGroup {
3063+ infrav1 .SecurityGroupControlPlane : {
3064+ ID : "1" ,
3065+ },
3066+ infrav1 .SecurityGroupNode : {
3067+ ID : "2" ,
3068+ },
3069+ infrav1 .SecurityGroupLB : {
3070+ ID : "3" ,
3071+ },
3072+ },
3073+ },
3074+ },
3075+ }
3076+
3077+ ownerMachine := & clusterv1.Machine {
3078+ ObjectMeta : metav1.ObjectMeta {
3079+ Labels : map [string ]string {
3080+ clusterv1 .ClusterNameLabel : "capi-test-1" ,
3081+ clusterv1 .MachineControlPlaneLabel : "" , // control plane node so that controller tries to register it with LB
3082+ },
3083+ Name : "capi-test-machine" ,
3084+ Namespace : ns ,
3085+ },
3086+ Spec : clusterv1.MachineSpec {
3087+ ClusterName : "capi-test" ,
3088+ Bootstrap : clusterv1.Bootstrap {
3089+ DataSecretName : aws .String ("bootstrap-data" ),
3090+ },
3091+ },
3092+ }
3093+
3094+ awsMachine := & infrav1.AWSMachine {
3095+ ObjectMeta : metav1.ObjectMeta {
3096+ Name : "aws-test-7" ,
3097+ Namespace : ns ,
3098+ OwnerReferences : []metav1.OwnerReference {
3099+ {
3100+ APIVersion : clusterv1 .GroupVersion .String (),
3101+ Kind : "Machine" ,
3102+ Name : "capi-test-machine" ,
3103+ UID : "1" ,
3104+ },
3105+ },
3106+ },
3107+ Spec : infrav1.AWSMachineSpec {
3108+ InstanceType : "test" ,
3109+ ProviderID : aws .String ("aws://the-zone/two" ),
3110+ CloudInit : infrav1.CloudInit {
3111+ SecureSecretsBackend : infrav1 .SecretBackendSecretsManager ,
3112+ SecretPrefix : "prefix" ,
3113+ SecretCount : 1000 ,
3114+ },
3115+ },
3116+ Status : infrav1.AWSMachineStatus {
3117+ Conditions : clusterv1beta1.Conditions {
3118+ {
3119+ Type : "Paused" ,
3120+ Status : corev1 .ConditionFalse ,
3121+ Reason : "NotPaused" ,
3122+ },
3123+ },
3124+ },
3125+ }
3126+
3127+ controllerIdentity := & infrav1.AWSClusterControllerIdentity {
3128+ TypeMeta : metav1.TypeMeta {
3129+ Kind : string (infrav1 .ControllerIdentityKind ),
3130+ },
3131+ ObjectMeta : metav1.ObjectMeta {
3132+ Name : "default" ,
3133+ },
3134+ Spec : infrav1.AWSClusterControllerIdentitySpec {
3135+ AWSClusterIdentitySpec : infrav1.AWSClusterIdentitySpec {
3136+ AllowedNamespaces : & infrav1.AllowedNamespaces {},
3137+ },
3138+ },
3139+ }
3140+
3141+ secret := & corev1.Secret {
3142+ ObjectMeta : metav1.ObjectMeta {
3143+ Name : "bootstrap-data" ,
3144+ Namespace : ns ,
3145+ },
3146+ Data : map [string ][]byte {
3147+ "value" : []byte ("shell-script" ),
3148+ },
3149+ }
3150+
3151+ fakeClient := fake .NewClientBuilder ().WithObjects (ownerCluster , awsCluster , ownerMachine , awsMachine , controllerIdentity , secret , cp ).WithStatusSubresource (awsCluster , awsMachine ).Build ()
3152+
3153+ recorder := record .NewFakeRecorder (10 )
3154+ reconciler := & AWSMachineReconciler {
3155+ Client : fakeClient ,
3156+ Recorder : recorder ,
3157+ }
3158+
3159+ mockCtrl := gomock .NewController (t )
3160+ ec2Mock := mocks .NewMockEC2API (mockCtrl )
3161+ elbMock := mocks .NewMockELBAPI (mockCtrl )
3162+ secretMock := mock_services .NewMockSecretInterface (mockCtrl )
3163+
3164+ cs , err := getClusterScope (* awsCluster )
3165+ g .Expect (err ).To (BeNil ())
3166+
3167+ ec2Svc := ec2Service .NewService (cs )
3168+ ec2Svc .EC2Client = ec2Mock
3169+ reconciler .ec2ServiceFactory = func (scope scope.EC2Scope ) services.EC2Interface {
3170+ return ec2Svc
3171+ }
3172+
3173+ elbSvc := elbService .NewService (cs )
3174+ elbSvc .EC2Client = ec2Mock
3175+ elbSvc .ELBClient = elbMock
3176+ reconciler .elbServiceFactory = func (scope scope.ELBScope ) services.ELBInterface {
3177+ return elbSvc
3178+ }
3179+
3180+ reconciler .secretsManagerServiceFactory = func (clusterScope cloud.ClusterScoper ) services.SecretInterface {
3181+ return secretMock
3182+ }
3183+
3184+ ec2Mock .EXPECT ().DescribeInstances (context .TODO (), gomock .Eq (& ec2.DescribeInstancesInput {
3185+ InstanceIds : []string {"two" },
3186+ })).Return (& ec2.DescribeInstancesOutput {
3187+ Reservations : []ec2types.Reservation {
3188+ {
3189+ Instances : []ec2types.Instance {
3190+ {
3191+ InstanceId : aws .String ("two" ),
3192+ InstanceType : ec2types .InstanceTypeM5Large ,
3193+ SubnetId : aws .String ("subnet-1" ),
3194+ ImageId : aws .String ("ami-1" ),
3195+ State : & ec2types.InstanceState {
3196+ Name : ec2types .InstanceStateNameRunning ,
3197+ },
3198+ Placement : & ec2types.Placement {
3199+ AvailabilityZone : aws .String ("thezone" ),
3200+ },
3201+ MetadataOptions : & ec2types.InstanceMetadataOptionsResponse {
3202+ HttpEndpoint : ec2types .InstanceMetadataEndpointState (string (infrav1 .InstanceMetadataEndpointStateEnabled )),
3203+ HttpPutResponseHopLimit : aws .Int32 (1 ),
3204+ HttpTokens : ec2types .HttpTokensState (string (infrav1 .HTTPTokensStateOptional )),
3205+ InstanceMetadataTags : ec2types .InstanceMetadataTagsState (string (infrav1 .InstanceMetadataEndpointStateDisabled )),
3206+ },
3207+ },
3208+ },
3209+ },
3210+ },
3211+ }, nil )
3212+
3213+ // Must attach to a classic LB, not another type. Only these mock calls are therefore expected.
3214+ mockedCreateLBCalls (t , elbMock .EXPECT (), false )
3215+
3216+ ec2Mock .EXPECT ().DescribeNetworkInterfaces (context .TODO (), gomock .Eq (& ec2.DescribeNetworkInterfacesInput {Filters : []ec2types.Filter {
3217+ {
3218+ Name : aws .String ("attachment.instance-id" ),
3219+ Values : []string {"two" },
3220+ },
3221+ }})).Return (& ec2.DescribeNetworkInterfacesOutput {
3222+ NetworkInterfaces : []ec2types.NetworkInterface {
3223+ {
3224+ NetworkInterfaceId : aws .String ("eni-1" ),
3225+ Groups : []ec2types.GroupIdentifier {
3226+ {
3227+ GroupId : aws .String ("2" ),
3228+ },
3229+ {
3230+ GroupId : aws .String ("3" ),
3231+ },
3232+ {
3233+ GroupId : aws .String ("1" ),
3234+ },
3235+ },
3236+ TagSet : []ec2types.Tag {
3237+ {
3238+ Key : aws .String ("sigs.k8s.io/cluster-api-provider-aws/cluster/test-cluster" ),
3239+ Value : aws .String ("owned" ),
3240+ },
3241+ },
3242+ },
3243+ {
3244+ NetworkInterfaceId : aws .String ("eni-cilium" ),
3245+ Groups : []ec2types.GroupIdentifier {
3246+ {
3247+ GroupId : aws .String ("3" ),
3248+ },
3249+ },
3250+ TagSet : []ec2types.Tag {
3251+ {
3252+ Key : aws .String ("cilium-managed" ),
3253+ Value : aws .String ("true" ),
3254+ },
3255+ },
3256+ },
3257+ }}, nil ).MaxTimes (3 )
3258+ ec2Mock .EXPECT ().DescribeNetworkInterfaceAttribute (context .TODO (), gomock .Eq (& ec2.DescribeNetworkInterfaceAttributeInput {
3259+ NetworkInterfaceId : aws .String ("eni-1" ),
3260+ Attribute : ec2types .NetworkInterfaceAttributeGroupSet ,
3261+ })).Return (& ec2.DescribeNetworkInterfaceAttributeOutput {Groups : []ec2types.GroupIdentifier {{GroupId : aws .String ("3" )}}}, nil ).MaxTimes (1 )
3262+ ec2Mock .EXPECT ().DescribeNetworkInterfaceAttribute (context .TODO (), gomock .Eq (& ec2.DescribeNetworkInterfaceAttributeInput {
3263+ NetworkInterfaceId : aws .String ("eni-cilium" ),
3264+ Attribute : ec2types .NetworkInterfaceAttributeGroupSet ,
3265+ })).Return (& ec2.DescribeNetworkInterfaceAttributeOutput {Groups : []ec2types.GroupIdentifier {{GroupId : aws .String ("3" )}}}, nil ).MaxTimes (1 )
3266+ ec2Mock .EXPECT ().ModifyNetworkInterfaceAttribute (context .TODO (), gomock .Any ()).Times (1 )
3267+
3268+ _ , err = reconciler .Reconcile (ctx , ctrl.Request {
3269+ NamespacedName : client.ObjectKey {
3270+ Namespace : awsMachine .Namespace ,
3271+ Name : awsMachine .Name ,
3272+ },
3273+ })
3274+
3275+ g .Expect (err ).To (BeNil ())
3276+ }
3277+
29993278func createObject (g * WithT , obj client.Object , namespace string ) {
30003279 if obj .DeepCopyObject () != nil {
30013280 obj .SetNamespace (namespace )
0 commit comments