diff --git a/pkg/deployer/platform/detect/detect.go b/pkg/deployer/platform/detect/detect.go index 4519e6ad..12d9deb4 100644 --- a/pkg/deployer/platform/detect/detect.go +++ b/pkg/deployer/platform/detect/detect.go @@ -64,13 +64,18 @@ func Platform(ctx context.Context) (platform.Platform, error) { if err != nil { return platform.Unknown, err } - return PlatformFromLister(ctx, ocpCli.ConfigV1.ClusterVersions()) + return PlatformFromClients(ctx, ocpCli.ConfigV1.ClusterVersions(), ocpCli.ConfigV1.Infrastructures()) } type ClusterVersionsLister interface { List(ctx context.Context, opts metav1.ListOptions) (*ocpconfigv1.ClusterVersionList, error) } +type InfrastructuresGetter interface { + Get(ctx context.Context, name string, options metav1.GetOptions) (*ocpconfigv1.Infrastructure, error) +} + +// PlatformFromLister is deprecated, use PlatformFromClients instead func PlatformFromLister(ctx context.Context, cvLister ClusterVersionsLister) (platform.Platform, error) { vers, err := cvLister.List(ctx, metav1.ListOptions{}) if err != nil { @@ -85,6 +90,27 @@ func PlatformFromLister(ctx context.Context, cvLister ClusterVersionsLister) (pl return platform.Kubernetes, nil } +func PlatformFromClients(ctx context.Context, cvLister ClusterVersionsLister, infraGetter InfrastructuresGetter) (platform.Platform, error) { + vers, err := cvLister.List(ctx, metav1.ListOptions{}) + if err != nil { + if errors.IsNotFound(err) { + return platform.Kubernetes, nil + } + return platform.Unknown, err + } + if len(vers.Items) > 0 { + infra, err := infraGetter.Get(ctx, "cluster", metav1.GetOptions{}) + if err != nil { + return platform.Unknown, err + } + if infra.Status.ControlPlaneTopology == ocpconfigv1.ExternalTopologyMode { + return platform.HyperShift, nil + } + return platform.OpenShift, nil + } + return platform.Kubernetes, nil +} + func Version(ctx context.Context, plat platform.Platform) (platform.Version, error) { if plat == platform.OpenShift { return OpenshiftVersion(ctx) diff --git a/pkg/deployer/platform/detect/detect_test.go b/pkg/deployer/platform/detect/detect_test.go index 5cbf424d..17a8bc9f 100644 --- a/pkg/deployer/platform/detect/detect_test.go +++ b/pkg/deployer/platform/detect/detect_test.go @@ -38,6 +38,58 @@ func TestPlatformFromLister(t *testing.T) { expectedPlatform platform.Platform expectedError error } + unexpectedError := fmt.Errorf("unexpected error") + testCases := []testCase{ + { + name: "unexpected error", + err: unexpectedError, + expectedError: unexpectedError, + expectedPlatform: platform.Unknown, + }, + { + name: "kubernetes, clusterversions not found", + err: errors.NewNotFound(schema.GroupResource{}, "ClusterVersions"), + expectedPlatform: platform.Kubernetes, + }, + { + name: "kubernetes, clusterversions empty", + expectedPlatform: platform.Kubernetes, + }, + { + name: "openshift", + vers: []ocpconfigv1.ClusterVersion{ + {}, // zero object is fine! We just need 1+ elements + }, + expectedPlatform: platform.OpenShift, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cli := fakeLister{ + vers: tc.vers, + err: tc.err, + } + got, err := PlatformFromLister(context.TODO(), cli) + if err != tc.expectedError { + t.Errorf("got error %v expected %v", err, tc.expectedError) + } + if got != tc.expectedPlatform { + t.Errorf("detect platform %v expected %v", got, tc.expectedPlatform) + } + }) + } +} + +func TestPlatformFromClients(t *testing.T) { + type testCase struct { + name string + vers []ocpconfigv1.ClusterVersion + infra ocpconfigv1.Infrastructure + err error + expectedPlatform platform.Platform + expectedError error + } unexpectedError := fmt.Errorf("unexpected error") @@ -64,6 +116,19 @@ func TestPlatformFromLister(t *testing.T) { }, expectedPlatform: platform.OpenShift, }, + { + name: "hypershift", + // hypershift is a flavor of openshift so it has a clusterversion object + vers: []ocpconfigv1.ClusterVersion{ + {}, // zero object is fine! We just need 1+ elements + }, + infra: ocpconfigv1.Infrastructure{ + Status: ocpconfigv1.InfrastructureStatus{ + ControlPlaneTopology: ocpconfigv1.ExternalTopologyMode, + }, + }, + expectedPlatform: platform.HyperShift, + }, } for _, tc := range testCases { @@ -72,7 +137,12 @@ func TestPlatformFromLister(t *testing.T) { vers: tc.vers, err: tc.err, } - got, err := PlatformFromLister(context.TODO(), cli) + infraCli := fakeGetter{ + infra: tc.infra, + err: tc.err, + } + + got, err := PlatformFromClients(context.TODO(), cli, infraCli) if err != tc.expectedError { t.Errorf("got error %v expected %v", err, tc.expectedError) } @@ -88,9 +158,18 @@ type fakeLister struct { err error } +type fakeGetter struct { + infra ocpconfigv1.Infrastructure + err error +} + func (fake fakeLister) List(ctx context.Context, opts metav1.ListOptions) (*ocpconfigv1.ClusterVersionList, error) { verList := ocpconfigv1.ClusterVersionList{ Items: fake.vers, } return &verList, fake.err } + +func (fake fakeGetter) Get(ctx context.Context, name string, opts metav1.GetOptions) (*ocpconfigv1.Infrastructure, error) { + return &fake.infra, fake.err +} diff --git a/pkg/deployer/platform/platform.go b/pkg/deployer/platform/platform.go index a0b69ccf..2ce73633 100644 --- a/pkg/deployer/platform/platform.go +++ b/pkg/deployer/platform/platform.go @@ -24,6 +24,7 @@ const ( Unknown = Platform("Unknown") Kubernetes = Platform("Kubernetes") OpenShift = Platform("OpenShift") + HyperShift = Platform("HyperShift") ) func (p Platform) String() string { @@ -37,6 +38,8 @@ func ParsePlatform(plat string) (Platform, bool) { return Kubernetes, true case "openshift": return OpenShift, true + case "hypershift": + return HyperShift, true default: return Unknown, false } diff --git a/pkg/deployer/platform/platform_test.go b/pkg/deployer/platform/platform_test.go index a7918b04..101c07e1 100644 --- a/pkg/deployer/platform/platform_test.go +++ b/pkg/deployer/platform/platform_test.go @@ -36,6 +36,11 @@ func TestRoudnTrip(t *testing.T) { expected: OpenShift, expectedOK: true, }, + { + name: "HyperShift", + expected: HyperShift, + expectedOK: true, + }, { name: "foobar", expected: Unknown,