Skip to content

Commit

Permalink
Merge pull request hashicorp#40370 from bryantbiggs/feat/eks-auto-mode
Browse files Browse the repository at this point in the history
r/aws_eks_cluster: Add support for EKS Auto Mode
  • Loading branch information
gdavison authored Dec 3, 2024
2 parents e77a728 + c136453 commit 0943f5b
Show file tree
Hide file tree
Showing 8 changed files with 720 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .changelog/40370.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_eks_cluster: Add `compute_config`, `storage_config`, and `kubernetes_network_config.elastic_load_balancing` arguments for EKS Auto Mode
```
269 changes: 266 additions & 3 deletions internal/service/eks/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package eks

import (
"context"
"errors"
"fmt"
"log"
"time"
Expand Down Expand Up @@ -53,6 +54,7 @@ func resourceCluster() *schema.Resource {

CustomizeDiff: customdiff.Sequence(
verify.SetTagsDiff,
validateAutoModeCustsomizeDiff,
customdiff.ForceNewIfChange("encryption_config", func(_ context.Context, old, new, meta interface{}) bool {
// You cannot disable envelope encryption after enabling it. This action is irreversible.
return len(old.([]interface{})) == 1 && len(new.([]interface{})) == 0
Expand Down Expand Up @@ -113,6 +115,33 @@ func resourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"compute_config": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
names.AttrEnabled: {
Type: schema.TypeBool,
Optional: true,
},
"node_pools": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(nodePoolType_Values(), false),
},
},
"node_role_arn": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: verify.ValidARN,
},
},
},
},
names.AttrCreatedAt: {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -188,6 +217,20 @@ func resourceCluster() *schema.Resource {
ConflictsWith: []string{"outpost_config"},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"elastic_load_balancing": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
names.AttrEnabled: {
Type: schema.TypeBool,
Optional: true,
},
},
},
},
"ip_family": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -326,6 +369,28 @@ func resourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"storage_config": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"block_storage": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
names.AttrEnabled: {
Type: schema.TypeBool,
Optional: true,
},
},
},
},
},
},
},
names.AttrTags: tftags.TagsSchema(),
names.AttrTagsAll: tftags.TagsSchemaComputed(),
"upgrade_policy": {
Expand Down Expand Up @@ -430,6 +495,10 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int
Tags: getTagsIn(ctx),
}

if v, ok := d.GetOk("compute_config"); ok {
input.ComputeConfig = expandComputeConfigRequest(v.([]interface{}))
}

if v, ok := d.GetOk("access_config"); ok {
input.AccessConfig = expandCreateAccessConfigRequest(v.([]interface{}))
}
Expand All @@ -446,6 +515,10 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int
input.RemoteNetworkConfig = expandRemoteNetworkConfigRequest(v.([]interface{}))
}

if v, ok := d.GetOk("storage_config"); ok {
input.StorageConfig = expandStorageConfigRequest(v.([]interface{}))
}

if v, ok := d.GetOk("upgrade_policy"); ok {
input.UpgradePolicy = expandUpgradePolicy(v.([]interface{}))
}
Expand Down Expand Up @@ -540,6 +613,9 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta inter
if cluster.OutpostConfig != nil {
d.Set("cluster_id", cluster.Id)
}
if err := d.Set("compute_config", flattenComputeConfigResponse(cluster.ComputeConfig)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting compute_config: %s", err)
}
d.Set(names.AttrCreatedAt, cluster.CreatedAt.Format(time.RFC3339))
if err := d.Set("enabled_cluster_log_types", flattenLogging(cluster.Logging)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting enabled_cluster_log_types: %s", err)
Expand All @@ -564,6 +640,9 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta inter
}
d.Set(names.AttrRoleARN, cluster.RoleArn)
d.Set(names.AttrStatus, cluster.Status)
if err := d.Set("storage_config", flattenStorageConfigResponse(cluster.StorageConfig)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting storage_config: %s", err)
}
if err := d.Set("upgrade_policy", flattenUpgradePolicy(cluster.UpgradePolicy)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting upgrade_policy: %s", err)
}
Expand Down Expand Up @@ -628,6 +707,31 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, meta int
}
}

if d.HasChanges("compute_config", "kubernetes_network_config", "storage_config") {
computeConfig := expandComputeConfigRequest(d.Get("compute_config").([]interface{}))
kubernetesNetworkConfig := expandKubernetesNetworkConfigRequest(d.Get("kubernetes_network_config").([]interface{}))
storageConfig := expandStorageConfigRequest(d.Get("storage_config").([]interface{}))

input := &eks.UpdateClusterConfigInput{
Name: aws.String(d.Id()),
ComputeConfig: computeConfig,
KubernetesNetworkConfig: kubernetesNetworkConfig,
StorageConfig: storageConfig,
}

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

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

updateID := aws.ToString(output.Update.Id)

if _, err = waitClusterUpdateSuccessful(ctx, conn, d.Id(), updateID, d.Timeout(schema.TimeoutUpdate)); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for EKS Cluster (%s) compute config update (%s): %s", d.Id(), updateID, err)
}
}

if d.HasChange("encryption_config") {
o, n := d.GetChange("encryption_config")

Expand Down Expand Up @@ -1009,6 +1113,33 @@ func expandUpdateAccessConfigRequest(tfList []interface{}) *types.UpdateAccessCo
return apiObject
}

func expandComputeConfigRequest(tfList []interface{}) *types.ComputeConfigRequest {
if len(tfList) == 0 {
return nil
}

tfMap, ok := tfList[0].(map[string]interface{})
if !ok {
return nil
}

apiObject := &types.ComputeConfigRequest{}

if v, ok := tfMap[names.AttrEnabled].(bool); ok {
apiObject.Enabled = aws.Bool(v)
}

if v, ok := tfMap["node_pools"].(*schema.Set); ok && v.Len() > 0 {
apiObject.NodePools = flex.ExpandStringValueSet(v)
}

if v, ok := tfMap["node_role_arn"].(string); ok && v != "" {
apiObject.NodeRoleArn = aws.String(v)
}

return apiObject
}

func expandEncryptionConfig(tfList []interface{}) []types.EncryptionConfig {
if len(tfList) == 0 {
return nil
Expand Down Expand Up @@ -1055,6 +1186,44 @@ func expandProvider(tfList []interface{}) *types.Provider {
return apiObject
}

func expandStorageConfigRequest(tfList []interface{}) *types.StorageConfigRequest {
if len(tfList) == 0 {
return nil
}

tfMap, ok := tfList[0].(map[string]interface{})
if !ok {
return nil
}

apiObject := &types.StorageConfigRequest{}

if v, ok := tfMap["block_storage"].([]interface{}); ok {
apiObject.BlockStorage = expandBlockStorage(v)
}

return apiObject
}

func expandBlockStorage(tfList []interface{}) *types.BlockStorage {
if len(tfList) == 0 {
return nil
}

tfMap, ok := tfList[0].(map[string]interface{})
if !ok {
return nil
}

apiObject := &types.BlockStorage{}

if v, ok := tfMap[names.AttrEnabled].(bool); ok {
apiObject.Enabled = aws.Bool(v)
}

return apiObject
}

func expandOutpostConfigRequest(tfList []interface{}) *types.OutpostConfigRequest {
if len(tfList) == 0 {
return nil
Expand Down Expand Up @@ -1137,6 +1306,10 @@ func expandKubernetesNetworkConfigRequest(tfList []interface{}) *types.Kubernete

apiObject := &types.KubernetesNetworkConfigRequest{}

if v, ok := tfMap["elastic_load_balancing"].([]interface{}); ok {
apiObject.ElasticLoadBalancing = expandKubernetesNetworkConfigElasticLoadBalancing(v)
}

if v, ok := tfMap["ip_family"].(string); ok && v != "" {
apiObject.IpFamily = types.IpFamily(v)
}
Expand All @@ -1148,6 +1321,25 @@ func expandKubernetesNetworkConfigRequest(tfList []interface{}) *types.Kubernete
return apiObject
}

func expandKubernetesNetworkConfigElasticLoadBalancing(tfList []interface{}) *types.ElasticLoadBalancing {
if len(tfList) == 0 {
return nil
}

tfMap, ok := tfList[0].(map[string]interface{})
if !ok {
return nil
}

apiObject := &types.ElasticLoadBalancing{}

if v, ok := tfMap[names.AttrEnabled].(bool); ok {
apiObject.Enabled = aws.Bool(v)
}

return apiObject
}

func expandRemoteNetworkConfigRequest(tfList []interface{}) *types.RemoteNetworkConfigRequest {
if len(tfList) == 0 {
return nil
Expand Down Expand Up @@ -1283,6 +1475,20 @@ func flattenCertificate(certificate *types.Certificate) []map[string]interface{}
return []map[string]interface{}{m}
}

func flattenComputeConfigResponse(apiObject *types.ComputeConfigResponse) []map[string]interface{} {
if apiObject == nil {
return []map[string]interface{}{}
}

m := map[string]interface{}{
names.AttrEnabled: aws.ToBool(apiObject.Enabled),
"node_pools": flex.FlattenStringValueList(apiObject.NodePools),
"node_role_arn": aws.ToString(apiObject.NodeRoleArn),
}

return []map[string]interface{}{m}
}

func flattenIdentity(identity *types.Identity) []map[string]interface{} {
if identity == nil {
return []map[string]interface{}{}
Expand Down Expand Up @@ -1398,9 +1604,22 @@ func flattenKubernetesNetworkConfigResponse(apiObject *types.KubernetesNetworkCo
}

tfMap := map[string]interface{}{
"service_ipv4_cidr": aws.ToString(apiObject.ServiceIpv4Cidr),
"service_ipv6_cidr": aws.ToString(apiObject.ServiceIpv6Cidr),
"ip_family": apiObject.IpFamily,
"elastic_load_balancing": flattenKubernetesNetworkConfigElasticLoadBalancing(apiObject.ElasticLoadBalancing),
"service_ipv4_cidr": aws.ToString(apiObject.ServiceIpv4Cidr),
"service_ipv6_cidr": aws.ToString(apiObject.ServiceIpv6Cidr),
"ip_family": apiObject.IpFamily,
}

return []interface{}{tfMap}
}

func flattenKubernetesNetworkConfigElasticLoadBalancing(apiObjects *types.ElasticLoadBalancing) []interface{} {
if apiObjects == nil {
return nil
}

tfMap := map[string]interface{}{
names.AttrEnabled: aws.ToBool(apiObjects.Enabled),
}

return []interface{}{tfMap}
Expand Down Expand Up @@ -1481,6 +1700,30 @@ func flattenControlPlanePlacementResponse(apiObject *types.ControlPlanePlacement
return []interface{}{tfMap}
}

func flattenStorageConfigResponse(apiObject *types.StorageConfigResponse) []interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{
"block_storage": flattenBlockStorage(apiObject.BlockStorage),
}

return []interface{}{tfMap}
}

func flattenBlockStorage(apiObject *types.BlockStorage) []interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{
names.AttrEnabled: aws.ToBool(apiObject.Enabled),
}

return []interface{}{tfMap}
}

func flattenUpgradePolicy(apiObject *types.UpgradePolicyResponse) []interface{} {
if apiObject == nil {
return nil
Expand All @@ -1504,3 +1747,23 @@ func flattenZonalShiftConfig(apiObject *types.ZonalShiftConfigResponse) []interf

return []interface{}{tfMap}
}

// InvalidParameterException: For EKS Auto Mode, please ensure that all required configs,
// including computeConfig, kubernetesNetworkConfig, and blockStorage are all either fully enabled or fully disabled.
func validateAutoModeCustsomizeDiff(_ context.Context, d *schema.ResourceDiff, _ any) error {
if d.HasChanges("compute_config", "kubernetes_network_config", "storage_config") {
computeConfig := expandComputeConfigRequest(d.Get("compute_config").([]interface{}))
kubernetesNetworkConfig := expandKubernetesNetworkConfigRequest(d.Get("kubernetes_network_config").([]interface{}))
storageConfig := expandStorageConfigRequest(d.Get("storage_config").([]interface{}))

computeConfigEnabled := computeConfig != nil && computeConfig.Enabled != nil && aws.ToBool(computeConfig.Enabled)
kubernetesNetworkConfigEnabled := kubernetesNetworkConfig != nil && kubernetesNetworkConfig.ElasticLoadBalancing != nil && kubernetesNetworkConfig.ElasticLoadBalancing.Enabled != nil && aws.ToBool(kubernetesNetworkConfig.ElasticLoadBalancing.Enabled)
storageConfigEnabled := storageConfig != nil && storageConfig.BlockStorage != nil && storageConfig.BlockStorage.Enabled != nil && aws.ToBool(storageConfig.BlockStorage.Enabled)

if computeConfigEnabled != kubernetesNetworkConfigEnabled || computeConfigEnabled != storageConfigEnabled {
return errors.New("compute_config.enabled, kubernetes_networking_config.elastic_load_balancing.enabled, and storage_config.block_storage.enabled must all be set to either true or false")
}
}

return nil
}
Loading

0 comments on commit 0943f5b

Please sign in to comment.