diff --git a/examples/csbs-backup-with-ecs/main.tf b/examples/csbs-backup-with-ecs/main.tf new file mode 100644 index 0000000000..664ce23c36 --- /dev/null +++ b/examples/csbs-backup-with-ecs/main.tf @@ -0,0 +1,64 @@ +resource "huaweicloud_networking_network_v2" "terraform" { + name = "terraform" + admin_state_up = "true" +} + +resource "huaweicloud_compute_secgroup_v2" "terraform" { + name = "terraform" + description = "Security group for the Terraform example instances" + + rule { + from_port = 22 + to_port = 22 + ip_protocol = "tcp" + cidr = "0.0.0.0/0" + } + + rule { + from_port = 80 + to_port = 80 + ip_protocol = "tcp" + cidr = "0.0.0.0/0" + } + + rule { + from_port = -1 + to_port = -1 + ip_protocol = "icmp" + cidr = "0.0.0.0/0" + } +} + +resource "huaweicloud_compute_instance_v2" "terraform" { + name = "terraform" + image_name = "${var.image}" + flavor_name = "${var.flavor}" + availability_zone = "${var.availability_zone}" + security_groups = ["${huaweicloud_compute_secgroup_v2.terraform.name}"] + + network { + uuid = "${huaweicloud_networking_network_v2.terraform.id}" + } + +} +resource "huaweicloud_csbs_backup_v1" "backup_v1" { + backup_name = "${var.project}-backup" + resource_id = "${huaweicloud_compute_instance_v2.terraform.id}" + resource_type = "OS::Nova::Server" +} + +resource "huaweicloud_csbs_backup_policy_v1" "backup_policy_v1" { + name = "csbs-backup-policy" + resource { + id = "${huaweicloud_compute_instance_v2.terraform.id}" + type = "OS::Nova::Server" + name = "resource1" + } + scheduled_operation { + name ="mybackup" + enabled = true + operation_type ="backup" + max_backups = 2 + trigger_pattern = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nRRULE:FREQ=WEEKLY;BYDAY=TH;BYHOUR=12;BYMINUTE=27\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n" + } +} \ No newline at end of file diff --git a/examples/csbs-backup-with-ecs/variables.tf b/examples/csbs-backup-with-ecs/variables.tf new file mode 100644 index 0000000000..b2df794fba --- /dev/null +++ b/examples/csbs-backup-with-ecs/variables.tf @@ -0,0 +1,15 @@ +variable "project" { + default = "terraform" +} + +variable "image" { + default = "Ubuntu 14.04" +} + +variable "flavor" { + default = "m1.small" +} + +variable "availability_zone" { + default = "The first az of the az list" +} \ No newline at end of file diff --git a/huaweicloud/config.go b/huaweicloud/config.go index ff4c5d961d..bf82ad2753 100644 --- a/huaweicloud/config.go +++ b/huaweicloud/config.go @@ -446,6 +446,13 @@ func (c *Config) autoscalingV1Client(region string) (*golangsdk.ServiceClient, e }) } +func (c *Config) csbsV1Client(region string) (*golangsdk.ServiceClient, error) { + return huaweisdk.NewHwCSBSServiceV1(c.HwClient, golangsdk.EndpointOpts{ + Region: c.determineRegion(region), + Availability: c.getHwEndpointType(), + }) +} + func (c *Config) dmsV1Client(region string) (*golangsdk.ServiceClient, error) { return huaweisdk.NewDMSServiceV1(c.HwClient, golangsdk.EndpointOpts{ Region: c.determineRegion(region), diff --git a/huaweicloud/data_source_huaweicloud_csbs_backup_policy_v1.go b/huaweicloud/data_source_huaweicloud_csbs_backup_policy_v1.go new file mode 100644 index 0000000000..bbe1adce51 --- /dev/null +++ b/huaweicloud/data_source_huaweicloud_csbs_backup_policy_v1.go @@ -0,0 +1,179 @@ +package huaweicloud + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies" +) + +func dataSourceCSBSBackupPolicyV1() *schema.Resource { + return &schema.Resource{ + Read: dataSourceCSBSBackupPolicyV1Read, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "provider_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "common": &schema.Schema{ + Type: schema.TypeMap, + Computed: true, + }, + "resource": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "scheduled_operation": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + "max_backups": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + "retention_duration_days": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + "permanent": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + "trigger_pattern": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "operation_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "trigger_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "trigger_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "trigger_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceCSBSBackupPolicyV1Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + policyClient, err := config.csbsV1Client(GetRegion(d, config)) + + listOpts := policies.ListOpts{ + ID: d.Get("id").(string), + Name: d.Get("name").(string), + Status: d.Get("status").(string), + } + + refinedPolicies, err := policies.List(policyClient, listOpts) + + if err != nil { + return fmt.Errorf("Unable to retrieve backup policies: %s", err) + } + + if len(refinedPolicies) < 1 { + return fmt.Errorf("Your query returned no results. " + + "Please change your search criteria and try again.") + } + + if len(refinedPolicies) > 1 { + return fmt.Errorf("Your query returned more than one result." + + " Please try a more specific search criteria") + } + + backupPolicy := refinedPolicies[0] + + log.Printf("[INFO] Retrieved backup policy %s using given filter", backupPolicy.ID) + + d.SetId(backupPolicy.ID) + + if err := d.Set("resource", flattenCSBSPolicyResources(backupPolicy)); err != nil { + return err + } + + if err := d.Set("scheduled_operation", flattenCSBSScheduledOperations(backupPolicy)); err != nil { + return err + } + + d.Set("name", backupPolicy.Name) + d.Set("id", backupPolicy.ID) + d.Set("common", backupPolicy.Parameters.Common) + d.Set("status", backupPolicy.Status) + d.Set("description", backupPolicy.Description) + d.Set("provider_id", backupPolicy.ProviderId) + + d.Set("region", GetRegion(d, config)) + + return nil +} diff --git a/huaweicloud/data_source_huaweicloud_csbs_backup_policy_v1_test.go b/huaweicloud/data_source_huaweicloud_csbs_backup_policy_v1_test.go new file mode 100644 index 0000000000..a800cda23c --- /dev/null +++ b/huaweicloud/data_source_huaweicloud_csbs_backup_policy_v1_test.go @@ -0,0 +1,76 @@ +package huaweicloud + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccCSBSBackupPolicyV1DataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCSBSBackupPolicyV1DataSource_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckCSBSBackupPolicyV1DataSourceID("data.huaweicloud_csbs_backup_policy_v1.csbs_policy"), + resource.TestCheckResourceAttr("data.huaweicloud_csbs_backup_policy_v1.csbs_policy", "name", "backup-policy"), + resource.TestCheckResourceAttr("data.huaweicloud_csbs_backup_policy_v1.csbs_policy", "status", "suspended"), + ), + }, + }, + }) +} + +func testAccCheckCSBSBackupPolicyV1DataSourceID(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Can't find backup data source: %s ", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("backup data source ID not set ") + } + + return nil + } +} + +var testAccCSBSBackupPolicyV1DataSource_basic = fmt.Sprintf(` +resource "huaweicloud_compute_instance_v2" "instance_1" { + name = "instance_1" + image_id = "%s" + security_groups = ["default"] + availability_zone = "%s" + flavor_id = "%s" + metadata { + foo = "bar" + } + network { + uuid = "%s" + } +} +resource "huaweicloud_csbs_backup_policy_v1" "backup_policy_v1" { + name = "backup-policy" + resource { + id = "${huaweicloud_compute_instance_v2.instance_1.id}" + type = "OS::Nova::Server" + name = "resource4" + } + scheduled_operation { + name ="mybackup" + enabled = true + operation_type ="backup" + max_backups = "2" + trigger_pattern = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nRRULE:FREQ=WEEKLY;BYDAY=TH;BYHOUR=12;BYMINUTE=27\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n" + } +} + +data "huaweicloud_csbs_backup_policy_v1" "csbs_policy" { + id = "${huaweicloud_csbs_backup_policy_v1.backup_policy_v1.id}" +} +`, OS_IMAGE_ID, OS_AVAILABILITY_ZONE, OS_FLAVOR_ID, OS_NETWORK_ID) diff --git a/huaweicloud/data_source_huaweicloud_csbs_backup_v1.go b/huaweicloud/data_source_huaweicloud_csbs_backup_v1.go new file mode 100644 index 0000000000..e90cfcc74b --- /dev/null +++ b/huaweicloud/data_source_huaweicloud_csbs_backup_v1.go @@ -0,0 +1,236 @@ +package huaweicloud + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup" +) + +func dataSourceCSBSBackupV1() *schema.Resource { + return &schema.Resource{ + Read: dataSourceCSBSBackupV1Read, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "backup_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "resource_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "resource_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "backup_record_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "auto_trigger": &schema.Schema{ + Type: schema.TypeBool, + Computed: true, + }, + "average_speed": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + "size": &schema.Schema{ + Type: schema.TypeInt, + Computed: true, + }, + "vm_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "policy_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "volume_backups": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Computed: true, + }, + "space_saving_ratio": { + Type: schema.TypeInt, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "bootable": { + Type: schema.TypeBool, + Computed: true, + }, + "average_speed": { + Type: schema.TypeInt, + Computed: true, + }, + "source_volume_size": { + Type: schema.TypeInt, + Computed: true, + }, + "source_volume_id": { + Type: schema.TypeString, + Computed: true, + }, + "incremental": { + Type: schema.TypeBool, + Computed: true, + }, + "snapshot_id": { + Type: schema.TypeString, + Computed: true, + }, + "source_volume_name": { + Type: schema.TypeString, + Computed: true, + }, + "image_type": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "size": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "vm_metadata": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "eip": { + Type: schema.TypeString, + Computed: true, + }, + "cloud_service_type": { + Type: schema.TypeString, + Computed: true, + }, + "ram": { + Type: schema.TypeInt, + Computed: true, + }, + "vcpus": { + Type: schema.TypeInt, + Computed: true, + }, + "private_ip": { + Type: schema.TypeString, + Computed: true, + }, + "disk": { + Type: schema.TypeInt, + Computed: true, + }, + "image_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceCSBSBackupV1Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + backupClient, err := config.csbsV1Client(GetRegion(d, config)) + + listOpts := backup.ListOpts{ + ID: d.Get("id").(string), + Name: d.Get("backup_name").(string), + Status: d.Get("status").(string), + ResourceName: d.Get("resource_name").(string), + CheckpointId: d.Get("backup_record_id").(string), + ResourceType: d.Get("resource_type").(string), + ResourceId: d.Get("resource_id").(string), + PolicyId: d.Get("policy_id").(string), + VmIp: d.Get("vm_ip").(string), + } + + refinedbackups, err := backup.List(backupClient, listOpts) + if err != nil { + return fmt.Errorf("Unable to retrieve backup: %s", err) + } + + if len(refinedbackups) < 1 { + return fmt.Errorf("Your query returned no results. " + + "Please change your search criteria and try again.") + } + + if len(refinedbackups) > 1 { + return fmt.Errorf("Your query returned more than one result." + + " Please try a more specific search criteria") + } + + backupObject := refinedbackups[0] + log.Printf("[INFO] Retrieved backup %s using given filter", backupObject.Id) + + d.SetId(backupObject.Id) + + d.Set("backup_record_id", backupObject.CheckpointId) + d.Set("backup_name", backupObject.Name) + d.Set("resource_id", backupObject.ResourceId) + d.Set("status", backupObject.Status) + d.Set("description", backupObject.Description) + d.Set("resource_type", backupObject.ResourceType) + d.Set("auto_trigger", backupObject.ExtendInfo.AutoTrigger) + d.Set("average_speed", backupObject.ExtendInfo.AverageSpeed) + d.Set("resource_name", backupObject.ExtendInfo.ResourceName) + d.Set("size", backupObject.ExtendInfo.Size) + d.Set("volume_backups", flattenCSBSVolumeBackups(&backupObject)) + d.Set("vm_metadata", flattenCSBSVMMetadata(&backupObject)) + + d.Set("region", GetRegion(d, config)) + + return nil +} diff --git a/huaweicloud/data_source_huaweicloud_csbs_backup_v1_test.go b/huaweicloud/data_source_huaweicloud_csbs_backup_v1_test.go new file mode 100644 index 0000000000..a69298575d --- /dev/null +++ b/huaweicloud/data_source_huaweicloud_csbs_backup_v1_test.go @@ -0,0 +1,66 @@ +package huaweicloud + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccCSBSBackupV1DataSource_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCSBSBackupV1DataSource_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckCSBSBackupV1DataSourceID("data.huaweicloud_csbs_backup_v1.csbs"), + resource.TestCheckResourceAttr("data.huaweicloud_csbs_backup_v1.csbs", "backup_name", "csbs-test"), + resource.TestCheckResourceAttr("data.huaweicloud_csbs_backup_v1.csbs", "resource_name", "instance_1"), + ), + }, + }, + }) +} + +func testAccCheckCSBSBackupV1DataSourceID(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Can't find backup data source: %s ", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("backup data source ID not set ") + } + + return nil + } +} + +var testAccCSBSBackupV1DataSource_basic = fmt.Sprintf(` +resource "huaweicloud_compute_instance_v2" "instance_1" { + name = "instance_1" + image_id = "%s" + security_groups = ["default"] + availability_zone = "%s" + flavor_id = "%s" + metadata { + foo = "bar" + } + network { + uuid = "%s" + } +} +resource "huaweicloud_csbs_backup_v1" "csbs" { + backup_name = "csbs-test" + description = "test-code" + resource_id = "${huaweicloud_compute_instance_v2.instance_1.id}" + resource_type = "OS::Nova::Server" +} +data "huaweicloud_csbs_backup_v1" "csbs" { + id = "${huaweicloud_csbs_backup_v1.csbs.id}" +} +`, OS_IMAGE_ID, OS_AVAILABILITY_ZONE, OS_FLAVOR_ID, OS_NETWORK_ID) diff --git a/huaweicloud/import_huaweicloud_csbs_backup_policy_v1_test.go b/huaweicloud/import_huaweicloud_csbs_backup_policy_v1_test.go new file mode 100644 index 0000000000..66a0a8c5ee --- /dev/null +++ b/huaweicloud/import_huaweicloud_csbs_backup_policy_v1_test.go @@ -0,0 +1,28 @@ +package huaweicloud + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccCSBSBackupPolicyV1_importBasic(t *testing.T) { + resourceName := "huaweicloud_csbs_backup_policy_v1.backup_policy_v1" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCSBSBackupPolicyV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCSBSBackupPolicyV1_basic, + }, + + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/huaweicloud/import_huaweicloud_csbs_backup_v1_test.go b/huaweicloud/import_huaweicloud_csbs_backup_v1_test.go new file mode 100644 index 0000000000..2c80ad21fd --- /dev/null +++ b/huaweicloud/import_huaweicloud_csbs_backup_v1_test.go @@ -0,0 +1,28 @@ +package huaweicloud + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccCSBSBackupV1_importBasic(t *testing.T) { + resourceName := "huaweicloud_csbs_backup_v1.csbs" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCSBSBackupV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCSBSBackupV1_basic, + }, + + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: false, + }, + }, + }) +} diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index 242669a081..653604a780 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -211,6 +211,8 @@ func Provider() terraform.ResourceProvider { "huaweicloud_cce_cluster_v3": dataSourceCCEClusterV3(), "huaweicloud_cce_node_v3": dataSourceCceNodesV3(), "huaweicloud_rts_software_config_v1": dataSourceRtsSoftwareConfigV1(), + "huaweicloud_csbs_backup_v1": dataSourceCSBSBackupV1(), + "huaweicloud_csbs_backup_policy_v1": dataSourceCSBSBackupPolicyV1(), "huaweicloud_dms_az_v1": dataSourceDmsAZV1(), "huaweicloud_dms_product_v1": dataSourceDmsProductV1(), "huaweicloud_dms_maintainwindow_v1": dataSourceDmsMaintainWindowV1(), @@ -280,6 +282,8 @@ func Provider() terraform.ResourceProvider { "huaweicloud_as_configuration_v1": resourceASConfiguration(), "huaweicloud_as_group_v1": resourceASGroup(), "huaweicloud_as_policy_v1": resourceASPolicy(), + "huaweicloud_csbs_backup_v1": resourceCSBSBackupV1(), + "huaweicloud_csbs_backup_policy_v1": resourceCSBSBackupPolicyV1(), "huaweicloud_vbs_backup_policy_v2": resourceVBSBackupPolicyV2(), "huaweicloud_vbs_backup_v2": resourceVBSBackupV2(), "huaweicloud_cts_tracker_v1": resourceCTSTrackerV1(), diff --git a/huaweicloud/resource_huaweicloud_csbs_backup_policy_v1.go b/huaweicloud/resource_huaweicloud_csbs_backup_policy_v1.go new file mode 100644 index 0000000000..ea8ce77bd9 --- /dev/null +++ b/huaweicloud/resource_huaweicloud_csbs_backup_policy_v1.go @@ -0,0 +1,444 @@ +package huaweicloud + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies" +) + +func resourceCSBSBackupPolicyV1() *schema.Resource { + return &schema.Resource{ + Create: resourceCSBSBackupPolicyCreate, + Read: resourceCSBSBackupPolicyRead, + Update: resourceCSBSBackupPolicyUpdate, + Delete: resourceCSBSBackupPolicyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "provider_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "fc4d5750-22e7-4798-8a46-f48f62c4c1da", + ForceNew: true, + }, + "common": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + }, + "scheduled_operation": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "max_backups": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "retention_duration_days": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "permanent": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "trigger_pattern": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "operation_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "trigger_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "trigger_name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "trigger_type": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "resource": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + ForceNew: false, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + } + +} + +func resourceCSBSBackupPolicyCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + policyClient, err := config.csbsV1Client(GetRegion(d, config)) + + if err != nil { + return fmt.Errorf("Error creating backup policy Client: %s", err) + } + + createOpts := policies.CreateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + ProviderId: d.Get("provider_id").(string), + Parameters: policies.PolicyParam{ + Common: resourceCSBSCommonParamsV1(d), + }, + ScheduledOperations: resourceCSBSScheduleV1(d), + + Resources: resourceCSBSResourceV1(d), + } + + backupPolicy, err := policies.Create(policyClient, createOpts).Extract() + + if err != nil { + return fmt.Errorf("Error creating Backup Policy : %s", err) + } + + d.SetId(backupPolicy.ID) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"creating"}, + Target: []string{"suspended"}, + Refresh: waitForCSBSBackupPolicyActive(policyClient, backupPolicy.ID), + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 5 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, StateErr := stateConf.WaitForState() + if StateErr != nil { + return fmt.Errorf("Error waiting for Backup Policy (%s) to become available: %s", backupPolicy.ID, StateErr) + } + + return resourceCSBSBackupPolicyRead(d, meta) + +} + +func resourceCSBSBackupPolicyRead(d *schema.ResourceData, meta interface{}) error { + + config := meta.(*Config) + policyClient, err := config.csbsV1Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + + backupPolicy, err := policies.Get(policyClient, d.Id()).Extract() + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + log.Printf("[WARN] Removing backup policy %s as it's already gone", d.Id()) + d.SetId("") + return nil + } + + return fmt.Errorf("Error retrieving backup policy: %s", err) + } + + if err := d.Set("resource", flattenCSBSPolicyResources(*backupPolicy)); err != nil { + return err + } + + if err := d.Set("scheduled_operation", flattenCSBSScheduledOperations(*backupPolicy)); err != nil { + return err + } + + d.Set("name", backupPolicy.Name) + d.Set("common", backupPolicy.Parameters.Common) + d.Set("status", backupPolicy.Status) + d.Set("description", backupPolicy.Description) + d.Set("provider_id", backupPolicy.ProviderId) + + d.Set("region", GetRegion(d, config)) + + return nil +} + +func resourceCSBSBackupPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + policyClient, err := config.csbsV1Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + var updateOpts policies.UpdateOpts + if d.HasChange("name") { + updateOpts.Name = d.Get("name").(string) + } + if d.HasChange("description") { + updateOpts.Description = d.Get("description").(string) + } + + updateOpts.Parameters.Common = resourceCSBSCommonParamsV1(d) + + if d.HasChange("resource") { + updateOpts.Resources = resourceCSBSResourceV1(d) + } + if d.HasChange("scheduled_operation") { + updateOpts.ScheduledOperations = resourceCSBScheduleUpdateV1(d) + } + + _, err = policies.Update(policyClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating Backup Policy: %s", err) + } + + return resourceCSBSBackupPolicyRead(d, meta) +} + +func resourceCSBSBackupPolicyDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + policyClient, err := config.csbsV1Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"available"}, + Target: []string{"deleted"}, + Refresh: waitForVBSPolicyDelete(policyClient, d.Id()), + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 5 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("Error deleting Backup Policy: %s", err) + } + + d.SetId("") + return nil +} + +func waitForCSBSBackupPolicyActive(policyClient *golangsdk.ServiceClient, policyID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + n, err := policies.Get(policyClient, policyID).Extract() + if err != nil { + return nil, "", err + } + + if n.Status == "error" { + return n, n.Status, nil + } + return n, n.Status, nil + } +} + +func waitForVBSPolicyDelete(policyClient *golangsdk.ServiceClient, policyID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + r, err := policies.Get(policyClient, policyID).Extract() + + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + log.Printf("[INFO] Successfully deleted Backup Policy %s", policyID) + return r, "deleted", nil + } + return r, "available", err + } + + policy := policies.Delete(policyClient, policyID) + err = policy.Err + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + log.Printf("[INFO] Successfully deleted Backup Policy %s", policyID) + return r, "deleted", nil + } + if errCode, ok := err.(golangsdk.ErrUnexpectedResponseCode); ok { + if errCode.Actual == 409 { + return r, "available", nil + } + } + return r, "available", err + } + + return r, "deleted", nil + } +} + +func resourceCSBSScheduleV1(d *schema.ResourceData) []policies.ScheduledOperation { + scheduledOperations := d.Get("scheduled_operation").(*schema.Set).List() + so := make([]policies.ScheduledOperation, len(scheduledOperations)) + for i, raw := range scheduledOperations { + rawMap := raw.(map[string]interface{}) + so[i] = policies.ScheduledOperation{ + Name: rawMap["name"].(string), + Description: rawMap["description"].(string), + Enabled: rawMap["enabled"].(bool), + OperationType: rawMap["operation_type"].(string), + Trigger: policies.Trigger{ + Properties: policies.TriggerProperties{ + Pattern: rawMap["trigger_pattern"].(string), + }, + }, + OperationDefinition: policies.OperationDefinition{ + MaxBackups: rawMap["max_backups"].(int), + RetentionDurationDays: rawMap["retention_duration_days"].(int), + Permanent: rawMap["permanent"].(bool), + }, + } + } + + return so +} + +func resourceCSBSResourceV1(d *schema.ResourceData) []policies.Resource { + resources := d.Get("resource").(*schema.Set).List() + res := make([]policies.Resource, len(resources)) + for i, raw := range resources { + rawMap := raw.(map[string]interface{}) + res[i] = policies.Resource{ + Name: rawMap["name"].(string), + Id: rawMap["id"].(string), + Type: rawMap["type"].(string), + } + } + return res +} + +func resourceCSBScheduleUpdateV1(d *schema.ResourceData) []policies.ScheduledOperationToUpdate { + + oldSORaw, newSORaw := d.GetChange("scheduled_operation") + oldSOList := oldSORaw.(*schema.Set).List() + newSOSetList := newSORaw.(*schema.Set).List() + + schedule := make([]policies.ScheduledOperationToUpdate, len(newSOSetList)) + for i, raw := range newSOSetList { + rawNewMap := raw.(map[string]interface{}) + rawOldMap := oldSOList[i].(map[string]interface{}) + schedule[i] = policies.ScheduledOperationToUpdate{ + Id: rawOldMap["id"].(string), + Name: rawNewMap["name"].(string), + Description: rawNewMap["description"].(string), + Enabled: rawNewMap["enabled"].(bool), + Trigger: policies.Trigger{ + Properties: policies.TriggerProperties{ + Pattern: rawNewMap["trigger_pattern"].(string), + }, + }, + OperationDefinition: policies.OperationDefinition{ + MaxBackups: rawNewMap["max_backups"].(int), + RetentionDurationDays: rawNewMap["retention_duration_days"].(int), + Permanent: rawNewMap["permanent"].(bool), + }, + } + } + + return schedule +} + +func resourceCSBSCommonParamsV1(d *schema.ResourceData) map[string]string { + m := make(map[string]string) + for key, val := range d.Get("common").(map[string]interface{}) { + m[key] = val.(string) + } + return m +} + +func flattenCSBSScheduledOperations(backupPolicy policies.BackupPolicy) []map[string]interface{} { + var scheduledOperationList []map[string]interface{} + for _, schedule := range backupPolicy.ScheduledOperations { + mapping := map[string]interface{}{ + "enabled": schedule.Enabled, + "trigger_id": schedule.TriggerID, + "name": schedule.Name, + "description": schedule.Description, + "operation_type": schedule.OperationType, + "max_backups": schedule.OperationDefinition.MaxBackups, + "retention_duration_days": schedule.OperationDefinition.RetentionDurationDays, + "permanent": schedule.OperationDefinition.Permanent, + "trigger_name": schedule.Trigger.Name, + "trigger_type": schedule.Trigger.Type, + "trigger_pattern": schedule.Trigger.Properties.Pattern, + "id": schedule.ID, + } + scheduledOperationList = append(scheduledOperationList, mapping) + } + + return scheduledOperationList +} + +func flattenCSBSPolicyResources(backupPolicy policies.BackupPolicy) []map[string]interface{} { + var resourceList []map[string]interface{} + for _, resources := range backupPolicy.Resources { + mapping := map[string]interface{}{ + "id": resources.Id, + "type": resources.Type, + "name": resources.Name, + } + resourceList = append(resourceList, mapping) + } + + return resourceList +} diff --git a/huaweicloud/resource_huaweicloud_csbs_backup_policy_v1_test.go b/huaweicloud/resource_huaweicloud_csbs_backup_policy_v1_test.go new file mode 100644 index 0000000000..c0427ff1d4 --- /dev/null +++ b/huaweicloud/resource_huaweicloud_csbs_backup_policy_v1_test.go @@ -0,0 +1,209 @@ +package huaweicloud + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies" +) + +func TestAccCSBSBackupPolicyV1_basic(t *testing.T) { + var policy policies.BackupPolicy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCSBSBackupPolicyV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCSBSBackupPolicyV1_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckCSBSBackupPolicyV1Exists("huaweicloud_csbs_backup_policy_v1.backup_policy_v1", &policy), + resource.TestCheckResourceAttr( + "huaweicloud_csbs_backup_policy_v1.backup_policy_v1", "name", "backup-policy"), + resource.TestCheckResourceAttr( + "huaweicloud_csbs_backup_policy_v1.backup_policy_v1", "status", "suspended"), + ), + }, + resource.TestStep{ + Config: testAccCSBSBackupPolicyV1_update, + Check: resource.ComposeTestCheckFunc( + testAccCheckCSBSBackupPolicyV1Exists("huaweicloud_csbs_backup_policy_v1.backup_policy_v1", &policy), + resource.TestCheckResourceAttr( + "huaweicloud_csbs_backup_policy_v1.backup_policy_v1", "name", "backup-policy-update"), + ), + }, + }, + }) +} + +func TestAccCSBSBackupPolicyV1_timeout(t *testing.T) { + var policy policies.BackupPolicy + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCSBSBackupPolicyV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCSBSBackupPolicyV1_timeout, + Check: resource.ComposeTestCheckFunc( + testAccCheckCSBSBackupPolicyV1Exists("huaweicloud_csbs_backup_policy_v1.backup_policy_v1", &policy), + ), + }, + }, + }) +} + +func testAccCheckCSBSBackupPolicyV1Destroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + policyClient, err := config.csbsV1Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "huaweicloud_csbs_backup_policy_v1" { + continue + } + + _, err := policies.Get(policyClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("backup policy still exists") + } + } + + return nil +} + +func testAccCheckCSBSBackupPolicyV1Exists(n string, policy *policies.BackupPolicy) 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) + policyClient, err := config.csbsV1Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + + found, err := policies.Get(policyClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("backup policy not found") + } + + *policy = *found + + return nil + } +} + +var testAccCSBSBackupPolicyV1_basic = fmt.Sprintf(` +resource "huaweicloud_compute_instance_v2" "instance_1" { + name = "instance_1" + image_id = "%s" + security_groups = ["default"] + availability_zone = "%s" + flavor_id = "%s" + metadata { + foo = "bar" + } + network { + uuid = "%s" + } +} +resource "huaweicloud_csbs_backup_policy_v1" "backup_policy_v1" { + name = "backup-policy" + resource { + id = "${huaweicloud_compute_instance_v2.instance_1.id}" + type = "OS::Nova::Server" + name = "resource4" + } + scheduled_operation { + name ="mybackup" + enabled = true + operation_type ="backup" + max_backups = "2" + trigger_pattern = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nRRULE:FREQ=WEEKLY;BYDAY=TH;BYHOUR=12;BYMINUTE=27\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n" + } +} +`, OS_IMAGE_ID, OS_AVAILABILITY_ZONE, OS_FLAVOR_ID, OS_NETWORK_ID) + +var testAccCSBSBackupPolicyV1_update = fmt.Sprintf(` +resource "huaweicloud_compute_instance_v2" "instance_1" { + name = "instance_1" + image_id = "%s" + security_groups = ["default"] + availability_zone = "%s" + flavor_id = "%s" + metadata { + foo = "bar" + } + network { + uuid = "%s" + } +} +resource "huaweicloud_csbs_backup_policy_v1" "backup_policy_v1" { + name = "backup-policy-update" + resource { + id = "${huaweicloud_compute_instance_v2.instance_1.id}" + type = "OS::Nova::Server" + name = "resource4" + } + scheduled_operation { + name ="mybackup" + enabled = true + operation_type ="backup" + max_backups = "2" + trigger_pattern = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nRRULE:FREQ=WEEKLY;BYDAY=TH;BYHOUR=12;BYMINUTE=27\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n" + } +} +`, OS_IMAGE_ID, OS_AVAILABILITY_ZONE, OS_FLAVOR_ID, OS_NETWORK_ID) + +var testAccCSBSBackupPolicyV1_timeout = fmt.Sprintf(` +resource "huaweicloud_compute_instance_v2" "instance_1" { + name = "instance_1" + image_id = "%s" + security_groups = ["default"] + availability_zone = "%s" + flavor_id = "%s" + metadata { + foo = "bar" + } + network { + uuid = "%s" + } +} +resource "huaweicloud_csbs_backup_policy_v1" "backup_policy_v1" { + name = "backup-policy" + resource { + id = "${huaweicloud_compute_instance_v2.instance_1.id}" + type = "OS::Nova::Server" + name = "resource4" + } + scheduled_operation { + name ="mybackup" + enabled = true + operation_type ="backup" + max_backups = "2" + trigger_pattern = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nRRULE:FREQ=WEEKLY;BYDAY=TH;BYHOUR=12;BYMINUTE=27\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n" + } + + timeouts { + create = "5m" + delete = "5m" + } +} +`, OS_IMAGE_ID, OS_AVAILABILITY_ZONE, OS_FLAVOR_ID, OS_NETWORK_ID) diff --git a/huaweicloud/resource_huaweicloud_csbs_backup_v1.go b/huaweicloud/resource_huaweicloud_csbs_backup_v1.go new file mode 100644 index 0000000000..7fa4de9973 --- /dev/null +++ b/huaweicloud/resource_huaweicloud_csbs_backup_v1.go @@ -0,0 +1,403 @@ +package huaweicloud + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup" +) + +func resourceCSBSBackupV1() *schema.Resource { + return &schema.Resource{ + Create: resourceCSBSBackupV1Create, + Read: resourceCSBSBackupV1Read, + Delete: resourceCSBSBackupV1Delete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + }, + "backup_record_id": { + Type: schema.TypeString, + Computed: true, + }, + "resource_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "backup_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + }, + "resource_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Default: "OS::Nova::Server", + ForceNew: true, + }, + "status": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "volume_backups": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "status": { + Type: schema.TypeString, + Computed: true, + }, + "space_saving_ratio": { + Type: schema.TypeInt, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "bootable": { + Type: schema.TypeBool, + Computed: true, + }, + "average_speed": { + Type: schema.TypeInt, + Computed: true, + }, + "source_volume_size": { + Type: schema.TypeInt, + Computed: true, + }, + "source_volume_id": { + Type: schema.TypeString, + Computed: true, + }, + "incremental": { + Type: schema.TypeBool, + Computed: true, + }, + "snapshot_id": { + Type: schema.TypeString, + Computed: true, + }, + "source_volume_name": { + Type: schema.TypeString, + Computed: true, + }, + "image_type": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "size": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + "vm_metadata": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "eip": { + Type: schema.TypeString, + Computed: true, + }, + "cloud_service_type": { + Type: schema.TypeString, + Computed: true, + }, + "ram": { + Type: schema.TypeInt, + Computed: true, + }, + "vcpus": { + Type: schema.TypeInt, + Computed: true, + }, + "private_ip": { + Type: schema.TypeString, + Computed: true, + }, + "disk": { + Type: schema.TypeInt, + Computed: true, + }, + "image_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func resourceCSBSBackupV1Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + backupClient, err := config.csbsV1Client(GetRegion(d, config)) + + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + + resourceID := d.Get("resource_id").(string) + resourceType := d.Get("resource_type").(string) + + queryOpts := backup.ResourceBackupCapOpts{ + CheckProtectable: []backup.ResourceCapQueryParams{ + { + ResourceId: resourceID, + ResourceType: resourceType, + }, + }, + } + + query, err := backup.QueryResourceBackupCapability(backupClient, queryOpts).ExtractQueryResponse() + if err != nil { + return fmt.Errorf("Error querying resource backup capability: %s", err) + } + + if query[0].Result { + + createOpts := backup.CreateOpts{ + BackupName: d.Get("backup_name").(string), + Description: d.Get("description").(string), + ResourceType: resourceType, + } + + checkpoint, err := backup.Create(backupClient, resourceID, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating backup: %s", err) + } + + backupOpts := backup.ListOpts{CheckpointId: checkpoint.Id} + backupItems, err := backup.List(backupClient, backupOpts) + + if err != nil { + return fmt.Errorf("Error listing Backup: %s", err) + } + + if len(backupItems) == 0 { + return fmt.Errorf("Not able to find created Backup: %s", err) + } + + backupObject := backupItems[0] + + d.SetId(backupObject.Id) + + log.Printf("[INFO] Resource Backup %s created successfully", backupObject.Id) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"protecting"}, + Target: []string{"available"}, + Refresh: waitForCSBSBackupActive(backupClient, d.Id()), + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 3 * time.Minute, + MinTimeout: 3 * time.Minute, + } + _, stateErr := stateConf.WaitForState() + if stateErr != nil { + return fmt.Errorf( + "Error waiting for Backup (%s) to become available: %s", + backupObject.Id, stateErr) + } + + } else { + return fmt.Errorf("Error code: %s\n Error msg: %s", query[0].ErrorCode, query[0].ErrorMsg) + } + + return resourceCSBSBackupV1Read(d, meta) + +} + +func resourceCSBSBackupV1Read(d *schema.ResourceData, meta interface{}) error { + + config := meta.(*Config) + backupClient, err := config.csbsV1Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + + backupObject, err := backup.Get(backupClient, d.Id()).ExtractBackup() + + if err != nil { + + if _, ok := err.(golangsdk.ErrDefault404); ok { + log.Printf("[WARN] Removing backup %s as it's already gone", d.Id()) + d.SetId("") + return nil + } + + return fmt.Errorf("Error retrieving backup: %s", err) + + } + + d.Set("resource_id", backupObject.ResourceId) + d.Set("backup_name", backupObject.Name) + d.Set("description", backupObject.Description) + d.Set("resource_type", backupObject.ResourceType) + d.Set("status", backupObject.Status) + d.Set("volume_backups", flattenCSBSVolumeBackups(backupObject)) + d.Set("vm_metadata", flattenCSBSVMMetadata(backupObject)) + d.Set("backup_record_id", backupObject.CheckpointId) + + d.Set("region", GetRegion(d, config)) + + return nil +} + +func resourceCSBSBackupV1Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + backupClient, err := config.csbsV1Client(GetRegion(d, config)) + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"available", "deleting"}, + Target: []string{"deleted"}, + Refresh: waitForCSBSBackupDelete(backupClient, d.Id(), d.Get("backup_record_id").(string)), + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 5 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("Error deleting csbs backup: %s", err) + } + + d.SetId("") + return nil +} + +func waitForCSBSBackupActive(backupClient *golangsdk.ServiceClient, backupId string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + n, err := backup.Get(backupClient, backupId).ExtractBackup() + if err != nil { + return nil, "", err + } + + if n.Id == "error" { + return nil, "", fmt.Errorf("Backup status: %s", n.Status) + } + + return n, n.Status, nil + } +} + +func waitForCSBSBackupDelete(backupClient *golangsdk.ServiceClient, backupId string, backupRecordID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + r, err := backup.Get(backupClient, backupId).ExtractBackup() + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + log.Printf("[INFO] Successfully deleted csbs backup %s", backupId) + return r, "deleted", nil + } + return r, "deleting", err + } + + err = backup.Delete(backupClient, backupRecordID).Err + + if err != nil { + + if _, ok := err.(golangsdk.ErrDefault404); ok { + log.Printf("[INFO] Successfully deleted Backup %s", backupId) + return r, "deleted", nil + } + if errCode, ok := err.(golangsdk.ErrUnexpectedResponseCode); ok { + if errCode.Actual == 409 { + return r, "deleting", nil + } + } + if _, ok := err.(golangsdk.ErrDefault400); ok { + return r, "deleting", nil + } + + return r, "deleting", err + } + + return r, r.Status, nil + } +} + +func flattenCSBSVolumeBackups(backupObject *backup.Backup) []map[string]interface{} { + var volumeBackups []map[string]interface{} + + for _, volume := range backupObject.ExtendInfo.VolumeBackups { + mapping := map[string]interface{}{ + "status": volume.Status, + "space_saving_ratio": volume.SpaceSavingRatio, + "name": volume.Name, + "bootable": volume.Bootable, + "average_speed": volume.AverageSpeed, + "source_volume_size": volume.SourceVolumeSize, + "source_volume_id": volume.SourceVolumeId, + "snapshot_id": volume.SnapshotID, + "incremental": volume.Incremental, + "source_volume_name": volume.SourceVolumeName, + "image_type": volume.ImageType, + "id": volume.Id, + "size": volume.Size, + } + volumeBackups = append(volumeBackups, mapping) + } + + return volumeBackups +} + +func flattenCSBSVMMetadata(backupObject *backup.Backup) []map[string]interface{} { + var vmMetadata []map[string]interface{} + + mapping := map[string]interface{}{ + "name": backupObject.ExtendInfo.ResourceName, + "eip": backupObject.VMMetadata.Eip, + "cloud_service_type": backupObject.VMMetadata.CloudServiceType, + "ram": backupObject.VMMetadata.Ram, + "vcpus": backupObject.VMMetadata.Vcpus, + "private_ip": backupObject.VMMetadata.PrivateIp, + "disk": backupObject.VMMetadata.Disk, + "image_type": backupObject.VMMetadata.ImageType, + } + + vmMetadata = append(vmMetadata, mapping) + + return vmMetadata + +} diff --git a/huaweicloud/resource_huaweicloud_csbs_backup_v1_test.go b/huaweicloud/resource_huaweicloud_csbs_backup_v1_test.go new file mode 100644 index 0000000000..41d8e7afbb --- /dev/null +++ b/huaweicloud/resource_huaweicloud_csbs_backup_v1_test.go @@ -0,0 +1,149 @@ +package huaweicloud + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "testing" + + "github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup" +) + +func TestAccCSBSBackupV1_basic(t *testing.T) { + var backups backup.Backup + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCSBSBackupV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCSBSBackupV1_basic, + Check: resource.ComposeTestCheckFunc( + testAccCSBSBackupV1Exists("huaweicloud_csbs_backup_v1.csbs", &backups), + resource.TestCheckResourceAttr( + "huaweicloud_csbs_backup_v1.csbs", "backup_name", "csbs-test1"), + resource.TestCheckResourceAttr( + "huaweicloud_csbs_backup_v1.csbs", "resource_type", "OS::Nova::Server"), + ), + }, + }, + }) +} + +func TestAccCSBSBackupV1_timeout(t *testing.T) { + var backups backup.Backup + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCSBSBackupV1Destroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCSBSBackupV1_timeout, + Check: resource.ComposeTestCheckFunc( + testAccCSBSBackupV1Exists("huaweicloud_csbs_backup_v1.csbs", &backups), + ), + }, + }, + }) +} + +func testAccCSBSBackupV1Destroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + backupClient, err := config.csbsV1Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "huaweicloud_csbs_backup_v1" { + continue + } + + _, err := backup.Get(backupClient, rs.Primary.ID).ExtractBackup() + if err == nil { + return fmt.Errorf("Backup still exists") + } + } + + return nil +} + +func testAccCSBSBackupV1Exists(n string, backups *backup.Backup) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Backup not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + config := testAccProvider.Meta().(*Config) + backupClient, err := config.csbsV1Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating csbs client: %s", err) + } + + found, err := backup.Get(backupClient, rs.Primary.ID).ExtractBackup() + if err != nil { + return err + } + + if found.Id != rs.Primary.ID { + return fmt.Errorf("backup not found") + } + + *backups = *found + + return nil + } +} + +var testAccCSBSBackupV1_basic = fmt.Sprintf(` +resource "huaweicloud_compute_instance_v2" "instance_1" { + name = "instance_1" + image_id = "%s" + security_groups = ["default"] + availability_zone = "%s" + flavor_id = "%s" + metadata { + foo = "bar" + } + network { + uuid = "%s" + } +} +resource "huaweicloud_csbs_backup_v1" "csbs" { + backup_name = "csbs-test1" + description = "test-code" + resource_id = "${huaweicloud_compute_instance_v2.instance_1.id}" + resource_type = "OS::Nova::Server" +} +`, OS_IMAGE_ID, OS_AVAILABILITY_ZONE, OS_FLAVOR_ID, OS_NETWORK_ID) + +var testAccCSBSBackupV1_timeout = fmt.Sprintf(` +resource "huaweicloud_compute_instance_v2" "instance_1" { + name = "instance_1" + image_id = "%s" + security_groups = ["default"] + availability_zone = "%s" + flavor_id = "%s" + metadata { + foo = "bar" + } + network { + uuid = "%s" + } +} +resource "huaweicloud_csbs_backup_v1" "csbs" { + backup_name = "csbs-test1" + description = "test-code" + resource_id = "${huaweicloud_compute_instance_v2.instance_1.id}" + resource_type = "OS::Nova::Server" +} +`, OS_IMAGE_ID, OS_AVAILABILITY_ZONE, OS_FLAVOR_ID, OS_NETWORK_ID) diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/doc.go b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/doc.go new file mode 100644 index 0000000000..103e809b2e --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/doc.go @@ -0,0 +1,44 @@ +/* +Package backup enables management and retrieval of +back up resources. + +Example to List Backup + listbackup := backup.ListOpts{ID: "7b99acfd-18c3-4f26-9d39-b4ebd2ea3e12"} + allbackups, err := backup.List(client,listbackup) + if err != nil { + panic(err) + } + fmt.Println(allbackups) + + + +Example to Create a Backup + createBackup:=backup.CreateOpts{BackupName: "c2c-backup", Description: "mybackup"} + out,err:=backup.Create(client,"fc4d5750-22e7-4798-8a46-f48f62c4c1da", "f8ddc472-cf00-4384-851e-5f2a68c33762", + createBackup).Extract() + fmt.Println(out) + fmt.Println(err) + +Example to Query if resources can be backed up + createQuery:=backup.ResourceBackupCapOpts{CheckProtectable:[]backup.ResourceCapQueryParams{{ResourceId: "069e678a-f1d1-4a38-880b-459bde82fcc6", + ResourceType: "OS::Nova::Server"}}} + out,err:=backup.QueryResourceBackupCapability(client,"fc4d5750-22e7-4798-8a46-f48f62c4c1da", + createQuery).ExtractQueryResponse() + fmt.Println(out) + fmt.Println(err) + + +Example to Delete a Backup + out:=backup.Delete(client,"fc4d5750-22e7-4798-8a46-f48f62c4c1da") + fmt.Println(out) + if err != nil { + panic(err) + } + +Example to Get Backup + result:=backup.Get(client,"7b99acfd-18c3-4f26-9d39-b4ebd2ea3e12") + out,err:=result.ExtractBackup() + fmt.Println(out) + +*/ +package backup diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/requests.go b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/requests.go new file mode 100644 index 0000000000..da74e9a187 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/requests.go @@ -0,0 +1,164 @@ +package backup + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +type ResourceTag struct { + Key string `json:"key"` + Value string `json:"value"` +} + +// ListOpts allows the filtering and sorting of paginated collections through +// the API. Filtering is achieved by passing in struct field values that map to +// the attributes you want to see returned. Marker and Limit are used for pagination. +type ListOpts struct { + Status string `q:"status"` + Limit string `q:"limit"` + Marker string `q:"marker"` + Sort string `q:"sort"` + AllTenants string `q:"all_tenants"` + Name string `q:"name"` + ResourceId string `q:"resource_id"` + ResourceName string `q:"resource_name"` + PolicyId string `q:"policy_id"` + VmIp string `q:"ip"` + CheckpointId string `q:"checkpoint_id"` + ID string + ResourceType string `q:"resource_type"` +} + +// List returns collection of +// backups. It accepts a ListOpts struct, which allows you to filter and sort +// the returned collection for greater efficiency. +func List(c *golangsdk.ServiceClient, opts ListOpts) ([]Backup, error) { + q, err := golangsdk.BuildQueryString(&opts) + if err != nil { + return nil, err + } + u := listURL(c) + q.String() + pages, err := pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { + return BackupPage{pagination.LinkedPageBase{PageResult: r}} + }).AllPages() + + allBackups, err := ExtractBackups(pages) + if err != nil { + return nil, err + } + + if opts.ID != "" { + return FilterBackupsById(allBackups, opts.ID) + } + + return allBackups, nil + +} + +func FilterBackupsById(backups []Backup, filterId string) ([]Backup, error) { + + var refinedBackups []Backup + + for _, backup := range backups { + + if filterId == backup.Id { + refinedBackups = append(refinedBackups, backup) + } + } + + return refinedBackups, nil +} + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToBackupCreateMap() (map[string]interface{}, error) +} + +// CreateOpts contains the options for create a Backup. This object is +// passed to backup.Create(). +type CreateOpts struct { + BackupName string `json:"backup_name,omitempty"` + Description string `json:"description,omitempty"` + ResourceType string `json:"resource_type,omitempty"` + Tags []ResourceTag `json:"tags,omitempty"` + ExtraInfo interface{} `json:"extra_info,omitempty"` +} + +// ToBackupCreateMap assembles a request body based on the contents of a +// CreateOpts. +func (opts CreateOpts) ToBackupCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "protect") +} + +// Create will create a new backup based on the values in CreateOpts. To extract +// the checkpoint object from the response, call the Extract method on the +// CreateResult. +func Create(client *golangsdk.ServiceClient, resourceId string, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToBackupCreateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = client.Post(rootURL(client, resourceId), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// ResourceBackupCapabilityOptsBuilder allows extensions to add additional parameters to the +// QueryResourceBackupCapability request. +type ResourceBackupCapabilityOptsBuilder interface { + ToQueryResourceCreateMap() (map[string]interface{}, error) +} + +// ResourceBackupCapOpts contains the options for querying whether resources can be backed up. This object is +// passed to backup.QueryResourceBackupCapability(). +type ResourceBackupCapOpts struct { + CheckProtectable []ResourceCapQueryParams `json:"check_protectable" required:"true"` +} + +type ResourceCapQueryParams struct { + ResourceId string `json:"resource_id" required:"true"` + ResourceType string `json:"resource_type" required:"true"` +} + +// ToQueryResourceCreateMap assembles a request body based on the contents of a +// ResourceBackupCapOpts. +func (opts ResourceBackupCapOpts) ToQueryResourceCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "") +} + +// QueryResourceBackupCapability will query whether resources can be backed up based on the values in ResourceBackupCapOpts. To extract +// the ResourceCap object from the response, call the ExtractQueryResponse method on the +// QueryResult. +func QueryResourceBackupCapability(client *golangsdk.ServiceClient, opts ResourceBackupCapabilityOptsBuilder) (r QueryResult) { + b, err := opts.ToQueryResourceCreateMap() + if err != nil { + r.Err = err + + return + } + _, r.Err = client.Post(resourceURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// Get will get a single backup with specific ID. To extract the Backup object from the response, +// call the ExtractBackup method on the GetResult. +func Get(client *golangsdk.ServiceClient, backupId string) (r GetResult) { + _, r.Err = client.Get(getURL(client, backupId), &r.Body, nil) + + return + +} + +// Delete will delete an existing backup. +func Delete(client *golangsdk.ServiceClient, checkpoint_id string) (r DeleteResult) { + _, r.Err = client.Delete(deleteURL(client, checkpoint_id), &golangsdk.RequestOpts{ + OkCodes: []int{200}, + JSONResponse: nil, + }) + return +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/results.go b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/results.go new file mode 100644 index 0000000000..30ea8a7970 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/results.go @@ -0,0 +1,276 @@ +package backup + +import ( + "encoding/json" + "strconv" + "time" + + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +type Checkpoint struct { + Status string `json:"status"` + CreatedAt time.Time `json:"-"` + Id string `json:"id"` + ResourceGraph string `json:"resource_graph"` + ProjectId string `json:"project_id"` + ProtectionPlan ProtectionPlan `json:"protection_plan"` +} + +type ProtectionPlan struct { + Id string `json:"id"` + Name string `json:"name"` + BackupResources []BackupResource `json:"resources"` +} + +type BackupResource struct { + ID string `json:"id"` + Type string `json:"type"` + Name string `json:"name"` + ExtraInfo string `json:"-"` +} + +type ResourceCapability struct { + Result bool `json:"result"` + ResourceType string `json:"resource_type"` + ErrorCode string `json:"error_code"` + ErrorMsg string `json:"error_msg"` + ResourceId string `json:"resource_id"` +} + +// UnmarshalJSON helps to unmarshal Checkpoint fields into needed values. +func (r *Checkpoint) UnmarshalJSON(b []byte) error { + type tmp Checkpoint + var s struct { + tmp + CreatedAt golangsdk.JSONRFC3339MilliNoZ `json:"created_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = Checkpoint(s.tmp) + + r.CreatedAt = time.Time(s.CreatedAt) + + return err +} + +// UnmarshalJSON helps to unmarshal BackupResource fields into needed values. +func (r *BackupResource) UnmarshalJSON(b []byte) error { + type tmp BackupResource + var s struct { + tmp + ExtraInfo interface{} `json:"extra_info"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + + *r = BackupResource(s.tmp) + + switch t := s.ExtraInfo.(type) { + case float64: + r.ID = strconv.FormatFloat(t, 'f', -1, 64) + case string: + r.ID = t + } + + return err +} + +func (r commonResult) ExtractQueryResponse() ([]ResourceCapability, error) { + var s struct { + ResourcesCaps []ResourceCapability `json:"protectable"` + } + err := r.ExtractInto(&s) + return s.ResourcesCaps, err +} + +type Backup struct { + CheckpointId string `json:"checkpoint_id"` + CreatedAt time.Time `json:"-"` + ExtendInfo ExtendInfo `json:"extend_info"` + Id string `json:"id"` + Name string `json:"name"` + ResourceId string `json:"resource_id"` + Status string `json:"status"` + UpdatedAt time.Time `json:"-"` + VMMetadata VMMetadata `json:"backup_data"` + Description string `json:"description"` + Tags []ResourceTag `json:"tags"` + ResourceType string `json:"resource_type"` +} + +type ExtendInfo struct { + AutoTrigger bool `json:"auto_trigger"` + AverageSpeed int `json:"average_speed"` + CopyFrom string `json:"copy_from"` + CopyStatus string `json:"copy_status"` + FailCode FailCode `json:"fail_code"` + FailOp string `json:"fail_op"` + FailReason string `json:"fail_reason"` + ImageType string `json:"image_type"` + Incremental bool `json:"incremental"` + Progress int `json:"progress"` + ResourceAz string `json:"resource_az"` + ResourceName string `json:"resource_name"` + ResourceType string `json:"resource_type"` + Size int `json:"size"` + SpaceSavingRatio int `json:"space_saving_ratio"` + VolumeBackups []VolumeBackup `json:"volume_backups"` + FinishedAt time.Time `json:"-"` + TaskId string `json:"taskid"` + HypervisorType string `json:"hypervisor_type"` + SupportedRestoreMode string `json:"supported_restore_mode"` + Supportlld bool `json:"support_lld"` +} + +type VMMetadata struct { + RegionName string `json:"__openstack_region_name"` + CloudServiceType string `json:"cloudservicetype"` + Disk int `json:"disk"` + ImageType string `json:"imagetype"` + Ram int `json:"ram"` + Vcpus int `json:"vcpus"` + Eip string `json:"eip"` + PrivateIp string `json:"private_ip"` +} + +type FailCode struct { + Code string `json:"Code"` + Description string `json:"Description"` +} + +type VolumeBackup struct { + AverageSpeed int `json:"average_speed"` + Bootable bool `json:"bootable"` + Id string `json:"id"` + ImageType string `json:"image_type"` + Incremental bool `json:"incremental"` + SnapshotID string `json:"snapshot_id"` + Name string `json:"name"` + Size int `json:"size"` + SourceVolumeId string `json:"source_volume_id"` + SourceVolumeSize int `json:"source_volume_size"` + SpaceSavingRatio int `json:"space_saving_ratio"` + Status string `json:"status"` + SourceVolumeName string `json:"source_volume_name"` +} + +// UnmarshalJSON helps to unmarshal Backup fields into needed values. +func (r *Backup) UnmarshalJSON(b []byte) error { + type tmp Backup + var s struct { + tmp + CreatedAt golangsdk.JSONRFC3339MilliNoZ `json:"created_at"` + UpdatedAt golangsdk.JSONRFC3339MilliNoZ `json:"updated_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = Backup(s.tmp) + + r.CreatedAt = time.Time(s.CreatedAt) + r.UpdatedAt = time.Time(s.UpdatedAt) + + return err +} + +// UnmarshalJSON helps to unmarshal ExtendInfo fields into needed values. +func (r *ExtendInfo) UnmarshalJSON(b []byte) error { + type tmp ExtendInfo + var s struct { + tmp + FinishedAt golangsdk.JSONRFC3339MilliNoZ `json:"finished_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = ExtendInfo(s.tmp) + + r.FinishedAt = time.Time(s.FinishedAt) + + return err +} + +// Extract will get the checkpoint object from the commonResult +func (r commonResult) Extract() (*Checkpoint, error) { + var s struct { + Checkpoint *Checkpoint `json:"checkpoint"` + } + + err := r.ExtractInto(&s) + return s.Checkpoint, err +} + +// ExtractBackup will get the backup object from the commonResult +func (r commonResult) ExtractBackup() (*Backup, error) { + var s struct { + Backup *Backup `json:"checkpoint_item"` + } + + err := r.ExtractInto(&s) + return s.Backup, err +} + +// BackupPage is the page returned by a pager when traversing over a +// collection of backups. +type BackupPage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of backups has reached +// the end of a page and the pager seeks to traverse over a new one. In order +// to do this, it needs to construct the next page's URL. +func (r BackupPage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"checkpoint_items_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a BackupPage struct is empty. +func (r BackupPage) IsEmpty() (bool, error) { + is, err := ExtractBackups(r) + return len(is) == 0, err +} + +// ExtractBackups accepts a Page struct, specifically a BackupPage struct, +// and extracts the elements into a slice of Backup structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractBackups(r pagination.Page) ([]Backup, error) { + var s struct { + Backups []Backup `json:"checkpoint_items"` + } + err := (r.(BackupPage)).ExtractInto(&s) + return s.Backups, err +} + +type commonResult struct { + golangsdk.Result +} + +type CreateResult struct { + commonResult +} + +type DeleteResult struct { + commonResult +} + +type GetResult struct { + commonResult +} + +type QueryResult struct { + commonResult +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/urls.go b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/urls.go new file mode 100644 index 0000000000..f15fdf5e38 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup/urls.go @@ -0,0 +1,26 @@ +package backup + +import "github.com/huaweicloud/golangsdk" + +const rootPath = "providers" +const ProviderID = "fc4d5750-22e7-4798-8a46-f48f62c4c1da" + +func rootURL(c *golangsdk.ServiceClient, resourceid string) string { + return c.ServiceURL(rootPath, ProviderID, "resources", resourceid, "action") +} + +func resourceURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL(rootPath, ProviderID, "resources", "action") +} + +func getURL(c *golangsdk.ServiceClient, checkpoint_item_id string) string { + return c.ServiceURL("checkpoint_items", checkpoint_item_id) +} + +func deleteURL(c *golangsdk.ServiceClient, checkpoint_id string) string { + return c.ServiceURL(rootPath, ProviderID, "checkpoints", checkpoint_id) +} + +func listURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("checkpoint_items") +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/doc.go b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/doc.go new file mode 100644 index 0000000000..c7e674c01b --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/doc.go @@ -0,0 +1,86 @@ +/* +Package backup policies enables management and retrieval of +backup servers periodically. + +Example to List Backup Policies + listpolicies := policies.ListOpts{} + allpolicies, err := policies.List(client,listpolicies) + if err != nil { + panic(err) + } + fmt.Println(allpolicies) + + + +Example to Create a Backup Policy + policy:=policies.CreateOpts{ + Name : "c2c-policy", + Description : "My plan", + ProviderId : "fc4d5750-22e7-4798-8a46-f48f62c4c1da", + Parameters : policies.PolicyParam{ + Common:map[string]interface{}{}, + }, + ScheduledOperations : []policies.ScheduledOperation{ { + Name: "my-backup", + Description: "My backup policy", + Enabled: true, + OperationDefinition: policies.OperationDefinition{ + MaxBackups: 5, + }, + Trigger: policies.Trigger{ + Properties : policies.TriggerProperties{ + Pattern : "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nRRULE:FREQ=WEEKLY;BYDAY=TH;BYHOUR=12;BYMINUTE=27\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + }, + }, + OperationType: "backup", + }}, + Resources : []policies.Resource{{ + Id: "9422f270-6fcf-4ba2-9319-a007f2f63a8e", + Type: "OS::Nova::Server", + Name: "resource4" + }}, + } + out,err:=policies.Create(client,policy).Extract() + fmt.Println(out) + fmt.Println(err) + + +Example to Update a Backup Policy + updatepolicy:=policies.UpdateOpts{ + Name:"my-plan-c2c-update", + Parameters : policies.PolicyParamUpdate{ + Common:map[string]interface{}{}, + }, + ScheduledOperations:[]policies.ScheduledOperationToUpdate{{ + Id:"b70c712d-f48b-43f7-9a0f-3bab86d59149", + Name:"my-backup-policy", + Description:"My backup policy", + Enabled:true, + OperationDefinition:policies.OperationDefinition{ + RetentionDurationDays:-1, + MaxBackups:20, + }, + Trigger:policies.Trigger{ + Properties:policies.TriggerProperties{ + Pattern:"BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nRRULE:FREQ=WEEKLY;BYDAY=TH;BYHOUR=12;BYMINUTE=27\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"}} + } + } + } + } + out,err:=policies.Update(client,"5af626d2-19b9-4dc4-8e95-ddba008318b3",updatepolicy).Extract() + fmt.Println(out) + +Example to Delete a Backup Policy + out:=policies.Delete(client,"16d4bf9e-85b2-41e2-a482-e48ace2ad726") + fmt.Println(out) + if err != nil { + panic(err) + } + +Example to Get Backup Policy + result:=policies.Get(client,"5af626d2-19b9-4dc4-8e95-ddba008318b3") + out,err:=result.Extract() + fmt.Println(out) + +*/ +package policies diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/requests.go b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/requests.go new file mode 100644 index 0000000000..5dc89857ee --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/requests.go @@ -0,0 +1,225 @@ +package policies + +import ( + "reflect" + + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +type ListOpts struct { + ID string `json:"id"` + Name string `q:"name"` + Status string `json:"status"` + Sort string `q:"sort"` + Limit int `q:"limit"` + Marker string `q:"marker"` + Offset int `q:"offset"` + AllTenants string `q:"all_tenants"` +} + +// List returns a Pager which allows you to iterate over a collection of +// backup policies. It accepts a ListOpts struct, which allows you to +// filter the returned collection for greater efficiency. +func List(c *golangsdk.ServiceClient, opts ListOpts) ([]BackupPolicy, error) { + q, err := golangsdk.BuildQueryString(&opts) + if err != nil { + return nil, err + } + u := rootURL(c) + q.String() + pages, err := pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { + return BackupPolicyPage{pagination.LinkedPageBase{PageResult: r}} + }).AllPages() + + allpolicy, err := ExtractBackupPolicies(pages) + if err != nil { + return nil, err + } + + return FilterPolicies(allpolicy, opts) +} + +func FilterPolicies(policies []BackupPolicy, opts ListOpts) ([]BackupPolicy, error) { + + var refinedPolicies []BackupPolicy + var matched bool + m := map[string]interface{}{} + + if opts.ID != "" { + m["ID"] = opts.ID + } + if opts.Status != "" { + m["Status"] = opts.Status + } + + if len(m) > 0 && len(policies) > 0 { + for _, policy := range policies { + matched = true + + for key, value := range m { + if sVal := getStructPolicyField(&policy, key); !(sVal == value) { + matched = false + } + } + + if matched { + refinedPolicies = append(refinedPolicies, policy) + } + } + + } else { + refinedPolicies = policies + } + + return refinedPolicies, nil +} + +func getStructPolicyField(v *BackupPolicy, field string) string { + r := reflect.ValueOf(v) + f := reflect.Indirect(r).FieldByName(field) + return string(f.String()) +} + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToBackupPolicyCreateMap() (map[string]interface{}, error) +} + +// CreateOpts contains the options for create a Backup Policy. This object is +// passed to policies.Create(). +type CreateOpts struct { + Description string `json:"description,omitempty"` + Name string `json:"name" required:"true"` + Parameters PolicyParam `json:"parameters" required:"true"` + ProviderId string `json:"provider_id" required:"true"` + Resources []Resource `json:"resources" required:"true"` + ScheduledOperations []ScheduledOperation `json:"scheduled_operations" required:"true"` + Tags []ResourceTag `json:"tags,omitempty"` +} + +type PolicyParam struct { + Common interface{} `json:"common,omitempty"` +} + +type Resource struct { + Id string `json:"id" required:"true"` + Type string `json:"type" required:"true"` + Name string `json:"name" required:"true"` + ExtraInfo interface{} `json:"extra_info,omitempty"` +} + +type ScheduledOperation struct { + Description string `json:"description,omitempty"` + Enabled bool `json:"enabled"` + Name string `json:"name,omitempty"` + OperationType string `json:"operation_type" required:"true"` + OperationDefinition OperationDefinition `json:"operation_definition" required:"true"` + Trigger Trigger `json:"trigger" required:"true"` +} + +type OperationDefinition struct { + MaxBackups int `json:"max_backups,omitempty"` + RetentionDurationDays int `json:"retention_duration_days,omitempty"` + Permanent bool `json:"permanent"` + PlanId string `json:"plan_id,omitempty"` + ProviderId string `json:"provider_id,omitempty"` +} + +type Trigger struct { + Properties TriggerProperties `json:"properties" required:"true"` +} + +type TriggerProperties struct { + Pattern string `json:"pattern" required:"true"` +} + +type ResourceTag struct { + Key string `json:"key" required:"true"` + Value string `json:"value" required:"true"` +} + +// ToBackupPolicyCreateMap assembles a request body based on the contents of a +// CreateOpts. +func (opts CreateOpts) ToBackupPolicyCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "policy") +} + +// Create will create a new backup policy based on the values in CreateOpts. To extract +// the Backup object from the response, call the Extract method on the +// CreateResult. +func Create(client *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToBackupPolicyCreateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = client.Post(rootURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// Get will get a single backup policy with specific ID. +// call the Extract method on the GetResult. +func Get(client *golangsdk.ServiceClient, policy_id string) (r GetResult) { + _, r.Err = client.Get(resourceURL(client, policy_id), &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + JSONBody: nil, + }) + + return +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// Update request. +type UpdateOptsBuilder interface { + ToPoliciesUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts contains the values used when updating a backup policy. +type UpdateOpts struct { + Description string `json:"description,omitempty"` + Name string `json:"name,omitempty"` + Parameters PolicyParam `json:"parameters,omitempty"` + Resources []Resource `json:"resources,omitempty"` + ScheduledOperations []ScheduledOperationToUpdate `json:"scheduled_operations,omitempty"` +} + +type ScheduledOperationToUpdate struct { + Description string `json:"description,omitempty"` + Enabled bool `json:"enabled"` + TriggerId string `json:"trigger_id,omitempty"` + Name string `json:"name,omitempty"` + OperationDefinition OperationDefinition `json:"operation_definition,omitempty"` + Trigger Trigger `json:"trigger,omitempty"` + Id string `json:"id" required:"true"` +} + +// ToPoliciesUpdateMap builds an update body based on UpdateOpts. +func (opts UpdateOpts) ToPoliciesUpdateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "policy") +} + +// Update allows backup policies to be updated. +// call the Extract method on the UpdateResult. +func Update(c *golangsdk.ServiceClient, policy_id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToPoliciesUpdateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Put(resourceURL(c, policy_id), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// Delete will delete an existing backup policy. +func Delete(client *golangsdk.ServiceClient, policy_id string) (r DeleteResult) { + _, r.Err = client.Delete(resourceURL(client, policy_id), &golangsdk.RequestOpts{ + OkCodes: []int{200}, + JSONResponse: nil, + }) + return +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/results.go b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/results.go new file mode 100644 index 0000000000..d679f0e1f2 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/results.go @@ -0,0 +1,234 @@ +package policies + +import ( + "encoding/json" + "strconv" + + "time" + + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +type BackupPolicy struct { + CreatedAt time.Time `json:"-"` + Description string `json:"description"` + ID string `json:"id"` + Name string `json:"name"` + Parameters PolicyParam `json:"parameters"` + ProjectId string `json:"project_id"` + ProviderId string `json:"provider_id"` + Resources []Resource `json:"resources"` + ScheduledOperations []ScheduledOperationResp `json:"scheduled_operations"` + Status string `json:"status"` + Tags []ResourceTag `json:"tags"` +} + +type ScheduledOperationResp struct { + Description string `json:"description"` + Enabled bool `json:"enabled"` + Name string `json:"name"` + OperationType string `json:"operation_type"` + OperationDefinition OperationDefinitionResp `json:"operation_definition"` + Trigger TriggerResp `json:"trigger"` + ID string `json:"id"` + TriggerID string `json:"trigger_id"` +} + +type OperationDefinitionResp struct { + MaxBackups int `json:"-"` + RetentionDurationDays int `json:"-"` + Permanent bool `json:"-"` + PlanId string `json:"plan_id"` + ProviderId string `json:"provider_id"` +} + +type TriggerResp struct { + Properties TriggerPropertiesResp `json:"properties"` + Name string `json:"name"` + ID string `json:"id"` + Type string `json:"type"` +} + +type TriggerPropertiesResp struct { + Pattern string `json:"pattern"` + StartTime time.Time `json:"-"` +} + +// UnmarshalJSON helps to unmarshal BackupPolicy fields into needed values. +func (r *BackupPolicy) UnmarshalJSON(b []byte) error { + type tmp BackupPolicy + var s struct { + tmp + CreatedAt golangsdk.JSONRFC3339MilliNoZ `json:"created_at"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = BackupPolicy(s.tmp) + + r.CreatedAt = time.Time(s.CreatedAt) + + return err +} + +// UnmarshalJSON helps to unmarshal TriggerPropertiesResp fields into needed values. +func (r *TriggerPropertiesResp) UnmarshalJSON(b []byte) error { + type tmp TriggerPropertiesResp + var s struct { + tmp + StartTime golangsdk.JSONRFC3339ZNoTNoZ `json:"start_time"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = TriggerPropertiesResp(s.tmp) + + r.StartTime = time.Time(s.StartTime) + + return err +} + +// UnmarshalJSON helps to unmarshal OperationDefinitionResp fields into needed values. +func (r *OperationDefinitionResp) UnmarshalJSON(b []byte) error { + type tmp OperationDefinitionResp + var s struct { + tmp + MaxBackups string `json:"max_backups"` + RetentionDurationDays string `json:"retention_duration_days"` + Permanent string `json:"permanent"` + } + + err := json.Unmarshal(b, &s) + + if err != nil { + switch err.(type) { + case *json.UnmarshalTypeError: //check if type error occurred (handles if no type conversion is required for cloud like Huawei) + + var s struct { + tmp + MaxBackups int `json:"max_backups"` + RetentionDurationDays int `json:"retention_duration_days"` + Permanent bool `json:"permanent"` + } + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = OperationDefinitionResp(s.tmp) + r.MaxBackups = s.MaxBackups + r.RetentionDurationDays = s.RetentionDurationDays + r.Permanent = s.Permanent + return nil + default: + return err + } + } + + *r = OperationDefinitionResp(s.tmp) + + switch s.MaxBackups { + case "": + r.MaxBackups = 0 + default: + r.MaxBackups, err = strconv.Atoi(s.MaxBackups) + if err != nil { + return err + } + } + + switch s.RetentionDurationDays { + case "": + r.RetentionDurationDays = 0 + default: + r.RetentionDurationDays, err = strconv.Atoi(s.RetentionDurationDays) + if err != nil { + return err + } + } + + switch s.Permanent { + case "": + r.Permanent = false + default: + r.Permanent, err = strconv.ParseBool(s.Permanent) + if err != nil { + return err + } + } + + return err +} + +// Extract will get the backup policies object from the commonResult +func (r commonResult) Extract() (*BackupPolicy, error) { + var s struct { + BackupPolicy *BackupPolicy `json:"policy"` + } + + err := r.ExtractInto(&s) + return s.BackupPolicy, err +} + +// BackupPolicyPage is the page returned by a pager when traversing over a +// collection of backup policies. +type BackupPolicyPage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of backup policies has reached +// the end of a page and the pager seeks to traverse over a new one. In order +// to do this, it needs to construct the next page's URL. +func (r BackupPolicyPage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"policies_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a BackupPolicyPage struct is empty. +func (r BackupPolicyPage) IsEmpty() (bool, error) { + is, err := ExtractBackupPolicies(r) + return len(is) == 0, err +} + +// ExtractBackupPolicies accepts a Page struct, specifically a BackupPolicyPage struct, +// and extracts the elements into a slice of Policy structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractBackupPolicies(r pagination.Page) ([]BackupPolicy, error) { + var s struct { + BackupPolicies []BackupPolicy `json:"policies"` + } + err := (r.(BackupPolicyPage)).ExtractInto(&s) + return s.BackupPolicies, err +} + +type commonResult struct { + golangsdk.Result +} + +type CreateResult struct { + commonResult +} + +type GetResult struct { + commonResult +} + +type DeleteResult struct { + commonResult +} + +type UpdateResult struct { + commonResult +} + +type ListResult struct { + commonResult +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/urls.go b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/urls.go new file mode 100644 index 0000000000..77eb0fb099 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies/urls.go @@ -0,0 +1,13 @@ +package policies + +import "github.com/huaweicloud/golangsdk" + +const rootPath = "policies" + +func rootURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL(rootPath) +} + +func resourceURL(c *golangsdk.ServiceClient, policyid string) string { + return c.ServiceURL(rootPath, policyid) +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/kms/v1/keys/results.go b/vendor/github.com/huaweicloud/golangsdk/openstack/kms/v1/keys/results.go index 964d579838..23f161882f 100644 --- a/vendor/github.com/huaweicloud/golangsdk/openstack/kms/v1/keys/results.go +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/kms/v1/keys/results.go @@ -34,7 +34,7 @@ type Key struct { ExpirationTime string `json:"expiration_time"` // Origin of a CMK. The default value is kms. The following values // are enumerated: kms indicates that the CMK material is generated by KMS. - //Origin string `json:"origin"` + Origin string `json:"origin"` } type ListKey struct { diff --git a/vendor/vendor.json b/vendor/vendor.json index 83e6acf0fe..9246d1b76e 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -679,6 +679,18 @@ "revision": "60672b79c76a4eec63f32293ce30b4119365e1bc", "revisionTime": "2018-11-08T02:36:44Z" }, + { + "checksumSHA1": "PNHjt6ndEgEXusEdKw7CqhdNMgE=", + "path": "github.com/huaweicloud/golangsdk/openstack/csbs/v1/backup", + "revision": "47182a470c085dc857cb6f8f7e965f77e48411bf", + "revisionTime": "2018-09-27T09:20:51Z" + }, + { + "checksumSHA1": "bMOaTZOVn98JmkhGgtP4p8ZzbUI=", + "path": "github.com/huaweicloud/golangsdk/openstack/csbs/v1/policies", + "revision": "6e33e83cae0cb3d06328701748ec252346ae2430", + "revisionTime": "2018-11-30T07:27:33Z" + }, { "checksumSHA1": "bndllnyp7+JlhisoXzhyStpRP+4=", "path": "github.com/huaweicloud/golangsdk/openstack/dms/v1/availablezones", diff --git a/website/docs/d/csbs_backup_policy_v1.html.markdown b/website/docs/d/csbs_backup_policy_v1.html.markdown new file mode 100644 index 0000000000..8ae7bda4ec --- /dev/null +++ b/website/docs/d/csbs_backup_policy_v1.html.markdown @@ -0,0 +1,76 @@ +--- +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_csbs_backup_policy_v1" +sidebar_current: "docs-huaweicloud-datasource-csbs-backup-policy-v1" +description: |- + Provides details about a specific Backup Policy. +--- + +# Data Source: huaweicloud_csbs_backup_policy_v1 + +The HuaweiCloud CSBS Backup Policy data source allows access of backup Policy resources. + +## Example Usage + + +```hcl +variable "policy_id" { } + +data "huaweicloud_csbs_backup_policy_v1" "csbs_policy" { + id = "${var.policy_id}" +} + +``` + +## Argument Reference +The following arguments are supported: + +* `id` - (Optional) Specifies the ID of backup policy. + +* `name` - (Optional) Specifies the backup policy name. + +* `status` - (Optional) Specifies the backup policy status. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `description` - Specifies the backup policy description. + +* `provider_id` - Provides the Backup provider ID. + +* `parameters` - Specifies the parameters of a backup policy. + +* `scheduled_operation` block supports the following arguments: + + * `name` - Specifies Scheduling period name. + + * `description` - Specifies Scheduling period description. + + * `enabled` - Specifies whether the scheduling period is enabled. + + * `max_backups` - Specifies maximum number of backups that can be automatically created for a backup object. + + * `retention_duration_days` - Specifies duration of retaining a backup, in days. + + * `permanent` - Specifies whether backups are permanently retained. + + * `trigger_pattern` - Specifies Scheduling policy of the scheduler. + + * `operation_type` - Specifies Operation type, which can be backup. + + * `id` - Specifies Scheduling period ID. + + * `trigger_id` - Specifies Scheduler ID. + + * `trigger_name` - Specifies Scheduler name. + + * `trigger_type` - Specifies Scheduler type. + +* `resource` block supports the following arguments: + + * `id` - Specifies the ID of the object to be backed up. + + * `type` - Entity object type of the backup object. + + * `name` - Specifies backup object name. \ No newline at end of file diff --git a/website/docs/d/csbs_backup_v1.html.markdown b/website/docs/d/csbs_backup_v1.html.markdown new file mode 100644 index 0000000000..a8d80617c3 --- /dev/null +++ b/website/docs/d/csbs_backup_v1.html.markdown @@ -0,0 +1,104 @@ +--- +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_csbs_backup_v1" +sidebar_current: "docs-huaweicloud-datasource-csbs-backup-v1" +description: |- + Provides details about a specific Backup. +--- + +# Data Source: huaweicloud_csbs_backup_v1 + +The HuaweiCloud CSBS Backup data source allows access of backup resources. + +## Example Usage + + +```hcl +variable "backup_name" { } + +data "huaweicloud_csbs_backup_v1" "csbs" { + backup_name = "${var.backup_name}" +} +``` + +## Argument Reference +The following arguments are supported: + +* `id` - (Optional) Specifies the ID of backup. + +* `backup_name` - (Optional) Specifies the backup name. + +* `status` - (Optional) Specifies the backup status. + +* `resource_name` - (Optional) Specifies the backup object name. + +* `backup_record_id` - (Optional) Specifies the backup record ID. + +* `resource_type` - (Optional) Specifies the type of backup objects. + +* `resource_id` - (Optional) Specifies the backup object ID. + +* `policy_id` - (Optional) Specifies the Policy Id. + +* `vm_ip` - (Optional) Specifies the ip of VM. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: + +* `description` - Provides the backup description. + +* `auto_trigger` - Specifies whether automatic trigger is enabled. + +* `average_speed` - Specifies average speed. + +* `size` - Specifies the backup capacity. + +* volume_backups + + * `space_saving_ratio` - Specifies the space saving rate. + + * `volume_backups` block supports the following arguments: + + * `status` - Status of backup Volume. + + * `space_saving_ratio` - Specifies space saving rate. + + * `name` - It gives EVS disk backup name. + + * `bootable` - Specifies whether the disk is bootable. + + * `average_speed` - Specifies the average speed. + + * `source_volume_size` - Shows source volume size in GB. + + * `source_volume_id` - It specifies source volume ID. + + * `incremental` - Shows whether incremental backup is used. + + * `snapshot_id` - ID of snapshot. + + * `source_volume_name` - Specifies source volume name. + + * `image_type` - It specifies backup. The default value is backup. + + * `id` - Specifies Cinder backup ID. + + * `size` - Specifies accumulated size (MB) of backups. + +* `vm_metadata` block supports the following arguments: + + * `name` - Name of backup data. + + * `eip` - Specifies elastic IP address of the ECS. + + * `cloud_service_type` - Specifies ECS type. + + * `ram` - Specifies memory size of the ECS, in MB. + + * `vcpus` - Specifies CPU cores corresponding to the ECS. + + * `private_ip` - It specifies internal IP address of the ECS. + + * `disk` - Shows system disk size corresponding to the ECS specifications. + + * `image_type` - Specifies image type. diff --git a/website/docs/r/csbs_backup_policy_v1.html.markdown b/website/docs/r/csbs_backup_policy_v1.html.markdown new file mode 100644 index 0000000000..1a4c3d940c --- /dev/null +++ b/website/docs/r/csbs_backup_policy_v1.html.markdown @@ -0,0 +1,100 @@ +--- +layout: "huaweicloud" +page_title: "HuaweiCloud: resource_huaweicloud_csbs_backup_policy_v1" +sidebar_current: "docs-huaweicloud-resource-csbs-backup-policy-v1" +description: |- + Provides an HuaweiCloud Backup Policy of Resource. +--- + +# huaweicloud_csbs_backup_policy_v1 + +Provides an HuaweiCloud Backup Policy of Resources. + +## Example Usage + + ```hcl + variable "name" { } + variable "id" { } + variable "resource_name" { } + + resource "huaweicloud_csbs_backup_policy_v1" "backup_policy_v1" { + name = "${var.name}" + resource { + id = "${var.id}" + type = "OS::Nova::Server" + name = "${var.resource_name}" + } + scheduled_operation { + enabled = true + operation_type = "backup" + trigger_pattern = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nRRULE:FREQ=WEEKLY;BYDAY=TH;BYHOUR=12;BYMINUTE=27\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n" + } + } + + ``` +## Argument Reference +The following arguments are supported: + +* `name` - (Required) Specifies the name of backup policy. The value consists of 1 to 255 characters and can contain only letters, digits, underscores (_), and hyphens (-). + +* `description` - (Optional) Backup policy description. The value consists of 0 to 255 characters and must not contain a greater-than sign (>) or less-than sign (<). + +* `provider_id` - (Required) Specifies backup provider ID. Default value is **fc4d5750-22e7-4798-8a46-f48f62c4c1da** + +* `common` - (Optional) General backup policy parameters, which are blank by default. + +* `scheduled_operation` block supports the following arguments: + + * `name` - (Optional) Specifies Scheduling period name.The value consists of 1 to 255 characters and can contain only letters, digits, underscores (_), and hyphens (-). + + * `description` - (Optional) Specifies Scheduling period description.The value consists of 0 to 255 characters and must not contain a greater-than sign (>) or less-than sign (<). + + * `enabled` - (Optional) Specifies whether the scheduling period is enabled. Default value is **true** + + * `max_backups` - (Optional) Specifies maximum number of backups that can be automatically created for a backup object. + + * `retention_duration_days` - (Optional) Specifies duration of retaining a backup, in days. + + * `permanent` - (Optional) Specifies whether backups are permanently retained. + + * `trigger_pattern` - (Required) Specifies Scheduling policy of the scheduler. + + * `operation_type` - (Required) Specifies Operation type, which can be backup. + +* `resource` block supports the following arguments: + + * `id` - (Required) Specifies the ID of the object to be backed up. + + * `type` - (Required) Entity object type of the backup object. If the type is VMs, the value is **OS::Nova::Server**. + + * `name` - (Required) Specifies backup object name. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: + +* `status` - Status of Backup Policy. + +* `id` - Backup Policy ID. + +* scheduled_operation - Backup plan information + + * `id` - Specifies Scheduling period ID. + + * `trigger_id` - Specifies Scheduler ID. + + * `trigger_name` - Specifies Scheduler name. + + * `trigger_type` - Specifies Scheduler type. + + +## Import + +Backup Policy can be imported using `id`, e.g. + +``` +$ terraform import huaweicloud_csbs_backup_policy_v1.backup_policy_v1 7056d636-ac60-4663-8a6c-82d3c32c1c64 +``` + + + + diff --git a/website/docs/r/csbs_backup_v1.html.markdown b/website/docs/r/csbs_backup_v1.html.markdown new file mode 100644 index 0000000000..8d8889c941 --- /dev/null +++ b/website/docs/r/csbs_backup_v1.html.markdown @@ -0,0 +1,100 @@ +--- +layout: "huaweicloud" +page_title: "HuaweiCloud: resource_huaweicloud_csbs_backup_v1" +sidebar_current: "docs-huaweicloud-resource-csbs-backup-v1" +description: |- + Provides an HuaweiCloud Backup of Resources. +--- + +# huaweicloud_csbs_backup_v1 + +Provides an HuaweiCloud Backup of Resources. + +## Example Usage + + ```hcl + variable "backup_name" { } + variable "resource_id" { } + + resource "huaweicloud_csbs_backup_v1" "backup_v1" { + backup_name = "${var.backup_name}" + resource_id = "${var.resource_id}" + resource_type = "OS::Nova::Server" + } + + ``` +## Argument Reference +The following arguments are supported: + +* `backup_name` - (Optional) Name for the backup. The value consists of 1 to 255 characters and can contain only letters, digits, underscores (_), and hyphens (-). Changing backup_name creates a new backup. + +* `description` - (Optional) Backup description. The value consists of 0 to 255 characters and must not contain a greater-than sign (>) or less-than sign (<). Changing description creates a new backup. + +* `resource_id` - (Required) ID of the target to which the backup is restored. Changing this creates a new backup. + +* `resource_type` - (Optional) Type of the target to which the backup is restored. The default value is **OS::Nova::Server** for an ECS. Changing this creates a new backup. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: + +* `status` - It specifies the status of backup. + +* `backup_record_id` - Specifies backup record ID. + +* `volume_backups` block supports the following arguments: + + * `status` - Status of backup Volume. + + * `space_saving_ratio` - Specifies space saving rate. + + * `name` - It gives EVS disk backup name. + + * `bootable` - Specifies whether the disk is bootable. + + * `average_speed` - Specifies the average speed. + + * `source_volume_size` - Shows source volume size in GB. + + * `source_volume_id` - It specifies source volume ID. + + * `incremental` - Shows whether incremental backup is used. + + * `snapshot_id` - ID of snapshot. + + * `source_volume_name` - Specifies source volume name. + + * `image_type` - It specifies backup. The default value is backup. + + * `id` - Specifies Cinder backup ID. + + * `size` - Specifies accumulated size (MB) of backups. + +* `vm_metadata` block supports the following arguments: + + * `name` - Name of backup data. + + * `eip` - Specifies elastic IP address of the ECS. + + * `cloud_service_type` - Specifies ECS type. + + * `ram` - Specifies memory size of the ECS, in MB. + + * `vcpus` - Specifies CPU cores corresponding to the ECS. + + * `private_ip` - It specifies internal IP address of the ECS. + + * `disk` - Shows system disk size corresponding to the ECS specifications. + + * `image_type` - Specifies image type. + + +## Import + +Backup can be imported using `backup_record_id`, e.g. + +``` +$ terraform import huaweicloud_csbs_backup_v1.backup_v1.backup_v1 7056d636-ac60-4663-8a6c-82d3c32c1c64 +``` + + + diff --git a/website/huaweicloud.erb b/website/huaweicloud.erb index 8d1c1c332e..a9108dc006 100644 --- a/website/huaweicloud.erb +++ b/website/huaweicloud.erb @@ -73,6 +73,12 @@ > huaweicloud_rts_software_config_v1 + > + huaweicloud_csbs_backup_v1 + + > + huaweicloud_csbs_backup_policy_v1 + > huaweicloud_vbs_backup_policy_v2 @@ -364,6 +370,17 @@ + > + CSBS Resources + + > CTS Resources