From 2d28f8adcf4541af843675cfc347b7efdbc3b958 Mon Sep 17 00:00:00 2001 From: Zippo-Wang <852420284@qq.com> Date: Tue, 31 Oct 2023 16:35:04 +0800 Subject: [PATCH] fix(RDS): import RDS resource and add unit test and document. --- docs/data-sources/rds_backups.md | 96 +++++ docs/data-sources/rds_engine_versions.md | 40 ++ docs/data-sources/rds_instances.md | 132 +++++++ docs/data-sources/rds_storage_types.md | 70 ++++ docs/resources/rds_backup.md | 83 ++++ .../rds_cross_region_backup_strategy.md | 74 ++++ docs/resources/rds_sql_audit.md | 57 +++ ..._source_flexibleengine_rds_backups_test.go | 205 ++++++++++ ...flexibleengine_rds_engine_versions_test.go | 96 +++++ ...ource_flexibleengine_rds_instances_test.go | 176 +++++++++ ...e_flexibleengine_rds_storage_types_test.go | 105 ++++++ ...resource_flexibleengine_rds_backup_test.go | 356 ++++++++++++++++++ ...e_rds_cross_region_backup_strategy_test.go | 217 +++++++++++ ...ource_flexibleengine_rds_sql_audit_test.go | 171 +++++++++ flexibleengine/provider.go | 22 +- 15 files changed, 1894 insertions(+), 6 deletions(-) create mode 100644 docs/data-sources/rds_backups.md create mode 100644 docs/data-sources/rds_engine_versions.md create mode 100644 docs/data-sources/rds_instances.md create mode 100644 docs/data-sources/rds_storage_types.md create mode 100644 docs/resources/rds_backup.md create mode 100644 docs/resources/rds_cross_region_backup_strategy.md create mode 100644 docs/resources/rds_sql_audit.md create mode 100644 flexibleengine/acceptance/data_source_flexibleengine_rds_backups_test.go create mode 100644 flexibleengine/acceptance/data_source_flexibleengine_rds_engine_versions_test.go create mode 100644 flexibleengine/acceptance/data_source_flexibleengine_rds_instances_test.go create mode 100644 flexibleengine/acceptance/data_source_flexibleengine_rds_storage_types_test.go create mode 100644 flexibleengine/acceptance/resource_flexibleengine_rds_backup_test.go create mode 100644 flexibleengine/acceptance/resource_flexibleengine_rds_cross_region_backup_strategy_test.go create mode 100644 flexibleengine/acceptance/resource_flexibleengine_rds_sql_audit_test.go diff --git a/docs/data-sources/rds_backups.md b/docs/data-sources/rds_backups.md new file mode 100644 index 00000000..b9856776 --- /dev/null +++ b/docs/data-sources/rds_backups.md @@ -0,0 +1,96 @@ +--- +subcategory: "Relational Database Service (RDS)" +--- + +# flexibleengine_rds_backups + +Use this data source to get the list of RDS backups. + +## Example Usage + +```hcl +variable "instance_id" {} + +data "flexibleengine_rds_backups" "test" { + instance_id = var.instance_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String) Specifies the region in which to query the data source. + If omitted, the provider-level region will be used. + +* `instance_id` - (Required, String) Specifies the DB instance ID. + +* `name` - (Optional, String) Specifies the backup name. + +* `backup_id` - (Optional, String) Specifies the backup ID. + +* `backup_type` - (Optional, String) Specifies the backup type. The options are as follows: + - **auto**: Automated full backup. + - **manual**: Manual full backup. + - **fragment**: Differential full backup. + - **incremental**: Automated incremental backup. + +* `begin_time` - (Optional, String) Specifies the start time for obtaining the backup list. + The format of the start time is "yyyy-mm-ddThh:mm:ssZ". + +* `end_time` - (Optional, String) Specifies the end time for obtaining the backup list. + The format of the end time is "yyyy-mm-ddThh:mm:ssZ" and the end time must be later than the start time. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. + +* `backups` - Backup list. For details, see Data structure of the Backup field. + The [backups](#rds_backups) structure is documented below. + + +The `backups` block supports: + +* `id` - Backup ID. + +* `instance_id` - RDS instance ID. + +* `name` - Backup name. + +* `type` - Backup type. The options are as follows: + - **auto**: Automated full backup. + - **manual**: Manual full backup. + - **fragment**: Differential full backup. + - **incremental**: Automated incremental backup. + +* `size` - Backup size in KB. + +* `status` - Backup status. The options are as follows: + - **BUILDING**: Backup in progress. + - **COMPLETED**: Backup completed. + - **FAILED**: Backup failed. + - **DELETING**: Backup being deleted. + +* `begin_time` - Backup start time in the "yyyy-mm-ddThh:mm:ssZ" format. + +* `end_time` - Backup end time in the "yyyy-mm-ddThh:mm:ssZ" format. + +* `associated_with_ddm` - Whether a DDM instance has been associated. + +* `datastore` - The database information. The [datastore](#rds_datastore) structure is documented below. + +* `databases` - Database been backed up. The [databases](#rds_databases) structure is documented below. + + +The `datastore` block supports: + +* `type` - DB engine. The value can be: **MySQL**, **PostgreSQL**, **SQLServer**. + +* `version` - DB engine version. + + +The `rds_databases` block supports: + +* `name` - Database to be backed up for Microsoft SQL Server. diff --git a/docs/data-sources/rds_engine_versions.md b/docs/data-sources/rds_engine_versions.md new file mode 100644 index 00000000..cd94f480 --- /dev/null +++ b/docs/data-sources/rds_engine_versions.md @@ -0,0 +1,40 @@ +--- +subcategory: "Relational Database Service (RDS)" +--- + +# flexibleengine_rds_engine_versions + +Use this data source to obtain all version information of the specified engine type of FlexibleEngine. + +## Example Usage + +```hcl +data "flexibleengine_rds_engine_versions" "test" { + type = "SQLServer" +} +``` + +## Argument Reference + +* `region` - (Optional, String) The region in which to obtain the RDS engine versions. + If omitted, the provider-level region will be used. + +* `type` - (Optional, String) Specifies the RDS engine type. + The valid values are **MySQL**, **PostgreSQL** and **SQLServer**, default to **MySQL**. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Data source ID in hashcode format. + +* `versions` - Indicates the list of database versions. The [versions](#rds_versions) object structure is + documented below. + + +The `versions` block supports: + +* `id` - Indicates the database version ID. Its value is unique. + +* `name` - Indicates the database version number. Only the major version number (two digits) is returned. + For example, if the version number is MySQL 5.6.X, only 5.6 is returned. diff --git a/docs/data-sources/rds_instances.md b/docs/data-sources/rds_instances.md new file mode 100644 index 00000000..0bd2b235 --- /dev/null +++ b/docs/data-sources/rds_instances.md @@ -0,0 +1,132 @@ +--- +subcategory: "Relational Database Service (RDS)" +--- + +# flexibleengine_rds_instances + +Use this data source to list all available RDS instances. + +## Example Usage + +```hcl +data "flexibleengine_rds_instances" "test" { + name = "rds-instance" +} +``` + +## Argument Reference + +* `region` - (Optional, String) The region in which query obtain the instances. If omitted, the provider-level region + will be used. + +* `name` - (Optional, String) Specifies the name of the instance. + +* `type` - (Optional, String) Specifies the type of the instance. Valid values are: + **Single**, **Ha**, **Replica**, and **Enterprise**. + +* `datastore_type` - (Optional, String) Specifies the type of the database. Valid values are: + **MySQL**, **PostgreSQL**, and **SQLServer**. + +* `vpc_id` - (Optional, String) Specifies the VPC ID. + +* `subnet_id` - (Optional, String) Specifies the network ID of a subnet. + +* `enterprise_project_id` - (Optional, String) Specifies the enterprise project id. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the data source. + +* `instances` - An array of available instances. The [instances](#rds_instances) object structure is documented below. + + +The `instances` block supports: + +* `region` - The region of the instance. + +* `name` - Indicates the name of the instance. + +* `availability_zone` - Indicates the availability zone name. + +* `flavor` - Indicates the instance specifications. + +* `vpc_id` - Indicates the VPC ID. + +* `subnet_id` - Indicates the network ID of a subnet. + +* `id` - Indicates the ID of the instance. + +* `security_group_id` - Indicates the security group ID. + +* `param_group_id` - Indicates the configuration ID. + +* `enterprise_project_id` - Indicates the enterprise project id. + +* `fixed_ip` - Indicates the intranet floating IP address of the instance. + +* `ssl_enable` - Indicates whether to enable SSL. + +* `tags` - Indicates the tags of the instance. + +* `ha_replication_mode` - Indicates the replication mode for the standby DB instance. + +* `time_zone` - Indicates the time zone. + +* `private_ips` - Indicates the private ips in list. + +* `public_ips` - Indicates the public ips in list. + +* `status` - Indicates the DB instance status. + +* `created` - Indicates the creation time. + +* `db` - Indicates the database information. The [db](#rds_db) object structure is documented below. + +* `volume` - Indicates the volume information. The [volume](#rds_volume) object structure is documented below. + +* `backup_strategy` - Indicates the advanced backup policy. The [backup_strategy](#rds_backup_strategy) object structure + is documented below. + +* `nodes` - Indicates the instance nodes information. The [nodes](#rds_nodes) object structure is documented below. + + +The `db` block supports: + +* `type` - Indicates the database engine. + +* `version` - Indicates the database version. + +* `port` - Indicates the database port. + +* `user_name` - Indicates the database username. + + +The `volume` block supports: + +* `size` - Indicates the volume size. + +* `type` - Indicates the volume type. + +* `disk_encryption_id` - Indicates the kms key id. + + +The `backup_strategy` block supports: + +* `start_time` - Indicates the backup time window. + +* `keep_days` - Indicates the number of days to retain the generated. + + +The `nodes` block supports: + +* `id` - Indicates the node ID. + +* `name` - Indicates the node name. + +* `status` - Indicates the node status. + +* `role` - Indicates the node type. + +* `availability_zone` - Indicates the availability zone where the node resides. diff --git a/docs/data-sources/rds_storage_types.md b/docs/data-sources/rds_storage_types.md new file mode 100644 index 00000000..7b4b0cfc --- /dev/null +++ b/docs/data-sources/rds_storage_types.md @@ -0,0 +1,70 @@ +--- +subcategory: "Relational Database Service (RDS)" +--- + +# flexibleengine_rds_storage_types + +Use this data source to get the list of RDS storage types. + +## Example Usage + +```hcl +variable "instance_id" {} + +data "flexibleengine_rds_storage_types" "test" { + db_type = "MySQL" + db_version = "8.0" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String) Specifies the region in which to query the data source. + If omitted, the provider-level region will be used. + +* `db_type` - (Required, String) Specifies the DB engine type. Its value can be any of the following and + is case-insensitive: **MySQL**, **PostgreSQL**, **SQLServer**. + +* `db_version` - (Required, String) Specifies the database version. For details about how to obtain the database + version, see section [Querying Version Information About a DB Engine](https://docs.prod-cloud-ocb.orange-business.com/en-us/api/rds/rds_06_0001.html). + +* `instance_mode` - (Optional, String) Specifies the HA mode. The value options are as + follows: **single**, **ha**, **replica**. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. + +* `storage_types` - Indicates the DB instance specifications information list. For details, see Data structure of + the storage_type field. The [storage_type](#Storagetype_storageType) structure is documented below. + + +The `storage_type` block supports: + +* `name` - Indicates the storage type. Its value can be any of the following: + - **COMMON**: Indicates the SATA type. + - **ULTRAHIGH**: Indicates the SSD type. + +* `az_status` - The status details of the AZs to which the specification belongs. + Key indicates the AZ ID, and value indicates the specification status in the AZ. + The options of value are as follows: + - **normal**: The specifications in the AZ are available. + - **unsupported**: The specifications are not supported by the AZ. + - **sellout**: The specifications in the AZ are sold out. + +* `support_compute_group_type` - Performance specifications. + The options are as follows: + - **normal**: General-enhanced. + - **normal2**: General-enhanced II. + - **armFlavors**: Kunpeng general-enhanced. + - **dedicicatenormal**: Exclusive x86. + - **armlocalssd**: Standard Kunpeng. + - **normallocalssd**: Standard x86. + - **general**: General-purpose. + - **dedicated**: Dedicated, which is only supported for cloud SSDs. + - **rapid**: Dedicated, which is only supported for extreme SSDs. + - **bigmen**: Large-memory. diff --git a/docs/resources/rds_backup.md b/docs/resources/rds_backup.md new file mode 100644 index 00000000..0b8eefe6 --- /dev/null +++ b/docs/resources/rds_backup.md @@ -0,0 +1,83 @@ +--- +subcategory: "Relational Database Service (RDS)" +--- + +# flexibleengine_rds_backup + +Manages a RDS manual backup resource within FlexibleEngine. + +## Example Usage + +```hcl +variable "instance_id" {} +variable "backup_name" {} + +resource "flexibleengine_rds_backup" "test" { + instance_id = var.instance_id + name = var.backup_name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) Specifies the region in which to create the resource. + If omitted, the provider-level region will be used. Changing this parameter will create a new resource. + +* `name` - (Required, String, ForceNew) Specifies the name of the resource backup. + The valid length is limited from can contain 4 to 64 characters long, start with a letter, and contain only + letters (case-sensitive),digits, hyphens (-), and underscores (_). + Changing this parameter will create a new resource. + +* `instance_id` - (Required, String, ForceNew) Specifies the instance id. + Changing this parameter will create a new resource. + +* `description` - (Optional, String, ForceNew) The description about the backup. + It contains a maximum of 256 characters and cannot contain the following special characters: **> ! < " & ' =**. + Changing this parameter will create a new resource. + +* `databases` - (Optional, List, ForceNew) List of self-built Microsoft SQL Server databases that are partially + backed up. (Only Microsoft SQL Server supports partial backups). The [databases](#rds_databases) structure is + documented below. Changing this parameter will create a new resource. + + +The `databases` block supports: + +* `name` - (Required, String, ForceNew) Database to be backed up for Microsoft SQL Server. + Changing this parameter will create a new resource. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. + +* `begin_time` - Backup start time in the "yyyy-mm-ddThh:mm:ssZ" format. + +* `end_time` - Backup end time in the "yyyy-mm-ddThh:mm:ssZ" format. + +* `status` - Backup status. The options are as follows: + + **BUILDING**: Backup in progress. + + **COMPLETED**: Backup completed. + + **FAILED**: Backup failed. + + **DELETING**: Backup being deleted. + +* `size` - Backup size in KB. + +* `associated_with_ddm` - Whether a DDM instance has been associated. + +## Timeouts + +This resource provides the following timeouts configuration options: + +* `create` - Default is 30 minutes. +* `delete` - Default is 30 minutes. + +## Import + +The rds manual backup can be imported using the instance ID and the backup ID separated by a slash, e.g.: + +```shell +terraform import flexibleengine_rds_backup.test 1ce123456a00f2591fabc00385ff1235/0ce123456a00f2591fabc00385ff1234 +``` diff --git a/docs/resources/rds_cross_region_backup_strategy.md b/docs/resources/rds_cross_region_backup_strategy.md new file mode 100644 index 00000000..2d4a752a --- /dev/null +++ b/docs/resources/rds_cross_region_backup_strategy.md @@ -0,0 +1,74 @@ +--- +subcategory: "Relational Database Service (RDS)" +--- + +# flexibleengine_rds_cross_region_backup_strategy + +Manages RDS cross-region backup strategy resource within FlexibleEngine. + +## Example Usage + +```hcl +variable "instance_id" {} +variable "destination_region" {} +variable "destination_project_id" {} + +resource "flexibleengine_rds_cross_region_backup_strategy" "test" { + instance_id = var.instance_id + backup_type = "all" + keep_days = 5 + destination_region = var.destination_region + destination_project_id = var.destination_project_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) Specifies the region in which to create the resource. + If omitted, the provider-level region will be used. Changing this parameter will create a new resource. + +* `instance_id` - (Required, String, ForceNew) Specifies the ID of the RDS instance. + + Changing this parameter will create a new resource. + +* `backup_type` - (Required, String) Specifies the backup type. Value options: + + **auto**: open automated full backup. + + **all**: open both automated full backup and automated incremental backup. + + Only **all** is supported for SQL server. + +* `keep_days` - (Required, Int) Specifies the number of days to retain the generated backup files. + Value ranges from `1` to `1825`. + +* `destination_region` - (Required, String, ForceNew) Specifies the target region ID for the cross-region backup policy. + + Changing this parameter will create a new resource. + +* `destination_project_id` - (Required, String, ForceNew) Specifies the target project ID for the cross-region backup + policy. + + Changing this parameter will create a new resource. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. + +## Timeouts + +This resource provides the following timeouts configuration options: + +* `create` - Default is 30 minutes. +* `update` - Default is 30 minutes. +* `delete` - Default is 30 minutes. + +## Import + +The RDS cross-region backup strategy can be imported using the `id`, e.g. + +```shell +terraform import flexibleengine_rds_cross_region_backup_strategy.test +``` diff --git a/docs/resources/rds_sql_audit.md b/docs/resources/rds_sql_audit.md new file mode 100644 index 00000000..92f5d7e2 --- /dev/null +++ b/docs/resources/rds_sql_audit.md @@ -0,0 +1,57 @@ +--- +subcategory: "Relational Database Service (RDS)" +--- + +# flexibleengine_rds_sql_audit + +Manages RDS SQL audit resource within FlexibleEngine. + +-> **NOTE:** Only MySQL and PostgreSQL engines are supported. + +## Example Usage + +```hcl +variable "instance_id" {} + +resource "flexibleengine_rds_sql_audit" "test" { + instance_id = var.instance_id + keep_days = 5 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) Specifies the region in which to create the resource. + If omitted, the provider-level region will be used. Changing this parameter will create a new resource. + +* `instance_id` - (Required, String, ForceNew) Specifies the ID of the RDS instance. + Changing this parameter will create a new resource. + +* `keep_days` - (Required, Int) Specifies the number of days for storing audit logs. Value ranges from `1` to `732`. + +* `reserve_auditlogs` - (Optional, Bool) Specifies whether the historical audit logs will be reserved for some time + when SQL audit is disabled. It is valid only when SQL audit is disabled. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The resource ID. + +## Timeouts + +This resource provides the following timeouts configuration options: + +* `create` - Default is 30 minutes. +* `update` - Default is 30 minutes. +* `delete` - Default is 30 minutes. + +## Import + +The RDS SQL audit can be imported using the `id`, e.g. + +```shell +terraform import flexibleengine_rds_sql_audit.test +``` diff --git a/flexibleengine/acceptance/data_source_flexibleengine_rds_backups_test.go b/flexibleengine/acceptance/data_source_flexibleengine_rds_backups_test.go new file mode 100644 index 00000000..fe91dbc8 --- /dev/null +++ b/flexibleengine/acceptance/data_source_flexibleengine_rds_backups_test.go @@ -0,0 +1,205 @@ +package acceptance + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccDatasourceBackup_basic(t *testing.T) { + rName := "data.flexibleengine_rds_backups.test" + dc := acceptance.InitDataSourceCheck(rName) + name := acceptance.RandomAccResourceName() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDatasourceBackup_basic(name), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "backups.0.id", "flexibleengine_rds_backup.test", "id"), + resource.TestCheckResourceAttrPair(rName, "backups.0.name", "flexibleengine_rds_backup.test", "name"), + resource.TestCheckResourceAttrPair(rName, "backups.0.instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttr(rName, "backups.0.type", "manual"), + resource.TestCheckResourceAttrSet(rName, "backups.0.size"), + resource.TestCheckResourceAttrSet(rName, "backups.0.status"), + resource.TestCheckResourceAttrSet(rName, "backups.0.begin_time"), + resource.TestCheckResourceAttrSet(rName, "backups.0.end_time"), + resource.TestCheckResourceAttrSet(rName, "backups.0.associated_with_ddm"), + resource.TestCheckResourceAttr(rName, "backups.0.datastore.#", "1"), + resource.TestCheckResourceAttr(rName, "backups.0.databases.#", "0"), + ), + }, + }, + }) +} + +func TestAccDatasourceBackup_auto_basic(t *testing.T) { + rName := "data.flexibleengine_rds_backups.test" + dc := acceptance.InitDataSourceCheck(rName) + name := acceptance.RandomAccResourceName() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDatasourceBackup_auto_basic(name), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "backups.0.id", "flexibleengine_rds_backup.test", "id"), + resource.TestCheckResourceAttrPair(rName, "backups.0.name", "flexibleengine_rds_backup.test", "name"), + resource.TestCheckResourceAttrPair(rName, "backups.0.instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttr(rName, "backups.0.type", "auto"), + resource.TestCheckResourceAttrSet(rName, "backups.0.size"), + resource.TestCheckResourceAttrSet(rName, "backups.0.status"), + resource.TestCheckResourceAttrSet(rName, "backups.0.begin_time"), + resource.TestCheckResourceAttrSet(rName, "backups.0.end_time"), + resource.TestCheckResourceAttrSet(rName, "backups.0.associated_with_ddm"), + resource.TestCheckResourceAttr(rName, "backups.0.datastore.#", "1"), + resource.TestCheckResourceAttr(rName, "backups.0.databases.#", "0"), + ), + }, + }, + }) +} + +func TestAccDatasourceBackup_incremental_basic(t *testing.T) { + rName := "data.flexibleengine_rds_backups.test" + dc := acceptance.InitDataSourceCheck(rName) + name := acceptance.RandomAccResourceName() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDatasourceBackup_incremental_basic(name), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "backups.0.id", "flexibleengine_rds_backup.test", "id"), + resource.TestCheckResourceAttrPair(rName, "backups.0.name", "flexibleengine_rds_backup.test", "name"), + resource.TestCheckResourceAttrPair(rName, "backups.0.instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttr(rName, "backups.0.type", "incremental"), + resource.TestCheckResourceAttrSet(rName, "backups.0.size"), + resource.TestCheckResourceAttrSet(rName, "backups.0.status"), + resource.TestCheckResourceAttrSet(rName, "backups.0.begin_time"), + resource.TestCheckResourceAttrSet(rName, "backups.0.end_time"), + resource.TestCheckResourceAttrSet(rName, "backups.0.associated_with_ddm"), + resource.TestCheckResourceAttr(rName, "backups.0.datastore.#", "1"), + resource.TestCheckResourceAttr(rName, "backups.0.databases.#", "0"), + ), + }, + }, + }) +} + +func testAccDatasourceBackup_base(name string) string { + return fmt.Sprintf(` +%[1]s + +data "flexibleengine_availability_zones" "test" {} + +data "flexibleengine_networking_secgroup_v2" "test" { + name = "default" +} + +data "flexibleengine_rds_flavors_v3" "test" { + db_type = "MySQL" + db_version = "8.0" + instance_mode = "single" +} + +resource "flexibleengine_rds_instance_v3" "test" { + name = "%[2]s" + flavor = data.flexibleengine_rds_flavors_v3.test.flavors[2].name + availability_zone = [data.flexibleengine_availability_zones.test.names[0]] + security_group_id = data.flexibleengine_networking_secgroup_v2.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + vpc_id = flexibleengine_vpc_v1.test.id + time_zone = "UTC+08:00" + + db { + password = "FlexibleEngine!120521" + type = "MySQL" + version = "8.0" + port = 8630 + } + + volume { + type = "COMMON" + size = 60 + } + + backup_strategy { + start_time = "08:00-09:00" + keep_days = 1 + } + + lifecycle { + ignore_changes = [ + backup_strategy, + ] + } +} + +resource "flexibleengine_rds_backup" "test" { + name = "%[2]s" + instance_id = flexibleengine_rds_instance_v3.test.id +} + +`, testVpc(name), name) +} + +func testAccDatasourceBackup_basic(name string) string { + return fmt.Sprintf(` +%s + +data "flexibleengine_rds_backups" "test" { + instance_id = flexibleengine_rds_instance_v3.test.id + backup_type = "manual" + + depends_on = [ + flexibleengine_rds_backup.test + ] +} +`, testAccDatasourceBackup_base(name)) +} + +func testAccDatasourceBackup_auto_basic(name string) string { + return fmt.Sprintf(` +%s + +data "flexibleengine_rds_backups" "test" { + instance_id = flexibleengine_rds_instance_v3.test.id + backup_type = "auto" + + depends_on = [ + flexibleengine_rds_backup.test + ] +} +`, testAccDatasourceBackup_base(name)) +} + +func testAccDatasourceBackup_incremental_basic(name string) string { + return fmt.Sprintf(` +%s + +data "flexibleengine_rds_backups" "test" { + instance_id = flexibleengine_rds_instance_v3.test.id + backup_type = "incremental" + + depends_on = [ + flexibleengine_rds_backup.test + ] +} +`, testAccDatasourceBackup_base(name)) +} diff --git a/flexibleengine/acceptance/data_source_flexibleengine_rds_engine_versions_test.go b/flexibleengine/acceptance/data_source_flexibleengine_rds_engine_versions_test.go new file mode 100644 index 00000000..b658cc67 --- /dev/null +++ b/flexibleengine/acceptance/data_source_flexibleengine_rds_engine_versions_test.go @@ -0,0 +1,96 @@ +package acceptance + +import ( + "fmt" + "regexp" + "testing" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccRdsEngineVersionsV3DataSource_basic(t *testing.T) { + dataSourceName := "data.flexibleengine_rds_engine_versions.test" + + dc := acceptance.InitDataSourceCheck(dataSourceName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccRdsEngineVersionsV3DataSource_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttr(dataSourceName, "type", "MySQL"), + resource.TestMatchResourceAttr(dataSourceName, "versions.#", regexp.MustCompile("\\d+")), + ), + }, + }, + }) +} + +func TestAccRdsEngineVersionsV3DataSource_PostgreSQL_basic(t *testing.T) { + dataSourceName := "data.flexibleengine_rds_engine_versions.test" + dc := acceptance.InitDataSourceCheck(dataSourceName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccRdsEngineVersionsV3DataSource_PostgreSQL_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttr(dataSourceName, "type", "PostgreSQL"), + resource.TestMatchResourceAttr(dataSourceName, "versions.#", regexp.MustCompile("\\d+")), + ), + }, + }, + }) +} + +func TestAccRdsEngineVersionsV3DataSource_SQLServer_basic(t *testing.T) { + dataSourceName := "data.flexibleengine_rds_engine_versions.test" + dc := acceptance.InitDataSourceCheck(dataSourceName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccRdsEngineVersionsV3DataSource_SQLServer_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttr(dataSourceName, "type", "SQLServer"), + resource.TestMatchResourceAttr(dataSourceName, "versions.#", regexp.MustCompile("\\d+")), + ), + }, + }, + }) +} + +func testAccRdsEngineVersionsV3DataSource_basic() string { + return fmt.Sprint(` +data "flexibleengine_rds_engine_versions" "test" { + type = "MySQL" +} +`) +} + +func testAccRdsEngineVersionsV3DataSource_PostgreSQL_basic() string { + return fmt.Sprint(` +data "flexibleengine_rds_engine_versions" "test" { + type = "PostgreSQL" +} +`) +} + +func testAccRdsEngineVersionsV3DataSource_SQLServer_basic() string { + return fmt.Sprint(` +data "flexibleengine_rds_engine_versions" "test" { + type = "SQLServer" +} +`) +} diff --git a/flexibleengine/acceptance/data_source_flexibleengine_rds_instances_test.go b/flexibleengine/acceptance/data_source_flexibleengine_rds_instances_test.go new file mode 100644 index 00000000..ebe0fc69 --- /dev/null +++ b/flexibleengine/acceptance/data_source_flexibleengine_rds_instances_test.go @@ -0,0 +1,176 @@ +package acceptance + +import ( + "fmt" + "regexp" + "testing" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccRdsInstanceDataSource_basic(t *testing.T) { + dataSourceName := "data.flexibleengine_rds_instances.test" + rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + + dc := acceptance.InitDataSourceCheck(dataSourceName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccRdsInstanceDataSource_basic(rName), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestMatchResourceAttr(dataSourceName, "instances.#", regexp.MustCompile("\\d+")), + resource.TestCheckResourceAttrSet(dataSourceName, "instances.0.name"), + ), + }, + }, + }) +} + +func TestAccRdsInstanceDataSource_ha_basic(t *testing.T) { + dataSourceName := "data.flexibleengine_rds_instances.test" + dc := acceptance.InitDataSourceCheck(dataSourceName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccRdsInstanceDataSource_ha_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestMatchResourceAttr(dataSourceName, "instances.#", regexp.MustCompile("\\d+")), + ), + }, + }, + }) +} + +func TestAccRdsInstanceDataSource_replica_basic(t *testing.T) { + dataSourceName := "data.flexibleengine_rds_instances.test" + dc := acceptance.InitDataSourceCheck(dataSourceName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccRdsInstanceDataSource_replica_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestMatchResourceAttr(dataSourceName, "instances.#", regexp.MustCompile("\\d+")), + ), + }, + }, + }) +} + +func TestAccRdsInstanceDataSource_enterprise_basic(t *testing.T) { + dataSourceName := "data.flexibleengine_rds_instances.test" + dc := acceptance.InitDataSourceCheck(dataSourceName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccRdsInstanceDataSource_enterprise_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestMatchResourceAttr(dataSourceName, "instances.#", regexp.MustCompile("\\d+")), + ), + }, + }, + }) +} + +func testAccRdsInstanceDataSource_basic(rName string) string { + return fmt.Sprintf(` +%s + +data "flexibleengine_availability_zones" "test" {} + +data "flexibleengine_networking_secgroup_v2" "test" { + name = "default" +} + +data "flexibleengine_rds_flavors_v3" "test" { + db_type = "MySQL" + db_version = "8.0" + instance_mode = "single" +} + +resource "flexibleengine_rds_instance_v3" "test" { + name = "%s" + flavor = data.flexibleengine_rds_flavors_v3.test.flavors[2].name + availability_zone = [data.flexibleengine_availability_zones.test.names[0]] + security_group_id = data.flexibleengine_networking_secgroup_v2.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + vpc_id = flexibleengine_vpc_v1.test.id + time_zone = "UTC+08:00" + fixed_ip = "192.168.0.58" + + db { + password = "FlexibleEngine!120521" + type = "MySQL" + version = "8.0" + port = 8630 + } + + volume { + type = "COMMON" + size = 50 + } + + backup_strategy { + start_time = "08:00-09:00" + keep_days = 1 + } + + tags = { + key = "value" + foo = "bar" + } +} + +data "flexibleengine_rds_instances" "test" { + depends_on = [ + flexibleengine_rds_instance_v3.test, + ] +} +`, testVpc(rName), rName) +} + +func testAccRdsInstanceDataSource_ha_basic() string { + return fmt.Sprintf(` +data "flexibleengine_rds_instances" "test" { + type = "Ha" + datastore_type = "PostgreSQL" +} +`) +} + +func testAccRdsInstanceDataSource_replica_basic() string { + return fmt.Sprintf(` +data "flexibleengine_rds_instances" "test" { + type = "Replica" + datastore_type = "PostgreSQL" +} +`) +} + +func testAccRdsInstanceDataSource_enterprise_basic() string { + return fmt.Sprintf(` +data "flexibleengine_rds_instances" "test" { + type = "Enterprise" + datastore_type = "SQLServer" + enterprise_project_id = "0" +} +`) +} diff --git a/flexibleengine/acceptance/data_source_flexibleengine_rds_storage_types_test.go b/flexibleengine/acceptance/data_source_flexibleengine_rds_storage_types_test.go new file mode 100644 index 00000000..96fed03c --- /dev/null +++ b/flexibleengine/acceptance/data_source_flexibleengine_rds_storage_types_test.go @@ -0,0 +1,105 @@ +package acceptance + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccDatasourceStoragetype_basic(t *testing.T) { + rName := "data.flexibleengine_rds_storage_types.test" + dc := acceptance.InitDataSourceCheck(rName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDatasourceStoragetype_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "db_type", "MySQL"), + resource.TestCheckResourceAttr(rName, "db_version", "8.0"), + resource.TestCheckResourceAttrSet(rName, "storage_types.0.name"), + resource.TestCheckResourceAttrSet(rName, "storage_types.0.az_status.%"), + resource.TestCheckResourceAttrSet(rName, "storage_types.0.support_compute_group_type.#"), + ), + }, + }, + }) +} + +func TestAccDatasourceStoragetype_PostgreSQL_basic(t *testing.T) { + rName := "data.flexibleengine_rds_storage_types.test" + dc := acceptance.InitDataSourceCheck(rName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDatasourceStoragetype_PostgreSQL_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "db_type", "PostgreSQL"), + resource.TestCheckResourceAttr(rName, "db_version", "14"), + resource.TestCheckResourceAttrSet(rName, "storage_types.0.name"), + resource.TestCheckResourceAttrSet(rName, "storage_types.0.az_status.%"), + resource.TestCheckResourceAttrSet(rName, "storage_types.0.support_compute_group_type.#"), + ), + }, + }, + }) +} + +func TestAccDatasourceStoragetype_SQLServer_basic(t *testing.T) { + rName := "data.flexibleengine_rds_storage_types.test" + dc := acceptance.InitDataSourceCheck(rName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDatasourceStoragetype_SQLServer_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "db_type", "SQLServer"), + resource.TestCheckResourceAttr(rName, "db_version", "2019_SE"), + resource.TestCheckResourceAttrSet(rName, "storage_types.0.name"), + resource.TestCheckResourceAttrSet(rName, "storage_types.0.az_status.%"), + resource.TestCheckResourceAttrSet(rName, "storage_types.0.support_compute_group_type.#"), + ), + }, + }, + }) +} + +func testAccDatasourceStoragetype_basic() string { + return ` +data "flexibleengine_rds_storage_types" "test" { + db_type = "MySQL" + db_version = "8.0" + instance_mode = "replica" +}` +} + +func testAccDatasourceStoragetype_PostgreSQL_basic() string { + return ` +data "flexibleengine_rds_storage_types" "test" { + db_type = "PostgreSQL" + db_version = "14" + instance_mode = "ha" +}` +} + +func testAccDatasourceStoragetype_SQLServer_basic() string { + return ` +data "flexibleengine_rds_storage_types" "test" { + db_type = "SQLServer" + db_version = "2019_SE" + instance_mode = "single" +}` +} diff --git a/flexibleengine/acceptance/resource_flexibleengine_rds_backup_test.go b/flexibleengine/acceptance/resource_flexibleengine_rds_backup_test.go new file mode 100644 index 00000000..7ded8f4d --- /dev/null +++ b/flexibleengine/acceptance/resource_flexibleengine_rds_backup_test.go @@ -0,0 +1,356 @@ +package acceptance + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +func getBackupResourceFunc(config *config.Config, state *terraform.ResourceState) (interface{}, error) { + region := OS_REGION_NAME + // getBackup: Query the RDS manual backup + var ( + getBackupHttpUrl = "v3/{project_id}/backups" + getBackupProduct = "rds" + ) + getBackupClient, err := config.NewServiceClient(getBackupProduct, region) + if err != nil { + return nil, fmt.Errorf("error creating Backup Client: %s", err) + } + + getBackupPath := getBackupClient.Endpoint + getBackupHttpUrl + getBackupPath = strings.Replace(getBackupPath, "{project_id}", getBackupClient.ProjectID, -1) + + getBackupqueryParams := fmt.Sprintf("?instance_id=%s&backup_id=%s", + state.Primary.Attributes["instance_id"], state.Primary.ID) + getBackupPath = getBackupPath + getBackupqueryParams + getBackupOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + OkCodes: []int{ + 200, + }, + } + getBackupResp, err := getBackupClient.Request("GET", getBackupPath, &getBackupOpt) + if err != nil { + return nil, fmt.Errorf("error retrieving Backup: %s", err) + } + + getBackupRespBody, err := utils.FlattenResponse(getBackupResp) + if err != nil { + return nil, fmt.Errorf("error retrieving Backup: %s", err) + } + + count := utils.PathSearch("total_count", getBackupRespBody, 0) + if fmt.Sprintf("%v", count) == "0" { + return nil, fmt.Errorf("error retrieving Backup: %s", err) + } + + return getBackupRespBody, nil +} + +func TestAccBackup_mysql_basic(t *testing.T) { + var obj interface{} + + name := acceptance.RandomAccResourceName() + rName := "flexibleengine_rds_backup.test" + rc := acceptance.InitResourceCheck( + rName, + &obj, + getBackupResourceFunc, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testBackup_mysql_basic(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "name", name), + resource.TestCheckResourceAttrPair(rName, "instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttrSet(rName, "begin_time"), + resource.TestCheckResourceAttrSet(rName, "end_time"), + resource.TestCheckResourceAttrSet(rName, "status"), + resource.TestCheckResourceAttrSet(rName, "size"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccBackupImportStateFunc(rName), + }, + }, + }) +} + +func TestAccBackup_sqlserver_basic(t *testing.T) { + var obj interface{} + + name := acceptance.RandomAccResourceName() + rName := "flexibleengine_rds_backup.test" + rc := acceptance.InitResourceCheck( + rName, + &obj, + getBackupResourceFunc, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testBackup_sqlserver_basic(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "name", name), + resource.TestCheckResourceAttrPair(rName, "instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttrSet(rName, "begin_time"), + resource.TestCheckResourceAttrSet(rName, "end_time"), + resource.TestCheckResourceAttrSet(rName, "status"), + resource.TestCheckResourceAttrSet(rName, "size"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccBackupImportStateFunc(rName), + }, + }, + }) +} + +func TestAccBackup_pg_basic(t *testing.T) { + var obj interface{} + + name := acceptance.RandomAccResourceName() + rName := "flexibleengine_rds_backup.test" + rc := acceptance.InitResourceCheck( + rName, + &obj, + getBackupResourceFunc, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testBackup_pg_basic(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttr(rName, "name", name), + resource.TestCheckResourceAttrPair(rName, "instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttrSet(rName, "begin_time"), + resource.TestCheckResourceAttrSet(rName, "end_time"), + resource.TestCheckResourceAttrSet(rName, "status"), + resource.TestCheckResourceAttrSet(rName, "size"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccBackupImportStateFunc(rName), + }, + }, + }) +} + +// disable auto_backup to prevent the instance status from changing to "BACKING UP" before manual backup creation. +func testBackup_mysql_basic(name string) string { + return fmt.Sprintf(` +%[1]s + +data "flexibleengine_availability_zones" "test" {} + +data "flexibleengine_networking_secgroup_v2" "test" { + name = "default" +} + +data "flexibleengine_rds_flavors_v3" "test" { + db_type = "MySQL" + db_version = "8.0" + instance_mode = "single" +} + +resource "flexibleengine_rds_instance_v3" "test" { + name = "%[2]s" + flavor = data.flexibleengine_rds_flavors_v3.test.flavors[2].name + availability_zone = [data.flexibleengine_availability_zones.test.names[0]] + security_group_id = data.flexibleengine_networking_secgroup_v2.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + vpc_id = flexibleengine_vpc_v1.test.id + time_zone = "UTC+08:00" + + db { + password = "FlexibleEngine!120521" + type = "MySQL" + version = "8.0" + port = 8630 + } + + volume { + type = "COMMON" + size = 60 + } + + backup_strategy { + start_time = "08:00-09:00" + keep_days = 1 + } + + lifecycle { + ignore_changes = [ + backup_strategy, + ] + } +} + +resource "flexibleengine_rds_backup" "test" { + name = "%[2]s" + instance_id = flexibleengine_rds_instance_v3.test.id +} +`, testVpc(name), name) +} + +// disable auto_backup to prevent the instance status from changing to "BACKING UP" before manual backup creation. +func testBackup_sqlserver_basic(name string) string { + return fmt.Sprintf(` +%[1]s + +data "flexibleengine_availability_zones" "test" {} + +data "flexibleengine_networking_secgroup_v2" "test" { + name = "default" +} + +data "flexibleengine_rds_flavors_v3" "test" { + db_type = "SQLServer" + db_version = "2019_SE" + instance_mode = "single" +} + +resource "flexibleengine_rds_instance_v3" "test" { + name = "%[2]s" + flavor = data.flexibleengine_rds_flavors_v3.test.flavors[0].name + availability_zone = [data.flexibleengine_availability_zones.test.names[0]] + security_group_id = data.flexibleengine_networking_secgroup_v2.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + vpc_id = flexibleengine_vpc_v1.test.id + time_zone = "UTC+08:00" + + db { + password = "FlexibleEngine!120521" + type = "SQLServer" + version = "2019_SE" + port = 8631 + } + volume { + type = "COMMON" + size = 50 + } + backup_strategy { + start_time = "08:00-09:00" + keep_days = 1 + } + + lifecycle { + ignore_changes = [ + backup_strategy, + ] + } +} + +resource "flexibleengine_rds_backup" "test" { + name = "%[2]s" + instance_id = flexibleengine_rds_instance_v3.test.id +} +`, testVpc(name), name) +} + +// disable auto_backup to prevent the instance status from changing to "BACKING UP" before manual backup creation. +func testBackup_pg_basic(name string) string { + return fmt.Sprintf(` +%[1]s + +data "flexibleengine_availability_zones" "test" {} + +data "flexibleengine_networking_secgroup_v2" "test" { + name = "default" +} + +data "flexibleengine_rds_flavors_v3" "test" { + db_type = "PostgreSQL" + db_version = "14" + instance_mode = "single" + vcpus = 8 +} + +resource "flexibleengine_rds_instance_v3" "test" { + name = "%[2]s" + flavor = data.flexibleengine_rds_flavors_v3.test.flavors[0].name + availability_zone = [data.flexibleengine_availability_zones.test.names[0]] + security_group_id = data.flexibleengine_networking_secgroup_v2.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + vpc_id = flexibleengine_vpc_v1.test.id + time_zone = "UTC+08:00" + + db { + password = "FlexibleEngine!120521" + type = "PostgreSQL" + version = "14" + port = 8632 + } + volume { + type = "COMMON" + size = 50 + } + backup_strategy { + start_time = "08:00-09:00" + keep_days = 1 + } + + lifecycle { + ignore_changes = [ + backup_strategy, + ] + } +} + +resource "flexibleengine_rds_backup" "test" { + name = "%[2]s" + instance_id = flexibleengine_rds_instance_v3.test.id +} +`, testVpc(name), name) +} + +func testAccBackupImportStateFunc(name string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[name] + if !ok { + return "", fmt.Errorf("Resource (%s) not found: %s", name, rs) + } + if rs.Primary.ID == "" || rs.Primary.Attributes["instance_id"] == "" { + return "", fmt.Errorf("resource (%s) not found: %s", name, rs) + } + return fmt.Sprintf("%s/%s", rs.Primary.Attributes["instance_id"], rs.Primary.ID), nil + } +} diff --git a/flexibleengine/acceptance/resource_flexibleengine_rds_cross_region_backup_strategy_test.go b/flexibleengine/acceptance/resource_flexibleengine_rds_cross_region_backup_strategy_test.go new file mode 100644 index 00000000..b30a42f9 --- /dev/null +++ b/flexibleengine/acceptance/resource_flexibleengine_rds_cross_region_backup_strategy_test.go @@ -0,0 +1,217 @@ +package acceptance + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +func getBackupStrategyResourceFunc(cfg *config.Config, state *terraform.ResourceState) (interface{}, error) { + region := OS_REGION_NAME + // getBackupStrategy: Query the RDS cross region backup strategy + var ( + getBackupStrategyHttpUrl = "v3/{project_id}/instances/{instance_id}/backups/offsite-policy" + getBackupStrategyProduct = "rds" + ) + getBackupStrategyClient, err := cfg.NewServiceClient(getBackupStrategyProduct, region) + if err != nil { + return nil, fmt.Errorf("error creating RDS client: %s", err) + } + + getBackupStrategyPath := getBackupStrategyClient.Endpoint + getBackupStrategyHttpUrl + getBackupStrategyPath = strings.ReplaceAll(getBackupStrategyPath, "{project_id}", getBackupStrategyClient.ProjectID) + getBackupStrategyPath = strings.ReplaceAll(getBackupStrategyPath, "{instance_id}", state.Primary.ID) + + getBackupStrategyOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + } + + getBackupStrategyResp, err := getBackupStrategyClient.Request("GET", getBackupStrategyPath, &getBackupStrategyOpt) + if err != nil { + return nil, fmt.Errorf("error retrieving RDS cross region backup strategy: %s", err) + } + + getBackupStrategyRespBody, err := utils.FlattenResponse(getBackupStrategyResp) + if err != nil { + return nil, fmt.Errorf("error retrieving RDS cross region backup strategy: %s", err) + } + + policyPara := utils.PathSearch("policy_para", getBackupStrategyRespBody, nil) + if policyPara == nil { + return nil, fmt.Errorf("error retrieving RDS cross region backup strategy: %s", err) + } + + backupStrategies := policyPara.([]interface{}) + if len(backupStrategies) == 0 || utils.PathSearch("keep_days", backupStrategies[0], 0).(float64) == 0 { + return nil, fmt.Errorf("error retrieving RDS cross region backup strategy: %s", err) + } + + return getBackupStrategyRespBody, nil +} + +func TestAccBackupStrategy_basic(t *testing.T) { + var obj interface{} + + name := acceptance.RandomAccResourceName() + rName := "flexibleengine_rds_cross_region_backup_strategy.test" + + rc := acceptance.InitResourceCheck( + rName, + &obj, + getBackupStrategyResourceFunc, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + acceptance.TestAccPreCheckReplication(t) + }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testBackupStrategy_basic(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttr(rName, "backup_type", "auto"), + resource.TestCheckResourceAttr(rName, "keep_days", "5"), + resource.TestCheckResourceAttr(rName, "destination_region", OS_DEST_REGION), + resource.TestCheckResourceAttr(rName, "destination_project_id", OS_DEST_PROJECT_ID), + ), + }, + { + Config: testBackupStrategy_basic_update1(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttr(rName, "backup_type", "all"), + resource.TestCheckResourceAttr(rName, "keep_days", "8"), + resource.TestCheckResourceAttr(rName, "destination_region", OS_DEST_REGION), + resource.TestCheckResourceAttr(rName, "destination_project_id", OS_DEST_PROJECT_ID), + ), + }, + { + Config: testBackupStrategy_basic_update2(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttr(rName, "backup_type", "auto"), + resource.TestCheckResourceAttr(rName, "keep_days", "10"), + resource.TestCheckResourceAttr(rName, "destination_region", OS_DEST_REGION), + resource.TestCheckResourceAttr(rName, "destination_project_id", OS_DEST_PROJECT_ID), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccRdsCrossRegionBackupStrategy(name string) string { + return fmt.Sprintf(` +%[1]s + +data "flexibleengine_availability_zones" "test" {} + +data "flexibleengine_networking_secgroup_v2" "test" { + name = "default" +} + +data "flexibleengine_rds_flavors_v3" "test" { + db_type = "MySQL" + db_version = "8.0" + instance_mode = "single" +} + +resource "flexibleengine_rds_instance_v3" "test" { + name = "%[2]s" + flavor = data.flexibleengine_rds_flavors_v3.test.flavors[2].name + availability_zone = [data.flexibleengine_availability_zones.test.names[0]] + security_group_id = data.flexibleengine_networking_secgroup_v2.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + vpc_id = flexibleengine_vpc_v1.test.id + time_zone = "UTC+08:00" + + db { + password = "FlexibleEngine!120521" + type = "MySQL" + version = "8.0" + port = 8630 + } + + volume { + type = "COMMON" + size = 50 + } + + backup_strategy { + start_time = "08:00-09:00" + keep_days = 1 + } + + lifecycle { + ignore_changes = [ + backup_strategy, + ] + } +} +`, testVpc(name), name) +} + +func testBackupStrategy_basic(name string) string { + return fmt.Sprintf(` +%s + +resource "flexibleengine_rds_cross_region_backup_strategy" "test" { + instance_id = flexibleengine_rds_instance_v3.test.id + backup_type = "auto" + keep_days = "5" + destination_region = "%s" + destination_project_id = "%s" +} +`, testAccRdsCrossRegionBackupStrategy(name), OS_DEST_REGION, OS_DEST_PROJECT_ID) +} + +func testBackupStrategy_basic_update1(name string) string { + return fmt.Sprintf(` +%s + +resource "flexibleengine_rds_cross_region_backup_strategy" "test" { + instance_id = flexibleengine_rds_instance_v3.test.id + backup_type = "all" + keep_days = "8" + destination_region = "%s" + destination_project_id = "%s" +} +`, testAccRdsCrossRegionBackupStrategy(name), OS_DEST_REGION, OS_DEST_PROJECT_ID) +} + +func testBackupStrategy_basic_update2(name string) string { + return fmt.Sprintf(` +%s + +resource "flexibleengine_rds_cross_region_backup_strategy" "test" { + instance_id = flexibleengine_rds_instance_v3.test.id + backup_type = "auto" + keep_days = "10" + destination_region = "%s" + destination_project_id = "%s" +} +`, testAccRdsCrossRegionBackupStrategy(name), OS_DEST_REGION, OS_DEST_PROJECT_ID) +} diff --git a/flexibleengine/acceptance/resource_flexibleengine_rds_sql_audit_test.go b/flexibleengine/acceptance/resource_flexibleengine_rds_sql_audit_test.go new file mode 100644 index 00000000..16d4a3ee --- /dev/null +++ b/flexibleengine/acceptance/resource_flexibleengine_rds_sql_audit_test.go @@ -0,0 +1,171 @@ +package acceptance + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/chnsz/golangsdk" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +func getSQLAuditResourceFunc(cfg *config.Config, state *terraform.ResourceState) (interface{}, error) { + region := OS_REGION_NAME + // getSQLAudit: Query the RDS SQL audit + var ( + getSQLAuditHttpUrl = "v3/{project_id}/instances/{instance_id}/auditlog-policy" + getSQLAuditProduct = "rds" + ) + getSQLAuditClient, err := cfg.NewServiceClient(getSQLAuditProduct, region) + if err != nil { + return nil, fmt.Errorf("error creating RDS client: %s", err) + } + + getSQLAuditPath := getSQLAuditClient.Endpoint + getSQLAuditHttpUrl + getSQLAuditPath = strings.ReplaceAll(getSQLAuditPath, "{project_id}", getSQLAuditClient.ProjectID) + getSQLAuditPath = strings.ReplaceAll(getSQLAuditPath, "{instance_id}", state.Primary.ID) + + getSQLAuditOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + MoreHeaders: map[string]string{"Content-Type": "application/json"}, + } + + getSQLAuditResp, err := getSQLAuditClient.Request("GET", getSQLAuditPath, &getSQLAuditOpt) + if err != nil { + return nil, fmt.Errorf("error retrieving RDS SQL audit: %s", err) + } + + getSQLAuditRespBody, err := utils.FlattenResponse(getSQLAuditResp) + if err != nil { + return nil, fmt.Errorf("error retrieving RDS SQL audit: %s", err) + } + + keepDays := utils.PathSearch("keep_days", getSQLAuditRespBody, 0).(float64) + if keepDays == 0 { + return nil, fmt.Errorf("error retrieving RDS SQL audit: %s", err) + } + + return getSQLAuditRespBody, nil +} + +func TestAccSQLAudit_basic(t *testing.T) { + var obj interface{} + name := acceptance.RandomAccResourceName() + rName := "flexibleengine_rds_sql_audit.test" + + rc := acceptance.InitResourceCheck( + rName, + &obj, + getSQLAuditResourceFunc, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testSQLAudit_basic(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttr(rName, "keep_days", "5"), + ), + }, + { + Config: testSQLAudit_basic_update(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "instance_id", + "flexibleengine_rds_instance_v3.test", "id"), + resource.TestCheckResourceAttr(rName, "keep_days", "9"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccRdsSqlAudit_base(name string) string { + return fmt.Sprintf(` +%[1]s + +data "flexibleengine_availability_zones" "test" {} + +data "flexibleengine_networking_secgroup_v2" "test" { + name = "default" +} + +data "flexibleengine_rds_flavors_v3" "test" { + db_type = "MySQL" + db_version = "8.0" + instance_mode = "single" +} + +resource "flexibleengine_rds_instance_v3" "test" { + name = "%[2]s" + flavor = data.flexibleengine_rds_flavors_v3.test.flavors[2].name + availability_zone = [data.flexibleengine_availability_zones.test.names[0]] + security_group_id = data.flexibleengine_networking_secgroup_v2.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + vpc_id = flexibleengine_vpc_v1.test.id + time_zone = "UTC+08:00" + + db { + password = "FlexibleEngine!120521" + type = "MySQL" + version = "8.0" + port = 8630 + } + + volume { + type = "COMMON" + size = 50 + } + + backup_strategy { + start_time = "08:00-09:00" + keep_days = 1 + } + + lifecycle { + ignore_changes = [ + backup_strategy, + ] + } +} +`, testVpc(name), name) +} + +func testSQLAudit_basic(name string) string { + return fmt.Sprintf(` +%s + +resource "flexibleengine_rds_sql_audit" "test" { + instance_id = flexibleengine_rds_instance_v3.test.id + keep_days = "5" +} +`, testAccRdsSqlAudit_base(name)) +} + +func testSQLAudit_basic_update(name string) string { + return fmt.Sprintf(` +%s + +resource "flexibleengine_rds_sql_audit" "test" { + instance_id = flexibleengine_rds_instance_v3.test.id + keep_days = "9" +} +`, testAccRdsSqlAudit_base(name)) +} diff --git a/flexibleengine/provider.go b/flexibleengine/provider.go index 7b666ee5..c194fa05 100644 --- a/flexibleengine/provider.go +++ b/flexibleengine/provider.go @@ -307,9 +307,15 @@ func Provider() *schema.Provider { "flexibleengine_images_image": ims.DataSourceImagesImageV2(), "flexibleengine_images_images": ims.DataSourceImagesImages(), - "flexibleengine_networking_port": vpc.DataSourceNetworkingPortV2(), - "flexibleengine_identity_group": iam.DataSourceIdentityGroup(), - "flexibleengine_identity_users": iam.DataSourceIdentityUsers(), + "flexibleengine_networking_port": vpc.DataSourceNetworkingPortV2(), + "flexibleengine_identity_group": iam.DataSourceIdentityGroup(), + "flexibleengine_identity_users": iam.DataSourceIdentityUsers(), + + "flexibleengine_rds_backups": rds.DataSourceBackup(), + "flexibleengine_rds_engine_versions": rds.DataSourceRdsEngineVersionsV3(), + "flexibleengine_rds_instances": rds.DataSourceRdsInstances(), + "flexibleengine_rds_storage_types": rds.DataSourceStoragetype(), + "flexibleengine_sfs_turbos": sfs.DataSourceTurbos(), "flexibleengine_smn_topics": smn.DataSourceTopics(), "flexibleengine_sms_source_servers": sms.DataSourceServers(), @@ -519,9 +525,13 @@ func Provider() *schema.Provider { "flexibleengine_obs_bucket_acl": obs.ResourceOBSBucketAcl(), - "flexibleengine_rds_account": rds.ResourceMysqlAccount(), - "flexibleengine_rds_database": rds.ResourceMysqlDatabase(), - "flexibleengine_rds_database_privilege": rds.ResourceMysqlDatabasePrivilege(), + "flexibleengine_rds_account": rds.ResourceMysqlAccount(), + "flexibleengine_rds_backup": rds.ResourceBackup(), + "flexibleengine_rds_cross_region_backup_strategy": rds.ResourceBackupStrategy(), + "flexibleengine_rds_database": rds.ResourceMysqlDatabase(), + "flexibleengine_rds_database_privilege": rds.ResourceMysqlDatabasePrivilege(), + "flexibleengine_rds_sql_audit": rds.ResourceSQLAudit(), + "flexibleengine_sms_server_template": sms.ResourceServerTemplate(), "flexibleengine_sms_task": sms.ResourceMigrateTask(), "flexibleengine_swr_organization": swr.ResourceSWROrganization(),