Skip to content

Commit

Permalink
feat(ecs-service-extensions): create an Environment from attributes (
Browse files Browse the repository at this point in the history
…#10932)

This PR introduces `Environment.fromEnvironmentAttributes()` so that a user can import a pre-existing cluster.

Closes #10931 

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
misterjoshua authored Nov 2, 2020
1 parent fcfed39 commit d395b5e
Show file tree
Hide file tree
Showing 7 changed files with 599 additions and 7 deletions.
17 changes: 17 additions & 0 deletions packages/@aws-cdk-containers/ecs-service-extensions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,20 @@ The above code uses the well known service discovery name for each
service, and passes it as an environment variable to the container so
that the container knows what address to use when communicating to
the other service.

## Importing a pre-existing cluster

To create an environment with a pre-existing cluster, you must import the cluster first, then use `Environment.fromEnvironmentAttributes()`. When a cluster is imported into an environment, the cluster is treated as immutable. As a result, no extension may modify the cluster to change a setting.

```ts

const cluster = ecs.Cluster.fromClusterAttributes(stack, 'Cluster', {
...
});

const environment = Environment.fromEnvironmentAttributes(stack, 'Environment', {
capacityType: EnvironmentCapacityType.EC2, // or `FARGATE`
cluster,
});

```
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,50 @@ export interface EnvironmentProps {
readonly capacityType?: EnvironmentCapacityType
}

/**
* An environment into which to deploy a service.
*/
export interface IEnvironment {
/**
* The name of this environment.
*/
readonly id: string;

/**
* The VPC into which environment services should be placed.
*/
readonly vpc: ec2.IVpc;

/**
* The cluster that is providing capacity for this service.
*/
readonly cluster: ecs.ICluster;

/**
* The capacity type used by the service's cluster.
*/
readonly capacityType: EnvironmentCapacityType;

/**
* Add a default cloudmap namespace to the environment's cluster.
*/
addDefaultCloudMapNamespace(options: ecs.CloudMapNamespaceOptions): void;
}

/**
* An environment into which to deploy a service. This environment
* can either be instantiated with a preexisting AWS VPC and ECS cluster,
* or it can create it's own VPC and cluster. By default it will create
* a cluster with Fargate capacity.
*/
export class Environment extends cdk.Construct {
export class Environment extends cdk.Construct implements IEnvironment {
/**
* Import an existing environment from its attributes.
*/
public static fromEnvironmentAttributes(scope: cdk.Construct, id: string, attrs: EnvironmentAttributes): IEnvironment {
return new ImportedEnvironment(scope, id, attrs);
}

/**
* The name of this environment.
*/
Expand Down Expand Up @@ -81,4 +118,47 @@ export class Environment extends cdk.Construct {
this.capacityType = EnvironmentCapacityType.FARGATE;
}
}

/**
* Add a default cloudmap namespace to the environment's cluster.
*/
addDefaultCloudMapNamespace(options: ecs.CloudMapNamespaceOptions) {
this.cluster.addDefaultCloudMapNamespace(options);
}
}

export interface EnvironmentAttributes {
/**
* The capacity type used by the service's cluster.
*/
capacityType: EnvironmentCapacityType;

/**
* The cluster that is providing capacity for this service.
*/
cluster: ecs.ICluster;
}

export class ImportedEnvironment extends cdk.Construct implements IEnvironment {
public readonly capacityType: EnvironmentCapacityType;
public readonly cluster: ecs.ICluster;
public readonly id: string;
public readonly vpc: ec2.IVpc;

constructor(scope: cdk.Construct, id: string, props: EnvironmentAttributes) {
super(scope, id);

this.id = id;
this.capacityType = props.capacityType;
this.cluster = props.cluster;
this.vpc = props.cluster.vpc;
}

/**
* Refuses to add a default cloudmap namespace to the cluster as we don't
* own it.
*/
addDefaultCloudMapNamespace(_options: ecs.CloudMapNamespaceOptions) {
throw new Error('the cluster environment is immutable when imported');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class AppMeshExtension extends ServiceExtension {
// Make sure that the parent cluster for this service has
// a namespace attached.
if (!this.parentService.cluster.defaultCloudMapNamespace) {
this.parentService.cluster.addDefaultCloudMapNamespace({
this.parentService.environment.addDefaultCloudMapNamespace({
// Name the namespace after the environment name.
// Service DNS will be like <service id>.<environment id>
name: this.parentService.environment.id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as ec2 from '@aws-cdk/aws-ec2';
import * as ecs from '@aws-cdk/aws-ecs';
import * as cdk from '@aws-cdk/core';
import { Environment } from './environment';
import { IEnvironment } from './environment';
import { EnvironmentCapacityType, ServiceBuild } from './extensions/extension-interfaces';
import { ServiceDescription } from './service-description';

Expand All @@ -17,7 +17,7 @@ export interface ServiceProps {
/**
* The environment to launch the service in
*/
readonly environment: Environment
readonly environment: IEnvironment
}

/**
Expand All @@ -44,7 +44,7 @@ export class Service extends cdk.Construct {
* The cluster that is providing capacity for this service
* [disable-awslint:ref-via-interface]
*/
public readonly cluster: ecs.Cluster;
public readonly cluster: ecs.ICluster;

/**
* The capacity type that this service will use
Expand All @@ -59,7 +59,7 @@ export class Service extends cdk.Construct {
/**
* The environment this service was launched in
*/
public readonly environment: Environment;
public readonly environment: IEnvironment;

/**
* The generated task definition for this service, is only
Expand Down
Loading

0 comments on commit d395b5e

Please sign in to comment.