diff --git a/docs/resources/codearts_deploy_hosts_copy.md b/docs/resources/codearts_deploy_hosts_copy.md new file mode 100644 index 0000000000..470e4923c4 --- /dev/null +++ b/docs/resources/codearts_deploy_hosts_copy.md @@ -0,0 +1,48 @@ +--- +subcategory: "CodeArts Deploy" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_codearts_deploy_hosts_copy" +description: |- + Manages a CodeArts deploy hosts copy resource within HuaweiCloud. +--- + +# huaweicloud_codearts_deploy_hosts_copy + +Manages a CodeArts deploy hosts copy resource within HuaweiCloud. + +## Example Usage + +```hcl +variable "source_group_id" {} +variable "host_uuids" {} +variable "target_group_id" {} + +resource "huaweicloud_codearts_deploy_hosts_copy" "test" { + source_group_id = var.source_group_id + host_uuids = var.host_uuids + target_group_id = var.target_group_id +} +``` + +## 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. + +* `source_group_id` - (Required, String, ForceNew) Specifies the source group ID. + Changing this creates a new resource. + +* `host_uuids` - (Required, List, ForceNew) Specifies the host IDs list. + Changing this creates a new resource. + +* `target_group_id` - (Required, String, ForceNew) Specifies the target group ID. + Changing this creates a new resource. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index 259e0bb127..973792cf5d 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -2214,6 +2214,7 @@ func Provider() *schema.Provider { "huaweicloud_codearts_deploy_application_group": codeartsdeploy.ResourceDeployApplicationGroup(), "huaweicloud_codearts_deploy_group": codeartsdeploy.ResourceDeployGroup(), "huaweicloud_codearts_deploy_host": codeartsdeploy.ResourceDeployHost(), + "huaweicloud_codearts_deploy_hosts_copy": codeartsdeploy.ResourceCodeArtsDeployHostsCopy(), "huaweicloud_codearts_inspector_website": codeartsinspector.ResourceInspectorWebsite(), "huaweicloud_codearts_inspector_website_scan": codeartsinspector.ResourceInspectorWebsiteScan(), diff --git a/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_hosts_copy_test.go b/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_hosts_copy_test.go new file mode 100644 index 0000000000..10c12b3e47 --- /dev/null +++ b/huaweicloud/services/acceptance/codeartsdeploy/resource_huaweicloud_codearts_deploy_hosts_copy_test.go @@ -0,0 +1,159 @@ +package codeartsdeploy + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance/common" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +func TestAccCodeArtsDeployHostsCopy_basic(t *testing.T) { + name := acceptance.RandomAccResourceName() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t) }, + ProviderFactories: acceptance.TestAccProviderFactories, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testCodeArtsDeployHostsCopy_basic(name), + Check: resource.ComposeTestCheckFunc( + removeTheCopyHost("huaweicloud_codearts_deploy_group.test.1"), + ), + }, + }, + }) +} + +func testCodeArtsDeployHostsCopy_base(name string) string { + return fmt.Sprintf(` +%[1]s + +%[2]s + +resource "huaweicloud_compute_instance" "test" { + name = "%[3]s" + image_id = data.huaweicloud_images_image.test.id + flavor_id = data.huaweicloud_compute_flavors.test.ids[0] + security_group_ids = [huaweicloud_networking_secgroup.test.id] + availability_zone = data.huaweicloud_availability_zones.test.names[0] + admin_pass = "Test@123" + delete_disks_on_termination = true + + network { + uuid = huaweicloud_vpc_subnet.test.id + } + + eip_type = "5_bgp" + + bandwidth { + share_type = "PER" + size = 5 + charge_mode = "bandwidth" + } +} + +resource "huaweicloud_codearts_deploy_group" "test" { + count = 2 + + project_id = huaweicloud_codearts_project.test.id + name = "%[3]s-${count.index}" + os_type = "linux" + description = "test" +} + +resource "huaweicloud_codearts_deploy_host" "test" { + group_id = huaweicloud_codearts_deploy_group.test[0].id + ip_address = huaweicloud_compute_instance.test.public_ip + port = 22 + username = "root" + password = "Test@123" + os_type = "linux" + name = "%[3]s" + as_proxy = true +} +`, common.TestBaseComputeResources(name), testProject_basic(name), name) +} + +func testCodeArtsDeployHostsCopy_basic(name string) string { + return fmt.Sprintf(` +%[1]s + +resource "huaweicloud_codearts_deploy_hosts_copy" "test" { + source_group_id = huaweicloud_codearts_deploy_group.test[0].id + host_uuids = [huaweicloud_codearts_deploy_host.test.id] + target_group_id = huaweicloud_codearts_deploy_group.test[1].id +} +`, testCodeArtsDeployHostsCopy_base(name)) +} + +// Can not delete group when group having a host, delete host before destroy +func removeTheCopyHost(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // get group ID + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("resource (%s) not found", resourceName) + } + groupId := rs.Primary.ID + if groupId == "" { + return fmt.Errorf("attribute ID of Resource (%s) not found: %s", resourceName, rs) + } + + cfg := acceptance.TestAccProvider.Meta().(*config.Config) + client, err := cfg.NewServiceClient("codearts_deploy", acceptance.HW_REGION_NAME) + if err != nil { + return fmt.Errorf("error creating CodeArts Deploy client, err: %s", err) + } + + // get host ID from host list + gethttpUrl := "v1/resources/host-groups/{group_id}/hosts" + getPath := client.Endpoint + gethttpUrl + getPath = strings.ReplaceAll(getPath, "{group_id}", groupId) + getOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + } + + getResp, err := client.Request("GET", getPath, &getOpt) + if err != nil { + return fmt.Errorf("error retrieving CodeArts deploy hosts: %s", err) + } + getRespBody, err := utils.FlattenResponse(getResp) + if err != nil { + return err + } + + hostId := utils.PathSearch("result[0].uuid", getRespBody, "").(string) + if hostId == "" { + return fmt.Errorf("unable to find host ID from API response") + } + + // delete host + deletehttpUrl := "v1/resources/host-groups/{group_id}/hosts/{host_id}" + deletePath := client.Endpoint + deletehttpUrl + deletePath = strings.ReplaceAll(deletePath, "{group_id}", groupId) + deletePath = strings.ReplaceAll(deletePath, "{host_id}", hostId) + deleteOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + MoreHeaders: map[string]string{ + "Content-Type": "application/json;charset=utf-8", + }, + } + + _, err = client.Request("DELETE", deletePath, &deleteOpt) + if err != nil { + return fmt.Errorf("error deleting CodeArts deploy host: %s", err) + } + + return nil + } +} diff --git a/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_hosts_copy.go b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_hosts_copy.go new file mode 100644 index 0000000000..4e2919a0d6 --- /dev/null +++ b/huaweicloud/services/codeartsdeploy/resource_huaweicloud_codearts_deploy_hosts_copy.go @@ -0,0 +1,104 @@ +package codeartsdeploy + +import ( + "context" + "strings" + + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" +) + +// @API CodeArtsDeploy POST /v1/resources/host-groups/{group_id}/hosts/replication +func ResourceCodeArtsDeployHostsCopy() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceCodeArtsDeployHostsCopyCreate, + ReadContext: resourceCodeArtsDeployHostsCopyRead, + DeleteContext: resourceCodeArtsDeployHostsCopyDelete, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "source_group_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Specifies the source group ID.`, + }, + "host_uuids": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: `Specifies the host ID list.`, + }, + "target_group_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Specifies the target group ID.`, + }, + }, + } +} + +func resourceCodeArtsDeployHostsCopyCreate(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + cfg := meta.(*config.Config) + region := cfg.GetRegion(d) + client, err := cfg.NewServiceClient("codearts_deploy", region) + if err != nil { + return diag.Errorf("error creating CodeArts deploy client: %s", err) + } + + httpUrl := "v1/resources/host-groups/{group_id}/hosts/replication" + createPath := client.Endpoint + httpUrl + createPath = strings.ReplaceAll(createPath, "{group_id}", d.Get("source_group_id").(string)) + createOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + JSONBody: buildCreateCodeArtsDeployHostsCopyBodyParams(d), + } + + _, err = client.Request("POST", createPath, &createOpt) + if err != nil { + return diag.Errorf("error copying CodeArts deploy hosts: %s", err) + } + + id, err := uuid.GenerateUUID() + if err != nil { + return diag.Errorf("unable to generate ID: %s", err) + } + d.SetId(id) + + return nil +} + +func buildCreateCodeArtsDeployHostsCopyBodyParams(d *schema.ResourceData) map[string]interface{} { + bodyParams := map[string]interface{}{ + "host_uuids": d.Get("host_uuids"), + "target_group_id": d.Get("target_group_id"), + } + return bodyParams +} + +func resourceCodeArtsDeployHostsCopyRead(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + return nil +} + +func resourceCodeArtsDeployHostsCopyDelete(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics { + errorMsg := "Deleting hosts copy resource is not supported. The resource is only removed from the" + + "state, the hosts remain in the cloud." + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Warning, + Summary: errorMsg, + }, + } +}