Skip to content

Commit

Permalink
Merge pull request #176 from volcengine/Feat/redis
Browse files Browse the repository at this point in the history
Feat/redis
  • Loading branch information
msq177 authored Nov 12, 2024
2 parents a248703 + f308e42 commit d0df8e8
Show file tree
Hide file tree
Showing 8 changed files with 544 additions and 83 deletions.
2 changes: 1 addition & 1 deletion common/common_volcengine_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package common

const (
TerraformProviderName = "terraform-provider-volcengine"
TerraformProviderVersion = "0.0.152"
TerraformProviderVersion = "0.0.153"
)
20 changes: 17 additions & 3 deletions example/redisInstance/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ resource "volcengine_subnet" "foo" {


resource "volcengine_redis_instance" "foo" {
zone_ids = [data.volcengine_zones.foo.zones[0].id]
instance_name = "tf-test"
instance_name = "tf-test2"
sharded_cluster = 1
password = "1qaz!QAZ12"
node_number = 2
node_number = 4
shard_capacity = 1024
shard_number = 2
engine_version = "5.0"
Expand Down Expand Up @@ -53,4 +52,19 @@ resource "volcengine_redis_instance" "foo" {

create_backup = false
apply_immediately = true

multi_az = "enabled"
configure_nodes {
az = "cn-guilin-a"
}
configure_nodes {
az = "cn-guilin-b"
}
configure_nodes {
az = "cn-guilin-c"
}
configure_nodes {
az = "cn-guilin-b"
}
#additional_bandwidth = 12
}
65 changes: 65 additions & 0 deletions volcengine/redis/instance/common_volcengine_redis_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ var tagsHash = func(v interface{}) int {
return hashcode.String(buf.String())
}

var configNodesHash = 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["az"], m["az"]))
return hashcode.String(buf.String())
}

func redisInstanceImportDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
// 不启用分片集群时,忽略 shard_number 的修改
if k == "shard_number" {
Expand All @@ -51,6 +63,9 @@ func redisInstanceImportDiffSuppress(k, old, new string, d *schema.ResourceData)

// 只在修改实例规格时需要这些参数,其它情况均忽略修改
if k == "create_backup" || k == "apply_immediately" {
if d.HasChanges("configure_nodes", "multi_az", "node_number") {
return false
}
if d.HasChanges("node_number", "shard_number", "shard_capacity") {
oldNum, _ := d.GetChange("shard_number")
if oldNum.(int) == 1 {
Expand All @@ -62,3 +77,53 @@ func redisInstanceImportDiffSuppress(k, old, new string, d *schema.ResourceData)

return false
}

func abs(num int) int {
if num < 0 {
return -num
}
return num
}

func compareMaps(oldArr, newArr []interface{}) (added, removed []map[string]interface{}) {
oldCount := make(map[string]int)
newCount := make(map[string]int)

// 统计 oldArr 中每个 "az" 值的出现次数
for _, i := range oldArr {
item := i.(map[string]interface{})
if azValue, ok := item["az"].(string); ok {
oldCount[azValue]++
}
}

// 统计 newArr 中每个 "az" 值的出现次数
for _, i := range newArr {
item := i.(map[string]interface{})
if azValue, ok := item["az"].(string); ok {
newCount[azValue]++
}
}

// 查找新增的元素
for azValue, newCountValue := range newCount {
if oldCountValue, exists := oldCount[azValue]; !exists || newCountValue > oldCountValue {
// 如果新的计数超过旧的计数,表示新增
for i := 0; i < newCountValue-oldCountValue; i++ {
added = append(added, map[string]interface{}{"az": azValue})
}
}
}

// 查找移除的元素
for azValue, oldCountValue := range oldCount {
if newCountValue, exists := newCount[azValue]; !exists || oldCountValue > newCountValue {
// 如果旧的计数超过新的计数,表示移除
for i := 0; i < oldCountValue-newCountValue; i++ {
removed = append(removed, map[string]interface{}{"az": azValue})
}
}
}

return added, removed
}
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,42 @@ func DataSourceVolcengineRedisDbInstances() *schema.Resource {
Type: schema.TypeString,
},
},
"multi_az": {
Type: schema.TypeString,
Computed: true,
Description: "Set the availability zone deployment scheme for the instance. " +
"The value range is as follows: \n" +
"disabled: Single availability zone deployment scheme.\n " +
"enabled: Multi-availability zone deployment scheme.\n " +
"Description:\n When the newly created instance is a single-node instance" +
" (that is, when the value of NodeNumber is 1), only the single availability zone deployment scheme is allowed. " +
"At this time, the value of MultiAZ must be disabled.",
},
"configure_nodes": {
Type: schema.TypeList,
Computed: true,
Description: "Set the list of available zones to which the node belongs.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"az": {
Type: schema.TypeString,
Computed: true,
Description: "Set the availability zone to which the node belongs. " +
"The number of nodes of an instance (i.e., NodeNumber) and the availability zone deployment scheme (i.e., the value of the MultiAZ parameter) will affect the filling of the current parameter." +
" Among them:\n When a new instance is a single-node instance (i.e., the value of NodeNumber is 1), " +
"only a single availability zone deployment scheme is allowed (i.e., the value of MultiAZ must be disabled). " +
"At this time, only one availability zone needs to be passed in AZ, " +
"and all nodes in the instance will be deployed in this availability zone. " +
"When creating a new instance as a primary-standby instance (that is, when the value of NodeNumber is greater than or equal to 2), " +
"the number of availability zones passed in must be equal to the number of nodes in a single shard (that is, the value of the NodeNumber parameter), " +
"and the value of AZ must comply with the multi-availability zone deployment scheme rules. " +
"The specific rules are as follows: If the primary-standby instance selects the multi-availability zone deployment scheme (that is, the value of MultiAZ is enabled), " +
"then at least two different availability zone IDs must be passed in in AZ, and the first availability zone is the availability zone where the primary node is located." +
" If the primary and standby instances choose a single availability zone deployment scheme (that is, the value of MultiAZ is disabled), then the availability zones passed in for each node must be the same.",
},
},
},
},
},
},
},
Expand Down
156 changes: 107 additions & 49 deletions volcengine/redis/instance/resource_volcengine_redis_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"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"
)

Expand All @@ -16,7 +15,7 @@ redis instance can be imported using the id, e.g.
```
$ terraform import volcengine_redis_instance.default redis-n769ewmjjqyqh5dv
```
Adding or removing nodes and migrating availability zones for multiple AZ instances are not supported to be orchestrated simultaneously, but it is possible for single AZ instances.
*/

func ResourceVolcengineRedisDbInstance() *schema.Resource {
Expand All @@ -36,9 +35,12 @@ func ResourceVolcengineRedisDbInstance() *schema.Resource {
Schema: map[string]*schema.Schema{
"zone_ids": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
Optional: true,
Deprecated: "This field has been deprecated after version-0.0.152. Please use multi_az and configure_nodes to specify the availability zone.",
Description: "The list of zone IDs of instance. When creating a single node instance, only one zone id can be specified.",
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return true
},
Elem: &schema.Schema{
Type: schema.TypeString,
},
Expand All @@ -54,29 +56,14 @@ func ResourceVolcengineRedisDbInstance() *schema.Resource {
Description: "The name of the redis instance.",
},
"sharded_cluster": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
ValidateFunc: validation.IntInSlice([]int{0, 1}),
Description: "Whether enable sharded cluster for the current redis instance. Valid values: 0, 1. 0 means disable, 1 means enable.",
},
"password": {
Type: schema.TypeString,
Type: schema.TypeInt,
Required: true,
Sensitive: true,
Description: "The account password. When importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields.",
},
"node_number": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(1, 6),
Description: "The number of nodes in each shard, the valid value range is `1-6`. When the value is 1, it means creating a single node instance, and this field can not be modified. When the value is greater than 1, it means creating a primary and secondary instance, and this field can be modified.",
Description: "Whether enable sharded cluster for the current redis instance. Valid values: 0, 1. 0 means disable, 1 means enable.",
},
"shard_number": {
Type: schema.TypeInt,
Optional: true,
Computed: true,
ValidateFunc: validation.IntBetween(2, 256),
DiffSuppressFunc: redisInstanceImportDiffSuppress,
Description: "The number of shards in redis instance, the valid value range is `2-256`. This field is valid and required when the value of `ShardedCluster` is 1.",
},
Expand All @@ -85,25 +72,100 @@ func ResourceVolcengineRedisDbInstance() *schema.Resource {
Required: true,
Description: "The memory capacity of each shard, unit is MiB. The valid value range is as fallows: When the value of `ShardedCluster` is 0: 256, 1024, 2048, 4096, 8192, 16384, 32768, 65536. When the value of `ShardedCluster` is 1: 1024, 2048, 4096, 8192, 16384. When the value of `node_number` is 1, the value of this field can not be 256.",
},
"password": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
Description: "The account password. When importing resources, this attribute will not be imported. " +
"If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields. " +
"If this parameter is left blank, it means that no password is set for the default account. " +
"At this time, the system will automatically generate a password for the default account to ensure instance access security. " +
"No account can obtain this random password. Therefore, " +
"before connecting to the instance, you need to reset the password of the default account through the ModifyDBAccount interface." +
"You can also set a new account and password through the CreateDBAccount interface according to business needs. " +
"If you need to use password-free access function, you need to enable password-free access first through the ModifyDBInstanceVpcAuthMode interface.",
},
"node_number": {
Type: schema.TypeInt,
Required: true,
Description: "The number of nodes in each shard, the valid value range is `1-6`. When the value is 1, it means creating a single node instance, and this field can not be modified. When the value is greater than 1, it means creating a primary and secondary instance, and this field can be modified.",
},
"multi_az": {
Type: schema.TypeString,
// 新增required字段不兼容了
// 改为optional,兼容改动
Optional: true,
Computed: true,
Description: "Set the availability zone deployment scheme for the instance. " +
"The value range is as follows: \n" +
"disabled: Single availability zone deployment scheme.\n " +
"enabled: Multi-availability zone deployment scheme.\n " +
"Description:\n When the newly created instance is a single-node instance" +
" (that is, when the value of NodeNumber is 1), only the single availability zone deployment scheme is allowed. " +
"At this time, the value of MultiAZ must be disabled.",
},
"configure_nodes": {
Type: schema.TypeList,
Optional: true,
// 新增required字段不兼容了
// 改为optional,兼容改动
Computed: true,
Description: "Set the list of available zones to which the node belongs.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"az": {
Type: schema.TypeString,
Required: true,
Description: "Set the availability zone to which the node belongs. " +
"The number of nodes of an instance (i.e., NodeNumber) and the availability zone deployment scheme (i.e., the value of the MultiAZ parameter) will affect the filling of the current parameter." +
" Among them:\n When a new instance is a single-node instance (i.e., the value of NodeNumber is 1), " +
"only a single availability zone deployment scheme is allowed (i.e., the value of MultiAZ must be disabled). " +
"At this time, only one availability zone needs to be passed in AZ, " +
"and all nodes in the instance will be deployed in this availability zone. " +
"When creating a new instance as a primary-standby instance (that is, when the value of NodeNumber is greater than or equal to 2), " +
"the number of availability zones passed in must be equal to the number of nodes in a single shard (that is, the value of the NodeNumber parameter), " +
"and the value of AZ must comply with the multi-availability zone deployment scheme rules. " +
"The specific rules are as follows: If the primary-standby instance selects the multi-availability zone deployment scheme (that is, the value of MultiAZ is enabled), " +
"then at least two different availability zone IDs must be passed in in AZ, and the first availability zone is the availability zone where the primary node is located." +
" If the primary and standby instances choose a single availability zone deployment scheme (that is, the value of MultiAZ is disabled), then the availability zones passed in for each node must be the same.",
},
},
},
},
"additional_bandwidth": {
Type: schema.TypeInt,
Optional: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
// 创建时不存在这个参数,修改时存在这个参数
return d.Id() == ""
},
Description: "Modify the single-shard additional bandwidth of the target Redis instance. " +
"Set the additional bandwidth of a single shard, that is, " +
"the bandwidth that needs to be additionally increased on the basis of the default bandwidth. Unit: MB/s. " +
"The value of additional bandwidth needs to meet the following conditions at the same time: " +
"It must be greater than or equal to 0. When the value is 0, it means that no additional bandwidth is added, " +
"and the bandwidth of a single shard is the default bandwidth. " +
"The sum of additional bandwidth and default bandwidth cannot exceed the upper limit of bandwidth that can be modified for the current instance. " +
"Different specification nodes have different upper limits of bandwidth that can be modified. " +
"For more details, please refer to bandwidth modification range. " +
"The upper limits of the total write bandwidth and the total read bandwidth of an instance are both 2048MB/s.",
},
"engine_version": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{"4.0", "5.0", "6.0"}, false),
Description: "The engine version of redis instance. Valid value: `4.0`, `5.0`, `6.0`.",
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The engine version of redis instance. Valid value: `5.0`, `6.0`, `7.0`.",
},
"charge_type": {
Type: schema.TypeString,
Optional: true,
Default: "PostPaid",
ValidateFunc: validation.StringInSlice([]string{"PostPaid", "PrePaid"}, false),
Description: "The charge type of redis instance. Valid value: `PostPaid`, `PrePaid`.",
Type: schema.TypeString,
Optional: true,
Default: "PostPaid",
Description: "The charge type of redis instance. Valid value: `PostPaid`, `PrePaid`.",
},
"purchase_months": {
Type: schema.TypeInt,
Optional: true,
Default: 1,
ValidateFunc: validation.IntInSlice([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36}),
DiffSuppressFunc: redisInstanceImportDiffSuppress,
Description: "The purchase months of redis instance, the unit is month. the valid value range is as fallows: `1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36`. This field is valid and required when `ChargeType` is `Prepaid`. \nWhen importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields.",
},
Expand All @@ -115,12 +177,11 @@ func ResourceVolcengineRedisDbInstance() *schema.Resource {
Description: "Whether to enable automatic renewal. This field is valid only when `ChargeType` is `PrePaid`, the default value is false. \nWhen importing resources, this attribute will not be imported. If this attribute is set, please use lifecycle and ignore_changes ignore changes in fields.",
},
"port": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
Default: 6379,
ValidateFunc: validation.IntBetween(1024, 65535),
Description: "The port of custom define private network address. The valid value range is `1024-65535`. The default value is `6379`.",
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
Default: 6379,
Description: "The port of custom define private network address. The valid value range is `1024-65535`. The default value is `6379`.",
},
"project_name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -149,11 +210,10 @@ func ResourceVolcengineRedisDbInstance() *schema.Resource {
},
},
"deletion_protection": {
Type: schema.TypeString,
Optional: true,
Default: "disabled",
ValidateFunc: validation.StringInSlice([]string{"enabled", "disabled"}, false),
Description: "Whether enable deletion protection for redis instance. Valid values: `enabled`, `disabled`(default).",
Type: schema.TypeString,
Optional: true,
Default: "disabled",
Description: "Whether enable deletion protection for redis instance. Valid values: `enabled`, `disabled`(default).",
},
"create_backup": {
Type: schema.TypeBool,
Expand All @@ -165,16 +225,14 @@ func ResourceVolcengineRedisDbInstance() *schema.Resource {
"apply_immediately": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: "Whether to apply the instance configuration change operation immediately. The value of this field is false, means that the change operation will be applied within maintenance time.",
DiffSuppressFunc: redisInstanceImportDiffSuppress,
},
"vpc_auth_mode": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Whether to enable password-free access when connecting to an instance through a private network. Valid values: `open`, `close`.",
ValidateFunc: validation.StringInSlice([]string{"open", "close"}, true),
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Whether to enable password-free access when connecting to an instance through a private network. Valid values: `open`, `close`.",
},
"param_values": {
Type: schema.TypeSet,
Expand Down
Loading

0 comments on commit d0df8e8

Please sign in to comment.