From c4b66bbce3db73e880714d425745bdc9cb23f211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=93=B2=E9=93=AD?= Date: Tue, 18 Apr 2023 12:17:53 +0000 Subject: [PATCH 1/9] feat: add rds mysql v2 * feat: add rds mysql allowlist and allowlist_associate * feat: opt allowlist_associate read func * fix: fix allowlist err * feat: rename(mysql_rds to rds_mysql) and opt param * feat:support rds mysql account and database. * fix:add update timeout for rds mysql account&database. * sort out code. * feat: add rds mysql allowlist and allowlist_associate * feat: opt allowlist_associate read func * fix: fix allowlist err * feat: rename(mysql_rds to rds_mysql) and opt param * feat:support rds mysql account and database. * fix:add update timeout for rds mysql account&database. * sort out code. * feat: support rds_mysql_instance * update rds_mysql document * feat: add refresh delay time * feat: opt readonly node * feat: opt mysql account code * feat: opt rds mysql database * feat: add doc and version * feat: opt rds account create * feat: add retry in rds v2 * feat: add doc and version * feat: support tos bucket policy * Merge branch 'feat/tos_bucket_policy' into 'feat/addRdsV2' https://code.byted.org/iaasng/terraform-provider-volcengine/merge_requests/170 --- common/common_volcengine_version.go | 2 +- docgen/main.go | 1 + example/dataRdsMysqlAccounts/main.tf | 4 + example/dataRdsMysqlAllowlists/main.tf | 3 + example/dataRdsMysqlDatabases/main.tf | 4 + example/dataRdsMysqlInstances/main.tf | 3 + example/rdsMysqlAccount/main.tf | 16 + example/rdsMysqlAllowlist/main.tf | 7 + example/rdsMysqlAllowlistAssociate/main.tf | 4 + example/rdsMysqlDatabase/main.tf | 5 + example/rdsMysqlInstance/main.tf | 31 + example/rdsMysqlInstanceReadonlyNode/main.tf | 5 + example/tosBucketPolicy/main.tf | 20 + volcengine/provider.go | 38 +- ..._source_volcengine_rds_mysql_allowlists.go | 102 +++ ...resource_volcengine_rds_mysql_allowlist.go | 104 +++ .../service_volcengine_rds_mysql_allowlist.go | 256 ++++++ ...olcengine_rds_mysql_allowlist_associate.go | 93 +++ ...olcengine_rds_mysql_allowlist_associate.go | 163 ++++ .../common_volcengine_rds_mysql_account.go | 72 ++ ...ta_source_volcengine_rds_mysql_accounts.go | 95 +++ .../resource_volcengine_rds_mysql_account.go | 138 ++++ .../service_volcengine_rds_mysql_account.go | 358 +++++++++ .../common_volcengine_rds_mysql_database.go | 22 + ...a_source_volcengine_rds_mysql_databases.go | 91 +++ .../resource_volcengine_rds_mysql_database.go | 82 ++ .../service_volcengine_rds_mysql_database.go | 231 ++++++ .../common_volcengine_rds_mysql_instance.go | 29 + ...a_source_volcengine_rds_mysql_instances.go | 473 +++++++++++ .../resource_volcengine_rds_mysql_instance.go | 207 +++++ .../service_volcengine_rds_mysql_instance.go | 740 ++++++++++++++++++ ...engine_rds_mysql_instance_readonly_node.go | 22 + ...engine_rds_mysql_instance_readonly_node.go | 96 +++ ...engine_rds_mysql_instance_readonly_node.go | 397 ++++++++++ .../service_volcengine_rds_instance_v2.go | 15 +- .../bucket/resource_volcengine_tos_bucket.go | 2 +- .../resource_volcengine_tos_bucket_policy.go | 152 ++++ .../service_volcengine_tos_bucket_policy.go | 230 ++++++ .../docs/d/rds_mysql_accounts.html.markdown | 37 + .../docs/d/rds_mysql_allowlists.html.markdown | 38 + .../docs/d/rds_mysql_databases.html.markdown | 36 + .../docs/d/rds_mysql_instances.html.markdown | 127 +++ .../docs/r/rds_mysql_account.html.markdown | 67 ++ .../docs/r/rds_mysql_allowlist.html.markdown | 39 + ...ds_mysql_allowlist_associate.html.markdown | 34 + .../docs/r/rds_mysql_database.html.markdown | 42 + .../docs/r/rds_mysql_instance.html.markdown | 175 +++++ ...mysql_instance_readonly_node.html.markdown | 36 + website/docs/r/tos_bucket.html.markdown | 2 +- .../docs/r/tos_bucket_policy.html.markdown | 50 ++ website/volcengine.erb | 33 + 51 files changed, 5016 insertions(+), 13 deletions(-) create mode 100644 example/dataRdsMysqlAccounts/main.tf create mode 100644 example/dataRdsMysqlAllowlists/main.tf create mode 100644 example/dataRdsMysqlDatabases/main.tf create mode 100644 example/dataRdsMysqlInstances/main.tf create mode 100644 example/rdsMysqlAccount/main.tf create mode 100644 example/rdsMysqlAllowlist/main.tf create mode 100644 example/rdsMysqlAllowlistAssociate/main.tf create mode 100644 example/rdsMysqlDatabase/main.tf create mode 100644 example/rdsMysqlInstance/main.tf create mode 100644 example/rdsMysqlInstanceReadonlyNode/main.tf create mode 100644 example/tosBucketPolicy/main.tf create mode 100644 volcengine/rds_mysql/allowlist/data_source_volcengine_rds_mysql_allowlists.go create mode 100644 volcengine/rds_mysql/allowlist/resource_volcengine_rds_mysql_allowlist.go create mode 100644 volcengine/rds_mysql/allowlist/service_volcengine_rds_mysql_allowlist.go create mode 100644 volcengine/rds_mysql/allowlist_associate/resource_volcengine_rds_mysql_allowlist_associate.go create mode 100644 volcengine/rds_mysql/allowlist_associate/service_volcengine_rds_mysql_allowlist_associate.go create mode 100644 volcengine/rds_mysql/rds_mysql_account/common_volcengine_rds_mysql_account.go create mode 100644 volcengine/rds_mysql/rds_mysql_account/data_source_volcengine_rds_mysql_accounts.go create mode 100644 volcengine/rds_mysql/rds_mysql_account/resource_volcengine_rds_mysql_account.go create mode 100644 volcengine/rds_mysql/rds_mysql_account/service_volcengine_rds_mysql_account.go create mode 100644 volcengine/rds_mysql/rds_mysql_database/common_volcengine_rds_mysql_database.go create mode 100644 volcengine/rds_mysql/rds_mysql_database/data_source_volcengine_rds_mysql_databases.go create mode 100644 volcengine/rds_mysql/rds_mysql_database/resource_volcengine_rds_mysql_database.go create mode 100644 volcengine/rds_mysql/rds_mysql_database/service_volcengine_rds_mysql_database.go create mode 100644 volcengine/rds_mysql/rds_mysql_instance/common_volcengine_rds_mysql_instance.go create mode 100644 volcengine/rds_mysql/rds_mysql_instance/data_source_volcengine_rds_mysql_instances.go create mode 100644 volcengine/rds_mysql/rds_mysql_instance/resource_volcengine_rds_mysql_instance.go create mode 100644 volcengine/rds_mysql/rds_mysql_instance/service_volcengine_rds_mysql_instance.go create mode 100644 volcengine/rds_mysql/rds_mysql_instance_readonly_node/common_volcengine_rds_mysql_instance_readonly_node.go create mode 100644 volcengine/rds_mysql/rds_mysql_instance_readonly_node/resource_volcengine_rds_mysql_instance_readonly_node.go create mode 100644 volcengine/rds_mysql/rds_mysql_instance_readonly_node/service_volcengine_rds_mysql_instance_readonly_node.go create mode 100644 volcengine/tos/bucket_policy/resource_volcengine_tos_bucket_policy.go create mode 100644 volcengine/tos/bucket_policy/service_volcengine_tos_bucket_policy.go create mode 100644 website/docs/d/rds_mysql_accounts.html.markdown create mode 100644 website/docs/d/rds_mysql_allowlists.html.markdown create mode 100644 website/docs/d/rds_mysql_databases.html.markdown create mode 100644 website/docs/d/rds_mysql_instances.html.markdown create mode 100644 website/docs/r/rds_mysql_account.html.markdown create mode 100644 website/docs/r/rds_mysql_allowlist.html.markdown create mode 100644 website/docs/r/rds_mysql_allowlist_associate.html.markdown create mode 100644 website/docs/r/rds_mysql_database.html.markdown create mode 100644 website/docs/r/rds_mysql_instance.html.markdown create mode 100644 website/docs/r/rds_mysql_instance_readonly_node.html.markdown create mode 100644 website/docs/r/tos_bucket_policy.html.markdown diff --git a/common/common_volcengine_version.go b/common/common_volcengine_version.go index e6886513..dfddd03e 100644 --- a/common/common_volcengine_version.go +++ b/common/common_volcengine_version.go @@ -2,5 +2,5 @@ package common const ( TerraformProviderName = "terraform-provider-volcengine" - TerraformProviderVersion = "0.0.67" + TerraformProviderVersion = "0.0.68" ) diff --git a/docgen/main.go b/docgen/main.go index aff19013..680e9216 100644 --- a/docgen/main.go +++ b/docgen/main.go @@ -130,6 +130,7 @@ var resourceKeys = map[string]string{ "autoscaling": "AUTOSCALING", "mongodb": "MONGODB", "bioos": "BIOOS", + "rds_mysql": "RDS_MYSQL", } type Products struct { diff --git a/example/dataRdsMysqlAccounts/main.tf b/example/dataRdsMysqlAccounts/main.tf new file mode 100644 index 00000000..f82b2e39 --- /dev/null +++ b/example/dataRdsMysqlAccounts/main.tf @@ -0,0 +1,4 @@ +data "volcengine_rds_mysql_accounts" "default"{ + instance_id="mysql-47d6bc58762b" + account_name="" +} \ No newline at end of file diff --git a/example/dataRdsMysqlAllowlists/main.tf b/example/dataRdsMysqlAllowlists/main.tf new file mode 100644 index 00000000..c8e8a3ca --- /dev/null +++ b/example/dataRdsMysqlAllowlists/main.tf @@ -0,0 +1,3 @@ +data "volcengine_rds_mysql_allowlists" "default" { + region_id = "cn-guilin-boe" +} \ No newline at end of file diff --git a/example/dataRdsMysqlDatabases/main.tf b/example/dataRdsMysqlDatabases/main.tf new file mode 100644 index 00000000..c4d4c026 --- /dev/null +++ b/example/dataRdsMysqlDatabases/main.tf @@ -0,0 +1,4 @@ +data "volcengine_rds_mysql_databases" "default"{ + instance_id="" + db_name="" +} \ No newline at end of file diff --git a/example/dataRdsMysqlInstances/main.tf b/example/dataRdsMysqlInstances/main.tf new file mode 100644 index 00000000..597b4cad --- /dev/null +++ b/example/dataRdsMysqlInstances/main.tf @@ -0,0 +1,3 @@ +data "volcengine_rds_mysql_instances" "default" { + instance_id = "mysql-72da4258c2c7" +} \ No newline at end of file diff --git a/example/rdsMysqlAccount/main.tf b/example/rdsMysqlAccount/main.tf new file mode 100644 index 00000000..40d13eb7 --- /dev/null +++ b/example/rdsMysqlAccount/main.tf @@ -0,0 +1,16 @@ +resource "volcengine_rds_mysql_account" "default"{ + instance_id="mysql-e9293705eed6" + account_name="test" + account_password="xdjsuiahHUH@" + account_type="Normal" +# account_privileges{ +# db_name="tf-test-dbdddddd" +# account_privilege="ReadOnly" +# account_privilege_detail="SELECT,UPDATE,INSERT" +# } +# account_privileges{ +# db_name="test-xx" +# account_privilege="ReadOnly" +# account_privilege_detail="SELECT,UPDATE,INSERT" +# } +} \ No newline at end of file diff --git a/example/rdsMysqlAllowlist/main.tf b/example/rdsMysqlAllowlist/main.tf new file mode 100644 index 00000000..6b0b0b1b --- /dev/null +++ b/example/rdsMysqlAllowlist/main.tf @@ -0,0 +1,7 @@ +resource "volcengine_rds_mysql_allowlist" "foo" { + allow_list_name = "tf-test-opt" + allow_list_desc = "terraform test zzm" + allow_list = [ + "127.0.0.1" + ] +} \ No newline at end of file diff --git a/example/rdsMysqlAllowlistAssociate/main.tf b/example/rdsMysqlAllowlistAssociate/main.tf new file mode 100644 index 00000000..2e1e287e --- /dev/null +++ b/example/rdsMysqlAllowlistAssociate/main.tf @@ -0,0 +1,4 @@ +resource "volcengine_rds_mysql_allowlist_associate" "foo" { + instance_id = "mysql-1b2c7b2d7583" + allow_list_id = "acl-15451212dcfa473baeda24be4baa02fe" +} \ No newline at end of file diff --git a/example/rdsMysqlDatabase/main.tf b/example/rdsMysqlDatabase/main.tf new file mode 100644 index 00000000..7d10d6ab --- /dev/null +++ b/example/rdsMysqlDatabase/main.tf @@ -0,0 +1,5 @@ +resource "volcengine_rds_mysql_database" "default"{ + instance_id="mysql-xxx" + db_name="xxx" + character_set_name="utf8" +} diff --git a/example/rdsMysqlInstance/main.tf b/example/rdsMysqlInstance/main.tf new file mode 100644 index 00000000..8765ccc0 --- /dev/null +++ b/example/rdsMysqlInstance/main.tf @@ -0,0 +1,31 @@ +resource "volcengine_rds_mysql_instance" "foo" { + db_engine_version = "MySQL_5_7" + node_spec = "rds.mysql.1c2g" + primary_zone_id = "cn-guilin-a" + secondary_zone_id = "cn-guilin-b" + storage_space = 80 + subnet_id = "subnet-2d72yi377stts58ozfdrlk9f6" + instance_name = "tf-test" + lower_case_table_names = "1" + + charge_info { + charge_type = "PostPaid" + } + + allow_list_ids = ["acl-2dd8f8317e4d4159b21630d13ae2e6ec", "acl-2eaa2a053b2a4a58b988e38ae975e81c"] + + parameters { + parameter_name = "auto_increment_increment" + parameter_value = "2" + } + parameters { + parameter_name = "auto_increment_offset" + parameter_value = "4" + } +} + +resource "volcengine_rds_mysql_instance_readonly_node" "readonly" { + instance_id = volcengine_rds_mysql_instance.foo.id + node_spec = "rds.mysql.2c4g" + zone_id = "cn-guilin-a" +} \ No newline at end of file diff --git a/example/rdsMysqlInstanceReadonlyNode/main.tf b/example/rdsMysqlInstanceReadonlyNode/main.tf new file mode 100644 index 00000000..9121f954 --- /dev/null +++ b/example/rdsMysqlInstanceReadonlyNode/main.tf @@ -0,0 +1,5 @@ +resource "volcengine_rds_mysql_instance_readonly_node" "foo" { + instance_id = "mysql-b3fca7f571d6" + node_spec = "rds.mysql.1c2g" + zone_id = "cn-guilin-b" +} \ No newline at end of file diff --git a/example/tosBucketPolicy/main.tf b/example/tosBucketPolicy/main.tf new file mode 100644 index 00000000..4a5222d3 --- /dev/null +++ b/example/tosBucketPolicy/main.tf @@ -0,0 +1,20 @@ +resource "volcengine_tos_bucket_policy" "default" { + bucket_name = "bucket-20230418" + policy = jsonencode({ + Statement = [ + { + Sid = "test" + Effect = "Allow" + Principal = [ + "AccountId/subUserName" + ] + Action = [ + "tos:List*" + ] + Resource = [ + "trn:tos:::bucket-20230418" + ] + } + ] + }) +} \ No newline at end of file diff --git a/volcengine/provider.go b/volcengine/provider.go index ccc6b88c..1f3dce70 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -4,9 +4,12 @@ import ( "strings" "github.com/volcengine/terraform-provider-volcengine/volcengine/mongodb/ssl_state" + "github.com/volcengine/terraform-provider-volcengine/volcengine/tos/bucket_policy" "github.com/volcengine/terraform-provider-volcengine/volcengine/mongodb/spec" + "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_mysql/rds_mysql_account" + "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_mysql/rds_mysql_database" "github.com/volcengine/terraform-provider-volcengine/volcengine/vke/kubeconfig" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -88,6 +91,10 @@ import ( "github.com/volcengine/terraform-provider-volcengine/volcengine/rds/rds_instance" "github.com/volcengine/terraform-provider-volcengine/volcengine/rds/rds_ip_list" "github.com/volcengine/terraform-provider-volcengine/volcengine/rds/rds_parameter_template" + "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_mysql/allowlist" + "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_mysql/allowlist_associate" + "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_mysql/rds_mysql_instance" + "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_mysql/rds_mysql_instance_readonly_node" "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_v2/rds_instance_v2" "github.com/volcengine/terraform-provider-volcengine/volcengine/tos/bucket" "github.com/volcengine/terraform-provider-volcengine/volcengine/tos/object" @@ -258,9 +265,6 @@ func Provider() terraform.ResourceProvider { "volcengine_rds_ip_lists": rds_ip_list.DataSourceVolcengineRdsIpLists(), "volcengine_rds_parameter_templates": rds_parameter_template.DataSourceVolcengineRdsParameterTemplates(), - // ================ RDS V2 ============== - "volcengine_rds_instances_v2": rds_instance_v2.DataSourceVolcengineRdsInstances(), - // ================ ESCloud ============= "volcengine_escloud_instances": instance.DataSourceVolcengineESCloudInstances(), "volcengine_escloud_regions": region.DataSourceVolcengineESCloudRegions(), @@ -301,6 +305,15 @@ func Provider() terraform.ResourceProvider { // ================ Bioos ================== "volcengine_bioos_clusters": bioosCluster.DataSourceVolcengineBioosClusters(), "volcengine_bioos_workspaces": workspace.DataSourceVolcengineBioosWorkspaces(), + + // ================ RDS V2 ============== + "volcengine_rds_instances_v2": rds_instance_v2.DataSourceVolcengineRdsInstances(), + + // ================ RdsMysql ================ + "volcengine_rds_mysql_instances": rds_mysql_instance.DataSourceVolcengineRdsMysqlInstances(), + "volcengine_rds_mysql_accounts": rds_mysql_account.DataSourceVolcengineRdsMysqlAccounts(), + "volcengine_rds_mysql_databases": rds_mysql_database.DataSourceVolcengineRdsMysqlDatabases(), + "volcengine_rds_mysql_allowlists": allowlist.DataSourceVolcengineRdsMysqlAllowLists(), }, ResourcesMap: map[string]*schema.Resource{ "volcengine_vpc": vpc.ResourceVolcengineVpc(), @@ -397,15 +410,13 @@ func Provider() terraform.ResourceProvider { "volcengine_rds_account_privilege": rds_account_privilege.ResourceVolcengineRdsAccountPrivilege(), "volcengine_rds_parameter_template": rds_parameter_template.ResourceVolcengineRdsParameterTemplate(), - // ================ RDS V2 ============== - "volcengine_rds_instance_v2": rds_instance_v2.ResourceVolcengineRdsInstance(), - // ================ ESCloud ================ "volcengine_escloud_instance": instance.ResourceVolcengineESCloudInstance(), //================= TOS ================= - "volcengine_tos_bucket": bucket.ResourceVolcengineTosBucket(), - "volcengine_tos_object": object.ResourceVolcengineTosObject(), + "volcengine_tos_bucket": bucket.ResourceVolcengineTosBucket(), + "volcengine_tos_object": object.ResourceVolcengineTosObject(), + "volcengine_tos_bucket_policy": bucket_policy.ResourceVolcengineTosBucketPolicy(), // ================ CR ================ "volcengine_cr_registry": cr_registry.ResourceVolcengineCrRegistry(), @@ -433,6 +444,17 @@ func Provider() terraform.ResourceProvider { "volcengine_bioos_cluster": bioosCluster.ResourceVolcengineBioosCluster(), "volcengine_bioos_workspace": workspace.ResourceVolcengineBioosWorkspace(), "volcengine_bioos_cluster_bind": cluster_bind.ResourceVolcengineBioosClusterBind(), + + // ================ RDS V2 ============== + "volcengine_rds_instance_v2": rds_instance_v2.ResourceVolcengineRdsInstance(), + + // ================ RdsMysql ================ + "volcengine_rds_mysql_instance": rds_mysql_instance.ResourceVolcengineRdsMysqlInstance(), + "volcengine_rds_mysql_instance_readonly_node": rds_mysql_instance_readonly_node.ResourceVolcengineRdsMysqlInstanceReadonlyNode(), + "volcengine_rds_mysql_account": rds_mysql_account.ResourceVolcengineRdsMysqlAccount(), + "volcengine_rds_mysql_database": rds_mysql_database.ResourceVolcengineRdsMysqlDatabase(), + "volcengine_rds_mysql_allowlist": allowlist.ResourceVolcengineRdsMysqlAllowlist(), + "volcengine_rds_mysql_allowlist_associate": allowlist_associate.ResourceVolcengineRdsMysqlAllowlistAssociate(), }, ConfigureFunc: ProviderConfigure, } diff --git a/volcengine/rds_mysql/allowlist/data_source_volcengine_rds_mysql_allowlists.go b/volcengine/rds_mysql/allowlist/data_source_volcengine_rds_mysql_allowlists.go new file mode 100644 index 00000000..274794b0 --- /dev/null +++ b/volcengine/rds_mysql/allowlist/data_source_volcengine_rds_mysql_allowlists.go @@ -0,0 +1,102 @@ +package allowlist + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + volc "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineRdsMysqlAllowLists() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineRdsMysqlAllowListsRead, + Schema: map[string]*schema.Schema{ + "region_id": { + Required: true, + Type: schema.TypeString, + Description: "The region of the allow lists.", + }, + "instance_id": { + Type: schema.TypeString, + Optional: true, + Description: "Instance ID. When an InstanceId is specified, the DescribeAllowLists interface will return the whitelist bound to the specified instance.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of Scaling Activity query.", + }, + "allow_lists": { + Description: "The list of allowed list.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow_list_desc": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the allow list.", + }, + "allow_list_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the allow list.", + }, + "allow_list_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the allow list.", + }, + "allow_list_ip_num": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of IP addresses (or address ranges) in the whitelist.", + }, + "allow_list_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the allow list.", + }, + "associated_instance_num": { + Type: schema.TypeInt, + Computed: true, + Description: "The total number of instances bound under the whitelist.", + }, + "associated_instances": { + Type: schema.TypeList, + Computed: true, + Description: "The list of instances.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the instance.", + }, + "instance_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the instance.", + }, + "vpc": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the vpc.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineRdsMysqlAllowListsRead(d *schema.ResourceData, meta interface{}) error { + service := NewRdsMysqlAllowListService(meta.(*volc.SdkClient)) + return service.Dispatcher.Data(service, d, DataSourceVolcengineRdsMysqlAllowLists()) +} diff --git a/volcengine/rds_mysql/allowlist/resource_volcengine_rds_mysql_allowlist.go b/volcengine/rds_mysql/allowlist/resource_volcengine_rds_mysql_allowlist.go new file mode 100644 index 00000000..4bc96642 --- /dev/null +++ b/volcengine/rds_mysql/allowlist/resource_volcengine_rds_mysql_allowlist.go @@ -0,0 +1,104 @@ +package allowlist + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + volc "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +RDS AllowList can be imported using the id, e.g. +``` +$ terraform import volcengine_rds_mysql_allowlist.default acl-d1fd76693bd54e658912e7337d5b**** +``` + +*/ + +func ResourceVolcengineRdsMysqlAllowlist() *schema.Resource { + return &schema.Resource{ + Create: resourceVolcengineRdsMysqlAllowlistCreate, + Read: resourceVolcengineRdsMysqlAllowlistRead, + Update: resourceVolcengineRdsMysqlAllowlistUpdate, + Delete: resourceVolcengineRdsMysqlAllowlistDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "allow_list_name": { + Type: schema.TypeString, + Required: true, + Description: "The name of the allow list.", + }, + "allow_list_desc": { + Type: schema.TypeString, + Optional: true, + Description: "The description of the allow list.", + }, + "allow_list_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The type of IP address in the whitelist. Currently only IPv4 addresses are supported.", + }, + "allow_list": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + Description: "Enter an IP address or a range of IP addresses in CIDR format.", + }, + "allow_list_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the allow list.", + }, + }, + } +} + +func resourceVolcengineRdsMysqlAllowlistCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewRdsMysqlAllowListService(meta.(*volc.SdkClient)) + err = service.Dispatcher.Create(service, d, ResourceVolcengineRdsMysqlAllowlist()) + if err != nil { + return fmt.Errorf("error creating RDS Mysql Allowlist service: %q, %w", d.Id(), err) + } + return resourceVolcengineRdsMysqlAllowlistRead(d, meta) +} + +func resourceVolcengineRdsMysqlAllowlistRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewRdsMysqlAllowListService(meta.(*volc.SdkClient)) + err = service.Dispatcher.Read(service, d, ResourceVolcengineRdsMysqlAllowlist()) + if err != nil { + return fmt.Errorf("error reading RDS Mysql Allowlist service: %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcengineRdsMysqlAllowlistUpdate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewRdsMysqlAllowListService(meta.(*volc.SdkClient)) + err = service.Dispatcher.Update(service, d, ResourceVolcengineRdsMysqlAllowlist()) + if err != nil { + return fmt.Errorf("error updating RDS Mysql Allowlist service: %q, %w", d.Id(), err) + } + return resourceVolcengineRdsMysqlAllowlistRead(d, meta) +} + +func resourceVolcengineRdsMysqlAllowlistDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewRdsMysqlAllowListService(meta.(*volc.SdkClient)) + err = service.Dispatcher.Delete(service, d, ResourceVolcengineRdsMysqlAllowlist()) + if err != nil { + return fmt.Errorf("error deleting RDS Mysql Allowlist service: %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/rds_mysql/allowlist/service_volcengine_rds_mysql_allowlist.go b/volcengine/rds_mysql/allowlist/service_volcengine_rds_mysql_allowlist.go new file mode 100644 index 00000000..5a7d5bd3 --- /dev/null +++ b/volcengine/rds_mysql/allowlist/service_volcengine_rds_mysql_allowlist.go @@ -0,0 +1,256 @@ +package allowlist + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + volc "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineRdsMysqlAllowListService struct { + Client *volc.SdkClient + Dispatcher *volc.Dispatcher +} + +func (s *VolcengineRdsMysqlAllowListService) GetClient() *volc.SdkClient { + return s.Client +} + +func (s *VolcengineRdsMysqlAllowListService) ReadResources(condition map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return volc.WithSimpleQuery(condition, func(m map[string]interface{}) ([]interface{}, error) { + action := "DescribeAllowLists" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + results, err = volc.ObtainSdkValue("Result.AllowLists", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.AllowLists is not slice ") + } + for index, ele := range data { + allowList := ele.(map[string]interface{}) + query := map[string]interface{}{ + "AllowListId": allowList["AllowListId"], + } + action = "DescribeAllowListDetail" + logger.Debug(logger.ReqFormat, action, query) + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &query) + if err != nil { + return data, err + } + logger.Debug(logger.RespFormat, action, query, *resp) + instances, err := volc.ObtainSdkValue("Result.AssociatedInstances", *resp) + if err != nil { + return data, err + } + data[index].(map[string]interface{})["AssociatedInstances"] = instances + } + return data, err + }) +} + +func (s *VolcengineRdsMysqlAllowListService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ) + if id == "" { + id = s.ReadResourceId(resourceData.Id()) + } + req := map[string]interface{}{ + "RegionId": s.Client.Region, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + result, ok := v.(map[string]interface{}) + if !ok { + return data, errors.New("Value is not map ") + } + if result["AllowListId"].(string) == id { + data = result + } + } + if len(data) == 0 { + return data, fmt.Errorf("Rds instance %s not exist ", id) + } + return data, err +} + +func (s *VolcengineRdsMysqlAllowListService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{} +} + +func (s *VolcengineRdsMysqlAllowListService) WithResourceResponseHandlers(m map[string]interface{}) []volc.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]volc.ResponseConvert, error) { + return m, map[string]volc.ResponseConvert{}, nil + } + return []volc.ResourceResponseHandler{handler} +} + +func (s *VolcengineRdsMysqlAllowListService) CreateResource(data *schema.ResourceData, resource *schema.Resource) []volc.Callback { + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "CreateAllowList", + ConvertMode: volc.RequestConvertAll, + ContentType: volc.ContentTypeJson, + Convert: map[string]volc.RequestConvert{ + "allow_list": { + Ignore: true, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (bool, error) { + var allowStrings []string + allowListsSet := d.Get("allow_list").(*schema.Set) + allowLists := allowListsSet.List() + for _, list := range allowLists { + allowStrings = append(allowStrings, list.(string)) + } + lists := strings.Join(allowStrings, ",") + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam, lists) + (*call.SdkParam)["AllowList"] = lists + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *volc.SdkClient, resp *map[string]interface{}, call volc.SdkCall) error { + id, _ := volc.ObtainSdkValue("Result.AllowListId", *resp) + d.SetId(id.(string)) + return nil + }, + }, + } + return []volc.Callback{callback} +} + +func (s *VolcengineRdsMysqlAllowListService) ModifyResource(data *schema.ResourceData, resource *schema.Resource) []volc.Callback { + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "ModifyAllowList", + ConvertMode: volc.RequestConvertInConvert, + ContentType: volc.ContentTypeJson, + Convert: map[string]volc.RequestConvert{ + "allow_list": { + Ignore: true, + }, + "apply_instance_num": { + Ignore: true, + }, + "allow_list_desc": { + ForceGet: true, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (bool, error) { + var allowStrings []string + // 修改allowList必须传ApplyInstanceNum + resp, err := s.ReadResource(d, d.Id()) + if err != nil { + return false, err + } + num := resp["AssociatedInstanceNum"].(float64) + (*call.SdkParam)["ApplyInstanceNum"] = int(num) + allowListsSet := d.Get("allow_list").(*schema.Set) + allowLists := allowListsSet.List() + for _, list := range allowLists { + allowStrings = append(allowStrings, list.(string)) + } + lists := strings.Join(allowStrings, ",") + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam, lists) + (*call.SdkParam)["AllowList"] = lists + return true, nil + }, + SdkParam: &map[string]interface{}{ + "AllowListId": data.Id(), + "AllowListName": data.Get("allow_list_name").(string), + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + return []volc.Callback{callback} +} + +func (s *VolcengineRdsMysqlAllowListService) RemoveResource(data *schema.ResourceData, resource *schema.Resource) []volc.Callback { + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "DeleteAllowList", + ConvertMode: volc.RequestConvertIgnore, + ContentType: volc.ContentTypeJson, + SdkParam: &map[string]interface{}{ + "AllowListId": data.Id(), + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + return []volc.Callback{callback} +} + +func (s *VolcengineRdsMysqlAllowListService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) volc.DataSourceInfo { + return volc.DataSourceInfo{ + ContentType: volc.ContentTypeJson, + NameField: "AllowListName", + IdField: "AllowListId", + CollectField: "allow_lists", + ResponseConverts: map[string]volc.ResponseConvert{ + "AllowListIPNum": { + TargetField: "allow_list_ip_num", + }, + "VPC": { + TargetField: "vpc", + }, + }, + } +} + +func (s *VolcengineRdsMysqlAllowListService) ReadResourceId(id string) string { + return id +} + +func NewRdsMysqlAllowListService(client *volc.SdkClient) *VolcengineRdsMysqlAllowListService { + return &VolcengineRdsMysqlAllowListService{ + Client: client, + Dispatcher: &volc.Dispatcher{}, + } +} + +func getUniversalInfo(actionName string) volc.UniversalInfo { + return volc.UniversalInfo{ + ServiceName: "rds_mysql", + Version: "2022-01-01", + HttpMethod: volc.POST, + ContentType: volc.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/rds_mysql/allowlist_associate/resource_volcengine_rds_mysql_allowlist_associate.go b/volcengine/rds_mysql/allowlist_associate/resource_volcengine_rds_mysql_allowlist_associate.go new file mode 100644 index 00000000..eaf178e0 --- /dev/null +++ b/volcengine/rds_mysql/allowlist_associate/resource_volcengine_rds_mysql_allowlist_associate.go @@ -0,0 +1,93 @@ +package allowlist_associate + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + volc "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +RDS AllowList Associate can be imported using the instance id and allow list id, e.g. +``` +$ terraform import volcengine_rds_mysql_allowlist_associate.default rds-mysql-h441603c68aaa:acl-d1fd76693bd54e658912e7337d5b**** +``` + +*/ + +func ResourceVolcengineRdsMysqlAllowlistAssociate() *schema.Resource { + return &schema.Resource{ + Create: resourceVolcengineRdsMysqlAllowlistAssociateCreate, + Read: resourceVolcengineRdsMysqlAllowlistAssociateRead, + Delete: resourceVolcengineRdsMysqlAllowlistAssociateDelete, + Importer: &schema.ResourceImporter{ + State: importAllowListAssociate, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of the mysql instance.", + }, + "allow_list_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The id of the allow list.", + }, + }, + } +} + +func resourceVolcengineRdsMysqlAllowlistAssociateCreate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewRdsMysqlAllowListAssociateService(meta.(*volc.SdkClient)) + err = service.Dispatcher.Create(service, d, ResourceVolcengineRdsMysqlAllowlistAssociate()) + if err != nil { + return fmt.Errorf("error creating RDS Mysql Allowlist Associate service: %q, %w", d.Id(), err) + } + return resourceVolcengineRdsMysqlAllowlistAssociateRead(d, meta) +} + +func resourceVolcengineRdsMysqlAllowlistAssociateRead(d *schema.ResourceData, meta interface{}) (err error) { + service := NewRdsMysqlAllowListAssociateService(meta.(*volc.SdkClient)) + err = service.Dispatcher.Read(service, d, ResourceVolcengineRdsMysqlAllowlistAssociate()) + if err != nil { + return fmt.Errorf("error reading RDS Mysql Allowlist Associate service: %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcengineRdsMysqlAllowlistAssociateDelete(d *schema.ResourceData, meta interface{}) (err error) { + service := NewRdsMysqlAllowListAssociateService(meta.(*volc.SdkClient)) + err = service.Dispatcher.Delete(service, d, ResourceVolcengineRdsMysqlAllowlistAssociate()) + if err != nil { + return fmt.Errorf("error deleting RDS Mysql Allowlist Associate service: %q, %w", d.Id(), err) + } + return err +} + +func importAllowListAssociate(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + var err error + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must be of the form InstanceId:AllowListId") + } + err = data.Set("instance_id", items[0]) + if err != nil { + return []*schema.ResourceData{data}, err + } + err = data.Set("allow_list_id", items[1]) + if err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil +} diff --git a/volcengine/rds_mysql/allowlist_associate/service_volcengine_rds_mysql_allowlist_associate.go b/volcengine/rds_mysql/allowlist_associate/service_volcengine_rds_mysql_allowlist_associate.go new file mode 100644 index 00000000..c1376404 --- /dev/null +++ b/volcengine/rds_mysql/allowlist_associate/service_volcengine_rds_mysql_allowlist_associate.go @@ -0,0 +1,163 @@ +package allowlist_associate + +import ( + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + volc "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineRdsMysqlAllowListAssociateService struct { + Client *volc.SdkClient + Dispatcher *volc.Dispatcher +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) GetClient() *volc.SdkClient { + return s.Client +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + return nil, nil +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) ReadResource(resourceData *schema.ResourceData, id string) (data map[string]interface{}, err error) { + var ( + results interface{} + resultsMap = make(map[string]interface{}) + instanceMap = make(map[string]interface{}) + instances = make([]interface{}, 0) + ok bool + ) + if id == "" { + id = s.ReadResourceId(resourceData.Id()) + } + ids := strings.Split(id, ":") + if len(ids) != 2 { + return data, err + } + req := map[string]interface{}{ + "AllowListId": ids[1], + } + action := "DescribeAllowListDetail" + resp, err := s.Client.UniversalClient.DoCall(getUniversalInfo(action), &req) + if err != nil { + return data, err + } + results, err = volc.ObtainSdkValue("Result", *resp) + if err != nil { + return data, err + } + if resultsMap, ok = results.(map[string]interface{}); !ok { + return resultsMap, errors.New("Value is not map ") + } + if len(resultsMap) == 0 { + return resultsMap, fmt.Errorf("Rds allowlist %s not exist ", ids[1]) + } + logger.Debug(logger.ReqFormat, action, resultsMap) + instances = resultsMap["AssociatedInstances"].([]interface{}) + logger.Debug(logger.ReqFormat, action, instances) + for _, instance := range instances { + if instanceMap, ok = instance.(map[string]interface{}); !ok { + return data, errors.New("instance is not map ") + } + if len(instanceMap) == 0 { + continue + } + if instanceMap["InstanceId"].(string) == ids[0] { + data = resultsMap + } + } + if len(data) == 0 { + return data, fmt.Errorf("Rds allowlist associate %s not exist ", id) + } + return data, err +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) RefreshResourceState(data *schema.ResourceData, strings []string, duration time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{} +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) WithResourceResponseHandlers(m map[string]interface{}) []volc.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]volc.ResponseConvert, error) { + return m, map[string]volc.ResponseConvert{}, nil + } + return []volc.ResourceResponseHandler{handler} +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) CreateResource(data *schema.ResourceData, resource *schema.Resource) []volc.Callback { + instanceId := data.Get("instance_id").(string) + allowListId := data.Get("allow_list_id").(string) + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "AssociateAllowList", + ContentType: volc.ContentTypeJson, + SdkParam: &map[string]interface{}{ + "InstanceIds": []string{instanceId}, + "AllowListIds": []string{allowListId}, + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *volc.SdkClient, resp *map[string]interface{}, call volc.SdkCall) error { + d.SetId(fmt.Sprint(instanceId, ":", allowListId)) + return nil + }, + }, + } + return []volc.Callback{callback} +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) ModifyResource(data *schema.ResourceData, resource *schema.Resource) []volc.Callback { + return []volc.Callback{} +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) RemoveResource(data *schema.ResourceData, resource *schema.Resource) []volc.Callback { + instanceId := data.Get("instance_id").(string) + allowListId := data.Get("allow_list_id").(string) + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "DisassociateAllowList", + ContentType: volc.ContentTypeJson, + SdkParam: &map[string]interface{}{ + "InstanceIds": []string{instanceId}, + "AllowListIds": []string{allowListId}, + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + return []volc.Callback{callback} +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) volc.DataSourceInfo { + return volc.DataSourceInfo{} +} + +func (s *VolcengineRdsMysqlAllowListAssociateService) ReadResourceId(id string) string { + return id +} + +func NewRdsMysqlAllowListAssociateService(client *volc.SdkClient) *VolcengineRdsMysqlAllowListAssociateService { + return &VolcengineRdsMysqlAllowListAssociateService{ + Client: client, + Dispatcher: &volc.Dispatcher{}, + } +} + +func getUniversalInfo(actionName string) volc.UniversalInfo { + return volc.UniversalInfo{ + ServiceName: "rds_mysql", + Version: "2022-01-01", + HttpMethod: volc.POST, + ContentType: volc.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/rds_mysql/rds_mysql_account/common_volcengine_rds_mysql_account.go b/volcengine/rds_mysql/rds_mysql_account/common_volcengine_rds_mysql_account.go new file mode 100644 index 00000000..4e6e676f --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_account/common_volcengine_rds_mysql_account.go @@ -0,0 +1,72 @@ +package rds_mysql_account + +import ( + "bytes" + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" + "sort" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +var rdsMysqlAccountImporter = func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("instance_id", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("account_name", items[1]); err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil +} + +var rdsMysqlAccountPrivilegeStrMapping = map[string]string{ + "create tmp table": "create temporary tables", + "CREATE TMP TABLE": "CREATE TEMPORARY TABLES", +} + +func mappingAccountPrivilegeStr(accountPrivilegeStr string) []string { + privileges := strings.Split(accountPrivilegeStr, ",") + mappingPrivileges := make([]string, 0) + for _, privilege := range privileges { + if mappedPrivilege, ok := rdsMysqlAccountPrivilegeStrMapping[privilege]; ok { + mappingPrivileges = append(mappingPrivileges, mappedPrivilege) + } else { + mappingPrivileges = append(mappingPrivileges, privilege) + } + } + return mappingPrivileges +} + +// mappingAndSortAccountPrivilegeStr RDS account privilege string mapping +func mappingAndSortAccountPrivilegeStr(accountPrivilegeStr string) string { + mappingPrivileges := mappingAccountPrivilegeStr(accountPrivilegeStr) + sort.Strings(mappingPrivileges) + return strings.Join(mappingPrivileges, ",") +} + +func rdsMysqlAccountPrivilegeHashBase(m map[string]interface{}) (buf bytes.Buffer) { + dbName := strings.ToLower(m["db_name"].(string)) + accountPrivilege := strings.ToLower(m["account_privilege"].(string)) + buf.WriteString(fmt.Sprintf("%s-", dbName)) + buf.WriteString(fmt.Sprintf("%s-", accountPrivilege)) + if accountPrivilege == "custom" { + buf.WriteString(fmt.Sprintf("%s-", mappingAndSortAccountPrivilegeStr(strings.ToLower(m["account_privilege_detail"].(string))))) + } + return buf +} + +func RdsMysqlAccountPrivilegeHash(v interface{}) int { + if v == nil { + return hashcode.String("") + } + m := v.(map[string]interface{}) + buf := rdsMysqlAccountPrivilegeHashBase(m) + logger.DebugInfo("RdsMysqlAccountPrivilegeHash %s", buf.String()) + return hashcode.String(buf.String()) +} diff --git a/volcengine/rds_mysql/rds_mysql_account/data_source_volcengine_rds_mysql_accounts.go b/volcengine/rds_mysql/rds_mysql_account/data_source_volcengine_rds_mysql_accounts.go new file mode 100644 index 00000000..1827375a --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_account/data_source_volcengine_rds_mysql_accounts.go @@ -0,0 +1,95 @@ +package rds_mysql_account + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + volc "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineRdsMysqlAccounts() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineRdsMysqlAccountsRead, + Schema: map[string]*schema.Schema{ + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + Description: "A Name Regex of database account.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of database account query.", + }, + "instance_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the RDS instance.", + }, + "account_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the database account. This field supports fuzzy query.", + }, + "accounts": { + Description: "The collection of RDS instance account query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "account_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the database account.", + }, + "account_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the database account.", + }, + "account_status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the database account.", + }, + "account_privileges": { + Type: schema.TypeList, + Computed: true, + Description: "The privilege detail list of RDS mysql instance account.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "db_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of database.", + }, + "account_privilege": { + Type: schema.TypeString, + Computed: true, + Description: "The privilege type of the account.", + }, + "account_privilege_detail": { + Type: schema.TypeString, + Computed: true, + Description: "The privilege detail of the account.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineRdsMysqlAccountsRead(d *schema.ResourceData, meta interface{}) error { + service := NewRdsMysqlAccountService(meta.(*volc.SdkClient)) + return service.Dispatcher.Data(service, d, DataSourceVolcengineRdsMysqlAccounts()) +} diff --git a/volcengine/rds_mysql/rds_mysql_account/resource_volcengine_rds_mysql_account.go b/volcengine/rds_mysql/rds_mysql_account/resource_volcengine_rds_mysql_account.go new file mode 100644 index 00000000..92a4039e --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_account/resource_volcengine_rds_mysql_account.go @@ -0,0 +1,138 @@ +package rds_mysql_account + +import ( + "fmt" + "reflect" + "sort" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + volc "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +RDS mysql account can be imported using the instance_id:account_name, e.g. +``` +$ terraform import volcengine_rds_mysql_account.default mysql-42b38c769c4b:test +``` + +*/ + +func ResourceVolcengineRdsMysqlAccount() *schema.Resource { + return &schema.Resource{ + Create: resourceVolcengineRdsMysqlAccountCreate, + Read: resourceVolcengineRdsMysqlAccountRead, + Update: resourceVolcengineRdsMysqlAccountUpdate, + Delete: resourceVolcengineRdsMysqlAccountDelete, + Importer: &schema.ResourceImporter{ + State: rdsMysqlAccountImporter, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the RDS instance.", + }, + "account_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Database account name. The rules are as follows:\nUnique name.\nStart with a letter and end with a letter or number.\nConsists of lowercase letters, numbers, or underscores (_).\nThe length is 2~32 characters.\nThe [keyword list](https://www.volcengine.com/docs/6313/66162) is disabled for database accounts, and certain reserved words, including root, admin, etc., cannot be used.", + }, + "account_password": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + Description: "The password of the database account.\nIllustrate:\nCannot start with `!` or `@`.\nThe length is 8~32 characters.\nIt consists of any three of uppercase letters, lowercase letters, numbers, and special characters.\nThe special characters are `!@#$%^*()_+-=`. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields.", + }, + "account_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Database account type, value:\nSuper: A high-privilege account. Only one database account can be created for an instance.\nNormal: An account with ordinary privileges.", + ValidateFunc: validation.StringInSlice([]string{"Super", "Normal"}, false), + }, + "account_privileges": { + Type: schema.TypeSet, + Optional: true, + Set: RdsMysqlAccountPrivilegeHash, + Description: "The privilege information of account.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "db_name": { + Type: schema.TypeString, + Required: true, + Description: "The name of database.", + }, + "account_privilege": { + Type: schema.TypeString, + Required: true, + Description: "The privilege type of the account.", + }, + "account_privilege_detail": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if len(old) != len(new) { + return false + } + oldArr := strings.Split(old, ",") + newArr := strings.Split(new, ",") + sort.Strings(oldArr) + sort.Strings(newArr) + return reflect.DeepEqual(oldArr, newArr) + }, + Description: "The privilege detail of the account.", + }, + }, + }, + }, + }, + } +} + +func resourceVolcengineRdsMysqlAccountCreate(d *schema.ResourceData, meta interface{}) (err error) { + rdsAccountService := NewRdsMysqlAccountService(meta.(*volc.SdkClient)) + err = rdsAccountService.Dispatcher.Create(rdsAccountService, d, ResourceVolcengineRdsMysqlAccount()) + if err != nil { + return fmt.Errorf("error on creating rds mysql account %q, %w", d.Id(), err) + } + return resourceVolcengineRdsMysqlAccountRead(d, meta) +} + +func resourceVolcengineRdsMysqlAccountRead(d *schema.ResourceData, meta interface{}) (err error) { + rdsAccountService := NewRdsMysqlAccountService(meta.(*volc.SdkClient)) + err = rdsAccountService.Dispatcher.Read(rdsAccountService, d, ResourceVolcengineRdsMysqlAccount()) + if err != nil { + return fmt.Errorf("error on reading rds mysql account %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcengineRdsMysqlAccountUpdate(d *schema.ResourceData, meta interface{}) (err error) { + service := NewRdsMysqlAccountService(meta.(*volc.SdkClient)) + err = service.Dispatcher.Update(service, d, ResourceVolcengineRdsMysqlAccount()) + if err != nil { + return fmt.Errorf("error on updating rds mysql account %q, %s", d.Id(), err) + } + return resourceVolcengineRdsMysqlAccountRead(d, meta) +} + +func resourceVolcengineRdsMysqlAccountDelete(d *schema.ResourceData, meta interface{}) (err error) { + rdsAccountService := NewRdsMysqlAccountService(meta.(*volc.SdkClient)) + err = rdsAccountService.Dispatcher.Delete(rdsAccountService, d, ResourceVolcengineRdsMysqlAccount()) + if err != nil { + return fmt.Errorf("error on deleting rds mysql account %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/rds_mysql/rds_mysql_account/service_volcengine_rds_mysql_account.go b/volcengine/rds_mysql/rds_mysql_account/service_volcengine_rds_mysql_account.go new file mode 100644 index 00000000..5c148b62 --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_account/service_volcengine_rds_mysql_account.go @@ -0,0 +1,358 @@ +package rds_mysql_account + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + volc "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" + database "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_mysql/rds_mysql_database" +) + +type VolcengineRdsMysqlAccountService struct { + Client *volc.SdkClient + Dispatcher *volc.Dispatcher +} + +func NewRdsMysqlAccountService(c *volc.SdkClient) *VolcengineRdsMysqlAccountService { + return &VolcengineRdsMysqlAccountService{ + Client: c, + Dispatcher: &volc.Dispatcher{}, + } +} + +func (s *VolcengineRdsMysqlAccountService) GetClient() *volc.SdkClient { + return s.Client +} + +func (s *VolcengineRdsMysqlAccountService) ReadResources(m map[string]interface{}) ([]interface{}, error) { + return volc.WithPageNumberQuery(m, "PageSize", "PageNumber", 20, 0, func(condition map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + universalClient := s.Client.UniversalClient + action := "DescribeDBAccounts" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = universalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = universalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + respBytes, _ := json.Marshal(resp) + logger.Debug(logger.RespFormat, action, condition, string(respBytes)) + results, err = volc.ObtainSdkValue("Result.Accounts", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Accounts is not Slice") + } + return data, err + }) +} + +func (s *VolcengineRdsMysqlAccountService) ReadResource(resourceData *schema.ResourceData, RdsMysqlAccountId string) (data map[string]interface{}, err error) { + var ( + results []interface{} + account = make(map[string]interface{}) + ok bool + ) + if RdsMysqlAccountId == "" { + RdsMysqlAccountId = s.ReadResourceId(resourceData.Id()) + } + + ids := strings.Split(RdsMysqlAccountId, ":") + if len(ids) != 2 { + return map[string]interface{}{}, fmt.Errorf("invalid rds mysql account id") + } + + instanceId := ids[0] + accountName := ids[1] + + req := map[string]interface{}{ + "InstanceId": instanceId, + "AccountName": accountName, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + + for _, r := range results { + account, ok = r.(map[string]interface{}) + if !ok { + return data, errors.New("Value is not map ") + } + if accountName == account["AccountName"].(string) { + data = account + break + } + } + + if len(data) == 0 { + return data, fmt.Errorf("RDS account %s not exist ", RdsMysqlAccountId) + } + + return data, err +} + +func (s *VolcengineRdsMysqlAccountService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (VolcengineRdsMysqlAccountService) WithResourceResponseHandlers(rdsAccount map[string]interface{}) []volc.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]volc.ResponseConvert, error) { + return rdsAccount, map[string]volc.ResponseConvert{ + "DBName": { + TargetField: "db_name", + }, + }, nil + } + return []volc.ResourceResponseHandler{handler} +} + +func (s *VolcengineRdsMysqlAccountService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []volc.Callback { + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "CreateDBAccount", + ConvertMode: volc.RequestConvertAll, + Convert: map[string]volc.RequestConvert{ + "account_privileges": { + TargetField: "AccountPrivileges", + ConvertType: volc.ConvertJsonObjectArray, + NextLevelConvert: map[string]volc.RequestConvert{ + "db_name": { + TargetField: "DBName", + }, + }, + }, + }, + ContentType: volc.ContentTypeJson, + BeforeCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (bool, error) { + privileges := d.Get("account_privileges") + if privileges == nil || privileges.(*schema.Set).Len() == 0 { + return true, nil + } + for _, privilege := range privileges.(*schema.Set).List() { + privilegeMap, ok := privilege.(map[string]interface{}) + if !ok { + return false, fmt.Errorf("account_privilege is not map") + } + id := fmt.Sprintf("%s:%s", d.Get("instance_id"), privilegeMap["db_name"]) + _, err := database.NewRdsMysqlDatabaseService(client).ReadResource(d, id) + if err != nil { + return false, err + } + } + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + //创建RdsMysqlAccount + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *volc.SdkClient, resp *map[string]interface{}, call volc.SdkCall) error { + id := fmt.Sprintf("%s:%s", d.Get("instance_id"), d.Get("account_name")) + d.SetId(id) + return nil + }, + }, + } + return []volc.Callback{callback} +} + +func (s *VolcengineRdsMysqlAccountService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []volc.Callback { + callbacks := []volc.Callback{} + if resourceData.HasChange("account_password") { + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "ResetDBAccount", + ConvertMode: volc.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "InstanceId": resourceData.Get("instance_id"), + "AccountName": resourceData.Get("account_name"), + "AccountPassword": resourceData.Get("account_password"), + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + callbacks = append(callbacks, callback) + } + if resourceData.HasChange("account_privileges") { + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "GrantDBAccountPrivilege", + ConvertMode: volc.RequestConvertInConvert, + ContentType: volc.ContentTypeJson, + Convert: map[string]volc.RequestConvert{ + "account_privileges": { + TargetField: "AccountPrivileges", + ForceGet: true, + NextLevelConvert: map[string]volc.RequestConvert{ + "db_name": { + TargetField: "DBName", + }, + }, + ConvertType: volc.ConvertJsonObjectArray, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (bool, error) { + (*call.SdkParam)["InstanceId"] = d.Get("instance_id") + (*call.SdkParam)["AccountName"] = d.Get("account_name") + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + callbacks = append(callbacks, callback) + + add, remove, _, _ := volc.GetSetDifference("account_privileges", resourceData, RdsMysqlAccountPrivilegeHash, false) + if remove != nil && remove.Len() > 0 { + removeCallback := volc.Callback{ + Call: volc.SdkCall{ + Action: "RevokeDBAccountPrivilege", + ConvertMode: volc.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (bool, error) { + (*call.SdkParam)["InstanceId"] = d.Get("instance_id") + (*call.SdkParam)["AccountName"] = d.Get("account_name") + dbNames := make([]string, 0) + for _, item := range remove.List() { + m, ok := item.(map[string]interface{}) + if !ok { + continue + } + removeDbName := m["db_name"].(string) + // 过滤掉有Grant操作的db_name,Grant权限方式为覆盖,先取消原有权限,再赋新权限,此处无需再取消一次。 + if add != nil && add.Len() > 0 && hasDbNameInSet(removeDbName, add) { + continue + } + dbNames = append(dbNames, removeDbName) + } + if len(dbNames) == 0 { + return false, nil + } + (*call.SdkParam)["DBNames"] = strings.Join(dbNames, ",") + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + }, + } + callbacks = append(callbacks, removeCallback) + } + } + return callbacks +} + +func hasDbNameInSet(dbName string, set *schema.Set) bool { + for _, item := range set.List() { + if m, ok := item.(map[string]interface{}); ok { + if v, ok := m["db_name"]; ok && v.(string) == dbName { + if detail, ok := m["account_privilege_detail"].(string); ok { + if len(detail) == 0 { + return false + } + } else { + return false + } + return true + } + } + } + return false +} + +func (s *VolcengineRdsMysqlAccountService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []volc.Callback { + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "DeleteDBAccount", + ContentType: volc.ContentTypeJson, + ConvertMode: volc.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (bool, error) { + rdsAccountId := d.Id() + ids := strings.Split(rdsAccountId, ":") + if len(ids) != 2 { + return false, fmt.Errorf("invalid rds account id") + } + (*call.SdkParam)["InstanceId"] = ids[0] + (*call.SdkParam)["AccountName"] = ids[1] + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + //删除RdsMysqlAccount + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + CallError: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall, baseErr error) error { + //出现错误后重试 + return resource.Retry(15*time.Minute, func() *resource.RetryError { + _, callErr := s.ReadResource(d, "") + if callErr != nil { + if volc.ResourceNotFoundError(callErr) { + return nil + } else { + return resource.NonRetryableError(fmt.Errorf("error on reading RDS account on delete %q, %w", d.Id(), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + }, + } + return []volc.Callback{callback} +} + +func (s *VolcengineRdsMysqlAccountService) DatasourceResources(*schema.ResourceData, *schema.Resource) volc.DataSourceInfo { + return volc.DataSourceInfo{ + ContentType: volc.ContentTypeJson, + NameField: "AccountName", + CollectField: "accounts", + ResponseConverts: map[string]volc.ResponseConvert{ + "DBName": { + TargetField: "db_name", + }, + }, + } +} + +func (s *VolcengineRdsMysqlAccountService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) volc.UniversalInfo { + return volc.UniversalInfo{ + ServiceName: "rds_mysql", + Version: "2022-01-01", + HttpMethod: volc.POST, + ContentType: volc.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/rds_mysql/rds_mysql_database/common_volcengine_rds_mysql_database.go b/volcengine/rds_mysql/rds_mysql_database/common_volcengine_rds_mysql_database.go new file mode 100644 index 00000000..cb4ede99 --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_database/common_volcengine_rds_mysql_database.go @@ -0,0 +1,22 @@ +package rds_mysql_database + +import ( + "fmt" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +var databaseImporter = func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("instance_id", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("db_name", items[1]); err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil +} diff --git a/volcengine/rds_mysql/rds_mysql_database/data_source_volcengine_rds_mysql_databases.go b/volcengine/rds_mysql/rds_mysql_database/data_source_volcengine_rds_mysql_databases.go new file mode 100644 index 00000000..fa16000d --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_database/data_source_volcengine_rds_mysql_databases.go @@ -0,0 +1,91 @@ +package rds_mysql_database + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + volc "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineRdsMysqlDatabases() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineRdsMysqlDatabasesRead, + Schema: map[string]*schema.Schema{ + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + Description: "A Name Regex of RDS database.", + }, + + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of RDS database query.", + }, + "instance_id": { + Type: schema.TypeString, + Required: true, + Description: "The id of the RDS instance.", + }, + "db_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the RDS database.", + }, + "databases": { + Description: "The collection of RDS instance account query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "db_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the RDS database. This field supports fuzzy queries.", + }, + "character_set_name": { + Type: schema.TypeString, + Computed: true, + Description: "The character set of the RDS database.", + }, + "database_privileges": { + Type: schema.TypeList, + Computed: true, + Description: "The privilege detail list of RDS mysql instance database.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "account_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of account.", + }, + "account_privilege": { + Type: schema.TypeString, + Computed: true, + Description: "The privilege type of the account.", + }, + "account_privilege_detail": { + Type: schema.TypeString, + Computed: true, + Description: "The privilege detail of the account.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineRdsMysqlDatabasesRead(d *schema.ResourceData, meta interface{}) error { + databaseService := NewRdsMysqlDatabaseService(meta.(*volc.SdkClient)) + return databaseService.Dispatcher.Data(databaseService, d, DataSourceVolcengineRdsMysqlDatabases()) +} diff --git a/volcengine/rds_mysql/rds_mysql_database/resource_volcengine_rds_mysql_database.go b/volcengine/rds_mysql/rds_mysql_database/resource_volcengine_rds_mysql_database.go new file mode 100644 index 00000000..1054af69 --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_database/resource_volcengine_rds_mysql_database.go @@ -0,0 +1,82 @@ +package rds_mysql_database + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + volc "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +Database can be imported using the instanceId:dbName, e.g. +``` +$ terraform import volcengine_rds_mysql_database.default mysql-42b38c769c4b:dbname +``` + +*/ + +func ResourceVolcengineRdsMysqlDatabase() *schema.Resource { + return &schema.Resource{ + Create: resourceVolcengineRdsMysqlDatabaseCreate, + Read: resourceVolcengineRdsMysqlDatabaseRead, + Delete: resourceVolcengineRdsMysqlDatabaseDelete, + Importer: &schema.ResourceImporter{ + State: databaseImporter, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the RDS instance.", + }, + "db_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name database.\nillustrate:\nUnique name.\nThe length is 2~64 characters.\nStart with a letter and end with a letter or number.\nConsists of lowercase letters, numbers, and underscores (_) or dashes (-).\nDatabase names are disabled [keywords](https://www.volcengine.com/docs/6313/66162).", + }, + "character_set_name": { + Type: schema.TypeString, + Optional: true, + Default: "utf8mb4", + ForceNew: true, + Description: "Database character set. Currently supported character sets include: utf8, utf8mb4, latin1, ascii.", + }, + }, + } +} + +func resourceVolcengineRdsMysqlDatabaseCreate(d *schema.ResourceData, meta interface{}) (err error) { + databaseService := NewRdsMysqlDatabaseService(meta.(*volc.SdkClient)) + err = databaseService.Dispatcher.Create(databaseService, d, ResourceVolcengineRdsMysqlDatabase()) + if err != nil { + return fmt.Errorf("error on creating database %q, %w", d.Id(), err) + } + return resourceVolcengineRdsMysqlDatabaseRead(d, meta) +} + +func resourceVolcengineRdsMysqlDatabaseRead(d *schema.ResourceData, meta interface{}) (err error) { + databaseService := NewRdsMysqlDatabaseService(meta.(*volc.SdkClient)) + err = databaseService.Dispatcher.Read(databaseService, d, ResourceVolcengineRdsMysqlDatabase()) + if err != nil { + return fmt.Errorf("error on reading database %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcengineRdsMysqlDatabaseDelete(d *schema.ResourceData, meta interface{}) (err error) { + databaseService := NewRdsMysqlDatabaseService(meta.(*volc.SdkClient)) + err = databaseService.Dispatcher.Delete(databaseService, d, ResourceVolcengineRdsMysqlDatabase()) + if err != nil { + return fmt.Errorf("error on deleting database %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/rds_mysql/rds_mysql_database/service_volcengine_rds_mysql_database.go b/volcengine/rds_mysql/rds_mysql_database/service_volcengine_rds_mysql_database.go new file mode 100644 index 00000000..39689541 --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_database/service_volcengine_rds_mysql_database.go @@ -0,0 +1,231 @@ +package rds_mysql_database + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + volc "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineRdsMysqlDatabaseService struct { + Client *volc.SdkClient + Dispatcher *volc.Dispatcher +} + +func NewRdsMysqlDatabaseService(c *volc.SdkClient) *VolcengineRdsMysqlDatabaseService { + return &VolcengineRdsMysqlDatabaseService{ + Client: c, + Dispatcher: &volc.Dispatcher{}, + } +} + +func (s *VolcengineRdsMysqlDatabaseService) GetClient() *volc.SdkClient { + return s.Client +} + +func (s *VolcengineRdsMysqlDatabaseService) ReadResources(m map[string]interface{}) ([]interface{}, error) { + return volc.WithPageNumberQuery(m, "PageSize", "PageNumber", 10, 1, func(condition map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + action := "DescribeDatabases" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + respBytes, _ := json.Marshal(resp) + logger.Debug(logger.RespFormat, action, condition, string(respBytes)) + + results, err = volc.ObtainSdkValue("Result.Databases", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Databases is not Slice") + } + return data, err + }) +} + +func (s *VolcengineRdsMysqlDatabaseService) ReadResource(resourceData *schema.ResourceData, rdsDatabaseId string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if rdsDatabaseId == "" { + rdsDatabaseId = s.ReadResourceId(resourceData.Id()) + } + + ids := strings.Split(rdsDatabaseId, ":") + if len(ids) != 2 { + return map[string]interface{}{}, fmt.Errorf("invalid database id") + } + + instanceId := ids[0] + dbName := ids[1] + + req := map[string]interface{}{ + "InstanceId": instanceId, + "DBName": dbName, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + dbMap := make(map[string]interface{}) + if dbMap, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + if dbName == dbMap["DBName"].(string) { + data = dbMap + break + } + } + if len(data) == 0 { + return data, fmt.Errorf("RDS database %s not exist ", rdsDatabaseId) + } + + return data, err +} + +func (s *VolcengineRdsMysqlDatabaseService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{} +} + +func (s *VolcengineRdsMysqlDatabaseService) WithResourceResponseHandlers(database map[string]interface{}) []volc.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]volc.ResponseConvert, error) { + return database, map[string]volc.ResponseConvert{ + "DBName": { + TargetField: "db_name", + }, + }, nil + } + return []volc.ResourceResponseHandler{handler} +} + +func (s *VolcengineRdsMysqlDatabaseService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []volc.Callback { + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "CreateDatabase", + ContentType: volc.ContentTypeJson, + ConvertMode: volc.RequestConvertAll, + Convert: map[string]volc.RequestConvert{ + "database_privileges": { + TargetField: "DatabasePrivileges", + ConvertType: volc.ConvertJsonObjectArray, + }, + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + //创建Database + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *volc.SdkClient, resp *map[string]interface{}, call volc.SdkCall) error { + id := fmt.Sprintf("%s:%s", d.Get("instance_id"), d.Get("db_name")) + d.SetId(id) + return nil + }, + }, + } + return []volc.Callback{callback} +} + +func (s *VolcengineRdsMysqlDatabaseService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []volc.Callback { + return []volc.Callback{} +} + +func (s *VolcengineRdsMysqlDatabaseService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []volc.Callback { + callback := volc.Callback{ + Call: volc.SdkCall{ + Action: "DeleteDatabase", + ContentType: volc.ContentTypeJson, + ConvertMode: volc.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (bool, error) { + databaseId := d.Id() + ids := strings.Split(databaseId, ":") + if len(ids) != 2 { + return false, fmt.Errorf("invalid rds database id") + } + (*call.SdkParam)["InstanceId"] = ids[0] + (*call.SdkParam)["DBName"] = ids[1] + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + //删除Database + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + CallError: func(d *schema.ResourceData, client *volc.SdkClient, call volc.SdkCall, baseErr error) error { + //出现错误后重试 + return resource.Retry(15*time.Minute, func() *resource.RetryError { + _, callErr := s.ReadResource(d, "") + if callErr != nil { + if volc.ResourceNotFoundError(callErr) { + return nil + } else { + return resource.NonRetryableError(fmt.Errorf("error on reading RDS database on delete %q, %w", d.Id(), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + }, + } + return []volc.Callback{callback} +} + +func (s *VolcengineRdsMysqlDatabaseService) DatasourceResources(*schema.ResourceData, *schema.Resource) volc.DataSourceInfo { + return volc.DataSourceInfo{ + ContentType: volc.ContentTypeJson, + RequestConverts: map[string]volc.RequestConvert{ + "db_name": { + TargetField: "DBName", + }, + }, + NameField: "DBName", + CollectField: "databases", + ResponseConverts: map[string]volc.ResponseConvert{ + "DBName": { + TargetField: "db_name", + }, + }, + } +} + +func (s *VolcengineRdsMysqlDatabaseService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) volc.UniversalInfo { + return volc.UniversalInfo{ + ServiceName: "rds_mysql", + Version: "2022-01-01", + HttpMethod: volc.POST, + ContentType: volc.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/rds_mysql/rds_mysql_instance/common_volcengine_rds_mysql_instance.go b/volcengine/rds_mysql/rds_mysql_instance/common_volcengine_rds_mysql_instance.go new file mode 100644 index 00000000..5859a749 --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_instance/common_volcengine_rds_mysql_instance.go @@ -0,0 +1,29 @@ +package rds_mysql_instance + +import ( + "bytes" + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/hashcode" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +var parameterHash = func(v interface{}) int { + if v == nil { + return hashcode.String("") + } + m := v.(map[string]interface{}) + var ( + buf bytes.Buffer + ) + buf.WriteString(fmt.Sprintf("%v#%v", m["parameter_name"], m["parameter_value"])) + return hashcode.String(buf.String()) +} + +func RdsMysqlInstanceImportDiffSuppress(k, old, new string, d *schema.ResourceData) bool { + //在计费方式为PostPaid的时候 period的变化会被忽略 + if d.Get("charge_info.0.charge_type").(string) == "PostPaid" && (k == "charge_info.0.period" || k == "charge_info.0.period_unit" || k == "charge_info.0.auto_renew") { + return true + } + + return false +} diff --git a/volcengine/rds_mysql/rds_mysql_instance/data_source_volcengine_rds_mysql_instances.go b/volcengine/rds_mysql/rds_mysql_instance/data_source_volcengine_rds_mysql_instances.go new file mode 100644 index 00000000..6fdb6fa7 --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_instance/data_source_volcengine_rds_mysql_instances.go @@ -0,0 +1,473 @@ +package rds_mysql_instance + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineRdsMysqlInstances() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineRdsMysqlInstancesRead, + Schema: map[string]*schema.Schema{ + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + Description: "A Name Regex of RDS instance.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of RDS instance query.", + }, + "instance_id": { + Type: schema.TypeString, + Optional: true, + Description: "The id of the RDS instance.", + }, + "instance_name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the RDS instance.", + }, + "instance_status": { + Type: schema.TypeString, + Optional: true, + Description: "The status of the RDS instance.", + }, + "db_engine_version": { + Type: schema.TypeString, + Optional: true, + Description: "The version of the RDS instance.", + }, + "create_time_start": { + Type: schema.TypeString, + Optional: true, + Description: "The start time of creating RDS instance.", + }, + "create_time_end": { + Type: schema.TypeString, + Optional: true, + Description: "The end time of creating RDS instance.", + }, + "zone_id": { + Type: schema.TypeString, + Optional: true, + Description: "The available zone of the RDS instance.", + }, + "charge_type": { + Type: schema.TypeString, + Optional: true, + Description: "The charge type of the RDS instance.", + ValidateFunc: validation.StringInSlice([]string{"PostPaid", "PrePaid"}, false), + }, + "rds_mysql_instances": { + Description: "The collection of RDS instance query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the RDS instance.", + }, + "instance_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the RDS instance.", + }, + "instance_name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the RDS instance.", + }, + "instance_status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the RDS instance.", + }, + "region_id": { + Type: schema.TypeString, + Computed: true, + Description: "The region of the RDS instance.", + }, + "zone_id": { + Type: schema.TypeString, + Computed: true, + Description: "The available zone of the RDS instance.", + }, + "db_engine_version": { + Type: schema.TypeString, + Computed: true, + Description: "The engine version of the RDS instance.", + }, + "v_cpu": { + Type: schema.TypeInt, + Computed: true, + Description: "CPU size.", + }, + "memory": { + Type: schema.TypeInt, + Computed: true, + Description: "Memory size.", + }, + "node_spec": { + Type: schema.TypeString, + Computed: true, + Description: "The specification of primary node.", + }, + "node_number": { + Type: schema.TypeInt, + Computed: true, + Description: "The number of nodes.", + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: "The create time of the RDS instance.", + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "The update time of the RDS instance.", + }, + "storage_use": { + Type: schema.TypeInt, + Computed: true, + Description: "The instance has used storage space. Unit: GB.", + }, + "backup_use": { + Type: schema.TypeInt, + Computed: true, + Description: "The instance has used backup space. Unit: GB.", + }, + "storage_space": { + Type: schema.TypeInt, + Computed: true, + Description: "Total instance storage space. Unit: GB.", + }, + "storage_type": { + Type: schema.TypeString, + Computed: true, + Description: "Instance storage type.", + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + Description: "The vpc ID of the RDS instance.", + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + Description: "The subnet ID of the RDS instance.", + }, + "time_zone": { + Type: schema.TypeString, + Computed: true, + Description: "Time zone.", + }, + "lower_case_table_names": { + Type: schema.TypeString, + Computed: true, + Description: "Whether the table name is case sensitive, the default value is 1.\nRanges:\n0: Table names are stored as fixed and table names are case-sensitive.\n1: Table names will be stored in lowercase and table names are not case sensitive.", + }, + "data_sync_mode": { + Type: schema.TypeString, + Computed: true, + Description: "Data synchronization mode.", + }, + "allow_list_version": { + Type: schema.TypeString, + Computed: true, + Description: "The version of allow list.", + }, + "charge_detail": { + Type: schema.TypeList, + Computed: true, + MaxItems: 1, + MinItems: 1, + Description: "Payment methods.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "charge_type": { + Type: schema.TypeString, + Computed: true, + Description: "Payment type. Value:\nPostPaid - Pay-As-You-Go\nPrePaid - Yearly and monthly (default).", + }, + "auto_renew": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether to automatically renew in prepaid scenarios.\nAutorenew_Enable\nAutorenew_Disable (default).", + }, + "period_unit": { + Type: schema.TypeString, + Computed: true, + Description: "The purchase cycle in the prepaid scenario.\nMonth - monthly subscription (default)\nYear - Package year.", + }, + "period": { + Type: schema.TypeInt, + Computed: true, + Description: "Purchase duration in prepaid scenarios. Default: 1.", + }, + "charge_status": { + Type: schema.TypeString, + Computed: true, + Description: "Pay status. Value:\nnormal - normal\noverdue - overdue\n.", + }, + "charge_start_time": { + Type: schema.TypeString, + Computed: true, + Description: "Billing start time (pay-as-you-go & monthly subscription).", + }, + "charge_end_time": { + Type: schema.TypeString, + Computed: true, + Description: "Billing expiry time (yearly and monthly only).", + }, + "overdue_time": { + Type: schema.TypeString, + Computed: true, + Description: "Shutdown time in arrears (pay-as-you-go & monthly subscription).", + }, + "overdue_reclaim_time": { + Type: schema.TypeString, + Computed: true, + Description: "Estimated release time when arrears are closed (pay-as-you-go & monthly subscription).", + }, + }, + }, + }, + "maintenance_window": { + Type: schema.TypeList, + Computed: true, + Description: "Maintenance Window.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "maintenance_time": { + Type: schema.TypeString, + Computed: true, + Description: "The maintainable time of the RDS instance.", + }, + "day_kind": { + Type: schema.TypeString, + Computed: true, + Description: "DayKind of maintainable window. Value: Week. Month.", + }, + "day_of_week": { + Type: schema.TypeList, + Computed: true, + Description: "Days of maintainable window of the week.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "day_of_month": { + Type: schema.TypeList, + Computed: true, + Description: "Days of maintainable window of the month.", + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "endpoints": { + Type: schema.TypeList, + Computed: true, + Description: "The endpoint info of the RDS instance.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "endpoint_id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance connection terminal ID.", + }, + "endpoint_name": { + Type: schema.TypeString, + Computed: true, + Description: "The instance connection terminal name.", + }, + "endpoint_type": { + Type: schema.TypeString, + Computed: true, + Description: "Terminal type:\nCluster: The default terminal. (created by default)\nPrimary: Primary node terminal.\nCustom: Custom terminal.\nDirect: Direct connection to the terminal. (Only the operation and maintenance side)\nAllNode: All node terminals. (Only the operation and maintenance side).", + }, + "read_write_mode": { + Type: schema.TypeString, + Computed: true, + Description: "Read and write mode:\nReadWrite: read and write\nReadOnly: read only (default).", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "Address description.", + }, + "auto_add_new_nodes": { + Type: schema.TypeString, + Computed: true, + Description: "When the terminal type is read-write terminal or read-only terminal, it supports setting whether new nodes are automatically added.", + }, + "enable_read_write_splitting": { + Type: schema.TypeString, + Computed: true, + Description: "Whether read-write separation is enabled, value: Enable: Enable. Disable: Disabled.", + }, + "enable_read_only": { + Type: schema.TypeString, + Computed: true, + Description: "Whether global read-only is enabled, value: Enable: Enable. Disable: Disabled.", + }, + "node_weight": { + Type: schema.TypeList, + Computed: true, + Description: "The list of nodes configured by the connection terminal and the corresponding read-only weights.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "node_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the node.", + }, + "node_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the node.", + }, + "weight": { + Type: schema.TypeInt, + Computed: true, + Description: "The weight of the node.", + }, + }, + }, + }, + "addresses": { + Type: schema.TypeList, + Computed: true, + Description: "Address list.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "network_type": { + Type: schema.TypeString, + Computed: true, + Description: "Network address type, temporarily Private, Public, PublicService.", + }, + "domain": { + Type: schema.TypeString, + Computed: true, + Description: "Connect domain name.", + }, + "ip_address": { + Type: schema.TypeString, + Computed: true, + Description: "The IP Address.", + }, + "port": { + Type: schema.TypeString, + Computed: true, + Description: "The Port.", + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + Description: "Subnet ID, valid only for private addresses.", + }, + "eip_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the EIP, only valid for Public addresses.", + }, + "dns_visibility": { + Type: schema.TypeBool, + Computed: true, + Description: "DNS Visibility.", + }, + }, + }, + }, + }, + }, + }, + "nodes": { + Type: schema.TypeList, + Computed: true, + Description: "Instance node information.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Computed: true, + Description: "Instance ID.", + }, + "node_id": { + Type: schema.TypeString, + Computed: true, + Description: "Node ID.", + }, + "region_id": { + Type: schema.TypeString, + Computed: true, + Description: "Region ID, you can call the DescribeRegions query and use this parameter to specify the region where the instance is to be created.", + }, + "zone_id": { + Type: schema.TypeString, + Computed: true, + Description: "Availability zone ID. Subsequent support for multi-availability zones can be separated and displayed by an English colon.", + }, + "node_type": { + Type: schema.TypeString, + Computed: true, + Description: "Node type. Value: Primary: Primary node.\nSecondary: Standby node.\nReadOnly: Read-only node.", + }, + "node_status": { + Type: schema.TypeString, + Computed: true, + Description: "Node state, value: aligned with instance state.", + }, + "node_spec": { + Type: schema.TypeString, + Computed: true, + Description: "General instance type, different from Custom instance type.", + }, + "v_cpu": { + Type: schema.TypeInt, + Computed: true, + Description: "CPU size. For example: 1 means 1U.", + }, + "memory": { + Type: schema.TypeInt, + Computed: true, + Description: "Memory size in GB.", + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: "Node creation local time.", + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "Node updates local time.", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineRdsMysqlInstancesRead(d *schema.ResourceData, meta interface{}) error { + rdsMysqlInstanceService := NewRdsMysqlInstanceService(meta.(*ve.SdkClient)) + return rdsMysqlInstanceService.Dispatcher.Data(rdsMysqlInstanceService, d, DataSourceVolcengineRdsMysqlInstances()) +} diff --git a/volcengine/rds_mysql/rds_mysql_instance/resource_volcengine_rds_mysql_instance.go b/volcengine/rds_mysql/rds_mysql_instance/resource_volcengine_rds_mysql_instance.go new file mode 100644 index 00000000..04b2aacb --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_instance/resource_volcengine_rds_mysql_instance.go @@ -0,0 +1,207 @@ +package rds_mysql_instance + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +Rds Mysql Instance can be imported using the id, e.g. +``` +$ terraform import volcengine_rds_mysql_instance.default mysql-72da4258c2c7 +``` + +*/ + +func ResourceVolcengineRdsMysqlInstance() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineRdsMysqlInstanceCreate, + Read: resourceVolcengineRdsMysqlInstanceRead, + Update: resourceVolcengineRdsMysqlInstanceUpdate, + Delete: resourceVolcengineRdsMysqlInstanceDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(1 * time.Hour), + Update: schema.DefaultTimeout(1 * time.Hour), + Delete: schema.DefaultTimeout(1 * time.Hour), + }, + Schema: map[string]*schema.Schema{ + "db_engine_version": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Instance type. Value:\nMySQL_5_7\nMySQL_8_0.", + ValidateFunc: validation.StringInSlice([]string{"MySQL_5_7", "MySQL_8_0"}, false), + }, + "node_spec": { + Type: schema.TypeString, + Required: true, + Description: "The specification of primary node and secondary node.", + }, + "primary_zone_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The available zone of primary node.", + }, + "secondary_zone_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The available zone of secondary node.", + }, + "storage_space": { + Type: schema.TypeInt, + Optional: true, + Default: 100, + Description: "Instance storage space. Value range: [20, 3000], unit: GB, increments every 100GB. Default value: 100.", + }, + "subnet_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Subnet ID of the RDS instance.", + }, + "instance_name": { + Type: schema.TypeString, + Optional: true, + Description: "Instance name. Cannot start with a number or a dash\nCan only contain Chinese characters, letters, numbers, underscores and dashes\nThe length is limited between 1 ~ 128.", + }, + "lower_case_table_names": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Whether the table name is case sensitive, the default value is 1.\nRanges:\n0: Table names are stored as fixed and table names are case-sensitive.\n1: Table names will be stored in lowercase and table names are not case sensitive.", + }, + "db_time_zone": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + Description: "Time zone. Support UTC -12:00 ~ +13:00. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields.", + }, + "charge_info": { + Type: schema.TypeList, + MaxItems: 1, + Required: true, + ForceNew: true, + Description: "Payment methods.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "charge_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + "PostPaid", + "PrePaid", + }, false), + Description: "Payment type. Value:\nPostPaid - Pay-As-You-Go\nPrePaid - Yearly and monthly (default).", + }, + "auto_renew": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + ForceNew: true, + DiffSuppressFunc: RdsMysqlInstanceImportDiffSuppress, + Description: "Whether to automatically renew in prepaid scenarios.", + }, + "period_unit": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + DiffSuppressFunc: RdsMysqlInstanceImportDiffSuppress, + Description: "The purchase cycle in the prepaid scenario.\nMonth - monthly subscription (default)\nYear - Package year.", + }, + "period": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + DiffSuppressFunc: RdsMysqlInstanceImportDiffSuppress, + Description: "Purchase duration in prepaid scenarios. Default: 1.", + }, + }, + }, + }, + "allow_list_ids": { + Type: schema.TypeSet, + Optional: true, + Set: schema.HashString, + Description: "Allow list Ids of the RDS instance.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "parameters": { + Type: schema.TypeSet, + Optional: true, + Set: parameterHash, + Description: "Parameter of the RDS instance. This field can only be added or modified. Deleting this field is invalid.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "parameter_name": { + Type: schema.TypeString, + Required: true, + Description: "Parameter name.", + }, + "parameter_value": { + Type: schema.TypeString, + Required: true, + Description: "Parameter value.", + }, + }, + }, + }, + }, + } + dataSource := DataSourceVolcengineRdsMysqlInstances().Schema["rds_mysql_instances"].Elem.(*schema.Resource).Schema + delete(dataSource, "id") + ve.MergeDateSourceToResource(dataSource, &resource.Schema) + return resource +} + +func resourceVolcengineRdsMysqlInstanceCreate(d *schema.ResourceData, meta interface{}) (err error) { + rdsMysqlInstanceService := NewRdsMysqlInstanceService(meta.(*ve.SdkClient)) + err = rdsMysqlInstanceService.Dispatcher.Create(rdsMysqlInstanceService, d, ResourceVolcengineRdsMysqlInstance()) + if err != nil { + return fmt.Errorf("error on creating RDS mysql instance %q, %w", d.Id(), err) + } + return resourceVolcengineRdsMysqlInstanceRead(d, meta) +} + +func resourceVolcengineRdsMysqlInstanceRead(d *schema.ResourceData, meta interface{}) (err error) { + rdsMysqlInstanceService := NewRdsMysqlInstanceService(meta.(*ve.SdkClient)) + err = rdsMysqlInstanceService.Dispatcher.Read(rdsMysqlInstanceService, d, ResourceVolcengineRdsMysqlInstance()) + if err != nil { + return fmt.Errorf("error on reading RDS mysql instance %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcengineRdsMysqlInstanceUpdate(d *schema.ResourceData, meta interface{}) (err error) { + rdsMysqlInstanceService := NewRdsMysqlInstanceService(meta.(*ve.SdkClient)) + err = rdsMysqlInstanceService.Dispatcher.Update(rdsMysqlInstanceService, d, ResourceVolcengineRdsMysqlInstance()) + if err != nil { + return fmt.Errorf("error on updating RDS mysql instance %q, %w", d.Id(), err) + } + return resourceVolcengineRdsMysqlInstanceRead(d, meta) +} + +func resourceVolcengineRdsMysqlInstanceDelete(d *schema.ResourceData, meta interface{}) (err error) { + rdsMysqlInstanceService := NewRdsMysqlInstanceService(meta.(*ve.SdkClient)) + err = rdsMysqlInstanceService.Dispatcher.Delete(rdsMysqlInstanceService, d, ResourceVolcengineRdsMysqlInstance()) + if err != nil { + return fmt.Errorf("error on deleting RDS mysql instance %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/rds_mysql/rds_mysql_instance/service_volcengine_rds_mysql_instance.go b/volcengine/rds_mysql/rds_mysql_instance/service_volcengine_rds_mysql_instance.go new file mode 100644 index 00000000..1e4b8f6a --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_instance/service_volcengine_rds_mysql_instance.go @@ -0,0 +1,740 @@ +package rds_mysql_instance + +import ( + "errors" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineRdsMysqlInstanceService struct { + Client *ve.SdkClient + Dispatcher *ve.Dispatcher +} + +func NewRdsMysqlInstanceService(c *ve.SdkClient) *VolcengineRdsMysqlInstanceService { + return &VolcengineRdsMysqlInstanceService{ + Client: c, + Dispatcher: &ve.Dispatcher{}, + } +} + +func (s *VolcengineRdsMysqlInstanceService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineRdsMysqlInstanceService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + rdsInstance map[string]interface{} + ) + data, err = ve.WithPageNumberQuery(m, "PageSize", "PageNumber", 10, 1, func(condition map[string]interface{}) ([]interface{}, error) { + action := "DescribeDBInstances" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + + results, err = ve.ObtainSdkValue("Result.Instances", *resp) + if err != nil { + return data, err + } + if results == nil { + results = []interface{}{} + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Instances is not Slice") + } + return data, err + }) + + if err != nil { + return nil, err + } + + for _, v := range data { + if rdsInstance, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } else { + // query rds instance detail + instanceDetailInfo, err := s.Client.UniversalClient.DoCall(getUniversalInfo("DescribeDBInstanceDetail"), &map[string]interface{}{ + "InstanceId": rdsInstance["InstanceId"], + }) + if err != nil { + logger.Info("DescribeDBInstanceDetail error:", err) + continue + } + + // 1. basic info + basicInfo, err := ve.ObtainSdkValue("Result.BasicInfo", *instanceDetailInfo) + if err != nil { + logger.Info("ObtainSdkValue Result.BasicInfo error:", err) + continue + } + if basicInfoMap, ok := basicInfo.(map[string]interface{}); ok { + rdsInstance["VCpu"] = basicInfoMap["VCPU"] + rdsInstance["Memory"] = basicInfoMap["Memory"] + rdsInstance["UpdateTime"] = basicInfoMap["UpdateTime"] + rdsInstance["BackupUse"] = basicInfoMap["BackupUse"] + rdsInstance["DataSyncMode"] = basicInfoMap["DataSyncMode"] + } + + // 2. endpoint info + endpoints, err := ve.ObtainSdkValue("Result.Endpoints", *instanceDetailInfo) + if err != nil { + logger.Info("ObtainSdkValue Result.Endpoints error:", err) + continue + } + for _, v1 := range endpoints.([]interface{}) { + if endpoint, ok := v1.(map[string]interface{}); ok { + endpoint["Addresses"] = convertAddressInfo(endpoint["Addresses"]) + endpoint["NodeWeight"] = endpoint["ReadOnlyNodeWeight"] + delete(endpoint, "ReadOnlyNodeWeight") + } + } + rdsInstance["Endpoints"] = endpoints + + // 3. node info + nodes, err := ve.ObtainSdkValue("Result.Nodes", *instanceDetailInfo) + if err != nil { + logger.Info("ObtainSdkValue Result.Nodes error:", err) + continue + } + for _, v2 := range nodes.([]interface{}) { + if node, ok := v2.(map[string]interface{}); ok { + node["VCpu"] = node["VCPU"] + delete(node, "VCPU") + } + } + rdsInstance["Nodes"] = nodes + } + } + + return data, err +} + +func (s *VolcengineRdsMysqlInstanceService) ReadResource(resourceData *schema.ResourceData, rdsInstanceId string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if rdsInstanceId == "" { + rdsInstanceId = s.ReadResourceId(resourceData.Id()) + } + req := map[string]interface{}{ + "InstanceId": rdsInstanceId, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + if data, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + } + if len(data) == 0 { + return data, fmt.Errorf("Rds instance %s not exist ", rdsInstanceId) + } + + if nodeArr, ok := data["Nodes"].([]interface{}); ok { + for _, node := range nodeArr { + if nodeMap, ok1 := node.(map[string]interface{}); ok1 { + if nodeMap["NodeType"] == "Primary" { + data["PrimaryZoneId"] = nodeMap["ZoneId"] + } else if nodeMap["NodeType"] == "Secondary" { + data["SecondaryZoneId"] = nodeMap["ZoneId"] + } + } + } + } + + data["ChargeInfo"] = data["ChargeDetail"] + + return data, err +} + +func (s *VolcengineRdsMysqlInstanceService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{}, + Delay: 10 * time.Second, + MinTimeout: 1 * time.Second, + Target: target, + Timeout: timeout, + Refresh: func() (result interface{}, state string, err error) { + var ( + demo map[string]interface{} + status interface{} + failStates []string + ) + failStates = append(failStates, "Error") + + if err = resource.Retry(20*time.Minute, func() *resource.RetryError { + demo, err = s.ReadResource(resourceData, id) + if err != nil { + if ve.ResourceNotFoundError(err) { + return resource.RetryableError(err) + } else { + return resource.NonRetryableError(err) + } + } + return nil + }); err != nil { + return nil, "", err + } + + status, err = ve.ObtainSdkValue("InstanceStatus", demo) + if err != nil { + return nil, "", err + } + for _, v := range failStates { + if v == status.(string) { + return nil, "", fmt.Errorf("Rds instance status error, status:%s ", status.(string)) + } + } + //注意 返回的第一个参数不能为空 否则会一直等下去 + return demo, status.(string), err + }, + } + +} + +func (*VolcengineRdsMysqlInstanceService) WithResourceResponseHandlers(rdsInstance map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return rdsInstance, map[string]ve.ResponseConvert{ + "DBEngineVersion": { + TargetField: "db_engine_version", + }, + "TimeZone": { + TargetField: "db_time_zone", + }, + }, nil + } + return []ve.ResourceResponseHandler{handler} + +} + +func (s *VolcengineRdsMysqlInstanceService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + instanceCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateDBInstance", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "db_engine_version": { + TargetField: "DBEngineVersion", + }, + "storage_space": { + TargetField: "StorageSpace", + }, + "subnet_id": { + TargetField: "SubnetId", + }, + "instance_name": { + TargetField: "InstanceName", + }, + "lower_case_table_names": { + TargetField: "LowerCaseTableNames", + }, + "db_time_zone": { + TargetField: "DBTimeZone", + }, + "charge_info": { + ConvertType: ve.ConvertJsonObject, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + var ( + nodeInfos []interface{} + subnets []interface{} + results interface{} + ok bool + ) + + // 1. NodeInfo + primaryNodeInfo := make(map[string]interface{}) + primaryNodeInfo["NodeType"] = "Primary" + primaryNodeInfo["ZoneId"] = d.Get("primary_zone_id") + primaryNodeInfo["NodeSpec"] = d.Get("node_spec") + nodeInfos = append(nodeInfos, primaryNodeInfo) + + secondaryNodeInfo := make(map[string]interface{}) + secondaryNodeInfo["NodeType"] = "Secondary" + secondaryNodeInfo["ZoneId"] = d.Get("secondary_zone_id") + secondaryNodeInfo["NodeSpec"] = d.Get("node_spec") + nodeInfos = append(nodeInfos, secondaryNodeInfo) + + // 2. VpcId + subnetId := d.Get("subnet_id") + req := map[string]interface{}{ + "SubnetIds.1": subnetId, + } + action := "DescribeSubnets" + resp, err := s.Client.VpcClient.DescribeSubnetsCommon(&req) + if err != nil { + return false, err + } + logger.Debug(logger.RespFormat, action, req, *resp) + results, err = ve.ObtainSdkValue("Result.Subnets", *resp) + if err != nil { + return false, err + } + if results == nil { + results = []interface{}{} + } + if subnets, ok = results.([]interface{}); !ok { + return false, errors.New("Result.Subnets is not Slice") + } + if len(subnets) == 0 { + return false, fmt.Errorf("subnet %s not exist", subnetId.(string)) + } + vpcId := subnets[0].(map[string]interface{})["VpcId"] + + (*call.SdkParam)["NodeInfo"] = nodeInfos + (*call.SdkParam)["StorageType"] = "LocalSSD" + (*call.SdkParam)["VpcId"] = vpcId + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + //创建rdsInstance + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + //注意 获取内容 这个地方不能是指针 需要转一次 + id, _ := ve.ObtainSdkValue("Result.InstanceId", *resp) + d.SetId(id.(string)) + return nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + }, + } + callbacks = append(callbacks, instanceCallback) + + // 关联白名单 + allowListCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "AssociateAllowList", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "allow_list_ids": { + ConvertType: ve.ConvertJsonArray, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if len(*call.SdkParam) > 0 { + (*call.SdkParam)["InstanceIds"] = []string{d.Id()} + return true, nil + } + return false, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + }, + } + callbacks = append(callbacks, allowListCallback) + + // 关联参数 + parameterCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyDBInstanceParameters", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "parameters": { + ConvertType: ve.ConvertJsonObjectArray, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if len(*call.SdkParam) > 0 { + (*call.SdkParam)["InstanceId"] = d.Id() + return true, nil + } + return false, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + }, + } + callbacks = append(callbacks, parameterCallback) + + return callbacks +} + +func (s *VolcengineRdsMysqlInstanceService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + // 1. NodeSpec & StorageSpace + if resourceData.HasChanges("node_spec", "storage_space") { + instanceCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyDBInstanceSpec", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["InstanceId"] = d.Id() + + if d.HasChange("storage_space") { + (*call.SdkParam)["StorageType"] = "LocalSSD" + (*call.SdkParam)["StorageSpace"] = d.Get("storage_space") + } + + if d.HasChange("node_spec") { + nodeInfos := make([]interface{}, 0) + primaryNodeInfo := make(map[string]interface{}) + secondaryNodeInfo := make(map[string]interface{}) + + instance, err := s.ReadResource(resourceData, d.Id()) + if err != nil { + return false, err + } + if nodeArr, ok := instance["Nodes"].([]interface{}); ok { + for _, node := range nodeArr { + if nodeMap, ok1 := node.(map[string]interface{}); ok1 { + if nodeMap["NodeType"] == "Primary" { + primaryNodeInfo["NodeId"] = nodeMap["NodeId"] + } else if nodeMap["NodeType"] == "Secondary" { + secondaryNodeInfo["NodeId"] = nodeMap["NodeId"] + } else if nodeMap["NodeType"] == "ReadOnly" { + readonlyNodeInfo := make(map[string]interface{}) + readonlyNodeInfo["NodeId"] = nodeMap["NodeId"] + readonlyNodeInfo["NodeType"] = nodeMap["NodeType"] + readonlyNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + readonlyNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, readonlyNodeInfo) + } + } + } + } + + primaryNodeInfo["NodeType"] = "Primary" + primaryNodeInfo["ZoneId"] = d.Get("primary_zone_id") + primaryNodeInfo["NodeSpec"] = d.Get("node_spec") + primaryNodeInfo["NodeOperateType"] = "Modify" + nodeInfos = append(nodeInfos, primaryNodeInfo) + + secondaryNodeInfo["NodeType"] = "Secondary" + secondaryNodeInfo["ZoneId"] = d.Get("secondary_zone_id") + secondaryNodeInfo["NodeSpec"] = d.Get("node_spec") + secondaryNodeInfo["NodeOperateType"] = "Modify" + nodeInfos = append(nodeInfos, secondaryNodeInfo) + + (*call.SdkParam)["NodeInfo"] = nodeInfos + } + + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + common, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + if err != nil { + return common, err + } + return common, nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + callbacks = append(callbacks, instanceCallback) + } + + // InstanceName + if resourceData.HasChange("instance_name") { + nameCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyDBInstanceName", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "instance_name": { + TargetField: "InstanceNewName", + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if len(*call.SdkParam) > 0 { + (*call.SdkParam)["InstanceId"] = d.Id() + return true, nil + } + return false, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + common, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + if err != nil { + return common, err + } + return common, nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + callbacks = append(callbacks, nameCallback) + } + + // AllowList + if resourceData.HasChange("allow_list_ids") { + addAlIds, removeAlIds, _, _ := ve.GetSetDifference("allow_list_ids", resourceData, schema.HashString, false) + + allowListRemoveCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DisassociateAllowList", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if removeAlIds != nil && len(removeAlIds.List()) > 0 { + (*call.SdkParam)["InstanceIds"] = []string{d.Id()} + (*call.SdkParam)["AllowListIds"] = removeAlIds.List() + return true, nil + } + return false, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + common, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + if err != nil { + return common, err + } + return common, nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + callbacks = append(callbacks, allowListRemoveCallback) + + allowListAddCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "AssociateAllowList", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertIgnore, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if addAlIds != nil && len(addAlIds.List()) > 0 { + (*call.SdkParam)["InstanceIds"] = []string{d.Id()} + (*call.SdkParam)["AllowListIds"] = addAlIds.List() + return true, nil + } + return false, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + common, err := s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + if err != nil { + return common, err + } + return common, nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + callbacks = append(callbacks, allowListAddCallback) + } + + // Parameters + if resourceData.HasChange("parameters") { + parameterCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyDBInstanceParameters", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "parameters": { + ConvertType: ve.ConvertJsonObjectArray, + ForceGet: true, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if len(*call.SdkParam) > 0 { + (*call.SdkParam)["InstanceId"] = d.Id() + return true, nil + } + return false, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + + callbacks = append(callbacks, parameterCallback) + } + + return callbacks +} + +func (s *VolcengineRdsMysqlInstanceService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + // 1. Disassociate Allow List + allowListCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DisassociateAllowList", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "allow_list_ids": { + ConvertType: ve.ConvertJsonArray, + ForceGet: true, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + if len(*call.SdkParam) > 0 { + (*call.SdkParam)["InstanceIds"] = []string{d.Id()} + return true, nil + } + return false, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + }, + }, + } + callbacks = append(callbacks, allowListCallback) + + // 2. delete instance + removeCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteDBInstance", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "InstanceId": resourceData.Id(), + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + //删除RdsInstance + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + CallError: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall, baseErr error) error { + //出现错误后重试 + return resource.Retry(15*time.Minute, func() *resource.RetryError { + _, callErr := s.ReadResource(d, "") + if callErr != nil { + if ve.ResourceNotFoundError(callErr) { + return nil + } else { + return resource.NonRetryableError(fmt.Errorf("error on reading rds mysql instance on delete %q, %w", d.Id(), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + }, + } + callbacks = append(callbacks, removeCallback) + + return callbacks +} + +func (s *VolcengineRdsMysqlInstanceService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + RequestConverts: map[string]ve.RequestConvert{ + "db_engine_version": { + TargetField: "DBEngineVersion", + }, + }, + NameField: "InstanceName", + IdField: "InstanceId", + CollectField: "rds_mysql_instances", + ContentType: ve.ContentTypeJson, + ResponseConverts: map[string]ve.ResponseConvert{ + "InstanceId": { + TargetField: "id", + KeepDefault: true, + }, + "DBEngineVersion": { + TargetField: "db_engine_version", + }, + }, + } +} + +func convertAddressInfo(addressesInfo interface{}) interface{} { + if addressesInfo == nil { + return nil + } + var addresses []interface{} + if addressInfoArr, ok := addressesInfo.([]interface{}); ok { + for _, address := range addressInfoArr { + if addressMap, ok := address.(map[string]interface{}); ok { + addressMap["IpAddress"] = addressMap["IPAddress"] + addressMap["DnsVisibility"] = addressMap["DNSVisibility"] + delete(addressMap, "IPAddress") + delete(addressMap, "DNSVisibility") + } + addresses = append(addresses, address) + } + } + + return addresses +} + +func (s *VolcengineRdsMysqlInstanceService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "rds_mysql", + Version: "2022-01-01", + HttpMethod: ve.POST, + ContentType: ve.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/rds_mysql/rds_mysql_instance_readonly_node/common_volcengine_rds_mysql_instance_readonly_node.go b/volcengine/rds_mysql/rds_mysql_instance_readonly_node/common_volcengine_rds_mysql_instance_readonly_node.go new file mode 100644 index 00000000..d2594d03 --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_instance_readonly_node/common_volcengine_rds_mysql_instance_readonly_node.go @@ -0,0 +1,22 @@ +package rds_mysql_instance_readonly_node + +import ( + "fmt" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +var rdsMysqlInstanceReadonlyNodeImporter = func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must split with ':'") + } + if err := data.Set("instance_id", items[0]); err != nil { + return []*schema.ResourceData{data}, err + } + if err := data.Set("node_id", items[1]); err != nil { + return []*schema.ResourceData{data}, err + } + return []*schema.ResourceData{data}, nil +} diff --git a/volcengine/rds_mysql/rds_mysql_instance_readonly_node/resource_volcengine_rds_mysql_instance_readonly_node.go b/volcengine/rds_mysql/rds_mysql_instance_readonly_node/resource_volcengine_rds_mysql_instance_readonly_node.go new file mode 100644 index 00000000..1eaa1b38 --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_instance_readonly_node/resource_volcengine_rds_mysql_instance_readonly_node.go @@ -0,0 +1,96 @@ +package rds_mysql_instance_readonly_node + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +Rds Mysql Instance Readonly Node can be imported using the instance_id:node_id, e.g. +``` +$ terraform import volcengine_rds_mysql_instance_readonly_node.default mysql-72da4258c2c7:mysql-72da4258c2c7-r7f93 +``` + +*/ + +func ResourceVolcengineRdsMysqlInstanceReadonlyNode() *schema.Resource { + return &schema.Resource{ + Create: resourceVolcengineRdsMysqlInstanceReadonlyNodeCreate, + Read: resourceVolcengineRdsMysqlInstanceReadonlyNodeRead, + Update: resourceVolcengineRdsMysqlInstanceReadonlyNodeUpdate, + Delete: resourceVolcengineRdsMysqlInstanceReadonlyNodeDelete, + Importer: &schema.ResourceImporter{ + State: rdsMysqlInstanceReadonlyNodeImporter, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(1 * time.Hour), + Update: schema.DefaultTimeout(1 * time.Hour), + Delete: schema.DefaultTimeout(1 * time.Hour), + }, + Schema: map[string]*schema.Schema{ + "instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The RDS mysql instance id of the readonly node.", + }, + "node_spec": { + Type: schema.TypeString, + Required: true, + Description: "The specification of readonly node.", + }, + "zone_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The available zone of readonly node.", + }, + "node_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the readonly node.", + }, + }, + } +} + +func resourceVolcengineRdsMysqlInstanceReadonlyNodeCreate(d *schema.ResourceData, meta interface{}) (err error) { + rdsMysqlInstanceReadonlyNodeService := NewRdsMysqlInstanceReadonlyNodeService(meta.(*ve.SdkClient)) + err = rdsMysqlInstanceReadonlyNodeService.Dispatcher.Create(rdsMysqlInstanceReadonlyNodeService, d, ResourceVolcengineRdsMysqlInstanceReadonlyNode()) + if err != nil { + return fmt.Errorf("error on creating RDS mysql instance readonly node %q, %w", d.Id(), err) + } + return resourceVolcengineRdsMysqlInstanceReadonlyNodeRead(d, meta) +} + +func resourceVolcengineRdsMysqlInstanceReadonlyNodeRead(d *schema.ResourceData, meta interface{}) (err error) { + rdsMysqlInstanceReadonlyNodeService := NewRdsMysqlInstanceReadonlyNodeService(meta.(*ve.SdkClient)) + err = rdsMysqlInstanceReadonlyNodeService.Dispatcher.Read(rdsMysqlInstanceReadonlyNodeService, d, ResourceVolcengineRdsMysqlInstanceReadonlyNode()) + if err != nil { + return fmt.Errorf("error on reading RDS mysql instance readonly node %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcengineRdsMysqlInstanceReadonlyNodeUpdate(d *schema.ResourceData, meta interface{}) (err error) { + rdsMysqlInstanceReadonlyNodeService := NewRdsMysqlInstanceReadonlyNodeService(meta.(*ve.SdkClient)) + err = rdsMysqlInstanceReadonlyNodeService.Dispatcher.Update(rdsMysqlInstanceReadonlyNodeService, d, ResourceVolcengineRdsMysqlInstanceReadonlyNode()) + if err != nil { + return fmt.Errorf("error on updating RDS mysql instance readonly node %q, %w", d.Id(), err) + } + return resourceVolcengineRdsMysqlInstanceReadonlyNodeRead(d, meta) +} + +func resourceVolcengineRdsMysqlInstanceReadonlyNodeDelete(d *schema.ResourceData, meta interface{}) (err error) { + rdsMysqlInstanceReadonlyNodeService := NewRdsMysqlInstanceReadonlyNodeService(meta.(*ve.SdkClient)) + err = rdsMysqlInstanceReadonlyNodeService.Dispatcher.Delete(rdsMysqlInstanceReadonlyNodeService, d, ResourceVolcengineRdsMysqlInstanceReadonlyNode()) + if err != nil { + return fmt.Errorf("error on deleting RDS mysql instance readonly node %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/rds_mysql/rds_mysql_instance_readonly_node/service_volcengine_rds_mysql_instance_readonly_node.go b/volcengine/rds_mysql/rds_mysql_instance_readonly_node/service_volcengine_rds_mysql_instance_readonly_node.go new file mode 100644 index 00000000..80dffb64 --- /dev/null +++ b/volcengine/rds_mysql/rds_mysql_instance_readonly_node/service_volcengine_rds_mysql_instance_readonly_node.go @@ -0,0 +1,397 @@ +package rds_mysql_instance_readonly_node + +import ( + "fmt" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" + "github.com/volcengine/terraform-provider-volcengine/volcengine/rds_mysql/rds_mysql_instance" +) + +type VolcengineRdsMysqlInstanceReadonlyNodeService struct { + Client *ve.SdkClient + Dispatcher *ve.Dispatcher + RdsInstanceService *rds_mysql_instance.VolcengineRdsMysqlInstanceService +} + +func NewRdsMysqlInstanceReadonlyNodeService(c *ve.SdkClient) *VolcengineRdsMysqlInstanceReadonlyNodeService { + return &VolcengineRdsMysqlInstanceReadonlyNodeService{ + Client: c, + Dispatcher: &ve.Dispatcher{}, + RdsInstanceService: rds_mysql_instance.NewRdsMysqlInstanceService(c), + } +} + +func (s *VolcengineRdsMysqlInstanceReadonlyNodeService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineRdsMysqlInstanceReadonlyNodeService) ReadResources(m map[string]interface{}) (data []interface{}, err error) { + return data, err +} + +func (s *VolcengineRdsMysqlInstanceReadonlyNodeService) ReadResource(resourceData *schema.ResourceData, rdsInstanceNodeId string) (data map[string]interface{}, err error) { + if rdsInstanceNodeId == "" { + rdsInstanceNodeId = resourceData.Id() + } + + ids := strings.Split(rdsInstanceNodeId, ":") + if len(ids) != 2 { + return map[string]interface{}{}, fmt.Errorf("invalid rdsInstanceNodeId: %s", rdsInstanceNodeId) + } + + instanceId := ids[0] + nodeId := ids[1] + + result, err := s.RdsInstanceService.ReadResource(resourceData, instanceId) + if err != nil { + return result, err + } + if len(result) == 0 { + return result, fmt.Errorf("Rds instance %s not exist ", instanceId) + } + + if nodeArr, ok := result["Nodes"].([]interface{}); ok { + for _, node := range nodeArr { + if nodeMap, ok1 := node.(map[string]interface{}); ok1 { + if nodeMap["NodeId"] == nodeId { + data = nodeMap + } + } + } + } + if len(data) == 0 { + return data, fmt.Errorf("Rds instance readonly node %s is not exist ", nodeId) + } + data["NodeId"] = nodeId + + return data, err +} + +func (s *VolcengineRdsMysqlInstanceReadonlyNodeService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (*VolcengineRdsMysqlInstanceReadonlyNodeService) WithResourceResponseHandlers(rdsInstance map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return rdsInstance, nil, nil + } + return []ve.ResourceResponseHandler{handler} + +} + +func (s *VolcengineRdsMysqlInstanceReadonlyNodeService) CreateResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + var ( + callbacks []ve.Callback + existingReadOnlyNodeIds = make(map[string]bool) + ) + + nodeCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyDBInstanceSpec", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertIgnore, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (common *map[string]interface{}, err error) { + // 在LockId执行后再进行已有Node信息的查询 + (*call.SdkParam)["InstanceId"] = d.Get("instance_id").(string) + + nodeInfos := make([]interface{}, 0) + // 1. 获取当前RdsInstance已有的Node信息 + instance, err := s.RdsInstanceService.ReadResource(resourceData, d.Get("instance_id").(string)) + if err != nil { + return common, err + } + if nodeArr, ok := instance["Nodes"].([]interface{}); ok { + for _, node := range nodeArr { + if nodeMap, ok1 := node.(map[string]interface{}); ok1 { + if nodeMap["NodeType"] == "Primary" { + primaryNodeInfo := make(map[string]interface{}) + primaryNodeInfo["NodeId"] = nodeMap["NodeId"] + primaryNodeInfo["NodeType"] = nodeMap["NodeType"] + primaryNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + primaryNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, primaryNodeInfo) + } else if nodeMap["NodeType"] == "Secondary" { + secondaryNodeInfo := make(map[string]interface{}) + secondaryNodeInfo["NodeId"] = nodeMap["NodeId"] + secondaryNodeInfo["NodeType"] = nodeMap["NodeType"] + secondaryNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + secondaryNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, secondaryNodeInfo) + } else if nodeMap["NodeType"] == "ReadOnly" { + readonlyNodeInfo := make(map[string]interface{}) + readonlyNodeInfo["NodeId"] = nodeMap["NodeId"] + readonlyNodeInfo["NodeType"] = nodeMap["NodeType"] + readonlyNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + readonlyNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, readonlyNodeInfo) + + existingReadOnlyNodeIds[readonlyNodeInfo["NodeId"].(string)] = true + } + } + } + } + + // 2. 新增 readonly node + newReadonlyNodeInfo := make(map[string]interface{}) + newReadonlyNodeInfo["NodeType"] = "ReadOnly" + newReadonlyNodeInfo["NodeSpec"] = d.Get("node_spec") + newReadonlyNodeInfo["ZoneId"] = d.Get("zone_id") + newReadonlyNodeInfo["NodeOperateType"] = "Create" + nodeInfos = append(nodeInfos, newReadonlyNodeInfo) + + (*call.SdkParam)["NodeInfo"] = nodeInfos + + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + common, err = s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + if err != nil { + return common, err + } + return common, nil + }, + AfterRefresh: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) error { + var ( + instance = make(map[string]interface{}) + err error + ) + instance, err = s.RdsInstanceService.ReadResource(d, d.Get("instance_id").(string)) + if err != nil { + return err + } + var newReadonlyNodeId string + if nodeArr, ok := instance["Nodes"].([]interface{}); ok { + for _, node := range nodeArr { + if nodeMap, ok1 := node.(map[string]interface{}); ok1 { + if nodeMap["NodeType"] == "ReadOnly" { + if _, ok := existingReadOnlyNodeIds[nodeMap["NodeId"].(string)]; !ok { + newReadonlyNodeId = nodeMap["NodeId"].(string) + } + } + } + } + } + // ResourceData中,rds_mysql_instance_readonly_node的Id形式为'instance_id:node_id' + logger.Debug(logger.ReqFormat, "newReadonlyNodeId", newReadonlyNodeId) + if newReadonlyNodeId == "" { + return fmt.Errorf(" Failed to create readonly node ") + } + id := fmt.Sprintf("%s:%s", d.Get("instance_id"), newReadonlyNodeId) + d.SetId(id) + return nil + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("instance_id").(string) + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + s.RdsInstanceService: { + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + ResourceId: resourceData.Get("instance_id").(string), + }, + }, + }, + } + callbacks = append(callbacks, nodeCallback) + + return callbacks +} + +func (s *VolcengineRdsMysqlInstanceReadonlyNodeService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + if resourceData.HasChange("node_spec") { + nodeCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyDBInstanceSpec", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertIgnore, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (common *map[string]interface{}, err error) { + // 在 LockId 后再进行已有 Node 信息的查询 + ids := strings.Split(d.Id(), ":") + if len(ids) != 2 { + return common, fmt.Errorf("invalid rdsInstanceNodeId: %s", d.Id()) + } + instanceId := ids[0] + nodeId := ids[1] + (*call.SdkParam)["InstanceId"] = instanceId + + nodeInfos := make([]interface{}, 0) + // 1. 获取当前RdsInstance已有的Node信息 + instance, err := s.RdsInstanceService.ReadResource(resourceData, d.Get("instance_id").(string)) + if err != nil { + return common, err + } + if nodeArr, ok := instance["Nodes"].([]interface{}); ok { + for _, node := range nodeArr { + if nodeMap, ok1 := node.(map[string]interface{}); ok1 { + if nodeMap["NodeType"] == "Primary" { + primaryNodeInfo := make(map[string]interface{}) + primaryNodeInfo["NodeId"] = nodeMap["NodeId"] + primaryNodeInfo["NodeType"] = nodeMap["NodeType"] + primaryNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + primaryNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, primaryNodeInfo) + } else if nodeMap["NodeType"] == "Secondary" { + secondaryNodeInfo := make(map[string]interface{}) + secondaryNodeInfo["NodeId"] = nodeMap["NodeId"] + secondaryNodeInfo["NodeType"] = nodeMap["NodeType"] + secondaryNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + secondaryNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, secondaryNodeInfo) + } else if nodeMap["NodeType"] == "ReadOnly" && nodeMap["NodeId"] != nodeId { + readonlyNodeInfo := make(map[string]interface{}) + readonlyNodeInfo["NodeId"] = nodeMap["NodeId"] + readonlyNodeInfo["NodeType"] = nodeMap["NodeType"] + readonlyNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + readonlyNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, readonlyNodeInfo) + } + } + } + } + + // 2. 修改当前 readonly node + newReadonlyNodeInfo := make(map[string]interface{}) + newReadonlyNodeInfo["NodeId"] = nodeId + newReadonlyNodeInfo["NodeType"] = "ReadOnly" + newReadonlyNodeInfo["NodeSpec"] = d.Get("node_spec") + newReadonlyNodeInfo["ZoneId"] = d.Get("zone_id") + newReadonlyNodeInfo["NodeOperateType"] = "Modify" + nodeInfos = append(nodeInfos, newReadonlyNodeInfo) + + (*call.SdkParam)["NodeInfo"] = nodeInfos + + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + common, err = s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + if err != nil { + return common, err + } + return common, nil + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("instance_id").(string) + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + s.RdsInstanceService: { + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutUpdate), + ResourceId: resourceData.Get("instance_id").(string), + }, + }, + }, + } + callbacks = append(callbacks, nodeCallback) + } + + return callbacks +} + +func (s *VolcengineRdsMysqlInstanceReadonlyNodeService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + nodeCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyDBInstanceSpec", + ContentType: ve.ContentTypeJson, + ConvertMode: ve.RequestConvertIgnore, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (common *map[string]interface{}, err error) { + // 在 LockId 后再进行已有 Node 信息的查询 + ids := strings.Split(d.Id(), ":") + if len(ids) != 2 { + return common, fmt.Errorf("invalid rdsInstanceNodeId: %s", d.Id()) + } + instanceId := ids[0] + nodeId := ids[1] + (*call.SdkParam)["InstanceId"] = instanceId + + nodeInfos := make([]interface{}, 0) + // 1. 获取当前RdsInstance已有的Node信息 + instance, err := s.RdsInstanceService.ReadResource(resourceData, d.Get("instance_id").(string)) + if err != nil { + return common, err + } + if nodeArr, ok := instance["Nodes"].([]interface{}); ok { + for _, node := range nodeArr { + if nodeMap, ok1 := node.(map[string]interface{}); ok1 { + if nodeMap["NodeType"] == "Primary" { + primaryNodeInfo := make(map[string]interface{}) + primaryNodeInfo["NodeId"] = nodeMap["NodeId"] + primaryNodeInfo["NodeType"] = nodeMap["NodeType"] + primaryNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + primaryNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, primaryNodeInfo) + } else if nodeMap["NodeType"] == "Secondary" { + secondaryNodeInfo := make(map[string]interface{}) + secondaryNodeInfo["NodeId"] = nodeMap["NodeId"] + secondaryNodeInfo["NodeType"] = nodeMap["NodeType"] + secondaryNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + secondaryNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, secondaryNodeInfo) + } else if nodeMap["NodeType"] == "ReadOnly" && nodeMap["NodeId"] != nodeId { + readonlyNodeInfo := make(map[string]interface{}) + readonlyNodeInfo["NodeId"] = nodeMap["NodeId"] + readonlyNodeInfo["NodeType"] = nodeMap["NodeType"] + readonlyNodeInfo["NodeSpec"] = nodeMap["NodeSpec"] + readonlyNodeInfo["ZoneId"] = nodeMap["ZoneId"] + nodeInfos = append(nodeInfos, readonlyNodeInfo) + } + } + } + } + + // 2. 删除 readonly node + newReadonlyNodeInfo := make(map[string]interface{}) + newReadonlyNodeInfo["NodeId"] = nodeId + newReadonlyNodeInfo["NodeType"] = "ReadOnly" + newReadonlyNodeInfo["NodeSpec"] = d.Get("node_spec") + newReadonlyNodeInfo["ZoneId"] = d.Get("zone_id") + newReadonlyNodeInfo["NodeOperateType"] = "Delete" + nodeInfos = append(nodeInfos, newReadonlyNodeInfo) + + (*call.SdkParam)["NodeInfo"] = nodeInfos + + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + common, err = s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + if err != nil { + return common, err + } + return common, nil + }, + LockId: func(d *schema.ResourceData) string { + return d.Get("instance_id").(string) + }, + ExtraRefresh: map[ve.ResourceService]*ve.StateRefresh{ + s.RdsInstanceService: { + Target: []string{"Running"}, + Timeout: resourceData.Timeout(schema.TimeoutDelete), + ResourceId: resourceData.Get("instance_id").(string), + }, + }, + }, + } + callbacks = append(callbacks, nodeCallback) + + return callbacks +} + +func (s *VolcengineRdsMysqlInstanceReadonlyNodeService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{} +} + +func (s *VolcengineRdsMysqlInstanceReadonlyNodeService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "rds_mysql", + Version: "2022-01-01", + HttpMethod: ve.POST, + ContentType: ve.ApplicationJSON, + Action: actionName, + } +} diff --git a/volcengine/rds_v2/rds_instance_v2/service_volcengine_rds_instance_v2.go b/volcengine/rds_v2/rds_instance_v2/service_volcengine_rds_instance_v2.go index fce2f5f2..c23de911 100644 --- a/volcengine/rds_v2/rds_instance_v2/service_volcengine_rds_instance_v2.go +++ b/volcengine/rds_v2/rds_instance_v2/service_volcengine_rds_instance_v2.go @@ -166,10 +166,21 @@ func (s *VolcengineRdsInstanceService) RefreshResourceState(resourceData *schema failStates []string ) failStates = append(failStates, "Error") - demo, err = s.ReadResource(resourceData, id) - if err != nil { + + if err = resource.Retry(20*time.Minute, func() *resource.RetryError { + demo, err = s.ReadResource(resourceData, id) + if err != nil { + if volc.ResourceNotFoundError(err) { + return resource.RetryableError(err) + } else { + return resource.NonRetryableError(err) + } + } + return nil + }); err != nil { return nil, "", err } + status, err = volc.ObtainSdkValue("InstanceStatus", demo) if err != nil { return nil, "", err diff --git a/volcengine/tos/bucket/resource_volcengine_tos_bucket.go b/volcengine/tos/bucket/resource_volcengine_tos_bucket.go index c7ece4ad..905e9ea3 100644 --- a/volcengine/tos/bucket/resource_volcengine_tos_bucket.go +++ b/volcengine/tos/bucket/resource_volcengine_tos_bucket.go @@ -15,7 +15,7 @@ import ( Import Tos Bucket can be imported using the id, e.g. ``` -$ terraform import volcengine_tos_bucket.default region:bucketName +$ terraform import volcengine_tos_bucket.default bucketName ``` */ diff --git a/volcengine/tos/bucket_policy/resource_volcengine_tos_bucket_policy.go b/volcengine/tos/bucket_policy/resource_volcengine_tos_bucket_policy.go new file mode 100644 index 00000000..6b923ab9 --- /dev/null +++ b/volcengine/tos/bucket_policy/resource_volcengine_tos_bucket_policy.go @@ -0,0 +1,152 @@ +package bucket_policy + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +Tos Bucket can be imported using the id, e.g. +``` +$ terraform import volcengine_tos_bucket_policy.default bucketName:policy +``` + +*/ + +func ResourceVolcengineTosBucketPolicy() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineTosBucketPolicyCreate, + Read: resourceVolcengineTosBucketPolicyRead, + Update: resourceVolcengineTosBucketPolicyUpdate, + Delete: resourceVolcengineTosBucketPolicyDelete, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(2 * time.Minute), + Update: schema.DefaultTimeout(2 * time.Minute), + Delete: schema.DefaultTimeout(2 * time.Minute), + }, + Importer: &schema.ResourceImporter{ + State: func(data *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + items := strings.Split(data.Id(), ":") + if len(items) != 2 { + return []*schema.ResourceData{data}, fmt.Errorf("import id must be of the form bucketName") + } + _ = data.Set("bucket_name", items[0]) + return []*schema.ResourceData{data}, nil + }, + }, + Schema: map[string]*schema.Schema{ + "bucket_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The name of the bucket.", + }, + "policy": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if k == "policy" { + om := map[string]interface{}{} + nm := map[string]interface{}{} + _ = json.Unmarshal([]byte(old), &om) + _ = json.Unmarshal([]byte(new), &nm) + //暂时不支持version 这里忽略掉 + delete(om, "Version") + delete(nm, "Version") + //重构单一Principal Action Resource 字符串转换数组 + if _, ok := om["Statement"].([]interface{}); ok { + for i, st := range om["Statement"].([]interface{}) { + if _, ok1 := st.(map[string]interface{}); ok1 { + temp := map[string]interface{}{} + for k1, v1 := range st.(map[string]interface{}) { + if k1 == "Principal" || k1 == "Action" || k1 == "Resource" { + if reflect.TypeOf(v1).Kind() == reflect.String { + temp[k1] = []string{v1.(string)} + } else { + temp[k1] = v1 + } + } else { + temp[k1] = v1 + } + } + om["Statement"].([]interface{})[i] = temp + } + } + } + + if _, ok := nm["Statement"].([]interface{}); ok { + for i, st := range nm["Statement"].([]interface{}) { + if _, ok1 := st.(map[string]interface{}); ok1 { + temp := map[string]interface{}{} + for k1, v1 := range st.(map[string]interface{}) { + if k1 == "Principal" || k1 == "Action" || k1 == "Resource" { + if reflect.TypeOf(v1).Kind() == reflect.String { + temp[k1] = []string{v1.(string)} + } else { + temp[k1] = v1 + } + } else { + temp[k1] = v1 + } + } + nm["Statement"].([]interface{})[i] = temp + } + } + } + + o, _ := json.MarshalIndent(om, "", "") + n, _ := json.MarshalIndent(nm, "", "") + return string(o) == string(n) + } + return false + }, + Description: "The policy document. This is a JSON formatted string. For more information about building Volcengine IAM policy documents with Terraform, see the [Volcengine IAM Policy Document Guide](https://www.volcengine.com/docs/6349/102127).", + }, + }, + } + return resource +} + +func resourceVolcengineTosBucketPolicyCreate(d *schema.ResourceData, meta interface{}) (err error) { + tosBucketService := NewTosBucketPolicyService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Create(tosBucketService, d, ResourceVolcengineTosBucketPolicy()) + if err != nil { + return fmt.Errorf("error on creating tos bucket %q, %s", d.Id(), err) + } + return resourceVolcengineTosBucketPolicyRead(d, meta) +} + +func resourceVolcengineTosBucketPolicyRead(d *schema.ResourceData, meta interface{}) (err error) { + tosBucketService := NewTosBucketPolicyService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Read(tosBucketService, d, ResourceVolcengineTosBucketPolicy()) + if err != nil { + return fmt.Errorf("error on reading tos bucket %q, %s", d.Id(), err) + } + return err +} + +func resourceVolcengineTosBucketPolicyUpdate(d *schema.ResourceData, meta interface{}) (err error) { + tosBucketService := NewTosBucketPolicyService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Update(tosBucketService, d, ResourceVolcengineTosBucketPolicy()) + if err != nil { + return fmt.Errorf("error on updating tos bucket %q, %s", d.Id(), err) + } + return resourceVolcengineTosBucketPolicyRead(d, meta) +} + +func resourceVolcengineTosBucketPolicyDelete(d *schema.ResourceData, meta interface{}) (err error) { + tosBucketService := NewTosBucketPolicyService(meta.(*ve.SdkClient)) + err = ve.DefaultDispatcher().Delete(tosBucketService, d, ResourceVolcengineTosBucketPolicy()) + if err != nil { + return fmt.Errorf("error on deleting tos bucket %q, %s", d.Id(), err) + } + return err +} diff --git a/volcengine/tos/bucket_policy/service_volcengine_tos_bucket_policy.go b/volcengine/tos/bucket_policy/service_volcengine_tos_bucket_policy.go new file mode 100644 index 00000000..d1d083a9 --- /dev/null +++ b/volcengine/tos/bucket_policy/service_volcengine_tos_bucket_policy.go @@ -0,0 +1,230 @@ +package bucket_policy + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineTosBucketPolicyService struct { + Client *ve.SdkClient +} + +func NewTosBucketPolicyService(c *ve.SdkClient) *VolcengineTosBucketPolicyService { + return &VolcengineTosBucketPolicyService{ + Client: c, + } +} + +func (s *VolcengineTosBucketPolicyService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineTosBucketPolicyService) ReadResources(condition map[string]interface{}) (data []interface{}, err error) { + tos := s.Client.TosClient + var ( + action string + resp *map[string]interface{} + results interface{} + ) + action = "GetBucketPolicy" + logger.Debug(logger.ReqFormat, action, nil) + resp, err = tos.DoTosCall(ve.TosInfo{ + HttpMethod: ve.GET, + Domain: condition[ve.TosDomain].(string), + UrlParam: map[string]string{ + "policy": "", + }, + }, nil) + if err != nil { + return data, err + } + results, err = ve.ObtainSdkValue(ve.TosResponse, *resp) + if err != nil { + return data, err + } + + if len(results.(map[string]interface{})) == 0 { + return data, fmt.Errorf("bucket Policy %s not exist ", condition[ve.TosDomain].(string)) + } + + data = append(data, map[string]interface{}{ + "Policy": results.(map[string]interface{}), + }) + return data, err +} + +func (s *VolcengineTosBucketPolicyService) ReadResource(resourceData *schema.ResourceData, instanceId string) (data map[string]interface{}, err error) { + bucketName := resourceData.Get("bucket_name").(string) + if instanceId == "" { + instanceId = s.ReadResourceId(resourceData.Id()) + } else { + instanceId = s.ReadResourceId(instanceId) + } + + var ( + ok bool + results []interface{} + ) + + logger.Debug(logger.ReqFormat, "GetBucketPolicy", bucketName+":"+instanceId) + condition := map[string]interface{}{ + ve.TosDomain: bucketName, + } + results, err = s.ReadResources(condition) + + if err != nil { + return data, err + } + for _, v := range results { + if data, ok = v.(map[string]interface{}); !ok { + return data, fmt.Errorf("Value is not map ") + } + } + + if len(data) == 0 { + return data, fmt.Errorf("bucket Policy %s not exist ", instanceId) + } + + return data, nil +} + +func (s *VolcengineTosBucketPolicyService) RefreshResourceState(data *schema.ResourceData, strings []string, duration time.Duration, id string) *resource.StateChangeConf { + return nil +} + +func (s *VolcengineTosBucketPolicyService) WithResourceResponseHandlers(m map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return m, map[string]ve.ResponseConvert{ + "Policy": { + Convert: func(i interface{}) interface{} { + b, _ := json.Marshal(i) + return string(b) + }, + }, + }, nil + } + return []ve.ResourceResponseHandler{handler} +} + +func (s *VolcengineTosBucketPolicyService) putBucketPolicy(data *schema.ResourceData, resource *schema.Resource, isUpdate bool) ve.Callback { + return ve.Callback{ + Call: ve.SdkCall{ + ServiceCategory: ve.ServiceTos, + Action: "PutBucketPolicy", + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "bucket_name": { + ConvertType: ve.ConvertDefault, + TargetField: "BucketName", + ForceGet: isUpdate, + SpecialParam: &ve.SpecialParam{ + Type: ve.DomainParam, + }, + }, + "policy": { + ForceGet: isUpdate, + ConvertType: ve.ConvertDefault, + }, + }, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + j := (*call.SdkParam)[ve.TosParam].(map[string]interface{})["Policy"] + data := map[string]interface{}{} + err := json.Unmarshal([]byte(j.(string)), &data) + if err != nil { + return false, err + } + delete((*call.SdkParam)[ve.TosParam].(map[string]interface{}), "Policy") + for k, v := range data { + (*call.SdkParam)[ve.TosParam].(map[string]interface{})[k] = v + } + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + param := (*call.SdkParam)[ve.TosParam].(map[string]interface{}) + return s.Client.TosClient.DoTosCall(ve.TosInfo{ + HttpMethod: ve.PUT, + ContentType: ve.ApplicationJSON, + UrlParam: map[string]string{ + "policy": "", + }, + Domain: (*call.SdkParam)[ve.TosDomain].(string), + }, ¶m) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + d.SetId((*call.SdkParam)[ve.TosDomain].(string) + ":POLICY") + return nil + }, + }, + } +} + +func (s *VolcengineTosBucketPolicyService) CreateResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{s.putBucketPolicy(data, resource, false)} +} + +func (s *VolcengineTosBucketPolicyService) ModifyResource(data *schema.ResourceData, resource *schema.Resource) []ve.Callback { + return []ve.Callback{s.putBucketPolicy(data, resource, true)} +} + +func (s *VolcengineTosBucketPolicyService) RemoveResource(data *schema.ResourceData, r *schema.Resource) []ve.Callback { + callback := ve.Callback{ + Call: ve.SdkCall{ + ServiceCategory: ve.ServiceTos, + Action: "DeleteBucketPolicy", + ConvertMode: ve.RequestConvertInConvert, + Convert: map[string]ve.RequestConvert{ + "bucket_name": { + ConvertType: ve.ConvertDefault, + TargetField: "BucketName", + ForceGet: true, + SpecialParam: &ve.SpecialParam{ + Type: ve.DomainParam, + }, + }, + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.TosClient.DoTosCall(ve.TosInfo{ + HttpMethod: ve.DELETE, + Domain: (*call.SdkParam)[ve.TosDomain].(string), + UrlParam: map[string]string{ + "policy": "", + }, + }, nil) + }, + CallError: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall, baseErr error) error { + return resource.Retry(15*time.Minute, func() *resource.RetryError { + _, callErr := s.ReadResource(d, "") + if callErr != nil { + if ve.ResourceNotFoundError(callErr) { + return nil + } else { + return resource.NonRetryableError(fmt.Errorf("error on reading tos bucket policy on delete %q, %w", s.ReadResourceId(d.Id()), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + }, + } + return []ve.Callback{callback} +} + +func (s *VolcengineTosBucketPolicyService) DatasourceResources(data *schema.ResourceData, resource *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{} +} + +func (s *VolcengineTosBucketPolicyService) ReadResourceId(id string) string { + return id +} diff --git a/website/docs/d/rds_mysql_accounts.html.markdown b/website/docs/d/rds_mysql_accounts.html.markdown new file mode 100644 index 00000000..b7bd8398 --- /dev/null +++ b/website/docs/d/rds_mysql_accounts.html.markdown @@ -0,0 +1,37 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_accounts" +sidebar_current: "docs-volcengine-datasource-rds_mysql_accounts" +description: |- + Use this data source to query detailed information of rds mysql accounts +--- +# volcengine_rds_mysql_accounts +Use this data source to query detailed information of rds mysql accounts +## Example Usage +```hcl +data "volcengine_rds_mysql_accounts" "default" { + instance_id = "mysql-47d6bc58762b" + account_name = "" +} +``` +## Argument Reference +The following arguments are supported: +* `instance_id` - (Required) The id of the RDS instance. +* `account_name` - (Optional) The name of the database account. This field supports fuzzy query. +* `name_regex` - (Optional) A Name Regex of database account. +* `output_file` - (Optional) File name where to save data source results. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `accounts` - The collection of RDS instance account query. + * `account_name` - The name of the database account. + * `account_privileges` - The privilege detail list of RDS mysql instance account. + * `account_privilege_detail` - The privilege detail of the account. + * `account_privilege` - The privilege type of the account. + * `db_name` - The name of database. + * `account_status` - The status of the database account. + * `account_type` - The type of the database account. +* `total_count` - The total count of database account query. + + diff --git a/website/docs/d/rds_mysql_allowlists.html.markdown b/website/docs/d/rds_mysql_allowlists.html.markdown new file mode 100644 index 00000000..ba300f08 --- /dev/null +++ b/website/docs/d/rds_mysql_allowlists.html.markdown @@ -0,0 +1,38 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_allowlists" +sidebar_current: "docs-volcengine-datasource-rds_mysql_allowlists" +description: |- + Use this data source to query detailed information of rds mysql allowlists +--- +# volcengine_rds_mysql_allowlists +Use this data source to query detailed information of rds mysql allowlists +## Example Usage +```hcl +data "volcengine_rds_mysql_allowlists" "default" { + region_id = "cn-guilin-boe" +} +``` +## Argument Reference +The following arguments are supported: +* `region_id` - (Required) The region of the allow lists. +* `instance_id` - (Optional) Instance ID. When an InstanceId is specified, the DescribeAllowLists interface will return the whitelist bound to the specified instance. +* `output_file` - (Optional) File name where to save data source results. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `allow_lists` - The list of allowed list. + * `allow_list_desc` - The description of the allow list. + * `allow_list_id` - The id of the allow list. + * `allow_list_ip_num` - The total number of IP addresses (or address ranges) in the whitelist. + * `allow_list_name` - The name of the allow list. + * `allow_list_type` - The type of the allow list. + * `associated_instance_num` - The total number of instances bound under the whitelist. + * `associated_instances` - The list of instances. + * `instance_id` - The id of the instance. + * `instance_name` - The name of the instance. + * `vpc` - The id of the vpc. +* `total_count` - The total count of Scaling Activity query. + + diff --git a/website/docs/d/rds_mysql_databases.html.markdown b/website/docs/d/rds_mysql_databases.html.markdown new file mode 100644 index 00000000..64b1ffa4 --- /dev/null +++ b/website/docs/d/rds_mysql_databases.html.markdown @@ -0,0 +1,36 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_databases" +sidebar_current: "docs-volcengine-datasource-rds_mysql_databases" +description: |- + Use this data source to query detailed information of rds mysql databases +--- +# volcengine_rds_mysql_databases +Use this data source to query detailed information of rds mysql databases +## Example Usage +```hcl +data "volcengine_rds_mysql_databases" "default" { + instance_id = "" + db_name = "" +} +``` +## Argument Reference +The following arguments are supported: +* `instance_id` - (Required) The id of the RDS instance. +* `db_name` - (Optional) The name of the RDS database. +* `name_regex` - (Optional) A Name Regex of RDS database. +* `output_file` - (Optional) File name where to save data source results. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `databases` - The collection of RDS instance account query. + * `character_set_name` - The character set of the RDS database. + * `database_privileges` - The privilege detail list of RDS mysql instance database. + * `account_name` - The name of account. + * `account_privilege_detail` - The privilege detail of the account. + * `account_privilege` - The privilege type of the account. + * `db_name` - The name of the RDS database. This field supports fuzzy queries. +* `total_count` - The total count of RDS database query. + + diff --git a/website/docs/d/rds_mysql_instances.html.markdown b/website/docs/d/rds_mysql_instances.html.markdown new file mode 100644 index 00000000..12b92fb8 --- /dev/null +++ b/website/docs/d/rds_mysql_instances.html.markdown @@ -0,0 +1,127 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_instances" +sidebar_current: "docs-volcengine-datasource-rds_mysql_instances" +description: |- + Use this data source to query detailed information of rds mysql instances +--- +# volcengine_rds_mysql_instances +Use this data source to query detailed information of rds mysql instances +## Example Usage +```hcl +data "volcengine_rds_mysql_instances" "default" { + instance_id = "mysql-72da4258c2c7" +} +``` +## Argument Reference +The following arguments are supported: +* `charge_type` - (Optional) The charge type of the RDS instance. +* `create_time_end` - (Optional) The end time of creating RDS instance. +* `create_time_start` - (Optional) The start time of creating RDS instance. +* `db_engine_version` - (Optional) The version of the RDS instance. +* `instance_id` - (Optional) The id of the RDS instance. +* `instance_name` - (Optional) The name of the RDS instance. +* `instance_status` - (Optional) The status of the RDS instance. +* `name_regex` - (Optional) A Name Regex of RDS instance. +* `output_file` - (Optional) File name where to save data source results. +* `zone_id` - (Optional) The available zone of the RDS instance. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `rds_mysql_instances` - The collection of RDS instance query. + * `allow_list_version` - The version of allow list. + * `backup_use` - The instance has used backup space. Unit: GB. + * `charge_detail` - Payment methods. + * `auto_renew` - Whether to automatically renew in prepaid scenarios. +Autorenew_Enable +Autorenew_Disable (default). + * `charge_end_time` - Billing expiry time (yearly and monthly only). + * `charge_start_time` - Billing start time (pay-as-you-go & monthly subscription). + * `charge_status` - Pay status. Value: +normal - normal +overdue - overdue +. + * `charge_type` - Payment type. Value: +PostPaid - Pay-As-You-Go +PrePaid - Yearly and monthly (default). + * `overdue_reclaim_time` - Estimated release time when arrears are closed (pay-as-you-go & monthly subscription). + * `overdue_time` - Shutdown time in arrears (pay-as-you-go & monthly subscription). + * `period_unit` - The purchase cycle in the prepaid scenario. +Month - monthly subscription (default) +Year - Package year. + * `period` - Purchase duration in prepaid scenarios. Default: 1. + * `create_time` - The create time of the RDS instance. + * `data_sync_mode` - Data synchronization mode. + * `db_engine_version` - The engine version of the RDS instance. + * `endpoints` - The endpoint info of the RDS instance. + * `addresses` - Address list. + * `dns_visibility` - DNS Visibility. + * `domain` - Connect domain name. + * `eip_id` - The ID of the EIP, only valid for Public addresses. + * `ip_address` - The IP Address. + * `network_type` - Network address type, temporarily Private, Public, PublicService. + * `port` - The Port. + * `subnet_id` - Subnet ID, valid only for private addresses. + * `auto_add_new_nodes` - When the terminal type is read-write terminal or read-only terminal, it supports setting whether new nodes are automatically added. + * `description` - Address description. + * `enable_read_only` - Whether global read-only is enabled, value: Enable: Enable. Disable: Disabled. + * `enable_read_write_splitting` - Whether read-write separation is enabled, value: Enable: Enable. Disable: Disabled. + * `endpoint_id` - Instance connection terminal ID. + * `endpoint_name` - The instance connection terminal name. + * `endpoint_type` - Terminal type: +Cluster: The default terminal. (created by default) +Primary: Primary node terminal. +Custom: Custom terminal. +Direct: Direct connection to the terminal. (Only the operation and maintenance side) +AllNode: All node terminals. (Only the operation and maintenance side). + * `node_weight` - The list of nodes configured by the connection terminal and the corresponding read-only weights. + * `node_id` - The ID of the node. + * `node_type` - The type of the node. + * `weight` - The weight of the node. + * `read_write_mode` - Read and write mode: +ReadWrite: read and write +ReadOnly: read only (default). + * `id` - The ID of the RDS instance. + * `instance_id` - The ID of the RDS instance. + * `instance_name` - The name of the RDS instance. + * `instance_status` - The status of the RDS instance. + * `lower_case_table_names` - Whether the table name is case sensitive, the default value is 1. +Ranges: +0: Table names are stored as fixed and table names are case-sensitive. +1: Table names will be stored in lowercase and table names are not case sensitive. + * `maintenance_window` - Maintenance Window. + * `day_kind` - DayKind of maintainable window. Value: Week. Month. + * `day_of_month` - Days of maintainable window of the month. + * `day_of_week` - Days of maintainable window of the week. + * `maintenance_time` - The maintainable time of the RDS instance. + * `memory` - Memory size. + * `node_number` - The number of nodes. + * `node_spec` - The specification of primary node. + * `nodes` - Instance node information. + * `create_time` - Node creation local time. + * `instance_id` - Instance ID. + * `memory` - Memory size in GB. + * `node_id` - Node ID. + * `node_spec` - General instance type, different from Custom instance type. + * `node_status` - Node state, value: aligned with instance state. + * `node_type` - Node type. Value: Primary: Primary node. +Secondary: Standby node. +ReadOnly: Read-only node. + * `region_id` - Region ID, you can call the DescribeRegions query and use this parameter to specify the region where the instance is to be created. + * `update_time` - Node updates local time. + * `v_cpu` - CPU size. For example: 1 means 1U. + * `zone_id` - Availability zone ID. Subsequent support for multi-availability zones can be separated and displayed by an English colon. + * `region_id` - The region of the RDS instance. + * `storage_space` - Total instance storage space. Unit: GB. + * `storage_type` - Instance storage type. + * `storage_use` - The instance has used storage space. Unit: GB. + * `subnet_id` - The subnet ID of the RDS instance. + * `time_zone` - Time zone. + * `update_time` - The update time of the RDS instance. + * `v_cpu` - CPU size. + * `vpc_id` - The vpc ID of the RDS instance. + * `zone_id` - The available zone of the RDS instance. +* `total_count` - The total count of RDS instance query. + + diff --git a/website/docs/r/rds_mysql_account.html.markdown b/website/docs/r/rds_mysql_account.html.markdown new file mode 100644 index 00000000..573ea846 --- /dev/null +++ b/website/docs/r/rds_mysql_account.html.markdown @@ -0,0 +1,67 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_account" +sidebar_current: "docs-volcengine-resource-rds_mysql_account" +description: |- + Provides a resource to manage rds mysql account +--- +# volcengine_rds_mysql_account +Provides a resource to manage rds mysql account +## Example Usage +```hcl +resource "volcengine_rds_mysql_account" "default" { + instance_id = "mysql-e9293705eed6" + account_name = "test" + account_password = "xdjsuiahHUH@" + account_type = "Normal" + # account_privileges{ + # db_name="tf-test-dbdddddd" + # account_privilege="ReadOnly" + # account_privilege_detail="SELECT,UPDATE,INSERT" + # } + # account_privileges{ + # db_name="test-xx" + # account_privilege="ReadOnly" + # account_privilege_detail="SELECT,UPDATE,INSERT" + # } +} +``` +## Argument Reference +The following arguments are supported: +* `account_name` - (Required, ForceNew) Database account name. The rules are as follows: +Unique name. +Start with a letter and end with a letter or number. +Consists of lowercase letters, numbers, or underscores (_). +The length is 2~32 characters. +The [keyword list](https://www.volcengine.com/docs/6313/66162) is disabled for database accounts, and certain reserved words, including root, admin, etc., cannot be used. +* `account_password` - (Required) The password of the database account. +Illustrate: +Cannot start with `!` or `@`. +The length is 8~32 characters. +It consists of any three of uppercase letters, lowercase letters, numbers, and special characters. +The special characters are `!@#$%^*()_+-=`. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields. +* `account_type` - (Required, ForceNew) Database account type, value: +Super: A high-privilege account. Only one database account can be created for an instance. +Normal: An account with ordinary privileges. +* `instance_id` - (Required, ForceNew) The ID of the RDS instance. +* `account_privileges` - (Optional) The privilege information of account. + +The `account_privileges` object supports the following: + +* `account_privilege` - (Required) The privilege type of the account. +* `db_name` - (Required) The name of database. +* `account_privilege_detail` - (Optional) The privilege detail of the account. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +RDS mysql account can be imported using the instance_id:account_name, e.g. +``` +$ terraform import volcengine_rds_mysql_account.default mysql-42b38c769c4b:test +``` + diff --git a/website/docs/r/rds_mysql_allowlist.html.markdown b/website/docs/r/rds_mysql_allowlist.html.markdown new file mode 100644 index 00000000..81221379 --- /dev/null +++ b/website/docs/r/rds_mysql_allowlist.html.markdown @@ -0,0 +1,39 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_allowlist" +sidebar_current: "docs-volcengine-resource-rds_mysql_allowlist" +description: |- + Provides a resource to manage rds mysql allowlist +--- +# volcengine_rds_mysql_allowlist +Provides a resource to manage rds mysql allowlist +## Example Usage +```hcl +resource "volcengine_rds_mysql_allowlist" "foo" { + allow_list_name = "tf-test-opt" + allow_list_desc = "terraform test zzm" + allow_list = [ + "127.0.0.1" + ] +} +``` +## Argument Reference +The following arguments are supported: +* `allow_list_name` - (Required) The name of the allow list. +* `allow_list` - (Required) Enter an IP address or a range of IP addresses in CIDR format. +* `allow_list_desc` - (Optional) The description of the allow list. +* `allow_list_type` - (Optional) The type of IP address in the whitelist. Currently only IPv4 addresses are supported. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `allow_list_id` - The id of the allow list. + + +## Import +RDS AllowList can be imported using the id, e.g. +``` +$ terraform import volcengine_rds_mysql_allowlist.default acl-d1fd76693bd54e658912e7337d5b**** +``` + diff --git a/website/docs/r/rds_mysql_allowlist_associate.html.markdown b/website/docs/r/rds_mysql_allowlist_associate.html.markdown new file mode 100644 index 00000000..7a3b848e --- /dev/null +++ b/website/docs/r/rds_mysql_allowlist_associate.html.markdown @@ -0,0 +1,34 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_allowlist_associate" +sidebar_current: "docs-volcengine-resource-rds_mysql_allowlist_associate" +description: |- + Provides a resource to manage rds mysql allowlist associate +--- +# volcengine_rds_mysql_allowlist_associate +Provides a resource to manage rds mysql allowlist associate +## Example Usage +```hcl +resource "volcengine_rds_mysql_allowlist_associate" "foo" { + instance_id = "mysql-1b2c7b2d7583" + allow_list_id = "acl-15451212dcfa473baeda24be4baa02fe" +} +``` +## Argument Reference +The following arguments are supported: +* `allow_list_id` - (Required, ForceNew) The id of the allow list. +* `instance_id` - (Required, ForceNew) The id of the mysql instance. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +RDS AllowList Associate can be imported using the instance id and allow list id, e.g. +``` +$ terraform import volcengine_rds_mysql_allowlist_associate.default rds-mysql-h441603c68aaa:acl-d1fd76693bd54e658912e7337d5b**** +``` + diff --git a/website/docs/r/rds_mysql_database.html.markdown b/website/docs/r/rds_mysql_database.html.markdown new file mode 100644 index 00000000..b84dbd72 --- /dev/null +++ b/website/docs/r/rds_mysql_database.html.markdown @@ -0,0 +1,42 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_database" +sidebar_current: "docs-volcengine-resource-rds_mysql_database" +description: |- + Provides a resource to manage rds mysql database +--- +# volcengine_rds_mysql_database +Provides a resource to manage rds mysql database +## Example Usage +```hcl +resource "volcengine_rds_mysql_database" "default" { + instance_id = "mysql-xxx" + db_name = "xxx" + character_set_name = "utf8" +} +``` +## Argument Reference +The following arguments are supported: +* `db_name` - (Required, ForceNew) Name database. +illustrate: +Unique name. +The length is 2~64 characters. +Start with a letter and end with a letter or number. +Consists of lowercase letters, numbers, and underscores (_) or dashes (-). +Database names are disabled [keywords](https://www.volcengine.com/docs/6313/66162). +* `instance_id` - (Required, ForceNew) The ID of the RDS instance. +* `character_set_name` - (Optional, ForceNew) Database character set. Currently supported character sets include: utf8, utf8mb4, latin1, ascii. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +Database can be imported using the instanceId:dbName, e.g. +``` +$ terraform import volcengine_rds_mysql_database.default mysql-42b38c769c4b:dbname +``` + diff --git a/website/docs/r/rds_mysql_instance.html.markdown b/website/docs/r/rds_mysql_instance.html.markdown new file mode 100644 index 00000000..5c82f0ec --- /dev/null +++ b/website/docs/r/rds_mysql_instance.html.markdown @@ -0,0 +1,175 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_instance" +sidebar_current: "docs-volcengine-resource-rds_mysql_instance" +description: |- + Provides a resource to manage rds mysql instance +--- +# volcengine_rds_mysql_instance +Provides a resource to manage rds mysql instance +## Example Usage +```hcl +resource "volcengine_rds_mysql_instance" "foo" { + db_engine_version = "MySQL_5_7" + node_spec = "rds.mysql.1c2g" + primary_zone_id = "cn-guilin-a" + secondary_zone_id = "cn-guilin-b" + storage_space = 80 + subnet_id = "subnet-2d72yi377stts58ozfdrlk9f6" + instance_name = "tf-test" + lower_case_table_names = "1" + + charge_info { + charge_type = "PostPaid" + } + + allow_list_ids = ["acl-2dd8f8317e4d4159b21630d13ae2e6ec", "acl-2eaa2a053b2a4a58b988e38ae975e81c"] + + parameters { + parameter_name = "auto_increment_increment" + parameter_value = "2" + } + parameters { + parameter_name = "auto_increment_offset" + parameter_value = "4" + } +} + +resource "volcengine_rds_mysql_instance_readonly_node" "readonly" { + instance_id = volcengine_rds_mysql_instance.foo.id + node_spec = "rds.mysql.2c4g" + zone_id = "cn-guilin-a" +} +``` +## Argument Reference +The following arguments are supported: +* `charge_info` - (Required, ForceNew) Payment methods. +* `db_engine_version` - (Required, ForceNew) Instance type. Value: +MySQL_5_7 +MySQL_8_0. +* `node_spec` - (Required) The specification of primary node and secondary node. +* `primary_zone_id` - (Required, ForceNew) The available zone of primary node. +* `secondary_zone_id` - (Required, ForceNew) The available zone of secondary node. +* `subnet_id` - (Required, ForceNew) Subnet ID of the RDS instance. +* `allow_list_ids` - (Optional) Allow list Ids of the RDS instance. +* `db_time_zone` - (Optional, ForceNew) Time zone. Support UTC -12:00 ~ +13:00. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields. +* `instance_name` - (Optional) Instance name. Cannot start with a number or a dash +Can only contain Chinese characters, letters, numbers, underscores and dashes +The length is limited between 1 ~ 128. +* `lower_case_table_names` - (Optional, ForceNew) Whether the table name is case sensitive, the default value is 1. +Ranges: +0: Table names are stored as fixed and table names are case-sensitive. +1: Table names will be stored in lowercase and table names are not case sensitive. +* `parameters` - (Optional) Parameter of the RDS instance. This field can only be added or modified. Deleting this field is invalid. +* `storage_space` - (Optional) Instance storage space. Value range: [20, 3000], unit: GB, increments every 100GB. Default value: 100. + +The `charge_info` object supports the following: + +* `charge_type` - (Required, ForceNew) Payment type. Value: +PostPaid - Pay-As-You-Go +PrePaid - Yearly and monthly (default). +* `auto_renew` - (Optional, ForceNew) Whether to automatically renew in prepaid scenarios. +* `period_unit` - (Optional, ForceNew) The purchase cycle in the prepaid scenario. +Month - monthly subscription (default) +Year - Package year. +* `period` - (Optional, ForceNew) Purchase duration in prepaid scenarios. Default: 1. + +The `parameters` object supports the following: + +* `parameter_name` - (Required) Parameter name. +* `parameter_value` - (Required) Parameter value. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `allow_list_version` - The version of allow list. +* `backup_use` - The instance has used backup space. Unit: GB. +* `charge_detail` - Payment methods. + * `auto_renew` - Whether to automatically renew in prepaid scenarios. +Autorenew_Enable +Autorenew_Disable (default). + * `charge_end_time` - Billing expiry time (yearly and monthly only). + * `charge_start_time` - Billing start time (pay-as-you-go & monthly subscription). + * `charge_status` - Pay status. Value: +normal - normal +overdue - overdue +. + * `charge_type` - Payment type. Value: +PostPaid - Pay-As-You-Go +PrePaid - Yearly and monthly (default). + * `overdue_reclaim_time` - Estimated release time when arrears are closed (pay-as-you-go & monthly subscription). + * `overdue_time` - Shutdown time in arrears (pay-as-you-go & monthly subscription). + * `period_unit` - The purchase cycle in the prepaid scenario. +Month - monthly subscription (default) +Year - Package year. + * `period` - Purchase duration in prepaid scenarios. Default: 1. +* `create_time` - The create time of the RDS instance. +* `data_sync_mode` - Data synchronization mode. +* `endpoints` - The endpoint info of the RDS instance. + * `addresses` - Address list. + * `dns_visibility` - DNS Visibility. + * `domain` - Connect domain name. + * `eip_id` - The ID of the EIP, only valid for Public addresses. + * `ip_address` - The IP Address. + * `network_type` - Network address type, temporarily Private, Public, PublicService. + * `port` - The Port. + * `subnet_id` - Subnet ID, valid only for private addresses. + * `auto_add_new_nodes` - When the terminal type is read-write terminal or read-only terminal, it supports setting whether new nodes are automatically added. + * `description` - Address description. + * `enable_read_only` - Whether global read-only is enabled, value: Enable: Enable. Disable: Disabled. + * `enable_read_write_splitting` - Whether read-write separation is enabled, value: Enable: Enable. Disable: Disabled. + * `endpoint_id` - Instance connection terminal ID. + * `endpoint_name` - The instance connection terminal name. + * `endpoint_type` - Terminal type: +Cluster: The default terminal. (created by default) +Primary: Primary node terminal. +Custom: Custom terminal. +Direct: Direct connection to the terminal. (Only the operation and maintenance side) +AllNode: All node terminals. (Only the operation and maintenance side). + * `node_weight` - The list of nodes configured by the connection terminal and the corresponding read-only weights. + * `node_id` - The ID of the node. + * `node_type` - The type of the node. + * `weight` - The weight of the node. + * `read_write_mode` - Read and write mode: +ReadWrite: read and write +ReadOnly: read only (default). +* `instance_id` - The ID of the RDS instance. +* `instance_status` - The status of the RDS instance. +* `maintenance_window` - Maintenance Window. + * `day_kind` - DayKind of maintainable window. Value: Week. Month. + * `day_of_month` - Days of maintainable window of the month. + * `day_of_week` - Days of maintainable window of the week. + * `maintenance_time` - The maintainable time of the RDS instance. +* `memory` - Memory size. +* `node_number` - The number of nodes. +* `nodes` - Instance node information. + * `create_time` - Node creation local time. + * `instance_id` - Instance ID. + * `memory` - Memory size in GB. + * `node_id` - Node ID. + * `node_spec` - General instance type, different from Custom instance type. + * `node_status` - Node state, value: aligned with instance state. + * `node_type` - Node type. Value: Primary: Primary node. +Secondary: Standby node. +ReadOnly: Read-only node. + * `region_id` - Region ID, you can call the DescribeRegions query and use this parameter to specify the region where the instance is to be created. + * `update_time` - Node updates local time. + * `v_cpu` - CPU size. For example: 1 means 1U. + * `zone_id` - Availability zone ID. Subsequent support for multi-availability zones can be separated and displayed by an English colon. +* `region_id` - The region of the RDS instance. +* `storage_type` - Instance storage type. +* `storage_use` - The instance has used storage space. Unit: GB. +* `time_zone` - Time zone. +* `update_time` - The update time of the RDS instance. +* `v_cpu` - CPU size. +* `vpc_id` - The vpc ID of the RDS instance. +* `zone_id` - The available zone of the RDS instance. + + +## Import +Rds Mysql Instance can be imported using the id, e.g. +``` +$ terraform import volcengine_rds_mysql_instance.default mysql-72da4258c2c7 +``` + diff --git a/website/docs/r/rds_mysql_instance_readonly_node.html.markdown b/website/docs/r/rds_mysql_instance_readonly_node.html.markdown new file mode 100644 index 00000000..844e95be --- /dev/null +++ b/website/docs/r/rds_mysql_instance_readonly_node.html.markdown @@ -0,0 +1,36 @@ +--- +subcategory: "RDS_MYSQL" +layout: "volcengine" +page_title: "Volcengine: volcengine_rds_mysql_instance_readonly_node" +sidebar_current: "docs-volcengine-resource-rds_mysql_instance_readonly_node" +description: |- + Provides a resource to manage rds mysql instance readonly node +--- +# volcengine_rds_mysql_instance_readonly_node +Provides a resource to manage rds mysql instance readonly node +## Example Usage +```hcl +resource "volcengine_rds_mysql_instance_readonly_node" "foo" { + instance_id = "mysql-b3fca7f571d6" + node_spec = "rds.mysql.1c2g" + zone_id = "cn-guilin-b" +} +``` +## Argument Reference +The following arguments are supported: +* `instance_id` - (Required, ForceNew) The RDS mysql instance id of the readonly node. +* `node_spec` - (Required) The specification of readonly node. +* `zone_id` - (Required, ForceNew) The available zone of readonly node. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `node_id` - The id of the readonly node. + + +## Import +Rds Mysql Instance Readonly Node can be imported using the instance_id:node_id, e.g. +``` +$ terraform import volcengine_rds_mysql_instance_readonly_node.default mysql-72da4258c2c7:mysql-72da4258c2c7-r7f93 +``` + diff --git a/website/docs/r/tos_bucket.html.markdown b/website/docs/r/tos_bucket.html.markdown index 5502dde9..66e9bee6 100644 --- a/website/docs/r/tos_bucket.html.markdown +++ b/website/docs/r/tos_bucket.html.markdown @@ -48,6 +48,6 @@ In addition to all arguments above, the following attributes are exported: ## Import Tos Bucket can be imported using the id, e.g. ``` -$ terraform import volcengine_tos_bucket.default region:bucketName +$ terraform import volcengine_tos_bucket.default bucketName ``` diff --git a/website/docs/r/tos_bucket_policy.html.markdown b/website/docs/r/tos_bucket_policy.html.markdown new file mode 100644 index 00000000..26b0c40e --- /dev/null +++ b/website/docs/r/tos_bucket_policy.html.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "TOS(BETA)" +layout: "volcengine" +page_title: "Volcengine: volcengine_tos_bucket_policy" +sidebar_current: "docs-volcengine-resource-tos_bucket_policy" +description: |- + Provides a resource to manage tos bucket policy +--- +# volcengine_tos_bucket_policy +Provides a resource to manage tos bucket policy +## Example Usage +```hcl +resource "volcengine_tos_bucket_policy" "default" { + bucket_name = "bucket-20230418" + policy = jsonencode({ + Statement = [ + { + Sid = "test" + Effect = "Allow" + Principal = [ + "AccountId/subUserName" + ] + Action = [ + "tos:List*" + ] + Resource = [ + "trn:tos:::bucket-20230418" + ] + } + ] + }) +} +``` +## Argument Reference +The following arguments are supported: +* `bucket_name` - (Required, ForceNew) The name of the bucket. +* `policy` - (Required) The policy document. This is a JSON formatted string. For more information about building Volcengine IAM policy documents with Terraform, see the [Volcengine IAM Policy Document Guide](https://www.volcengine.com/docs/6349/102127). + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +Tos Bucket can be imported using the id, e.g. +``` +$ terraform import volcengine_tos_bucket_policy.default bucketName:policy +``` + diff --git a/website/volcengine.erb b/website/volcengine.erb index 80fc227f..faa6e3a8 100644 --- a/website/volcengine.erb +++ b/website/volcengine.erb @@ -544,6 +544,18 @@
  • rds_parameter_templates
  • +
  • + rds_mysql_allowlists +
  • +
  • + rds_mysql_accounts +
  • +
  • + rds_mysql_databases +
  • +
  • + rds_mysql_instances +
  • rds_instances_v2
  • @@ -570,6 +582,24 @@
  • rds_parameter_template
  • +
  • + rds_mysql_allowlist +
  • +
  • + rds_mysql_allowlist_associate +
  • +
  • + rds_mysql_account +
  • +
  • + rds_mysql_database +
  • +
  • + rds_mysql_instance +
  • +
  • + rds_mysql_instance_readonly_node +
  • rds_instance_v2
  • @@ -597,6 +627,9 @@
  • tos_bucket
  • +
  • + tos_bucket_policy +
  • tos_object
  • From 53d50bacbcc5c7524869722b5d6bd389a37b9c16 Mon Sep 17 00:00:00 2001 From: "maoshuai.17" Date: Fri, 3 Mar 2023 11:45:26 +0800 Subject: [PATCH 2/9] feat: support ipv6 --- example/dataVpcIpv6AddressBandwidths/main.tf | 3 + example/dataVpcIpv6Gateways/main.tf | 3 + example/vpcIpv6AddressBandwidth/main.tf | 5 + example/vpcIpv6Gateway/main.tf | 5 + .../resource_volcengine_ecs_instance.go | 7 + volcengine/provider.go | 44 +-- ..._volcengine_vpc_ipv6_address_bandwidths.go | 161 +++++++++++ ...e_volcengine_vpc_ipv6_address_bandwidth.go | 96 +++++++ ...e_volcengine_vpc_ipv6_address_bandwidth.go | 267 ++++++++++++++++++ ...ata_source_volcengine_vpc_ipv6_gateways.go | 108 +++++++ .../resource_volcengine_vpc_ipv6_gateway.go | 91 ++++++ .../service_volcengine_vpc_ipv6_gateway.go | 258 +++++++++++++++++ .../subnet/data_source_volcengine_subnets.go | 5 + .../vpc/subnet/resource_volcengine_subnet.go | 25 ++ .../vpc/subnet/service_volcengine_subnet.go | 28 ++ .../vpc/vpc/data_source_volcengine_vpcs.go | 5 + volcengine/vpc/vpc/resource_volcengine_vpc.go | 18 ++ volcengine/vpc/vpc/service_volcengine_vpc.go | 7 + website/docs/d/subnets.html.markdown | 1 + .../vpc_ipv6_address_bandwidths.html.markdown | 49 ++++ .../docs/d/vpc_ipv6_gateways.html.markdown | 38 +++ website/docs/d/vpcs.html.markdown | 1 + website/docs/r/ecs_instance.html.markdown | 1 + website/docs/r/subnet.html.markdown | 2 + website/docs/r/vpc.html.markdown | 3 + .../vpc_ipv6_address_bandwidth.html.markdown | 47 +++ website/docs/r/vpc_ipv6_gateway.html.markdown | 36 +++ website/volcengine.erb | 12 + 28 files changed, 1307 insertions(+), 19 deletions(-) create mode 100644 example/dataVpcIpv6AddressBandwidths/main.tf create mode 100644 example/dataVpcIpv6Gateways/main.tf create mode 100644 example/vpcIpv6AddressBandwidth/main.tf create mode 100644 example/vpcIpv6Gateway/main.tf create mode 100644 volcengine/vpc/ipv6_address_bandwidth/data_source_volcengine_vpc_ipv6_address_bandwidths.go create mode 100644 volcengine/vpc/ipv6_address_bandwidth/resource_volcengine_vpc_ipv6_address_bandwidth.go create mode 100644 volcengine/vpc/ipv6_address_bandwidth/service_volcengine_vpc_ipv6_address_bandwidth.go create mode 100644 volcengine/vpc/ipv6_gateway/data_source_volcengine_vpc_ipv6_gateways.go create mode 100644 volcengine/vpc/ipv6_gateway/resource_volcengine_vpc_ipv6_gateway.go create mode 100644 volcengine/vpc/ipv6_gateway/service_volcengine_vpc_ipv6_gateway.go create mode 100644 website/docs/d/vpc_ipv6_address_bandwidths.html.markdown create mode 100644 website/docs/d/vpc_ipv6_gateways.html.markdown create mode 100644 website/docs/r/vpc_ipv6_address_bandwidth.html.markdown create mode 100644 website/docs/r/vpc_ipv6_gateway.html.markdown diff --git a/example/dataVpcIpv6AddressBandwidths/main.tf b/example/dataVpcIpv6AddressBandwidths/main.tf new file mode 100644 index 00000000..fd989e83 --- /dev/null +++ b/example/dataVpcIpv6AddressBandwidths/main.tf @@ -0,0 +1,3 @@ +data "volcengine_vpc_ipv6_address_bandwidths" "default" { + ids = ["eip-in2y2duvtlhc8gbssyfnhfre"] +} \ No newline at end of file diff --git a/example/dataVpcIpv6Gateways/main.tf b/example/dataVpcIpv6Gateways/main.tf new file mode 100644 index 00000000..bbaf74af --- /dev/null +++ b/example/dataVpcIpv6Gateways/main.tf @@ -0,0 +1,3 @@ +data "volcengine_vpc_ipv6_gateways" "default" { + ids = ["ipv6gw-12bcapllb5ukg17q7y2sd3thx"] +} \ No newline at end of file diff --git a/example/vpcIpv6AddressBandwidth/main.tf b/example/vpcIpv6AddressBandwidth/main.tf new file mode 100644 index 00000000..912b3d17 --- /dev/null +++ b/example/vpcIpv6AddressBandwidth/main.tf @@ -0,0 +1,5 @@ +resource "volcengine_vpc_ipv6_address_bandwidth" "foo" { + ipv6_address = "2000:1000:89ff:ff02:ea70:18ce:dda2:a02e" + billing_type = 3 + bandwidth = 5 +} \ No newline at end of file diff --git a/example/vpcIpv6Gateway/main.tf b/example/vpcIpv6Gateway/main.tf new file mode 100644 index 00000000..e5253fc6 --- /dev/null +++ b/example/vpcIpv6Gateway/main.tf @@ -0,0 +1,5 @@ +resource "volcengine_vpc_ipv6_gateway" "foo" { + vpc_id = "vpc-12afxho4sxyio17q7y2kkp8ej" + name = "tf-test-1" + description = "test" +} \ No newline at end of file diff --git a/volcengine/ecs/ecs_instance/resource_volcengine_ecs_instance.go b/volcengine/ecs/ecs_instance/resource_volcengine_ecs_instance.go index 3d42d422..2cab5227 100644 --- a/volcengine/ecs/ecs_instance/resource_volcengine_ecs_instance.go +++ b/volcengine/ecs/ecs_instance/resource_volcengine_ecs_instance.go @@ -239,6 +239,13 @@ func ResourceVolcengineEcsInstance() *schema.Resource { Description: "The ID of Ecs Deployment Set.", }, + "ipv6_address_count": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Description: "The ipv6 address count of ECS instance. Valid values: 0, 1.", + }, + "data_volumes": { Type: schema.TypeList, Optional: true, diff --git a/volcengine/provider.go b/volcengine/provider.go index 1f3dce70..f0a024aa 100644 --- a/volcengine/provider.go +++ b/volcengine/provider.go @@ -110,6 +110,8 @@ import ( "github.com/volcengine/terraform-provider-volcengine/volcengine/vke/node" "github.com/volcengine/terraform-provider-volcengine/volcengine/vke/node_pool" "github.com/volcengine/terraform-provider-volcengine/volcengine/vke/support_addon" + "github.com/volcengine/terraform-provider-volcengine/volcengine/vpc/ipv6_address_bandwidth" + "github.com/volcengine/terraform-provider-volcengine/volcengine/vpc/ipv6_gateway" "github.com/volcengine/terraform-provider-volcengine/volcengine/vpc/network_acl" "github.com/volcengine/terraform-provider-volcengine/volcengine/vpc/network_acl_associate" "github.com/volcengine/terraform-provider-volcengine/volcengine/vpc/network_interface" @@ -186,14 +188,16 @@ func Provider() terraform.ResourceProvider { }, }, DataSourcesMap: map[string]*schema.Resource{ - "volcengine_vpcs": vpc.DataSourceVolcengineVpcs(), - "volcengine_subnets": subnet.DataSourceVolcengineSubnets(), - "volcengine_route_tables": route_table.DataSourceVolcengineRouteTables(), - "volcengine_route_entries": route_entry.DataSourceVolcengineRouteEntries(), - "volcengine_security_groups": security_group.DataSourceVolcengineSecurityGroups(), - "volcengine_security_group_rules": security_group_rule.DataSourceVolcengineSecurityGroupRules(), - "volcengine_network_interfaces": network_interface.DataSourceVolcengineNetworkInterfaces(), - "volcengine_network_acls": network_acl.DataSourceVolcengineNetworkAcls(), + "volcengine_vpcs": vpc.DataSourceVolcengineVpcs(), + "volcengine_subnets": subnet.DataSourceVolcengineSubnets(), + "volcengine_route_tables": route_table.DataSourceVolcengineRouteTables(), + "volcengine_route_entries": route_entry.DataSourceVolcengineRouteEntries(), + "volcengine_security_groups": security_group.DataSourceVolcengineSecurityGroups(), + "volcengine_security_group_rules": security_group_rule.DataSourceVolcengineSecurityGroupRules(), + "volcengine_network_interfaces": network_interface.DataSourceVolcengineNetworkInterfaces(), + "volcengine_network_acls": network_acl.DataSourceVolcengineNetworkAcls(), + "volcengine_vpc_ipv6_gateways": ipv6_gateway.DataSourceVolcengineIpv6Gateways(), + "volcengine_vpc_ipv6_address_bandwidths": ipv6_address_bandwidth.DataSourceVolcengineIpv6AddressBandwidths(), // ================ EIP ================ "volcengine_eip_addresses": eip_address.DataSourceVolcengineEipAddresses(), @@ -316,17 +320,19 @@ func Provider() terraform.ResourceProvider { "volcengine_rds_mysql_allowlists": allowlist.DataSourceVolcengineRdsMysqlAllowLists(), }, ResourcesMap: map[string]*schema.Resource{ - "volcengine_vpc": vpc.ResourceVolcengineVpc(), - "volcengine_subnet": subnet.ResourceVolcengineSubnet(), - "volcengine_route_table": route_table.ResourceVolcengineRouteTable(), - "volcengine_route_entry": route_entry.ResourceVolcengineRouteEntry(), - "volcengine_route_table_associate": route_table_associate.ResourceVolcengineRouteTableAssociate(), - "volcengine_security_group": security_group.ResourceVolcengineSecurityGroup(), - "volcengine_network_interface": network_interface.ResourceVolcengineNetworkInterface(), - "volcengine_network_interface_attach": network_interface_attach.ResourceVolcengineNetworkInterfaceAttach(), - "volcengine_security_group_rule": security_group_rule.ResourceVolcengineSecurityGroupRule(), - "volcengine_network_acl": network_acl.ResourceVolcengineNetworkAcl(), - "volcengine_network_acl_associate": network_acl_associate.ResourceVolcengineNetworkAclAssociate(), + "volcengine_vpc": vpc.ResourceVolcengineVpc(), + "volcengine_subnet": subnet.ResourceVolcengineSubnet(), + "volcengine_route_table": route_table.ResourceVolcengineRouteTable(), + "volcengine_route_entry": route_entry.ResourceVolcengineRouteEntry(), + "volcengine_route_table_associate": route_table_associate.ResourceVolcengineRouteTableAssociate(), + "volcengine_security_group": security_group.ResourceVolcengineSecurityGroup(), + "volcengine_network_interface": network_interface.ResourceVolcengineNetworkInterface(), + "volcengine_network_interface_attach": network_interface_attach.ResourceVolcengineNetworkInterfaceAttach(), + "volcengine_security_group_rule": security_group_rule.ResourceVolcengineSecurityGroupRule(), + "volcengine_network_acl": network_acl.ResourceVolcengineNetworkAcl(), + "volcengine_network_acl_associate": network_acl_associate.ResourceVolcengineNetworkAclAssociate(), + "volcengine_vpc_ipv6_gateway": ipv6_gateway.ResourceVolcengineIpv6Gateway(), + "volcengine_vpc_ipv6_address_bandwidth": ipv6_address_bandwidth.ResourceVolcengineIpv6AddressBandwidth(), // ================ EIP ================ "volcengine_eip_address": eip_address.ResourceVolcengineEipAddress(), diff --git a/volcengine/vpc/ipv6_address_bandwidth/data_source_volcengine_vpc_ipv6_address_bandwidths.go b/volcengine/vpc/ipv6_address_bandwidth/data_source_volcengine_vpc_ipv6_address_bandwidths.go new file mode 100644 index 00000000..8e94215f --- /dev/null +++ b/volcengine/vpc/ipv6_address_bandwidth/data_source_volcengine_vpc_ipv6_address_bandwidths.go @@ -0,0 +1,161 @@ +package ipv6_address_bandwidth + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineIpv6AddressBandwidths() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineIpv6AddressBandwidthsRead, + Schema: map[string]*schema.Schema{ + "ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + Description: "Allocation IDs of the Ipv6 address width.", + }, + "associated_instance_id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the associated instance.", + }, + "associated_instance_type": { + Type: schema.TypeString, + Optional: true, + Description: "The type of the associated instance.", + }, + "isp": { + Type: schema.TypeString, + Optional: true, + Description: "ISP of the ipv6 address.", + }, + "ipv6_addresses": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + Description: "The ipv6 addresses.", + }, + "network_type": { + Type: schema.TypeString, + Optional: true, + Description: "The network type of the ipv6 address.", + }, + "vpc_id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of Vpc the ipv6 address in.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of Ipv6AddressBandwidth query.", + }, + "ipv6_address_bandwidths": { + Description: "The collection of Ipv6AddressBandwidth query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Ipv6AddressBandwidth.", + }, + "allocation_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Ipv6AddressBandwidth.", + }, + "bandwidth": { + Type: schema.TypeInt, + Computed: true, + Description: "Peek bandwidth of the Ipv6 address.", + }, + "billing_type": { + Type: schema.TypeInt, + Computed: true, + Description: "BillingType of the Ipv6 bandwidth.", + }, + "business_status": { + Type: schema.TypeString, + Computed: true, + Description: "The BusinessStatus of the Ipv6AddressBandwidth.", + }, + "isp": { + Type: schema.TypeString, + Computed: true, + Description: "The ISP of the Ipv6AddressBandwidth.", + }, + "instance_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the associated instance.", + }, + "instance_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the associated instance.", + }, + "ipv6_address": { + Type: schema.TypeString, + Computed: true, + Description: "The IPv6 address.", + }, + "lock_reason": { + Type: schema.TypeString, + Computed: true, + Description: "The BusinessStatus of the Ipv6AddressBandwidth.", + }, + "network_type": { + Type: schema.TypeString, + Computed: true, + Description: "The network type of the Ipv6AddressBandwidth.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The status of the Ipv6AddressBandwidth.", + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the Ipv6AddressBandwidth.", + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "Update time of the Ipv6AddressBandwidth.", + }, + "overdue_time": { + Type: schema.TypeString, + Computed: true, + Description: "Overdue time of the Ipv6AddressBandwidth.", + }, + "delete_time": { + Type: schema.TypeString, + Computed: true, + Description: "Delete time of the Ipv6AddressBandwidth.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineIpv6AddressBandwidthsRead(d *schema.ResourceData, meta interface{}) error { + ipv6AddressBandwidthService := NewIpv6AddressBandwidthService(meta.(*ve.SdkClient)) + return ipv6AddressBandwidthService.Dispatcher.Data(ipv6AddressBandwidthService, d, DataSourceVolcengineIpv6AddressBandwidths()) +} diff --git a/volcengine/vpc/ipv6_address_bandwidth/resource_volcengine_vpc_ipv6_address_bandwidth.go b/volcengine/vpc/ipv6_address_bandwidth/resource_volcengine_vpc_ipv6_address_bandwidth.go new file mode 100644 index 00000000..bd57b6ca --- /dev/null +++ b/volcengine/vpc/ipv6_address_bandwidth/resource_volcengine_vpc_ipv6_address_bandwidth.go @@ -0,0 +1,96 @@ +package ipv6_address_bandwidth + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +Ipv6AddressBandwidth can be imported using the id, e.g. +``` +$ terraform import volcengine_vpc_ipv6_address_bandwidth.default eip-2fede9fsgnr4059gp674m6ney +``` + +*/ + +func ResourceVolcengineIpv6AddressBandwidth() *schema.Resource { + resource := &schema.Resource{ + Create: resourceVolcengineIpv6AddressBandwidthCreate, + Read: resourceVolcengineIpv6AddressBandwidthRead, + Update: resourceVolcengineIpv6AddressBandwidthUpdate, + Delete: resourceVolcengineIpv6AddressBandwidthDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "ipv6_address": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Ipv6 address.", + }, + "billing_type": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + Description: "BillingType of the Ipv6 bandwidth. Valid values: 3(Pay by Traffic).", + }, + "bandwidth": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Peek bandwidth of the Ipv6 address. Valid values: 1 to 200. Unit: Mbit/s.", + }, + }, + } + dataSource := DataSourceVolcengineIpv6AddressBandwidths().Schema["ipv6_address_bandwidths"].Elem.(*schema.Resource).Schema + delete(dataSource, "id") + ve.MergeDateSourceToResource(dataSource, &resource.Schema) + return resource +} + +func resourceVolcengineIpv6AddressBandwidthCreate(d *schema.ResourceData, meta interface{}) (err error) { + ipv6AddressBandwidthService := NewIpv6AddressBandwidthService(meta.(*ve.SdkClient)) + err = ipv6AddressBandwidthService.Dispatcher.Create(ipv6AddressBandwidthService, d, ResourceVolcengineIpv6AddressBandwidth()) + if err != nil { + return fmt.Errorf("error on creating Ipv6AddressBandwidth %q, %w", d.Id(), err) + } + return resourceVolcengineIpv6AddressBandwidthRead(d, meta) +} + +func resourceVolcengineIpv6AddressBandwidthRead(d *schema.ResourceData, meta interface{}) (err error) { + ipv6AddressBandwidthService := NewIpv6AddressBandwidthService(meta.(*ve.SdkClient)) + err = ipv6AddressBandwidthService.Dispatcher.Read(ipv6AddressBandwidthService, d, ResourceVolcengineIpv6AddressBandwidth()) + if err != nil { + return fmt.Errorf("error on reading Ipv6AddressBandwidth %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcengineIpv6AddressBandwidthUpdate(d *schema.ResourceData, meta interface{}) (err error) { + ipv6AddressBandwidthService := NewIpv6AddressBandwidthService(meta.(*ve.SdkClient)) + err = ipv6AddressBandwidthService.Dispatcher.Update(ipv6AddressBandwidthService, d, ResourceVolcengineIpv6AddressBandwidth()) + if err != nil { + return fmt.Errorf("error on updating Ipv6AddressBandwidth %q, %w", d.Id(), err) + } + return resourceVolcengineIpv6AddressBandwidthRead(d, meta) +} + +func resourceVolcengineIpv6AddressBandwidthDelete(d *schema.ResourceData, meta interface{}) (err error) { + ipv6AddressBandwidthService := NewIpv6AddressBandwidthService(meta.(*ve.SdkClient)) + err = ipv6AddressBandwidthService.Dispatcher.Delete(ipv6AddressBandwidthService, d, ResourceVolcengineIpv6AddressBandwidth()) + if err != nil { + return fmt.Errorf("error on deleting Ipv6AddressBandwidth %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/vpc/ipv6_address_bandwidth/service_volcengine_vpc_ipv6_address_bandwidth.go b/volcengine/vpc/ipv6_address_bandwidth/service_volcengine_vpc_ipv6_address_bandwidth.go new file mode 100644 index 00000000..b2bed3c1 --- /dev/null +++ b/volcengine/vpc/ipv6_address_bandwidth/service_volcengine_vpc_ipv6_address_bandwidth.go @@ -0,0 +1,267 @@ +package ipv6_address_bandwidth + +import ( + "errors" + "fmt" + "time" + + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineIpv6AddressBandwidthService struct { + Client *ve.SdkClient + Dispatcher *ve.Dispatcher +} + +func NewIpv6AddressBandwidthService(c *ve.SdkClient) *VolcengineIpv6AddressBandwidthService { + return &VolcengineIpv6AddressBandwidthService{ + Client: c, + Dispatcher: &ve.Dispatcher{}, + } +} + +func (s *VolcengineIpv6AddressBandwidthService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineIpv6AddressBandwidthService) ReadResources(condition map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(condition, "PageSize", "PageNumber", 20, 1, func(m map[string]interface{}) ([]interface{}, error) { + action := "DescribeIpv6AddressBandwidths" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, condition, *resp) + + results, err = ve.ObtainSdkValue("Result.Ipv6AddressBandwidths", *resp) + if err != nil { + return data, err + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Ipv6AddressBandwidths is not Slice") + } + + return data, err + }) +} + +func (s *VolcengineIpv6AddressBandwidthService) ReadResource(resourceData *schema.ResourceData, allocationId string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if allocationId == "" { + allocationId = s.ReadResourceId(resourceData.Id()) + } + req := map[string]interface{}{ + "AllocationIds.1": allocationId, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + if data, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + } + if len(data) == 0 { + return data, fmt.Errorf("Ipv6AddressBandwidth %s is not exist ", allocationId) + } + + return data, err +} + +func (s *VolcengineIpv6AddressBandwidthService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{}, + Delay: 1 * time.Second, + MinTimeout: 1 * time.Second, + Target: target, + Timeout: timeout, + Refresh: func() (result interface{}, state string, err error) { + var ( + demo map[string]interface{} + status interface{} + ) + //no failed status. + demo, err = s.ReadResource(resourceData, id) + if err != nil { + return nil, "", err + } + status, err = ve.ObtainSdkValue("Status", demo) + if err != nil { + return nil, "", err + } + return demo, status.(string), err + }, + } +} + +func (VolcengineIpv6AddressBandwidthService) WithResourceResponseHandlers(ipv6AddressBandwidth map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return ipv6AddressBandwidth, map[string]ve.ResponseConvert{ + "ISP": { + TargetField: "isp", + }, + }, nil + } + return []ve.ResourceResponseHandler{handler} + +} + +func (s *VolcengineIpv6AddressBandwidthService) CreateResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "AllocateIpv6AddressBandwidth", + ConvertMode: ve.RequestConvertAll, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["ClientToken"] = uuid.New().String() + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + id, _ := ve.ObtainSdkValue("Result.AllocationId", *resp) + d.SetId(id.(string)) + return nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + }, + } + callbacks = append(callbacks, callback) + + return callbacks +} + +func (s *VolcengineIpv6AddressBandwidthService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyIpv6AddressBandwidth", + ConvertMode: ve.RequestConvertAll, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["AllocationId"] = d.Id() + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + }, + } + callbacks = append(callbacks, callback) + + return callbacks +} + +func (s *VolcengineIpv6AddressBandwidthService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + removeCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ReleaseIpv6AddressBandwidth", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "AllocationId": resourceData.Id(), + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + CallError: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall, baseErr error) error { + //出现错误后重试 + return resource.Retry(15*time.Minute, func() *resource.RetryError { + _, callErr := s.ReadResource(d, "") + if callErr != nil { + if ve.ResourceNotFoundError(callErr) { + return nil + } else { + return resource.NonRetryableError(fmt.Errorf("error on reading Ipv6AddressBandwidth on delete %q, %w", d.Id(), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + }, + } + callbacks = append(callbacks, removeCallback) + + return callbacks +} + +func (s *VolcengineIpv6AddressBandwidthService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + RequestConverts: map[string]ve.RequestConvert{ + "ids": { + TargetField: "AllocationIds", + ConvertType: ve.ConvertWithN, + }, + "isp": { + TargetField: "ISP", + }, + "ipv6_addresses": { + TargetField: "Ipv6Addresses", + ConvertType: ve.ConvertWithN, + }, + }, + IdField: "AllocationId", + CollectField: "ipv6_address_bandwidths", + ResponseConverts: map[string]ve.ResponseConvert{ + "AllocationId": { + TargetField: "id", + KeepDefault: true, + }, + "ISP": { + TargetField: "isp", + }, + }, + } +} + +func (s *VolcengineIpv6AddressBandwidthService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "vpc", + Version: "2020-04-01", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} diff --git a/volcengine/vpc/ipv6_gateway/data_source_volcengine_vpc_ipv6_gateways.go b/volcengine/vpc/ipv6_gateway/data_source_volcengine_vpc_ipv6_gateways.go new file mode 100644 index 00000000..ee1e5ff7 --- /dev/null +++ b/volcengine/vpc/ipv6_gateway/data_source_volcengine_vpc_ipv6_gateways.go @@ -0,0 +1,108 @@ +package ipv6_gateway + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +func DataSourceVolcengineIpv6Gateways() *schema.Resource { + return &schema.Resource{ + Read: dataSourceVolcengineIpv6GatewaysRead, + Schema: map[string]*schema.Schema{ + "ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + Description: "The ID list of the Ipv6Gateways.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the Ipv6Gateway.", + }, + "vpc_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + Description: "The ID list of the VPC which the Ipv6Gateway belongs to.", + }, + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + Description: "A Name Regex of the Ipv6Gateway.", + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + Description: "File name where to save data source results.", + }, + "total_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The total count of Ipv6Gateway query.", + }, + "ipv6_gateways": { + Description: "The collection of Ipv6Gateway query.", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Ipv6Gateway.", + }, + "ipv6_gateway_id": { + Type: schema.TypeString, + Computed: true, + Description: "The ID of the Ipv6Gateway.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The Name of the Ipv6Gateway.", + }, + "description": { + Type: schema.TypeString, + Computed: true, + Description: "The description of the Ipv6Gateway.", + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + Description: "The id of the VPC which the Ipv6Gateway belongs to.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The Status of the Ipv6Gateway.", + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + Description: "Creation time of the Ipv6Gateway.", + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: "Update time of the Ipv6Gateway.", + }, + }, + }, + }, + }, + } +} + +func dataSourceVolcengineIpv6GatewaysRead(d *schema.ResourceData, meta interface{}) error { + ipv6GatewayService := NewIpv6GatewayService(meta.(*ve.SdkClient)) + return ipv6GatewayService.Dispatcher.Data(ipv6GatewayService, d, DataSourceVolcengineIpv6Gateways()) +} diff --git a/volcengine/vpc/ipv6_gateway/resource_volcengine_vpc_ipv6_gateway.go b/volcengine/vpc/ipv6_gateway/resource_volcengine_vpc_ipv6_gateway.go new file mode 100644 index 00000000..995212de --- /dev/null +++ b/volcengine/vpc/ipv6_gateway/resource_volcengine_vpc_ipv6_gateway.go @@ -0,0 +1,91 @@ +package ipv6_gateway + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" +) + +/* + +Import +Ipv6Gateway can be imported using the id, e.g. +``` +$ terraform import volcengine_vpc_ipv6_gateway.default ipv6gw-12bcapllb5ukg17q7y2sd3thx +``` + +*/ + +func ResourceVolcengineIpv6Gateway() *schema.Resource { + return &schema.Resource{ + Create: resourceVolcengineIpv6GatewayCreate, + Read: resourceVolcengineIpv6GatewayRead, + Update: resourceVolcengineIpv6GatewayUpdate, + Delete: resourceVolcengineIpv6GatewayDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + Schema: map[string]*schema.Schema{ + "vpc_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the VPC which the Ipv6Gateway belongs to.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "The name of the Ipv6Gateway.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "The description of the Ipv6Gateway.", + }, + }, + } +} + +func resourceVolcengineIpv6GatewayCreate(d *schema.ResourceData, meta interface{}) (err error) { + ipv6GatewayService := NewIpv6GatewayService(meta.(*ve.SdkClient)) + err = ipv6GatewayService.Dispatcher.Create(ipv6GatewayService, d, ResourceVolcengineIpv6Gateway()) + if err != nil { + return fmt.Errorf("error on creating Ipv6Gateway %q, %w", d.Id(), err) + } + return resourceVolcengineIpv6GatewayRead(d, meta) +} + +func resourceVolcengineIpv6GatewayRead(d *schema.ResourceData, meta interface{}) (err error) { + ipv6GatewayService := NewIpv6GatewayService(meta.(*ve.SdkClient)) + err = ipv6GatewayService.Dispatcher.Read(ipv6GatewayService, d, ResourceVolcengineIpv6Gateway()) + if err != nil { + return fmt.Errorf("error on reading Ipv6Gateway %q, %w", d.Id(), err) + } + return err +} + +func resourceVolcengineIpv6GatewayUpdate(d *schema.ResourceData, meta interface{}) (err error) { + ipv6GatewayService := NewIpv6GatewayService(meta.(*ve.SdkClient)) + err = ipv6GatewayService.Dispatcher.Update(ipv6GatewayService, d, ResourceVolcengineIpv6Gateway()) + if err != nil { + return fmt.Errorf("error on updating Ipv6Gateway %q, %w", d.Id(), err) + } + return resourceVolcengineIpv6GatewayRead(d, meta) +} + +func resourceVolcengineIpv6GatewayDelete(d *schema.ResourceData, meta interface{}) (err error) { + ipv6GatewayService := NewIpv6GatewayService(meta.(*ve.SdkClient)) + err = ipv6GatewayService.Dispatcher.Delete(ipv6GatewayService, d, ResourceVolcengineIpv6Gateway()) + if err != nil { + return fmt.Errorf("error on deleting Ipv6Gateway %q, %w", d.Id(), err) + } + return err +} diff --git a/volcengine/vpc/ipv6_gateway/service_volcengine_vpc_ipv6_gateway.go b/volcengine/vpc/ipv6_gateway/service_volcengine_vpc_ipv6_gateway.go new file mode 100644 index 00000000..cdf56690 --- /dev/null +++ b/volcengine/vpc/ipv6_gateway/service_volcengine_vpc_ipv6_gateway.go @@ -0,0 +1,258 @@ +package ipv6_gateway + +import ( + "errors" + "fmt" + "time" + + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + ve "github.com/volcengine/terraform-provider-volcengine/common" + "github.com/volcengine/terraform-provider-volcengine/logger" +) + +type VolcengineIpv6GatewayService struct { + Client *ve.SdkClient + Dispatcher *ve.Dispatcher +} + +func NewIpv6GatewayService(c *ve.SdkClient) *VolcengineIpv6GatewayService { + return &VolcengineIpv6GatewayService{ + Client: c, + Dispatcher: &ve.Dispatcher{}, + } +} + +func (s *VolcengineIpv6GatewayService) GetClient() *ve.SdkClient { + return s.Client +} + +func (s *VolcengineIpv6GatewayService) ReadResources(condition map[string]interface{}) (data []interface{}, err error) { + var ( + resp *map[string]interface{} + results interface{} + ok bool + ) + return ve.WithPageNumberQuery(condition, "PageSize", "PageNumber", 20, 1, func(m map[string]interface{}) ([]interface{}, error) { + action := "DescribeIpv6Gateways" + logger.Debug(logger.ReqFormat, action, condition) + if condition == nil { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), nil) + if err != nil { + return data, err + } + } else { + resp, err = s.Client.UniversalClient.DoCall(getUniversalInfo(action), &condition) + if err != nil { + return data, err + } + } + logger.Debug(logger.RespFormat, action, condition, *resp) + + results, err = ve.ObtainSdkValue("Result.Ipv6Gateways", *resp) + if err != nil { + return data, err + } + if data, ok = results.([]interface{}); !ok { + return data, errors.New("Result.Ipv6Gateways is not Slice") + } + + return data, err + }) +} + +func (s *VolcengineIpv6GatewayService) ReadResource(resourceData *schema.ResourceData, ipv6GatewayId string) (data map[string]interface{}, err error) { + var ( + results []interface{} + ok bool + ) + if ipv6GatewayId == "" { + ipv6GatewayId = s.ReadResourceId(resourceData.Id()) + } + req := map[string]interface{}{ + "Ipv6GatewayIds.1": ipv6GatewayId, + } + results, err = s.ReadResources(req) + if err != nil { + return data, err + } + for _, v := range results { + if data, ok = v.(map[string]interface{}); !ok { + return data, errors.New("Value is not map ") + } + } + if len(data) == 0 { + return data, fmt.Errorf("Ipv6Gateway %s is not exist ", ipv6GatewayId) + } + + return data, err +} + +func (s *VolcengineIpv6GatewayService) RefreshResourceState(resourceData *schema.ResourceData, target []string, timeout time.Duration, id string) *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{}, + Delay: 1 * time.Second, + MinTimeout: 1 * time.Second, + Target: target, + Timeout: timeout, + Refresh: func() (result interface{}, state string, err error) { + var ( + demo map[string]interface{} + status interface{} + ) + //no failed status. + demo, err = s.ReadResource(resourceData, id) + if err != nil { + return nil, "", err + } + status, err = ve.ObtainSdkValue("Status", demo) + if err != nil { + return nil, "", err + } + return demo, status.(string), err + }, + } +} + +func (VolcengineIpv6GatewayService) WithResourceResponseHandlers(ipv6Gateway map[string]interface{}) []ve.ResourceResponseHandler { + handler := func() (map[string]interface{}, map[string]ve.ResponseConvert, error) { + return ipv6Gateway, nil, nil + } + return []ve.ResourceResponseHandler{handler} + +} + +func (s *VolcengineIpv6GatewayService) CreateResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "CreateIpv6Gateway", + ConvertMode: ve.RequestConvertAll, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["ClientToken"] = uuid.New().String() + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + AfterCall: func(d *schema.ResourceData, client *ve.SdkClient, resp *map[string]interface{}, call ve.SdkCall) error { + id, _ := ve.ObtainSdkValue("Result.Ipv6GatewayId", *resp) + d.SetId(id.(string)) + return nil + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + }, + } + callbacks = append(callbacks, callback) + + return callbacks +} + +func (s *VolcengineIpv6GatewayService) ModifyResource(resourceData *schema.ResourceData, resource *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + callback := ve.Callback{ + Call: ve.SdkCall{ + Action: "ModifyIpv6GatewayAttribute", + ConvertMode: ve.RequestConvertAll, + BeforeCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (bool, error) { + (*call.SdkParam)["Ipv6GatewayId"] = d.Id() + return true, nil + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.ReqFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + Refresh: &ve.StateRefresh{ + Target: []string{"Available"}, + Timeout: resourceData.Timeout(schema.TimeoutCreate), + }, + }, + } + callbacks = append(callbacks, callback) + + return callbacks +} + +func (s *VolcengineIpv6GatewayService) RemoveResource(resourceData *schema.ResourceData, r *schema.Resource) []ve.Callback { + var callbacks []ve.Callback + + removeCallback := ve.Callback{ + Call: ve.SdkCall{ + Action: "DeleteIpv6Gateway", + ConvertMode: ve.RequestConvertIgnore, + SdkParam: &map[string]interface{}{ + "Ipv6GatewayId": resourceData.Id(), + }, + ExecuteCall: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall) (*map[string]interface{}, error) { + logger.Debug(logger.RespFormat, call.Action, call.SdkParam) + return s.Client.UniversalClient.DoCall(getUniversalInfo(call.Action), call.SdkParam) + }, + CallError: func(d *schema.ResourceData, client *ve.SdkClient, call ve.SdkCall, baseErr error) error { + //出现错误后重试 + return resource.Retry(15*time.Minute, func() *resource.RetryError { + _, callErr := s.ReadResource(d, "") + if callErr != nil { + if ve.ResourceNotFoundError(callErr) { + return nil + } else { + return resource.NonRetryableError(fmt.Errorf("error on reading Ipv6Gateway on delete %q, %w", d.Id(), callErr)) + } + } + _, callErr = call.ExecuteCall(d, client, call) + if callErr == nil { + return nil + } + return resource.RetryableError(callErr) + }) + }, + }, + } + callbacks = append(callbacks, removeCallback) + + return callbacks +} + +func (s *VolcengineIpv6GatewayService) DatasourceResources(*schema.ResourceData, *schema.Resource) ve.DataSourceInfo { + return ve.DataSourceInfo{ + RequestConverts: map[string]ve.RequestConvert{ + "ids": { + TargetField: "Ipv6GatewayIds", + ConvertType: ve.ConvertWithN, + }, + "vpc_ids": { + TargetField: "VpcIds", + ConvertType: ve.ConvertWithN, + }, + }, + NameField: "Name", + IdField: "Ipv6GatewayId", + CollectField: "ipv6_gateways", + ResponseConverts: map[string]ve.ResponseConvert{ + "Ipv6GatewayId": { + TargetField: "id", + KeepDefault: true, + }, + }, + } +} + +func (s *VolcengineIpv6GatewayService) ReadResourceId(id string) string { + return id +} + +func getUniversalInfo(actionName string) ve.UniversalInfo { + return ve.UniversalInfo{ + ServiceName: "vpc", + Version: "2020-04-01", + HttpMethod: ve.GET, + ContentType: ve.Default, + Action: actionName, + } +} diff --git a/volcengine/vpc/subnet/data_source_volcengine_subnets.go b/volcengine/vpc/subnet/data_source_volcengine_subnets.go index 56bcda8d..613c6553 100644 --- a/volcengine/vpc/subnet/data_source_volcengine_subnets.go +++ b/volcengine/vpc/subnet/data_source_volcengine_subnets.go @@ -136,6 +136,11 @@ func DataSourceVolcengineSubnets() *schema.Resource { Computed: true, Description: "The ID of network acl which this subnet associate with.", }, + "ipv6_cidr_block": { + Type: schema.TypeString, + Computed: true, + Description: "The IPv6 CIDR block of the VPC.", + }, "route_table": { Type: schema.TypeSet, MaxItems: 1, diff --git a/volcengine/vpc/subnet/resource_volcengine_subnet.go b/volcengine/vpc/subnet/resource_volcengine_subnet.go index cd75c401..d750d18b 100644 --- a/volcengine/vpc/subnet/resource_volcengine_subnet.go +++ b/volcengine/vpc/subnet/resource_volcengine_subnet.go @@ -69,6 +69,31 @@ func ResourceVolcengineSubnet() *schema.Resource { ForceNew: true, Description: "Id of the Zone.", }, + "enable_ipv6": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // 创建时不存在这个参数,修改时存在这个参数 + return d.Id() == "" + }, + Description: "Specifies whether to enable the IPv6 CIDR block of the Subnet. This field is only valid when modifying the Subnet.", + }, + "ipv6_cidr_block": { + Type: schema.TypeInt, + Optional: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if d.Id() == "" { + return false + } else { + if d.HasChange("enable_ipv6") && d.Get("enable_ipv6").(bool) { + return false + } + return true + } + }, + Description: "The last eight bits of the IPv6 CIDR block of the Subnet. Valid values: 0 - 255.", + }, "creation_time": { Type: schema.TypeString, Computed: true, diff --git a/volcengine/vpc/subnet/service_volcengine_subnet.go b/volcengine/vpc/subnet/service_volcengine_subnet.go index c718238b..985a8a2a 100644 --- a/volcengine/vpc/subnet/service_volcengine_subnet.go +++ b/volcengine/vpc/subnet/service_volcengine_subnet.go @@ -3,6 +3,9 @@ package subnet import ( "errors" "fmt" + "net" + "strconv" + "strings" "time" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -87,6 +90,31 @@ func (s *VolcengineSubnetService) ReadResource(resourceData *schema.ResourceData if len(data) == 0 { return data, fmt.Errorf("Subnet %s not exist ", subnetId) } + + if ipv6CidrBlock, ok1 := data["Ipv6CidrBlock"]; ok1 && ipv6CidrBlock.(string) != "" { + data["EnableIpv6"] = true + + ipv6Address, _, err := net.ParseCIDR(ipv6CidrBlock.(string)) + if err != nil { + return data, err + } + bits := strings.Split(ipv6Address.String(), ":") + if len(bits) < 4 { + data["Ipv6CidrBlock"] = 0 + } else { + temp := bits[3] + temp = strings.Repeat("0", 4-len(temp)) + temp + ipv6CidrValue, err := strconv.ParseInt(temp[2:], 16, 9) + if err != nil { + return data, err + } + data["Ipv6CidrBlock"] = int(ipv6CidrValue) + } + } else { + data["EnableIpv6"] = false + delete(data, "Ipv6CidrBlock") + } + return data, err } diff --git a/volcengine/vpc/vpc/data_source_volcengine_vpcs.go b/volcengine/vpc/vpc/data_source_volcengine_vpcs.go index 674353b3..6bfd3541 100644 --- a/volcengine/vpc/vpc/data_source_volcengine_vpcs.go +++ b/volcengine/vpc/vpc/data_source_volcengine_vpcs.go @@ -175,6 +175,11 @@ func DataSourceVolcengineVpcs() *schema.Resource { Set: schema.HashString, Description: "The auxiliary cidr block list of VPC.", }, + "ipv6_cidr_block": { + Type: schema.TypeString, + Computed: true, + Description: "The IPv6 CIDR block of the VPC.", + }, "project_name": { Type: schema.TypeString, Computed: true, diff --git a/volcengine/vpc/vpc/resource_volcengine_vpc.go b/volcengine/vpc/vpc/resource_volcengine_vpc.go index dbc895fc..740ea7bb 100644 --- a/volcengine/vpc/vpc/resource_volcengine_vpc.go +++ b/volcengine/vpc/vpc/resource_volcengine_vpc.go @@ -62,6 +62,24 @@ func ResourceVolcengineVpc() *schema.Resource { Set: schema.HashString, Description: "The DNS server list of the VPC. And you can specify 0 to 5 servers to this list.", }, + "enable_ipv6": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Specifies whether to enable the IPv6 CIDR block of the VPC.", + }, + "ipv6_cidr_block": { + Type: schema.TypeString, + Optional: true, + Computed: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if d.HasChange("enable_ipv6") && d.Get("enable_ipv6").(bool) { + return false + } + return true + }, + Description: "The IPv6 CIDR block of the VPC.", + }, "project_name": { Type: schema.TypeString, Optional: true, diff --git a/volcengine/vpc/vpc/service_volcengine_vpc.go b/volcengine/vpc/vpc/service_volcengine_vpc.go index 85fff040..7a207aba 100644 --- a/volcengine/vpc/vpc/service_volcengine_vpc.go +++ b/volcengine/vpc/vpc/service_volcengine_vpc.go @@ -89,6 +89,13 @@ func (s *VolcengineVpcService) ReadResource(resourceData *schema.ResourceData, v if _, ok1 := data["AuxiliaryCidrBlocks"]; !ok1 { data["AuxiliaryCidrBlocks"] = []string{} } + + if ipv6CidrBlock, ok2 := data["Ipv6CidrBlock"]; ok2 && ipv6CidrBlock != "" { + data["EnableIpv6"] = true + } else { + data["EnableIpv6"] = false + } + return data, err } diff --git a/website/docs/d/subnets.html.markdown b/website/docs/d/subnets.html.markdown index faa5cfbc..f99db349 100644 --- a/website/docs/d/subnets.html.markdown +++ b/website/docs/d/subnets.html.markdown @@ -33,6 +33,7 @@ In addition to all arguments above, the following attributes are exported: * `creation_time` - Creation time of Subnet. * `description` - The description of Subnet. * `id` - The ID of Subnet. + * `ipv6_cidr_block` - The IPv6 CIDR block of the VPC. * `network_acl_id` - The ID of network acl which this subnet associate with. * `route_table_id` - The ID of route table. * `route_table_type` - The type of route table. diff --git a/website/docs/d/vpc_ipv6_address_bandwidths.html.markdown b/website/docs/d/vpc_ipv6_address_bandwidths.html.markdown new file mode 100644 index 00000000..39831e85 --- /dev/null +++ b/website/docs/d/vpc_ipv6_address_bandwidths.html.markdown @@ -0,0 +1,49 @@ +--- +subcategory: "VPC" +layout: "volcengine" +page_title: "Volcengine: volcengine_vpc_ipv6_address_bandwidths" +sidebar_current: "docs-volcengine-datasource-vpc_ipv6_address_bandwidths" +description: |- + Use this data source to query detailed information of vpc ipv6 address bandwidths +--- +# volcengine_vpc_ipv6_address_bandwidths +Use this data source to query detailed information of vpc ipv6 address bandwidths +## Example Usage +```hcl +data "volcengine_vpc_ipv6_address_bandwidths" "default" { + ids = ["eip-in2y2duvtlhc8gbssyfnhfre"] +} +``` +## Argument Reference +The following arguments are supported: +* `associated_instance_id` - (Optional) The ID of the associated instance. +* `associated_instance_type` - (Optional) The type of the associated instance. +* `ids` - (Optional) Allocation IDs of the Ipv6 address width. +* `ipv6_addresses` - (Optional) The ipv6 addresses. +* `isp` - (Optional) ISP of the ipv6 address. +* `network_type` - (Optional) The network type of the ipv6 address. +* `output_file` - (Optional) File name where to save data source results. +* `vpc_id` - (Optional) The ID of Vpc the ipv6 address in. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `ipv6_address_bandwidths` - The collection of Ipv6AddressBandwidth query. + * `allocation_id` - The ID of the Ipv6AddressBandwidth. + * `bandwidth` - Peek bandwidth of the Ipv6 address. + * `billing_type` - BillingType of the Ipv6 bandwidth. + * `business_status` - The BusinessStatus of the Ipv6AddressBandwidth. + * `creation_time` - Creation time of the Ipv6AddressBandwidth. + * `delete_time` - Delete time of the Ipv6AddressBandwidth. + * `id` - The ID of the Ipv6AddressBandwidth. + * `instance_id` - The ID of the associated instance. + * `instance_type` - The type of the associated instance. + * `ipv6_address` - The IPv6 address. + * `isp` - The ISP of the Ipv6AddressBandwidth. + * `lock_reason` - The BusinessStatus of the Ipv6AddressBandwidth. + * `network_type` - The network type of the Ipv6AddressBandwidth. + * `overdue_time` - Overdue time of the Ipv6AddressBandwidth. + * `status` - The status of the Ipv6AddressBandwidth. + * `update_time` - Update time of the Ipv6AddressBandwidth. +* `total_count` - The total count of Ipv6AddressBandwidth query. + + diff --git a/website/docs/d/vpc_ipv6_gateways.html.markdown b/website/docs/d/vpc_ipv6_gateways.html.markdown new file mode 100644 index 00000000..928448f4 --- /dev/null +++ b/website/docs/d/vpc_ipv6_gateways.html.markdown @@ -0,0 +1,38 @@ +--- +subcategory: "VPC" +layout: "volcengine" +page_title: "Volcengine: volcengine_vpc_ipv6_gateways" +sidebar_current: "docs-volcengine-datasource-vpc_ipv6_gateways" +description: |- + Use this data source to query detailed information of vpc ipv6 gateways +--- +# volcengine_vpc_ipv6_gateways +Use this data source to query detailed information of vpc ipv6 gateways +## Example Usage +```hcl +data "volcengine_vpc_ipv6_gateways" "default" { + ids = ["ipv6gw-12bcapllb5ukg17q7y2sd3thx"] +} +``` +## Argument Reference +The following arguments are supported: +* `ids` - (Optional) The ID list of the Ipv6Gateways. +* `name_regex` - (Optional) A Name Regex of the Ipv6Gateway. +* `name` - (Optional) The name of the Ipv6Gateway. +* `output_file` - (Optional) File name where to save data source results. +* `vpc_ids` - (Optional) The ID list of the VPC which the Ipv6Gateway belongs to. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `ipv6_gateways` - The collection of Ipv6Gateway query. + * `creation_time` - Creation time of the Ipv6Gateway. + * `description` - The description of the Ipv6Gateway. + * `id` - The ID of the Ipv6Gateway. + * `ipv6_gateway_id` - The ID of the Ipv6Gateway. + * `name` - The Name of the Ipv6Gateway. + * `status` - The Status of the Ipv6Gateway. + * `update_time` - Update time of the Ipv6Gateway. + * `vpc_id` - The id of the VPC which the Ipv6Gateway belongs to. +* `total_count` - The total count of Ipv6Gateway query. + + diff --git a/website/docs/d/vpcs.html.markdown b/website/docs/d/vpcs.html.markdown index 31cdc3a3..18b735e6 100644 --- a/website/docs/d/vpcs.html.markdown +++ b/website/docs/d/vpcs.html.markdown @@ -42,6 +42,7 @@ In addition to all arguments above, the following attributes are exported: * `creation_time` - The create time of VPC. * `description` - The description of VPC. * `dns_servers` - The dns server list of VPC. + * `ipv6_cidr_block` - The IPv6 CIDR block of the VPC. * `nat_gateway_ids` - The nat gateway ID list of VPC. * `project_name` - The ProjectName of the VPC. * `route_table_ids` - The route table ID list of VPC. diff --git a/website/docs/r/ecs_instance.html.markdown b/website/docs/r/ecs_instance.html.markdown index 3738d5b1..5435b5a1 100644 --- a/website/docs/r/ecs_instance.html.markdown +++ b/website/docs/r/ecs_instance.html.markdown @@ -68,6 +68,7 @@ The following arguments are supported: * `include_data_volumes` - (Optional) The include data volumes flag of ECS instance.Only effective when change instance charge type.include_data_volumes. * `instance_charge_type` - (Optional) The charge type of ECS instance, the value can be `PrePaid` or `PostPaid`. * `instance_name` - (Optional) The name of ECS instance. +* `ipv6_address_count` - (Optional, ForceNew) The ipv6 address count of ECS instance. Valid values: 0, 1. * `keep_image_credential` - (Optional) Whether to keep the mirror settings. Only custom images and shared images support this field. When the value of this field is true, the Password and KeyPairName cannot be specified. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields. diff --git a/website/docs/r/subnet.html.markdown b/website/docs/r/subnet.html.markdown index 8b44b448..d088089d 100644 --- a/website/docs/r/subnet.html.markdown +++ b/website/docs/r/subnet.html.markdown @@ -23,6 +23,8 @@ The following arguments are supported: * `vpc_id` - (Required, ForceNew) Id of the VPC. * `zone_id` - (Required, ForceNew) Id of the Zone. * `description` - (Optional) The description of the Subnet. +* `enable_ipv6` - (Optional) Specifies whether to enable the IPv6 CIDR block of the Subnet. This field is only valid when modifying the Subnet. +* `ipv6_cidr_block` - (Optional) The last eight bits of the IPv6 CIDR block of the Subnet. Valid values: 0 - 255. * `subnet_name` - (Optional) The name of the Subnet. ## Attributes Reference diff --git a/website/docs/r/vpc.html.markdown b/website/docs/r/vpc.html.markdown index d22ee706..7482aee7 100644 --- a/website/docs/r/vpc.html.markdown +++ b/website/docs/r/vpc.html.markdown @@ -23,6 +23,9 @@ The following arguments are supported: * `description` - (Optional) The description of the VPC. * `dns_servers` - (Optional) The DNS server list of the VPC. And you can specify 0 to 5 servers to this list. * `project_name` - (Optional) The ProjectName of the VPC. +* `enable_ipv6` - (Optional) Specifies whether to enable the IPv6 CIDR block of the VPC. +* `ipv6_cidr_block` - (Optional) The IPv6 CIDR block of the VPC. +* `project_name` - (Optional, ForceNew) The ProjectName of the VPC. * `tags` - (Optional) Tags. * `vpc_name` - (Optional) The name of the VPC. diff --git a/website/docs/r/vpc_ipv6_address_bandwidth.html.markdown b/website/docs/r/vpc_ipv6_address_bandwidth.html.markdown new file mode 100644 index 00000000..11595798 --- /dev/null +++ b/website/docs/r/vpc_ipv6_address_bandwidth.html.markdown @@ -0,0 +1,47 @@ +--- +subcategory: "VPC" +layout: "volcengine" +page_title: "Volcengine: volcengine_vpc_ipv6_address_bandwidth" +sidebar_current: "docs-volcengine-resource-vpc_ipv6_address_bandwidth" +description: |- + Provides a resource to manage vpc ipv6 address bandwidth +--- +# volcengine_vpc_ipv6_address_bandwidth +Provides a resource to manage vpc ipv6 address bandwidth +## Example Usage +```hcl +resource "volcengine_vpc_ipv6_address_bandwidth" "foo" { + ipv6_address = "2000:1000:89ff:ff02:ea70:18ce:dda2:a02e" + billing_type = 3 + bandwidth = 5 +} +``` +## Argument Reference +The following arguments are supported: +* `billing_type` - (Required, ForceNew) BillingType of the Ipv6 bandwidth. Valid values: 3(Pay by Traffic). +* `ipv6_address` - (Required, ForceNew) Ipv6 address. +* `bandwidth` - (Optional) Peek bandwidth of the Ipv6 address. Valid values: 1 to 200. Unit: Mbit/s. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. +* `allocation_id` - The ID of the Ipv6AddressBandwidth. +* `business_status` - The BusinessStatus of the Ipv6AddressBandwidth. +* `creation_time` - Creation time of the Ipv6AddressBandwidth. +* `delete_time` - Delete time of the Ipv6AddressBandwidth. +* `instance_id` - The ID of the associated instance. +* `instance_type` - The type of the associated instance. +* `isp` - The ISP of the Ipv6AddressBandwidth. +* `lock_reason` - The BusinessStatus of the Ipv6AddressBandwidth. +* `network_type` - The network type of the Ipv6AddressBandwidth. +* `overdue_time` - Overdue time of the Ipv6AddressBandwidth. +* `status` - The status of the Ipv6AddressBandwidth. +* `update_time` - Update time of the Ipv6AddressBandwidth. + + +## Import +Ipv6AddressBandwidth can be imported using the id, e.g. +``` +$ terraform import volcengine_vpc_ipv6_address_bandwidth.default eip-2fede9fsgnr4059gp674m6ney +``` + diff --git a/website/docs/r/vpc_ipv6_gateway.html.markdown b/website/docs/r/vpc_ipv6_gateway.html.markdown new file mode 100644 index 00000000..be7ae640 --- /dev/null +++ b/website/docs/r/vpc_ipv6_gateway.html.markdown @@ -0,0 +1,36 @@ +--- +subcategory: "VPC" +layout: "volcengine" +page_title: "Volcengine: volcengine_vpc_ipv6_gateway" +sidebar_current: "docs-volcengine-resource-vpc_ipv6_gateway" +description: |- + Provides a resource to manage vpc ipv6 gateway +--- +# volcengine_vpc_ipv6_gateway +Provides a resource to manage vpc ipv6 gateway +## Example Usage +```hcl +resource "volcengine_vpc_ipv6_gateway" "foo" { + vpc_id = "vpc-12afxho4sxyio17q7y2kkp8ej" + name = "tf-test-1" + description = "test" +} +``` +## Argument Reference +The following arguments are supported: +* `vpc_id` - (Required, ForceNew) The ID of the VPC which the Ipv6Gateway belongs to. +* `description` - (Optional) The description of the Ipv6Gateway. +* `name` - (Optional) The name of the Ipv6Gateway. + +## Attributes Reference +In addition to all arguments above, the following attributes are exported: +* `id` - ID of the resource. + + + +## Import +Ipv6Gateway can be imported using the id, e.g. +``` +$ terraform import volcengine_vpc_ipv6_gateway.default ipv6gw-12bcapllb5ukg17q7y2sd3thx +``` + diff --git a/website/volcengine.erb b/website/volcengine.erb index faa6e3a8..dac2904f 100644 --- a/website/volcengine.erb +++ b/website/volcengine.erb @@ -736,6 +736,12 @@
  • Data Sources