github.com/openshift/installer@v1.4.17/pkg/asset/imagebased/configimage/clusterconfiguration_test.go (about) 1 package configimage 2 3 import ( 4 "context" 5 "errors" 6 "os" 7 "testing" 8 9 "github.com/golang/mock/gomock" 10 "github.com/stretchr/testify/assert" 11 "sigs.k8s.io/yaml" 12 13 "github.com/openshift/installer/pkg/asset" 14 "github.com/openshift/installer/pkg/asset/installconfig" 15 "github.com/openshift/installer/pkg/asset/mock" 16 "github.com/openshift/installer/pkg/asset/password" 17 "github.com/openshift/installer/pkg/asset/tls" 18 "github.com/openshift/installer/pkg/types" 19 "github.com/openshift/installer/pkg/types/imagebased" 20 ) 21 22 const ( 23 testSSHKey = "ssh-rsa AAAAB3NzaC1y1LJe3zew1ghc= root@localhost.localdomain" 24 25 testSecret = `{"auths":{"cloud.openshift.com":{"auth":"b3BlUTA=","email":"test@redhat.com"}}}` //nolint:gosec // not real credentials 26 ) 27 28 func TestClusterConfiguration_Generate(t *testing.T) { 29 cases := []struct { 30 name string 31 dependencies []asset.Asset 32 33 expectedError string 34 expectedConfig *imagebased.SeedReconfiguration 35 }{ 36 { 37 name: "missing install config", 38 dependencies: []asset.Asset{ 39 clusterID(), 40 &InstallConfig{}, 41 kubeadminPassword(), 42 lbCertKey(), 43 localhostCertKey(), 44 serviceNetworkCertKey(), 45 adminKubeConfigCertKey(), 46 ingressCertKey(), 47 imageBasedConfig(), 48 }, 49 expectedError: "missing configuration or manifest file", 50 }, 51 { 52 name: "valid configuration", 53 dependencies: []asset.Asset{ 54 clusterID(), 55 kubeadminPassword(), 56 lbCertKey(), 57 localhostCertKey(), 58 serviceNetworkCertKey(), 59 adminKubeConfigCertKey(), 60 ingressCertKey(), 61 installConfig().build(), 62 imageBasedConfig(), 63 }, 64 65 expectedConfig: clusterConfiguration().build().Config, 66 }, 67 { 68 name: "valid configuration with proxy", 69 dependencies: []asset.Asset{ 70 clusterID(), 71 kubeadminPassword(), 72 lbCertKey(), 73 localhostCertKey(), 74 serviceNetworkCertKey(), 75 adminKubeConfigCertKey(), 76 ingressCertKey(), 77 installConfig().proxy(proxy()).build(), 78 imageBasedConfig(), 79 }, 80 81 expectedConfig: clusterConfiguration().proxy(proxy()).build().Config, 82 }, 83 { 84 name: "valid configuration with additionalTrustBundle, policyAlways without proxy", 85 dependencies: []asset.Asset{ 86 clusterID(), 87 kubeadminPassword(), 88 lbCertKey(), 89 localhostCertKey(), 90 serviceNetworkCertKey(), 91 adminKubeConfigCertKey(), 92 ingressCertKey(), 93 installConfig(). 94 additionalTrustBundle(testCert). 95 additionalTrustBundlePolicy(types.PolicyAlways).build(), 96 imageBasedConfig(), 97 }, 98 99 expectedConfig: clusterConfiguration().additionalTrustBundle(imagebased.AdditionalTrustBundle{ 100 UserCaBundle: testCert, 101 ProxyConfigmapBundle: testCert, 102 ProxyConfigmapName: "user-ca-bundle", 103 }).build().Config, 104 }, 105 { 106 name: "valid configuration with additionalTrustBundle, policyProxyOnly without proxy", 107 dependencies: []asset.Asset{ 108 clusterID(), 109 kubeadminPassword(), 110 lbCertKey(), 111 localhostCertKey(), 112 serviceNetworkCertKey(), 113 adminKubeConfigCertKey(), 114 ingressCertKey(), 115 installConfig().proxy(proxy()).additionalTrustBundle(testCert).build(), 116 imageBasedConfig(), 117 }, 118 119 expectedConfig: clusterConfiguration(). 120 proxy(proxy()). 121 additionalTrustBundle(imagebased.AdditionalTrustBundle{ 122 UserCaBundle: testCert, 123 }). 124 build().Config, 125 }, 126 { 127 name: "valid configuration with additionalTrustBundle with proxy", 128 dependencies: []asset.Asset{ 129 clusterID(), 130 kubeadminPassword(), 131 lbCertKey(), 132 localhostCertKey(), 133 serviceNetworkCertKey(), 134 adminKubeConfigCertKey(), 135 ingressCertKey(), 136 installConfig(). 137 proxy(proxy()). 138 additionalTrustBundle(testCert). 139 additionalTrustBundlePolicy(types.PolicyProxyOnly).build(), 140 imageBasedConfig(), 141 }, 142 143 expectedConfig: clusterConfiguration(). 144 proxy(proxy()). 145 additionalTrustBundle(imagebased.AdditionalTrustBundle{ 146 UserCaBundle: testCert, 147 ProxyConfigmapBundle: testCert, 148 ProxyConfigmapName: "user-ca-bundle", 149 }). 150 build().Config, 151 }, 152 } 153 for _, tc := range cases { 154 t.Run(tc.name, func(t *testing.T) { 155 parents := asset.Parents{} 156 parents.Add(tc.dependencies...) 157 158 asset := &ClusterConfiguration{} 159 err := asset.Generate(context.TODO(), parents) 160 161 if tc.expectedError != "" { 162 assert.Equal(t, tc.expectedError, err.Error()) 163 } else { 164 assert.NoError(t, err) 165 assert.Equal(t, tc.expectedConfig, asset.Config) 166 assert.NotEmpty(t, asset.Files()) 167 168 configFile := asset.Files()[0] 169 assert.Equal(t, "cluster-configuration/manifest.json", configFile.Filename) 170 171 var actualConfig imagebased.SeedReconfiguration 172 err = yaml.Unmarshal(configFile.Data, &actualConfig) 173 assert.NoError(t, err) 174 assert.Equal(t, *tc.expectedConfig, actualConfig) 175 } 176 }) 177 } 178 } 179 180 func TestClusterConfiguration_LoadedFromDisk(t *testing.T) { 181 cases := []struct { 182 name string 183 data string 184 fetchError error 185 186 expectedFound bool 187 expectedError string 188 expectedConfig *imagebased.SeedReconfiguration 189 }{ 190 { 191 name: "valid-config-file", 192 data: ` 193 { 194 "api_version": 1, 195 "base_domain": "testing.com", 196 "cluster_name": "ocp-ibi", 197 "cluster_id": "6065edc6-939c-4dc3-81c7-1c20d840d064", 198 "infra_id": "an-infra-id", 199 "release_registry": "quay.io", 200 "hostname": "somehostname", 201 "KubeconfigCryptoRetention": { 202 "KubeAPICrypto": { 203 "ServingCrypto": { 204 "localhost_signer_private_key": "localhost-key", 205 "service_network_signer_private_key": "service-network-key", 206 "loadbalancer_external_signer_private_key": "lb-key" 207 }, 208 "ClientAuthCrypto": { 209 "admin_ca_certificate": "admin-kubeconfig-cert" 210 } 211 }, 212 "IngresssCrypto": { 213 "ingress_ca": "ingress-key" 214 } 215 }, 216 "ssh_key": "ssh-rsa AAAAB3NzaC1y1LJe3zew1ghc= root@localhost.localdomain", 217 "kubeadmin_password_hash": "a-password-hash", 218 "raw_nm_state_config": "interfaces:\n- ipv4:\n address:\n - ip: 192.168.122.2\n prefix-length: 23\n dhcp: false\n enabled: true\n mac-address: \"00:00:00:00:00:00\"\n name: eth0\n state: up\n type: ethernet\n", 219 "pull_secret": "{\"auths\":{\"cloud.openshift.com\":{\"auth\":\"b3BlUTA=\",\"email\":\"test@redhat.com\"}}}", 220 "machine_network": "10.10.11.0/24" 221 }`, 222 223 expectedFound: true, 224 expectedConfig: clusterConfiguration().Config, 225 }, 226 { 227 name: "not-json", 228 data: `This is not a JSON file`, 229 230 expectedError: "failed to unmarshal cluster-configuration/manifest.json: invalid JSON syntax", 231 }, 232 { 233 name: "file-not-found", 234 fetchError: &os.PathError{Err: os.ErrNotExist}, 235 }, 236 { 237 name: "error-fetching-file", 238 fetchError: errors.New("fetch failed"), 239 240 expectedError: "failed to load cluster-configuration/manifest.json file: fetch failed", 241 }, 242 { 243 name: "unknown-field", 244 data: `{"some-unknown-field":"withsomevalue"}`, 245 246 expectedError: "failed to unmarshal cluster-configuration/manifest.json: unknown field \"some-unknown-field\"", 247 }, 248 } 249 for _, tc := range cases { 250 t.Run(tc.name, func(t *testing.T) { 251 mockCtrl := gomock.NewController(t) 252 defer mockCtrl.Finish() 253 254 fileFetcher := mock.NewMockFileFetcher(mockCtrl) 255 fileFetcher.EXPECT().FetchByName(clusterConfigurationFilename). 256 Return( 257 &asset.File{ 258 Filename: clusterConfigurationFilename, 259 Data: []byte(tc.data)}, 260 tc.fetchError, 261 ) 262 263 asset := &ClusterConfiguration{} 264 found, err := asset.Load(fileFetcher) 265 assert.Equal(t, tc.expectedFound, found, "unexpected found value returned from Load") 266 267 if tc.expectedError != "" { 268 assert.Equal(t, tc.expectedError, err.Error()) 269 } else { 270 assert.Equal(t, nil, err) 271 } 272 273 if tc.expectedFound { 274 assert.Equal(t, tc.expectedConfig, asset.Config, "unexpected Config in ClusterConfiguration") 275 } 276 }) 277 } 278 } 279 280 type ClusterConfigurationBuilder struct { 281 ClusterConfiguration 282 } 283 284 func (ccb *ClusterConfigurationBuilder) build() *ClusterConfiguration { 285 return &ccb.ClusterConfiguration 286 } 287 288 func (ccb *ClusterConfigurationBuilder) proxy(proxy *types.Proxy) *ClusterConfigurationBuilder { 289 ccb.ClusterConfiguration.Config.Proxy = proxy 290 return ccb 291 } 292 293 func (ccb *ClusterConfigurationBuilder) additionalTrustBundle(additionalTrustBundle imagebased.AdditionalTrustBundle) *ClusterConfigurationBuilder { 294 ccb.ClusterConfiguration.Config.AdditionalTrustBundle = additionalTrustBundle 295 return ccb 296 } 297 298 func clusterConfiguration() *ClusterConfigurationBuilder { 299 ccb := &ClusterConfigurationBuilder{} 300 301 cc := &ClusterConfiguration{} 302 303 clusterID := clusterID() 304 installConfig := installConfig().build() 305 imageBasedConfig := imageBasedConfig() 306 307 cc.Config = &imagebased.SeedReconfiguration{ 308 APIVersion: imagebased.SeedReconfigurationVersion, 309 BaseDomain: installConfig.Config.BaseDomain, 310 ClusterID: clusterID.UUID, 311 ClusterName: installConfig.ClusterName(), 312 Hostname: imageBasedConfig.Config.Hostname, 313 InfraID: clusterID.InfraID, 314 KubeadminPasswordHash: string(kubeadminPassword().PasswordHash), 315 PullSecret: installConfig.Config.PullSecret, 316 RawNMStateConfig: imageBasedConfig.Config.NetworkConfig.String(), 317 ReleaseRegistry: imageBasedConfig.Config.ReleaseRegistry, 318 SSHKey: installConfig.Config.SSHKey, 319 } 320 321 cc.Config.KubeconfigCryptoRetention = imagebased.KubeConfigCryptoRetention{ 322 KubeAPICrypto: imagebased.KubeAPICrypto{ 323 ServingCrypto: imagebased.ServingCrypto{ 324 LoadbalancerSignerPrivateKey: string(lbCertKey().Key()), 325 LocalhostSignerPrivateKey: string(localhostCertKey().Key()), 326 ServiceNetworkSignerPrivateKey: string(serviceNetworkCertKey().Key()), 327 }, 328 ClientAuthCrypto: imagebased.ClientAuthCrypto{ 329 AdminCACertificate: string(adminKubeConfigCertKey().Cert()), 330 }, 331 }, 332 IngresssCrypto: imagebased.IngresssCrypto{ 333 IngressCA: string(ingressCertKey().SelfSignedCertKey.Key()), 334 }, 335 } 336 337 cc.Config.MachineNetwork = installConfig.Config.Networking.MachineNetwork[0].CIDR.String() 338 339 ccb.ClusterConfiguration = *cc 340 return ccb 341 } 342 343 func clusterID() *ClusterID { 344 return &ClusterID{ 345 installconfig.ClusterID{ 346 UUID: "6065edc6-939c-4dc3-81c7-1c20d840d064", 347 InfraID: "an-infra-id", 348 }, 349 } 350 } 351 352 func proxy() *types.Proxy { 353 return &types.Proxy{ 354 HTTPProxy: "http://10.10.10.11:80", 355 HTTPSProxy: "http://my-lab-proxy.org:443", 356 NoProxy: "internal.com", 357 } 358 } 359 360 func kubeadminPassword() *password.KubeadminPassword { 361 return &password.KubeadminPassword{ 362 PasswordHash: []byte("a-password-hash"), 363 } 364 } 365 366 func lbCertKey() *tls.KubeAPIServerLBSignerCertKey { 367 return &tls.KubeAPIServerLBSignerCertKey{ 368 SelfSignedCertKey: tls.SelfSignedCertKey{ 369 CertKey: tls.CertKey{ 370 CertRaw: []byte("lb-cert"), 371 KeyRaw: []byte("lb-key"), 372 }, 373 }, 374 } 375 } 376 377 func localhostCertKey() *tls.KubeAPIServerLocalhostSignerCertKey { 378 return &tls.KubeAPIServerLocalhostSignerCertKey{ 379 SelfSignedCertKey: tls.SelfSignedCertKey{ 380 CertKey: tls.CertKey{ 381 CertRaw: []byte("localhost-cert"), 382 KeyRaw: []byte("localhost-key"), 383 }, 384 }, 385 } 386 } 387 388 func serviceNetworkCertKey() *tls.KubeAPIServerServiceNetworkSignerCertKey { 389 return &tls.KubeAPIServerServiceNetworkSignerCertKey{ 390 SelfSignedCertKey: tls.SelfSignedCertKey{ 391 CertKey: tls.CertKey{ 392 CertRaw: []byte("service-network-cert"), 393 KeyRaw: []byte("service-network-key"), 394 }, 395 }, 396 } 397 } 398 399 func adminKubeConfigCertKey() *tls.AdminKubeConfigSignerCertKey { 400 return &tls.AdminKubeConfigSignerCertKey{ 401 SelfSignedCertKey: tls.SelfSignedCertKey{ 402 CertKey: tls.CertKey{ 403 CertRaw: []byte("admin-kubeconfig-cert"), 404 KeyRaw: []byte("admin-kubeconfig-key"), 405 }, 406 }, 407 } 408 } 409 410 func ingressCertKey() *IngressOperatorSignerCertKey { 411 return &IngressOperatorSignerCertKey{ 412 SelfSignedCertKey: tls.SelfSignedCertKey{ 413 CertKey: tls.CertKey{ 414 CertRaw: []byte("ingress-cert"), 415 KeyRaw: []byte("ingress-key"), 416 }, 417 }, 418 } 419 } 420 421 type InstallConfigBuilder struct { 422 InstallConfig 423 } 424 425 func (icb *InstallConfigBuilder) build() *InstallConfig { 426 return &icb.InstallConfig 427 } 428 429 func (icb *InstallConfigBuilder) proxy(proxy *types.Proxy) *InstallConfigBuilder { 430 icb.InstallConfig.Config.Proxy = proxy 431 return icb 432 } 433 434 func (icb *InstallConfigBuilder) additionalTrustBundle(additionalTrustBundle string) *InstallConfigBuilder { 435 icb.InstallConfig.Config.AdditionalTrustBundle = additionalTrustBundle 436 return icb 437 } 438 439 func (icb *InstallConfigBuilder) additionalTrustBundlePolicy(policy types.PolicyType) *InstallConfigBuilder { 440 icb.InstallConfig.Config.AdditionalTrustBundlePolicy = policy 441 return icb 442 } 443 444 func installConfig() *InstallConfigBuilder { 445 return &InstallConfigBuilder{ 446 InstallConfig: *defaultInstallConfig(), 447 } 448 }