Skip to content

Commit e7485b7

Browse files
authored
[TK-1373] Update resource and data of 'kubernetes_(default_)service_account' to handle deprecated 'default_secret_name' in Kubernetes 1.24.0+ (#1792)
* Update resource and data of 'kubernetes_(default_)service_account' to handle deprecated 'default_secret_name' in Kubernetes 1.24.0+
1 parent c370d92 commit e7485b7

14 files changed

+129
-27
lines changed

kubernetes/data_source_kubernetes_service_account.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ func dataSourceKubernetesServiceAccount() *schema.Resource {
4848
Computed: true,
4949
},
5050
"default_secret_name": {
51-
Type: schema.TypeString,
52-
Computed: true,
51+
Type: schema.TypeString,
52+
Computed: true,
53+
Deprecated: "Starting from version 1.24.0 Kubernetes does not automatically generate a token for service accounts, in this case, `default_secret_name` will be empty",
5354
},
5455
},
5556
}

kubernetes/data_source_kubernetes_service_account_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ func TestAccKubernetesDataSourceServiceAccount_basic(t *testing.T) {
2525
resource.TestCheckResourceAttr("kubernetes_service_account.test", "secret.0.name", name+"-secret"),
2626
resource.TestCheckResourceAttr("kubernetes_service_account.test", "image_pull_secret.0.name", name+"-image-pull-secret"),
2727
resource.TestCheckResourceAttr("kubernetes_service_account.test", "automount_service_account_token", "true"),
28-
resource.TestCheckResourceAttrSet("kubernetes_service_account.test", "default_secret_name"),
2928
),
3029
},
3130
{
@@ -38,7 +37,6 @@ func TestAccKubernetesDataSourceServiceAccount_basic(t *testing.T) {
3837
resource.TestCheckResourceAttr("data.kubernetes_service_account.test", "secret.0.name", name+"-secret"),
3938
resource.TestCheckResourceAttr("data.kubernetes_service_account.test", "image_pull_secret.0.name", name+"-image-pull-secret"),
4039
resource.TestCheckResourceAttr("data.kubernetes_service_account.test", "automount_service_account_token", "true"),
41-
resource.TestCheckResourceAttrSet("data.kubernetes_service_account.test", "default_secret_name"),
4240
),
4341
},
4442
},
@@ -49,18 +47,21 @@ func TestAccKubernetesDataSourceServiceAccount_default_secret(t *testing.T) {
4947
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
5048

5149
resource.Test(t, resource.TestCase{
52-
PreCheck: func() { testAccPreCheck(t) },
50+
PreCheck: func() {
51+
testAccPreCheck(t)
52+
skipIfClusterVersionGreaterThanOrEqual(t, "1.24.0")
53+
},
5354
ProviderFactories: testAccProviderFactories,
5455
Steps: []resource.TestStep{
5556
{
56-
Config: testAccKubernetesServiceAccountConfig_default_secret(name),
57+
Config: testAccKubernetesDataSourceServiceAccountConfig_default_secret(name),
5758
Check: resource.ComposeAggregateTestCheckFunc(
5859
resource.TestCheckResourceAttr("kubernetes_service_account.test", "metadata.0.name", name),
5960
resource.TestCheckResourceAttr("kubernetes_service_account.test", "secret.#", "1"),
6061
),
6162
},
6263
{
63-
Config: testAccKubernetesServiceAccountConfig_default_secret(name) +
64+
Config: testAccKubernetesDataSourceServiceAccountConfig_default_secret(name) +
6465
testAccKubernetesDataSourceServiceAccountConfig_default_secret_read(name),
6566
Check: resource.ComposeAggregateTestCheckFunc(
6667
resource.TestCheckResourceAttr("data.kubernetes_service_account.test", "metadata.0.name", name),
@@ -117,7 +118,7 @@ func testAccKubernetesDataSourceServiceAccountConfig_read() string {
117118
`)
118119
}
119120

120-
func testAccKubernetesServiceAccountConfig_default_secret(name string) string {
121+
func testAccKubernetesDataSourceServiceAccountConfig_default_secret(name string) string {
121122
return fmt.Sprintf(`
122123
variable "token_name" {
123124
default = "%s-token-test0"

kubernetes/provider.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strconv"
1212

1313
"github.com/hashicorp/go-cty/cty"
14+
gversion "github.com/hashicorp/go-version"
1415
"github.com/mitchellh/go-homedir"
1516

1617
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -633,3 +634,26 @@ func useAdmissionregistrationV1beta1(conn *kubernetes.Clientset) (bool, error) {
633634
useadmissionregistrationv1beta1 = ptrToBool(true)
634635
return true, nil
635636
}
637+
638+
func getServerVersion(connection *kubernetes.Clientset) (*gversion.Version, error) {
639+
sv, err := connection.ServerVersion()
640+
if err != nil {
641+
return nil, err
642+
}
643+
644+
return gversion.NewVersion(sv.String())
645+
}
646+
647+
func serverVersionGreaterThanOrEqual(connection *kubernetes.Clientset, version string) (bool, error) {
648+
sv, err := getServerVersion(connection)
649+
if err != nil {
650+
return false, err
651+
}
652+
// server version that we need to compare with
653+
cv, err := gversion.NewVersion(version)
654+
if err != nil {
655+
return false, err
656+
}
657+
658+
return sv.GreaterThanOrEqual(cv), nil
659+
}

kubernetes/resource_kubernetes_default_service_account.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ func resourceKubernetesDefaultServiceAccountCreate(ctx context.Context, d *schem
5555
log.Printf("[INFO] Default service account exists: %s", metadata.Namespace)
5656
return nil
5757
})
58-
5958
if err != nil {
6059
return diag.FromErr(err)
6160
}

kubernetes/resource_kubernetes_service.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ func resourceKubernetesServiceUpdate(ctx context.Context, d *schema.ResourceData
442442

443443
ops := patchMetadata("metadata.0.", "/metadata/", d)
444444
if d.HasChange("spec") {
445-
serverVersion, err := conn.ServerVersion()
445+
serverVersion, err := getServerVersion(conn)
446446
if err != nil {
447447
return diag.FromErr(err)
448448
}

kubernetes/resource_kubernetes_service_account.go

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ func resourceKubernetesServiceAccount() *schema.Resource {
6969
Default: true,
7070
},
7171
"default_secret_name": {
72-
Type: schema.TypeString,
73-
Computed: true,
72+
Type: schema.TypeString,
73+
Computed: true,
74+
Deprecated: "Starting from version 1.24.0 Kubernetes does not automatically generate a token for service accounts, in this case, `default_secret_name` will be empty",
7475
},
7576
},
7677
}
@@ -106,12 +107,21 @@ func resourceKubernetesServiceAccountCreate(ctx context.Context, d *schema.Resou
106107
if err != nil {
107108
return diag.FromErr(err)
108109
}
110+
109111
return resourceKubernetesServiceAccountRead(ctx, d, meta)
110112
}
111113

112114
func getServiceAccountDefaultSecret(ctx context.Context, name string, config api.ServiceAccount, timeout time.Duration, conn *kubernetes.Clientset) (*api.Secret, error) {
115+
sv, err := serverVersionGreaterThanOrEqual(conn, "1.24.0")
116+
if err != nil {
117+
return &api.Secret{}, err
118+
}
119+
if sv {
120+
return &api.Secret{}, nil
121+
}
122+
113123
var svcAccTokens []api.Secret
114-
err := resource.RetryContext(ctx, timeout, func() *resource.RetryError {
124+
err = resource.RetryContext(ctx, timeout, func() *resource.RetryError {
115125
resp, err := conn.CoreV1().ServiceAccounts(config.Namespace).Get(ctx, name, metav1.GetOptions{})
116126
if err != nil {
117127
return resource.NonRetryableError(err)
@@ -167,6 +177,20 @@ func findDefaultServiceAccount(ctx context.Context, sa *api.ServiceAccount, conn
167177
*/
168178
ds := make([]string, 0)
169179

180+
sv, err := serverVersionGreaterThanOrEqual(conn, "1.24.0")
181+
if err != nil {
182+
return "", diag.FromErr(err)
183+
}
184+
if sv {
185+
return "", diag.Diagnostics{
186+
diag.Diagnostic{
187+
Severity: diag.Warning,
188+
Summary: `"default_secret_name" is no longer applicable for Kubernetes v1.24.0 and above`,
189+
Detail: `Starting from version 1.24.0 Kubernetes does not automatically generate a token for service accounts, in this case, "default_secret_name" will be empty`,
190+
},
191+
}
192+
}
193+
170194
for _, saSecret := range sa.Secrets {
171195
if !strings.HasPrefix(saSecret.Name, fmt.Sprintf("%s-token-", sa.Name)) {
172196
log.Printf("[DEBUG] Skipping %s as it doesn't have the right name", saSecret.Name)
@@ -292,6 +316,20 @@ func resourceKubernetesServiceAccountRead(ctx context.Context, d *schema.Resourc
292316
return diag.FromErr(err)
293317
}
294318

319+
sv, err := serverVersionGreaterThanOrEqual(conn, "1.24.0")
320+
if err != nil {
321+
return diag.FromErr(err)
322+
}
323+
if sv {
324+
return diag.Diagnostics{
325+
diag.Diagnostic{
326+
Severity: diag.Warning,
327+
Summary: `"default_secret_name" is no longer applicable for Kubernetes v1.24.0 and above`,
328+
Detail: `Starting from version 1.24.0 Kubernetes does not automatically generate a token for service accounts, in this case, "default_secret_name" will be empty`,
329+
},
330+
}
331+
}
332+
295333
return nil
296334
}
297335

@@ -415,6 +453,7 @@ func resourceKubernetesServiceAccountImportState(ctx context.Context, d *schema.
415453
if err != nil {
416454
return nil, fmt.Errorf("Unable to set default_secret_name: %s", err)
417455
}
456+
418457
d.SetId(buildId(sa.ObjectMeta))
419458

420459
return []*schema.ResourceData{d}, nil

kubernetes/resource_kubernetes_service_account_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,38 @@ func TestAccKubernetesServiceAccount_basic(t *testing.T) {
6363
})
6464
}
6565

66+
func TestAccKubernetesServiceAccount_default_secret(t *testing.T) {
67+
var conf api.ServiceAccount
68+
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
69+
resourceName := "kubernetes_service_account_v1.test"
70+
71+
resource.Test(t, resource.TestCase{
72+
PreCheck: func() {
73+
testAccPreCheck(t)
74+
skipIfClusterVersionGreaterThanOrEqual(t, "1.24.0")
75+
},
76+
IDRefreshName: resourceName,
77+
ProviderFactories: testAccProviderFactories,
78+
CheckDestroy: testAccCheckKubernetesServiceAccountDestroy,
79+
Steps: []resource.TestStep{
80+
{
81+
Config: testAccKubernetesServiceAccountConfig_default_secret(name),
82+
Check: resource.ComposeAggregateTestCheckFunc(
83+
testAccCheckKubernetesServiceAccountExists(resourceName, &conf),
84+
resource.TestCheckResourceAttr(resourceName, "metadata.0.name", name),
85+
resource.TestCheckResourceAttrSet(resourceName, "default_secret_name"),
86+
),
87+
},
88+
{
89+
ResourceName: resourceName,
90+
ImportState: true,
91+
ImportStateVerify: true,
92+
ImportStateVerifyIgnore: []string{"metadata.0.resource_version", "automount_service_account_token"},
93+
},
94+
},
95+
})
96+
}
97+
6698
func TestAccKubernetesServiceAccount_automount(t *testing.T) {
6799
var conf api.ServiceAccount
68100
name := fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
@@ -257,6 +289,9 @@ func matchLocalObjectReferenceName(lor []api.LocalObjectReference, expected []*r
257289

258290
func testAccCheckServiceAccountSecrets(m *api.ServiceAccount, expected []*regexp.Regexp) resource.TestCheckFunc {
259291
return func(s *terraform.State) error {
292+
if clusterVersionGreaterThanOrEqual("1.24.0") {
293+
return nil
294+
}
260295
if len(expected) == 0 && len(m.Secrets) == 0 {
261296
return nil
262297
}
@@ -397,6 +432,14 @@ resource "kubernetes_secret" "four" {
397432
`, name, name, name, name, name)
398433
}
399434

435+
func testAccKubernetesServiceAccountConfig_default_secret(name string) string {
436+
return fmt.Sprintf(`resource "kubernetes_service_account_v1" "test" {
437+
metadata {
438+
name = "%s"
439+
}
440+
}`, name)
441+
}
442+
400443
func testAccKubernetesServiceAccountConfig_modified(name string) string {
401444
return fmt.Sprintf(`resource "kubernetes_service_account" "test" {
402445
metadata {

kubernetes/structure_service_spec.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
66
v1 "k8s.io/api/core/v1"
77
"k8s.io/apimachinery/pkg/util/intstr"
8-
"k8s.io/apimachinery/pkg/version"
98
)
109

1110
// Flatteners
@@ -284,7 +283,7 @@ func expandServiceSpec(l []interface{}) v1.ServiceSpec {
284283

285284
// Patch Ops
286285

287-
func patchServiceSpec(keyPrefix, pathPrefix string, d *schema.ResourceData, v *version.Info) (PatchOperations, error) {
286+
func patchServiceSpec(keyPrefix, pathPrefix string, d *schema.ResourceData, kv *gversion.Version) (PatchOperations, error) {
288287
ops := make([]PatchOperation, 0, 0)
289288

290289
if d.HasChange(keyPrefix + "allocate_load_balancer_node_ports") {
@@ -360,12 +359,8 @@ func patchServiceSpec(keyPrefix, pathPrefix string, d *schema.ResourceData, v *v
360359
})
361360
}
362361
if d.HasChange(keyPrefix + "external_ips") {
363-
k8sVersion, err := gversion.NewVersion(v.String())
364-
if err != nil {
365-
return nil, err
366-
}
367-
v1_8_0, _ := gversion.NewVersion("1.8.0")
368-
if k8sVersion.LessThan(v1_8_0) {
362+
version, _ := gversion.NewVersion("1.8.0")
363+
if kv.LessThan(version) {
369364
// If we haven't done this the deprecated field would have priority
370365
ops = append(ops, &ReplaceOperation{
371366
Path: pathPrefix + "deprecatedPublicIPs",

website/docs/d/service_account.html.markdown

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ The following arguments are supported:
5353

5454
* `image_pull_secret` - A list of image pull secrets associated with the service account.
5555
* `secret` - A list of secrets associated with the service account.
56-
* `default_secret_name` - Name of the default secret, containing service account token, created & managed by the service. By default, the provider will try to find the secret containing the service account token that Kubernetes automatically created for the service account. Where there are multiple tokens and the provider cannot determine which was created by Kubernetes, this attribute will be empty. When only one token is associated with the service account, the provider will return this single token secret.
56+
* `default_secret_name` - Name of the default secret, containing service account token, created & managed by the service. By default, the provider will try to find the secret containing the service account token that Kubernetes automatically created for the service account. Where there are multiple tokens and the provider cannot determine which was created by Kubernetes, this attribute will be empty. When only one token is associated with the service account, the provider will return this single token secret. Starting from version 1.24.0 Kubernetes does not automatically generate a token for service accounts, in this case, `default_secret_name` will be empty.
5757

5858
### `image_pull_secret`
5959

website/docs/d/service_account_v1.html.markdown

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ The following arguments are supported:
5353

5454
* `image_pull_secret` - A list of image pull secrets associated with the service account.
5555
* `secret` - A list of secrets associated with the service account.
56-
* `default_secret_name` - Name of the default secret, containing service account token, created & managed by the service. By default, the provider will try to find the secret containing the service account token that Kubernetes automatically created for the service account. Where there are multiple tokens and the provider cannot determine which was created by Kubernetes, this attribute will be empty. When only one token is associated with the service account, the provider will return this single token secret.
56+
* `default_secret_name` - Name of the default secret, containing service account token, created & managed by the service. By default, the provider will try to find the secret containing the service account token that Kubernetes automatically created for the service account. Where there are multiple tokens and the provider cannot determine which was created by Kubernetes, this attribute will be empty. When only one token is associated with the service account, the provider will return this single token secret. Starting from version 1.24.0 Kubernetes does not automatically generate a token for service accounts, in this case, `default_secret_name` will be empty.
5757

5858
### `image_pull_secret`
5959

0 commit comments

Comments
 (0)