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  }