From ef751a9235ea69adbf9893ec74cb8f058cde1fab Mon Sep 17 00:00:00 2001 From: Vincenzo Mauro Date: Wed, 4 Feb 2026 15:15:38 +0100 Subject: [PATCH] Add support for platform External in TNA clusters --- pkg/asset/machines/arbiter.go | 5 +- pkg/asset/machines/arbiter_test.go | 98 +++++++++++++--------- pkg/types/validation/installconfig.go | 4 +- pkg/types/validation/installconfig_test.go | 16 +++- 4 files changed, 77 insertions(+), 46 deletions(-) diff --git a/pkg/asset/machines/arbiter.go b/pkg/asset/machines/arbiter.go index e1c72ddfcd..5891f9c0e7 100644 --- a/pkg/asset/machines/arbiter.go +++ b/pkg/asset/machines/arbiter.go @@ -31,6 +31,7 @@ import ( "github.com/openshift/installer/pkg/asset/rhcos" "github.com/openshift/installer/pkg/types" baremetaltypes "github.com/openshift/installer/pkg/types/baremetal" + externaltypes "github.com/openshift/installer/pkg/types/external" nonetypes "github.com/openshift/installer/pkg/types/none" ibmcloudapi "github.com/openshift/machine-api-provider-ibmcloud/pkg/apis" ibmcloudprovider "github.com/openshift/machine-api-provider-ibmcloud/pkg/apis/ibmcloudprovider/v1" @@ -116,8 +117,8 @@ func (m *Arbiter) Generate(ctx context.Context, dependencies asset.Parents) erro if ic.Arbiter == nil { return nil } - if ic.Platform.Name() != baremetaltypes.Name && ic.Platform.Name() != nonetypes.Name { - return fmt.Errorf("only BareMetal and None platforms are supported for Arbiter deployments") + if ic.Platform.Name() != baremetaltypes.Name && ic.Platform.Name() != externaltypes.Name && ic.Platform.Name() != nonetypes.Name { + return fmt.Errorf("only BareMetal, External, and None platforms are supported for Arbiter deployments") } pool := *ic.Arbiter diff --git a/pkg/asset/machines/arbiter_test.go b/pkg/asset/machines/arbiter_test.go index 559a1ca4ef..7a5854c0e2 100644 --- a/pkg/asset/machines/arbiter_test.go +++ b/pkg/asset/machines/arbiter_test.go @@ -15,6 +15,7 @@ import ( "github.com/openshift/installer/pkg/types" awstypes "github.com/openshift/installer/pkg/types/aws" "github.com/openshift/installer/pkg/types/baremetal" + "github.com/openshift/installer/pkg/types/external" "github.com/openshift/installer/pkg/types/none" ) @@ -220,51 +221,66 @@ func TestArbiterInstallOnlyForBaremetal(t *testing.T) { arbiter := &Arbiter{} err := arbiter.Generate(context.Background(), parents) assert.NotNil(t, err, "expected arbiter generate to fail for non baremetal platforms") - assert.Contains(t, err.Error(), "only BareMetal and None platforms are supported for Arbiter deployments") + assert.Contains(t, err.Error(), "only BareMetal, External, and None platforms are supported for Arbiter deployments") } -func TestArbiterInstallNonePlatform(t *testing.T) { - parents := asset.Parents{} - installConfig := installconfig.MakeAsset( - &types.InstallConfig{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-cluster", - }, - SSHKey: "ssh-rsa: dummy-key", - BaseDomain: "test-domain", - Platform: types.Platform{ - None: &none.Platform{}, - }, - Arbiter: &types.MachinePool{ - Hyperthreading: types.HyperthreadingDisabled, - Replicas: ptr.To(int64(1)), - }, - }) - - parents.Add( - &installconfig.ClusterID{ - UUID: "test-uuid", - InfraID: "test-infra-id", +func TestArbiterInstallNoneExternalPlatforms(t *testing.T) { + cases := []struct { + name string + platform types.Platform + }{ + { + name: "None platform", + platform: types.Platform{None: &none.Platform{}}, }, - installConfig, - rhcos.MakeAsset("test-image"), - (*rhcos.Release)(ptr.To("412.86.202208101040-0")), - &machine.Arbiter{ - File: &asset.File{ - Filename: "arbiter-ignition", - Data: []byte("test-ignition"), - }, + { + name: "External platform", + platform: types.Platform{External: &external.Platform{}}, }, - ) - arbiter := &Arbiter{} - err := arbiter.Generate(context.Background(), parents) - assert.Nil(t, err, "expected arbiter generate to succeed for None platform") - // For None platform, no Machine API objects or BareMetalHost CRs should be generated - assert.Equal(t, 0, len(arbiter.MachineFiles), "expected no machine files for None platform") - assert.Equal(t, 0, len(arbiter.HostFiles), "expected no host files for None platform") - assert.Equal(t, 0, len(arbiter.SecretFiles), "expected no secret files for None platform") - // MachineConfigs should still be generated (hyperthreading disabled + SSH key) - assert.Greater(t, len(arbiter.MachineConfigFiles), 0, "expected machine config files for None platform") + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + parents := asset.Parents{} + installConfig := installconfig.MakeAsset( + &types.InstallConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + }, + SSHKey: "ssh-rsa: dummy-key", + BaseDomain: "test-domain", + Platform: tc.platform, + Arbiter: &types.MachinePool{ + Hyperthreading: types.HyperthreadingDisabled, + Replicas: ptr.To(int64(1)), + }, + }) + + parents.Add( + &installconfig.ClusterID{ + UUID: "test-uuid", + InfraID: "test-infra-id", + }, + installConfig, + rhcos.MakeAsset("test-image"), + (*rhcos.Release)(ptr.To("412.86.202208101040-0")), + &machine.Arbiter{ + File: &asset.File{ + Filename: "arbiter-ignition", + Data: []byte("test-ignition"), + }, + }, + ) + arbiter := &Arbiter{} + err := arbiter.Generate(context.Background(), parents) + assert.Nil(t, err, "expected arbiter generate to succeed for %s", tc.name) + // For non-baremetal platforms, no Machine API objects or BareMetalHost CRs should be generated + assert.Equal(t, 0, len(arbiter.MachineFiles), "expected no machine files for %s", tc.name) + assert.Equal(t, 0, len(arbiter.HostFiles), "expected no host files for %s", tc.name) + assert.Equal(t, 0, len(arbiter.SecretFiles), "expected no secret files for %s", tc.name) + // MachineConfigs should still be generated (hyperthreading disabled + SSH key) + assert.Greater(t, len(arbiter.MachineConfigFiles), 0, "expected machine config files for %s", tc.name) + }) + } } func TestArbiterIsNotModified(t *testing.T) { diff --git a/pkg/types/validation/installconfig.go b/pkg/types/validation/installconfig.go index fa7b9954ba..c8829b5c26 100644 --- a/pkg/types/validation/installconfig.go +++ b/pkg/types/validation/installconfig.go @@ -779,8 +779,8 @@ func validateControlPlane(installConfig *types.InstallConfig, fldPath *field.Pat func validateArbiter(platform *types.Platform, arbiterPool, masterPool *types.MachinePool, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} - if platform != nil && platform.BareMetal == nil && platform.None == nil { - allErrs = append(allErrs, field.NotSupported(fldPath.Child("platform"), platform.Name(), []string{baremetal.Name, none.Name})) + if platform != nil && platform.BareMetal == nil && platform.External == nil && platform.None == nil { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("platform"), platform.Name(), []string{baremetal.Name, external.Name, none.Name})) } if arbiterPool.Name != types.MachinePoolArbiterRoleName { allErrs = append(allErrs, field.NotSupported(fldPath.Child("name"), arbiterPool.Name, []string{types.MachinePoolArbiterRoleName})) diff --git a/pkg/types/validation/installconfig_test.go b/pkg/types/validation/installconfig_test.go index 3cdba4b3d8..1802e508bc 100644 --- a/pkg/types/validation/installconfig_test.go +++ b/pkg/types/validation/installconfig_test.go @@ -3232,6 +3232,20 @@ func TestValidateArbiter(t *testing.T) { name: "valid_platform_baremetal", expected: "", }, + { + config: installConfig(). + PlatformExternal(). + MachinePoolArbiter( + machinePool(). + Name("arbiter"). + Hyperthreading(types.HyperthreadingEnabled). + Architecture(types.ArchitectureAMD64)). + MachinePoolCP(machinePool()). + ArbiterReplicas(1). + CpReplicas(2).build(), + name: "valid_platform_external", + expected: "", + }, { config: installConfig(). PlatformAWS(). @@ -3243,7 +3257,7 @@ func TestValidateArbiter(t *testing.T) { ArbiterReplicas(1). CpReplicas(2).build(), name: "invalid_platform", - expected: `supported values: "baremetal", "none"`, + expected: `supported values: "baremetal", "external", "none"`, }, { config: installConfig().