Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/aws_eks_cluster: Add support for EKS Auto Mode #40370

Merged
merged 17 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading