Skip to content

Commit

Permalink
Merge pull request #35037 from sasidhar-aws/f-aws-eks-cluster-access
Browse files Browse the repository at this point in the history
EKS access entry and policy association changes
  • Loading branch information
ewbankkit authored Jan 18, 2024
2 parents a12f861 + 152868a commit 68f1f9d
Show file tree
Hide file tree
Showing 20 changed files with 2,076 additions and 51 deletions.
19 changes: 19 additions & 0 deletions .changelog/35037.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
```release-note:new-resource
aws_eks_access_entry
```

```release-note:new-data-source
aws_eks_access_entry
```

```release-note:new-resource
aws_eks_access_policy_association
```

```release-note:enhancement
resource/aws_eks_cluster: Add `access_config` configuration block
```

```release-note:enhancement
resource/aws_eks_cluster: Add `access_config` attribute
```
256 changes: 256 additions & 0 deletions internal/service/eks/access_entry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package eks

import (
"context"
"fmt"
"log"
"strings"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/eks"
"github.com/aws/aws-sdk-go-v2/service/eks/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @SDKResource("aws_eks_access_entry", name="Access Entry")
// @Tags(identifierAttribute="access_entry_arn")
func resourceAccessEntry() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceAccessEntryCreate,
ReadWithoutTimeout: resourceAccessEntryRead,
UpdateWithoutTimeout: resourceAccessEntryUpdate,
DeleteWithoutTimeout: resourceAccessEntryDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

CustomizeDiff: verify.SetTagsDiff,

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(10 * time.Minute),
Delete: schema.DefaultTimeout(10 * time.Minute),
},

Schema: map[string]*schema.Schema{
"access_entry_arn": {
Type: schema.TypeString,
Computed: true,
},
"cluster_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validClusterName,
},
"created_at": {
Type: schema.TypeString,
Computed: true,
},
"kubernetes_groups": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"modified_at": {
Type: schema.TypeString,
Computed: true,
},
"principal_arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: verify.ValidARN,
},
names.AttrTags: tftags.TagsSchema(),
names.AttrTagsAll: tftags.TagsSchemaComputed(),
"type": {
Type: schema.TypeString,
Computed: true,
},
"user_name": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceAccessEntryCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).EKSClient(ctx)

clusterName := d.Get("cluster_name").(string)
principalARN := d.Get("principal_arn").(string)
id := accessEntryCreateResourceID(clusterName, principalARN)
input := &eks.CreateAccessEntryInput{
ClusterName: aws.String(clusterName),
PrincipalArn: aws.String(principalARN),
Tags: getTagsIn(ctx),
}

if v, ok := d.GetOk("kubernetes_groups"); ok {
input.KubernetesGroups = flex.ExpandStringValueSet(v.(*schema.Set))
}

_, err := conn.CreateAccessEntry(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "creating EKS Access Entry (%s): %s", id, err)
}

d.SetId(id)

return append(diags, resourceAccessEntryRead(ctx, d, meta)...)
}

func resourceAccessEntryRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).EKSClient(ctx)

clusterName, principalARN, err := accessEntryParseResourceID(d.Id())
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}

output, err := findAccessEntryByTwoPartKey(ctx, conn, clusterName, principalARN)

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] EKS Access Entry (%s) not found, removing from state", d.Id())
d.SetId("")
return diags
}

if err != nil {
return sdkdiag.AppendErrorf(diags, "reading EKS Access Entry (%s): %s", d.Id(), err)
}

d.Set("access_entry_arn", output.AccessEntryArn)
d.Set("cluster_name", output.ClusterName)
d.Set("created_at", aws.ToTime(output.CreatedAt).Format(time.RFC3339))
d.Set("kubernetes_groups", output.KubernetesGroups)
d.Set("modified_at", aws.ToTime(output.ModifiedAt).Format(time.RFC3339))
d.Set("principal_arn", output.PrincipalArn)
d.Set("type", output.Type)
d.Set("user_name", output.Username)

setTagsOut(ctx, output.Tags)

return diags
}

func resourceAccessEntryUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).EKSClient(ctx)

if d.HasChangesExcept("tags", "tags_all") {
clusterName, principalARN, err := accessEntryParseResourceID(d.Id())
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}

input := &eks.UpdateAccessEntryInput{
ClusterName: aws.String(clusterName),
PrincipalArn: aws.String(principalARN),
}

if d.HasChange("kubernetes_groups") {
input.KubernetesGroups = flex.ExpandStringValueSet(d.Get("kubernetes_groups").(*schema.Set))
}

_, err = conn.UpdateAccessEntry(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "updating EKS Access Entry (%s): %s", d.Id(), err)
}
}

return append(diags, resourceAccessEntryRead(ctx, d, meta)...)
}

func resourceAccessEntryDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).EKSClient(ctx)

clusterName, principalARN, err := accessEntryParseResourceID(d.Id())
if err != nil {
return sdkdiag.AppendFromErr(diags, err)
}

log.Printf("[DEBUG] Deleting EKS Access Entry: %s", d.Id())
_, err = conn.DeleteAccessEntry(ctx, &eks.DeleteAccessEntryInput{
ClusterName: aws.String(clusterName),
PrincipalArn: aws.String(principalARN),
})

if errs.IsA[*types.ResourceNotFoundException](err) {
return diags
}

if err != nil {
return sdkdiag.AppendErrorf(diags, "deleting EKS Access Entry (%s): %s", d.Id(), err)
}

return diags
}

const accessEntryResourceIDSeparator = ":"

func accessEntryCreateResourceID(clusterName, principal_arn string) string {
parts := []string{clusterName, principal_arn}
id := strings.Join(parts, accessEntryResourceIDSeparator)

return id
}

func accessEntryParseResourceID(id string) (string, string, error) {
parts := strings.SplitN(id, accessEntryResourceIDSeparator, 2)

if len(parts) == 2 && parts[0] != "" && parts[1] != "" {
return parts[0], parts[1], nil
}

return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected cluster-name%[2]sprincipal-arn", id, accessEntryResourceIDSeparator)
}

func findAccessEntryByTwoPartKey(ctx context.Context, conn *eks.Client, clusterName, principalARN string) (*types.AccessEntry, error) {
input := &eks.DescribeAccessEntryInput{
ClusterName: aws.String(clusterName),
PrincipalArn: aws.String(principalARN),
}

output, err := conn.DescribeAccessEntry(ctx, input)

if errs.IsA[*types.ResourceNotFoundException](err) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || output.AccessEntry == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output.AccessEntry, nil
}
95 changes: 95 additions & 0 deletions internal/service/eks/access_entry_datasource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package eks

import (
"context"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @SDKDataSource("aws_eks_access_entry", name="Access Entry")
func dataSourceAccessEntry() *schema.Resource {
return &schema.Resource{
ReadWithoutTimeout: dataSourceAccessEntryRead,

Schema: map[string]*schema.Schema{
"access_entry_arn": {
Type: schema.TypeString,
Computed: true,
},
"cluster_name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validClusterName,
},
"created_at": {
Type: schema.TypeString,
Computed: true,
},
"kubernetes_groups": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"modified_at": {
Type: schema.TypeString,
Computed: true,
},
"principal_arn": {
Type: schema.TypeString,
Required: true,
ValidateFunc: verify.ValidARN,
},
"user_name": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
names.AttrTags: tftags.TagsSchema(),
names.AttrTagsAll: tftags.TagsSchemaComputed(),
},
}
}

func dataSourceAccessEntryRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).EKSClient(ctx)

clusterName := d.Get("cluster_name").(string)
principalARN := d.Get("principal_arn").(string)
id := accessEntryCreateResourceID(clusterName, principalARN)
output, err := findAccessEntryByTwoPartKey(ctx, conn, clusterName, principalARN)

if err != nil {
return sdkdiag.AppendErrorf(diags, "reading EKS Access Entry (%s): %s", id, err)
}

d.SetId(id)
d.Set("access_entry_arn", output.AccessEntryArn)
d.Set("cluster_name", output.ClusterName)
d.Set("created_at", aws.ToTime(output.CreatedAt).Format(time.RFC3339))
d.Set("kubernetes_groups", output.KubernetesGroups)
d.Set("modified_at", aws.ToTime(output.ModifiedAt).Format(time.RFC3339))
d.Set("principal_arn", output.PrincipalArn)
d.Set("type", output.Type)
d.Set("user_name", output.Username)

setTagsOut(ctx, output.Tags)

return diags
}
Loading

0 comments on commit 68f1f9d

Please sign in to comment.