alibabacloudstack/resource_apsarastack_mongodb_shardinginstance.go (523 lines of code) (raw):
package alibabacloudstack
import (
"strconv"
"strings"
"time"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/services/dds"
"github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/connectivity"
"github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/errmsgs"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func resourceAlibabacloudStackMongoDBShardingInstance() *schema.Resource {
resource := &schema.Resource{
Schema: map[string]*schema.Schema{
"engine_version": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
},
"storage_engine": {
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{"WiredTiger", "RocksDB"}, false),
Optional: true,
Computed: true,
ForceNew: true,
},
"instance_charge_type": {
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{string(PrePaid), string(PostPaid)}, false),
Optional: true,
ForceNew: true,
Computed: true,
},
"period": {
Type: schema.TypeInt,
ValidateFunc: validation.IntInSlice([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36}),
Optional: true,
Computed: true,
DiffSuppressFunc: PostPaidDiffSuppressFunc,
},
"zone_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"vswitch_id": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
},
"name": {
Type: schema.TypeString,
Optional: true,
Computed:true,
ValidateFunc: validation.StringLenBetween(2, 256),
Deprecated: "Field 'name' is deprecated and will be removed in a future release. Please use new field 'db_instance_description' instead.",
ConflictsWith: []string{"db_instance_description"},
},
"db_instance_description": {
Type: schema.TypeString,
Optional: true,
Computed:true,
ValidateFunc: validation.StringLenBetween(2, 256),
ConflictsWith: []string{"name"},
},
"security_ip_list": {
Type: schema.TypeSet,
Elem: &schema.Schema{Type: schema.TypeString},
Computed: true,
Optional: true,
},
"security_group_id": {
Type: schema.TypeString,
Computed: true,
Optional: true,
},
"account_password": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
},
"kms_encrypted_password": {
Type: schema.TypeString,
Optional: true,
DiffSuppressFunc: kmsDiffSuppressFunc,
},
"kms_encryption_context": {
Type: schema.TypeMap,
Optional: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return d.Get("kms_encrypted_password").(string) == ""
},
Elem: schema.TypeString,
},
"tde_status": {
Type: schema.TypeString,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return old == "" && new == "disabled" || old == "enabled"
},
ValidateFunc: validation.StringInSlice([]string{"enabled", "disabled"}, false),
Optional: true,
},
"backup_period": {
Type: schema.TypeSet,
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
Computed: true,
Deprecated: "Field 'backup_period' is deprecated and will be removed in a future release. " +
"Please use new field 'preferred_backup_period' instead.",
ConflictsWith: []string{"preferred_backup_period"},
},
"preferred_backup_period": {
Type: schema.TypeSet,
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
Computed: true,
ConflictsWith: []string{"backup_period"},
},
"backup_time": {
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(BACKUP_TIME, false),
Optional: true,
Computed: true,
Deprecated: "Field 'backup_time' is deprecated and will be removed in a future release. " +
"Please use new field 'preferred_backup_time' instead.",
ConflictsWith: []string{"preferred_backup_time"},
},
"preferred_backup_time": {
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(BACKUP_TIME, false),
Optional: true,
Computed: true,
ConflictsWith: []string{"backup_time"},
},
//Computed
"retention_period": {
Type: schema.TypeInt,
Computed: true,
},
"shard_list": {
Type: schema.TypeList,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"node_class": {
Type: schema.TypeString,
Required: true,
},
"node_storage": {
Type: schema.TypeInt,
Required: true,
},
//Computed
"node_id": {
Type: schema.TypeString,
Computed: true,
},
},
},
Required: true,
MinItems: 2,
MaxItems: 32,
},
"mongo_list": {
Type: schema.TypeList,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"node_class": {
Type: schema.TypeString,
Required: true,
},
//Computed
"node_id": {
Type: schema.TypeString,
Computed: true,
},
"connect_string": {
Type: schema.TypeString,
Computed: true,
},
"port": {
Type: schema.TypeInt,
Computed: true,
},
},
},
Required: true,
MinItems: 2,
MaxItems: 32,
},
},
}
setResourceFunc(resource, resourceAlibabacloudStackMongoDBShardingInstanceCreate,
resourceAlibabacloudStackMongoDBShardingInstanceRead, resourceAlibabacloudStackMongoDBShardingInstanceUpdate, resourceAlibabacloudStackMongoDBShardingInstanceDelete)
return resource
}
func buildMongoDBShardingCreateRequest(d *schema.ResourceData, meta interface{}) (*dds.CreateShardingDBInstanceRequest, error) {
client := meta.(*connectivity.AlibabacloudStackClient)
request := dds.CreateCreateShardingDBInstanceRequest()
client.InitRpcRequest(*request.RpcRequest)
request.EngineVersion = Trim(d.Get("engine_version").(string))
request.Engine = "MongoDB"
request.DBInstanceDescription = connectivity.GetResourceData(d, "db_instance_description", "name").(string)
request.AccountPassword = d.Get("account_password").(string)
if request.AccountPassword == "" {
if v := d.Get("kms_encrypted_password").(string); v != "" {
kmsService := KmsService{client}
decryptResp, err := kmsService.Decrypt(v, d.Get("kms_encryption_context").(map[string]interface{}))
if err != nil {
return request, errmsgs.WrapError(err)
}
request.AccountPassword = decryptResp.Plaintext
}
}
request.ZoneId = d.Get("zone_id").(string)
shardList, ok := d.GetOk("shard_list")
if ok {
replicaSets := []dds.CreateShardingDBInstanceReplicaSet{}
for _, rew := range shardList.([]interface{}) {
item := rew.(map[string]interface{})
class := item["node_class"].(string)
nodeStorage := item["node_storage"].(int)
var csr dds.CreateShardingDBInstanceReplicaSet
csr.Class = class
csr.Storage = strconv.Itoa(nodeStorage)
replicaSets = append(replicaSets, csr)
}
request.ReplicaSet = &replicaSets
}
mongoList, ok := d.GetOk("mongo_list")
if ok {
mongos := []dds.CreateShardingDBInstanceMongos{}
for _, rew := range mongoList.([]interface{}) {
item := rew.(map[string]interface{})
class := item["node_class"].(string)
mongos = append(mongos, dds.CreateShardingDBInstanceMongos{class})
}
request.Mongos = &mongos
}
request.ConfigServer = &[]dds.CreateShardingDBInstanceConfigServer{{"20", "dds.cs.mid"}}
request.NetworkType = string(Classic)
vswitchId := Trim(d.Get("vswitch_id").(string))
if vswitchId != "" {
// check vswitchId in zone
vpcService := VpcService{client}
vsw, err := vpcService.DescribeVSwitch(vswitchId)
if err != nil {
return nil, errmsgs.WrapError(err)
}
if request.ZoneId == "" {
request.ZoneId = vsw.ZoneId
} else if strings.Contains(request.ZoneId, MULTI_IZ_SYMBOL) {
zonestr := strings.Split(strings.SplitAfter(request.ZoneId, "(")[1], ")")[0]
if !strings.Contains(zonestr, string([]byte(vsw.ZoneId)[len(vsw.ZoneId)-1])) {
return nil, errmsgs.WrapError(errmsgs.Error("The specified vswitch " + vsw.VSwitchId + " isn't in multi the zone " + request.ZoneId))
}
} else if request.ZoneId != vsw.ZoneId {
return nil, errmsgs.WrapError(errmsgs.Error("The specified vswitch " + vsw.VSwitchId + " isn't in the zone " + request.ZoneId))
}
request.VSwitchId = vswitchId
request.NetworkType = strings.ToUpper(string(Vpc))
request.VpcId = vsw.VpcId
}
request.ChargeType = d.Get("instance_charge_type").(string)
period, ok := d.GetOk("period")
if ok && PayType(request.ChargeType) == PrePaid {
request.Period = requests.NewInteger(period.(int))
}
request.SecurityIPList = LOCAL_HOST_IP
if len(d.Get("security_ip_list").(*schema.Set).List()) > 0 {
request.SecurityIPList = strings.Join(expandStringList(d.Get("security_ip_list").(*schema.Set).List()), COMMA_SEPARATED)
}
request.ClientToken = buildClientToken(request.GetActionName())
return request, nil
}
func resourceAlibabacloudStackMongoDBShardingInstanceCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*connectivity.AlibabacloudStackClient)
ddsService := MongoDBService{client}
request, err := buildMongoDBShardingCreateRequest(d, meta)
if err != nil {
return errmsgs.WrapError(err)
}
raw, err := client.WithDdsClient(func(client *dds.Client) (interface{}, error) {
return client.CreateShardingDBInstance(request)
})
if err != nil {
errmsg := ""
if raw != nil {
response, ok := raw.(*dds.CreateShardingDBInstanceResponse)
if ok {
errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse)
}
}
return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, "alibabacloudstack_mongodb_sharding_instance", request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg)
}
response, _ := raw.(*dds.CreateShardingDBInstanceResponse)
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
d.SetId(response.DBInstanceId)
if err := ddsService.WaitForMongoDBInstance(d.Id(), Running, DefaultLongTimeout); err != nil {
return errmsgs.WrapError(err)
}
return nil
}
func resourceAlibabacloudStackMongoDBShardingInstanceRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*connectivity.AlibabacloudStackClient)
ddsService := MongoDBService{client}
instance, err := ddsService.DescribeMongoDBInstance(d.Id())
if err != nil {
if errmsgs.NotFoundError(err) {
d.SetId("")
return nil
}
return errmsgs.WrapError(err)
}
backupPolicy, err := ddsService.DescribeMongoDBBackupPolicy(d.Id())
if err != nil {
return errmsgs.WrapError(err)
}
connectivity.SetResourceData(d, backupPolicy.PreferredBackupTime, "preferred_backup_time", "backup_time")
connectivity.SetResourceData(d, backupPolicy.PreferredBackupPeriod, "preferred_backup_period", "backup_period")
retention_period, _ := strconv.Atoi(backupPolicy.BackupRetentionPeriod)
d.Set("retention_period", retention_period)
connectivity.SetResourceData(d, instance.DBInstanceDescription, "db_instance_description", "name")
d.Set("engine_version", instance.EngineVersion)
d.Set("storage_engine", instance.StorageEngine)
d.Set("zone_id", instance.ZoneId)
d.Set("instance_charge_type", instance.ChargeType)
if instance.ChargeType == "PrePaid" {
period, err := computePeriodByUnit(instance.CreationTime, instance.ExpireTime, d.Get("period").(int), "Month")
if err != nil {
return errmsgs.WrapError(err)
}
d.Set("period", period)
}
d.Set("vswitch_id", instance.VSwitchId)
mongosList := []map[string]interface{}{}
for _, item := range instance.MongosList.MongosAttribute {
mongo := map[string]interface{}{
"node_class": item.NodeClass,
"node_id": item.NodeId,
"port": item.Port,
"connect_string": item.ConnectSting,
}
mongosList = append(mongosList, mongo)
}
err = d.Set("mongo_list", mongosList)
if err != nil {
return errmsgs.WrapError(err)
}
shardList := []map[string]interface{}{}
for _, item := range instance.ShardList.ShardAttribute {
shard := map[string]interface{}{
"node_id": item.NodeId,
"node_storage": item.NodeStorage,
"node_class": item.NodeClass,
}
shardList = append(shardList, shard)
}
err = d.Set("shard_list", shardList)
if err != nil {
return errmsgs.WrapError(err)
}
tdeInfo, err := ddsService.DescribeMongoDBTDEInfo(d.Id())
if err != nil {
return errmsgs.WrapError(err)
}
if !(d.Get("tde_status") == "" && tdeInfo.TDEStatus == "disabled") {
d.Set("tde_status", tdeInfo.TDEStatus)
}
ips, err := ddsService.DescribeMongoDBSecurityIps(d.Id())
if err != nil {
return errmsgs.WrapError(err)
}
d.Set("security_ip_list", ips)
// 混合云不支持
// groupIp, err := ddsService.DescribeMongoDBSecurityGroupId(d.Id())
// if err != nil {
// return errmsgs.WrapError(err)
// }
// if len(groupIp.Items.RdsEcsSecurityGroupRel) > 0 {
// d.Set("security_group_id", groupIp.Items.RdsEcsSecurityRel[0].SecurityGroupId)
// }
return nil
}
func resourceAlibabacloudStackMongoDBShardingInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*connectivity.AlibabacloudStackClient)
ddsService := MongoDBService{client}
d.Partial(true)
if d.HasChanges("preferred_backup_time", "preferred_backup_period", "backup_time", "backup_period") {
if err := ddsService.MotifyMongoDBBackupPolicy(d); err != nil {
return errmsgs.WrapError(err)
}
//d.SetPartial("preferred_backup_time")
//d.SetPartial("preferred_backup_period")
}
if d.HasChange("tde_status") {
request := dds.CreateModifyDBInstanceTDERequest()
client.InitRpcRequest(*request.RpcRequest)
request.DBInstanceId = d.Id()
request.TDEStatus = d.Get("tde_status").(string)
raw, err := client.WithDdsClient(func(client *dds.Client) (interface{}, error) {
return client.ModifyDBInstanceTDE(request)
})
if err != nil {
errmsg := ""
if raw != nil {
response, ok := raw.(*dds.ModifyDBInstanceTDEResponse)
if ok {
errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse)
}
}
return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
//d.SetPartial("tde_status")
}
if d.HasChange("security_group_id") {
request := dds.CreateModifySecurityGroupConfigurationRequest()
client.InitRpcRequest(*request.RpcRequest)
request.DBInstanceId = d.Id()
request.SecurityGroupId = d.Get("security_group_id").(string)
raw, err := client.WithDdsClient(func(client *dds.Client) (interface{}, error) {
return client.ModifySecurityGroupConfiguration(request)
})
if err != nil {
errmsg := ""
if raw != nil {
response, ok := raw.(*dds.ModifySecurityGroupConfigurationResponse)
if ok {
errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse)
}
}
return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
//d.SetPartial("security_group_id")
}
if d.IsNewResource() {
d.Partial(false)
return nil
}
if d.HasChange("shard_list") {
state, diff := d.GetChange("shard_list")
err := ddsService.ModifyMongodbShardingInstanceNode(d.Id(), MongoDBShardingNodeShard, state.([]interface{}), diff.([]interface{}))
if err != nil {
return errmsgs.WrapError(err)
}
//d.SetPartial("shard_list")
}
if d.HasChange("mongo_list") {
state, diff := d.GetChange("mongo_list")
err := ddsService.ModifyMongodbShardingInstanceNode(d.Id(), MongoDBShardingNodeMongos, state.([]interface{}), diff.([]interface{}))
if err != nil {
return errmsgs.WrapError(err)
}
//d.SetPartial("mongo_list")
}
if d.HasChanges("db_instance_description", "name"){
request := dds.CreateModifyDBInstanceDescriptionRequest()
client.InitRpcRequest(*request.RpcRequest)
request.DBInstanceId = d.Id()
request.DBInstanceDescription = connectivity.GetResourceData(d, "db_instance_description", "name").(string)
raw, err := client.WithDdsClient(func(ddsClient *dds.Client) (interface{}, error) {
return ddsClient.ModifyDBInstanceDescription(request)
})
if err != nil {
errmsg := ""
if raw != nil {
response, ok := raw.(*dds.ModifyDBInstanceDescriptionResponse)
if ok {
errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse)
}
}
return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg)
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
//d.SetPartial("db_instance_description")
}
if d.HasChanges("account_password", "kms_encrypted_password") {
var accountPassword string
if accountPassword = d.Get("account_password").(string); accountPassword != "" {
//d.SetPartial("account_password")
} else if kmsPassword := d.Get("kms_encrypted_password").(string); kmsPassword != "" {
kmsService := KmsService{meta.(*connectivity.AlibabacloudStackClient)}
decryptResp, err := kmsService.Decrypt(kmsPassword, d.Get("kms_encryption_context").(map[string]interface{}))
if err != nil {
return errmsgs.WrapError(err)
}
accountPassword = decryptResp.Plaintext
//d.SetPartial("kms_encrypted_password")
//d.SetPartial("kms_encryption_context")
}
err := ddsService.ResetAccountPassword(d, accountPassword)
if err != nil {
return errmsgs.WrapError(err)
}
//d.SetPartial("account_password")
}
if d.HasChange("security_ip_list") {
ipList := expandStringList(d.Get("security_ip_list").(*schema.Set).List())
ipstr := strings.Join(ipList[:], COMMA_SEPARATED)
// default disable connect from outside
if ipstr == "" {
ipstr = LOCAL_HOST_IP
}
if err := ddsService.ModifyMongoDBSecurityIps(d.Id(), ipstr); err != nil {
return errmsgs.WrapError(err)
}
//d.SetPartial("security_ip_list")
}
d.Partial(false)
return nil
}
func resourceAlibabacloudStackMongoDBShardingInstanceDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*connectivity.AlibabacloudStackClient)
ddsService := MongoDBService{client}
request := dds.CreateDeleteDBInstanceRequest()
client.InitRpcRequest(*request.RpcRequest)
request.DBInstanceId = d.Id()
err := resource.Retry(10*5*time.Minute, func() *resource.RetryError {
raw, err := client.WithDdsClient(func(ddsClient *dds.Client) (interface{}, error) {
return ddsClient.DeleteDBInstance(request)
})
if err != nil {
if errmsgs.IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) {
return resource.NonRetryableError(err)
}
errmsg := ""
if raw != nil {
response, ok := raw.(*dds.DeleteDBInstanceResponse)
if ok {
errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse)
}
}
return resource.RetryableError(errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg))
}
addDebug(request.GetActionName(), raw, request.RpcRequest, request)
return nil
})
if err != nil {
if errmsgs.IsExpectedErrors(err, []string{"InvalidDBInstanceId.NotFound"}) {
return nil
}
return errmsgs.WrapErrorf(err, errmsgs.DefaultErrorMsg, d.Id(), request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR)
}
return errmsgs.WrapError(ddsService.WaitForMongoDBInstance(d.Id(), Deleted, DefaultTimeout))
}