diff --git a/cmd/create/cluster/cmd.go b/cmd/create/cluster/cmd.go index 86956721f3..f60c3c6bfb 100644 --- a/cmd/create/cluster/cmd.go +++ b/cmd/create/cluster/cmd.go @@ -1127,7 +1127,7 @@ func run(cmd *cobra.Command, _ []string) { // OpenShift version: version := args.version channelGroup := args.channelGroup - versionList, err := versions.GetVersionList(r, channelGroup, isSTS, isHostedCP, true) + versionList, err := versions.GetVersionList(r, channelGroup, isSTS, isHostedCP, true, true) if err != nil { r.Reporter.Errorf("%s", err) os.Exit(1) diff --git a/cmd/create/machinepool/nodepool.go b/cmd/create/machinepool/nodepool.go index cade049c85..447b1d2db2 100644 --- a/cmd/create/machinepool/nodepool.go +++ b/cmd/create/machinepool/nodepool.go @@ -71,7 +71,7 @@ func addNodePool(cmd *cobra.Command, clusterKey string, cluster *cmv1.Cluster, r clusterVersion := cluster.Version().RawID() // This is called in HyperShift, but we don't want to exclude version which are HCP disabled for node pools // so we pass the relative parameter as false - versionList, err := versions.GetVersionList(r, channelGroup, true, false, false) + versionList, err := versions.GetVersionList(r, channelGroup, true, true, false, false) if err != nil { r.Reporter.Errorf("%s", err) os.Exit(1) @@ -85,7 +85,7 @@ func addNodePool(cmd *cobra.Command, clusterKey string, cluster *cmv1.Cluster, r } // Filter the available list of versions for a hosted machine pool - filteredVersionList := versions.GetFilteredVersionListForCreation(versionList, minVersion, clusterVersion) + filteredVersionList := versions.GetFilteredVersionList(versionList, minVersion, clusterVersion) if err != nil { r.Reporter.Errorf("%s", err) os.Exit(1) diff --git a/cmd/describe/machinepool/cmd_test.go b/cmd/describe/machinepool/cmd_test.go index 4a7ca0d1ea..59d871fe1b 100644 --- a/cmd/describe/machinepool/cmd_test.go +++ b/cmd/describe/machinepool/cmd_test.go @@ -1,7 +1,6 @@ package machinepool import ( - "bytes" "fmt" "net/http" "time" @@ -260,12 +259,7 @@ func formatNodePool() string { np, err := cmv1.NewNodePool().ID(nodePoolName).Version(version). AWSNodePool(awsNodePool).AvailabilityZone("us-east-1a").Build() Expect(err).To(BeNil()) - var npJson bytes.Buffer - - err = cmv1.MarshalNodePool(np, &npJson) - Expect(err).To(BeNil()) - - return npJson.String() + return test.FormatResource(np) } // formatMachinePool simulates the output of APIs for a fake machine pool @@ -274,12 +268,7 @@ func formatMachinePool() string { mp, err := cmv1.NewMachinePool().ID(nodePoolName).AWS(awsMachinePoolPool).InstanceType("m5.xlarge"). AvailabilityZones("us-east-1a", "us-east-1b", "us-east-1c").Build() Expect(err).To(BeNil()) - var mpJson bytes.Buffer - - err = cmv1.MarshalMachinePool(mp, &mpJson) - Expect(err).To(BeNil()) - - return mpJson.String() + return test.FormatResource(mp) } func buildNodePoolUpgradePolicy() *cmv1.NodePoolUpgradePolicy { diff --git a/cmd/describe/upgrade/cmd_test.go b/cmd/describe/upgrade/cmd_test.go index 6163055a04..97720c3934 100644 --- a/cmd/describe/upgrade/cmd_test.go +++ b/cmd/describe/upgrade/cmd_test.go @@ -63,75 +63,23 @@ var _ = Describe("Describe upgrade", func() { var clusterID = "cluster1" var nodePoolID = "nodepool85" - const nodePoolResponse = `{ - "kind": "NodePool", - "href": "/api/clusters_mgmt/v1/clusters/243nmgjr5v2q9rn5sf3456euj2lcq5tn/node_pools/workers", - "id": "workers", - "replicas": 2, - "auto_repair": true, - "aws_node_pool": { - "instance_type": "m5.xlarge", - "instance_profile": "rosa-service-managed-integration-243nmgjr5v2q9rn5sf3456euj2lcq5tn-ad-int1-worker", - "tags": { - "api.openshift.com/environment": "integration", - "api.openshift.com/id": "243nmgjr5v2q9rn5sf3456euj2lcq5tn", - "api.openshift.com/legal-entity-id": "1jIHnIbrnLH9kQD57W0BuPm78f1", - "api.openshift.com/name": "ad-int1", - "api.openshift.com/nodepool-hypershift": "ad-int1-workers", - "api.openshift.com/nodepool-ocm": "workers", - "red-hat-clustertype": "rosa", - "red-hat-managed": "true" - } - }, - "availability_zone": "us-west-2a", - "subnet": "subnet-0e3a4046c1c2f1078", - "status": { - "current_replicas": 0, - "message": "WaitingForAvailableMachines: NodeProvisioning" - }, - "version": { - "kind": "VersionLink", - "id": "openshift-v4.12.%s", - "href": "/api/clusters_mgmt/v1/versions/openshift-v4.12.%s" - }, - "tuning_configs": [] - }` + version41224 := cmv1.NewVersion().ID("openshift-v4.12.24").RawID("4.12.24").ReleaseImage("1"). + HREF("/api/clusters_mgmt/v1/versions/openshift-v4.12.24").Enabled(true).ChannelGroup("stable"). + ROSAEnabled(true).HostedControlPlaneEnabled(true).AvailableUpgrades("4.12.25", "4.12.26") + nodePool, err := cmv1.NewNodePool().ID("workers").Replicas(2).AutoRepair(true).Version(version41224).Build() + Expect(err).To(BeNil()) - // nolint:lll - const nodePoolUpgradePolicy = `{ - "kind": "NodePoolUpgradePolicyList", - "page": 1, - "size": 1, - "total": 1, - "items": [ - { - "kind": "NodePoolUpgradePolicy", - "id": "e2800d05-3534-11ee-b9bc-0a580a811709", - "href": "/api/clusters_mgmt/v1/clusters/25f96obptkqc5mh9vdc779jiqb3sihnn/node_pools/workers/upgrade_policies/e2800d05-3534-11ee-b9bc-0a580a811709", - "schedule_type": "manual", - "upgrade_type": "NodePool", - "version": "4.12.25", - "next_run": "2023-08-07T15:22:00Z", - "cluster_id": "25f96obptkqc5mh9vdc779jiqb3sihnn", - "node_pool_id": "workers", - "enable_minor_version_upgrades": true, - "creation_timestamp": "2023-08-07T15:12:54.967835Z", - "last_update_timestamp": "2023-08-07T15:12:54.967835Z", - "state": { - "value": "scheduled", - "description": "Upgrade scheduled." - } - } - ] -}` + upgradePolicies := make([]*cmv1.NodePoolUpgradePolicy, 0) + upgradePolicies = append(upgradePolicies, buildNodePoolUpgradePolicy()) BeforeEach(func() { testRuntime.InitRuntime() }) It("Upgrade policy found, no error", func() { args.nodePool = nodePoolID - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolUpgradePolicy)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, + test.FormatNodePoolUpgradePolicyList(upgradePolicies))) err := describeHypershiftUpgrades(testRuntime.RosaRuntime, clusterID, nodePoolID) Expect(err).To(BeNil()) }) @@ -143,3 +91,13 @@ var _ = Describe("Describe upgrade", func() { }) }) }) + +func buildNodePoolUpgradePolicy() *cmv1.NodePoolUpgradePolicy { + t, err := time.Parse(time.RFC3339, "2023-06-02T12:30:00Z") + Expect(err).To(BeNil()) + state := cmv1.NewUpgradePolicyState().Value(cmv1.UpgradePolicyStateValuePending) + policy, err := cmv1.NewNodePoolUpgradePolicy().ScheduleType(cmv1.ScheduleTypeManual). + UpgradeType(cmv1.UpgradeTypeNodePool).Version("4.12.25").State(state).NextRun(t).Build() + Expect(err).To(BeNil()) + return policy +} diff --git a/cmd/list/upgrade/cmd.go b/cmd/list/upgrade/cmd.go index dcd7124c9e..005bfda1e5 100644 --- a/cmd/list/upgrade/cmd.go +++ b/cmd/list/upgrade/cmd.go @@ -24,7 +24,6 @@ import ( "text/tabwriter" cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" - "github.com/openshift/rosa/cmd/upgrade/machinepool" "github.com/openshift/rosa/pkg/interactive/confirm" "github.com/spf13/cobra" @@ -104,16 +103,17 @@ func runWithRuntime(r *rosa.Runtime, _ *cobra.Command) error { } // Get available node pool upgrades - availableUpgrades, err = machinepool.GetAvailableVersion(r, cluster, nodePool) - if err != nil { - return err - } + availableUpgrades = ocm.GetNodePoolAvailableUpgrades(nodePool) } else { // Control plane or cluster updates r.Reporter.Debugf("Loading available upgrades for cluster '%s'", clusterKey) - availableUpgrades, err = r.OCMClient.GetAvailableUpgrades(ocm.GetVersionID(cluster)) - if err != nil { - return fmt.Errorf("Failed to get available upgrades for cluster '%s': %v", clusterKey, err) + if isHypershift { + availableUpgrades = ocm.GetAvailableUpgradesByCluster(cluster) + } else { + availableUpgrades, err = r.OCMClient.GetAvailableUpgrades(ocm.GetVersionID(cluster)) + if err != nil { + return fmt.Errorf("Failed to get available upgrades for cluster '%s': %v", clusterKey, err) + } } if len(availableUpgrades) == 0 { diff --git a/cmd/list/upgrade/cmd_test.go b/cmd/list/upgrade/cmd_test.go index c4e409f742..ed0158f27b 100644 --- a/cmd/list/upgrade/cmd_test.go +++ b/cmd/list/upgrade/cmd_test.go @@ -91,180 +91,22 @@ var _ = Describe("List upgrade", func() { Expect(err).To(BeNil()) var classicCluster = test.FormatClusterList([]*cmv1.Cluster{mockClassicCluster}) - // nolint:lll - const versionListResponse = `{ - "kind": "VersionList", - "page": 1, - "size": 3, - "total": 3, - "items": [ - { - "kind": "Version", - "id": "openshift-v4.12.26", - "href": "/api/clusters_mgmt/v1/versions/openshift-v4.12.26", - "raw_id": "4.12.26", - "enabled": true, - "default": true, - "channel_group": "stable", - "rosa_enabled": true, - "hosted_control_plane_enabled": true, - "end_of_life_timestamp": "2024-05-17T00:00:00Z", - "ami_overrides": [ - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-2", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-2" - }, - "ami": "ami-0e677f92eb4180cc0" - }, - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-1", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-1" - }, - "ami": "ami-00354720d36d019f9" - } - ], - "release_image": "quay.io/openshift-release-dev/ocp-release@sha256:8d72f29227418d2ae12ee52e25cce9edef7cd645bdaea02410a89fe8a0ec6a47" - }, - { - "kind": "Version", - "id": "openshift-v4.12.25", - "href": "/api/clusters_mgmt/v1/versions/openshift-v4.12.25", - "raw_id": "4.12.25", - "enabled": true, - "default": false, - "channel_group": "stable", - "available_upgrades": [ - "4.12.26" - ], - "rosa_enabled": true, - "hosted_control_plane_enabled": true, - "end_of_life_timestamp": "2024-05-17T00:00:00Z", - "ami_overrides": [ - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-1", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-1" - }, - "ami": "ami-00354720d36d019f9" - }, - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-2", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-2" - }, - "ami": "ami-0e677f92eb4180cc0" - } - ], - "release_image": "quay.io/openshift-release-dev/ocp-release@sha256:5a4fb052cda1d14d1e306ce87e6b0ded84edddaa76f1cf401bcded99cef2ad84" - }, - { - "kind": "Version", - "id": "openshift-v4.12.24", - "href": "/api/clusters_mgmt/v1/versions/openshift-v4.12.24", - "raw_id": "4.12.24", - "enabled": true, - "default": false, - "channel_group": "stable", - "available_upgrades": [ - "4.12.25", - "4.12.26" - ], - "rosa_enabled": true, - "hosted_control_plane_enabled": true, - "end_of_life_timestamp": "2024-05-17T00:00:00Z", - "ami_overrides": [ - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-2", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-2" - }, - "ami": "ami-0e677f92eb4180cc0" - }, - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-1", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-1" - }, - "ami": "ami-00354720d36d019f9" - } - ], - "release_image": "quay.io/openshift-release-dev/ocp-release@sha256:b0b11eedf91175459b5d7aefcf3936d0cabf00f01ced756677483f5f26227328" - } - ] - }` + versionNoUpgrades := cmv1.NewVersion().ID("openshift-v4.12.24").RawID("4.12.24").ReleaseImage("1"). + HREF("/api/clusters_mgmt/v1/versions/openshift-v4.12.24").Enabled(true).ChannelGroup("stable"). + ROSAEnabled(true).HostedControlPlaneEnabled(true) + version41224 := cmv1.NewVersion().ID("openshift-v4.12.24").RawID("4.12.24").ReleaseImage("1"). + HREF("/api/clusters_mgmt/v1/versions/openshift-v4.12.24").Enabled(true).ChannelGroup("stable"). + ROSAEnabled(true).HostedControlPlaneEnabled(true).AvailableUpgrades("4.12.25", "4.12.26") + nodePool, err := cmv1.NewNodePool().ID("workers").Replicas(2).AutoRepair(true).Version(version41224).Build() + Expect(err).To(BeNil()) + nodePoolNoUpgrades, err := cmv1.NewNodePool().ID("workers").Replicas(2).AutoRepair(true). + Version(versionNoUpgrades).Build() + Expect(err).To(BeNil()) + emptyUpgradePolicies := make([]*cmv1.NodePoolUpgradePolicy, 0) + + upgradePolicies := make([]*cmv1.NodePoolUpgradePolicy, 0) + upgradePolicies = append(upgradePolicies, buildNodePoolUpgradePolicy()) - // nolint:lll - const nodePoolResponse = `{ - "kind": "NodePool", - "href": "/api/clusters_mgmt/v1/clusters/243nmgjr5v2q9rn5sf3456euj2lcq5tn/node_pools/workers", - "id": "workers", - "replicas": 2, - "auto_repair": true, - "aws_node_pool": { - "instance_type": "m5.xlarge", - "instance_profile": "rosa-service-managed-integration-243nmgjr5v2q9rn5sf3456euj2lcq5tn-ad-int1-worker", - "tags": { - "api.openshift.com/environment": "integration", - "api.openshift.com/id": "243nmgjr5v2q9rn5sf3456euj2lcq5tn", - "api.openshift.com/legal-entity-id": "1jIHnIbrnLH9kQD57W0BuPm78f1", - "api.openshift.com/name": "ad-int1", - "api.openshift.com/nodepool-hypershift": "ad-int1-workers", - "api.openshift.com/nodepool-ocm": "workers", - "red-hat-clustertype": "rosa", - "red-hat-managed": "true" - } - }, - "availability_zone": "us-west-2a", - "subnet": "subnet-0e3a4046c1c2f1078", - "status": { - "current_replicas": 0, - "message": "WaitingForAvailableMachines: NodeProvisioning" - }, - "version": { - "kind": "VersionLink", - "id": "openshift-v4.12.%s", - "href": "/api/clusters_mgmt/v1/versions/openshift-v4.12.%s" - }, - "tuning_configs": [] - }` BeforeEach(func() { testRuntime.InitRuntime() }) @@ -288,23 +130,10 @@ var _ = Describe("List upgrade", func() { args.nodePool = nodePoolName testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) // A node pool - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, - fmt.Sprintf(nodePoolResponse, "26", "26"))) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePoolNoUpgrades))) // No existing policy upgrade - testRuntime.ApiServer.AppendHandlers( - RespondWithJSON( - http.StatusOK, - `{ - "kind": "NodePoolUpgradePolicyList", - "page": 1, - "size": 0, - "total": 0, - "items": [] - }`, - ), - ) - // available versions - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, + test.FormatNodePoolUpgradePolicyList(emptyUpgradePolicies))) stdout, _, err := test.RunWithOutputCapture(runWithRuntime, testRuntime.RosaRuntime, Cmd) Expect(stdout).To(Equal(noUpgradeOutput)) Expect(err).To(BeNil()) @@ -315,23 +144,10 @@ var _ = Describe("List upgrade", func() { args.nodePool = nodePoolName testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) // A node pool - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, - fmt.Sprintf(nodePoolResponse, "24", "24"))) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) // No existing policy upgrade - testRuntime.ApiServer.AppendHandlers( - RespondWithJSON( - http.StatusOK, - `{ - "kind": "NodePoolUpgradePolicyList", - "page": 1, - "size": 0, - "total": 0, - "items": [] - }`, - ), - ) - // available versions - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, + test.FormatNodePoolUpgradePolicyList(emptyUpgradePolicies))) stdout, _, err := test.RunWithOutputCapture(runWithRuntime, testRuntime.RosaRuntime, Cmd) Expect(stdout).To(Equal(upgradeAvailableOutput)) Expect(err).To(BeNil()) @@ -342,45 +158,23 @@ var _ = Describe("List upgrade", func() { args.nodePool = nodePoolName testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) // A node pool - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, - fmt.Sprintf(nodePoolResponse, "24", "24"))) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) // An existing policy upgrade - // nolint:lll - testRuntime.ApiServer.AppendHandlers( - RespondWithJSON( - http.StatusOK, - `{ - "kind": "NodePoolUpgradePolicyList", - "page": 1, - "size": 1, - "total": 1, - "items": [ - { - "kind": "NodePoolUpgradePolicy", - "id": "a33c8cae-013f-11ee-a3b2-acde48001122", - "href": "/api/clusters_mgmt/v1/clusters/243nmgjr5v2q9rn5sf3456euj2lcq5tn/node_pools/upgrade_policies/a33c8cae-013f-11ee-a3b2-acde48001122", - "schedule_type": "manual", - "upgrade_type": "NodePool", - "version": "4.12.25", - "next_run": "2023-06-02T12:30:00Z", - "cluster_id": "243nmgjr5v2q9rn5sf3456euj2lcq5tn", - "enable_minor_version_upgrades": false, - "creation_timestamp": "2023-06-02T14:18:52.828589+02:00", - "last_update_timestamp": "2023-06-02T14:18:52.828589+02:00", - "state": { - "value": "pending", - "description": "Upgrade policy defined, pending scheduling." - } - } - ] - }`, - ), - ) - // available versions - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, + test.FormatNodePoolUpgradePolicyList(upgradePolicies))) stdout, _, err := test.RunWithOutputCapture(runWithRuntime, testRuntime.RosaRuntime, Cmd) Expect(stdout).To(Equal(ongoingUpgradeOutput)) Expect(err).To(BeNil()) }) }) }) + +func buildNodePoolUpgradePolicy() *cmv1.NodePoolUpgradePolicy { + t, err := time.Parse(time.RFC3339, "2023-06-02T12:30:00Z") + Expect(err).To(BeNil()) + state := cmv1.NewUpgradePolicyState().Value(cmv1.UpgradePolicyStateValuePending) + policy, err := cmv1.NewNodePoolUpgradePolicy().ScheduleType(cmv1.ScheduleTypeManual). + UpgradeType(cmv1.UpgradeTypeNodePool).Version("4.12.25").State(state).NextRun(t).Build() + Expect(err).To(BeNil()) + return policy +} diff --git a/cmd/list/version/cmd.go b/cmd/list/version/cmd.go index 6e07169a6c..f808747b38 100644 --- a/cmd/list/version/cmd.go +++ b/cmd/list/version/cmd.go @@ -66,10 +66,14 @@ func run(cmd *cobra.Command, _ []string) { r := rosa.NewRuntime().WithOCM() defer r.Cleanup() isHostedCp := args.hostedCp + var product string + if isHostedCp { + product = ocm.HcpProduct + } // Try to find the cluster: r.Reporter.Debugf("Fetching versions") - versions, err := r.OCMClient.GetVersions(args.channelGroup, false) + versions, err := r.OCMClient.GetVersionsWithProduct(product, args.channelGroup, false) if err != nil { r.Reporter.Errorf("Failed to fetch versions: %v", err) os.Exit(1) diff --git a/cmd/upgrade/cluster/cmd.go b/cmd/upgrade/cluster/cmd.go index 6d54fea806..d5b72983f2 100644 --- a/cmd/upgrade/cluster/cmd.go +++ b/cmd/upgrade/cluster/cmd.go @@ -411,9 +411,15 @@ func createUpgradePolicyClassic(r *rosa.Runtime, cmd *cobra.Command, clusterKey func buildVersion(r *rosa.Runtime, cmd *cobra.Command, cluster *cmv1.Cluster, version string, isAutomaticUpgrade bool) ([]string, string, error) { - availableUpgrades, err := r.OCMClient.GetAvailableUpgrades(ocm.GetVersionID(cluster)) - if err != nil { - return availableUpgrades, version, fmt.Errorf("Failed to find available upgrades: %v", err) + var availableUpgrades []string + var err error + if ocm.IsHyperShiftCluster(cluster) { + availableUpgrades = ocm.GetAvailableUpgradesByCluster(cluster) + } else { + availableUpgrades, err = r.OCMClient.GetAvailableUpgrades(ocm.GetVersionID(cluster)) + if err != nil { + return availableUpgrades, version, fmt.Errorf("Failed to find available upgrades: %v", err) + } } if len(availableUpgrades) == 0 { return availableUpgrades, version, nil diff --git a/cmd/upgrade/cluster/cmd_test.go b/cmd/upgrade/cluster/cmd_test.go index ef7f9c638c..d9077f7cae 100644 --- a/cmd/upgrade/cluster/cmd_test.go +++ b/cmd/upgrade/cluster/cmd_test.go @@ -33,14 +33,6 @@ var _ = Describe("Upgrade", Ordered, func() { version4130 := cmv1.NewVersion().ID("openshift-v4.13.0").RawID("4.13.0").ReleaseImage("1"). HREF("/api/clusters_mgmt/v1/versions/openshift-v4.13.0").Enabled(true).ChannelGroup("stable"). ROSAEnabled(true).HostedControlPlaneEnabled(true) - version4130WithUpdate, err := version4130.AvailableUpgrades("4.13.1").Build() - Expect(err).To(BeNil()) - version4130WithoutUpdate, err := version4130.AvailableUpgrades().Build() - Expect(err).To(BeNil()) - version4131, err := cmv1.NewVersion().ID("openshift-v4.13.1").RawID("4.13.1").ReleaseImage("1"). - HREF("/api/clusters_mgmt/v1/versions/openshift-v4.13.1").Enabled(true).ChannelGroup("stable"). - ROSAEnabled(true).HostedControlPlaneEnabled(true).AvailableUpgrades("4.13.2").Build() - Expect(err).To(BeNil()) mockClusterError, err := test.MockOCMCluster(func(c *cmv1.ClusterBuilder) { c.AWS(cmv1.NewAWS().SubnetIDs("subnet-0b761d44d3d9a4663", "subnet-0f87f640e56934cbc")) @@ -56,10 +48,24 @@ var _ = Describe("Upgrade", Ordered, func() { c.Region(cmv1.NewCloudRegion().ID("us-east-1")) c.State(cmv1.ClusterStateReady) c.Hypershift(cmv1.NewHypershift().Enabled(true)) + c.Version(version4130) }) Expect(err).To(BeNil()) + // hypershiftClusterReady has no available upgrades var hypershiftClusterReady = test.FormatClusterList([]*cmv1.Cluster{mockClusterReady}) + version4130WithUpgrades := version4130.AvailableUpgrades("4.13.1") + mockClusterReadyWithUpgrades, err := test.MockOCMCluster(func(c *cmv1.ClusterBuilder) { + c.AWS(cmv1.NewAWS().SubnetIDs("subnet-0b761d44d3d9a4663", "subnet-0f87f640e56934cbc")) + c.Region(cmv1.NewCloudRegion().ID("us-east-1")) + c.State(cmv1.ClusterStateReady) + c.Hypershift(cmv1.NewHypershift().Enabled(true)) + c.Version(version4130WithUpgrades) + }) + Expect(err).To(BeNil()) + // hypershiftClusterReadyWithUpdates has one available upgrade + var hypershiftClusterReadyWithUpdates = test.FormatClusterList([]*cmv1.Cluster{mockClusterReadyWithUpgrades}) + mockClassicCluster, err := test.MockOCMCluster(func(c *cmv1.ClusterBuilder) { c.AWS(cmv1.NewAWS().SubnetIDs("subnet-0b761d44d3d9a4663", "subnet-0f87f640e56934cbc")) c.Region(cmv1.NewCloudRegion().ID("us-east-1")) @@ -144,18 +150,6 @@ var _ = Describe("Upgrade", Ordered, func() { Expect(err).ToNot(BeNil()) Expect(err.Error()).To(ContainSubstring("Cluster 'cluster1' is not yet ready")) }) - It("Cluster is ready but no upgrade type specified", func() { - args.controlPlane = true - args.schedule = cronSchedule - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - // No existing policy upgrade - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, - formatControlPlaneUpgradePolicyList([]*cmv1.ControlPlaneUpgradePolicy{}))) - err := runWithRuntime(testRuntime.RosaRuntime, Cmd) - Expect(err).ToNot(BeNil()) - // Missing the upgrade type - Expect(err.Error()).To(ContainSubstring("Failed to find available upgrades")) - }) It("Cluster is ready but existing upgrade scheduled", func() { args.controlPlane = true args.schedule = cronSchedule @@ -213,12 +207,12 @@ var _ = Describe("Upgrade", Ordered, func() { // Not a valid date format args.scheduleDate = dateSchedule args.scheduleTime = timeSchedule + // The version we want to update to + args.version = "4.13.4" testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) // No existing policy upgrade testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatControlPlaneUpgradePolicyList([]*cmv1.ControlPlaneUpgradePolicy{}))) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatVersion(version4130WithoutUpdate))) - stdout, stderr, err := test.RunWithOutputCapture(runWithRuntime, testRuntime.RosaRuntime, Cmd) Expect(err).To(BeNil()) Expect(stdout).To(BeEmpty()) @@ -229,11 +223,11 @@ var _ = Describe("Upgrade", Ordered, func() { args.schedule = "20 5 * * *" args.scheduleDate = "" args.scheduleTime = "" + args.version = "" testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) // No existing policy upgrade testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatControlPlaneUpgradePolicyList([]*cmv1.ControlPlaneUpgradePolicy{}))) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatVersion(version4130WithoutUpdate))) // POST - // /api/clusters_mgmt/v1/clusters/24vf9iitg3p6tlml88iml6j6mu095mh8/control_plane/upgrade_policies?dryRun=true testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusNoContent, "")) @@ -257,12 +251,10 @@ var _ = Describe("Upgrade", Ordered, func() { args.scheduleTime = timeSchedule // The version we want to update to args.version = "4.13.4" - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReadyWithUpdates)) // No existing policy upgrade testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatControlPlaneUpgradePolicyList([]*cmv1.ControlPlaneUpgradePolicy{}))) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatVersion(version4130WithUpdate))) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatVersion(version4131))) err := runWithRuntime(testRuntime.RosaRuntime, Cmd) Expect(err).ToNot(BeNil()) @@ -277,25 +269,20 @@ var _ = Describe("Upgrade", Ordered, func() { args.scheduleTime = timeSchedule // The version we want to update to args.version = "4.13.1" - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReadyWithUpdates)) // No existing policy upgrade testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatControlPlaneUpgradePolicyList([]*cmv1.ControlPlaneUpgradePolicy{}))) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatVersion(version4130WithUpdate))) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, formatVersion(version4131))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusNoContent, "")) - testRuntime.ApiServer.AppendHandlers( - RespondWithJSON( - http.StatusCreated, `{ - "kind": "ControlPlaneUpgradePolicy", - "enable_minor_version_upgrades": false, - "schedule": "35 12 * * *", - "schedule_type": "automatic", - "upgrade_type": "ControlPlane" - }`)) + + cpUpgradePolicy, err := cmv1.NewControlPlaneUpgradePolicy().UpgradeType(cmv1.UpgradeTypeControlPlane). + ScheduleType(cmv1.ScheduleTypeAutomatic).Schedule("30 12 * * *"). + EnableMinorVersionUpgrades(false).Build() + Expect(err).To(BeNil()) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusCreated, test.FormatResource(cpUpgradePolicy))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusNotFound, clusterNotFound)) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, emptyClusterList)) - err := runWithRuntime(testRuntime.RosaRuntime, Cmd) + err = runWithRuntime(testRuntime.RosaRuntime, Cmd) Expect(err).ToNot(BeNil()) Expect(err.Error()).To(ContainSubstring("There is no cluster with identifier or name")) }) @@ -315,11 +302,3 @@ func formatControlPlaneUpgradePolicyList(upgradePolicies []*cmv1.ControlPlaneUpg "items": %s }`, len(upgradePolicies), len(upgradePolicies), policiesJson.String()) } - -func formatVersion(version *cmv1.Version) string { - var versionJson bytes.Buffer - - cmv1.MarshalVersion(version, &versionJson) - - return versionJson.String() -} diff --git a/cmd/upgrade/machinepool/cmd.go b/cmd/upgrade/machinepool/cmd.go index 29381b79c9..94b85fbc03 100644 --- a/cmd/upgrade/machinepool/cmd.go +++ b/cmd/upgrade/machinepool/cmd.go @@ -21,7 +21,6 @@ import ( "os" cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" - "github.com/openshift/rosa/pkg/helper/versions" "github.com/openshift/rosa/pkg/input" "github.com/openshift/rosa/pkg/interactive" "github.com/openshift/rosa/pkg/interactive/confirm" @@ -334,11 +333,9 @@ func checkNodePoolExistingScheduledUpgrade(r *rosa.Runtime, cluster *cmv1.Cluste func ComputeNodePoolVersion(r *rosa.Runtime, cmd *cobra.Command, cluster *cmv1.Cluster, nodePool *cmv1.NodePool, version string) (string, error) { + var err error channelGroup := cluster.Version().ChannelGroup() - filteredVersionList, err := GetAvailableVersion(r, cluster, nodePool) - if err != nil { - return "", err - } + filteredVersionList := ocm.GetNodePoolAvailableUpgrades(nodePool) // No updates available if len(filteredVersionList) == 0 { return "", nil @@ -368,21 +365,3 @@ func ComputeNodePoolVersion(r *rosa.Runtime, cmd *cobra.Command, cluster *cmv1.C } return version, nil } - -func GetAvailableVersion(r *rosa.Runtime, cluster *cmv1.Cluster, nodePool *cmv1.NodePool) ([]string, error) { - clusterVersion := cluster.Version().RawID() - nodePoolVersion := ocm.GetRawVersionId(nodePool.Version().ID()) - // This is called in HyperShift, but we don't want to exclude version which are HCP disabled for node pools - // so we pass the relative parameter as false - versionList, err := versions.GetVersionList(r, cluster.Version().ChannelGroup(), true, false, false) - if err != nil { - return nil, err - } - - // Filter the available list of versions for a hosted machine pool - filteredVersionList := versions.GetFilteredVersionListForUpdate(versionList, nodePoolVersion, clusterVersion) - if err != nil { - return nil, err - } - return filteredVersionList, nil -} diff --git a/cmd/upgrade/machinepool/cmd_test.go b/cmd/upgrade/machinepool/cmd_test.go index d1f6e32feb..42d59fc6b3 100644 --- a/cmd/upgrade/machinepool/cmd_test.go +++ b/cmd/upgrade/machinepool/cmd_test.go @@ -17,7 +17,7 @@ const ( validScheduleDate = "2023-12-25" cronSchedule = "* * * * *" invalidVersionError = `Expected a valid machine pool version: A valid version number must be specified -Valid versions: 4.12.26 4.12.25 4.12.24` +Valid versions: 4.12.26 4.12.25` ) var _ = Describe("Upgrade machine pool", func() { @@ -42,180 +42,11 @@ var _ = Describe("Upgrade machine pool", func() { Expect(err).To(BeNil()) hypershiftClusterReady := test.FormatClusterList([]*cmv1.Cluster{mockClusterReady}) - // nolint:lll - const versionListResponse = `{ - "kind": "VersionList", - "page": 1, - "size": 3, - "total": 3, - "items": [ - { - "kind": "Version", - "id": "openshift-v4.12.26", - "href": "/api/clusters_mgmt/v1/versions/openshift-v4.12.26", - "raw_id": "4.12.26", - "enabled": true, - "default": true, - "channel_group": "stable", - "rosa_enabled": true, - "hosted_control_plane_enabled": true, - "end_of_life_timestamp": "2024-05-17T00:00:00Z", - "ami_overrides": [ - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-2", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-2" - }, - "ami": "ami-0e677f92eb4180cc0" - }, - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-1", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-1" - }, - "ami": "ami-00354720d36d019f9" - } - ], - "release_image": "quay.io/openshift-release-dev/ocp-release@sha256:8d72f29227418d2ae12ee52e25cce9edef7cd645bdaea02410a89fe8a0ec6a47" - }, - { - "kind": "Version", - "id": "openshift-v4.12.25", - "href": "/api/clusters_mgmt/v1/versions/openshift-v4.12.25", - "raw_id": "4.12.25", - "enabled": true, - "default": false, - "channel_group": "stable", - "available_upgrades": [ - "4.12.26" - ], - "rosa_enabled": true, - "hosted_control_plane_enabled": true, - "end_of_life_timestamp": "2024-05-17T00:00:00Z", - "ami_overrides": [ - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-1", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-1" - }, - "ami": "ami-00354720d36d019f9" - }, - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-2", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-2" - }, - "ami": "ami-0e677f92eb4180cc0" - } - ], - "release_image": "quay.io/openshift-release-dev/ocp-release@sha256:5a4fb052cda1d14d1e306ce87e6b0ded84edddaa76f1cf401bcded99cef2ad84" - }, - { - "kind": "Version", - "id": "openshift-v4.12.24", - "href": "/api/clusters_mgmt/v1/versions/openshift-v4.12.24", - "raw_id": "4.12.24", - "enabled": true, - "default": false, - "channel_group": "stable", - "available_upgrades": [ - "4.12.25", - "4.12.26" - ], - "rosa_enabled": true, - "hosted_control_plane_enabled": true, - "end_of_life_timestamp": "2024-05-17T00:00:00Z", - "ami_overrides": [ - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-2", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-2" - }, - "ami": "ami-0e677f92eb4180cc0" - }, - { - "product": { - "kind": "ProductLink", - "id": "rosa", - "href": "/api/clusters_mgmt/v1/products/rosa" - }, - "region": { - "kind": "CloudRegionLink", - "id": "us-east-1", - "href": "/api/clusters_mgmt/v1/cloud_providers/aws/regions/us-east-1" - }, - "ami": "ami-00354720d36d019f9" - } - ], - "release_image": "quay.io/openshift-release-dev/ocp-release@sha256:b0b11eedf91175459b5d7aefcf3936d0cabf00f01ced756677483f5f26227328" - } - ] - }` - - // nolint:lll - const nodePoolResponse = `{ - "kind": "NodePool", - "href": "/api/clusters_mgmt/v1/clusters/243nmgjr5v2q9rn5sf3456euj2lcq5tn/node_pools/workers", - "id": "workers", - "replicas": 2, - "auto_repair": true, - "aws_node_pool": { - "instance_type": "m5.xlarge", - "instance_profile": "rosa-service-managed-integration-243nmgjr5v2q9rn5sf3456euj2lcq5tn-ad-int1-worker", - "tags": { - "api.openshift.com/environment": "integration", - "api.openshift.com/id": "243nmgjr5v2q9rn5sf3456euj2lcq5tn", - "api.openshift.com/legal-entity-id": "1jIHnIbrnLH9kQD57W0BuPm78f1", - "api.openshift.com/name": "ad-int1", - "api.openshift.com/nodepool-hypershift": "ad-int1-workers", - "api.openshift.com/nodepool-ocm": "workers", - "red-hat-clustertype": "rosa", - "red-hat-managed": "true" - } - }, - "availability_zone": "us-west-2a", - "subnet": "subnet-0e3a4046c1c2f1078", - "status": { - "current_replicas": 0, - "message": "WaitingForAvailableMachines: NodeProvisioning" - }, - "version": { - "kind": "VersionLink", - "id": "openshift-v4.12.%s", - "href": "/api/clusters_mgmt/v1/versions/openshift-v4.12.%s" - }, - "tuning_configs": [] - }` + version41224 := cmv1.NewVersion().ID("openshift-v4.12.24").RawID("4.12.24").ReleaseImage("1"). + HREF("/api/clusters_mgmt/v1/versions/openshift-v4.12.24").Enabled(true).ChannelGroup("stable"). + ROSAEnabled(true).HostedControlPlaneEnabled(true).AvailableUpgrades("4.12.25", "4.12.26") + nodePool, err := cmv1.NewNodePool().ID("workers").Replicas(2).AutoRepair(true).Version(version41224).Build() + Expect(err).To(BeNil()) upgradePolicies := make([]*cmv1.NodePoolUpgradePolicy, 0) upgradePolicies = append(upgradePolicies, buildNodePoolUpgradePolicy()) @@ -277,7 +108,7 @@ var _ = Describe("Upgrade machine pool", func() { }) It("Cluster is ready and there is a scheduled upgraded", func() { testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolUpgradePolicy)) _, stderr, err := test.RunWithOutputCaptureAndArgv(runWithRuntime, testRuntime.RosaRuntime, Cmd, &[]string{nodePoolName}) @@ -285,9 +116,9 @@ var _ = Describe("Upgrade machine pool", func() { Expect(stderr).To(ContainSubstring( "WARN: There is already a scheduled upgrade to version 4.12.25 on 2023-08-07 15:22 UTC")) }) - It("Cluster is ready and there is a scheduled upgraded", func() { + It("Succeeds if cluster is ready and there is a scheduled upgraded", func() { testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolUpgradePolicy)) _, stderr, err := test.RunWithOutputCaptureAndArgv(runWithRuntime, testRuntime.RosaRuntime, Cmd, &[]string{nodePoolName}) @@ -295,14 +126,13 @@ var _ = Describe("Upgrade machine pool", func() { Expect(stderr).To(ContainSubstring( "WARN: There is already a scheduled upgrade to version 4.12.25 on 2023-08-07 15:22 UTC")) }) - It("Cluster is ready and there is no scheduled upgraded but schedule date is invalid -> fail", func() { + It("Fails if cluster is ready and there is no scheduled upgraded but schedule date is invalid", func() { args.scheduleTime = scheduleTime args.scheduleDate = invalidScheduleDate Cmd.Flags().Set("interactive", "false") testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, noNodePoolUpgradePolicy)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) stdout, stderr, err := test.RunWithOutputCaptureAndArgv(runWithRuntime, testRuntime.RosaRuntime, Cmd, &[]string{nodePoolName}) Expect(err).ToNot(BeNil()) @@ -311,17 +141,16 @@ var _ = Describe("Upgrade machine pool", func() { Expect(stdout).To(BeEmpty()) Expect(stderr).To(BeEmpty()) }) - It("Cluster is ready and there is no scheduled upgraded and an invalid version is specified -> fail", + It("Fails if cluster is ready and there is no scheduled upgraded but a version not "+ + "in available upgrades is specified", func() { args.scheduleTime = scheduleTime args.scheduleDate = validScheduleDate Cmd.Flags().Set("version", "4.13.26") Cmd.Flags().Set("interactive", "false") testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, noNodePoolUpgradePolicy)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, "")) stdout, stderr, err := test.RunWithOutputCaptureAndArgv(runWithRuntime, testRuntime.RosaRuntime, Cmd, &[]string{nodePoolName}) Expect(err).ToNot(BeNil()) @@ -329,15 +158,14 @@ var _ = Describe("Upgrade machine pool", func() { Expect(stderr).To(BeEmpty()) Expect(stdout).To(BeEmpty()) }) - It("Cluster is ready and there is no scheduled upgraded and a version is specified -> success", func() { + It("Succeeds if cluster is ready and there is no scheduled upgraded and a version is specified", func() { args.scheduleTime = scheduleTime args.scheduleDate = validScheduleDate Cmd.Flags().Set("version", "4.12.26") Cmd.Flags().Set("interactive", "false") testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, noNodePoolUpgradePolicy)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, "")) stdout, stderr, err := test.RunWithOutputCaptureAndArgv(runWithRuntime, testRuntime.RosaRuntime, Cmd, &[]string{nodePoolName}) @@ -346,14 +174,13 @@ var _ = Describe("Upgrade machine pool", func() { Expect(stdout).To(ContainSubstring( "Upgrade successfully scheduled for the machine pool 'nodepool85' on cluster 'cluster1")) }) - It("Cluster is ready and there is no scheduled upgraded -> success", func() { + It("Succeeds if cluster is ready and there is no scheduled upgraded", func() { args.scheduleTime = scheduleTime args.scheduleDate = validScheduleDate Cmd.Flags().Set("interactive", "false") testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, noNodePoolUpgradePolicy)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, "")) stdout, stderr, err := test.RunWithOutputCaptureAndArgv(runWithRuntime, testRuntime.RosaRuntime, Cmd, &[]string{nodePoolName}) @@ -367,9 +194,8 @@ var _ = Describe("Upgrade machine pool", func() { args.scheduleDate = validScheduleDate Cmd.Flags().Set("interactive", "false") testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, noNodePoolUpgradePolicy)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusBadRequest, "an error")) stdout, stderr, err := test.RunWithOutputCaptureAndArgv(runWithRuntime, testRuntime.RosaRuntime, Cmd, &[]string{nodePoolName}) @@ -386,9 +212,8 @@ var _ = Describe("Upgrade machine pool", func() { args.schedule = "* a" Cmd.Flags().Set("interactive", "false") testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, noNodePoolUpgradePolicy)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, "")) _, _, err := test.RunWithOutputCaptureAndArgv(runWithRuntime, testRuntime.RosaRuntime, Cmd, &[]string{nodePoolName}) @@ -403,10 +228,9 @@ var _ = Describe("Upgrade machine pool", func() { args.schedule = cronSchedule Cmd.Flags().Set("interactive", "false") testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, hypershiftClusterReady)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, nodePoolResponse)) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, test.FormatResource(nodePool))) testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, noNodePoolUpgradePolicy)) - testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, versionListResponse)) - //testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, "")) + testRuntime.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, "")) stdout, stderr, err := test.RunWithOutputCaptureAndArgv(runWithRuntime, testRuntime.RosaRuntime, Cmd, &[]string{nodePoolName}) Expect(err).To(BeNil()) diff --git a/pkg/helper/versions/helpers.go b/pkg/helper/versions/helpers.go index d079d1da4a..f3a69b1d8c 100644 --- a/pkg/helper/versions/helpers.go +++ b/pkg/helper/versions/helpers.go @@ -6,6 +6,7 @@ import ( "github.com/hashicorp/go-version" ver "github.com/hashicorp/go-version" + v1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" "github.com/openshift/rosa/pkg/ocm" "github.com/openshift/rosa/pkg/rosa" ) @@ -14,9 +15,15 @@ const ( MinorVersionsSupported = 2 ) -func GetVersionList(r *rosa.Runtime, channelGroup string, isSTS bool, isHostedCP bool, +func GetVersionList(r *rosa.Runtime, channelGroup string, isSTS bool, isHostedCP bool, filterHostedCP bool, defaultFirst bool) (versionList []string, err error) { - vs, err := r.OCMClient.GetVersions(channelGroup, defaultFirst) + var vs []*v1.Version + var product string + if isHostedCP { + product = ocm.HcpProduct + } + // Product can be empty. In this case, no filter will be applied + vs, err = r.OCMClient.GetVersionsWithProduct(product, channelGroup, defaultFirst) if err != nil { err = fmt.Errorf("Failed to retrieve versions: %s", err) return @@ -26,7 +33,7 @@ func GetVersionList(r *rosa.Runtime, channelGroup string, isSTS bool, isHostedCP if isSTS && !ocm.HasSTSSupport(v.RawID(), v.ChannelGroup()) { continue } - if isHostedCP { + if filterHostedCP { valid, err := ocm.HasHostedCPSupport(v) if err != nil { return versionList, fmt.Errorf("failed to check HostedCP support: %v", err) @@ -46,15 +53,7 @@ func GetVersionList(r *rosa.Runtime, channelGroup string, isSTS bool, isHostedCP return } -func GetFilteredVersionListForCreation(versionList []string, minVersion string, maxVersion string) []string { - return getFilteredVersionList(versionList, minVersion, maxVersion, false) -} - -func GetFilteredVersionListForUpdate(versionList []string, minVersion string, maxVersion string) []string { - return getFilteredVersionList(versionList, minVersion, maxVersion, true) -} - -func getFilteredVersionList(versionList []string, minVersion string, maxVersion string, excludeCurrent bool) []string { +func GetFilteredVersionList(versionList []string, minVersion string, maxVersion string) []string { var filteredVersionList []string // Parse the versions for comparison @@ -71,10 +70,6 @@ func getFilteredVersionList(versionList []string, minVersion string, maxVersion continue } if ver.GreaterThanOrEqual(min) && ver.LessThanOrEqual(max) { - // For upgrades, we don't want to show the current version. For creation, it should be shown - if excludeCurrent && ver.Equal(min) { - continue - } filteredVersionList = append(filteredVersionList, version) } } diff --git a/pkg/helper/versions/helpers_test.go b/pkg/helper/versions/helpers_test.go index 32b0e921f1..ddcf02e93b 100644 --- a/pkg/helper/versions/helpers_test.go +++ b/pkg/helper/versions/helpers_test.go @@ -12,7 +12,7 @@ var _ = Describe("Version Helpers", Ordered, func() { Context("when creating a hosted machine pool ", func() { DescribeTable("Filtered versions", func(versionList []string, minVersion string, maxVersion string, expectedVersionList []string) { - filteredVersionList := getFilteredVersionList(versionList, minVersion, maxVersion, false) + filteredVersionList := GetFilteredVersionList(versionList, minVersion, maxVersion) Expect(filteredVersionList).To(BeEquivalentTo(expectedVersionList)) }, Entry("machinepool create", @@ -74,31 +74,5 @@ var _ = Describe("Version Helpers", Ordered, func() { ) }) - Context("when updating a hosted machine pool ", func() { - DescribeTable("Filtered versions", - func(versionList []string, minVersion string, maxVersion string, expectedVersionList []string) { - filteredVersionList := getFilteredVersionList(versionList, minVersion, maxVersion, true) - Expect(filteredVersionList).To(BeEquivalentTo(expectedVersionList)) - }, - Entry("machinepool update", - []string{ - "4.12.22", - "4.12.23", - "4.12.24", - "4.12.25", - "4.12.26", - "4.13.0-0.nightly-2023-02-22-192922", - }, - "4.12.22", - "4.12.26", - []string{ - "4.12.23", - "4.12.24", - "4.12.25", - "4.12.26", - }, - ), - ) - }) }) diff --git a/pkg/ocm/helpers.go b/pkg/ocm/helpers.go index 3d89e0954d..03a712ccd4 100644 --- a/pkg/ocm/helpers.go +++ b/pkg/ocm/helpers.go @@ -63,6 +63,8 @@ const ( USERRoleLabel = "sts_user_role" maxClusterNameLength = 15 + + HcpProduct = "hcp" ) // Regular expression to used to make sure that the identifier or name given by the user is diff --git a/pkg/ocm/versions.go b/pkg/ocm/versions.go index 9d14599833..d2e0601c17 100644 --- a/pkg/ocm/versions.go +++ b/pkg/ocm/versions.go @@ -62,6 +62,11 @@ func (c *Client) ManagedServiceVersionInquiry(serviceType string) (string, error } func (c *Client) GetVersions(channelGroup string, defaultFirst bool) (versions []*cmv1.Version, err error) { + return c.GetVersionsWithProduct("", channelGroup, defaultFirst) +} + +func (c *Client) GetVersionsWithProduct(product string, channelGroup string, + defaultFirst bool) (versions []*cmv1.Version, err error) { collection := c.ocm.ClustersMgmt().V1().Versions() page := 1 size := 100 @@ -72,12 +77,15 @@ func (c *Client) GetVersions(channelGroup string, defaultFirst bool) (versions [ } for { var response *cmv1.VersionsListResponse - response, err = collection.List(). + request := collection.List(). Search(filter). Order(order). Page(page). - Size(size). - Send() + Size(size) + if product != "" { + request.Parameter("product", product) + } + response, err = request.Send() if err != nil { return nil, handleErr(response.Error(), err) } @@ -204,6 +212,20 @@ func (c *Client) GetAvailableUpgrades(versionID string) ([]string, error) { return availableUpgrades, nil } +func GetAvailableUpgradesByCluster(cluster *cmv1.Cluster) []string { + if cluster == nil { + return []string{} + } + return sortVersionsDesc(cluster.Version().AvailableUpgrades()) +} + +func GetNodePoolAvailableUpgrades(nodePool *cmv1.NodePool) []string { + if nodePool == nil { + return []string{} + } + return sortVersionsDesc(nodePool.Version().AvailableUpgrades()) +} + func CreateVersionID(version string, channelGroup string) string { versionID := fmt.Sprintf("openshift-v%s", version) if channelGroup != DefaultChannelGroup { @@ -438,6 +460,7 @@ func (c *Client) ValidateVersion(version string, versionList []string, channelGr Search(filter). Page(1). Size(1). + Parameter("product", HcpProduct). Send() if err != nil { return "", handleErr(response.Error(), err) @@ -456,3 +479,16 @@ func (c *Client) ValidateVersion(version string, versionList []string, channelGr return CreateVersionID(version, channelGroup), nil } + +// sortVersionsDesc sorts list in descending order +func sortVersionsDesc(versions []string) []string { + sort.Slice(versions, func(i, j int) bool { + a, erra := ver.NewVersion(versions[i]) + b, errb := ver.NewVersion(versions[j]) + if erra != nil || errb != nil { + return false + } + return a.GreaterThan(b) + }) + return versions +} diff --git a/pkg/test/helpers.go b/pkg/test/helpers.go index 30e7db397c..e61507b0b1 100644 --- a/pkg/test/helpers.go +++ b/pkg/test/helpers.go @@ -6,6 +6,7 @@ import ( "io" "net/http" "os" + "reflect" "time" . "github.com/onsi/ginkgo/v2" @@ -141,6 +142,39 @@ func FormatNodePoolUpgradePolicyList(upgrades []*v1.NodePoolUpgradePolicy) strin }`, len(upgrades), len(upgrades), outputJson.String()) } +// FormatResource wraps the SDK marshalling and returns a string starting from an object +func FormatResource(resource interface{}) string { + var outputJson bytes.Buffer + var err error + switch reflect.TypeOf(resource).String() { + case "*v1.Version": + if res, ok := resource.(*v1.Version); ok { + err = v1.MarshalVersion(res, &outputJson) + } + case "*v1.NodePool": + if res, ok := resource.(*v1.NodePool); ok { + err = v1.MarshalNodePool(res, &outputJson) + } + case "*v1.MachinePool": + if res, ok := resource.(*v1.MachinePool); ok { + err = v1.MarshalMachinePool(res, &outputJson) + } + case "*v1.ControlPlaneUpgradePolicy": + if res, ok := resource.(*v1.ControlPlaneUpgradePolicy); ok { + err = v1.MarshalControlPlaneUpgradePolicy(res, &outputJson) + } + default: + { + return "NOTIMPLEMENTED" + } + } + if err != nil { + return err.Error() + } + + return outputJson.String() +} + // TestingRuntime is a wrapper for the structure used for testing type TestingRuntime struct { SsoServer *ghttp.Server