diff --git a/pkg/dependencies/factory.go b/pkg/dependencies/factory.go index 4a7a85fbdab36..885b11cf3ecb5 100644 --- a/pkg/dependencies/factory.go +++ b/pkg/dependencies/factory.go @@ -1046,8 +1046,12 @@ func (f *Factory) WithVSphereValidator() *Factory { if f.dependencies.VSphereValidator != nil { return nil } - - f.dependencies.VSphereValidator = vsphere.NewValidator(f.dependencies.Govc, &networkutils.DefaultNetClient{}, nil) + vb := vsphere.NewValidatorBuilder( + f.dependencies.Govc, + &networkutils.DefaultNetClient{}, + &vsphere.VMOMIClientBuilder{}, + ) + f.dependencies.VSphereValidator = vb.Build() return nil }) diff --git a/pkg/providers/vsphere/govmomiclient.go b/pkg/providers/vsphere/govmomiclient.go index 27fc03c9437cd..a35b5f81d3d70 100644 --- a/pkg/providers/vsphere/govmomiclient.go +++ b/pkg/providers/vsphere/govmomiclient.go @@ -22,9 +22,13 @@ type VMOMIClient struct { username string } -type NewVSphereClientCallable func(ctx context.Context, host string, username string, password string, insecure bool, datacenter string) (VSphereClient, error) +type VSphereClientBuilder interface { + Build(ctx context.Context, host string, username string, password string, insecure bool, datacenter string) (VSphereClient, error) +} + +type VMOMIClientBuilder struct{} -func NewVMOMIClient(ctx context.Context, host string, username string, password string, insecure bool, datacenter string) (*VMOMIClient, error) { +func (*VMOMIClientBuilder) Build(ctx context.Context, host string, username string, password string, insecure bool, datacenter string) (VSphereClient, error) { u, err := soap.ParseURL(host) u.User = url.UserPassword(username, password) if err != nil { diff --git a/pkg/providers/vsphere/validator.go b/pkg/providers/vsphere/validator.go index 70435332ef227..1c3addcf7c97b 100644 --- a/pkg/providers/vsphere/validator.go +++ b/pkg/providers/vsphere/validator.go @@ -30,21 +30,30 @@ type RequiredAccess struct { } type Validator struct { - govc ProviderGovcClient - netClient networkutils.NetClient - newVSphereClient NewVSphereClientCallable + govc ProviderGovcClient + netClient networkutils.NetClient + vSphereClientBuilder VSphereClientBuilder } -func NewValidator(govc ProviderGovcClient, netClient networkutils.NetClient, f NewVSphereClientCallable) *Validator { - if f == nil { - f = func(ctx context.Context, host string, username string, password string, insecure bool, datacenter string) (VSphereClient, error) { - return NewVMOMIClient(ctx, host, username, password, insecure, datacenter) - } - } +type validatorBuilder struct { + govc ProviderGovcClient + netClient networkutils.NetClient + vscb VSphereClientBuilder +} + +func NewValidatorBuilder(govc ProviderGovcClient, netClient networkutils.NetClient, vscb VSphereClientBuilder) *validatorBuilder { + return &validatorBuilder{govc, netClient, vscb} +} + +func (b *validatorBuilder) Build() *Validator { + return NewValidator(b.govc, b.netClient, b.vscb) +} + +func NewValidator(govc ProviderGovcClient, netClient networkutils.NetClient, vscb VSphereClientBuilder) *Validator { return &Validator{ - govc: govc, - netClient: netClient, - newVSphereClient: f, + govc: govc, + netClient: netClient, + vSphereClientBuilder: vscb, } } @@ -456,7 +465,7 @@ func (v *Validator) validateUserPrivs(ctx context.Context, spec *Spec, vuc *conf host := spec.datacenterConfig.Spec.Server datacenter := spec.datacenterConfig.Spec.Datacenter - vsc, err := v.newVSphereClient( + vsc, err := v.vSphereClientBuilder.Build( ctx, host, vuc.EksaVsphereCPUsername, @@ -501,7 +510,7 @@ func (v *Validator) validateCSIUserPrivs(ctx context.Context, spec *Spec, vuc *c host := spec.datacenterConfig.Spec.Server datacenter := spec.datacenterConfig.Spec.Datacenter - vsc, err := v.newVSphereClient( + vsc, err := v.vSphereClientBuilder.Build( ctx, host, vuc.EksaVsphereCSIUsername, @@ -529,7 +538,7 @@ func (v *Validator) validateCPUserPrivs(ctx context.Context, spec *Spec, vuc *co host := spec.datacenterConfig.Spec.Server datacenter := spec.datacenterConfig.Spec.Datacenter - vsc, err := v.newVSphereClient( + vsc, err := v.vSphereClientBuilder.Build( ctx, host, vuc.EksaVsphereCPUsername, diff --git a/pkg/providers/vsphere/vsphere.go b/pkg/providers/vsphere/vsphere.go index 1f2c352db7db8..ddb8b02d57135 100644 --- a/pkg/providers/vsphere/vsphere.go +++ b/pkg/providers/vsphere/vsphere.go @@ -142,8 +142,18 @@ type ClusterResourceSetManager interface { ForceUpdate(ctx context.Context, name, namespace string, managementCluster, workloadCluster *types.Cluster) error } +type ValidatorBuilder interface { + Build() *Validator +} + func NewProvider(datacenterConfig *v1alpha1.VSphereDatacenterConfig, machineConfigs map[string]*v1alpha1.VSphereMachineConfig, clusterConfig *v1alpha1.Cluster, providerGovcClient ProviderGovcClient, providerKubectlClient ProviderKubectlClient, writer filewriter.FileWriter, now types.NowFunc, skipIpCheck bool, resourceSetManager ClusterResourceSetManager) *vsphereProvider { - var validator *Validator = nil + netClient := &networkutils.DefaultNetClient{} + vb := NewValidatorBuilder( + providerGovcClient, + netClient, + &VMOMIClientBuilder{}, + ) + return NewProviderCustomNet( datacenterConfig, machineConfigs, @@ -151,15 +161,15 @@ func NewProvider(datacenterConfig *v1alpha1.VSphereDatacenterConfig, machineConf providerGovcClient, providerKubectlClient, writer, - &networkutils.DefaultNetClient{}, + netClient, now, skipIpCheck, resourceSetManager, - validator, + vb, ) } -func NewProviderCustomNet(datacenterConfig *v1alpha1.VSphereDatacenterConfig, machineConfigs map[string]*v1alpha1.VSphereMachineConfig, clusterConfig *v1alpha1.Cluster, providerGovcClient ProviderGovcClient, providerKubectlClient ProviderKubectlClient, writer filewriter.FileWriter, netClient networkutils.NetClient, now types.NowFunc, skipIpCheck bool, resourceSetManager ClusterResourceSetManager, validator *Validator) *vsphereProvider { +func NewProviderCustomNet(datacenterConfig *v1alpha1.VSphereDatacenterConfig, machineConfigs map[string]*v1alpha1.VSphereMachineConfig, clusterConfig *v1alpha1.Cluster, providerGovcClient ProviderGovcClient, providerKubectlClient ProviderKubectlClient, writer filewriter.FileWriter, netClient networkutils.NetClient, now types.NowFunc, skipIpCheck bool, resourceSetManager ClusterResourceSetManager, vb ValidatorBuilder) *vsphereProvider { var controlPlaneMachineSpec, etcdMachineSpec *v1alpha1.VSphereMachineConfigSpec if clusterConfig.Spec.ControlPlaneConfiguration.MachineGroupRef != nil && machineConfigs[clusterConfig.Spec.ControlPlaneConfiguration.MachineGroupRef.Name] != nil { controlPlaneMachineSpec = &machineConfigs[clusterConfig.Spec.ControlPlaneConfiguration.MachineGroupRef.Name].Spec @@ -173,9 +183,7 @@ func NewProviderCustomNet(datacenterConfig *v1alpha1.VSphereDatacenterConfig, ma } } - if validator == nil { - validator = NewValidator(providerGovcClient, netClient, nil) - } + validator := vb.Build() retrier := retrier.NewWithMaxRetries(maxRetries, backOffPeriod) return &vsphereProvider{ datacenterConfig: datacenterConfig, diff --git a/pkg/providers/vsphere/vsphere_test.go b/pkg/providers/vsphere/vsphere_test.go index e2d40af06489c..b4e1782a2173f 100644 --- a/pkg/providers/vsphere/vsphere_test.go +++ b/pkg/providers/vsphere/vsphere_test.go @@ -321,6 +321,8 @@ func newProviderTest(t *testing.T) *providerTest { ctrl := gomock.NewController(t) kubectl := mocks.NewMockProviderKubectlClient(ctrl) govc := mocks.NewMockProviderGovcClient(ctrl) + vscb, _ := newMockVSphereClientBuilder(ctrl) + vb := NewValidatorBuilder(govc, &DummyNetClient{}, vscb) resourceSetManager := mocks.NewMockClusterResourceSetManager(ctrl) clusterConfig := givenClusterConfig(t, testClusterConfigMainFilename) datacenterConfig := givenDatacenterConfig(t, testClusterConfigMainFilename) @@ -333,6 +335,7 @@ func newProviderTest(t *testing.T) *providerTest { govc, kubectl, resourceSetManager, + vb, ) return &providerTest{ WithT: NewWithT(t), @@ -402,20 +405,26 @@ func TestNewProvider(t *testing.T) { func newProviderWithKubectl(t *testing.T, datacenterConfig *v1alpha1.VSphereDatacenterConfig, machineConfigs map[string]*v1alpha1.VSphereMachineConfig, clusterConfig *v1alpha1.Cluster, kubectl ProviderKubectlClient) *vsphereProvider { ctrl := gomock.NewController(t) + govc := NewDummyProviderGovcClient() + vscb, _ := newMockVSphereClientBuilder(ctrl) + vb := NewValidatorBuilder(govc, &DummyNetClient{}, vscb) resourceSetManager := mocks.NewMockClusterResourceSetManager(ctrl) return newProvider( t, datacenterConfig, machineConfigs, clusterConfig, - NewDummyProviderGovcClient(), + govc, kubectl, resourceSetManager, + vb, ) } func newProviderWithGovc(t *testing.T, datacenterConfig *v1alpha1.VSphereDatacenterConfig, machineConfigs map[string]*v1alpha1.VSphereMachineConfig, clusterConfig *v1alpha1.Cluster, govc ProviderGovcClient) *vsphereProvider { ctrl := gomock.NewController(t) + vscb, _ := newMockVSphereClientBuilder(ctrl) + vb := NewValidatorBuilder(govc, &DummyNetClient{}, vscb) resourceSetManager := mocks.NewMockClusterResourceSetManager(ctrl) kubectl := mocks.NewMockProviderKubectlClient(ctrl) return newProvider( @@ -426,27 +435,42 @@ func newProviderWithGovc(t *testing.T, datacenterConfig *v1alpha1.VSphereDatacen govc, kubectl, resourceSetManager, + vb, ) } -func newProvider(t *testing.T, datacenterConfig *v1alpha1.VSphereDatacenterConfig, machineConfigs map[string]*v1alpha1.VSphereMachineConfig, clusterConfig *v1alpha1.Cluster, govc ProviderGovcClient, kubectl ProviderKubectlClient, resourceSetManager ClusterResourceSetManager) *vsphereProvider { - _, writer := test.NewWriter(t) - netClient := &DummyNetClient{} - ctrl := gomock.NewController(t) - vSphereClientCallable := func(ctx context.Context, host string, username string, password string, insecure bool, datacenter string) (VSphereClient, error) { - vsc := mocks.NewMockVSphereClient(ctrl) - vsc.EXPECT().Username().Return("foobar").AnyTimes() - - var privs []string - err := json.Unmarshal([]byte(config.VSphereAdminPrivsFile), &privs) - if err != nil { - return nil, err - } +type mockVSphereClientBuilder struct { + vsc *mocks.MockVSphereClient +} + +func (mvscb *mockVSphereClientBuilder) Build(ctx context.Context, host string, username string, password string, insecure bool, datacenter string) (VSphereClient, error) { + return mvscb.vsc, nil +} - vsc.EXPECT().GetPrivsOnEntity(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(privs, nil).AnyTimes() - return vsc, nil +func setDefaultVSphereClientMock(vsc *mocks.MockVSphereClient) error { + vsc.EXPECT().Username().Return("foobar").AnyTimes() + + var privs []string + err := json.Unmarshal([]byte(config.VSphereAdminPrivsFile), &privs) + if err != nil { + return err } - validator := NewValidator(govc, netClient, vSphereClientCallable) + + vsc.EXPECT().GetPrivsOnEntity(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(privs, nil).AnyTimes() + + return nil +} + +func newMockVSphereClientBuilder(ctrl *gomock.Controller) (VSphereClientBuilder, error) { + vsc := mocks.NewMockVSphereClient(ctrl) + err := setDefaultVSphereClientMock(vsc) + mvscb := mockVSphereClientBuilder{vsc} + return &mvscb, err +} + +func newProvider(t *testing.T, datacenterConfig *v1alpha1.VSphereDatacenterConfig, machineConfigs map[string]*v1alpha1.VSphereMachineConfig, clusterConfig *v1alpha1.Cluster, govc ProviderGovcClient, kubectl ProviderKubectlClient, resourceSetManager ClusterResourceSetManager, vb ValidatorBuilder) *vsphereProvider { + _, writer := test.NewWriter(t) + netClient := &DummyNetClient{} return NewProviderCustomNet( datacenterConfig, @@ -459,7 +483,7 @@ func newProvider(t *testing.T, datacenterConfig *v1alpha1.VSphereDatacenterConfi test.FakeNow, false, resourceSetManager, - validator, + vb, ) } @@ -939,8 +963,19 @@ func TestProviderGenerateCAPISpecForCreateWithBottlerocketAndExternalEtcd(t *tes machineConfigs := givenMachineConfigs(t, clusterSpecManifest) ctx := context.Background() govc := NewDummyProviderGovcClient() + vscb, _ := newMockVSphereClientBuilder(mockCtrl) + vb := NewValidatorBuilder(govc, &DummyNetClient{}, vscb) govc.osTag = bottlerocketOSTag - provider := newProvider(t, datacenterConfig, machineConfigs, clusterSpec.Cluster, govc, kubectl, resourceSetManager) + provider := newProvider( + t, + datacenterConfig, + machineConfigs, + clusterSpec.Cluster, + govc, + kubectl, + resourceSetManager, + vb, + ) if err := provider.SetupAndValidateCreateCluster(ctx, clusterSpec); err != nil { t.Fatalf("failed to setup and validate: %v", err) @@ -967,8 +1002,19 @@ func TestProviderGenerateDeploymentFileForBottleRocketWithMirrorConfig(t *testin machineConfigs := givenMachineConfigs(t, clusterSpecManifest) ctx := context.Background() govc := NewDummyProviderGovcClient() + vscb, _ := newMockVSphereClientBuilder(mockCtrl) + vb := NewValidatorBuilder(govc, &DummyNetClient{}, vscb) govc.osTag = bottlerocketOSTag - provider := newProvider(t, datacenterConfig, machineConfigs, clusterSpec.Cluster, govc, kubectl, resourceSetManager) + provider := newProvider( + t, + datacenterConfig, + machineConfigs, + clusterSpec.Cluster, + govc, + kubectl, + resourceSetManager, + vb, + ) if err := provider.SetupAndValidateCreateCluster(ctx, clusterSpec); err != nil { t.Fatalf("failed to setup and validate: %v", err) } @@ -995,7 +1041,18 @@ func TestProviderGenerateDeploymentFileForBottleRocketWithMirrorAndCertConfig(t ctx := context.Background() govc := NewDummyProviderGovcClient() govc.osTag = bottlerocketOSTag - provider := newProvider(t, datacenterConfig, machineConfigs, clusterSpec.Cluster, govc, kubectl, resourceSetManager) + vscb, _ := newMockVSphereClientBuilder(mockCtrl) + vb := NewValidatorBuilder(govc, &DummyNetClient{}, vscb) + provider := newProvider( + t, + datacenterConfig, + machineConfigs, + clusterSpec.Cluster, + govc, + kubectl, + resourceSetManager, + vb, + ) if err := provider.SetupAndValidateCreateCluster(ctx, clusterSpec); err != nil { t.Fatalf("failed to setup and validate: %v", err) }