From f4669448c474c67bda0dddfe7ba1ad4065f17c7f Mon Sep 17 00:00:00 2001 From: Artem Lifshits <55093318+artem-lifshits@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:57:05 +0100 Subject: [PATCH 1/4] fix (#774) --- openstack/dcs/v2/whitelists/Put.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/dcs/v2/whitelists/Put.go b/openstack/dcs/v2/whitelists/Put.go index f76efd5c3..d6e1ac31a 100644 --- a/openstack/dcs/v2/whitelists/Put.go +++ b/openstack/dcs/v2/whitelists/Put.go @@ -32,7 +32,7 @@ func Put(client *golangsdk.ServiceClient, id string, opts WhitelistOpts) (err er url := client.ServiceURL("instance", id, "whitelist") _, err = client.Put(strings.Replace(url, "v1.0", "v2", 1), b, nil, &golangsdk.RequestOpts{ - OkCodes: []int{204}, + OkCodes: []int{204, 200}, }) return } From a596977d5b13bf66b515c7fedbc3246c8dfaafdf Mon Sep 17 00:00:00 2001 From: Anton Sidelnikov <53078276+anton-sidelnikov@users.noreply.github.com> Date: Mon, 16 Dec 2024 20:43:12 +0100 Subject: [PATCH 2/4] [Feat.] Remove codeowners (#776) --- CODEOWNERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 9e43318fc..e69de29bb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +0,0 @@ -* @anton-sidelnikov -* @artem-lifshits From c35f3bd67003aaf8d8576917a938cc94b7986f82 Mon Sep 17 00:00:00 2001 From: "Muneeb H. Jan" Date: Tue, 17 Dec 2024 14:07:28 +0100 Subject: [PATCH 3/4] [Refactor] CCE: Refactor CCE addons (#775) --- acceptance/openstack/cce/v3/addons_test.go | 172 ++++++------- openstack/cce/v3/addons/Create.go | 58 +++++ openstack/cce/v3/addons/Delete.go | 24 ++ openstack/cce/v3/addons/Get.go | 25 ++ openstack/cce/v3/addons/GetTemplates.go | 18 ++ openstack/cce/v3/addons/ListAddonInstances.go | 35 +++ openstack/cce/v3/addons/ListTemplates.go | 27 ++ openstack/cce/v3/addons/Update.go | 50 ++++ openstack/cce/v3/addons/WaitCompleteion.go | 35 +++ openstack/cce/v3/addons/common.go | 150 +++++++++++ openstack/cce/v3/addons/requests.go | 209 --------------- openstack/cce/v3/addons/results.go | 238 ------------------ openstack/cce/v3/addons/urls.go | 39 --- 13 files changed, 497 insertions(+), 583 deletions(-) create mode 100644 openstack/cce/v3/addons/Create.go create mode 100644 openstack/cce/v3/addons/Delete.go create mode 100644 openstack/cce/v3/addons/Get.go create mode 100644 openstack/cce/v3/addons/GetTemplates.go create mode 100644 openstack/cce/v3/addons/ListAddonInstances.go create mode 100644 openstack/cce/v3/addons/ListTemplates.go create mode 100644 openstack/cce/v3/addons/Update.go create mode 100644 openstack/cce/v3/addons/WaitCompleteion.go create mode 100644 openstack/cce/v3/addons/common.go delete mode 100644 openstack/cce/v3/addons/requests.go delete mode 100644 openstack/cce/v3/addons/results.go delete mode 100644 openstack/cce/v3/addons/urls.go diff --git a/acceptance/openstack/cce/v3/addons_test.go b/acceptance/openstack/cce/v3/addons_test.go index 58de32236..36fcd8d1d 100644 --- a/acceptance/openstack/cce/v3/addons_test.go +++ b/acceptance/openstack/cce/v3/addons_test.go @@ -1,62 +1,25 @@ package v3 import ( - "encoding/json" "testing" - "github.com/stretchr/testify/suite" - "github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients" "github.com/opentelekomcloud/gophertelekomcloud/openstack/cce/v3/addons" th "github.com/opentelekomcloud/gophertelekomcloud/testhelper" ) -type testAddons struct { - suite.Suite - - vpcID string - subnetID string - clusterID string -} - -func TestAddons(t *testing.T) { - suite.Run(t, new(testAddons)) -} +func TestAddonsLifecycle(t *testing.T) { -func (a *testAddons) SetupSuite() { - t := a.T() - a.vpcID = clients.EnvOS.GetEnv("VPC_ID") - a.subnetID = clients.EnvOS.GetEnv("NETWORK_ID") - a.clusterID = clients.EnvOS.GetEnv("CLUSTER_ID") - if a.vpcID == "" || a.subnetID == "" { + clusterID := clients.EnvOS.GetEnv("CLUSTER_ID") + tenantID := clients.EnvOS.GetEnv("TENANT_ID") + if clusterID == "" || tenantID == "" { t.Skip("OS_VPC_ID, OS_NETWORK_ID, and OS_CLUSTER_ID are required for this test") } -} - -func (a *testAddons) TestAddonsLifecycle() { - t := a.T() client, err := clients.NewCceV3AddonClient() th.AssertNoErr(t, err) - custom := map[string]interface{}{ - "coresTotal": 32000, - "maxEmptyBulkDeleteFlag": 10, - "maxNodesTotal": 1000, - "memoryTotal": 128000, - "scaleDownDelayAfterAdd": 10, - "scaleDownDelayAfterDelete": 10, - "scaleDownDelayAfterFailure": 3, - "scaleDownEnabled": true, - "scaleDownUnneededTime": 10, - "scaleDownUtilizationThreshold": 0.25, - "scaleUpCpuUtilizationThreshold": 0.8, - "scaleUpMemUtilizationThreshold": 0.8, - "scaleUpUnscheduledPodEnabled": true, - "scaleUpUtilizationEnabled": true, - "unremovableNodeRecheckTimeout": 5, - } - cOpts := addons.CreateOpts{ + createOpts := addons.CreateOpts{ Kind: "Addon", ApiVersion: "v3", Metadata: addons.CreateMetadata{ @@ -65,45 +28,72 @@ func (a *testAddons) TestAddonsLifecycle() { }, }, Spec: addons.RequestSpec{ - Version: "1.17.2", - ClusterID: a.clusterID, - AddonTemplateName: "autoscaler", + Version: "1.19.1", + ClusterID: clusterID, + AddonTemplateName: "npd", Values: addons.Values{ Basic: map[string]interface{}{ - "cceEndpoint": "https://cce.eu-de.otc.t-systems.com", - "ecsEndpoint": "https://ecs.eu-de.otc.t-systems.com", - "euleros_version": "2.5", - "region": "eu-de", - "swr_addr": "100.125.7.25:20202", - "swr_user": "hwofficial", + "image_version": "1.19.1", + "swr_addr": "100.125.7.25:20202", + "swr_user": "cce-addons", + }, + Advanced: map[string]interface{}{ + "multiAZBalance": false, + "multiAZEnabled": false, + "feature_gates": "", + "node_match_expressions": []interface{}{}, + "npc": map[string]interface{}{ + "maxTaintedNode": "10%", + }, + "tolerations": []map[string]interface{}{ + { + "effect": "NoExecute", + "key": "node.kubernetes.io/not-ready", + "operator": "Exists", + "tolerationSeconds": 60, + }, + { + "effect": "NoExecute", + "key": "node.kubernetes.io/unreachable", + "operator": "Exists", + "tolerationSeconds": 60, + }, + }, }, - Advanced: custom, }, }, } - addon, err := addons.Create(client, cOpts, a.clusterID).Extract() + listExistingAddons, err := addons.ListAddonInstances(client, clusterID) + th.AssertNoErr(t, err) + + existingAddons := len(listExistingAddons.Items) + + addon, err := addons.Create(client, createOpts, clusterID) th.AssertNoErr(t, err) addonID := addon.Metadata.Id defer func() { - err := addons.Delete(client, addonID, a.clusterID).ExtractErr() + err := addons.Delete(client, addonID, clusterID) th.AssertNoErr(t, err) - th.AssertNoErr(t, addons.WaitForAddonDeleted(client, addonID, a.clusterID, 600)) + th.AssertNoErr(t, addons.WaitForAddonDeleted(client, addonID, clusterID, 1200)) }() - getAddon, err := addons.Get(client, addonID, a.clusterID).Extract() + listAddons, err := addons.ListAddonInstances(client, clusterID) th.AssertNoErr(t, err) - th.AssertEquals(t, "autoscaler", getAddon.Spec.AddonTemplateName) - th.AssertEquals(t, "1.17.2", getAddon.Spec.Version) - th.AssertEquals(t, true, getAddon.Spec.Values.Advanced["scaleDownEnabled"]) + th.AssertEquals(t, existingAddons+1, len(listAddons.Items)) - waitErr := addons.WaitForAddonRunning(client, addonID, a.clusterID, 600) + getAddon, err := addons.Get(client, addonID, clusterID) + th.AssertNoErr(t, err) + th.AssertEquals(t, "npd", getAddon.Spec.AddonTemplateName) + th.AssertEquals(t, "1.19.1", getAddon.Spec.Version) + + waitErr := addons.WaitForAddonRunning(client, addonID, clusterID, 1200) th.AssertNoErr(t, waitErr) - uOpts := addons.UpdateOpts{ + updateOpts := addons.UpdateOpts{ Kind: "Addon", ApiVersion: "v3", Metadata: addons.UpdateMetadata{ @@ -112,67 +102,55 @@ func (a *testAddons) TestAddonsLifecycle() { }, }, Spec: addons.RequestSpec{ - Version: cOpts.Spec.Version, - ClusterID: cOpts.Spec.ClusterID, - AddonTemplateName: cOpts.Spec.AddonTemplateName, + Version: createOpts.Spec.Version, + ClusterID: createOpts.Spec.ClusterID, + AddonTemplateName: createOpts.Spec.AddonTemplateName, Values: addons.Values{ - Basic: cOpts.Spec.Values.Basic, - Advanced: cOpts.Spec.Values.Advanced, + Basic: createOpts.Spec.Values.Basic, + Advanced: createOpts.Spec.Values.Advanced, }, }, } - uOpts.Spec.Values.Advanced["scaleDownEnabled"] = false - uOpts.Spec.Values.Advanced["scaleDownDelayAfterAdd"] = 11 - _, err = addons.Update(client, addonID, a.clusterID, uOpts).Extract() - th.AssertNoErr(t, err) + updateOpts.Spec.Values.Basic["rbac_enabled"] = true - getAddon2, err := addons.Get(client, addonID, a.clusterID).Extract() + getAddon2, err := addons.Update(client, addonID, clusterID, updateOpts) th.AssertNoErr(t, err) - th.AssertEquals(t, false, getAddon2.Spec.Values.Advanced["scaleDownEnabled"]) - th.AssertEquals(t, 11.0, getAddon2.Spec.Values.Advanced["scaleDownDelayAfterAdd"]) + + // USE THIS TO DEBUG + // addonJson, _ := json.MarshalIndent(getAddon2, "", " ") + // t.Logf("existing addon templates:\n%s", string(addonJson)) + th.AssertEquals(t, true, getAddon2.Spec.Values.Basic["rbac_enabled"]) + waitErr = addons.WaitForAddonRunning(client, addonID, clusterID, 1200) + th.AssertNoErr(t, waitErr) } -func (a *testAddons) TestListAddonTemplates() { - t := a.T() +func TestAddonsListTemplates(t *testing.T) { + clusterID := clients.EnvOS.GetEnv("CLUSTER_ID") + if clusterID == "" { + t.Skip("OS_VPC_ID, OS_NETWORK_ID, and OS_CLUSTER_ID are required for this test") + } client, err := clients.NewCceV3AddonClient() th.AssertNoErr(t, err) - list, err := addons.ListTemplates(client, a.clusterID, nil).Extract() + list, err := addons.ListTemplates(client, clusterID, addons.ListOpts{}) th.AssertNoErr(t, err) if len(list.Items) == 0 { t.Fatal("empty addon template list") } - jsonList, _ := json.MarshalIndent(list.Items, "", " ") - - t.Logf("existing addon templates:\n%s", string(jsonList)) -} - -func (a *testAddons) TestListAddonInstances() { - t := a.T() - - client, err := clients.NewCceV3AddonClient() - th.AssertNoErr(t, err) - - list, err := addons.ListAddonInstances(client, a.clusterID).Extract() - th.AssertNoErr(t, err) - - th.AssertEquals(t, len(list.Items), 3) - // check if listed addon exists - _, err = addons.Get(client, list.Items[0].Metadata.ID, a.clusterID).Extract() - th.AssertNoErr(t, err) + // jsonList, _ := json.MarshalIndent(list.Items, "", " ") + // t.Logf("existing addon templates:\n%s", string(jsonList)) } -func (a *testAddons) TestGetAddonTemplates() { - t := a.T() +func TestAddonsGetTemplates(t *testing.T) { client, err := clients.NewCceV3AddonClient() th.AssertNoErr(t, err) - templates, err := addons.GetTemplates(client).Extract() + templates, err := addons.GetTemplates(client) th.AssertNoErr(t, err) if len(templates.Items) == 0 { t.Fatal("empty addon templates list") diff --git a/openstack/cce/v3/addons/Create.go b/openstack/cce/v3/addons/Create.go new file mode 100644 index 000000000..8122dcfe1 --- /dev/null +++ b/openstack/cce/v3/addons/Create.go @@ -0,0 +1,58 @@ +package addons + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +// CreateOpts contains all the values needed to create a new addon +type CreateOpts struct { + // API type, fixed value Addon + Kind string `json:"kind" required:"true"` + // API version, fixed value v3 + ApiVersion string `json:"apiVersion" required:"true"` + // Metadata required to create an addon + Metadata CreateMetadata `json:"metadata" required:"true"` + // specifications to create an addon + Spec RequestSpec `json:"spec" required:"true"` +} + +type CreateMetadata struct { + Annotations CreateAnnotations `json:"annotations" required:"true"` +} + +type CreateAnnotations struct { + AddonInstallType string `json:"addon.install/type" required:"true"` +} + +// Specifications to create an addon +type RequestSpec struct { + // For the addon version. + Version string `json:"version" required:"true"` + // Cluster ID. + ClusterID string `json:"clusterID" required:"true"` + // Addon Template Name. + AddonTemplateName string `json:"addonTemplateName" required:"true"` + // Addon Parameters + Values Values `json:"values" required:"true"` +} + +// Create accepts a CreateOpts struct and uses the values to create a new +// addon. +func Create(client *golangsdk.ServiceClient, opts CreateOpts, clusterId string) (*Addon, error) { + b, err := build.RequestBody(opts, "") + if err != nil { + return nil, err + } + // POST /api/v3/addons + raw, err := client.Post(CCEServiceURL(client, clusterId, "addons"), b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{201}, + }) + if err != nil { + return nil, err + } + + var res Addon + return &res, extract.Into(raw.Body, &res) +} diff --git a/openstack/cce/v3/addons/Delete.go b/openstack/cce/v3/addons/Delete.go new file mode 100644 index 000000000..74a9a59ad --- /dev/null +++ b/openstack/cce/v3/addons/Delete.go @@ -0,0 +1,24 @@ +package addons + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" +) + +// Delete will permanently delete a particular addon based on its unique ID. +func Delete(client *golangsdk.ServiceClient, addonId, clusterId string) error { + // DELETE /api/v3/addons/{id}?cluster_id={cluster_id} + url, err := golangsdk.NewURLBuilder().WithEndpoints("addons", addonId).WithQueryParams(&ClusterIdQueryParam{ClusterId: clusterId}).Build() + if err != nil { + return err + } + + _, err = client.Delete(CCEServiceURL(client, clusterId, url.String()), &golangsdk.RequestOpts{ + OkCodes: []int{200}, + MoreHeaders: map[string]string{"Content-Type": "application/json"}, + JSONBody: nil, + }) + if err != nil { + return err + } + return nil +} diff --git a/openstack/cce/v3/addons/Get.go b/openstack/cce/v3/addons/Get.go new file mode 100644 index 000000000..434ef1a98 --- /dev/null +++ b/openstack/cce/v3/addons/Get.go @@ -0,0 +1,25 @@ +package addons + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +// Get retrieves a particular addon based on its unique ID. +func Get(client *golangsdk.ServiceClient, addonId string, clusterId string) (*Addon, error) { + // GET /api/v3/addons/{id}?cluster_id={cluster_id} + url, err := golangsdk.NewURLBuilder().WithEndpoints("addons", addonId).WithQueryParams(&ClusterIdQueryParam{ClusterId: clusterId}).Build() + if err != nil { + return nil, err + } + + raw, err := client.Get(CCEServiceURL(client, clusterId, url.String()), nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + if err != nil { + return nil, err + } + + var res Addon + return &res, extract.Into(raw.Body, &res) +} diff --git a/openstack/cce/v3/addons/GetTemplates.go b/openstack/cce/v3/addons/GetTemplates.go new file mode 100644 index 000000000..ada1747aa --- /dev/null +++ b/openstack/cce/v3/addons/GetTemplates.go @@ -0,0 +1,18 @@ +package addons + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +func GetTemplates(client *golangsdk.ServiceClient) (*AddonTemplateList, error) { + raw, err := client.Get(client.ServiceURL("addontemplates"), nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + if err != nil { + return nil, err + } + + var res AddonTemplateList + return &res, extract.Into(raw.Body, &res) +} diff --git a/openstack/cce/v3/addons/ListAddonInstances.go b/openstack/cce/v3/addons/ListAddonInstances.go new file mode 100644 index 000000000..e8444c8a4 --- /dev/null +++ b/openstack/cce/v3/addons/ListAddonInstances.go @@ -0,0 +1,35 @@ +package addons + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +func ListAddonInstances(client *golangsdk.ServiceClient, clusterId string) (*AddonInstanceList, error) { + // GET /api/v3/addons?cluster_id={cluster_id} + url, err := golangsdk.NewURLBuilder().WithEndpoints("addons").WithQueryParams(&ClusterIdQueryParam{ClusterId: clusterId}).Build() + if err != nil { + return nil, err + } + + raw, err := client.Get(CCEServiceURL(client, clusterId, url.String()), nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + if err != nil { + return nil, err + } + + var res AddonInstanceList + return &res, extract.Into(raw.Body, &res) +} + +type AddonInstanceList struct { + // API type, fixed value Addon + Kind string `json:"kind" required:"true"` + // API version, fixed value v3 + ApiVersion string `json:"apiVersion" required:"true"` + // Metadata - Basic information about the add-on. A collection of attributes. + Metadata string `json:"metadata"` + // Add-on template list + Items []Addon `json:"items" required:"true"` +} diff --git a/openstack/cce/v3/addons/ListTemplates.go b/openstack/cce/v3/addons/ListTemplates.go new file mode 100644 index 000000000..5183cbd70 --- /dev/null +++ b/openstack/cce/v3/addons/ListTemplates.go @@ -0,0 +1,27 @@ +package addons + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +type ListOpts struct { + Name string `q:"addon_template_name"` +} + +func ListTemplates(client *golangsdk.ServiceClient, clusterID string, opts ListOpts) (*AddonTemplateList, error) { + url, err := golangsdk.NewURLBuilder().WithEndpoints("addontemplates").WithQueryParams(&opts).Build() + if err != nil { + return nil, err + } + + raw, err := client.Get(CCEServiceURL(client, clusterID, url.String()), err, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + if err != nil { + return nil, err + } + + var res AddonTemplateList + return &res, extract.Into(raw.Body, &res) +} diff --git a/openstack/cce/v3/addons/Update.go b/openstack/cce/v3/addons/Update.go new file mode 100644 index 000000000..1143baa88 --- /dev/null +++ b/openstack/cce/v3/addons/Update.go @@ -0,0 +1,50 @@ +package addons + +import ( + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" + "github.com/opentelekomcloud/gophertelekomcloud/internal/build" + "github.com/opentelekomcloud/gophertelekomcloud/internal/extract" +) + +type UpdateMetadata struct { + // Add-on annotations in the format of key-value pairs. + // For add-on upgrade, the value is fixed at {"addon.upgrade/type":"upgrade"}. + Annotations UpdateAnnotations `json:"annotations" required:"true"` + // Add-on labels in the format of key-value pairs. + Labels map[string]string `json:"metadata,omitempty"` +} + +type UpdateAnnotations struct { + AddonUpdateType string `json:"addon.upgrade/type" required:"true"` +} + +type UpdateOpts struct { + // API type, fixed value Addon + Kind string `json:"kind" required:"true"` + // API version, fixed value v3 + ApiVersion string `json:"apiVersion" required:"true"` + // Metadata required to create an addon + Metadata UpdateMetadata `json:"metadata" required:"true"` + // specifications to create an addon + Spec RequestSpec `json:"spec" required:"true"` +} + +func Update(client *golangsdk.ServiceClient, addonId string, clusterId string, opts UpdateOpts) (*Addon, error) { + url, err := golangsdk.NewURLBuilder().WithEndpoints("addons", addonId).WithQueryParams(&ClusterIdQueryParam{ClusterId: clusterId}).Build() + if err != nil { + return nil, err + } + b, err := build.RequestBody(opts, "") + if err != nil { + return nil, err + } + raw, err := client.Put(CCEServiceURL(client, clusterId, url.String()), b, nil, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + if err != nil { + return nil, err + } + + var res Addon + return &res, extract.Into(raw.Body, &res) +} diff --git a/openstack/cce/v3/addons/WaitCompleteion.go b/openstack/cce/v3/addons/WaitCompleteion.go new file mode 100644 index 000000000..850abeb68 --- /dev/null +++ b/openstack/cce/v3/addons/WaitCompleteion.go @@ -0,0 +1,35 @@ +package addons + +import ( + "fmt" + + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" +) + +// WaitForAddonRunning - wait until addon status is `running` +func WaitForAddonRunning(client *golangsdk.ServiceClient, id, clusterID string, timeoutSeconds int) error { + return golangsdk.WaitFor(timeoutSeconds, func() (bool, error) { + addon, err := Get(client, id, clusterID) + if err != nil { + return false, fmt.Errorf("error retriving addon status: %w", err) + } + if addon.Status.Status == "running" { + return true, nil + } + return false, nil + }) +} + +// WaitForAddonDeleted - wait until addon is deleted +func WaitForAddonDeleted(client *golangsdk.ServiceClient, id, clusterID string, timeoutSeconds int) error { + return golangsdk.WaitFor(timeoutSeconds, func() (bool, error) { + _, err := Get(client, id, clusterID) + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + return true, nil + } + return false, fmt.Errorf("error retriving addon status: %w", err) + } + return false, nil + }) +} diff --git a/openstack/cce/v3/addons/common.go b/openstack/cce/v3/addons/common.go new file mode 100644 index 000000000..cf5f70ac1 --- /dev/null +++ b/openstack/cce/v3/addons/common.go @@ -0,0 +1,150 @@ +package addons + +import ( + "fmt" + "strings" + + golangsdk "github.com/opentelekomcloud/gophertelekomcloud" +) + +type Addon struct { + // API type, fixed value Addon + Kind string `json:"kind" required:"true"` + // API version, fixed value v3 + ApiVersion string `json:"apiVersion" required:"true"` + // Metadata of an Addon + Metadata MetaData `json:"metadata" required:"true"` + // Specifications of an Addon + Spec Spec `json:"spec" required:"true"` + // Status of an Addon + Status Status `json:"status"` +} + +// Metadata required to create an addon +type MetaData struct { + // Addon unique name + Name string `json:"name"` + // Addon unique Id + Id string `json:"uid"` + // Addon tag, key/value pair format + Labels map[string]string `json:"labels"` + // Addon annotation, key/value pair format + Annotations map[string]string `json:"annotaions"` + // Time when the add-on instance was updated. + UpdateTimestamp string `json:"updateTimestamp"` + // Time when the add-on instance was created. + CreationTimestamp string `json:"creationTimestamp"` +} + +// Specifications to create an addon +type Spec struct { + // For the addon version. + Version string `json:"version" required:"true"` + // Cluster ID. + ClusterID string `json:"clusterID" required:"true"` + // Addon Template Name. + AddonTemplateName string `json:"addonTemplateName" required:"true"` + // Addon Template Type. + AddonTemplateType string `json:"addonTemplateType" required:"true"` + // Addon Template Labels. + AddonTemplateLabels []string `json:"addonTemplateLabels,omitempty"` + // Addon Description. + Description string `json:"description" required:"true"` + // Addon Parameters + Values Values `json:"values" required:"true"` +} + +type Status struct { + // The state of the addon + Status string `json:"status"` + // Reasons for the addon to become current + Reason string `json:"reason"` + // Error Message + Message string `json:"message"` + // The target versions of the addon + TargetVersions []string `json:"targetVersions"` + // Current add-on version. + CurrentVersion Version `json:"currentVersion"` +} + +type Values struct { + Basic map[string]interface{} `json:"basic" required:"true"` + Advanced map[string]interface{} `json:"custom,omitempty"` + Flavor map[string]interface{} `json:"flavor,omitempty"` +} + +type Version struct { + // Add-on version + Version string `json:"version"` + // Add-on installation parameters + Input Input `json:"input"` + // Whether the add-on version is a stable release + Stable bool `json:"stable"` + // Translation information used by the GUI. + Translate map[string]interface{} `json:"translate"` + // Cluster versions that support the add-on template + SupportVersions []SupportVersion `json:"supportVersions"` + // Creation time of the add-on instance + CreationTimestamp string `json:"creationTimestamp"` + // Time when the add-on instance was updated + UpdateTimestamp string `json:"updateTimestamp"` +} + +type Input struct { + Basic map[string]interface{} `json:"basic"` + Parameters map[string]interface{} `json:"parameters"` +} + +type SupportVersion struct { + // Cluster type that supports the add-on template + ClusterType string `json:"clusterType"` + // Cluster versions that support the add-on template, + // the parameter value is a regular expression + ClusterVersion []string `json:"clusterVersion"` +} + +type ClusterIdQueryParam struct { + ClusterId string `q:"cluster_id"` +} + +type AddonTemplateList struct { + // API type, fixed value Addon + Kind string `json:"kind" required:"true"` + // API version, fixed value v3 + ApiVersion string `json:"apiVersion" required:"true"` + // Add-on template list + Items []AddonTemplate `json:"items" required:"true"` +} + +type AddonTemplate struct { + // API type, fixed value Addon + Kind string `json:"kind" required:"true"` + // API version, fixed value v3 + ApiVersion string `json:"apiVersion" required:"true"` + // Metadata of an Addon + Metadata MetaData `json:"metadata" required:"true"` + // Specifications of an Addon + Spec AddonTemplateSpec `json:"spec" required:"true"` +} + +type AddonTemplateSpec struct { + // Template type (helm or static). + Type string `json:"type" required:"true"` + // Whether the add-on is installed by default + Require bool `json:"require" required:"true"` + // Group to which the template belongs + Labels []string `json:"labels" required:"true"` + // URL of the logo image + LogoURL string `json:"logoURL" required:"true"` + // URL of the readme file + ReadmeURL string `json:"readmeURL" required:"true"` + // Template description + Description string `json:"description" required:"true"` + // Template version details + Versions []Version `json:"versions" required:"true"` +} + +func CCEServiceURL(client *golangsdk.ServiceClient, clusterID string, parts ...string) string { + rbUrl := fmt.Sprintf("https://%s.%s", clusterID, client.ResourceBaseURL()[8:]) + return rbUrl + strings.Join(parts, "/") +} diff --git a/openstack/cce/v3/addons/requests.go b/openstack/cce/v3/addons/requests.go deleted file mode 100644 index 13416a75a..000000000 --- a/openstack/cce/v3/addons/requests.go +++ /dev/null @@ -1,209 +0,0 @@ -package addons - -import ( - "fmt" - - "github.com/opentelekomcloud/gophertelekomcloud" -) - -var RequestOpts = golangsdk.RequestOpts{ - MoreHeaders: map[string]string{"Content-Type": "application/json"}, -} - -// CreateOptsBuilder allows extensions to add additional parameters to the -// Create request. -type CreateOptsBuilder interface { - ToAddonCreateMap() (map[string]interface{}, error) -} - -// CreateOpts contains all the values needed to create a new addon -type CreateOpts struct { - // API type, fixed value Addon - Kind string `json:"kind" required:"true"` - // API version, fixed value v3 - ApiVersion string `json:"apiVersion" required:"true"` - // Metadata required to create an addon - Metadata CreateMetadata `json:"metadata" required:"true"` - // specifications to create an addon - Spec RequestSpec `json:"spec" required:"true"` -} - -type CreateMetadata struct { - Annotations CreateAnnotations `json:"annotations" required:"true"` -} - -type CreateAnnotations struct { - AddonInstallType string `json:"addon.install/type" required:"true"` -} - -// Specifications to create an addon -type RequestSpec struct { - // For the addon version. - Version string `json:"version" required:"true"` - // Cluster ID. - ClusterID string `json:"clusterID" required:"true"` - // Addon Template Name. - AddonTemplateName string `json:"addonTemplateName" required:"true"` - // Addon Parameters - Values Values `json:"values" required:"true"` -} - -type Values struct { - Basic map[string]interface{} `json:"basic" required:"true"` - Advanced map[string]interface{} `json:"custom,omitempty"` - Flavor map[string]interface{} `json:"flavor,omitempty"` -} - -// ToAddonCreateMap builds a create request body from CreateOpts. -func (opts CreateOpts) ToAddonCreateMap() (map[string]interface{}, error) { - return golangsdk.BuildRequestBody(opts, "") -} - -// Create accepts a CreateOpts struct and uses the values to create a new -// addon. -func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder, clusterId string) (r CreateResult) { - b, err := opts.ToAddonCreateMap() - if err != nil { - r.Err = err - return - } - reqOpt := &golangsdk.RequestOpts{OkCodes: []int{201}} - _, r.Err = c.Post(rootURL(c, clusterId), b, &r.Body, reqOpt) - return -} - -// Get retrieves a particular addon based on its unique ID. -func Get(c *golangsdk.ServiceClient, id, clusterId string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id, clusterId), &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// UpdateOptsBuilder allows extensions to add additional parameters to the -// Update request. -type UpdateOptsBuilder interface { - ToAddonUpdateMap() (map[string]interface{}, error) -} - -type UpdateMetadata struct { - // Add-on annotations in the format of key-value pairs. - // For add-on upgrade, the value is fixed at {"addon.upgrade/type":"upgrade"}. - Annotations UpdateAnnotations `json:"annotations" required:"true"` - // Add-on labels in the format of key-value pairs. - Labels map[string]string `json:"metadata,omitempty"` -} - -type UpdateAnnotations struct { - AddonUpdateType string `json:"addon.upgrade/type" required:"true"` -} - -type UpdateOpts struct { - // API type, fixed value Addon - Kind string `json:"kind" required:"true"` - // API version, fixed value v3 - ApiVersion string `json:"apiVersion" required:"true"` - // Metadata required to create an addon - Metadata UpdateMetadata `json:"metadata" required:"true"` - // specifications to create an addon - Spec RequestSpec `json:"spec" required:"true"` -} - -func (opts UpdateOpts) ToAddonUpdateMap() (map[string]interface{}, error) { - return golangsdk.BuildRequestBody(opts, "") -} - -func Update(c *golangsdk.ServiceClient, id, clusterId string, opts UpdateOpts) (r UpdateResult) { - b, err := opts.ToAddonUpdateMap() - if err != nil { - r.Err = err - return - } - _, r.Err = c.Put(resourceURL(c, id, clusterId), b, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// Delete will permanently delete a particular addon based on its unique ID. -func Delete(c *golangsdk.ServiceClient, id, clusterId string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id, clusterId), &golangsdk.RequestOpts{ - OkCodes: []int{200}, - MoreHeaders: RequestOpts.MoreHeaders, JSONBody: nil, - }) - return -} - -type ListOptsBuilder interface { - ToAddonListQuery() (string, error) -} - -type ListOpts struct { - Name string `q:"addon_template_name"` -} - -func (opts ListOpts) ToAddonListQuery() (string, error) { - u, err := golangsdk.BuildQueryString(opts) - if err != nil { - return "", err - } - return u.String(), nil -} - -func ListTemplates(c *golangsdk.ServiceClient, clusterID string, opts ListOptsBuilder) (r ListTemplateResult) { - url := templatesURL(c, clusterID) - if opts != nil { - q, err := opts.ToAddonListQuery() - if err != nil { - r.Err = err - return - } - url += q - } - _, r.Err = c.Get(url, &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func GetTemplates(c *golangsdk.ServiceClient) (r ListTemplateResult) { - _, r.Err = c.Get(addonTemplatesURL(c), &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -func ListAddonInstances(c *golangsdk.ServiceClient, clusterID string) (r ListInstanceResult) { - _, r.Err = c.Get(instanceURL(c, clusterID), &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - }) - return -} - -// WaitForAddonRunning - wait until addon status is `running` -func WaitForAddonRunning(client *golangsdk.ServiceClient, id, clusterID string, timeoutSeconds int) error { - return golangsdk.WaitFor(timeoutSeconds, func() (bool, error) { - addon, err := Get(client, id, clusterID).Extract() - if err != nil { - return false, fmt.Errorf("error retriving addon status: %w", err) - } - if addon.Status.Status == "running" { - return true, nil - } - return false, nil - }) -} - -// WaitForAddonDeleted - wait until addon is deleted -func WaitForAddonDeleted(client *golangsdk.ServiceClient, id, clusterID string, timeoutSeconds int) error { - return golangsdk.WaitFor(timeoutSeconds, func() (bool, error) { - _, err := Get(client, id, clusterID).Extract() - if err != nil { - if _, ok := err.(golangsdk.ErrDefault404); ok { - return true, nil - } - return false, fmt.Errorf("error retriving addon status: %w", err) - } - return false, nil - }) -} diff --git a/openstack/cce/v3/addons/results.go b/openstack/cce/v3/addons/results.go deleted file mode 100644 index 49cbcaafb..000000000 --- a/openstack/cce/v3/addons/results.go +++ /dev/null @@ -1,238 +0,0 @@ -package addons - -import ( - "github.com/opentelekomcloud/gophertelekomcloud" -) - -type Addon struct { - // API type, fixed value Addon - Kind string `json:"kind" required:"true"` - // API version, fixed value v3 - ApiVersion string `json:"apiVersion" required:"true"` - // Metadata of an Addon - Metadata MetaData `json:"metadata" required:"true"` - // Specifications of an Addon - Spec Spec `json:"spec" required:"true"` - // Status of an Addon - Status Status `json:"status"` -} - -// Metadata required to create an addon -type MetaData struct { - // Addon unique name - Name string `json:"name"` - // Addon unique Id - Id string `json:"uid"` - // Addon tag, key/value pair format - Labels map[string]string `json:"lables"` - // Addon annotation, key/value pair format - Annotations map[string]string `json:"annotaions"` -} - -// Specifications to create an addon -type Spec struct { - // For the addon version. - Version string `json:"version" required:"true"` - // Cluster ID. - ClusterID string `json:"clusterID" required:"true"` - // Addon Template Name. - AddonTemplateName string `json:"addonTemplateName" required:"true"` - // Addon Template Type. - AddonTemplateType string `json:"addonTemplateType" required:"true"` - // Addon Template Labels. - AddonTemplateLables []string `json:"addonTemplateLables,omitempty"` - // Addon Description. - Description string `json:"description" required:"true"` - // Addon Parameters - Values Values `json:"values" required:"true"` -} - -type Status struct { - // The state of the addon - Status string `json:"status"` - // Reasons for the addon to become current - Reason string `json:"reason"` - // Error Message - Message string `json:"message"` - // The target versions of the addon - TargetVersions []string `json:"targetVersions"` -} - -type commonResult struct { - golangsdk.Result -} - -// Extract is a function that accepts a result and extracts an Addon. -func (r commonResult) Extract() (*Addon, error) { - var s Addon - err := r.ExtractInto(&s) - return &s, err -} - -// CreateResult represents the result of a create operation. Call its Extract -// method to interpret it as an Addon. -type CreateResult struct { - commonResult -} - -// GetResult represents the result of a get operation. Call its Extract -// method to interpret it as an Addon. -type GetResult struct { - commonResult -} - -// UpdateResult represents the result of an update operation. Call its Extract -// method to interpret it as an Addon. -type UpdateResult struct { - commonResult -} - -// DeleteResult represents the result of a delete operation. Call its ExtractErr -// method to determine if the request succeeded or failed. -type DeleteResult struct { - golangsdk.ErrResult -} - -type ListTemplateResult struct { - golangsdk.Result -} - -type ListInstanceResult struct { - golangsdk.Result -} - -type SupportVersion struct { - // Cluster type that supports the add-on template - ClusterType string `json:"clusterType"` - // Cluster versions that support the add-on template, - // the parameter value is a regular expression - ClusterVersion []string `json:"clusterVersion"` -} - -type Version struct { - // Add-on version - Version string `json:"version"` - // Add-on installation parameters - Input map[string]interface{} `json:"input"` - // Whether the add-on version is a stable release - Stable bool `json:"stable"` - // Cluster versions that support the add-on template - SupportVersions []SupportVersion `json:"supportVersions"` - // Creation time of the add-on instance - CreationTimestamp string `json:"creationTimestamp"` - // Time when the add-on instance was updated - UpdateTimestamp string `json:"updateTimestamp"` -} - -type AddonSpec struct { - // Template type (helm or static). - Type string `json:"type" required:"true"` - // Whether the add-on is installed by default - Require bool `json:"require" required:"true"` - // Group to which the template belongs - Labels []string `json:"labels" required:"true"` - // URL of the logo image - LogoURL string `json:"logoURL" required:"true"` - // URL of the readme file - ReadmeURL string `json:"readmeURL" required:"true"` - // Template description - Description string `json:"description" required:"true"` - // Template version details - Versions []Version `json:"versions" required:"true"` -} - -type AddonTemplate struct { - // API type, fixed value Addon - Kind string `json:"kind" required:"true"` - // API version, fixed value v3 - ApiVersion string `json:"apiVersion" required:"true"` - // Metadata of an Addon - Metadata MetaData `json:"metadata" required:"true"` - // Specifications of an Addon - Spec AddonSpec `json:"spec" required:"true"` -} - -type AddonTemplateList struct { - // API type, fixed value Addon - Kind string `json:"kind" required:"true"` - // API version, fixed value v3 - ApiVersion string `json:"apiVersion" required:"true"` - // Add-on template list - Items []AddonTemplate `json:"items" required:"true"` -} - -// Extract is a function that accepts a result and extracts an Addon. -func (r ListTemplateResult) Extract() (*AddonTemplateList, error) { - var s AddonTemplateList - err := r.ExtractInto(&s) - return &s, err -} - -type InstanceMetadata struct { - ID string `json:"uid"` - Name string `json:"name"` - Labels map[string]string `json:"labels"` - Annotations map[string]string `json:"annotations"` - UpdateTimestamp string `json:"updateTimestamp"` - CreationTimestamp string `json:"creationTimestamp"` -} - -type AddonInstanceSpec struct { - ClusterID string `json:"clusterID"` - Version string `json:"version"` - TemplateName string `json:"addonTemplateName"` - TemplateType string `json:"addonTemplateType"` - TemplateLabels []string `json:"addonTemplateLabels"` - Descrition string `json:"descrition"` - Values map[string]interface{} `json:"values"` -} - -type Versions struct { - Version string `json:"version"` - Input map[string]interface{} `json:"input"` - Stable bool `json:"stable"` - Translate map[string]interface{} `json:"translate"` - UpdateTimestamp string `json:"updateTimestamp"` - CreationTimestamp string `json:"creationTimestamp"` -} - -type InstanceStatus struct { - Status string `json:"status"` - Reason string `json:"Reason"` - Message string `json:"message"` - TargetVersions []string `json:"targetVersions"` - CurrentVersion Versions `json:"currentVersion"` -} - -type AddonInstance struct { - // API type, fixed value Addon - Kind string `json:"kind" required:"true"` - // API version, fixed value v3 - ApiVersion string `json:"apiVersion" required:"true"` - // Metadata of an Addon - Metadata InstanceMetadata `json:"metadata" required:"true"` - // Specifications of an Addon - Spec AddonInstanceSpec `json:"spec" required:"true"` - // Status of an Addon - Status InstanceStatus `json:"status"` -} - -type AddonInstanceList struct { - // API type, fixed value Addon - Kind string `json:"kind" required:"true"` - // API version, fixed value v3 - ApiVersion string `json:"apiVersion" required:"true"` - // Metadata - Basic information about the add-on. A collection of attributes. - Metadata string `json:"metadata"` - // Add-on template list - Items []AddonInstance `json:"items" required:"true"` -} - -func (r ListInstanceResult) Extract() (*AddonInstanceList, error) { - s := new(AddonInstanceList) - err := r.ExtractInto(s) - if err != nil { - return nil, err - } - return s, err -} diff --git a/openstack/cce/v3/addons/urls.go b/openstack/cce/v3/addons/urls.go deleted file mode 100644 index 4b37dbd8b..000000000 --- a/openstack/cce/v3/addons/urls.go +++ /dev/null @@ -1,39 +0,0 @@ -package addons - -import ( - "fmt" - "strings" - - "github.com/opentelekomcloud/gophertelekomcloud" -) - -const ( - rootPath = "addons" - templatesPath = "addontemplates" -) - -func rootURL(client *golangsdk.ServiceClient, clusterID string) string { - return CCEServiceURL(client, clusterID, rootPath) -} - -func resourceURL(client *golangsdk.ServiceClient, id, clusterID string) string { - return CCEServiceURL(client, clusterID, rootPath, id+"?cluster_id="+clusterID) -} - -func CCEServiceURL(client *golangsdk.ServiceClient, clusterID string, parts ...string) string { - rbUrl := fmt.Sprintf("https://%s.%s", clusterID, client.ResourceBaseURL()[8:]) - return rbUrl + strings.Join(parts, "/") -} - -func templatesURL(client *golangsdk.ServiceClient, clusterID string) string { - return CCEServiceURL(client, clusterID, templatesPath) -} - -func instanceURL(client *golangsdk.ServiceClient, clusterID string) string { - return fmt.Sprintf("%s?cluster_id=%s", CCEServiceURL(client, clusterID, rootPath), clusterID) -} - -// GET /api/v3/addontemplates -func addonTemplatesURL(client *golangsdk.ServiceClient) string { - return client.ServiceURL(templatesPath) -} From 94247b8d11eebcef55282be00e3891e245269b2d Mon Sep 17 00:00:00 2001 From: Anton Sidelnikov <53078276+anton-sidelnikov@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:43:59 +0100 Subject: [PATCH 4/4] [CI] run acc tests on pull_request_target only (#777) --- .github/workflows/ci.yaml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8870dcbf9..77b30f3e4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,9 +2,9 @@ name: CI on: pull_request: - types: - - opened - - synchronize + types: [opened, synchronize] + pull_request_target: + types: [opened, synchronize] workflow_dispatch: env: @@ -46,6 +46,9 @@ jobs: acc_tests: name: acceptance tests + if: > + github.event_name == 'pull_request_target' || + (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false) runs-on: ubuntu-latest environment: tests steps: @@ -64,7 +67,12 @@ jobs: eco_check: name: eco/check - if: always() + if: > + always() && + ( + github.event_name == 'pull_request_target' || + (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false) + ) needs: [lint, vet, unit_tests, acc_tests] runs-on: ubuntu-latest steps: