Skip to content

Commit 3997471

Browse files
authored
Feat/tke cluster addon modify (#1363)
* wip: addon modify * feat: tke - support extension_addon modifying * fix: tke - addon update name * changelog 1363 * fix: tke - lint err and polling duration * fix: tke - addon testcase add worker * fix: tke - rename testcase name
1 parent ad08528 commit 3997471

File tree

7 files changed

+364
-67
lines changed

7 files changed

+364
-67
lines changed

.changelog/1363.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
```release-note:enhancement
2+
resource/tencentcloud_kubernetes_cluster: support tke cluster addon modify
3+
```
4+

examples/tencentcloud-tke/main.tf

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -71,28 +71,31 @@ resource "tencentcloud_kubernetes_cluster" "cluster_with_addon" {
7171
}
7272

7373
extension_addon {
74-
name = "NodeProblemDetectorPlus"
75-
param = "{\"kind\":\"NodeProblemDetector\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"npd\"},\"spec\":{\"version\":\"v2.0.0\",\"selfCure\":true,\"uin\":\"12345\",\"subUin\":\"12345\",\"policys\":[{\"actions\":{\"CVM\":{\"reBootCVM\":true,\"retryCounts\":1},\"runtime\":{\"reStartDokcer\":true,\"reStartKubelet\":true,\"retryCounts\":1},\"nodePod\":{\"evict\":true,\"retryCounts\":1}},\"conditionType\":\"Ready\"},{\"actions\":{\"runtime\":{\"reStartDokcer\":true,\"reStartKubelet\":true,\"retryCounts\":1}},\"conditionType\":\"KubeletProblem\"},{\"actions\":{\"runtime\":{\"reStartDokcer\":true,\"reStartKubelet\":false,\"retryCounts\":1}},\"conditionType\":\"DockerdProblem\"}]}}"
74+
name = "CBS",
75+
param = jsonencode({
76+
"kind" : "App", "spec" : {
77+
"chart" : { "chartName" : "cbs", "chartVersion" : "1.0.7" },
78+
"values" : { "values" : [], "rawValues" : "e30=", "rawValuesType" : "json" }
79+
}
80+
})
7681
}
7782
extension_addon {
78-
name = "OOMGuard"
79-
param = "{\"kind\":\"OOMGuard\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"oom\"},\"spec\":{}}"
83+
name = "SecurityGroupPolicy",
84+
param = jsonencode({
85+
"kind" : "App", "spec" : { "chart" : { "chartName" : "securitygrouppolicy", "chartVersion" : "0.1.0" } }
86+
})
8087
}
8188
extension_addon {
82-
name = "DNSAutoscaler"
83-
param = "{\"kind\":\"DNSAutoscaler\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"da\"},\"spec\":{}}"
89+
name = "OOMGuard",
90+
param = jsonencode({
91+
"kind" : "App", "spec" : { "chart" : { "chartName" : "oomguard", "chartVersion" : "1.0.1" } }
92+
})
8493
}
8594
extension_addon {
86-
name = "COS"
87-
param = "{\"kind\":\"COS\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"cos\"},\"spec\":{\"version\":\"1.0.0\"}}"
88-
}
89-
extension_addon {
90-
name = "CFS"
91-
param = "{\"kind\":\"CFS\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"cfs\"},\"spec\":{\"version\":\"1.0.0\"}}"
92-
}
93-
extension_addon {
94-
name = "CBS"
95-
param = "{\"kind\":\"CBS\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"cbs\"},\"spec\":{}}"
95+
name = "OLM",
96+
param = jsonencode({
97+
"kind" : "App", "spec" : { "chart" : { "chartName" : "olm", "chartVersion" : "1.0.0" } }
98+
})
9699
}
97100
}
98101

tencentcloud/internal/helper/helper.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/base64"
77
"encoding/json"
88
"fmt"
9+
"hash/crc32"
910
"reflect"
1011
"sort"
1112
"strings"
@@ -27,9 +28,24 @@ func DataResourceIdsHash(ids []string) string {
2728
return fmt.Sprintf("%d", hashcode.String(buf.String()))
2829
}
2930

31+
// HashString hashes a string to a unique hashcode.
32+
//
33+
// This will be removed in v2 without replacement. So we place here instead of import.
34+
func HashString(s string) int {
35+
v := int(crc32.ChecksumIEEE([]byte(s)))
36+
if v >= 0 {
37+
return v
38+
}
39+
if -v >= 0 {
40+
return -v
41+
}
42+
// v == MinInt
43+
return 0
44+
}
45+
3046
// Generates a hash for the set hash function used by the ID
3147
func DataResourceIdHash(id string) string {
32-
return fmt.Sprintf("%d", hashcode.String(id))
48+
return fmt.Sprintf("%d", HashString(id))
3349
}
3450

3551
func GetTags(d *schema.ResourceData, k string) map[string]string {

tencentcloud/resource_tc_kubernetes_cluster.go

Lines changed: 110 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,15 @@ data "tencentcloud_vpc_subnets" "vpc_first" {
213213
availability_zone = var.availability_zone_first
214214
}
215215
216+
# fetch latest addon(chart) versions
217+
data "tencentcloud_kubernetes_charts" "charts" {}
218+
219+
locals {
220+
chartNames = data.tencentcloud_kubernetes_charts.charts.chart_list.*.name
221+
chartVersions = data.tencentcloud_kubernetes_charts.charts.chart_list.*.latest_version
222+
chartMap = zipmap(local.chartNames, local.chartVersions)
223+
}
224+
216225
resource "tencentcloud_kubernetes_cluster" "cluster_with_addon" {
217226
vpc_id = data.tencentcloud_vpc_subnets.vpc_first.instance_list.0.vpc_id
218227
cluster_cidr = var.cluster_cidr
@@ -242,28 +251,31 @@ resource "tencentcloud_kubernetes_cluster" "cluster_with_addon" {
242251
}
243252
244253
extension_addon {
245-
name = "NodeProblemDetectorPlus"
246-
param = "{\"kind\":\"NodeProblemDetector\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"npd\"},\"spec\":{\"version\":\"v2.0.0\",\"selfCure\":true,\"uin\":\"12345\",\"subUin\":\"12345\",\"policys\":[{\"actions\":{\"CVM\":{\"reBootCVM\":true,\"retryCounts\":1},\"runtime\":{\"reStartDokcer\":true,\"reStartKubelet\":true,\"retryCounts\":1},\"nodePod\":{\"evict\":true,\"retryCounts\":1}},\"conditionType\":\"Ready\"},{\"actions\":{\"runtime\":{\"reStartDokcer\":true,\"reStartKubelet\":true,\"retryCounts\":1}},\"conditionType\":\"KubeletProblem\"},{\"actions\":{\"runtime\":{\"reStartDokcer\":true,\"reStartKubelet\":false,\"retryCounts\":1}},\"conditionType\":\"DockerdProblem\"}]}}"
247-
}
248-
extension_addon {
249-
name = "OOMGuard"
250-
param = "{\"kind\":\"OOMGuard\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"oom\"},\"spec\":{}}"
251-
}
252-
extension_addon {
253-
name = "DNSAutoscaler"
254-
param = "{\"kind\":\"DNSAutoscaler\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"da\"},\"spec\":{}}"
254+
name = "COS"
255+
param = jsonencode({
256+
"kind" : "App", "spec" : {
257+
"chart" : { "chartName" : "cos", "chartVersion" : local.chartMap["cos"] },
258+
"values" : { "values" : [], "rawValues" : "e30=", "rawValuesType" : "json" }
259+
}
260+
})
255261
}
256262
extension_addon {
257-
name = "COS"
258-
param = "{\"kind\":\"COS\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"cos\"},\"spec\":{\"version\":\"1.0.0\"}}"
263+
name = "SecurityGroupPolicy"
264+
param = jsonencode({
265+
"kind" : "App", "spec" : { "chart" : { "chartName" : "securitygrouppolicy", "chartVersion" : local.chartMap["securitygrouppolicy"] } }
266+
})
259267
}
260268
extension_addon {
261-
name = "CFS"
262-
param = "{\"kind\":\"CFS\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"cfs\"},\"spec\":{\"version\":\"1.0.0\"}}"
269+
name = "OOMGuard"
270+
param = jsonencode({
271+
"kind" : "App", "spec" : { "chart" : { "chartName" : "oomguard", "chartVersion" : local.chartMap["oomguard"] } }
272+
})
263273
}
264274
extension_addon {
265-
name = "CBS"
266-
param = "{\"kind\":\"CBS\",\"apiVersion\":\"platform.tke/v1\",\"metadata\":{\"generateName\":\"cbs\"},\"spec\":{}}"
275+
name = "OLM"
276+
param = jsonencode({
277+
"kind" : "App", "spec" : { "chart" : { "chartName" : "olm", "chartVersion" : local.chartMap["olm"] } }
278+
})
267279
}
268280
}
269281
```
@@ -1260,9 +1272,9 @@ func resourceTencentCloudTkeCluster() *schema.Resource {
12601272
Description: "Specify cluster authentication configuration. Only available for managed cluster and `cluster_version` >= 1.20.",
12611273
},
12621274
"extension_addon": {
1263-
Type: schema.TypeList,
1264-
Optional: true,
1265-
ForceNew: true,
1275+
Type: schema.TypeList,
1276+
Optional: true,
1277+
Description: "Information of the add-on to be installed.",
12661278
Elem: &schema.Resource{
12671279
Schema: map[string]*schema.Schema{
12681280
"name": {
@@ -1271,13 +1283,13 @@ func resourceTencentCloudTkeCluster() *schema.Resource {
12711283
Description: "Add-on name.",
12721284
},
12731285
"param": {
1274-
Type: schema.TypeString,
1275-
Required: true,
1276-
Description: "Description of the add-on resource object in JSON string format.",
1286+
Type: schema.TypeString,
1287+
Required: true,
1288+
DiffSuppressFunc: helper.DiffSupressJSON,
1289+
Description: "Parameter of the add-on resource object in JSON string format, please check the example at the top of page for reference.",
12771290
},
12781291
},
12791292
},
1280-
Description: "Information of the add-on to be installed.",
12811293
},
12821294
"log_agent": {
12831295
Type: schema.TypeList,
@@ -2908,6 +2920,56 @@ func resourceTencentCloudTkeClusterUpdate(d *schema.ResourceData, meta interface
29082920
}
29092921
}
29102922

2923+
if d.HasChange("extension_addon") {
2924+
o, n := d.GetChange("extension_addon")
2925+
adds, removes, changes := resourceTkeGetAddonsDiffs(o.([]interface{}), n.([]interface{}))
2926+
updates := append(adds, changes...)
2927+
for i := range updates {
2928+
var err error
2929+
addon := updates[i].(map[string]interface{})
2930+
param := addon["param"].(string)
2931+
name, err := tkeService.GetAddonNameFromJson(param)
2932+
if err != nil {
2933+
return err
2934+
}
2935+
_, has, _ := tkeService.PollingAddonsPhase(ctx, id, name, nil)
2936+
if has {
2937+
err = tkeService.UpdateExtensionAddon(ctx, id, name, param)
2938+
} else {
2939+
err = tkeService.CreateExtensionAddon(ctx, id, param)
2940+
}
2941+
if err != nil {
2942+
return err
2943+
}
2944+
_, _, err = tkeService.PollingAddonsPhase(ctx, id, name, nil)
2945+
if err != nil {
2946+
return err
2947+
}
2948+
}
2949+
2950+
for i := range removes {
2951+
addon := removes[i].(map[string]interface{})
2952+
param := addon["param"].(string)
2953+
name, err := tkeService.GetAddonNameFromJson(param)
2954+
if err != nil {
2955+
return err
2956+
}
2957+
_, has, _ := tkeService.PollingAddonsPhase(ctx, id, name, nil)
2958+
if !has {
2959+
continue
2960+
}
2961+
err = tkeService.DeleteExtensionAddon(ctx, id, name)
2962+
if err != nil {
2963+
return err
2964+
}
2965+
_, has, _ = tkeService.PollingAddonsPhase(ctx, id, name, nil)
2966+
if has {
2967+
return fmt.Errorf("addon %s still exists", name)
2968+
}
2969+
}
2970+
2971+
}
2972+
29112973
d.Partial(false)
29122974
if err := resourceTencentCloudTkeClusterRead(d, meta); err != nil {
29132975
log.Printf("[WARN]%s resource.kubernetes_cluster.read after update fail , %s", logId, err.Error())
@@ -2992,3 +3054,28 @@ func resourceTencentCloudTkeClusterDelete(d *schema.ResourceData, meta interface
29923054
return err
29933055

29943056
}
3057+
3058+
func resourceTkeGetAddonsDiffs(o, n []interface{}) (adds, removes, changes []interface{}) {
3059+
indexByName := func(i interface{}) int {
3060+
v := i.(map[string]interface{})
3061+
return helper.HashString(v["name"].(string))
3062+
}
3063+
indexAll := func(i interface{}) int {
3064+
v := i.(map[string]interface{})
3065+
name := v["name"].(string)
3066+
param := v["param"].(string)
3067+
return helper.HashString(fmt.Sprintf("%s#%s", name, param))
3068+
}
3069+
3070+
os := schema.NewSet(indexByName, o)
3071+
ns := schema.NewSet(indexByName, n)
3072+
3073+
adds = ns.Difference(os).List()
3074+
removes = os.Difference(ns).List()
3075+
3076+
fullIndexedKeeps := schema.NewSet(indexAll, ns.Intersection(os).List())
3077+
fullIndexedOlds := schema.NewSet(indexAll, o)
3078+
3079+
changes = fullIndexedKeeps.Difference(fullIndexedOlds).List()
3080+
return
3081+
}

0 commit comments

Comments
 (0)