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 Hybrid nodes #40371

Merged
merged 12 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 10 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/40371.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_eks_cluster: Add `remote_network_config` argument for EKS Auto Mode
```
185 changes: 182 additions & 3 deletions internal/service/eks/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"log"
"time"

"github.com/YakDriver/regexache"
"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"
Expand Down Expand Up @@ -203,7 +202,7 @@ func resourceCluster() *schema.Resource {
ForceNew: true,
ValidateFunc: validation.All(
validation.IsCIDRNetwork(12, 24),
validation.StringMatch(regexache.MustCompile(`^(10|172\.(1[6-9]|2[0-9]|3[0-1])|192\.168)\..*`), "must be within 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16"),
validateIPv4CIDRPrivateRange,
),
},
"service_ipv6_cidr": {
Expand All @@ -223,7 +222,7 @@ func resourceCluster() *schema.Resource {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
ConflictsWith: []string{"encryption_config", "kubernetes_network_config"},
ConflictsWith: []string{"encryption_config", "kubernetes_network_config", "remote_network_config"},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"control_plane_instance_type": {
Expand Down Expand Up @@ -260,6 +259,63 @@ func resourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"remote_network_config": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
MaxItems: 1,
ConflictsWith: []string{"outpost_config"},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"remote_node_networks": {
Type: schema.TypeList,
MinItems: 1,
MaxItems: 1,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cidrs": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
MinItems: 1,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.All(
verify.ValidIPv4CIDRNetworkAddress,
validateIPv4CIDRPrivateRange,
),
},
},
},
},
},
"remote_pod_networks": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cidrs": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
MinItems: 1,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.All(
verify.ValidIPv4CIDRNetworkAddress,
validateIPv4CIDRPrivateRange,
),
},
},
},
},
},
},
},
},
names.AttrRoleARN: {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -386,6 +442,10 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, meta int
input.OutpostConfig = expandOutpostConfigRequest(v.([]interface{}))
}

if v, ok := d.GetOk("remote_network_config"); ok {
input.RemoteNetworkConfig = expandRemoteNetworkConfigRequest(v.([]interface{}))
}

if v, ok := d.GetOk("upgrade_policy"); ok {
input.UpgradePolicy = expandUpgradePolicy(v.([]interface{}))
}
Expand Down Expand Up @@ -499,6 +559,9 @@ func resourceClusterRead(ctx context.Context, d *schema.ResourceData, meta inter
return sdkdiag.AppendErrorf(diags, "setting outpost_config: %s", err)
}
d.Set("platform_version", cluster.PlatformVersion)
if err := d.Set("remote_network_config", flattenRemoteNetworkConfigResponse(cluster.RemoteNetworkConfig)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting remote_network_config: %s", err)
}
d.Set(names.AttrRoleARN, cluster.RoleArn)
d.Set(names.AttrStatus, cluster.Status)
if err := d.Set("upgrade_policy", flattenUpgradePolicy(cluster.UpgradePolicy)); err != nil {
Expand Down Expand Up @@ -1085,6 +1148,73 @@ func expandKubernetesNetworkConfigRequest(tfList []interface{}) *types.Kubernete
return apiObject
}

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

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

apiObject := &types.RemoteNetworkConfigRequest{
RemoteNodeNetworks: expandRemoteNodeNetworks(tfMap["remote_node_networks"].([]interface{})),
}

if v, ok := tfMap["remote_pod_networks"].([]interface{}); ok {
apiObject.RemotePodNetworks = expandRemotePodNetworks(v)
}

return apiObject
}

func expandRemoteNodeNetworks(tfList []interface{}) []types.RemoteNodeNetwork {
if len(tfList) == 0 {
return nil
}

var apiObjects []types.RemoteNodeNetwork

for _, tfMapRaw := range tfList {
tfMap, ok := tfMapRaw.(map[string]interface{})
if !ok {
continue
}

apiObject := types.RemoteNodeNetwork{
Cidrs: flex.ExpandStringValueSet(tfMap["cidrs"].(*schema.Set)),
}

apiObjects = append(apiObjects, apiObject)
}

return apiObjects
}

func expandRemotePodNetworks(tfList []interface{}) []types.RemotePodNetwork {
if len(tfList) == 0 {
return nil
}

var apiObjects []types.RemotePodNetwork

for _, tfMapRaw := range tfList {
tfMap, ok := tfMapRaw.(map[string]interface{})
if !ok {
continue
}

apiObject := types.RemotePodNetwork{
Cidrs: flex.ExpandStringValueSet(tfMap["cidrs"].(*schema.Set)),
}

apiObjects = append(apiObjects, apiObject)
}

return apiObjects
}

func expandLogging(vEnabledLogTypes *schema.Set) *types.Logging {
allLogTypes := enum.EnumValues[types.LogType]()
enabledLogTypes := flex.ExpandStringyValueSet[types.LogType](vEnabledLogTypes)
Expand Down Expand Up @@ -1290,6 +1420,55 @@ func flattenOutpostConfigResponse(apiObject *types.OutpostConfigResponse) []inte
return []interface{}{tfMap}
}

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

tfMap := map[string]interface{}{
"remote_node_networks": flattenRemoteNodeNetwork(apiObject.RemoteNodeNetworks),
"remote_pod_networks": flattenRemotePodNetwork(apiObject.RemotePodNetworks),
}

return []interface{}{tfMap}
}

func flattenRemoteNodeNetwork(apiObjects []types.RemoteNodeNetwork) []interface{} {
if len(apiObjects) == 0 {
return nil
}

var tfList []interface{}

for _, apiObject := range apiObjects {
tfMap := map[string]interface{}{
"cidrs": flex.FlattenStringValueList(apiObject.Cidrs),
}

tfList = append(tfList, tfMap)
}

return tfList
}

func flattenRemotePodNetwork(apiObjects []types.RemotePodNetwork) []interface{} {
if len(apiObjects) == 0 {
return nil
}

var tfList []interface{}

for _, apiObject := range apiObjects {
tfMap := map[string]interface{}{
"cidrs": flex.FlattenStringValueList(apiObject.Cidrs),
}

tfList = append(tfList, tfMap)
}

return tfList
}

func flattenControlPlanePlacementResponse(apiObject *types.ControlPlanePlacementResponse) []interface{} {
if apiObject == nil {
return nil
Expand Down
37 changes: 37 additions & 0 deletions internal/service/eks/cluster_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,40 @@ func dataSourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"remote_network_config": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"remote_node_networks": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cidrs": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
"remote_pod_networks": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cidrs": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
},
},
},
names.AttrRoleARN: {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -271,6 +305,9 @@ func dataSourceClusterRead(ctx context.Context, d *schema.ResourceData, meta int
return sdkdiag.AppendErrorf(diags, "setting outpost_config: %s", err)
}
d.Set("platform_version", cluster.PlatformVersion)
if err := d.Set("remote_network_config", flattenRemoteNetworkConfigResponse(cluster.RemoteNetworkConfig)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting remote_network_config: %s", err)
}
d.Set(names.AttrRoleARN, cluster.RoleArn)
d.Set(names.AttrStatus, cluster.Status)
if err := d.Set("upgrade_policy", flattenUpgradePolicy(cluster.UpgradePolicy)); err != nil {
Expand Down
65 changes: 65 additions & 0 deletions internal/service/eks/cluster_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func TestAccEKSClusterDataSource_basic(t *testing.T) {
resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.service_ipv6_cidr", dataSourceResourceName, "kubernetes_network_config.0.service_ipv6_cidr"),
resource.TestCheckResourceAttrPair(resourceName, "outpost_config.#", dataSourceResourceName, "outpost_config.#"),
resource.TestMatchResourceAttr(dataSourceResourceName, "platform_version", regexache.MustCompile(`^eks\.\d+$`)),
resource.TestCheckResourceAttr(dataSourceResourceName, "remote_network_config.#", "0"),
resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, dataSourceResourceName, names.AttrRoleARN),
resource.TestCheckResourceAttrPair(resourceName, names.AttrStatus, dataSourceResourceName, names.AttrStatus),
resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsPercent, dataSourceResourceName, acctest.CtTagsPercent),
Expand Down Expand Up @@ -95,6 +96,7 @@ func TestAccEKSClusterDataSource_outpost(t *testing.T) {
resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.service_ipv4_cidr", dataSourceResourceName, "kubernetes_network_config.0.service_ipv4_cidr"),
resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.service_ipv6_cidr", dataSourceResourceName, "kubernetes_network_config.0.service_ipv6_cidr"),
resource.TestMatchResourceAttr(dataSourceResourceName, "platform_version", regexache.MustCompile(`^eks-local-outposts\.\d+$`)),
resource.TestCheckResourceAttr(dataSourceResourceName, "remote_network_config.#", "0"),
resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, dataSourceResourceName, names.AttrRoleARN),
resource.TestCheckResourceAttrPair(resourceName, names.AttrStatus, dataSourceResourceName, names.AttrStatus),
resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsPercent, dataSourceResourceName, acctest.CtTagsPercent),
Expand All @@ -118,6 +120,61 @@ func TestAccEKSClusterDataSource_outpost(t *testing.T) {
})
}

func TestAccEKSClusterDataSource_remoteNetwork(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
dataSourceResourceName := "data.aws_eks_cluster.test"
resourceName := "aws_eks_cluster.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.EKSServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckClusterDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccClusterDataSourceConfig_remoteNetwork(rName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrPair(resourceName, names.AttrARN, dataSourceResourceName, names.AttrARN),
resource.TestCheckResourceAttr(dataSourceResourceName, "certificate_authority.#", "1"),
resource.TestCheckResourceAttrPair(resourceName, "certificate_authority.0.data", dataSourceResourceName, "certificate_authority.0.data"),
resource.TestCheckResourceAttrPair(resourceName, names.AttrCreatedAt, dataSourceResourceName, names.AttrCreatedAt),
resource.TestCheckResourceAttr(dataSourceResourceName, "enabled_cluster_log_types.#", "0"),
resource.TestCheckResourceAttrPair(resourceName, names.AttrEndpoint, dataSourceResourceName, names.AttrEndpoint),
resource.TestCheckResourceAttr(dataSourceResourceName, "identity.#", "0"),
resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.#", dataSourceResourceName, "kubernetes_network_config.#"),
resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.ip_family", dataSourceResourceName, "kubernetes_network_config.0.ip_family"),
resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.service_ipv4_cidr", dataSourceResourceName, "kubernetes_network_config.0.service_ipv4_cidr"),
resource.TestCheckResourceAttrPair(resourceName, "kubernetes_network_config.0.service_ipv6_cidr", dataSourceResourceName, "kubernetes_network_config.0.service_ipv6_cidr"),
resource.TestCheckResourceAttrPair(resourceName, "outpost_config.#", dataSourceResourceName, "outpost_config.#"),
resource.TestMatchResourceAttr(dataSourceResourceName, "platform_version", regexache.MustCompile(`^eks-local-outposts\.\d+$`)),
resource.TestCheckResourceAttr(resourceName, "remote_network_config.#", "1"),
resource.TestCheckResourceAttr(resourceName, "remote_network_config.0.remote_node_networks.#", "1"),
resource.TestCheckResourceAttr(resourceName, "remote_network_config.0.remote_node_networks.0.cidrs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "remote_network_config.0.remote_node_networks.0.cidrs.0", "10.90.0.0/22"),
resource.TestCheckResourceAttr(resourceName, "remote_network_config.0.remote_pod_networks.#", "1"),
resource.TestCheckResourceAttr(resourceName, "remote_network_config.0.remote_pod_networks.0.cidrs.#", "1"),
resource.TestCheckResourceAttr(resourceName, "remote_network_config.0.remote_pod_networks.0.cidrs.0", "10.80.0.0/22"),
resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, dataSourceResourceName, names.AttrRoleARN),
resource.TestCheckResourceAttrPair(resourceName, names.AttrStatus, dataSourceResourceName, names.AttrStatus),
resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsPercent, dataSourceResourceName, acctest.CtTagsPercent),
resource.TestCheckResourceAttr(resourceName, "upgrade_policy.#", "1"),
resource.TestCheckResourceAttr(resourceName, "upgrade_policy.0.support_type", "EXTENDED"),
resource.TestCheckResourceAttrPair(resourceName, names.AttrVersion, dataSourceResourceName, names.AttrVersion),
resource.TestCheckResourceAttr(dataSourceResourceName, "vpc_config.#", "1"),
resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.cluster_security_group_id", dataSourceResourceName, "vpc_config.0.cluster_security_group_id"),
resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.endpoint_private_access", dataSourceResourceName, "vpc_config.0.endpoint_private_access"),
resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.endpoint_public_access", dataSourceResourceName, "vpc_config.0.endpoint_public_access"),
resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.security_group_ids.#", dataSourceResourceName, "vpc_config.0.security_group_ids.#"),
resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.subnet_ids.#", dataSourceResourceName, "vpc_config.0.subnet_ids.#"),
resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.public_access_cidrs.#", dataSourceResourceName, "vpc_config.0.public_access_cidrs.#"),
resource.TestCheckResourceAttrPair(resourceName, "vpc_config.0.vpc_id", dataSourceResourceName, "vpc_config.0.vpc_id"),
),
},
},
})
}

func testAccClusterDataSourceConfig_basic(rName string) string {
return acctest.ConfigCompose(testAccClusterConfig_logging(rName, []string{"api", "audit"}), `
data "aws_eks_cluster" "test" {
Expand All @@ -133,3 +190,11 @@ data "aws_eks_cluster" "test" {
}
`)
}

func testAccClusterDataSourceConfig_remoteNetwork(rName string) string {
return acctest.ConfigCompose(testAccClusterConfig_remotePodNetwork(rName, "10.90.0.0/22", "10.80.0.0/22"), `
data "aws_eks_cluster" "test" {
name = aws_eks_cluster.test.name
}
`)
}
Loading
Loading