diff --git a/.changelog/3200.txt b/.changelog/3200.txt new file mode 100644 index 0000000000..b9f87e995f --- /dev/null +++ b/.changelog/3200.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +tencentcloud_mongodb_readonly_instance +``` \ No newline at end of file diff --git a/tencentcloud/acctest/basic.go b/tencentcloud/acctest/basic.go index 906fbc90b3..32dd227fcc 100644 --- a/tencentcloud/acctest/basic.go +++ b/tencentcloud/acctest/basic.go @@ -856,10 +856,10 @@ locals { locals { filtered_sharding_spec = [for i in data.tencentcloud_mongodb_zone_config.zone_config.list: i if lookup(i, "cluster_type") == "SHARD" && lookup(i, "min_replicate_set_num") > 0 && lookup(i, "machine_type") == "HIO10G" && lookup(i, "engine_version") == "4.4" && lookup(i, "memory") == 4096 && lookup(i, "default_storage") == 256000] sharding_spec = concat(local.filtered_sharding_spec, [for i in data.tencentcloud_mongodb_zone_config.zone_config.list: i if lookup(i, "cluster_type") == "SHARD" && lookup(i, "min_replicate_set_num") > 0]) - sharding_machine_type = local.sharding_spec.0.machine_type - sharding_memory = local.sharding_spec.0.memory / 1024 - sharding_volume = local.sharding_spec.0.default_storage / 1000 - sharding_engine_version = lookup(var.engine_versions, local.sharding_spec.0.engine_version) + sharding_machine_type = local.filtered_sharding_spec.0.machine_type + sharding_memory = local.filtered_sharding_spec.0.memory / 1024 + sharding_volume = local.filtered_sharding_spec.0.default_storage / 1000 + sharding_engine_version = lookup(var.engine_versions, local.filtered_sharding_spec.0.engine_version) } ` diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index f358099b64..e29d27771d 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -1529,6 +1529,7 @@ func Provider() *schema.Provider { "tencentcloud_monitor_grafana_sso_config": tcmg.ResourceTencentCloudMonitorGrafanaSsoConfig(), "tencentcloud_monitor_grafana_version_upgrade": tcmg.ResourceTencentCloudMonitorGrafanaVersionUpgrade(), "tencentcloud_mongodb_standby_instance": mongodb.ResourceTencentCloudMongodbStandbyInstance(), + "tencentcloud_mongodb_readonly_instance": mongodb.ResourceTencentCloudMongodbReadOnlyInstance(), "tencentcloud_elasticsearch_instance": es.ResourceTencentCloudElasticsearchInstance(), "tencentcloud_elasticsearch_security_group": es.ResourceTencentCloudElasticsearchSecurityGroup(), "tencentcloud_elasticsearch_logstash": es.ResourceTencentCloudElasticsearchLogstash(), diff --git a/tencentcloud/provider.md b/tencentcloud/provider.md index 9b38a2449e..c08ba05a87 100644 --- a/tencentcloud/provider.md +++ b/tencentcloud/provider.md @@ -733,6 +733,7 @@ tencentcloud_mongodb_instance_backup tencentcloud_mongodb_instance_transparent_data_encryption tencentcloud_mongodb_instance_backup_rule tencentcloud_mongodb_instance_params +tencentcloud_mongodb_readonly_instance TencentDB for MySQL(cdb) Data Source diff --git a/tencentcloud/services/mongodb/resource_tc_mongodb_readonly_instance.go b/tencentcloud/services/mongodb/resource_tc_mongodb_readonly_instance.go new file mode 100644 index 0000000000..63c9ef9bee --- /dev/null +++ b/tencentcloud/services/mongodb/resource_tc_mongodb_readonly_instance.go @@ -0,0 +1,582 @@ +package mongodb + +import ( + "context" + "errors" + "fmt" + "log" + "reflect" + "strings" + + tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + svctag "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/services/tag" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + mongodb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/mongodb/v20190725" + + sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/ratelimit" +) + +func ResourceTencentCloudMongodbReadOnlyInstance() *schema.Resource { + mongodbReadOnlyInstanceInfo := map[string]*schema.Schema{ + "father_instance_region": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "Indicates the region of main instance.", + }, + "father_instance_id": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: "Indicates the main instance ID of readonly instances.", + }, + "cluster_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Instance schema type." + + " - REPLSET: Replset cluster;" + + " - SHARD: Shard cluster.", + }, + "node_num": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "The number of nodes in each replica set. Default value: 3.", + }, + "shard_quantity": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: tccommon.ValidateIntegerInRange(2, 20), + Description: "Number of sharding.", + }, + "nodes_per_shard": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: tccommon.ValidateIntegerInRange(3, 5), + Description: "Number of nodes per shard, at least 3(one master and two slaves).", + }, + } + basic := TencentMongodbBasicInfo() + conflictList := []string{"password"} + for _, item := range conflictList { + delete(basic, item) + } + for k, v := range basic { + mongodbReadOnlyInstanceInfo[k] = v + } + + return &schema.Resource{ + Create: resourceTencentCloudMongodbReadOnlyInstanceCreate, + Read: resourceTencentCloudMongodbReadOnlyInstanceRead, + Update: resourceTencentCloudMongodbReadOnlyInstanceUpdate, + Delete: resourceTencentCloudMongodbReadOnlyInstanceDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: mongodbReadOnlyInstanceInfo, + } +} + +func mongodbAllReadOnlyInstanceReqSet(requestInter interface{}, d *schema.ResourceData, masterInfo map[string]string) error { + var ( + replicateSetNum = 1 + nodeNum = 3 + goodsNum = 1 + clusterType = MONGODB_CLUSTER_TYPE_REPLSET + memoryInterface = d.Get("memory").(int) + volumeInterface = d.Get("volume").(int) + mongoVersionInterface = masterInfo["engine_version"] + zoneInterface = d.Get("available_zone").(string) + machine = masterInfo["machine_type"] + fatherId = masterInfo["father_instance_id"] + instanceType = MONGO_INSTANCE_TYPE_READONLY + projectId = d.Get("project_id").(int) + ) + + if v, ok := d.GetOk("shard_quantity"); ok { + replicateSetNum = v.(int) + } + + if v, ok := d.GetOk("nodes_per_shard"); ok { + nodeNum = v.(int) + } + + if v, ok := d.GetOk("cluster_type"); ok { + clusterType = v.(string) + } + + getType := reflect.TypeOf(requestInter) + value := reflect.ValueOf(requestInter).Elem() + + for k, v := range map[string]interface{}{ + "ReplicateSetNum": helper.IntUint64(replicateSetNum), + "NodeNum": helper.IntUint64(nodeNum), + "GoodsNum": helper.IntUint64(goodsNum), + "ClusterType": &clusterType, + "Memory": helper.IntUint64(memoryInterface), + "Volume": helper.IntUint64(volumeInterface), + "MongoVersion": &mongoVersionInterface, + "Zone": &zoneInterface, + "MachineCode": &machine, + "Clone": helper.IntInt64(instanceType), + "ProjectId": helper.IntInt64(projectId), + "Father": &fatherId, + } { + value.FieldByName(k).Set(reflect.ValueOf(v)) + } + + var okVpc, okSubnet bool + if v, ok := d.GetOk("vpc_id"); ok { + okVpc = ok + value.FieldByName("VpcId").Set(reflect.ValueOf(helper.String(v.(string)))) + } + if v, ok := d.GetOk("subnet_id"); ok { + okSubnet = ok + value.FieldByName("SubnetId").Set(reflect.ValueOf(helper.String(v.(string)))) + } + if (okVpc && !okSubnet) || (!okVpc && okSubnet) { + return fmt.Errorf("you have to set vpc_id and subnet_id both") + } + if v, ok := d.GetOk("security_groups"); ok { + sliceReflect := helper.InterfacesStringsPoint(v.(*schema.Set).List()) + value.FieldByName("SecurityGroup").Set(reflect.ValueOf(sliceReflect)) + } + + if strings.Contains(getType.String(), "CreateDBInstanceRequest") { + if v, ok := d.GetOk("prepaid_period"); ok { + value.FieldByName("Period").Set(reflect.ValueOf(helper.IntUint64(v.(int)))) + } else { + return fmt.Errorf("prepaid_period must be specified for a PREPAID instance") + } + value.FieldByName("AutoRenewFlag").Set(reflect.ValueOf(helper.IntUint64(d.Get("auto_renew_flag").(int)))) + } + if v, ok := d.GetOk("availability_zone_list"); ok { + availabilityZoneList := helper.InterfacesStringsPoint(v.([]interface{})) + value.FieldByName("AvailabilityZoneList").Set(reflect.ValueOf(availabilityZoneList)) + } + if v, ok := d.GetOk("hidden_zone"); ok { + value.FieldByName("HiddenZone").Set(reflect.ValueOf(helper.String(v.(string)))) + } + + if v, ok := d.GetOk("mongos_memory"); ok { + value.FieldByName("MongosMemory").Set(reflect.ValueOf(helper.IntUint64(v.(int)))) + } + if v, ok := d.GetOk("mongos_cpu"); ok { + value.FieldByName("MongosCpu").Set(reflect.ValueOf(helper.IntUint64(v.(int)))) + } + if v, ok := d.GetOk("mongos_node_num"); ok { + value.FieldByName("MongosNodeNum").Set(reflect.ValueOf(helper.IntUint64(v.(int)))) + } + return nil +} + +func mongodbCreateReadOnlyInstanceByUse(ctx context.Context, d *schema.ResourceData, meta interface{}, masterInfo map[string]string) error { + logId := tccommon.GetLogId(ctx) + request := mongodb.NewCreateDBInstanceHourRequest() + + if err := mongodbAllReadOnlyInstanceReqSet(request, d, masterInfo); err != nil { + return err + } + + var response *mongodb.CreateDBInstanceHourResponse + var err error + err = resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + ratelimit.Check(request.GetAction()) + response, err = meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseMongodbClient().CreateDBInstanceHour(request) + if err != nil { + log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), err.Error()) + return tccommon.RetryError(err) + } + return nil + }) + if err != nil { + return err + } + + if len(response.Response.InstanceIds) < 1 { + return fmt.Errorf("mongodb ReadOnly instance id is nil") + } + d.SetId(*response.Response.InstanceIds[0]) + + return nil +} + +func mongodbCreateReadOnlyInstanceByMonth(ctx context.Context, d *schema.ResourceData, meta interface{}, masterInfo map[string]string) error { + logId := tccommon.GetLogId(ctx) + request := mongodb.NewCreateDBInstanceRequest() + + if err := mongodbAllReadOnlyInstanceReqSet(request, d, masterInfo); err != nil { + return err + } + + var response *mongodb.CreateDBInstanceResponse + var err error + err = resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { + ratelimit.Check(request.GetAction()) + response, err = meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseMongodbClient().CreateDBInstance(request) + if err != nil { + log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), err.Error()) + return tccommon.RetryError(err) + } + return nil + }) + if err != nil { + return err + } + + if len(response.Response.InstanceIds) < 1 { + return fmt.Errorf("mongodb ReadOnly instance id is nil") + } + d.SetId(*response.Response.InstanceIds[0]) + + return nil +} + +func resourceTencentCloudMongodbReadOnlyInstanceCreate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_mongodb_readonly_instance.create")() + + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + + client := meta.(tccommon.ProviderMeta).GetAPIV3Conn() + client1 := *client + mongodbService := MongodbService{client: client} + mongodbService1 := MongodbService{client: &client1} + tagService := svctag.NewTagService(client) + region := client.Region + + // collect info from master instance + var masterInfoMap = make(map[string]string, 3) + if _, ok := d.GetOk("father_instance_id"); !ok { + return fmt.Errorf("[CRITAL] father instance id must be specified for ReadOnly instance") + } + if _, ok := d.GetOk("father_instance_region"); !ok { + return fmt.Errorf("[CRITAL] father instance region must be specified for ReadOnly instance") + } + fatherRegion := d.Get("father_instance_region").(string) + mongodbService1.client.Region = fatherRegion + masterInfoMap["father_instance_id"] = d.Get("father_instance_id").(string) + masterInfo, has, err := mongodbService1.DescribeInstanceById(ctx, masterInfoMap["father_instance_id"]) + if err != nil { + return err + } + if !has { + return fmt.Errorf("[CRITAL] father instance can't be found for creating mongodb ReadOnly instance") + } + + masterInfoMap["machine_type"] = *masterInfo.MachineType + masterInfoMap["engine_version"] = *masterInfo.MongoVersion + + chargeType := d.Get("charge_type").(string) + + if chargeType == MONGODB_CHARGE_TYPE_POSTPAID { + _, ok := d.GetOk("prepaid_period") + _, ok1 := d.GetOk("auto_renew_flag") + if ok || ok1 { + return fmt.Errorf("prepaid_period and auto_renew_flag don't make sense for POSTPAID_BY_HOUR mongodb ReadOnly instance, please remove them from your template") + } + if err := mongodbCreateReadOnlyInstanceByUse(ctx, d, meta, masterInfoMap); err != nil { + return err + } + } else { + if err := mongodbCreateReadOnlyInstanceByMonth(ctx, d, meta, masterInfoMap); err != nil { + return err + } + } + + instanceId := d.Id() + + _, has, err = mongodbService.DescribeInstanceById(ctx, instanceId) + if err != nil { + return err + } + if !has { + return fmt.Errorf("[CRITAL]%s creating mongodb ReadOnly instance failed, instance doesn't exist", logId) + } + + // setting instance name + instanceName := d.Get("instance_name").(string) + err = mongodbService.ModifyInstanceName(ctx, instanceId, instanceName) + if err != nil { + return err + } + + _, has, err = mongodbService.DescribeInstanceById(ctx, instanceId) + if err != nil { + return err + } + if !has { + return fmt.Errorf("[CRITAL]%s creating mongodb instance failed, instance doesn't exist", logId) + } + + if tags := helper.GetTags(d, "tags"); len(tags) > 0 { + resourceName := tccommon.BuildTagResourceName("mongodb", "instance", region, instanceId) + if err := tagService.ModifyTags(ctx, resourceName, tags, nil); err != nil { + return err + } + } + + return resourceTencentCloudMongodbReadOnlyInstanceRead(d, meta) +} + +func resourceTencentCloudMongodbReadOnlyInstanceRead(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_mongodb_readonly_instance.read")() + defer tccommon.InconsistentCheck(d, meta)() + + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + + instanceId := d.Id() + + mongodbService := MongodbService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + instance, has, err := mongodbService.DescribeInstanceById(ctx, instanceId) + if err != nil { + return err + } + if !has { + d.SetId("") + return nil + } + + if nilFields := tccommon.CheckNil(instance, map[string]string{ + "InstanceName": "instance name", + "ProjectId": "project id", + "Zone": "available zone", + "VpcId": "vpc id", + "SubnetId": "subnet id", + "Status": "status", + "Vip": "vip", + "Vport": "vport", + "CreateTime": "create time", + "MongoVersion": "engine version", + "Memory": "memory", + "Volume": "volume", + "MachineType": "machine type", + "ReplicationSetNum": "shard quantity", + "SecondaryNum": "secondary number", + }); len(nilFields) > 0 { + return fmt.Errorf("mongodb %v are nil", nilFields) + } + + _ = d.Set("shard_quantity", instance.ReplicationSetNum) + _ = d.Set("nodes_per_shard", *instance.SecondaryNum+1) + _ = d.Set("instance_name", instance.InstanceName) + _ = d.Set("memory", *instance.Memory/1024) + _ = d.Set("volume", *instance.Volume/1024) + _ = d.Set("engine_version", instance.MongoVersion) + _ = d.Set("charge_type", MONGODB_CHARGE_TYPE[*instance.PayMode]) + if MONGODB_CHARGE_TYPE[*instance.PayMode] == MONGODB_CHARGE_TYPE_PREPAID { + _ = d.Set("auto_renew_flag", *instance.AutoRenewFlag) + } + + groups, err := mongodbService.DescribeSecurityGroup(ctx, instanceId) + if err != nil { + return err + } + groupIds := make([]string, 0) + for _, group := range groups { + groupIds = append(groupIds, *group.SecurityGroupId) + } + if len(groupIds) > 1 { + _ = d.Set("security_groups", groupIds) + } + _ = d.Set("machine_type", *instance.MachineType) + _ = d.Set("available_zone", instance.Zone) + _ = d.Set("vpc_id", instance.VpcId) + _ = d.Set("subnet_id", instance.SubnetId) + _ = d.Set("project_id", instance.ProjectId) + _ = d.Set("status", instance.Status) + _ = d.Set("vip", instance.Vip) + _ = d.Set("vport", instance.Vport) + _ = d.Set("create_time", instance.CreateTime) + _ = d.Set("mongos_cpu", instance.MongosCpuNum) + _ = d.Set("mongos_memory", *instance.MongosMemory/1024) + _ = d.Set("mongos_node_num", instance.MongosNodeNum) + + // info of master info + if instance.RelatedInstance != nil { + _ = d.Set("father_instance_id", instance.RelatedInstance.InstanceId) + _ = d.Set("father_instance_region", instance.RelatedInstance.Region) + } + + if len(instance.Tags) > 0 { + tags := make(map[string]string, len(instance.Tags)) + for _, tag := range instance.Tags { + if tag.TagKey == nil { + return errors.New("mongodb tag key is nil") + } + if tag.TagValue == nil { + return errors.New("mongodb tag value is nil") + } + if *tag.TagKey == "project" { + continue + } + + tags[*tag.TagKey] = *tag.TagValue + } + _ = d.Set("tags", tags) + } + + return nil +} + +func resourceTencentCloudMongodbReadOnlyInstanceUpdate(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_mongodb_readonly_instance.update")() + + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + + instanceId := d.Id() + + client := meta.(tccommon.ProviderMeta).GetAPIV3Conn() + mongodbService := MongodbService{client: client} + tagService := svctag.NewTagService(client) + region := client.Region + + d.Partial(true) + + if d.HasChange("memory") || d.HasChange("volume") { + memory := d.Get("memory").(int) + volume := d.Get("volume").(int) + dealId, err := mongodbService.UpgradeInstance(ctx, instanceId, memory, volume, nil) + if err != nil { + return err + } + if dealId == "" { + return fmt.Errorf("deal id is empty") + } + + errUpdate := resource.Retry(20*tccommon.ReadRetryTimeout, func() *resource.RetryError { + dealResponseParams, err := mongodbService.DescribeDBInstanceDeal(ctx, dealId) + if err != nil { + if sdkError, ok := err.(*sdkErrors.TencentCloudSDKError); ok { + if sdkError.Code == "InvalidParameter" && sdkError.Message == "deal resource not found." { + return resource.RetryableError(err) + } + } + return resource.NonRetryableError(err) + } + + if *dealResponseParams.Status != MONGODB_STATUS_DELIVERY_SUCCESS { + return resource.RetryableError(fmt.Errorf("mongodb status is not delivery success")) + } + return nil + }) + if errUpdate != nil { + return errUpdate + } + + } + + if d.HasChange("instance_name") { + instanceName := d.Get("instance_name").(string) + err := mongodbService.ModifyInstanceName(ctx, instanceId, instanceName) + if err != nil { + return err + } + + } + + if d.HasChange("project_id") { + projectId := d.Get("project_id").(int) + err := mongodbService.ModifyProjectId(ctx, instanceId, projectId) + if err != nil { + return err + } + + } + + if d.HasChange("tags") { + oldTags, newTags := d.GetChange("tags") + replaceTags, deleteTags := svctag.DiffTags(oldTags.(map[string]interface{}), newTags.(map[string]interface{})) + + resourceName := tccommon.BuildTagResourceName("mongodb", "instance", region, instanceId) + if err := tagService.ModifyTags(ctx, resourceName, replaceTags, deleteTags); err != nil { + return err + } + + } + + if d.HasChange("prepaid_period") { + return fmt.Errorf("setting of the field[prepaid_period] does not make sense after the initialization") + } + + if d.HasChange("auto_renew_flag") { + autoRenewFlag := d.Get("auto_renew_flag").(int) + period := d.Get("prepaid_period").(int) + err := mongodbService.ModifyAutoRenewFlag(ctx, instanceId, period, autoRenewFlag) + if err != nil { + return err + } + + } + + if d.HasChange("security_groups") { + securityGroups := d.Get("security_groups").(*schema.Set).List() + securityGroupIds := make([]*string, 0, len(securityGroups)) + for _, securityGroup := range securityGroups { + securityGroupIds = append(securityGroupIds, helper.String(securityGroup.(string))) + } + err := mongodbService.ModifySecurityGroups(ctx, instanceId, securityGroupIds) + if err != nil { + return err + } + } + + d.Partial(false) + + return resourceTencentCloudMongodbReadOnlyInstanceRead(d, meta) +} + +func resourceTencentCloudMongodbReadOnlyInstanceDelete(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("resource.tencentcloud_mongodb_readonly_instance.delete")() + + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + + instanceId := d.Id() + mongodbService := MongodbService{ + client: meta.(tccommon.ProviderMeta).GetAPIV3Conn(), + } + + instanceDetail, has, err := mongodbService.DescribeInstanceById(ctx, instanceId) + if err != nil { + return err + } + if !has { + d.SetId("") + return nil + } + if MONGODB_CHARGE_TYPE[*instanceDetail.PayMode] == MONGODB_CHARGE_TYPE_PREPAID { + return fmt.Errorf("PREPAID instances are not allowed to be deleted now, please isolate them on console") + } + + err = mongodbService.IsolateInstance(ctx, instanceId) + if err != nil { + return err + } + err = mongodbService.OfflineIsolatedDBInstance(ctx, instanceId, true) + if err != nil { + log.Printf("[CRITAL]%s mongodb %s fail, reason:%s", logId, "OfflineIsolatedDBInstance", err.Error()) + return err + } + //describe and check not exist + _, has, errRet := mongodbService.DescribeInstanceById(ctx, instanceId) + if errRet != nil { + return errRet + } + if !has { + return nil + } + return fmt.Errorf("[CRITAL]%s mongodb %s fail", logId, "OfflineIsolatedDBInstance") +} diff --git a/tencentcloud/services/mongodb/resource_tc_mongodb_readonly_instance.md b/tencentcloud/services/mongodb/resource_tc_mongodb_readonly_instance.md new file mode 100644 index 0000000000..5f7200ca83 --- /dev/null +++ b/tencentcloud/services/mongodb/resource_tc_mongodb_readonly_instance.md @@ -0,0 +1,54 @@ +Provide a resource to create a Readonly mongodb instance. + +Example Usage + +Replset readonly instance + +```hcl +resource "tencentcloud_mongodb_readonly_instance" "mongodb" { + instance_name = "tf-mongodb-readonly-test" + memory = 4 + volume = 100 + engine_version = "MONGO_44_WT" + machine_type = "HIO10G" + available_zone = "ap-guangzhou-3" + project_id = 0 + father_instance_id = "cmgo-xxxxxx" + father_instance_region = "ap-guangzhou" + vpc_id = "vpc-xxxxxx" + subnet_id = "subnet-xxxxxx" + security_groups = ["sg-xxxxxx"] + cluster_type = "REPLSET" +} +``` + +Shard readonly instance + +```hcl +resource "tencentcloud_mongodb_readonly_instance" "sharding_mongodb" { + instance_name = "tf-mongodb-readonly-shard" + memory = 4 + volume = 100 + engine_version = "MONGO_44_WT" + machine_type = "HIO10G" + available_zone = "ap-guangzhou-3" + project_id = 0 + father_instance_id = "cmgo-xxxxxx" + father_instance_region = "ap-guangzhou" + vpc_id = "vpc-xxxxxx" + subnet_id = "subnet-xxxxxx" + security_groups = ["sg-xxxxxx"] + cluster_type = "SHARD" + mongos_cpu = 1 + mongos_memory = 2 + mongos_node_num = 3 +} +``` + +Import + +Mongodb instance can be imported using the id, e.g. + +``` +$ terraform import tencentcloud_mongodb_instance.mongodb cmgo-xxxxxx +``` \ No newline at end of file diff --git a/tencentcloud/services/mongodb/resource_tc_mongodb_readonly_instance_test.go b/tencentcloud/services/mongodb/resource_tc_mongodb_readonly_instance_test.go new file mode 100644 index 0000000000..1ec075a0e0 --- /dev/null +++ b/tencentcloud/services/mongodb/resource_tc_mongodb_readonly_instance_test.go @@ -0,0 +1,156 @@ +package mongodb_test + +import ( + tcacctest "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/acctest" + + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccTencentCloudMongodbReadOnlyInstanceResource_replset(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + PreCheck: func() { tcacctest.AccPreCheck(t) }, + Providers: tcacctest.AccProviders, + Steps: []resource.TestStep{ + { + Config: testAccMongodbReplsetReadOnlyInstance, + Check: resource.ComposeTestCheckFunc( + testAccCheckMongodbInstanceExists("tencentcloud_mongodb_readonly_instance.mongodb"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.mongodb", "instance_name", "tf-mongodb-readonly-test"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.mongodb", "memory", "4"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.mongodb", "volume", "100"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.mongodb", "cluster_type", "REPLSET"), + ), + }, + { + ResourceName: "tencentcloud_mongodb_readonly_instance.mongodb", + ImportState: true, + ImportStateVerifyIgnore: []string{"security_groups", "auto_renew_flag", "password"}, + }, + }, + }) +} + +func TestAccTencentCloudMongodbReadOnlyInstanceResource_shard(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + PreCheck: func() { tcacctest.AccPreCheck(t) }, + Providers: tcacctest.AccProviders, + Steps: []resource.TestStep{ + { + Config: testAccMongodbShardingReadOnlyInstance, + Check: resource.ComposeTestCheckFunc( + testAccCheckMongodbInstanceExists("tencentcloud_mongodb_readonly_instance.sharding_mongodb"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.sharding_mongodb", "instance_name", "tf-mongodb-readonly-shard"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.sharding_mongodb", "memory", "4"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.sharding_mongodb", "volume", "100"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.sharding_mongodb", "cluster_type", "SHARD"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.sharding_mongodb", "mongos_cpu", "1"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.sharding_mongodb", "mongos_memory", "2"), + resource.TestCheckResourceAttr("tencentcloud_mongodb_readonly_instance.sharding_mongodb", "mongos_node_num", "3"), + ), + }, + { + ResourceName: "tencentcloud_mongodb_readonly_instance.sharding_mongodb", + ImportState: true, + ImportStateVerifyIgnore: []string{"security_groups", "auto_renew_flag", "password"}, + }, + }, + }) +} + +const testAccMongodbReplsetReadOnlyInstance = tcacctest.DefaultMongoDBSpec + ` +resource "tencentcloud_vpc" "vpc" { + name = "mongodb-sharding-vpc" + cidr_block = "10.0.0.0/16" +} + +resource "tencentcloud_subnet" "subnet" { + vpc_id = tencentcloud_vpc.vpc.id + name = "mongodb-sharding-subnet" + cidr_block = "10.0.0.0/16" + availability_zone = "ap-guangzhou-3" +} +resource "tencentcloud_mongodb_instance" "mongodb" { + instance_name = "tf-mongodb-test" + memory = 4 + volume = 100 + engine_version = local.engine_version + machine_type = local.machine_type + available_zone = "ap-guangzhou-3" + project_id = 0 + password = "test1234" + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id +} + +resource "tencentcloud_mongodb_readonly_instance" "mongodb" { + instance_name = "tf-mongodb-readonly-test" + memory = 4 + volume = 100 + engine_version = local.engine_version + machine_type = local.machine_type + available_zone = "ap-guangzhou-3" + project_id = 0 + father_instance_id = tencentcloud_mongodb_instance.mongodb.id + father_instance_region = "ap-guangzhou" + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id + security_groups = [local.security_group_id] + cluster_type = "REPLSET" +} +` + +const testAccMongodbShardingReadOnlyInstance = tcacctest.DefaultMongoDBSpec + ` +resource "tencentcloud_vpc" "vpc" { + name = "mongodb-sharding-vpc" + cidr_block = "10.0.0.0/16" + } + +resource "tencentcloud_subnet" "subnet" { + vpc_id = tencentcloud_vpc.vpc.id + name = "mongodb-sharding-subnet" + cidr_block = "10.0.0.0/16" + availability_zone = "ap-guangzhou-3" +} + +resource "tencentcloud_mongodb_sharding_instance" "mongodb" { + instance_name = "tf-mongodb-sharding" + shard_quantity = 2 + nodes_per_shard = 3 + memory = local.sharding_memory + volume = local.sharding_volume + engine_version = local.sharding_engine_version + machine_type = local.sharding_machine_type + security_groups = [local.security_group_id] + available_zone = "ap-guangzhou-3" + project_id = 0 + password = "test1234" + mongos_cpu = 1 + mongos_memory = 2 + mongos_node_num = 3 + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id +} + +resource "tencentcloud_mongodb_readonly_instance" "sharding_mongodb" { + instance_name = "tf-mongodb-readonly-shard" + memory = 4 + volume = 100 + engine_version = local.engine_version + machine_type = local.machine_type + available_zone = "ap-guangzhou-3" + project_id = 0 + father_instance_id = tencentcloud_mongodb_sharding_instance.mongodb.id + father_instance_region = "ap-guangzhou" + vpc_id = tencentcloud_vpc.vpc.id + subnet_id = tencentcloud_subnet.subnet.id + security_groups = [local.security_group_id] + cluster_type = "SHARD" + mongos_cpu = 1 + mongos_memory = 2 + mongos_node_num = 3 +} +` diff --git a/website/docs/r/mongodb_readonly_instance.html.markdown b/website/docs/r/mongodb_readonly_instance.html.markdown new file mode 100644 index 0000000000..d1646b65cb --- /dev/null +++ b/website/docs/r/mongodb_readonly_instance.html.markdown @@ -0,0 +1,105 @@ +--- +subcategory: "TencentDB for MongoDB(mongodb)" +layout: "tencentcloud" +page_title: "TencentCloud: tencentcloud_mongodb_readonly_instance" +sidebar_current: "docs-tencentcloud-resource-mongodb_readonly_instance" +description: |- + Provide a resource to create a Readonly mongodb instance. +--- + +# tencentcloud_mongodb_readonly_instance + +Provide a resource to create a Readonly mongodb instance. + +## Example Usage + +### Replset readonly instance + +```hcl +resource "tencentcloud_mongodb_readonly_instance" "mongodb" { + instance_name = "tf-mongodb-readonly-test" + memory = 4 + volume = 100 + engine_version = "MONGO_44_WT" + machine_type = "HIO10G" + available_zone = "ap-guangzhou-3" + project_id = 0 + father_instance_id = "cmgo-xxxxxx" + father_instance_region = "ap-guangzhou" + vpc_id = "vpc-xxxxxx" + subnet_id = "subnet-xxxxxx" + security_groups = ["sg-xxxxxx"] + cluster_type = "REPLSET" +} +``` + +### Shard readonly instance + +```hcl +resource "tencentcloud_mongodb_readonly_instance" "sharding_mongodb" { + instance_name = "tf-mongodb-readonly-shard" + memory = 4 + volume = 100 + engine_version = "MONGO_44_WT" + machine_type = "HIO10G" + available_zone = "ap-guangzhou-3" + project_id = 0 + father_instance_id = "cmgo-xxxxxx" + father_instance_region = "ap-guangzhou" + vpc_id = "vpc-xxxxxx" + subnet_id = "subnet-xxxxxx" + security_groups = ["sg-xxxxxx"] + cluster_type = "SHARD" + mongos_cpu = 1 + mongos_memory = 2 + mongos_node_num = 3 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `available_zone` - (Required, String, ForceNew) The available zone of the Mongodb. +* `cluster_type` - (Required, String, ForceNew) Instance schema type. - REPLSET: Replset cluster; - SHARD: Shard cluster. +* `engine_version` - (Required, String, ForceNew) Version of the Mongodb, and available values include `MONGO_36_WT` (MongoDB 3.6 WiredTiger Edition), `MONGO_40_WT` (MongoDB 4.0 WiredTiger Edition) and `MONGO_42_WT` (MongoDB 4.2 WiredTiger Edition). NOTE: `MONGO_3_WT` (MongoDB 3.2 WiredTiger Edition) and `MONGO_3_ROCKS` (MongoDB 3.2 RocksDB Edition) will deprecated. +* `father_instance_id` - (Required, String, ForceNew) Indicates the main instance ID of readonly instances. +* `father_instance_region` - (Required, String, ForceNew) Indicates the region of main instance. +* `instance_name` - (Required, String) Name of the Mongodb instance. +* `machine_type` - (Required, String, ForceNew) Type of Mongodb instance, and available values include `HIO`(or `GIO` which will be deprecated, represents high IO) and `HIO10G`(or `TGIO` which will be deprecated, represents 10-gigabit high IO). +* `memory` - (Required, Int) Memory size. The minimum value is 2, and unit is GB. Memory and volume must be upgraded or degraded simultaneously. +* `volume` - (Required, Int) Disk size. The minimum value is 25, and unit is GB. Memory and volume must be upgraded or degraded simultaneously. +* `auto_renew_flag` - (Optional, Int) Auto renew flag. Valid values are `0`(NOTIFY_AND_MANUAL_RENEW), `1`(NOTIFY_AND_AUTO_RENEW) and `2`(DISABLE_NOTIFY_AND_MANUAL_RENEW). Default value is `0`. Note: only works for PREPAID instance. Only supports`0` and `1` for creation. +* `charge_type` - (Optional, String, ForceNew) The charge type of instance. Valid values are `PREPAID` and `POSTPAID_BY_HOUR`. Default value is `POSTPAID_BY_HOUR`. Note: TencentCloud International only supports `POSTPAID_BY_HOUR`. Caution that update operation on this field will delete old instances and create new one with new charge type. +* `mongos_cpu` - (Optional, Int) Number of mongos cpu. +* `mongos_memory` - (Optional, Int) Mongos memory size in GB. +* `mongos_node_num` - (Optional, Int) Number of mongos. +* `node_num` - (Optional, Int) The number of nodes in each replica set. Default value: 3. +* `nodes_per_shard` - (Optional, Int, ForceNew) Number of nodes per shard, at least 3(one master and two slaves). +* `prepaid_period` - (Optional, Int) The tenancy (time unit is month) of the prepaid instance. Valid values are 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 24, 36. NOTE: it only works when charge_type is set to `PREPAID`. +* `project_id` - (Optional, Int) ID of the project which the instance belongs. +* `security_groups` - (Optional, Set: [`String`]) ID of the security group. +* `shard_quantity` - (Optional, Int, ForceNew) Number of sharding. +* `subnet_id` - (Optional, String, ForceNew) ID of the subnet within this VPC. The value is required if `vpc_id` is set. +* `tags` - (Optional, Map) The tags of the Mongodb. Key name `project` is system reserved and can't be used. +* `vpc_id` - (Optional, String, ForceNew) ID of the VPC. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - ID of the resource. +* `create_time` - Creation time of the Mongodb instance. +* `status` - Status of the Mongodb instance, and available values include pending initialization(expressed with 0), processing(expressed with 1), running(expressed with 2) and expired(expressed with -2). +* `vip` - IP of the Mongodb instance. +* `vport` - IP port of the Mongodb instance. + + +## Import + +Mongodb instance can be imported using the id, e.g. + +``` +$ terraform import tencentcloud_mongodb_instance.mongodb cmgo-xxxxxx +``` + diff --git a/website/tencentcloud.erb b/website/tencentcloud.erb index 0911685033..9b8dc2734d 100644 --- a/website/tencentcloud.erb +++ b/website/tencentcloud.erb @@ -5763,6 +5763,9 @@
  • tencentcloud_mongodb_instance_transparent_data_encryption
  • +
  • + tencentcloud_mongodb_readonly_instance +
  • tencentcloud_mongodb_sharding_instance