From 6c4ff6af18bbb61ce03403ed9481222355261781 Mon Sep 17 00:00:00 2001 From: Zhenguo Niu Date: Thu, 8 Apr 2021 02:57:16 +0000 Subject: [PATCH 1/2] Add SWR organization resource --- docs/resources/swr_organization.md | 50 +++++++ go.mod | 2 +- go.sum | 4 +- huaweicloud/config.go | 4 + huaweicloud/endpoints.go | 5 + huaweicloud/endpoints_test.go | 10 ++ huaweicloud/provider.go | 1 + .../resource_huaweicloud_swr_organization.go | 131 ++++++++++++++++++ ...ource_huaweicloud_swr_organization_test.go | 103 ++++++++++++++ .../openstack/swr/v2/namespaces/requests.go | 55 ++++++++ .../openstack/swr/v2/namespaces/results.go | 42 ++++++ .../openstack/swr/v2/namespaces/urls.go | 11 ++ vendor/modules.txt | 3 +- 13 files changed, 417 insertions(+), 4 deletions(-) create mode 100644 docs/resources/swr_organization.md create mode 100644 huaweicloud/resource_huaweicloud_swr_organization.go create mode 100644 huaweicloud/resource_huaweicloud_swr_organization_test.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/requests.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/results.go create mode 100644 vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/urls.go diff --git a/docs/resources/swr_organization.md b/docs/resources/swr_organization.md new file mode 100644 index 0000000000..ee1cdda415 --- /dev/null +++ b/docs/resources/swr_organization.md @@ -0,0 +1,50 @@ +--- +subcategory: "SoftWare Repository for Container (SWR)" +--- + +# huaweicloud\_swr\_organization + +Manages a SWR organization resource within HuaweiCloud. + +## Example Usage + +```hcl +resource "huaweicloud_swr_organization" "test" { + name = "terraform-test" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) Specifies the region in which to create the resource. If omitted, the provider-level region will be used. Changing this creates a new resource. + +* `name` - (Required, String, ForceNew) Specifies the name of the organization. The organization name must be globally unique. + + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - ID of the organization. + +* `creator` - The creator user name of the organization. + +* `permission` - The permission of the organization, the value can be Manage, Write, and Read. + +* `login_server` - The URL that can be used to log into the container registry. + + +## Timeouts +This resource provides the following timeouts configuration options: +- `create` - Default is 10 minute. +- `delete` - Default is 10 minute. + +## Import + +Organizations can be imported using the `name`, e.g. + +``` +$ terraform import huaweicloud_swr_organization.test org-name +``` diff --git a/go.mod b/go.mod index 66ea9e7725..d7ef2e31b9 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-20210406114125-0f07278d722c + github.com/huaweicloud/golangsdk v0.0.0-20210407074202-8678feadcd3b 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 bf851040e0..107b40e99d 100644 --- a/go.sum +++ b/go.sum @@ -225,8 +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-20210406114125-0f07278d722c h1:CwxvUSdetbTeImxmNxmVTLUE+5ryDAf6DLYE47/28Yo= -github.com/huaweicloud/golangsdk v0.0.0-20210406114125-0f07278d722c/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0= +github.com/huaweicloud/golangsdk v0.0.0-20210407074202-8678feadcd3b h1:FgYDXrLHLnUofVQvkdju0JnYwMTDzTf1OyWan4TLS98= +github.com/huaweicloud/golangsdk v0.0.0-20210407074202-8678feadcd3b/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/config.go b/huaweicloud/config.go index ee6a65a3eb..ab2817ccfd 100644 --- a/huaweicloud/config.go +++ b/huaweicloud/config.go @@ -559,6 +559,10 @@ func (c *Config) FgsV2Client(region string) (*golangsdk.ServiceClient, error) { return c.NewServiceClient("fgsv2", region) } +func (c *Config) SwrV2Client(region string) (*golangsdk.ServiceClient, error) { + return c.NewServiceClient("swr", region) +} + // ********** client for Storage ********** func (c *Config) BlockStorageV2Client(region string) (*golangsdk.ServiceClient, error) { return c.NewServiceClient("volumev2", region) diff --git a/huaweicloud/endpoints.go b/huaweicloud/endpoints.go index e0cb2b83f3..c964b1b18b 100644 --- a/huaweicloud/endpoints.go +++ b/huaweicloud/endpoints.go @@ -100,6 +100,11 @@ var allServiceCatalog = map[string]ServiceCatalog{ Name: "functiongraph", Version: "v2", }, + "swr": { + Name: "swr-api", + Version: "v2", + WithOutProjectID: true, + }, // ******* catalog for storage ****** "volumev2": { diff --git a/huaweicloud/endpoints_test.go b/huaweicloud/endpoints_test.go index 52f3655561..b94d648d09 100644 --- a/huaweicloud/endpoints_test.go +++ b/huaweicloud/endpoints_test.go @@ -468,6 +468,16 @@ func TestAccServiceEndpoints_Compute(t *testing.T) { expectedURL = fmt.Sprintf("https://functiongraph.%s.%s/v2/%s/", HW_REGION_NAME, config.Cloud, config.TenantID) actualURL = serviceClient.ResourceBaseURL() compareURL(expectedURL, actualURL, "fgs", "v2", t) + + // test for swrV2Client + serviceClient, err = nil, nil + serviceClient, err = config.SwrV2Client(HW_REGION_NAME) + if err != nil { + t.Fatalf("Error creating HuaweiCloud swr v2 client: %s", err) + } + expectedURL = fmt.Sprintf("https://swr-api.%s.%s/v2/", HW_REGION_NAME, config.Cloud) + actualURL = serviceClient.ResourceBaseURL() + compareURL(expectedURL, actualURL, "swr", "v2", t) } // TestAccServiceEndpoints_Storage test for the endpoints of the clients used in storage diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index a720971256..89379b2ed5 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -443,6 +443,7 @@ func Provider() terraform.ResourceProvider { "huaweicloud_sfs_turbo": ResourceSFSTurbo(), "huaweicloud_smn_topic": resourceTopic(), "huaweicloud_smn_subscription": resourceSubscription(), + "huaweicloud_swr_organization": resourceSWROrganization(), "huaweicloud_vbs_backup": resourceVBSBackupV2(), "huaweicloud_vbs_backup_policy": resourceVBSBackupPolicyV2(), "huaweicloud_vpc": ResourceVirtualPrivateCloudV1(), diff --git a/huaweicloud/resource_huaweicloud_swr_organization.go b/huaweicloud/resource_huaweicloud_swr_organization.go new file mode 100644 index 0000000000..36893d52e8 --- /dev/null +++ b/huaweicloud/resource_huaweicloud_swr_organization.go @@ -0,0 +1,131 @@ +package huaweicloud + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces" +) + +func resourceSWROrganization() *schema.Resource { + return &schema.Resource{ + Create: resourceSWROrganizationCreate, + Read: resourceSWROrganizationRead, + Delete: resourceSWROrganizationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + //request and response parameters + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "creator": { + Type: schema.TypeString, + Computed: true, + }, + "permission": { + Type: schema.TypeString, + Computed: true, + }, + "login_server": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceSWROrganizationCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + swrClient, err := config.SwrV2Client(GetRegion(d, config)) + + if err != nil { + return fmt.Errorf("Unable to create HuaweiCloud SWR client : %s", err) + } + + name := d.Get("name").(string) + createOpts := namespaces.CreateOpts{ + Namespace: name, + } + + err = namespaces.Create(swrClient, createOpts).ExtractErr() + + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud SWR Organization: %s", err) + } + + d.SetId(name) + + return resourceSWROrganizationRead(d, meta) +} + +func resourceSWROrganizationRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + swrClient, err := config.SwrV2Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud SWR client: %s", err) + } + + n, err := namespaces.Get(swrClient, d.Id()).Extract() + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + d.SetId("") + return nil + } + + return fmt.Errorf("Error retrieving HuaweiCloud SWR: %s", err) + } + + permission := "Unknown" + switch n.Auth { + case 7: + permission = "Manage" + case 3: + permission = "Write" + case 1: + permission = "Read" + } + + d.Set("region", GetRegion(d, config)) + d.Set("name", n.Name) + d.Set("creator", n.CreatorName) + d.Set("permission", permission) + + login := fmt.Sprintf("swr.%s.myhuaweicloud.com", GetRegion(d, config)) + d.Set("login_server", login) + + return nil +} + +func resourceSWROrganizationDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + swrClient, err := config.SwrV2Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud SWR Client: %s", err) + } + + err = namespaces.Delete(swrClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting HuaweiCloud SWR Organization: %s", err) + } + + d.SetId("") + return nil +} diff --git a/huaweicloud/resource_huaweicloud_swr_organization_test.go b/huaweicloud/resource_huaweicloud_swr_organization_test.go new file mode 100644 index 0000000000..e5ac41848d --- /dev/null +++ b/huaweicloud/resource_huaweicloud_swr_organization_test.go @@ -0,0 +1,103 @@ +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" + + "github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces" +) + +func TestAccSWROrganization_basic(t *testing.T) { + var org namespaces.Namespace + + rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + resourceName := "huaweicloud_swr_organization.test" + loginServer := fmt.Sprintf("swr.%s.myhuaweicloud.com", HW_REGION_NAME) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckSWROrganizationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccSWROrganization_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckSWROrganizationExists(resourceName, &org), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "permission", "Manage"), + resource.TestCheckResourceAttr(resourceName, "login_server", loginServer), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckSWROrganizationDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + swrClient, err := config.SwrV2Client(HW_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud SWR client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "huaweicloud_swr_organization" { + continue + } + + _, err := namespaces.Get(swrClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("SWR organization still exists") + } + } + + return nil +} + +func testAccCheckSWROrganizationExists(n string, org *namespaces.Namespace) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + config := testAccProvider.Meta().(*Config) + swrClient, err := config.SwrV2Client(HW_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud SWR client: %s", err) + } + + found, err := namespaces.Get(swrClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.Name != rs.Primary.ID { + return fmt.Errorf("SWR organization not found") + } + + *org = *found + + return nil + } +} + +func testAccSWROrganization_basic(rName string) string { + return fmt.Sprintf(` +resource "huaweicloud_swr_organization" "test" { + name = "%s" +} +`, rName) +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/requests.go b/vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/requests.go new file mode 100644 index 0000000000..da9d0ca2f3 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/requests.go @@ -0,0 +1,55 @@ +package namespaces + +import ( + "github.com/huaweicloud/golangsdk" +) + +var RequestOpts golangsdk.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 { + ToNamespaceCreateMap() (map[string]interface{}, error) +} + +// CreateOpts contains all the values needed to create a new network +type CreateOpts struct { + Namespace string `json:"namespace" required:"true"` +} + +// ToNamespaceCreateMap builds a create request body from CreateOpts. +func (opts CreateOpts) ToNamespaceCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "") +} + +// Create accepts a CreateOpts struct and uses the values to create a new namespace. +func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToNamespaceCreateMap() + if err != nil { + r.Err = err + return + } + reqOpt := &golangsdk.RequestOpts{OkCodes: []int{201}} + _, r.Err = c.Post(rootURL(c), b, &r.Body, reqOpt) + return +} + +// Get retrieves a particular network based on its unique ID. +func Get(c *golangsdk.ServiceClient, id string) (r GetResult) { + _, r.Err = c.Get(resourceURL(c, id), &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + MoreHeaders: RequestOpts.MoreHeaders, JSONBody: nil, + }) + return +} + +// Delete will permanently delete a particular network based on its unique ID. +func Delete(c *golangsdk.ServiceClient, id string) (r DeleteResult) { + _, r.Err = c.Delete(resourceURL(c, id), &golangsdk.RequestOpts{ + OkCodes: []int{204}, + MoreHeaders: RequestOpts.MoreHeaders, JSONBody: nil, + }) + return +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/results.go b/vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/results.go new file mode 100644 index 0000000000..bd2c85fa93 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/results.go @@ -0,0 +1,42 @@ +package namespaces + +import ( + "github.com/huaweicloud/golangsdk" +) + +type Namespace struct { + // Name of the Namespace + Name string `json:"name"` + // Creator Name of the Namespace + CreatorName string `json:"creator_name"` + // Auth permission of the Namespace + Auth int `json:"auth"` +} + +type commonResult struct { + golangsdk.Result +} + +// Extract is a function that accepts a result and extracts a namespace. +func (r commonResult) Extract() (*Namespace, error) { + var s Namespace + err := r.ExtractInto(&s) + return &s, err +} + +// CreateResult represents the result of a create operation. +type CreateResult struct { + golangsdk.ErrResult +} + +// GetResult represents the result of a get operation. Call its Extract +// method to interpret it as a Network. +type GetResult 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 +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/urls.go b/vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/urls.go new file mode 100644 index 0000000000..c430f24b2f --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces/urls.go @@ -0,0 +1,11 @@ +package namespaces + +import "github.com/huaweicloud/golangsdk" + +func rootURL(client *golangsdk.ServiceClient) string { + return client.ServiceURL("manage", "namespaces") +} + +func resourceURL(client *golangsdk.ServiceClient, name string) string { + return client.ServiceURL("manage", "namespaces", name) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index b6bfbbf66d..12e2d127e8 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-20210406114125-0f07278d722c +# github.com/huaweicloud/golangsdk v0.0.0-20210407074202-8678feadcd3b ## explicit github.com/huaweicloud/golangsdk github.com/huaweicloud/golangsdk/internal @@ -420,6 +420,7 @@ github.com/huaweicloud/golangsdk/openstack/sfs/v2/shares github.com/huaweicloud/golangsdk/openstack/sfs_turbo/v1/shares github.com/huaweicloud/golangsdk/openstack/smn/v2/subscriptions github.com/huaweicloud/golangsdk/openstack/smn/v2/topics +github.com/huaweicloud/golangsdk/openstack/swr/v2/namespaces github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/backups github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/configurations github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances From 76ec512210865731b8c4d51c2ace9112364eaa58 Mon Sep 17 00:00:00 2001 From: Zhenguo Niu Date: Fri, 9 Apr 2021 11:44:44 +0800 Subject: [PATCH 2/2] Update resource_huaweicloud_swr_organization.go --- huaweicloud/resource_huaweicloud_swr_organization.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/huaweicloud/resource_huaweicloud_swr_organization.go b/huaweicloud/resource_huaweicloud_swr_organization.go index 36893d52e8..be02074b4b 100644 --- a/huaweicloud/resource_huaweicloud_swr_organization.go +++ b/huaweicloud/resource_huaweicloud_swr_organization.go @@ -108,7 +108,7 @@ func resourceSWROrganizationRead(d *schema.ResourceData, meta interface{}) error d.Set("creator", n.CreatorName) d.Set("permission", permission) - login := fmt.Sprintf("swr.%s.myhuaweicloud.com", GetRegion(d, config)) + login := fmt.Sprintf("swr.%s.%s", GetRegion(d, config), config.Cloud) d.Set("login_server", login) return nil