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

Add new publicSubnetIds and privateSubnetIds cluster options. Also, update tests to use new awsx.ec2.Vpc API and new subnet options #238

Closed
wants to merge 4 commits into from
Closed
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.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

### Improvements

- Add new publicSubnetIds and privateSubnetIds cluster options. Also, update
tests to use new awsx.ec2.Vpc API and new subnet options
[#238](https://github.com/pulumi/pulumi-eks/pull/238)
- fix(iam): improve YAML error handling & reporting in IAM ops
[#231](https://github.com/pulumi/pulumi-eks/pull/231)

Expand Down
105 changes: 99 additions & 6 deletions nodejs/eks/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ export interface CoreData {
cluster: aws.eks.Cluster;
vpcId: pulumi.Output<string>;
subnetIds: pulumi.Output<string[]>;
publicSubnetIds: pulumi.Output<string[]>;
privateSubnetIds: pulumi.Output<string[]>;
clusterSecurityGroup: aws.ec2.SecurityGroup;
provider: k8s.Provider;
instanceRoles: pulumi.Output<aws.iam.Role[]>;
Expand Down Expand Up @@ -223,16 +225,36 @@ export function createCore(name: string, args: ClusterOptions, parent: pulumi.Co
throw new Error("instanceRole and instanceRoles are mutually exclusive, and cannot both be set.");
}

// If no VPC was specified, use the default VPC.
if (args.subnetIds && (args.publicSubnetIds || args.privateSubnetIds)) {
throw new Error("subnetIds, and the use of publicSubnetIds and/or privateSubnetIds are mutually exclusive. Choose a single approach.");
}

// Configure default networking architecture.
let vpcId: pulumi.Input<string> = args.vpcId!;
let subnetIds: pulumi.Input<pulumi.Input<string>[]> = args.subnetIds!;
if (args.vpcId === undefined) {
let publicSubnetIds: pulumi.Input<pulumi.Input<string>[]> = args.publicSubnetIds!;
let privateSubnetIds: pulumi.Input<pulumi.Input<string>[]> = args.privateSubnetIds!;

// If no VPC is set, use the default VPC's subnets.
if (!args.vpcId) {
const invokeOpts = { parent: parent };
const vpc = aws.ec2.getVpc({ default: true }, invokeOpts);
vpcId = vpc.then(v => v.id);
subnetIds = vpc.then(v => aws.ec2.getSubnetIds({ vpcId: v.id }, invokeOpts)).then(subnets => subnets.ids);
}

// Form the subnetIds to pass to the EKS cluster.
subnetIds = pulumi.all([subnetIds || [], args.publicSubnetIds || []])
.apply(([ids, publicIds]) => {
publicSubnetIds = publicIds;
return ids.concat(publicIds);
});
subnetIds = pulumi.all([subnetIds, args.privateSubnetIds || []])
.apply(([ids, privateIds]) => {
privateSubnetIds = privateSubnetIds;
return ids.concat(privateIds);
});

// Create the EKS service role
let eksRole: pulumi.Output<aws.iam.Role>;
if (args.serviceRole) {
Expand Down Expand Up @@ -447,6 +469,8 @@ export function createCore(name: string, args: ClusterOptions, parent: pulumi.Co
return {
vpcId: pulumi.output(vpcId),
subnetIds: pulumi.output(subnetIds),
publicSubnetIds: pulumi.output(publicSubnetIds),
privateSubnetIds: pulumi.output(privateSubnetIds),
clusterSecurityGroup: eksClusterSecurityGroup,
cluster: eksCluster,
kubeconfig: kubeconfig,
Expand Down Expand Up @@ -484,13 +508,82 @@ export interface ClusterOptions {
vpcId?: pulumi.Input<string>;

/**
* The subnets to attach to the EKS cluster. If either vpcId or subnetIds is unset, the cluster will use the
* default VPC's subnets. If the list of subnets includes both public and private subnets, the Kubernetes API
* server and the worker nodes will only be attached to the private subnets. See
* https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html for more details.
* The set of subnets to use on the EKS cluster.
* These subnets are automatically tagged by EKS for Kubernetes purposes.
*
* Note, `vpcId` must be set. If not, then the cluster will use the AWS
* account's default VPC subnets.
*
* If the list of subnets includes both public and private subnets, the worker
* nodes will only be attached to the private subnets, and the public
* subnets will be used for internet-facing load balancers.
*
* See for more details: https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html.
*
* Note, the use of `subnetIds`, and the combination of `publicSubnetIds`
* and/or `privateSubnetIds` is mutually exclusive. The former is the
* current implementation, and the latter combination
* is newer functionality.
*/
subnetIds?: pulumi.Input<pulumi.Input<string>[]>;

/**
* The set of public subnets to use on the cluster. These subnets
* are used as the default public subnets for the worker node groups, and
* are automatically tagged by EKS for Kubernetes purposes.
*
* Note, `vpcId` must be set. If not, then the cluster will use the AWS
* account's default VPC subnets.
*
* Network architecture options:
* - Private-only: Only set `privateSubnetIds`.
* - Default workers to run in a private subnet and Kubernetes cannot create internet-facing load
* balancers for your pods.
* - Public-only: Only set `publicSubnetIds`.
* - Default workers to run in a public subnet, including your worker nodes.
* - Mixed (recommended): Set both `privateSubnetIds` and `publicSubnetIds`.
* - Default all worker nodes to run in private subnets, and use the public subnets
* for internet-facing load balancers.
*
* See for more details: https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html.
*
* Note, the use of `subnetIds`, and the combination of `publicSubnetIds`
* and/or `privateSubnetIds` is mutually exclusive. The former is the
* current implementation, and the latter combination
* is newer functionality.
*/
publicSubnetIds?: pulumi.Input<pulumi.Input<string>[]>;

/*
* The set of private subnets to use on the cluster. These subnets
* are used as the default private subnets for the worker node groups, and
* are automatically tagged by EKS for Kubernetes purposes.
*
* Note, `vpcId` must be set. If not, then the cluster will use the AWS
* account's default VPC subnets.
*
* Network architecture options:
* - Private-only: Only set `privateSubnetIds`.
* - Default workers to run in a private subnet and Kubernetes cannot create internet-facing load
* balancers for your pods.
* - Public-only: Only set `publicSubnetIds`.
* - Default workers to run in a public subnet, including your worker nodes.
* - Mixed (recommended): Set both `privateSubnetIds` and `publicSubnetIds`.
* - Default all worker nodes to run in private subnets, and use the public subnets
* for internet-facing load balancers.
*
* See for more details: https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html.
*
* Note, the use of `subnetIds`, and the combination of `publicSubnetIds`
* and/or `privateSubnetIds` is mutually exclusive. The former is the
* current implementation, and the latter combination
* is newer functionality.
*
* Also consider setting `nodeAssociatePublicIpAddress: true` for
* fully private workers.
*/
privateSubnetIds?: pulumi.Input<pulumi.Input<string>[]>;

/**
* Whether or not to auto-assign the EKS worker nodes public IP addresses.
* If this toggle is set to true, the EKS workers will be
Expand Down
17 changes: 17 additions & 0 deletions nodejs/eks/examples/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,23 @@ func Test_AllTests(t *testing.T) {
)
},
},
{
Dir: path.Join(cwd, "tests", "awsx-network-and-subnetIds"),
Config: map[string]string{
"aws:region": region,
},
Dependencies: []string{
"@pulumi/eks",
},
ExpectRefreshChanges: true,
ExtraRuntimeValidation: func(t *testing.T, info integration.RuntimeValidationStackInfo) {
utils.RunEKSSmokeTest(t,
info.Deployment.Resources,
info.Outputs["kubeconfig1"],
info.Outputs["kubeconfig2"],
)
},
},
{
Dir: path.Join(cwd, "tests", "migrate-nodegroups"),
Config: map[string]string{
Expand Down
4 changes: 3 additions & 1 deletion nodejs/eks/examples/cluster/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# examples/cluster

Creates an EKS cluster in the default VPC with two t2.medium nodes.
Creates two EKS clusters in the default VPC with two t2.medium nodes.
- One cluster uses the default configuration.
- One cluster uses a non-default configuration.
18 changes: 12 additions & 6 deletions nodejs/eks/examples/cluster/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import * as pulumi from "@pulumi/pulumi";
import * as awsx from "@pulumi/awsx";
import * as eks from "@pulumi/eks";

const projectName = pulumi.getProject();

// Create an EKS cluster with the default configuration.
const cluster1 = new eks.Cluster("example-cluster1");
const cluster1 = new eks.Cluster(`${projectName}-1`);

// Create an EKS cluster with a non-default configuration.
const vpc = new awsx.ec2.Vpc(`${projectName}-2`, {
tags: { "Name": `${projectName}-2` },
});

// Create an EKS cluster with non-default configuration
const vpc = new awsx.Network("example-cluster2-vpc", { usePrivateSubnets: true });
const cluster2 = new eks.Cluster("example-cluster2", {
vpcId: vpc.vpcId,
subnetIds: vpc.subnetIds,
const cluster2 = new eks.Cluster(`${projectName}-2`, {
vpcId: vpc.id,
publicSubnetIds: vpc.publicSubnetIds,
desiredCapacity: 2,
minSize: 2,
maxSize: 2,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
name: test-awsx-network-and-subnetIds
description: EKS cluster examples using the previous awsx.Network API and cluster network setups.
runtime: nodejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# test-awsx-network-and-subnetIds

EKS cluster examples using the previous `awsx.Network` API and cluster network setups.

Tests two types of clusters that use the previous network API setup:
- One cluster uses a VPC from the `awsx.Network` API, and cluster `subnetIds`.
- One cluster uses a VPC from the `awsx.Network` API, cluster `subnetIds`, and a node group with the `nodeSubnetIds` override option.
27 changes: 27 additions & 0 deletions nodejs/eks/examples/tests/awsx-network-and-subnetIds/iam.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";

const managedPolicyArns: string[] = [
"arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy",
"arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy",
"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",
];

// Creates a role and attches the EKS worker node IAM managed policies
export function createRole(name: string): aws.iam.Role {
const role = new aws.iam.Role(name, {
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({
Service: "ec2.amazonaws.com",
}),
});

let counter = 0;
for (const policy of managedPolicyArns) {
// Create RolePolicyAttachment without returning it.
const rpa = new aws.iam.RolePolicyAttachment(`${name}-policy-${counter++}`,
{ policyArn: policy, role: role },
);
}

return role;
}
40 changes: 40 additions & 0 deletions nodejs/eks/examples/tests/awsx-network-and-subnetIds/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
import * as eks from "@pulumi/eks";
import * as iam from "./iam";

const projectName = pulumi.getProject();

// Create an EKS cluster with awsx.Network VPC and cluster subnetIds.
const vpc1 = new awsx.Network(`${projectName}-1`);
const cluster1 = new eks.Cluster(`${projectName}-1`, {
vpcId: vpc1.vpcId,
subnetIds: vpc1.subnetIds,
deployDashboard: false,
});

const role = iam.createRole("role");
const instanceProfile = new aws.iam.InstanceProfile("instanceProfile", {role: role});

// Create an EKS cluster with awsx.Network VPC and a nodegroup with
// nodeSubnetIds overrides.
const vpc2 = new awsx.Network(`${projectName}-2`);
const cluster2 = new eks.Cluster(`${projectName}-2`, {
vpcId: vpc2.vpcId,
subnetIds: vpc2.subnetIds,
deployDashboard: false,
instanceRole: role,
});

// Create the node group with the nodeSubnetIds override option.
const ng = new eks.NodeGroup(`${projectName}-2-ng`, {
cluster: cluster2,
nodeSubnetIds: vpc2.publicSubnetIds,
}, {
providers: { kubernetes: cluster2.provider},
});

// Export the cluster's kubeconfig.
export const kubeconfig1 = cluster1.kubeconfig;
export const kubeconfig2 = cluster2.kubeconfig;
15 changes: 15 additions & 0 deletions nodejs/eks/examples/tests/awsx-network-and-subnetIds/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "test-awsx-network-and-subnetIds",
"devDependencies": {
"typescript": "^3.0.0",
"@types/node": "latest"
},
"dependencies": {
"@pulumi/pulumi": "^1.0.0-beta",
"@pulumi/aws": "^1.0.0-beta",
"@pulumi/awsx": "latest"
},
"peerDependencies": {
"@pulumi/eks": "latest"
}
}
24 changes: 24 additions & 0 deletions nodejs/eks/examples/tests/awsx-network-and-subnetIds/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"outDir": "bin",
"target": "es6",
"lib": [
"es6"
],
"module": "commonjs",
"moduleResolution": "node",
"declaration": true,
"sourceMap": true,
"stripInternal": true,
"experimentalDecorators": true,
"pretty": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true,
"strictNullChecks": true
},
"files": [
"index.ts"
]
}
6 changes: 3 additions & 3 deletions nodejs/eks/examples/tests/migrate-nodegroups/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ const projectName = pulumi.getProject();
// Allocate a new VPC with custom settings, and a public & private subnet per AZ.
const vpc = new awsx.ec2.Vpc(`${projectName}`, {
cidrBlock: "172.16.0.0/16",
subnets: [{ type: "public" }, { type: "private" }],
tags: { "Name": `${projectName}` },
});

// Export VPC ID and Subnets.
export const vpcId = vpc.id;
export const allVpcSubnets = vpc.privateSubnetIds.concat(vpc.publicSubnetIds);

// Create IAM Role and matching InstanceProfile to use with the nodegroups.
const roles = iam.createRoles(projectName, 1);
Expand All @@ -29,7 +28,8 @@ const instanceProfiles = iam.createInstanceProfiles(projectName, roles);
const myCluster = new eks.Cluster(`${projectName}`, {
version: "1.13",
vpcId: vpcId,
subnetIds: allVpcSubnets,
publicSubnetIds: vpc.publicSubnetIds,
privateSubnetIds: vpc.privateSubnetIds,
nodeAssociatePublicIpAddress: false,
skipDefaultNodeGroup: true,
deployDashboard: false,
Expand Down
11 changes: 7 additions & 4 deletions nodejs/eks/examples/tests/replace-cluster-add-subnets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ import * as pulumi from "@pulumi/pulumi";

const projectName = pulumi.getProject();

const vpc = new awsx.Network(`${projectName}-net`, {
// Allocate a new VPC with custom settings, and a public & private subnet per AZ.
const vpc = new awsx.ec2.Vpc(`${projectName}`, {
cidrBlock: "172.16.0.0/16",
numberOfAvailabilityZones: 3,
tags: { "Name": `${projectName}` },
});

const publicSubnetIds = vpc.publicSubnetIds;

// Remove this line after the init update to repro: https://git.io/fj8cn
publicSubnetIds.pop();

const cluster = new eks.Cluster(projectName, {
vpcId: vpc.vpcId,
subnetIds: publicSubnetIds,
const cluster = new eks.Cluster(`${projectName}`, {
vpcId: vpc.id,
publicSubnetIds: publicSubnetIds,
deployDashboard: false,
});

Expand Down
Loading