github.com/openshift/installer@v1.4.17/pkg/asset/machines/aws/awsmachines_test.go (about) 1 // Package aws generates Machine objects for aws. 2 package aws 3 4 import ( 5 "fmt" 6 "strings" 7 "testing" 8 9 "github.com/google/go-cmp/cmp" 10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 "k8s.io/utils/ptr" 12 capa "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" 13 14 "github.com/openshift/installer/pkg/asset" 15 "github.com/openshift/installer/pkg/types" 16 awstypes "github.com/openshift/installer/pkg/types/aws" 17 ) 18 19 var stubMachineInputManagedVpc = &MachineInput{ 20 Role: "master", 21 Pool: &types.MachinePool{ 22 Name: "master", 23 Replicas: ptr.To(int64(3)), 24 Platform: types.MachinePoolPlatform{ 25 AWS: &awstypes.MachinePool{ 26 Zones: []string{"A", "B", "C"}, 27 }, 28 }, 29 }, 30 Subnets: make(map[string]string, 0), 31 Tags: capa.Tags{}, 32 PublicIP: false, 33 Ignition: &capa.Ignition{ 34 StorageType: capa.IgnitionStorageTypeOptionUnencryptedUserData, 35 }, 36 } 37 38 func stubDeepCopyMachineInput(in *MachineInput) *MachineInput { 39 out := &MachineInput{ 40 Role: in.Role, 41 PublicIP: in.PublicIP, 42 } 43 if in.Pool != nil { 44 out.Pool = &types.MachinePool{} 45 *out.Pool = *in.Pool 46 } 47 if len(in.Subnets) > 0 { 48 out.Subnets = make(map[string]string, len(in.Subnets)) 49 for k, v := range in.Subnets { 50 out.Subnets[k] = v 51 } 52 } 53 if len(in.Tags) > 0 { 54 out.Tags = in.Tags.DeepCopy() 55 } 56 if in.Ignition != nil { 57 out.Ignition = in.Ignition.DeepCopy() 58 } 59 return out 60 } 61 62 func stubGetMachineManagedVpc() *MachineInput { 63 return stubDeepCopyMachineInput(stubMachineInputManagedVpc) 64 } 65 66 func TestGenerateMachines(t *testing.T) { 67 stubClusterID := "vpc-zr2-m2" 68 tests := []struct { 69 name string 70 clusterID string 71 input *MachineInput 72 want []*asset.RuntimeFile 73 wantInfraFiles []*asset.RuntimeFile 74 wantErr string 75 }{ 76 { 77 name: "topology ha, managed vpc, default zones region, 2 zones A and B, 3 machines should be in A, B and A private subnet", 78 clusterID: stubClusterID, 79 input: func() *MachineInput { 80 in := stubGetMachineManagedVpc() 81 in.Pool.Platform.AWS.Zones = []string{"A", "B"} 82 return in 83 }(), 84 // generate 3 AWSMachine manifests for control plane nodes in two zones 85 wantInfraFiles: func() []*asset.RuntimeFile { 86 machineZoneMap := map[int]string{0: "A", 1: "B", 2: "A"} 87 infraMachineFiles := []*asset.RuntimeFile{} 88 for mid := 0; mid < 3; mid++ { 89 machineName := fmt.Sprintf("%s-%s-%d", stubClusterID, "master", mid) 90 machineZone := machineZoneMap[mid] 91 machine := &capa.AWSMachine{ 92 TypeMeta: metav1.TypeMeta{ 93 APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", 94 Kind: "AWSMachine", 95 }, 96 ObjectMeta: metav1.ObjectMeta{ 97 Name: machineName, 98 Labels: map[string]string{"cluster.x-k8s.io/control-plane": ""}, 99 }, 100 Spec: capa.AWSMachineSpec{ 101 InstanceMetadataOptions: &capa.InstanceMetadataOptions{ 102 HTTPEndpoint: capa.InstanceMetadataEndpointStateEnabled, 103 HTTPTokens: capa.HTTPTokensStateOptional, 104 }, 105 AMI: capa.AMIReference{ 106 ID: ptr.To(""), 107 }, 108 IAMInstanceProfile: fmt.Sprintf("%s-%s-profile", stubClusterID, "master"), 109 PublicIP: ptr.To(false), 110 Subnet: &capa.AWSResourceReference{ 111 Filters: []capa.Filter{{Name: "tag:Name", Values: []string{ 112 fmt.Sprintf("%s-subnet-private-%s", stubClusterID, machineZone), 113 }}}, 114 }, 115 SSHKeyName: ptr.To(""), 116 RootVolume: &capa.Volume{ 117 Encrypted: ptr.To(true), 118 }, 119 UncompressedUserData: ptr.To(true), 120 Ignition: &capa.Ignition{ 121 StorageType: capa.IgnitionStorageTypeOptionUnencryptedUserData, 122 }, 123 }, 124 } 125 infraMachineFiles = append(infraMachineFiles, &asset.RuntimeFile{ 126 File: asset.File{Filename: fmt.Sprintf("10_inframachine_%s.yaml", machineName)}, 127 Object: machine, 128 }) 129 } 130 return infraMachineFiles 131 }(), 132 }, 133 { 134 name: "topology ha, byo vpc, two zones subnets A and B, 3 machines should be in A, B and A private subnets", 135 clusterID: stubClusterID, 136 input: func() *MachineInput { 137 in := stubGetMachineManagedVpc() 138 in.Pool.Platform.AWS.Zones = []string{"A", "B"} 139 in.Subnets = map[string]string{"A": "subnet-id-A", "B": "subnet-id-B"} 140 return in 141 }(), 142 // generate 3 AWSMachine manifests for control plane nodes in two subnets/zones 143 wantInfraFiles: func() []*asset.RuntimeFile { 144 machineZoneMap := map[int]string{0: "subnet-id-A", 1: "subnet-id-B", 2: "subnet-id-A"} 145 infraMachineFiles := []*asset.RuntimeFile{} 146 for mid := 0; mid < 3; mid++ { 147 machineName := fmt.Sprintf("%s-%s-%d", stubClusterID, "master", mid) 148 machineSubnet := machineZoneMap[mid] 149 machine := &capa.AWSMachine{ 150 TypeMeta: metav1.TypeMeta{ 151 APIVersion: "infrastructure.cluster.x-k8s.io/v1beta2", 152 Kind: "AWSMachine", 153 }, 154 ObjectMeta: metav1.ObjectMeta{ 155 Name: machineName, 156 Labels: map[string]string{"cluster.x-k8s.io/control-plane": ""}, 157 }, 158 Spec: capa.AWSMachineSpec{ 159 InstanceMetadataOptions: &capa.InstanceMetadataOptions{ 160 HTTPEndpoint: capa.InstanceMetadataEndpointStateEnabled, 161 HTTPTokens: capa.HTTPTokensStateOptional, 162 }, 163 AMI: capa.AMIReference{ 164 ID: ptr.To(""), 165 }, 166 IAMInstanceProfile: fmt.Sprintf("%s-%s-profile", stubClusterID, "master"), 167 PublicIP: ptr.To(false), 168 Subnet: &capa.AWSResourceReference{ 169 ID: ptr.To(machineSubnet), 170 }, 171 SSHKeyName: ptr.To(""), 172 RootVolume: &capa.Volume{ 173 Encrypted: ptr.To(true), 174 }, 175 UncompressedUserData: ptr.To(true), 176 Ignition: &capa.Ignition{ 177 StorageType: capa.IgnitionStorageTypeOptionUnencryptedUserData, 178 }, 179 }, 180 } 181 infraMachineFiles = append(infraMachineFiles, &asset.RuntimeFile{ 182 File: asset.File{Filename: fmt.Sprintf("10_inframachine_%s.yaml", machineName)}, 183 Object: machine, 184 }) 185 } 186 return infraMachineFiles 187 }(), 188 }, 189 // Error's scenarios 190 { 191 name: "error topology ha, byo vpc, no subnet for zones", 192 clusterID: stubClusterID, 193 input: func() *MachineInput { 194 in := stubGetMachineManagedVpc() 195 in.Pool.Platform.AWS.Zones = []string{"A", "B"} 196 in.Subnets = map[string]string{"C": "subnet-id-C", "D": "subnet-id-D"} 197 return in 198 }(), 199 wantErr: `no subnet for zone A`, 200 }, 201 { 202 name: "error topology ha, managed vpc, empty subnet zone", 203 clusterID: stubClusterID, 204 input: func() *MachineInput { 205 in := stubGetMachineManagedVpc() 206 in.Pool.Platform.AWS.Zones = []string{"A", "B"} 207 in.Subnets = map[string]string{"A": "subnet-id-A", "B": ""} 208 return in 209 }(), 210 wantErr: `invalid subnet ID for zone B`, 211 }, 212 // TODO: add more use cases. 213 // { 214 // name: "managed vpc, default zones region, 5 zones A to E, 3 machines should be in A, B and C private subnet", 215 // }, 216 // { 217 // name: "managed vpc, default zones region, 5 zones A to E, 3 machines should be in A, B and C private subnet", 218 // }, 219 // { 220 // name: "byo vpc, 2 zones subnets A and B, 3 machines' subnet should be in A, B and A", 221 // }, 222 // { 223 // name: "managed vpc, default zones region, 5 zones A to E, bootstrap should be in zone A public subnet", 224 // }, 225 // { 226 // name: "topology ha, managed vpc, two zones subnets A and B, bootstrap node using public subnet A", 227 // }, 228 } 229 for _, tt := range tests { 230 t.Run(tt.name, func(t *testing.T) { 231 files, err := GenerateMachines(tt.clusterID, tt.input) 232 if err != nil { 233 if len(tt.wantErr) > 0 { 234 if got := err.Error(); !cmp.Equal(got, tt.wantErr) { 235 t.Errorf("GenerateMachines() unexpected error message: %v", cmp.Diff(got, tt.wantErr)) 236 } 237 return 238 } 239 t.Errorf("GenerateMachines() unexpected error: %v", err) 240 return 241 } 242 // TODO: support the CAPA v1beta1.Machine manifest check. 243 // Support only comparing manifest file for CAPA v1beta2.AWSMachine. 244 if len(tt.wantInfraFiles) > 0 { 245 got := []*asset.RuntimeFile{} 246 for _, file := range files { 247 if !strings.HasPrefix(file.Filename, "10_inframachine") { 248 continue 249 } 250 got = append(got, file) 251 } 252 if !cmp.Equal(got, tt.wantInfraFiles) { 253 t.Errorf("GenerateMachines() Got unexpected results:\n%v", cmp.Diff(got, tt.wantInfraFiles)) 254 } 255 } 256 }) 257 } 258 }