From 64c859404f3999eaef352456968f49fe7acab730 Mon Sep 17 00:00:00 2001 From: sattila1999 Date: Fri, 18 Oct 2024 15:38:54 +0200 Subject: [PATCH 01/11] Adding CSS security mode, security group and flavor update functions --- .../css/v1/cluster_update_flavor_test.go | 51 +++++++ .../css/v1/cluster_update_sg_test.go | 28 ++++ .../css/v1/cluster_update_sm_test.go | 141 ++++++++++++++++++ .../css/v1/clusters/UpdateClusterFlavor.go | 54 +++++++ .../css/v1/clusters/UpdateSecurityGroup.go | 30 ++++ .../css/v1/clusters/UpdateSecurityMode.go | 34 +++++ openstack/css/v1/clusters/util.go | 26 ++++ 7 files changed, 364 insertions(+) create mode 100644 acceptance/openstack/css/v1/cluster_update_flavor_test.go create mode 100644 acceptance/openstack/css/v1/cluster_update_sg_test.go create mode 100644 acceptance/openstack/css/v1/cluster_update_sm_test.go create mode 100644 openstack/css/v1/clusters/UpdateClusterFlavor.go create mode 100644 openstack/css/v1/clusters/UpdateSecurityGroup.go create mode 100644 openstack/css/v1/clusters/UpdateSecurityMode.go diff --git a/acceptance/openstack/css/v1/cluster_update_flavor_test.go b/acceptance/openstack/css/v1/cluster_update_flavor_test.go new file mode 100644 index 000000000..08d145ff7 --- /dev/null +++ b/acceptance/openstack/css/v1/cluster_update_flavor_test.go @@ -0,0 +1,51 @@ +package v1 + +import ( + "os" + "testing" + + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" +) + +func TestUpdateClusterFlavor(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + + clusterID := os.Getenv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("CSS_CLUSTER_ID needs to be defined") + } + + err = clusters.UpdateClusterFlavor(client, clusterID, clusters.ClusterFlavorOpts{ + NeedCheckReplica: false, + // css.medium.8: ced8d1a7-eff8-4e30-a3de-cd9578fd518f + // css.xlarge.2: d9dc06ae-b9c4-4ef4-acd8-953ef4205e27 + NewFlavorID: "d9dc06ae-b9c4-4ef4-acd8-953ef4205e27", + }) + th.AssertNoErr(t, err) + + timeout := 1200 + + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) +} + +func TestUpdateClusterNodeFlavor(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + + clusterID := os.Getenv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("CSS_CLUSTER_ID needs to be defined") + } + + err = clusters.UpdateClusterFlavor(client, clusterID, clusters.ClusterNodeFlavorOpts{ + NeedCheckReplica: false, + NewFlavorID: "ced8d1a7-eff8-4e30-a3de-cd9578fd518f", + NodeType: "ess", + }) + th.AssertNoErr(t, err) + + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) +} diff --git a/acceptance/openstack/css/v1/cluster_update_sg_test.go b/acceptance/openstack/css/v1/cluster_update_sg_test.go new file mode 100644 index 000000000..e35622092 --- /dev/null +++ b/acceptance/openstack/css/v1/cluster_update_sg_test.go @@ -0,0 +1,28 @@ +package v1 + +import ( + "os" + "testing" + + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" +) + +func TestUpdateSecurityGroup(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + + clusterID := os.Getenv("CSS_CLUSTER_ID") + sgID := os.Getenv("SECURITY_GROUP_ID") + if clusterID == "" || sgID == "" { + t.Skip("Both CSS_CLUSTER_ID and SECURITY_GROUP_ID needs to be defined") + } + + err = clusters.UpdateSecurityGroup(client, clusterID, clusters.SecurityGroupOpts{ + SecurityGroupID: sgID, + }) + th.AssertNoErr(t, err) + + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) +} diff --git a/acceptance/openstack/css/v1/cluster_update_sm_test.go b/acceptance/openstack/css/v1/cluster_update_sm_test.go new file mode 100644 index 000000000..c7f049e49 --- /dev/null +++ b/acceptance/openstack/css/v1/cluster_update_sm_test.go @@ -0,0 +1,141 @@ +package v1 + +import ( + "os" + "testing" + + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" +) + +func TestUpdateSecurityModeEnableAll(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + clusterID := os.Getenv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("CSS_CLUSTER_ID needs to be defined.") + } + + cssCluster, err := clusters.Get(client, clusterID) + th.AssertNoErr(t, err) + + httpsEnable := cssCluster.HttpsEnabled + authEnable := cssCluster.AuthorityEnabled + + if httpsEnable == false && authEnable == false { + httpsEnable = !httpsEnable + authEnable = !authEnable + } else { + t.Skip("The HTTPS and the Authority is already enabled.") + } + + var adminPWD string = "P4s77gfhz!+%" + + err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ + AuthorityEnable: authEnable, + AdminPwd: adminPWD, + HttpsEnable: httpsEnable, + }) + th.AssertNoErr(t, err) + + th.AssertNoErr(t, clusters.WaitForClusterOperationSucces(client, clusterID, timeout)) + +} + +func TestUpdateSecurityModeDisableAll(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + clusterID := os.Getenv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("CSS_CLUSTER_ID needs to be defined.") + } + + cssCluster, err := clusters.Get(client, clusterID) + th.AssertNoErr(t, err) + + httpsEnable := cssCluster.HttpsEnabled + authEnable := cssCluster.AuthorityEnabled + + if httpsEnable == true && authEnable == true { + httpsEnable = !httpsEnable + authEnable = !authEnable + } else { + t.Skip("The HTTPS and the Authority is already disabled.") + } + + err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ + AuthorityEnable: authEnable, + HttpsEnable: httpsEnable, + }) + th.AssertNoErr(t, err) + + th.AssertNoErr(t, clusters.WaitForClusterOperationSucces(client, clusterID, timeout)) + +} + +func TestUpdateSecurityModeEnableHttps(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + clusterID := os.Getenv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("CSS_CLUSTER_ID needs to be defined.") + } + + cssCluster, err := clusters.Get(client, clusterID) + th.AssertNoErr(t, err) + + httpsEnable := cssCluster.HttpsEnabled + + if httpsEnable == false { + httpsEnable = !httpsEnable + } else { + t.Skip("HTTPS is already enabled.") + } + + var adminPWD string = "P4s77gfhz!+%" + var authEnable bool = true + + err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ + AuthorityEnable: authEnable, + AdminPwd: adminPWD, + HttpsEnable: httpsEnable, + }) + th.AssertNoErr(t, err) + + th.AssertNoErr(t, clusters.WaitForClusterOperationSucces(client, clusterID, timeout)) + +} + +func TestUpdateSecurityModeEnableAuthority(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + clusterID := os.Getenv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("CSS_CLUSTER_ID needs to be defined.") + } + + cssCluster, err := clusters.Get(client, clusterID) + th.AssertNoErr(t, err) + + authEnable := cssCluster.AuthorityEnabled + + if authEnable == false { + authEnable = !authEnable + } else { + t.Skip("Authority is already enabled.") + } + + var adminPWD string = "P4s77gfhz!+%" + var httpsEnable bool = false + + err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ + AuthorityEnable: authEnable, + AdminPwd: adminPWD, + HttpsEnable: httpsEnable, + }) + th.AssertNoErr(t, err) + + th.AssertNoErr(t, clusters.WaitForClusterOperationSucces(client, clusterID, timeout)) + +} diff --git a/openstack/css/v1/clusters/UpdateClusterFlavor.go b/openstack/css/v1/clusters/UpdateClusterFlavor.go new file mode 100644 index 000000000..e0cd853ca --- /dev/null +++ b/openstack/css/v1/clusters/UpdateClusterFlavor.go @@ -0,0 +1,54 @@ +package clusters + +import ( + "fmt" + + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" +) + +type ClusterFlavorOptsBuilder interface { +} + +type ClusterFlavorOpts struct { + // Indicates whether to verify replicas. + NeedCheckReplica bool `json:"needCheckReplica"` + // ID of the new flavor. + NewFlavorID string `json:"newFlavorId" required:"true"` +} + +type ClusterNodeFlavorOpts struct { + // Indicates whether to verify replicas. + NeedCheckReplica bool `json:"needCheckReplica"` + // ID of the new flavor. + NewFlavorID string `json:"newFlavorId" required:"true"` + // Type of the cluster node to modify. + NodeType string `json:"type" required:"true"` +} + +func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID string, opts ClusterFlavorOptsBuilder) error { + url := "" + + switch options := opts.(type) { + case ClusterFlavorOpts: + url = client.ServiceURL("clusters", clusterID, "flavor") + case ClusterNodeFlavorOpts: + url = client.ServiceURL("clusters", clusterID, options.NodeType, "flavor") + default: + return fmt.Errorf("invalid options type provided: %T", opts) + } + + b, err := build.RequestBody(opts, "") + if err != nil { + return err + } + + _, err = client.Post(url, b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + MoreHeaders: map[string]string{ + "Content-Type": "application/json", + }, + }) + + return err +} diff --git a/openstack/css/v1/clusters/UpdateSecurityGroup.go b/openstack/css/v1/clusters/UpdateSecurityGroup.go new file mode 100644 index 000000000..3feef0cbb --- /dev/null +++ b/openstack/css/v1/clusters/UpdateSecurityGroup.go @@ -0,0 +1,30 @@ +package clusters + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" +) + +type SecurityGroupOpts struct { + // Security group ID. + SecurityGroupID string `json:"security_group_ids" required:"true"` +} + +// UpdateSecurityGroup - change the security group of a cluster. +func UpdateSecurityGroup(client *golangsdk.ServiceClient, clusterID string, opts SecurityGroupOpts) error { + b, err := build.RequestBody(opts, "") + if err != nil { + return err + } + + url := client.ServiceURL("clusters", clusterID, "sg/change") + + _, err = client.Post(url, b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + MoreHeaders: map[string]string{ + "Content-Type": "application/json", + }, + }) + + return err +} diff --git a/openstack/css/v1/clusters/UpdateSecurityMode.go b/openstack/css/v1/clusters/UpdateSecurityMode.go new file mode 100644 index 000000000..68f412361 --- /dev/null +++ b/openstack/css/v1/clusters/UpdateSecurityMode.go @@ -0,0 +1,34 @@ +package clusters + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" +) + +type SecurityModeOpts struct { + // Indicates whether to enable the security mode. + AuthorityEnable bool `json:"authorityEnable"` + // Cluster password. + AdminPwd string `json:"adminPwd"` + // Indicates whether to enable HTTPS. + HttpsEnable bool `json:"httpsEnable"` +} + +// UpdateSecurityMode - change the security mode of a cluster. +func UpdateSecurityMode(client *golangsdk.ServiceClient, clusterID string, opts SecurityModeOpts) error { + b, err := build.RequestBody(opts, "") + if err != nil { + return err + } + + url := client.ServiceURL("clusters", clusterID, "mode/change") + + _, err = client.Post(url, b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + MoreHeaders: map[string]string{ + "Content-Type": "application/json", + }, + }) + + return err +} diff --git a/openstack/css/v1/clusters/util.go b/openstack/css/v1/clusters/util.go index e7285d474..01f79816d 100644 --- a/openstack/css/v1/clusters/util.go +++ b/openstack/css/v1/clusters/util.go @@ -54,3 +54,29 @@ func WaitForClusterToExtend(client *golangsdk.ServiceClient, id string, timeout return false, fmt.Errorf("unexpected cluster actions: %v; progress: %v", cluster.Actions, cluster.ActionProgress) }) } + +func WaitForCluster(client *golangsdk.ServiceClient, id string, timeout int) error { + return golangsdk.WaitFor(timeout, func() (bool, error) { + cluster, err := Get(client, id) + if err != nil { + if _, ok := err.(golangsdk.BaseError); ok { + return true, err + } + log.Printf("Error waiting for CSS cluster to end active task: %s", err) // ignore connection-related errors + return false, nil + } + // No active action + if len(cluster.Actions) == 0 { + return true, nil + } + // if cluster.Actions[0] == "RESIZING_FLAVOR" { + // time.Sleep(30 * time.Second) // make a bigger wait if it's not ready + // return false, nil + // } + if len(cluster.Actions[0]) != 0 { + time.Sleep(30 * time.Second) // make a bigger wait if it's not ready + return false, nil + } + return false, fmt.Errorf("unexpected cluster actions: %v; progress: %v", cluster.Actions, cluster.ActionProgress) + }) +} From b919e327aa9ba94ef0f07b79633ab4a4ec34d694 Mon Sep 17 00:00:00 2001 From: Vineet Pruthi Date: Mon, 11 Nov 2024 08:02:28 +0100 Subject: [PATCH 02/11] Adding CSS ClusterScaleIn func --- .../openstack/css/v1/cluster_scale_in_test.go | 36 +++++++++++++ openstack/css/v1/clusters/ScaleInCluster.go | 51 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 acceptance/openstack/css/v1/cluster_scale_in_test.go create mode 100644 openstack/css/v1/clusters/ScaleInCluster.go diff --git a/acceptance/openstack/css/v1/cluster_scale_in_test.go b/acceptance/openstack/css/v1/cluster_scale_in_test.go new file mode 100644 index 000000000..98bff134c --- /dev/null +++ b/acceptance/openstack/css/v1/cluster_scale_in_test.go @@ -0,0 +1,36 @@ +package v1 + +import ( + "os" + "testing" + + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" +) + +func TestScaleInCluster(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + + clusterID := os.Getenv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("CSS_CLUSTER_ID needs to be defined") + } + + err = clusters.ScaleInCluster(client, clusterID, []clusters.ScaleInOpts{ + { + Type: "ess", + ReduceNodeNum: 1, + }, + { + Type: "ess-cold", + ReduceNodeNum: 2, + }, + }) + th.AssertNoErr(t, err) + + timeout := 1200 + + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) +} diff --git a/openstack/css/v1/clusters/ScaleInCluster.go b/openstack/css/v1/clusters/ScaleInCluster.go new file mode 100644 index 000000000..1fdf7a8ca --- /dev/null +++ b/openstack/css/v1/clusters/ScaleInCluster.go @@ -0,0 +1,51 @@ +package clusters + +import ( + "strings" + + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" +) + +// ScaleInOpts defines options for scaling in a cluster. +type ScaleInOpts struct { + // Type specifies the type of instance to be scaled in. + // Select at least one from `ess`, `ess-cold`, `ess-master`, and `ess-client`. + Type string `json:"type"` + // ReduceNodeNum is the number of nodes to be removed. + // After scaling in, there must be at least one node in each AZ under each node type. + // In a cross-AZ cluster, the difference between the number of nodes of the same type in different AZs cannot exceed 1. + // For a cluster with Master nodes, the number of removed master nodes in a scale-in must be fewer than half of the original master node count. + ReduceNodeNum int `json:"reducedNodeNum"` +} + +// ScaleInRequest is a wrapper to structure the "shrink" key in the JSON body. +type ScaleInRequest struct { + Shrink []ScaleInOpts `json:"shrink"` +} + +// ScaleInCluster scales in a cluster by removing specified nodes. +func ScaleInCluster(client *golangsdk.ServiceClient, clusterID string, opts []ScaleInOpts) error { + // Wrap opts in ScaleInRequest to match the required JSON structure. + request := ScaleInRequest{ + Shrink: opts, + } + + b, err := build.RequestBody(request, "") + if err != nil { + return err + } + + // POST /v1.0/extend/{project_id}/clusters/{cluster_id}/role/shrink + url := client.ServiceURL("clusters", clusterID, "role", "shrink") + convertedURL := strings.Replace(url, "v1.0", "v1.0/extend", 1) + + _, err = client.Post(convertedURL, b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + MoreHeaders: map[string]string{ + "Content-Type": "application/json", + }, + }) + + return err +} From 35fdf2d8690768985a29e5b790d5018811090ade Mon Sep 17 00:00:00 2001 From: gerzson Date: Tue, 12 Nov 2024 17:51:41 +0100 Subject: [PATCH 03/11] add changeclustername, changepassword, restartcluster implementation and test code --- .../css/v1/change_cluser_name_test.go | 28 +++++++++++++++++ .../openstack/css/v1/change_password_test.go | 30 +++++++++++++++++++ .../openstack/css/v1/restart_cluster_test.go | 25 ++++++++++++++++ .../css/v1/clusters/ChangeClusterName.go | 22 ++++++++++++++ openstack/css/v1/clusters/ChangePassword.go | 22 ++++++++++++++ openstack/css/v1/clusters/RestartCluster.go | 10 +++++++ 6 files changed, 137 insertions(+) create mode 100644 acceptance/openstack/css/v1/change_cluser_name_test.go create mode 100644 acceptance/openstack/css/v1/change_password_test.go create mode 100644 acceptance/openstack/css/v1/restart_cluster_test.go create mode 100644 openstack/css/v1/clusters/ChangeClusterName.go create mode 100644 openstack/css/v1/clusters/ChangePassword.go create mode 100644 openstack/css/v1/clusters/RestartCluster.go diff --git a/acceptance/openstack/css/v1/change_cluser_name_test.go b/acceptance/openstack/css/v1/change_cluser_name_test.go new file mode 100644 index 000000000..c98ae8984 --- /dev/null +++ b/acceptance/openstack/css/v1/change_cluser_name_test.go @@ -0,0 +1,28 @@ +package v1 + +import ( + "os" + "testing" + + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/tools" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" +) + +func TestChangeClusterNameWorkflow(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + + clusterID := os.Getenv("CSS_CLUSTER_ID") + + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` need to be defined") + } + + opts := clusters.ChangeClusterNameOpts{ + DisplayName: tools.RandomString("changed-css-", 4), + } + err = clusters.ChangeClusterName(client, opts, clusterID) + th.AssertNoErr(t, err) +} diff --git a/acceptance/openstack/css/v1/change_password_test.go b/acceptance/openstack/css/v1/change_password_test.go new file mode 100644 index 000000000..9c3dd7832 --- /dev/null +++ b/acceptance/openstack/css/v1/change_password_test.go @@ -0,0 +1,30 @@ +package v1 + +import ( + "os" + "testing" + + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/tools" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" +) + +func TestChangePasswordWorkflow(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + + clusterID := os.Getenv("CSS_CLUSTER_ID") + + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` need to be defined") + } + + opts := clusters.ChangePasswordOpts{ + + NewPassword: tools.RandomString("newpass-css-", 4), + } + err = clusters.ChangePassword(client, opts, clusterID) + + th.AssertNoErr(t, err) +} diff --git a/acceptance/openstack/css/v1/restart_cluster_test.go b/acceptance/openstack/css/v1/restart_cluster_test.go new file mode 100644 index 000000000..e472dd8d0 --- /dev/null +++ b/acceptance/openstack/css/v1/restart_cluster_test.go @@ -0,0 +1,25 @@ +package v1 + +import ( + "os" + "testing" + + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" +) + +func TestRestartClusterWorkflow(t *testing.T) { + + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + + cssCluserID := os.Getenv("CSS_CLUSTER_ID") + + if cssCluserID == "" { + t.Skip("`CSS_CLUSTER_ID` need to be defined") + } + + err = clusters.RestartCluster(client, cssCluserID) + th.AssertNoErr(t, err) +} diff --git a/openstack/css/v1/clusters/ChangeClusterName.go b/openstack/css/v1/clusters/ChangeClusterName.go new file mode 100644 index 000000000..02d024164 --- /dev/null +++ b/openstack/css/v1/clusters/ChangeClusterName.go @@ -0,0 +1,22 @@ +package clusters + +import golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + +type ChangeClusterNameOpts struct { + // DisplayName contains options for new name + // This object is passed to the snapshots.ChangeClusterName function. + DisplayName string `json:"displayName" required:"true"` +} + +func ChangeClusterName(client *golangsdk.ServiceClient, opts ChangeClusterNameOpts, clusterId string) (err error) { + // ChangeClusterName will change cluster name based on ChangeClusterNameOpts + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return + } + + _, err = client.Post(client.ServiceURL("clusters", clusterId, "changename"), b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} diff --git a/openstack/css/v1/clusters/ChangePassword.go b/openstack/css/v1/clusters/ChangePassword.go new file mode 100644 index 000000000..f5a94faf6 --- /dev/null +++ b/openstack/css/v1/clusters/ChangePassword.go @@ -0,0 +1,22 @@ +package clusters + +import golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + +type ChangePasswordOpts struct { + // DisplayName contains options for new name + // This object is passed to the snapshots.ChangeClusterName function. + NewPassword string `json:"newpassword" required:"true"` +} + +func ChangePassword(client *golangsdk.ServiceClient, opts ChangePasswordOpts, clusterId string) (err error) { + // ChangeClusterName will change cluster name based on ChangeClusterNameOpts + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return + } + + _, err = client.Post(client.ServiceURL("clusters", clusterId, "password/reset"), b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} diff --git a/openstack/css/v1/clusters/RestartCluster.go b/openstack/css/v1/clusters/RestartCluster.go new file mode 100644 index 000000000..70bf6307e --- /dev/null +++ b/openstack/css/v1/clusters/RestartCluster.go @@ -0,0 +1,10 @@ +package clusters + +import golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + +func RestartCluster(client *golangsdk.ServiceClient, clusterId string) (err error) { + _, err = client.Post(client.ServiceURL("clusters", clusterId, "restart"), nil, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} From b0fdcc9be4e8220fe22dfc0b9703db37133538b7 Mon Sep 17 00:00:00 2001 From: Vineet Pruthi Date: Wed, 13 Nov 2024 08:36:40 +0100 Subject: [PATCH 04/11] Adding CSS AddClusterNodes func --- .../css/v1/cluster_add_nodes_test.go | 35 ++++++++++++ openstack/css/v1/clusters/AddClusterNodes.go | 53 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 acceptance/openstack/css/v1/cluster_add_nodes_test.go create mode 100644 openstack/css/v1/clusters/AddClusterNodes.go diff --git a/acceptance/openstack/css/v1/cluster_add_nodes_test.go b/acceptance/openstack/css/v1/cluster_add_nodes_test.go new file mode 100644 index 000000000..fa94a457b --- /dev/null +++ b/acceptance/openstack/css/v1/cluster_add_nodes_test.go @@ -0,0 +1,35 @@ +package v1 + +import ( + "os" + "testing" + + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" +) + +func TestAddClusterNodes(t *testing.T) { + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + + nodeType := "ess-client" + + clusterID := os.Getenv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("CSS_CLUSTER_ID needs to be defined") + } + + _, err = clusters.AddClusterNodes(client, clusterID, nodeType, clusters.AddNodesOpts{ + // css.medium.8: ced8d1a7-eff8-4e30-a3de-cd9578fd518f + // css.xlarge.2: d9dc06ae-b9c4-4ef4-acd8-953ef4205e27 + Flavor: "d9dc06ae-b9c4-4ef4-acd8-953ef4205e27", + NodeSize: 1, + VolumeType: "HIGH", + }) + th.AssertNoErr(t, err) + + timeout := 1200 + + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) +} diff --git a/openstack/css/v1/clusters/AddClusterNodes.go b/openstack/css/v1/clusters/AddClusterNodes.go new file mode 100644 index 000000000..553c3dba6 --- /dev/null +++ b/openstack/css/v1/clusters/AddClusterNodes.go @@ -0,0 +1,53 @@ +package clusters + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +// ScaleInOpts defines options for scaling in a cluster. +type AddNodesOpts struct { + // NodeSize - Number of nodes. The value range is 1 to 32. + // If the node type is ess-master, the number of nodes must be an odd number in the range 3 to 10. + // If the node type is ess-client, the number of nodes must be in the range 1 to 32. + NodeSize int `json:"node_size" required:"true"` + // Flavor - Flavor ID. + Flavor string `json:"flavor_ref" required:"true"` + // Type of the volume. + // One of: + // - `COMMON`: Common I/O + // - `HIGH`: High I/O + // - `ULTRAHIGH`: Ultra-high I/O + VolumeType string `json:"volume_type" required:"true"` +} + +func AddClusterNodes(client *golangsdk.ServiceClient, clusterID string, NodeType string, opts AddNodesOpts) (*AddNodesResponse, error) { + + b, err := build.RequestBody(opts, "type") + if err != nil { + return nil, err + } + + // POST /v1.0/{project_id}/clusters/{cluster_id}/type/{type}/independent + url := client.ServiceURL("clusters", clusterID, "type", NodeType, "independent") + + raw, err := client.Post(url, b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + MoreHeaders: map[string]string{ + "Content-Type": "application/json", + }, + }) + if err != nil { + return nil, err + } + + var res AddNodesResponse + err = extract.IntoStructPtr(raw.Body, &res, "") + + return &res, err +} + +type AddNodesResponse struct { + ID string `json:"id"` +} From eb2d89d52bb7188d56c8178b410e516611a83dfc Mon Sep 17 00:00:00 2001 From: sattila1999 Date: Tue, 19 Nov 2024 17:21:43 +0100 Subject: [PATCH 05/11] adding small fixes to CSS tests and functions --- .../css/v1/cluster_update_flavor_test.go | 24 ++++----- .../css/v1/cluster_update_sm_test.go | 52 ++++++++++--------- .../css/v1/clusters/UpdateClusterFlavor.go | 10 ++-- .../css/v1/clusters/UpdateSecurityGroup.go | 2 +- .../css/v1/clusters/UpdateSecurityMode.go | 8 +-- openstack/css/v1/clusters/util.go | 11 ++-- 6 files changed, 52 insertions(+), 55 deletions(-) diff --git a/acceptance/openstack/css/v1/cluster_update_flavor_test.go b/acceptance/openstack/css/v1/cluster_update_flavor_test.go index 08d145ff7..eccaeb349 100644 --- a/acceptance/openstack/css/v1/cluster_update_flavor_test.go +++ b/acceptance/openstack/css/v1/cluster_update_flavor_test.go @@ -14,20 +14,17 @@ func TestUpdateClusterFlavor(t *testing.T) { th.AssertNoErr(t, err) clusterID := os.Getenv("CSS_CLUSTER_ID") - if clusterID == "" { - t.Skip("CSS_CLUSTER_ID needs to be defined") + flavorID := os.Getenv("CSS_NEW_FLAVOR_ID") + if clusterID == "" || flavorID == "" { + t.Skip("CSS_CLUSTER_ID and CSS_NEW_FALVOR_ID need to be defined") } - err = clusters.UpdateClusterFlavor(client, clusterID, clusters.ClusterFlavorOpts{ + err = clusters.UpdateClusterFlavor(client, clusterID, flavorID, clusters.ClusterFlavorOpts{ NeedCheckReplica: false, - // css.medium.8: ced8d1a7-eff8-4e30-a3de-cd9578fd518f - // css.xlarge.2: d9dc06ae-b9c4-4ef4-acd8-953ef4205e27 - NewFlavorID: "d9dc06ae-b9c4-4ef4-acd8-953ef4205e27", + FlavorID: flavorID, }) th.AssertNoErr(t, err) - timeout := 1200 - th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) } @@ -36,14 +33,15 @@ func TestUpdateClusterNodeFlavor(t *testing.T) { th.AssertNoErr(t, err) clusterID := os.Getenv("CSS_CLUSTER_ID") - if clusterID == "" { - t.Skip("CSS_CLUSTER_ID needs to be defined") + flavorID := os.Getenv("CSS_NEW_FLAVOR_ID") + if clusterID == "" || flavorID == "" { + t.Skip("CSS_CLUSTER_ID and CSS_FLAVOR_ID need to be defined") } - err = clusters.UpdateClusterFlavor(client, clusterID, clusters.ClusterNodeFlavorOpts{ + err = clusters.UpdateClusterFlavor(client, clusterID, flavorID, clusters.ClusterNodeFlavorOpts{ NeedCheckReplica: false, - NewFlavorID: "ced8d1a7-eff8-4e30-a3de-cd9578fd518f", - NodeType: "ess", + FlavorID: flavorID, + Type: "ess-master", }) th.AssertNoErr(t, err) diff --git a/acceptance/openstack/css/v1/cluster_update_sm_test.go b/acceptance/openstack/css/v1/cluster_update_sm_test.go index c7f049e49..6e58e2526 100644 --- a/acceptance/openstack/css/v1/cluster_update_sm_test.go +++ b/acceptance/openstack/css/v1/cluster_update_sm_test.go @@ -13,8 +13,10 @@ func TestUpdateSecurityModeEnableAll(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) clusterID := os.Getenv("CSS_CLUSTER_ID") - if clusterID == "" { - t.Skip("CSS_CLUSTER_ID needs to be defined.") + adminPWD := os.Getenv("CSS_ADMIN_PASSWORD") + + if clusterID == "" || adminPWD == "" { + t.Skip("CSS_CLUSTER_ID and CSS_ADMIN_PASSWORD need to be defined.") } cssCluster, err := clusters.Get(client, clusterID) @@ -30,16 +32,14 @@ func TestUpdateSecurityModeEnableAll(t *testing.T) { t.Skip("The HTTPS and the Authority is already enabled.") } - var adminPWD string = "P4s77gfhz!+%" - err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ - AuthorityEnable: authEnable, - AdminPwd: adminPWD, - HttpsEnable: httpsEnable, + AuthorityEnabled: authEnable, + AdminPassword: adminPWD, + HttpsEnabled: httpsEnable, }) th.AssertNoErr(t, err) - th.AssertNoErr(t, clusters.WaitForClusterOperationSucces(client, clusterID, timeout)) + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) } @@ -65,12 +65,12 @@ func TestUpdateSecurityModeDisableAll(t *testing.T) { } err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ - AuthorityEnable: authEnable, - HttpsEnable: httpsEnable, + AuthorityEnabled: authEnable, + HttpsEnabled: httpsEnable, }) th.AssertNoErr(t, err) - th.AssertNoErr(t, clusters.WaitForClusterOperationSucces(client, clusterID, timeout)) + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) } @@ -78,8 +78,10 @@ func TestUpdateSecurityModeEnableHttps(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) clusterID := os.Getenv("CSS_CLUSTER_ID") - if clusterID == "" { - t.Skip("CSS_CLUSTER_ID needs to be defined.") + adminPWD := os.Getenv("CSS_ADMIN_PASSWORD") + + if clusterID == "" || adminPWD == "" { + t.Skip("CSS_CLUSTER_ID and CSS_ADMIN_PASSWORD need to be defined.") } cssCluster, err := clusters.Get(client, clusterID) @@ -93,17 +95,16 @@ func TestUpdateSecurityModeEnableHttps(t *testing.T) { t.Skip("HTTPS is already enabled.") } - var adminPWD string = "P4s77gfhz!+%" var authEnable bool = true err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ - AuthorityEnable: authEnable, - AdminPwd: adminPWD, - HttpsEnable: httpsEnable, + AuthorityEnabled: authEnable, + AdminPassword: adminPWD, + HttpsEnabled: httpsEnable, }) th.AssertNoErr(t, err) - th.AssertNoErr(t, clusters.WaitForClusterOperationSucces(client, clusterID, timeout)) + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) } @@ -111,8 +112,10 @@ func TestUpdateSecurityModeEnableAuthority(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) clusterID := os.Getenv("CSS_CLUSTER_ID") - if clusterID == "" { - t.Skip("CSS_CLUSTER_ID needs to be defined.") + adminPWD := os.Getenv("CSS_ADMIN_PASSWORD") + + if clusterID == "" || adminPWD == "" { + t.Skip("CSS_CLUSTER_ID and CSS_ADMIN_PASSWORD need to be defined.") } cssCluster, err := clusters.Get(client, clusterID) @@ -126,16 +129,15 @@ func TestUpdateSecurityModeEnableAuthority(t *testing.T) { t.Skip("Authority is already enabled.") } - var adminPWD string = "P4s77gfhz!+%" var httpsEnable bool = false err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ - AuthorityEnable: authEnable, - AdminPwd: adminPWD, - HttpsEnable: httpsEnable, + AuthorityEnabled: authEnable, + AdminPassword: adminPWD, + HttpsEnabled: httpsEnable, }) th.AssertNoErr(t, err) - th.AssertNoErr(t, clusters.WaitForClusterOperationSucces(client, clusterID, timeout)) + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) } diff --git a/openstack/css/v1/clusters/UpdateClusterFlavor.go b/openstack/css/v1/clusters/UpdateClusterFlavor.go index e0cd853ca..15af11bdf 100644 --- a/openstack/css/v1/clusters/UpdateClusterFlavor.go +++ b/openstack/css/v1/clusters/UpdateClusterFlavor.go @@ -14,26 +14,26 @@ type ClusterFlavorOpts struct { // Indicates whether to verify replicas. NeedCheckReplica bool `json:"needCheckReplica"` // ID of the new flavor. - NewFlavorID string `json:"newFlavorId" required:"true"` + FlavorID string `json:"newFlavorId" required:"true"` } type ClusterNodeFlavorOpts struct { // Indicates whether to verify replicas. NeedCheckReplica bool `json:"needCheckReplica"` // ID of the new flavor. - NewFlavorID string `json:"newFlavorId" required:"true"` + FlavorID string `json:"newFlavorId" required:"true"` // Type of the cluster node to modify. - NodeType string `json:"type" required:"true"` + Type string `json:"type" required:"true"` } -func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID string, opts ClusterFlavorOptsBuilder) error { +func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID string, flavorID string, opts ClusterFlavorOptsBuilder) error { url := "" switch options := opts.(type) { case ClusterFlavorOpts: url = client.ServiceURL("clusters", clusterID, "flavor") case ClusterNodeFlavorOpts: - url = client.ServiceURL("clusters", clusterID, options.NodeType, "flavor") + url = client.ServiceURL("clusters", clusterID, options.Type, "flavor") default: return fmt.Errorf("invalid options type provided: %T", opts) } diff --git a/openstack/css/v1/clusters/UpdateSecurityGroup.go b/openstack/css/v1/clusters/UpdateSecurityGroup.go index 3feef0cbb..2fa27ad94 100644 --- a/openstack/css/v1/clusters/UpdateSecurityGroup.go +++ b/openstack/css/v1/clusters/UpdateSecurityGroup.go @@ -17,7 +17,7 @@ func UpdateSecurityGroup(client *golangsdk.ServiceClient, clusterID string, opts return err } - url := client.ServiceURL("clusters", clusterID, "sg/change") + url := client.ServiceURL("clusters", clusterID, "sg", "change") _, err = client.Post(url, b, nil, &golangsdk.RequestOpts{ OkCodes: []int{200}, diff --git a/openstack/css/v1/clusters/UpdateSecurityMode.go b/openstack/css/v1/clusters/UpdateSecurityMode.go index 68f412361..bb4917cbb 100644 --- a/openstack/css/v1/clusters/UpdateSecurityMode.go +++ b/openstack/css/v1/clusters/UpdateSecurityMode.go @@ -7,11 +7,11 @@ import ( type SecurityModeOpts struct { // Indicates whether to enable the security mode. - AuthorityEnable bool `json:"authorityEnable"` + AuthorityEnabled bool `json:"authorityEnable"` // Cluster password. - AdminPwd string `json:"adminPwd"` + AdminPassword string `json:"adminPwd"` // Indicates whether to enable HTTPS. - HttpsEnable bool `json:"httpsEnable"` + HttpsEnabled bool `json:"httpsEnable"` } // UpdateSecurityMode - change the security mode of a cluster. @@ -21,7 +21,7 @@ func UpdateSecurityMode(client *golangsdk.ServiceClient, clusterID string, opts return err } - url := client.ServiceURL("clusters", clusterID, "mode/change") + url := client.ServiceURL("clusters", clusterID, "mode", "change") _, err = client.Post(url, b, nil, &golangsdk.RequestOpts{ OkCodes: []int{200}, diff --git a/openstack/css/v1/clusters/util.go b/openstack/css/v1/clusters/util.go index 01f79816d..a7b7a40f9 100644 --- a/openstack/css/v1/clusters/util.go +++ b/openstack/css/v1/clusters/util.go @@ -62,19 +62,16 @@ func WaitForCluster(client *golangsdk.ServiceClient, id string, timeout int) err if _, ok := err.(golangsdk.BaseError); ok { return true, err } - log.Printf("Error waiting for CSS cluster to end active task: %s", err) // ignore connection-related errors + log.Printf("Error waiting for CSS cluster to end active task: %s", err) return false, nil } - // No active action + if len(cluster.Actions) == 0 { return true, nil } - // if cluster.Actions[0] == "RESIZING_FLAVOR" { - // time.Sleep(30 * time.Second) // make a bigger wait if it's not ready - // return false, nil - // } + if len(cluster.Actions[0]) != 0 { - time.Sleep(30 * time.Second) // make a bigger wait if it's not ready + time.Sleep(30 * time.Second) return false, nil } return false, fmt.Errorf("unexpected cluster actions: %v; progress: %v", cluster.Actions, cluster.ActionProgress) From 53a35191b20f511142eae4c7477b44644f39f904 Mon Sep 17 00:00:00 2001 From: sattila1999 Date: Wed, 20 Nov 2024 14:17:11 +0100 Subject: [PATCH 06/11] Adding adjustments for CSS cluster_update_flavor function to use flavor name --- .../css/v1/cluster_update_flavor_test.go | 23 ++++---- .../css/v1/clusters/UpdateClusterFlavor.go | 58 +++++++++++++++++-- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/acceptance/openstack/css/v1/cluster_update_flavor_test.go b/acceptance/openstack/css/v1/cluster_update_flavor_test.go index eccaeb349..9200eee5a 100644 --- a/acceptance/openstack/css/v1/cluster_update_flavor_test.go +++ b/acceptance/openstack/css/v1/cluster_update_flavor_test.go @@ -14,14 +14,14 @@ func TestUpdateClusterFlavor(t *testing.T) { th.AssertNoErr(t, err) clusterID := os.Getenv("CSS_CLUSTER_ID") - flavorID := os.Getenv("CSS_NEW_FLAVOR_ID") - if clusterID == "" || flavorID == "" { - t.Skip("CSS_CLUSTER_ID and CSS_NEW_FALVOR_ID need to be defined") + flavor := os.Getenv("CSS_NEW_FLAVOR") + if clusterID == "" || flavor == "" { + t.Skip("CSS_CLUSTER_ID and CSS_NEW_FALVOR need to be defined") } - err = clusters.UpdateClusterFlavor(client, clusterID, flavorID, clusters.ClusterFlavorOpts{ + err = clusters.UpdateClusterFlavor(client, clusterID, flavor, clusters.ClusterFlavorOpts{ NeedCheckReplica: false, - FlavorID: flavorID, + Flavor: flavor, }) th.AssertNoErr(t, err) @@ -33,15 +33,16 @@ func TestUpdateClusterNodeFlavor(t *testing.T) { th.AssertNoErr(t, err) clusterID := os.Getenv("CSS_CLUSTER_ID") - flavorID := os.Getenv("CSS_NEW_FLAVOR_ID") - if clusterID == "" || flavorID == "" { - t.Skip("CSS_CLUSTER_ID and CSS_FLAVOR_ID need to be defined") + flavor := os.Getenv("CSS_NEW_FLAVOR") + nodeType := os.Getenv("CSS_NODE_TYPE") + if clusterID == "" || flavor == "" || nodeType == "" { + t.Skip("CSS_CLUSTER_ID, CSS_NEW_FLAVOR, and CSS_NODE_TYPE need to be defined") } - err = clusters.UpdateClusterFlavor(client, clusterID, flavorID, clusters.ClusterNodeFlavorOpts{ + err = clusters.UpdateClusterFlavor(client, clusterID, flavor, clusters.ClusterNodeFlavorOpts{ NeedCheckReplica: false, - FlavorID: flavorID, - Type: "ess-master", + Flavor: flavor, + Type: nodeType, }) th.AssertNoErr(t, err) diff --git a/openstack/css/v1/clusters/UpdateClusterFlavor.go b/openstack/css/v1/clusters/UpdateClusterFlavor.go index 15af11bdf..dbc93f4fb 100644 --- a/openstack/css/v1/clusters/UpdateClusterFlavor.go +++ b/openstack/css/v1/clusters/UpdateClusterFlavor.go @@ -5,6 +5,7 @@ import ( golangsdk "github.com/opentelekomcloud/gophertelekomcloud" "github.com/opentelekomcloud/gophertelekomcloud/internal/build" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/flavors" ) type ClusterFlavorOptsBuilder interface { @@ -14,31 +15,78 @@ type ClusterFlavorOpts struct { // Indicates whether to verify replicas. NeedCheckReplica bool `json:"needCheckReplica"` // ID of the new flavor. - FlavorID string `json:"newFlavorId" required:"true"` + Flavor string `json:"-" required:"true"` } type ClusterNodeFlavorOpts struct { // Indicates whether to verify replicas. NeedCheckReplica bool `json:"needCheckReplica"` // ID of the new flavor. - FlavorID string `json:"newFlavorId" required:"true"` + Flavor string `json:"-" required:"true"` // Type of the cluster node to modify. Type string `json:"type" required:"true"` } -func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID string, flavorID string, opts ClusterFlavorOptsBuilder) error { - url := "" +type apiFlavorOpts struct { + // Indicates whether to verify replicas. + NeedCheckReplica bool `json:"needCheckReplica"` + // ID of the new flavor. + NewFlavorID string `json:"newFlavorId"` +} + +func getFlavorIDByName(client *golangsdk.ServiceClient, flavorName string, nodeType string) (string, error) { + var flavorID string + versions, err := flavors.List(client) + + if err != nil { + return "", err + } + + findFlavorByName := flavors.FindFlavor(versions, flavors.FilterOpts{ + FlavorName: flavorName, + Type: nodeType, + }) + + if findFlavorByName == nil { + flavorID = flavorName + } else { + flavorID = findFlavorByName.FlavorID + } + + return flavorID, err +} + +func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID string, flavor string, opts ClusterFlavorOptsBuilder) error { + var url string + var flavorID string + var needCheckReplica bool + var err error switch options := opts.(type) { case ClusterFlavorOpts: url = client.ServiceURL("clusters", clusterID, "flavor") + needCheckReplica = options.NeedCheckReplica + flavorID, err = getFlavorIDByName(client, flavor, "ess") + if err != nil { + return err + } case ClusterNodeFlavorOpts: url = client.ServiceURL("clusters", clusterID, options.Type, "flavor") + needCheckReplica = options.NeedCheckReplica + flavorID, err = getFlavorIDByName(client, flavor, options.Type) + if err != nil { + return err + } default: return fmt.Errorf("invalid options type provided: %T", opts) } - b, err := build.RequestBody(opts, "") + apiOpts := apiFlavorOpts{ + NeedCheckReplica: needCheckReplica, + NewFlavorID: flavorID, + } + + b, err := build.RequestBody(apiOpts, "") if err != nil { return err } From 94abc9250910be8cd722b5e78d1c727dd6daaa94 Mon Sep 17 00:00:00 2001 From: Vineet Pruthi Date: Thu, 21 Nov 2024 08:41:53 +0100 Subject: [PATCH 07/11] Optimized css cluster functions and tests --- .../css/v1/change_cluser_name_test.go | 9 +-- .../openstack/css/v1/change_password_test.go | 9 +-- .../css/v1/cluster_add_nodes_test.go | 6 +- .../openstack/css/v1/cluster_scale_in_test.go | 10 +--- .../css/v1/cluster_update_flavor_test.go | 19 +++---- .../css/v1/cluster_update_sg_test.go | 8 +-- .../css/v1/cluster_update_sm_test.go | 7 +-- acceptance/openstack/css/v1/clusters_test.go | 9 +++ .../openstack/css/v1/restart_cluster_test.go | 9 +-- .../css/v1/clusters/ChangeClusterName.go | 15 +++-- openstack/css/v1/clusters/ChangePassword.go | 13 +++-- openstack/css/v1/clusters/RestartCluster.go | 6 +- .../css/v1/clusters/UpdateClusterFlavor.go | 56 ++++++++++--------- 13 files changed, 79 insertions(+), 97 deletions(-) diff --git a/acceptance/openstack/css/v1/change_cluser_name_test.go b/acceptance/openstack/css/v1/change_cluser_name_test.go index c98ae8984..2fc455419 100644 --- a/acceptance/openstack/css/v1/change_cluser_name_test.go +++ b/acceptance/openstack/css/v1/change_cluser_name_test.go @@ -1,7 +1,6 @@ package v1 import ( - "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" @@ -14,15 +13,11 @@ func TestChangeClusterNameWorkflow(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") - - if clusterID == "" { - t.Skip("`CSS_CLUSTER_ID` need to be defined") - } + clusterID := getEnvVar("CSS_CLUSTER_ID") opts := clusters.ChangeClusterNameOpts{ DisplayName: tools.RandomString("changed-css-", 4), } - err = clusters.ChangeClusterName(client, opts, clusterID) + err = clusters.ChangeClusterName(client, clusterID, opts) th.AssertNoErr(t, err) } diff --git a/acceptance/openstack/css/v1/change_password_test.go b/acceptance/openstack/css/v1/change_password_test.go index 9c3dd7832..9bd8facca 100644 --- a/acceptance/openstack/css/v1/change_password_test.go +++ b/acceptance/openstack/css/v1/change_password_test.go @@ -1,7 +1,6 @@ package v1 import ( - "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" @@ -14,17 +13,13 @@ func TestChangePasswordWorkflow(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") - - if clusterID == "" { - t.Skip("`CSS_CLUSTER_ID` need to be defined") - } + clusterID := getEnvVar("CSS_CLUSTER_ID") opts := clusters.ChangePasswordOpts{ NewPassword: tools.RandomString("newpass-css-", 4), } - err = clusters.ChangePassword(client, opts, clusterID) + err = clusters.ChangePassword(client, clusterID, opts) th.AssertNoErr(t, err) } diff --git a/acceptance/openstack/css/v1/cluster_add_nodes_test.go b/acceptance/openstack/css/v1/cluster_add_nodes_test.go index fa94a457b..92335beb2 100644 --- a/acceptance/openstack/css/v1/cluster_add_nodes_test.go +++ b/acceptance/openstack/css/v1/cluster_add_nodes_test.go @@ -1,7 +1,6 @@ package v1 import ( - "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" @@ -15,10 +14,7 @@ func TestAddClusterNodes(t *testing.T) { nodeType := "ess-client" - clusterID := os.Getenv("CSS_CLUSTER_ID") - if clusterID == "" { - t.Skip("CSS_CLUSTER_ID needs to be defined") - } + clusterID := getEnvVar("CSS_CLUSTER_ID") _, err = clusters.AddClusterNodes(client, clusterID, nodeType, clusters.AddNodesOpts{ // css.medium.8: ced8d1a7-eff8-4e30-a3de-cd9578fd518f diff --git a/acceptance/openstack/css/v1/cluster_scale_in_test.go b/acceptance/openstack/css/v1/cluster_scale_in_test.go index 98bff134c..01376d289 100644 --- a/acceptance/openstack/css/v1/cluster_scale_in_test.go +++ b/acceptance/openstack/css/v1/cluster_scale_in_test.go @@ -1,7 +1,6 @@ package v1 import ( - "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" @@ -13,20 +12,13 @@ func TestScaleInCluster(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") - if clusterID == "" { - t.Skip("CSS_CLUSTER_ID needs to be defined") - } + clusterID := getEnvVar("CSS_CLUSTER_ID") err = clusters.ScaleInCluster(client, clusterID, []clusters.ScaleInOpts{ { Type: "ess", ReduceNodeNum: 1, }, - { - Type: "ess-cold", - ReduceNodeNum: 2, - }, }) th.AssertNoErr(t, err) diff --git a/acceptance/openstack/css/v1/cluster_update_flavor_test.go b/acceptance/openstack/css/v1/cluster_update_flavor_test.go index 9200eee5a..b9c8d4325 100644 --- a/acceptance/openstack/css/v1/cluster_update_flavor_test.go +++ b/acceptance/openstack/css/v1/cluster_update_flavor_test.go @@ -1,7 +1,6 @@ package v1 import ( - "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" @@ -13,11 +12,8 @@ func TestUpdateClusterFlavor(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") - flavor := os.Getenv("CSS_NEW_FLAVOR") - if clusterID == "" || flavor == "" { - t.Skip("CSS_CLUSTER_ID and CSS_NEW_FALVOR need to be defined") - } + clusterID := getEnvVar("CSS_CLUSTER_ID") + flavor := getEnvVar("CSS_NEW_FLAVOR") err = clusters.UpdateClusterFlavor(client, clusterID, flavor, clusters.ClusterFlavorOpts{ NeedCheckReplica: false, @@ -25,6 +21,7 @@ func TestUpdateClusterFlavor(t *testing.T) { }) th.AssertNoErr(t, err) + timeout := 600 th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) } @@ -32,12 +29,9 @@ func TestUpdateClusterNodeFlavor(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") - flavor := os.Getenv("CSS_NEW_FLAVOR") - nodeType := os.Getenv("CSS_NODE_TYPE") - if clusterID == "" || flavor == "" || nodeType == "" { - t.Skip("CSS_CLUSTER_ID, CSS_NEW_FLAVOR, and CSS_NODE_TYPE need to be defined") - } + clusterID := getEnvVar("CSS_CLUSTER_ID") + flavor := getEnvVar("CSS_NEW_FLAVOR") + nodeType := getEnvVar("CSS_NODE_TYPE") err = clusters.UpdateClusterFlavor(client, clusterID, flavor, clusters.ClusterNodeFlavorOpts{ NeedCheckReplica: false, @@ -46,5 +40,6 @@ func TestUpdateClusterNodeFlavor(t *testing.T) { }) th.AssertNoErr(t, err) + timeout := 600 th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) } diff --git a/acceptance/openstack/css/v1/cluster_update_sg_test.go b/acceptance/openstack/css/v1/cluster_update_sg_test.go index e35622092..f7d7b5ccd 100644 --- a/acceptance/openstack/css/v1/cluster_update_sg_test.go +++ b/acceptance/openstack/css/v1/cluster_update_sg_test.go @@ -1,7 +1,6 @@ package v1 import ( - "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" @@ -13,11 +12,8 @@ func TestUpdateSecurityGroup(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") - sgID := os.Getenv("SECURITY_GROUP_ID") - if clusterID == "" || sgID == "" { - t.Skip("Both CSS_CLUSTER_ID and SECURITY_GROUP_ID needs to be defined") - } + clusterID := getEnvVar("CSS_CLUSTER_ID") + sgID := getEnvVar("SECURITY_GROUP_ID") err = clusters.UpdateSecurityGroup(client, clusterID, clusters.SecurityGroupOpts{ SecurityGroupID: sgID, diff --git a/acceptance/openstack/css/v1/cluster_update_sm_test.go b/acceptance/openstack/css/v1/cluster_update_sm_test.go index 6e58e2526..ec17a5b99 100644 --- a/acceptance/openstack/css/v1/cluster_update_sm_test.go +++ b/acceptance/openstack/css/v1/cluster_update_sm_test.go @@ -12,12 +12,9 @@ import ( func TestUpdateSecurityModeEnableAll(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") - adminPWD := os.Getenv("CSS_ADMIN_PASSWORD") - if clusterID == "" || adminPWD == "" { - t.Skip("CSS_CLUSTER_ID and CSS_ADMIN_PASSWORD need to be defined.") - } + clusterID := getEnvVar("CSS_CLUSTER_ID") + adminPWD := getEnvVar("CSS_ADMIN_PASSWORD") cssCluster, err := clusters.Get(client, clusterID) th.AssertNoErr(t, err) diff --git a/acceptance/openstack/css/v1/clusters_test.go b/acceptance/openstack/css/v1/clusters_test.go index af96071a5..373724b4e 100644 --- a/acceptance/openstack/css/v1/clusters_test.go +++ b/acceptance/openstack/css/v1/clusters_test.go @@ -2,6 +2,7 @@ package v1 import ( "log" + "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" @@ -13,6 +14,14 @@ import ( const timeout = 1200 +func getEnvVar(key string) string { + value := os.Getenv(key) + if value == "" { + panic("Missing required environment variable: " + key) + } + return value +} + func TestClusterWorkflow(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) diff --git a/acceptance/openstack/css/v1/restart_cluster_test.go b/acceptance/openstack/css/v1/restart_cluster_test.go index e472dd8d0..8f4f1662b 100644 --- a/acceptance/openstack/css/v1/restart_cluster_test.go +++ b/acceptance/openstack/css/v1/restart_cluster_test.go @@ -1,7 +1,6 @@ package v1 import ( - "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" @@ -14,12 +13,8 @@ func TestRestartClusterWorkflow(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - cssCluserID := os.Getenv("CSS_CLUSTER_ID") + clusterID := getEnvVar("CSS_CLUSTER_ID") - if cssCluserID == "" { - t.Skip("`CSS_CLUSTER_ID` need to be defined") - } - - err = clusters.RestartCluster(client, cssCluserID) + err = clusters.RestartCluster(client, clusterID) th.AssertNoErr(t, err) } diff --git a/openstack/css/v1/clusters/ChangeClusterName.go b/openstack/css/v1/clusters/ChangeClusterName.go index 02d024164..9bb4bdd18 100644 --- a/openstack/css/v1/clusters/ChangeClusterName.go +++ b/openstack/css/v1/clusters/ChangeClusterName.go @@ -1,6 +1,9 @@ package clusters -import golangsdk "github.com/opentelekomcloud/gophertelekomcloud" +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" +) type ChangeClusterNameOpts struct { // DisplayName contains options for new name @@ -8,15 +11,15 @@ type ChangeClusterNameOpts struct { DisplayName string `json:"displayName" required:"true"` } -func ChangeClusterName(client *golangsdk.ServiceClient, opts ChangeClusterNameOpts, clusterId string) (err error) { +func ChangeClusterName(client *golangsdk.ServiceClient, clusterID string, opts ChangeClusterNameOpts) error { // ChangeClusterName will change cluster name based on ChangeClusterNameOpts - b, err := golangsdk.BuildRequestBody(opts, "") + b, err := build.RequestBody(opts, "") if err != nil { - return + return err } - _, err = client.Post(client.ServiceURL("clusters", clusterId, "changename"), b, nil, &golangsdk.RequestOpts{ + _, err = client.Post(client.ServiceURL("clusters", clusterID, "changename"), b, nil, &golangsdk.RequestOpts{ OkCodes: []int{200}, }) - return + return err } diff --git a/openstack/css/v1/clusters/ChangePassword.go b/openstack/css/v1/clusters/ChangePassword.go index f5a94faf6..ec2aafa2f 100644 --- a/openstack/css/v1/clusters/ChangePassword.go +++ b/openstack/css/v1/clusters/ChangePassword.go @@ -1,6 +1,9 @@ package clusters -import golangsdk "github.com/opentelekomcloud/gophertelekomcloud" +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" +) type ChangePasswordOpts struct { // DisplayName contains options for new name @@ -8,14 +11,14 @@ type ChangePasswordOpts struct { NewPassword string `json:"newpassword" required:"true"` } -func ChangePassword(client *golangsdk.ServiceClient, opts ChangePasswordOpts, clusterId string) (err error) { +func ChangePassword(client *golangsdk.ServiceClient, clusterID string, opts ChangePasswordOpts) (err error) { // ChangeClusterName will change cluster name based on ChangeClusterNameOpts - b, err := golangsdk.BuildRequestBody(opts, "") + b, err := build.RequestBody(opts, "") if err != nil { - return + return err } - _, err = client.Post(client.ServiceURL("clusters", clusterId, "password/reset"), b, nil, &golangsdk.RequestOpts{ + _, err = client.Post(client.ServiceURL("clusters", clusterID, "password", "reset"), b, nil, &golangsdk.RequestOpts{ OkCodes: []int{200}, }) return diff --git a/openstack/css/v1/clusters/RestartCluster.go b/openstack/css/v1/clusters/RestartCluster.go index 70bf6307e..aef9c22b5 100644 --- a/openstack/css/v1/clusters/RestartCluster.go +++ b/openstack/css/v1/clusters/RestartCluster.go @@ -2,9 +2,9 @@ package clusters import golangsdk "github.com/opentelekomcloud/gophertelekomcloud" -func RestartCluster(client *golangsdk.ServiceClient, clusterId string) (err error) { - _, err = client.Post(client.ServiceURL("clusters", clusterId, "restart"), nil, nil, &golangsdk.RequestOpts{ +func RestartCluster(client *golangsdk.ServiceClient, clusterID string) error { + _, err := client.Post(client.ServiceURL("clusters", clusterID, "restart"), nil, nil, &golangsdk.RequestOpts{ OkCodes: []int{200}, }) - return + return err } diff --git a/openstack/css/v1/clusters/UpdateClusterFlavor.go b/openstack/css/v1/clusters/UpdateClusterFlavor.go index dbc93f4fb..e66ded4b7 100644 --- a/openstack/css/v1/clusters/UpdateClusterFlavor.go +++ b/openstack/css/v1/clusters/UpdateClusterFlavor.go @@ -8,18 +8,23 @@ import ( "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/flavors" ) -type ClusterFlavorOptsBuilder interface { -} +const ( + DefaultNodeType = "ess" +) + +type ClusterFlavorOptsBuilder interface{} +// ClusterFlavorOpts for updating the flavor of a cluster. type ClusterFlavorOpts struct { - // Indicates whether to verify replicas. + // Whether to verify replicas. NeedCheckReplica bool `json:"needCheckReplica"` // ID of the new flavor. Flavor string `json:"-" required:"true"` } +// ClusterNodeFlavorOpts for updating the flavor of a specific cluster node type. type ClusterNodeFlavorOpts struct { - // Indicates whether to verify replicas. + // Whether to verify replicas. NeedCheckReplica bool `json:"needCheckReplica"` // ID of the new flavor. Flavor string `json:"-" required:"true"` @@ -28,64 +33,65 @@ type ClusterNodeFlavorOpts struct { } type apiFlavorOpts struct { - // Indicates whether to verify replicas. + // Whether to verify replicas. NeedCheckReplica bool `json:"needCheckReplica"` // ID of the new flavor. NewFlavorID string `json:"newFlavorId"` } -func getFlavorIDByName(client *golangsdk.ServiceClient, flavorName string, nodeType string) (string, error) { - var flavorID string +// getFlavorIDByName retrieves the flavor ID for a given flavor name and node type. +func getFlavorIDByName(client *golangsdk.ServiceClient, flavorName, nodeType string) (string, error) { versions, err := flavors.List(client) - if err != nil { return "", err } + // Search for the flavor by name and node type. findFlavorByName := flavors.FindFlavor(versions, flavors.FilterOpts{ FlavorName: flavorName, Type: nodeType, }) if findFlavorByName == nil { - flavorID = flavorName - } else { - flavorID = findFlavorByName.FlavorID + return flavorName, nil } - return flavorID, err + return findFlavorByName.FlavorID, nil } -func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID string, flavor string, opts ClusterFlavorOptsBuilder) error { - var url string - var flavorID string - var needCheckReplica bool - var err error +// UpdateClusterFlavor updates the flavor of a cluster or a specific cluster node type. +func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID, flavor string, opts ClusterFlavorOptsBuilder) error { + var ( + url string + flavorID string + needCheckReplica bool + err error + ) switch options := opts.(type) { case ClusterFlavorOpts: + // Update cluster flavor. url = client.ServiceURL("clusters", clusterID, "flavor") needCheckReplica = options.NeedCheckReplica - flavorID, err = getFlavorIDByName(client, flavor, "ess") - if err != nil { - return err - } + flavorID, err = getFlavorIDByName(client, flavor, DefaultNodeType) case ClusterNodeFlavorOpts: + // Update specific node type flavor. url = client.ServiceURL("clusters", clusterID, options.Type, "flavor") needCheckReplica = options.NeedCheckReplica flavorID, err = getFlavorIDByName(client, flavor, options.Type) - if err != nil { - return err - } default: return fmt.Errorf("invalid options type provided: %T", opts) } + if err != nil { + return err + } + + // Construct the API payload. apiOpts := apiFlavorOpts{ NeedCheckReplica: needCheckReplica, NewFlavorID: flavorID, } - b, err := build.RequestBody(apiOpts, "") if err != nil { return err From 3a7ce658ec47a368cdce5c3b1c0473c0291f66e4 Mon Sep 17 00:00:00 2001 From: Vineet Pruthi Date: Thu, 21 Nov 2024 09:44:45 +0100 Subject: [PATCH 08/11] Updated CSS AddClusterNodes function --- .../css/v1/cluster_add_nodes_test.go | 4 +- openstack/css/v1/clusters/AddClusterNodes.go | 39 +++++++++++++++++-- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/acceptance/openstack/css/v1/cluster_add_nodes_test.go b/acceptance/openstack/css/v1/cluster_add_nodes_test.go index 92335beb2..0f973f8db 100644 --- a/acceptance/openstack/css/v1/cluster_add_nodes_test.go +++ b/acceptance/openstack/css/v1/cluster_add_nodes_test.go @@ -17,9 +17,7 @@ func TestAddClusterNodes(t *testing.T) { clusterID := getEnvVar("CSS_CLUSTER_ID") _, err = clusters.AddClusterNodes(client, clusterID, nodeType, clusters.AddNodesOpts{ - // css.medium.8: ced8d1a7-eff8-4e30-a3de-cd9578fd518f - // css.xlarge.2: d9dc06ae-b9c4-4ef4-acd8-953ef4205e27 - Flavor: "d9dc06ae-b9c4-4ef4-acd8-953ef4205e27", + Flavor: "css.xlarge.2", NodeSize: 1, VolumeType: "HIGH", }) diff --git a/openstack/css/v1/clusters/AddClusterNodes.go b/openstack/css/v1/clusters/AddClusterNodes.go index 553c3dba6..c2142bc80 100644 --- a/openstack/css/v1/clusters/AddClusterNodes.go +++ b/openstack/css/v1/clusters/AddClusterNodes.go @@ -13,7 +13,22 @@ type AddNodesOpts struct { // If the node type is ess-client, the number of nodes must be in the range 1 to 32. NodeSize int `json:"node_size" required:"true"` // Flavor - Flavor ID. - Flavor string `json:"flavor_ref" required:"true"` + Flavor string `json:"-" required:"true"` + // Type of the volume. + // One of: + // - `COMMON`: Common I/O + // - `HIGH`: High I/O + // - `ULTRAHIGH`: Ultra-high I/O + VolumeType string `json:"volume_type" required:"true"` +} + +type apiAddNodesOpts struct { + // NodeSize - Number of nodes. The value range is 1 to 32. + // If the node type is ess-master, the number of nodes must be an odd number in the range 3 to 10. + // If the node type is ess-client, the number of nodes must be in the range 1 to 32. + NodeSize int `json:"node_size" required:"true"` + // ID of the new flavor. + FlavorRef string `json:"flavor_ref" required:"true"` // Type of the volume. // One of: // - `COMMON`: Common I/O @@ -23,14 +38,31 @@ type AddNodesOpts struct { } func AddClusterNodes(client *golangsdk.ServiceClient, clusterID string, NodeType string, opts AddNodesOpts) (*AddNodesResponse, error) { + var ( + url string + flavorID string + err error + res AddNodesResponse + ) + + flavorID, err = getFlavorIDByName(client, opts.Flavor, NodeType) + if err != nil { + return &res, err + } + + apiOpts := apiAddNodesOpts{ + NodeSize: opts.NodeSize, + VolumeType: opts.VolumeType, + FlavorRef: flavorID, + } - b, err := build.RequestBody(opts, "type") + b, err := build.RequestBody(apiOpts, "type") if err != nil { return nil, err } // POST /v1.0/{project_id}/clusters/{cluster_id}/type/{type}/independent - url := client.ServiceURL("clusters", clusterID, "type", NodeType, "independent") + url = client.ServiceURL("clusters", clusterID, "type", NodeType, "independent") raw, err := client.Post(url, b, nil, &golangsdk.RequestOpts{ OkCodes: []int{200}, @@ -42,7 +74,6 @@ func AddClusterNodes(client *golangsdk.ServiceClient, clusterID string, NodeType return nil, err } - var res AddNodesResponse err = extract.IntoStructPtr(raw.Body, &res, "") return &res, err From ee551b5179d9f7718d9599b1973f6f07afc24778 Mon Sep 17 00:00:00 2001 From: sattila1999 Date: Sat, 14 Dec 2024 10:44:15 +0100 Subject: [PATCH 09/11] Adding modifications based on feedback --- .../css/v1/change_cluser_name_test.go | 6 +- .../openstack/css/v1/change_password_test.go | 6 +- .../css/v1/cluster_add_nodes_test.go | 71 ++++++++++++++- .../openstack/css/v1/cluster_scale_in_test.go | 6 +- .../css/v1/cluster_update_flavor_test.go | 91 ++++++++++++++++--- .../css/v1/cluster_update_sg_test.go | 9 +- .../css/v1/cluster_update_sm_test.go | 56 ++++++------ acceptance/openstack/css/v1/clusters_test.go | 9 -- .../openstack/css/v1/restart_cluster_test.go | 6 +- openstack/css/v1/clusters/AddClusterNodes.go | 39 +------- .../css/v1/clusters/UpdateClusterFlavor.go | 76 +++------------- .../css/v1/clusters/UpdateSecurityMode.go | 4 +- openstack/css/v1/clusters/util.go | 2 +- 13 files changed, 213 insertions(+), 168 deletions(-) diff --git a/acceptance/openstack/css/v1/change_cluser_name_test.go b/acceptance/openstack/css/v1/change_cluser_name_test.go index 2fc455419..a0ac36f6e 100644 --- a/acceptance/openstack/css/v1/change_cluser_name_test.go +++ b/acceptance/openstack/css/v1/change_cluser_name_test.go @@ -10,11 +10,13 @@ import ( ) func TestChangeClusterNameWorkflow(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := getEnvVar("CSS_CLUSTER_ID") - opts := clusters.ChangeClusterNameOpts{ DisplayName: tools.RandomString("changed-css-", 4), } diff --git a/acceptance/openstack/css/v1/change_password_test.go b/acceptance/openstack/css/v1/change_password_test.go index 9bd8facca..27a93568f 100644 --- a/acceptance/openstack/css/v1/change_password_test.go +++ b/acceptance/openstack/css/v1/change_password_test.go @@ -10,11 +10,13 @@ import ( ) func TestChangePasswordWorkflow(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := getEnvVar("CSS_CLUSTER_ID") - opts := clusters.ChangePasswordOpts{ NewPassword: tools.RandomString("newpass-css-", 4), diff --git a/acceptance/openstack/css/v1/cluster_add_nodes_test.go b/acceptance/openstack/css/v1/cluster_add_nodes_test.go index 0f973f8db..ac147ff59 100644 --- a/acceptance/openstack/css/v1/cluster_add_nodes_test.go +++ b/acceptance/openstack/css/v1/cluster_add_nodes_test.go @@ -5,21 +5,82 @@ import ( "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/flavors" th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" ) -func TestAddClusterNodes(t *testing.T) { +func TestAddClusterClientNodes(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) nodeType := "ess-client" + nodeSize := 1 + volumeType := "HIGH" - clusterID := getEnvVar("CSS_CLUSTER_ID") + cluster, err := clusters.Get(client, clusterID) + th.AssertNoErr(t, err) + + for _, instance := range cluster.Instances { + if instance.Type == nodeType { + t.Skip("Cluster already contains ess-client nodes.") + } + } + + Versions, err := flavors.List(client) + th.AssertNoErr(t, err) + filteredVersions := flavors.FilterVersions(Versions, flavors.FilterOpts{ + Version: cluster.Datastore.Version, + Type: nodeType, + }) + + _, err = clusters.AddClusterNodes(client, clusterID, nodeType, clusters.AddNodesOpts{ + Flavor: filteredVersions[0].Flavors[0].FlavorID, + NodeSize: nodeSize, + VolumeType: volumeType, + }) + th.AssertNoErr(t, err) + + timeout := 1200 + + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) +} + +func TestAddClusterMasterNodes(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) + + nodeType := "ess-master" + nodeSize := 3 + volumeType := "HIGH" + + cluster, err := clusters.Get(client, clusterID) + th.AssertNoErr(t, err) + + for _, instance := range cluster.Instances { + if instance.Type == nodeType { + t.Skip("Cluster already contains ess-master nodes.") + } + } + + Versions, err := flavors.List(client) + th.AssertNoErr(t, err) + filteredVersions := flavors.FilterVersions(Versions, flavors.FilterOpts{ + Version: cluster.Datastore.Version, + Type: nodeType, + }) _, err = clusters.AddClusterNodes(client, clusterID, nodeType, clusters.AddNodesOpts{ - Flavor: "css.xlarge.2", - NodeSize: 1, - VolumeType: "HIGH", + Flavor: filteredVersions[0].Flavors[0].FlavorID, + NodeSize: nodeSize, + VolumeType: volumeType, }) th.AssertNoErr(t, err) diff --git a/acceptance/openstack/css/v1/cluster_scale_in_test.go b/acceptance/openstack/css/v1/cluster_scale_in_test.go index 01376d289..db030dfea 100644 --- a/acceptance/openstack/css/v1/cluster_scale_in_test.go +++ b/acceptance/openstack/css/v1/cluster_scale_in_test.go @@ -9,11 +9,13 @@ import ( ) func TestScaleInCluster(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := getEnvVar("CSS_CLUSTER_ID") - err = clusters.ScaleInCluster(client, clusterID, []clusters.ScaleInOpts{ { Type: "ess", diff --git a/acceptance/openstack/css/v1/cluster_update_flavor_test.go b/acceptance/openstack/css/v1/cluster_update_flavor_test.go index b9c8d4325..9330583b2 100644 --- a/acceptance/openstack/css/v1/cluster_update_flavor_test.go +++ b/acceptance/openstack/css/v1/cluster_update_flavor_test.go @@ -5,41 +5,108 @@ import ( "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" + "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/flavors" th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" ) func TestUpdateClusterFlavor(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := getEnvVar("CSS_CLUSTER_ID") - flavor := getEnvVar("CSS_NEW_FLAVOR") + cluster, err := clusters.Get(client, clusterID) + th.AssertNoErr(t, err) + + var ( + currentFlavor string + newFlavorID string + instanceType string = "ess" + ) + + for _, instance := range cluster.Instances { + if instance.Type == instanceType { + currentFlavor = instance.SpecCode + break + } + } + + filterOpts := flavors.FilterOpts{ + Version: cluster.Datastore.Version, + Type: instanceType, + } - err = clusters.UpdateClusterFlavor(client, clusterID, flavor, clusters.ClusterFlavorOpts{ + versions, err := flavors.List(client) + th.AssertNoErr(t, err) + + filteredVersions := flavors.FilterVersions(versions, filterOpts) + if filteredVersions[0].Flavors[0].Name != currentFlavor { + newFlavorID = filteredVersions[0].Flavors[0].FlavorID + } else { + newFlavorID = filteredVersions[0].Flavors[1].FlavorID + } + + err = clusters.UpdateClusterFlavor(client, clusterID, clusters.ClusterFlavorOpts{ NeedCheckReplica: false, - Flavor: flavor, + NewFlavorID: newFlavorID, }) th.AssertNoErr(t, err) - timeout := 600 th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) } func TestUpdateClusterNodeFlavor(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := getEnvVar("CSS_CLUSTER_ID") - flavor := getEnvVar("CSS_NEW_FLAVOR") - nodeType := getEnvVar("CSS_NODE_TYPE") + cluster, err := clusters.Get(client, clusterID) + th.AssertNoErr(t, err) + + var ( + currentFlavor string + newFlavorID string + instanceType string + ) + + for _, instance := range cluster.Instances { + if instance.Type == "ess-cold" || instance.Type == "ess-client" || instance.Type == "ess-master" { + currentFlavor = instance.SpecCode + instanceType = instance.Type + break + } + } + + if instanceType == "" { + t.Skip("There are no client, cold or master nodes to change the flavor.") + } + + filterOpts := flavors.FilterOpts{ + Version: cluster.Datastore.Version, + Type: instanceType, + } + + versions, err := flavors.List(client) + th.AssertNoErr(t, err) + + filteredVersions := flavors.FilterVersions(versions, filterOpts) + if filteredVersions[0].Flavors[0].Name != currentFlavor { + newFlavorID = filteredVersions[0].Flavors[0].FlavorID + } else { + newFlavorID = filteredVersions[0].Flavors[1].FlavorID + } - err = clusters.UpdateClusterFlavor(client, clusterID, flavor, clusters.ClusterNodeFlavorOpts{ + err = clusters.UpdateClusterFlavor(client, clusterID, clusters.ClusterNodeFlavorOpts{ NeedCheckReplica: false, - Flavor: flavor, - Type: nodeType, + NewFlavorID: newFlavorID, + NodeType: instanceType, }) th.AssertNoErr(t, err) - timeout := 600 th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, timeout)) } diff --git a/acceptance/openstack/css/v1/cluster_update_sg_test.go b/acceptance/openstack/css/v1/cluster_update_sg_test.go index f7d7b5ccd..86f5028ae 100644 --- a/acceptance/openstack/css/v1/cluster_update_sg_test.go +++ b/acceptance/openstack/css/v1/cluster_update_sg_test.go @@ -4,17 +4,20 @@ import ( "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/openstack" "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" ) func TestUpdateSecurityGroup(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } + sgID := openstack.DefaultSecurityGroup(t) client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := getEnvVar("CSS_CLUSTER_ID") - sgID := getEnvVar("SECURITY_GROUP_ID") - err = clusters.UpdateSecurityGroup(client, clusterID, clusters.SecurityGroupOpts{ SecurityGroupID: sgID, }) diff --git a/acceptance/openstack/css/v1/cluster_update_sm_test.go b/acceptance/openstack/css/v1/cluster_update_sm_test.go index ec17a5b99..e577958ca 100644 --- a/acceptance/openstack/css/v1/cluster_update_sm_test.go +++ b/acceptance/openstack/css/v1/cluster_update_sm_test.go @@ -1,24 +1,26 @@ package v1 import ( - "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" + "github.com/opentelekomcloud/gophertelekomcloud/acceptance/tools" "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/clusters" th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" ) func TestUpdateSecurityModeEnableAll(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := getEnvVar("CSS_CLUSTER_ID") - adminPWD := getEnvVar("CSS_ADMIN_PASSWORD") - cssCluster, err := clusters.Get(client, clusterID) th.AssertNoErr(t, err) + adminPWD := tools.RandomString("newpass-css-", 4) httpsEnable := cssCluster.HttpsEnabled authEnable := cssCluster.AuthorityEnabled @@ -30,9 +32,9 @@ func TestUpdateSecurityModeEnableAll(t *testing.T) { } err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ - AuthorityEnabled: authEnable, + AuthorityEnabled: &authEnable, AdminPassword: adminPWD, - HttpsEnabled: httpsEnable, + HttpsEnabled: &httpsEnable, }) th.AssertNoErr(t, err) @@ -41,12 +43,12 @@ func TestUpdateSecurityModeEnableAll(t *testing.T) { } func TestUpdateSecurityModeDisableAll(t *testing.T) { - client, err := clients.NewCssV1Client() - th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") if clusterID == "" { - t.Skip("CSS_CLUSTER_ID needs to be defined.") + t.Skip("`CSS_CLUSTER_ID` must be defined") } + client, err := clients.NewCssV1Client() + th.AssertNoErr(t, err) cssCluster, err := clusters.Get(client, clusterID) th.AssertNoErr(t, err) @@ -62,8 +64,8 @@ func TestUpdateSecurityModeDisableAll(t *testing.T) { } err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ - AuthorityEnabled: authEnable, - HttpsEnabled: httpsEnable, + AuthorityEnabled: &authEnable, + HttpsEnabled: &httpsEnable, }) th.AssertNoErr(t, err) @@ -72,18 +74,17 @@ func TestUpdateSecurityModeDisableAll(t *testing.T) { } func TestUpdateSecurityModeEnableHttps(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") - adminPWD := os.Getenv("CSS_ADMIN_PASSWORD") - - if clusterID == "" || adminPWD == "" { - t.Skip("CSS_CLUSTER_ID and CSS_ADMIN_PASSWORD need to be defined.") - } cssCluster, err := clusters.Get(client, clusterID) th.AssertNoErr(t, err) + adminPWD := tools.RandomString("newpass-css-", 4) httpsEnable := cssCluster.HttpsEnabled if httpsEnable == false { @@ -95,9 +96,9 @@ func TestUpdateSecurityModeEnableHttps(t *testing.T) { var authEnable bool = true err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ - AuthorityEnabled: authEnable, + AuthorityEnabled: &authEnable, AdminPassword: adminPWD, - HttpsEnabled: httpsEnable, + HttpsEnabled: &httpsEnable, }) th.AssertNoErr(t, err) @@ -106,18 +107,17 @@ func TestUpdateSecurityModeEnableHttps(t *testing.T) { } func TestUpdateSecurityModeEnableAuthority(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := os.Getenv("CSS_CLUSTER_ID") - adminPWD := os.Getenv("CSS_ADMIN_PASSWORD") - - if clusterID == "" || adminPWD == "" { - t.Skip("CSS_CLUSTER_ID and CSS_ADMIN_PASSWORD need to be defined.") - } cssCluster, err := clusters.Get(client, clusterID) th.AssertNoErr(t, err) + adminPWD := tools.RandomString("newpass-css-", 4) authEnable := cssCluster.AuthorityEnabled if authEnable == false { @@ -129,9 +129,9 @@ func TestUpdateSecurityModeEnableAuthority(t *testing.T) { var httpsEnable bool = false err = clusters.UpdateSecurityMode(client, clusterID, clusters.SecurityModeOpts{ - AuthorityEnabled: authEnable, + AuthorityEnabled: &authEnable, AdminPassword: adminPWD, - HttpsEnabled: httpsEnable, + HttpsEnabled: &httpsEnable, }) th.AssertNoErr(t, err) diff --git a/acceptance/openstack/css/v1/clusters_test.go b/acceptance/openstack/css/v1/clusters_test.go index 373724b4e..af96071a5 100644 --- a/acceptance/openstack/css/v1/clusters_test.go +++ b/acceptance/openstack/css/v1/clusters_test.go @@ -2,7 +2,6 @@ package v1 import ( "log" - "os" "testing" "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" @@ -14,14 +13,6 @@ import ( const timeout = 1200 -func getEnvVar(key string) string { - value := os.Getenv(key) - if value == "" { - panic("Missing required environment variable: " + key) - } - return value -} - func TestClusterWorkflow(t *testing.T) { client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) diff --git a/acceptance/openstack/css/v1/restart_cluster_test.go b/acceptance/openstack/css/v1/restart_cluster_test.go index 8f4f1662b..2b25d0d88 100644 --- a/acceptance/openstack/css/v1/restart_cluster_test.go +++ b/acceptance/openstack/css/v1/restart_cluster_test.go @@ -10,11 +10,13 @@ import ( func TestRestartClusterWorkflow(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CSS_CLUSTER_ID") + if clusterID == "" { + t.Skip("`CSS_CLUSTER_ID` must be defined") + } client, err := clients.NewCssV1Client() th.AssertNoErr(t, err) - clusterID := getEnvVar("CSS_CLUSTER_ID") - err = clusters.RestartCluster(client, clusterID) th.AssertNoErr(t, err) } diff --git a/openstack/css/v1/clusters/AddClusterNodes.go b/openstack/css/v1/clusters/AddClusterNodes.go index c2142bc80..553c3dba6 100644 --- a/openstack/css/v1/clusters/AddClusterNodes.go +++ b/openstack/css/v1/clusters/AddClusterNodes.go @@ -13,22 +13,7 @@ type AddNodesOpts struct { // If the node type is ess-client, the number of nodes must be in the range 1 to 32. NodeSize int `json:"node_size" required:"true"` // Flavor - Flavor ID. - Flavor string `json:"-" required:"true"` - // Type of the volume. - // One of: - // - `COMMON`: Common I/O - // - `HIGH`: High I/O - // - `ULTRAHIGH`: Ultra-high I/O - VolumeType string `json:"volume_type" required:"true"` -} - -type apiAddNodesOpts struct { - // NodeSize - Number of nodes. The value range is 1 to 32. - // If the node type is ess-master, the number of nodes must be an odd number in the range 3 to 10. - // If the node type is ess-client, the number of nodes must be in the range 1 to 32. - NodeSize int `json:"node_size" required:"true"` - // ID of the new flavor. - FlavorRef string `json:"flavor_ref" required:"true"` + Flavor string `json:"flavor_ref" required:"true"` // Type of the volume. // One of: // - `COMMON`: Common I/O @@ -38,31 +23,14 @@ type apiAddNodesOpts struct { } func AddClusterNodes(client *golangsdk.ServiceClient, clusterID string, NodeType string, opts AddNodesOpts) (*AddNodesResponse, error) { - var ( - url string - flavorID string - err error - res AddNodesResponse - ) - - flavorID, err = getFlavorIDByName(client, opts.Flavor, NodeType) - if err != nil { - return &res, err - } - - apiOpts := apiAddNodesOpts{ - NodeSize: opts.NodeSize, - VolumeType: opts.VolumeType, - FlavorRef: flavorID, - } - b, err := build.RequestBody(apiOpts, "type") + b, err := build.RequestBody(opts, "type") if err != nil { return nil, err } // POST /v1.0/{project_id}/clusters/{cluster_id}/type/{type}/independent - url = client.ServiceURL("clusters", clusterID, "type", NodeType, "independent") + url := client.ServiceURL("clusters", clusterID, "type", NodeType, "independent") raw, err := client.Post(url, b, nil, &golangsdk.RequestOpts{ OkCodes: []int{200}, @@ -74,6 +42,7 @@ func AddClusterNodes(client *golangsdk.ServiceClient, clusterID string, NodeType return nil, err } + var res AddNodesResponse err = extract.IntoStructPtr(raw.Body, &res, "") return &res, err diff --git a/openstack/css/v1/clusters/UpdateClusterFlavor.go b/openstack/css/v1/clusters/UpdateClusterFlavor.go index e66ded4b7..e0cd853ca 100644 --- a/openstack/css/v1/clusters/UpdateClusterFlavor.go +++ b/openstack/css/v1/clusters/UpdateClusterFlavor.go @@ -5,94 +5,40 @@ import ( golangsdk "github.com/opentelekomcloud/gophertelekomcloud" "github.com/opentelekomcloud/gophertelekomcloud/internal/build" - "github.com/opentelekomcloud/gophertelekomcloud/openstack/css/v1/flavors" ) -const ( - DefaultNodeType = "ess" -) - -type ClusterFlavorOptsBuilder interface{} +type ClusterFlavorOptsBuilder interface { +} -// ClusterFlavorOpts for updating the flavor of a cluster. type ClusterFlavorOpts struct { - // Whether to verify replicas. + // Indicates whether to verify replicas. NeedCheckReplica bool `json:"needCheckReplica"` // ID of the new flavor. - Flavor string `json:"-" required:"true"` + NewFlavorID string `json:"newFlavorId" required:"true"` } -// ClusterNodeFlavorOpts for updating the flavor of a specific cluster node type. type ClusterNodeFlavorOpts struct { - // Whether to verify replicas. + // Indicates whether to verify replicas. NeedCheckReplica bool `json:"needCheckReplica"` // ID of the new flavor. - Flavor string `json:"-" required:"true"` + NewFlavorID string `json:"newFlavorId" required:"true"` // Type of the cluster node to modify. - Type string `json:"type" required:"true"` + NodeType string `json:"type" required:"true"` } -type apiFlavorOpts struct { - // Whether to verify replicas. - NeedCheckReplica bool `json:"needCheckReplica"` - // ID of the new flavor. - NewFlavorID string `json:"newFlavorId"` -} - -// getFlavorIDByName retrieves the flavor ID for a given flavor name and node type. -func getFlavorIDByName(client *golangsdk.ServiceClient, flavorName, nodeType string) (string, error) { - versions, err := flavors.List(client) - if err != nil { - return "", err - } - - // Search for the flavor by name and node type. - findFlavorByName := flavors.FindFlavor(versions, flavors.FilterOpts{ - FlavorName: flavorName, - Type: nodeType, - }) - - if findFlavorByName == nil { - return flavorName, nil - } - - return findFlavorByName.FlavorID, nil -} - -// UpdateClusterFlavor updates the flavor of a cluster or a specific cluster node type. -func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID, flavor string, opts ClusterFlavorOptsBuilder) error { - var ( - url string - flavorID string - needCheckReplica bool - err error - ) +func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID string, opts ClusterFlavorOptsBuilder) error { + url := "" switch options := opts.(type) { case ClusterFlavorOpts: - // Update cluster flavor. url = client.ServiceURL("clusters", clusterID, "flavor") - needCheckReplica = options.NeedCheckReplica - flavorID, err = getFlavorIDByName(client, flavor, DefaultNodeType) case ClusterNodeFlavorOpts: - // Update specific node type flavor. - url = client.ServiceURL("clusters", clusterID, options.Type, "flavor") - needCheckReplica = options.NeedCheckReplica - flavorID, err = getFlavorIDByName(client, flavor, options.Type) + url = client.ServiceURL("clusters", clusterID, options.NodeType, "flavor") default: return fmt.Errorf("invalid options type provided: %T", opts) } - if err != nil { - return err - } - - // Construct the API payload. - apiOpts := apiFlavorOpts{ - NeedCheckReplica: needCheckReplica, - NewFlavorID: flavorID, - } - b, err := build.RequestBody(apiOpts, "") + b, err := build.RequestBody(opts, "") if err != nil { return err } diff --git a/openstack/css/v1/clusters/UpdateSecurityMode.go b/openstack/css/v1/clusters/UpdateSecurityMode.go index bb4917cbb..3269560c8 100644 --- a/openstack/css/v1/clusters/UpdateSecurityMode.go +++ b/openstack/css/v1/clusters/UpdateSecurityMode.go @@ -7,11 +7,11 @@ import ( type SecurityModeOpts struct { // Indicates whether to enable the security mode. - AuthorityEnabled bool `json:"authorityEnable"` + AuthorityEnabled *bool `json:"authorityEnable"` // Cluster password. AdminPassword string `json:"adminPwd"` // Indicates whether to enable HTTPS. - HttpsEnabled bool `json:"httpsEnable"` + HttpsEnabled *bool `json:"httpsEnable"` } // UpdateSecurityMode - change the security mode of a cluster. diff --git a/openstack/css/v1/clusters/util.go b/openstack/css/v1/clusters/util.go index a7b7a40f9..10589aefe 100644 --- a/openstack/css/v1/clusters/util.go +++ b/openstack/css/v1/clusters/util.go @@ -62,7 +62,7 @@ func WaitForCluster(client *golangsdk.ServiceClient, id string, timeout int) err if _, ok := err.(golangsdk.BaseError); ok { return true, err } - log.Printf("Error waiting for CSS cluster to end active task: %s", err) + log.Printf("Error while waiting for cluster's status to change to active: %s", err) return false, nil } From 269c19c5a6b6dc81534e3df7e127bb0a3b7c288c Mon Sep 17 00:00:00 2001 From: anton-sidelnikov Date: Wed, 18 Dec 2024 16:49:10 +0100 Subject: [PATCH 10/11] added wait in TestRestartClusterWorkflow --- acceptance/openstack/css/v1/restart_cluster_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/acceptance/openstack/css/v1/restart_cluster_test.go b/acceptance/openstack/css/v1/restart_cluster_test.go index 2b25d0d88..034655240 100644 --- a/acceptance/openstack/css/v1/restart_cluster_test.go +++ b/acceptance/openstack/css/v1/restart_cluster_test.go @@ -19,4 +19,6 @@ func TestRestartClusterWorkflow(t *testing.T) { err = clusters.RestartCluster(client, clusterID) th.AssertNoErr(t, err) + + th.AssertNoErr(t, clusters.WaitForCluster(client, clusterID, 1200)) } From 1ba2fa31508568485478e3fc4608a8913a316fae Mon Sep 17 00:00:00 2001 From: Vineet Pruthi Date: Fri, 20 Dec 2024 09:33:47 +0100 Subject: [PATCH 11/11] Improvements based on suggestion from Muneeb --- .../css/v1/cluster_update_flavor_test.go | 13 ++++---- openstack/css/v1/clusters/AddClusterNodes.go | 3 +- .../css/v1/clusters/ChangeClusterName.go | 1 + openstack/css/v1/clusters/ChangePassword.go | 1 + openstack/css/v1/clusters/RestartCluster.go | 1 + .../css/v1/clusters/UpdateClusterFlavor.go | 32 ++++++------------- 6 files changed, 22 insertions(+), 29 deletions(-) diff --git a/acceptance/openstack/css/v1/cluster_update_flavor_test.go b/acceptance/openstack/css/v1/cluster_update_flavor_test.go index 9330583b2..320b4e787 100644 --- a/acceptance/openstack/css/v1/cluster_update_flavor_test.go +++ b/acceptance/openstack/css/v1/cluster_update_flavor_test.go @@ -34,7 +34,7 @@ func TestUpdateClusterFlavor(t *testing.T) { } filterOpts := flavors.FilterOpts{ - Version: cluster.Datastore.Version, + Version: "7.10.2", Type: instanceType, } @@ -47,9 +47,9 @@ func TestUpdateClusterFlavor(t *testing.T) { } else { newFlavorID = filteredVersions[0].Flavors[1].FlavorID } - + needCheckReplica := false err = clusters.UpdateClusterFlavor(client, clusterID, clusters.ClusterFlavorOpts{ - NeedCheckReplica: false, + NeedCheckReplica: &needCheckReplica, NewFlavorID: newFlavorID, }) th.AssertNoErr(t, err) @@ -87,7 +87,7 @@ func TestUpdateClusterNodeFlavor(t *testing.T) { } filterOpts := flavors.FilterOpts{ - Version: cluster.Datastore.Version, + Version: "7.10.2", Type: instanceType, } @@ -101,8 +101,9 @@ func TestUpdateClusterNodeFlavor(t *testing.T) { newFlavorID = filteredVersions[0].Flavors[1].FlavorID } - err = clusters.UpdateClusterFlavor(client, clusterID, clusters.ClusterNodeFlavorOpts{ - NeedCheckReplica: false, + needCheckReplica := false + err = clusters.UpdateClusterFlavor(client, clusterID, clusters.ClusterFlavorOpts{ + NeedCheckReplica: &needCheckReplica, NewFlavorID: newFlavorID, NodeType: instanceType, }) diff --git a/openstack/css/v1/clusters/AddClusterNodes.go b/openstack/css/v1/clusters/AddClusterNodes.go index 553c3dba6..e8b32126b 100644 --- a/openstack/css/v1/clusters/AddClusterNodes.go +++ b/openstack/css/v1/clusters/AddClusterNodes.go @@ -6,7 +6,7 @@ import ( "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" ) -// ScaleInOpts defines options for scaling in a cluster. +// AddNodesOpts defines options to add master or client nodes . type AddNodesOpts struct { // NodeSize - Number of nodes. The value range is 1 to 32. // If the node type is ess-master, the number of nodes must be an odd number in the range 3 to 10. @@ -22,6 +22,7 @@ type AddNodesOpts struct { VolumeType string `json:"volume_type" required:"true"` } +// AddClusterNodes function lets you add master and client nodes to a cluster. func AddClusterNodes(client *golangsdk.ServiceClient, clusterID string, NodeType string, opts AddNodesOpts) (*AddNodesResponse, error) { b, err := build.RequestBody(opts, "type") diff --git a/openstack/css/v1/clusters/ChangeClusterName.go b/openstack/css/v1/clusters/ChangeClusterName.go index 9bb4bdd18..a81a25a05 100644 --- a/openstack/css/v1/clusters/ChangeClusterName.go +++ b/openstack/css/v1/clusters/ChangeClusterName.go @@ -11,6 +11,7 @@ type ChangeClusterNameOpts struct { DisplayName string `json:"displayName" required:"true"` } +// ChangeClusterName function is used to change the name of a cluster. func ChangeClusterName(client *golangsdk.ServiceClient, clusterID string, opts ChangeClusterNameOpts) error { // ChangeClusterName will change cluster name based on ChangeClusterNameOpts b, err := build.RequestBody(opts, "") diff --git a/openstack/css/v1/clusters/ChangePassword.go b/openstack/css/v1/clusters/ChangePassword.go index ec2aafa2f..885aa044d 100644 --- a/openstack/css/v1/clusters/ChangePassword.go +++ b/openstack/css/v1/clusters/ChangePassword.go @@ -11,6 +11,7 @@ type ChangePasswordOpts struct { NewPassword string `json:"newpassword" required:"true"` } +// ChangePassword function is used to change the password of a cluster. func ChangePassword(client *golangsdk.ServiceClient, clusterID string, opts ChangePasswordOpts) (err error) { // ChangeClusterName will change cluster name based on ChangeClusterNameOpts b, err := build.RequestBody(opts, "") diff --git a/openstack/css/v1/clusters/RestartCluster.go b/openstack/css/v1/clusters/RestartCluster.go index aef9c22b5..2e671ffa4 100644 --- a/openstack/css/v1/clusters/RestartCluster.go +++ b/openstack/css/v1/clusters/RestartCluster.go @@ -2,6 +2,7 @@ package clusters import golangsdk "github.com/opentelekomcloud/gophertelekomcloud" +// RestartCluster function is used to restart a cluster. func RestartCluster(client *golangsdk.ServiceClient, clusterID string) error { _, err := client.Post(client.ServiceURL("clusters", clusterID, "restart"), nil, nil, &golangsdk.RequestOpts{ OkCodes: []int{200}, diff --git a/openstack/css/v1/clusters/UpdateClusterFlavor.go b/openstack/css/v1/clusters/UpdateClusterFlavor.go index e0cd853ca..325b75f4d 100644 --- a/openstack/css/v1/clusters/UpdateClusterFlavor.go +++ b/openstack/css/v1/clusters/UpdateClusterFlavor.go @@ -1,41 +1,29 @@ package clusters import ( - "fmt" - golangsdk "github.com/opentelekomcloud/gophertelekomcloud" "github.com/opentelekomcloud/gophertelekomcloud/internal/build" ) -type ClusterFlavorOptsBuilder interface { -} - type ClusterFlavorOpts struct { // Indicates whether to verify replicas. - NeedCheckReplica bool `json:"needCheckReplica"` - // ID of the new flavor. - NewFlavorID string `json:"newFlavorId" required:"true"` -} - -type ClusterNodeFlavorOpts struct { - // Indicates whether to verify replicas. - NeedCheckReplica bool `json:"needCheckReplica"` + NeedCheckReplica *bool `json:"needCheckReplica,omitempty"` // ID of the new flavor. NewFlavorID string `json:"newFlavorId" required:"true"` // Type of the cluster node to modify. - NodeType string `json:"type" required:"true"` + NodeType string `json:"-"` } -func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID string, opts ClusterFlavorOptsBuilder) error { - url := "" +// UpdateClusterFlavor is used to modify the specifications of a cluster or specifications of a specified node type. +func UpdateClusterFlavor(client *golangsdk.ServiceClient, clusterID string, opts ClusterFlavorOpts) error { + // Construct the URL dynamically based on the optional NodeType. + + var url string - switch options := opts.(type) { - case ClusterFlavorOpts: + if opts.NodeType != "" { + url = client.ServiceURL("clusters", clusterID, opts.NodeType, "flavor") + } else { url = client.ServiceURL("clusters", clusterID, "flavor") - case ClusterNodeFlavorOpts: - url = client.ServiceURL("clusters", clusterID, options.NodeType, "flavor") - default: - return fmt.Errorf("invalid options type provided: %T", opts) } b, err := build.RequestBody(opts, "")