From ede0d76b0f21ad11edf043ceab25c81d0da58176 Mon Sep 17 00:00:00 2001 From: Jason Zhang Date: Wed, 14 Apr 2021 11:01:26 +0800 Subject: [PATCH] add data_source huaweicloud_cce_addon --- docs/data-sources/cce_addon.md | 37 ++++++++ go.mod | 2 +- go.sum | 8 +- .../data_source_huaweicloud_cce_addon_v3.go | 90 +++++++++++++++++++ ...ta_source_huaweicloud_cce_addon_v3_test.go | 55 ++++++++++++ huaweicloud/provider.go | 1 + .../openstack/cce/v3/addons/requests.go | 89 +++++++++++++++--- .../openstack/cce/v3/addons/results.go | 67 +++++++++++--- .../golangsdk/openstack/cce/v3/addons/urls.go | 9 +- vendor/modules.txt | 2 +- 10 files changed, 330 insertions(+), 30 deletions(-) create mode 100644 docs/data-sources/cce_addon.md create mode 100644 huaweicloud/data_source_huaweicloud_cce_addon_v3.go create mode 100644 huaweicloud/data_source_huaweicloud_cce_addon_v3_test.go diff --git a/docs/data-sources/cce_addon.md b/docs/data-sources/cce_addon.md new file mode 100644 index 0000000000..a8427f78a2 --- /dev/null +++ b/docs/data-sources/cce_addon.md @@ -0,0 +1,37 @@ +--- +subcategory: "Cloud Container Engine (CCE)" +--- + +# huaweicloud\_cce\_addon + +To get the specified addon in a cluster. + +## Example Usage + +```hcl +variable "cluster_id" { } +variable "tempalte_name" { } + +data "huaweicloud_cce_addon" "addon" { + cluster_id = var.cluster_id + name = var.tempalte_name +} +``` +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String) The region in which to create the cce addon resource. + If omitted, the provider-level region will be used. +* `cluster_id` - (Required, String) Specifies the ID of the cluster. +* `addon_id` - (Optional, String) Specifies the ID of the addon. +* `template_name` - (Optional, String) Specifies the name of the addon template. +* `version` - (Optional, String) Specifies the version of the addon. +* `status` - (Optional, String) Specifies the addon status. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + + * `id` - ID of the addon instance. + * `description` - Description of addon instance. diff --git a/go.mod b/go.mod index 6d20c92d24..863d589756 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( github.com/hashicorp/errwrap v1.0.0 github.com/hashicorp/terraform-plugin-sdk v1.16.0 - github.com/huaweicloud/golangsdk v0.0.0-20210417091247-f78a81171753 + github.com/huaweicloud/golangsdk v0.0.0-20210420021131-cc06e265cc39 github.com/jen20/awspolicyequivalence v1.1.0 github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa // indirect github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index f1f17aa6fc..ee9c891af6 100644 --- a/go.sum +++ b/go.sum @@ -225,12 +225,8 @@ github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/huaweicloud/golangsdk v0.0.0-20210408110332-c61d9b336da5 h1:qsDthJ6oyB3Jexl1NTK/d8LePQL+zM7dIVyeeSpSmBs= -github.com/huaweicloud/golangsdk v0.0.0-20210408110332-c61d9b336da5/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0= -github.com/huaweicloud/golangsdk v0.0.0-20210412080213-f1dcb144bd25 h1:nal36cQv+dJUErG3UCFqdQFWdYjAZw9XqJP4Xwnoxf0= -github.com/huaweicloud/golangsdk v0.0.0-20210412080213-f1dcb144bd25/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0= -github.com/huaweicloud/golangsdk v0.0.0-20210417091247-f78a81171753 h1:ogihIkqOr4NqphAjbdgZb7di7HzVU9lD9ZcQEOnLrJI= -github.com/huaweicloud/golangsdk v0.0.0-20210417091247-f78a81171753/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0= +github.com/huaweicloud/golangsdk v0.0.0-20210420021131-cc06e265cc39 h1:QFIWCqLimeHn9WO/nVlNSWwu8vm2UqbbIp5I2UQoFMk= +github.com/huaweicloud/golangsdk v0.0.0-20210420021131-cc06e265cc39/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= diff --git a/huaweicloud/data_source_huaweicloud_cce_addon_v3.go b/huaweicloud/data_source_huaweicloud_cce_addon_v3.go new file mode 100644 index 0000000000..5033be6cf2 --- /dev/null +++ b/huaweicloud/data_source_huaweicloud_cce_addon_v3.go @@ -0,0 +1,90 @@ +package huaweicloud + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/huaweicloud/golangsdk/openstack/cce/v3/addons" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +func DataSourceCCEAddonV3() *schema.Resource { + return &schema.Resource{ + Read: dataSourceCceAddonsV3Read, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "cluster_id": { + Type: schema.TypeString, + Required: true, + }, + "addon_id": { + Type: schema.TypeString, + Optional: true, + }, + "template_name": { + Type: schema.TypeString, + Optional: true, + }, + "version": { + Type: schema.TypeString, + Optional: true, + }, + "status": { + Type: schema.TypeString, + Optional: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceCceAddonsV3Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*config.Config) + cceClient, err := config.CceAddonV3Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("unable to create HuaweiCloud CCE client : %s", err) + } + + listOpts := addons.ListOpts{ + Uid: d.Get("addon_id").(string), + AddonTemplateName: d.Get("template_name").(string), + Version: d.Get("version").(string), + Status: d.Get("status").(string), + } + + refinedAddons, err := addons.List(cceClient, d.Get("cluster_id").(string), listOpts) + + if err != nil { + return fmt.Errorf("unable to retrieve Addons: %s", err) + } + + if len(refinedAddons) < 1 { + return fmt.Errorf("your query returned no results, please change your search criteria and try again") + } + + if len(refinedAddons) > 1 { + return fmt.Errorf("your query returned more than one result, please try a more specific search criteria") + } + + Addon := refinedAddons[0] + + log.Printf("[DEBUG] Retrieved Nodes using given filter %s: %+v", Addon.Metadata.Id, Addon) + d.SetId(Addon.Metadata.Id) + d.Set("addon_id", Addon.Metadata.Id) + d.Set("template_name", Addon.Spec.AddonTemplateName) + d.Set("version", Addon.Spec.Version) + d.Set("status", Addon.Status.Status) + d.Set("region", GetRegion(d, config)) + d.Set("description", Addon.Spec.Description) + + return nil +} diff --git a/huaweicloud/data_source_huaweicloud_cce_addon_v3_test.go b/huaweicloud/data_source_huaweicloud_cce_addon_v3_test.go new file mode 100644 index 0000000000..80abc72406 --- /dev/null +++ b/huaweicloud/data_source_huaweicloud_cce_addon_v3_test.go @@ -0,0 +1,55 @@ +package huaweicloud + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccCCEAddonV3DataSource_basic(t *testing.T) { + rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "data.huaweicloud_cce_addon.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCCEAddonV3DataSource_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCCEAddonV3DataSourceID(resourceName), + resource.TestCheckResourceAttr(resourceName, "template_name", "metrics-server"), + ), + }, + }, + }) +} + +func testAccCheckCCEAddonV3DataSourceID(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Can't find Addons data source: %s ", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("Addon data source ID not set ") + } + + return nil + } +} + +func testAccCCEAddonV3DataSource_basic(rName string) string { + return fmt.Sprintf(` +%s + +data "huaweicloud_cce_addon" "test" { + cluster_id = huaweicloud_cce_cluster.test.id + template_name = huaweicloud_cce_addon.test.template_name +} +`, testAccCCEAddonV3_basic(rName)) +} diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index bd2480607e..84f4af15ec 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -260,6 +260,7 @@ func Provider() terraform.ResourceProvider { "huaweicloud_cce_cluster": DataSourceCCEClusterV3(), "huaweicloud_cce_node": DataSourceCCENodeV3(), "huaweicloud_cce_node_pool": DataSourceCCENodePoolV3(), + "huaweicloud_cce_addon": DataSourceCCEAddonV3(), "huaweicloud_cdm_flavors": dataSourceCdmFlavorV1(), "huaweicloud_compute_flavors": DataSourceEcsFlavors(), "huaweicloud_compute_instance": DataSourceComputeInstance(), diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/requests.go b/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/requests.go index 56a83ec118..1b54457b24 100644 --- a/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/requests.go +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/requests.go @@ -1,11 +1,85 @@ package addons import ( + "reflect" + "github.com/huaweicloud/golangsdk" ) -var RequestOpts golangsdk.RequestOpts = golangsdk.RequestOpts{ - MoreHeaders: map[string]string{"Content-Type": "application/json"}, +// ListOpts allows the filtering of list data using given parameters. +type ListOpts struct { + AddonTemplateName string `json:"addonTemplateName"` + Uid string `json:"uid"` + Version string `json:"version"` + Status string `json:"status"` +} + +// List returns collection of addons. +func List(client *golangsdk.ServiceClient, clusterID string, opts ListOpts) ([]Addon, error) { + var r ListResult + _, r.Err = client.Get(resourceListURL(client, clusterID), &r.Body, nil) + + allAddons, err := r.ExtractAddon() + + if err != nil { + return nil, err + } + + return FilterAddons(allAddons, opts), nil +} + +func FilterAddons(addons []Addon, opts ListOpts) []Addon { + + var refinedAddons []Addon + var matched bool + + m := map[string]FilterStruct{} + + if opts.AddonTemplateName != "" { + m["AddonTemplateName"] = FilterStruct{Value: opts.AddonTemplateName, Driller: []string{"Spec"}} + } + if opts.Version != "" { + m["Version"] = FilterStruct{Value: opts.Version, Driller: []string{"Spec"}} + } + if opts.Uid != "" { + m["Id"] = FilterStruct{Value: opts.Uid, Driller: []string{"Metadata"}} + } + if opts.Status != "" { + m["Status"] = FilterStruct{Value: opts.Status, Driller: []string{"Status"}} + } + + if len(m) > 0 && len(addons) > 0 { + for _, addon := range addons { + matched = true + + for key, value := range m { + if sVal := GetStructNestedField(&addon, key, value.Driller); sVal != value.Value { + matched = false + break + } + } + if matched { + refinedAddons = append(refinedAddons, addon) + } + } + } + + return refinedAddons +} + +func GetStructNestedField(v *Addon, field string, structDriller []string) string { + r := reflect.ValueOf(v) + for _, drillField := range structDriller { + f := reflect.Indirect(r).FieldByName(drillField).Interface() + r = reflect.ValueOf(f) + } + f1 := reflect.Indirect(r).FieldByName(field) + return string(f1.String()) +} + +type FilterStruct struct { + Value string + Driller []string } // CreateOptsBuilder allows extensions to add additional parameters to the @@ -71,18 +145,13 @@ func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder, cluster_id strin // Get retrieves a particular addon based on its unique ID. func Get(c *golangsdk.ServiceClient, id, cluster_id string) (r GetResult) { - _, r.Err = c.Get(resourceURL(c, id, cluster_id), &r.Body, &golangsdk.RequestOpts{ - OkCodes: []int{200}, - MoreHeaders: RequestOpts.MoreHeaders, JSONBody: nil, - }) + _, r.Err = c.Get(resourceURL(c, id, cluster_id), &r.Body, nil) return } // Delete will permanently delete a particular addon based on its unique ID. func Delete(c *golangsdk.ServiceClient, id, cluster_id string) (r DeleteResult) { - _, r.Err = c.Delete(resourceURL(c, id, cluster_id), &golangsdk.RequestOpts{ - OkCodes: []int{200}, - MoreHeaders: RequestOpts.MoreHeaders, JSONBody: nil, - }) + reqOpt := &golangsdk.RequestOpts{OkCodes: []int{200}} + _, r.Err = c.Delete(resourceURL(c, id, cluster_id), reqOpt) return } diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/results.go b/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/results.go index f59ca6ddb1..8edc5d1a64 100644 --- a/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/results.go +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/results.go @@ -4,15 +4,24 @@ import ( "github.com/huaweicloud/golangsdk" ) +type ListAddon struct { + // API type, fixed value "List" + Kind string `json:"kind"` + // API version, fixed value "v3" + Apiversion string `json:"apiVersion"` + // all Node Pools + Addons []Addon `json:"items"` +} + type Addon struct { // API type, fixed value Addon - Kind string `json:"kind" required:"true"` + Kind string `json:"kind"` // API version, fixed value v3 - ApiVersion string `json:"apiVersion" required:"true"` + ApiVersion string `json:"apiVersion"` // Metadata of an Addon - Metadata MetaData `json:"metadata" required:"true"` + Metadata MetaData `json:"metadata"` // Specifications of an Addon - Spec Spec `json:"spec" required:"true"` + Spec Spec `json:"spec"` // Status of an Addon Status Status `json:"status"` } @@ -32,19 +41,19 @@ type MetaData struct { //Specifications to create an addon type Spec struct { // For the addon version. - Version string `json:"version" required:"true"` + Version string `json:"version"` // Cluster ID. - ClusterID string `json:"clusterID" required:"true"` + ClusterID string `json:"clusterID"` // Addon Template Name. - AddonTemplateName string `json:"addonTemplateName" required:"true"` + AddonTemplateName string `json:"addonTemplateName"` // Addon Template Type. - AddonTemplateType string `json:"addonTemplateType" required:"true"` + AddonTemplateType string `json:"addonTemplateType"` // Addon Template Labels. - AddonTemplateLables []string `json:"addonTemplateLables,omitempty"` + AddonTemplateLables []string `json:"addonTemplateLables"` // Addon Description. - Description string `json:"description" required:"true"` + Description string `json:"description"` // Addon Parameters - Values Values `json:"values" required:"true"` + Values Values `json:"values"` } type Status struct { @@ -56,8 +65,27 @@ type Status struct { Message string `json:"message"` //The target versions of the addon TargetVersions []string `json:"targetVersions"` + //Current version of the addon + CurrentVersion Versions `json:"currentVersion"` +} + +type Versions struct { + // Version of the addon + Version string `json:"version"` + // The installing param of the addon + Input map[string]interface{} `json:"input"` + // Wether it is a stable version + Stable bool `json:"stable"` + // Translate information + Translate map[string]interface{} `json:"translate"` + // Supported versions + SupportVersions []SupportVersions `json:"supportVersions"` } +type SupportVersions struct { + ClusterType string `json:"clusterType"` + ClusterVersion []string `json:"clusterVersion"` +} type commonResult struct { golangsdk.Result } @@ -69,6 +97,23 @@ func (r commonResult) Extract() (*Addon, error) { return &s, err } +// ExtractAddon is a function that accepts a ListOpts struct, which allows you to filter and sort +// the returned collection for greater efficiency. +func (r commonResult) ExtractAddon() ([]Addon, error) { + var s ListAddon + err := r.ExtractInto(&s) + if err != nil { + return nil, err + } + return s.Addons, nil +} + +// ListResult represents the result of a list operation. Call its ExtractAddon +// method to interpret it as a Addon. +type ListResult struct { + commonResult +} + // CreateResult represents the result of a create operation. Call its Extract // method to interpret it as an Addon. type CreateResult struct { diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/urls.go b/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/urls.go index 4e4b0fee41..8882161272 100644 --- a/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/urls.go +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/cce/v3/addons/urls.go @@ -1,6 +1,7 @@ package addons import ( + "net/url" "strings" "github.com/huaweicloud/golangsdk" @@ -18,7 +19,13 @@ func resourceURL(client *golangsdk.ServiceClient, id, cluster_id string) string return CCEServiceURL(client, cluster_id, rootPath, id+"?cluster_id="+cluster_id) } +func resourceListURL(client *golangsdk.ServiceClient, cluster_id string) string { + return CCEServiceURL(client, cluster_id, rootPath+"?cluster_id="+cluster_id) +} + func CCEServiceURL(client *golangsdk.ServiceClient, cluster_id string, parts ...string) string { - rbUrl := "https://" + cluster_id + "." + client.ResourceBaseURL()[8:] + u, _ := url.Parse(client.ResourceBaseURL()) + u.Host = cluster_id + "." + u.Host + rbUrl := u.String() return rbUrl + strings.Join(parts, "/") } diff --git a/vendor/modules.txt b/vendor/modules.txt index 767aafd910..a9d364fa45 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -257,7 +257,7 @@ github.com/hashicorp/terraform-svchost/auth github.com/hashicorp/terraform-svchost/disco # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux -# github.com/huaweicloud/golangsdk v0.0.0-20210417091247-f78a81171753 +# github.com/huaweicloud/golangsdk v0.0.0-20210420021131-cc06e265cc39 ## explicit github.com/huaweicloud/golangsdk github.com/huaweicloud/golangsdk/internal