Skip to content

Commit

Permalink
feat(aws-codedeploy): Added ability to tag EC2 and on-premise instanc…
Browse files Browse the repository at this point in the history
…es in Deployment Groups.
  • Loading branch information
skinny85 committed Oct 2, 2018
1 parent 6c523f2 commit 859a86d
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 0 deletions.
19 changes: 19 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,25 @@ const deploymentGroup = new codedeploy.ServerDeploymentGroup(this, 'CodeDeployDe
// adds User Data that installs the CodeDeploy agent on your auto-scaling groups hosts
// default: true
installAgent: true,
// adds EC2 instances matching tags
ec2InstanceTags: new codedeploy.InstanceTagSet(
{
// any instance with key1=v1 or key1=v2 or key2 (any value)
// tags will match this group
'key1': ['v1', 'v2'],
'key2': [],
},
),
// adds on-premise instances matching tags
onPremiseInstanceTags: new codedeploy.InstanceTagSet(
// only instances with tags k1=v1 AND k2=v2 will match this set
{
'key1': ['v1'],
},
{
'key2': ['v2'],
},
)
});
```

Expand Down
103 changes: 103 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,37 @@ class ImportedServerDeploymentGroupRef extends ServerDeploymentGroupRef {
}
}

/**
* Represents a group of instance tags.
* An instance will match a group if it has a tag matching
* any of the group's tags by name and any of the provided values -
* in other words, tag groups follow 'or' semantics.
* If the value for a given key is an empty array,
* an instance will match when it has a tag with the given key,
* regardless of the value.
*/
export interface InstanceTagGroup {
[key: string]: string[],
}

/**
* Represents a set of instance tag groups.
* An instance will match a set if it matches all of the groups in the set -
* in other words, sets follow 'and' semantics.
* You can have a maximum of 3 tag groups inside a set.
*/
export class InstanceTagSet {
public readonly instanceTagGroups: InstanceTagGroup[];

constructor(...instanceTagGroups: InstanceTagGroup[]) {
if (instanceTagGroups.length > 3) {
throw new Error('An instance tag set can have a maximum of 3 instance tag groups, ' +
`but ${instanceTagGroups.length} were provided`);
}
this.instanceTagGroups = instanceTagGroups;
}
}

/**
* Construction properties for {@link ServerDeploymentGroup}.
*/
Expand Down Expand Up @@ -143,6 +174,20 @@ export interface ServerDeploymentGroupProps {
* @see https://docs.aws.amazon.com/codedeploy/latest/userguide/codedeploy-agent-operations-install.html
*/
installAgent?: boolean;

/**
* All EC2 instances matching the given set of tags will be added to this Deployment Group.
*
* @default no additional EC2 instances will be added to the Deployment Group
*/
ec2InstanceTags?: InstanceTagSet;

/**
* All on-premise instances matching the given set of tags will be added to this Deployment Group.
*
* @default no additional on-premise instances will be added to the Deployment Group
*/
onPremiseInstanceTags?: InstanceTagSet;
}

/**
Expand Down Expand Up @@ -188,6 +233,8 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
this._autoScalingGroups.length === 0
? undefined
: this._autoScalingGroups.map(asg => asg.autoScalingGroupName())),
ec2TagSet: this.ec2TagSet(props.ec2InstanceTags),
onPremisesTagSet: this.onPremiseTagSet(props.onPremiseInstanceTags),
});

this.deploymentGroupName = resource.deploymentGroupName;
Expand Down Expand Up @@ -244,6 +291,62 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupRef {
break;
}
}

private ec2TagSet(tagSet?: InstanceTagSet):
cloudformation.DeploymentGroupResource.EC2TagSetProperty | undefined {
if (!tagSet || tagSet.instanceTagGroups.length === 0) {
return undefined;
}

return {
ec2TagSetList: tagSet.instanceTagGroups.map(tagGroup => {
return {
ec2TagGroup: this.tagGroup2TagsArray(tagGroup) as
cloudformation.DeploymentGroupResource.EC2TagFilterProperty[],
};
}),
};
}

private onPremiseTagSet(tagSet?: InstanceTagSet):
cloudformation.DeploymentGroupResource.OnPremisesTagSetProperty | undefined {
if (!tagSet || tagSet.instanceTagGroups.length === 0) {
return undefined;
}

return {
onPremisesTagSetList: tagSet.instanceTagGroups.map(tagGroup => {
return {
onPremisesTagGroup: this.tagGroup2TagsArray(tagGroup) as
cloudformation.DeploymentGroupResource.TagFilterProperty[],
};
}),
};
}

private tagGroup2TagsArray(tagGroup: InstanceTagGroup): any[] {
const tagsInGroup = [];
for (const tagKey in tagGroup) {
if (tagGroup.hasOwnProperty(tagKey)) {
const tagValues = tagGroup[tagKey];
if (tagValues.length > 0) {
for (const tagValue of tagValues) {
tagsInGroup.push({
key: tagKey,
value: tagValue,
type: 'KEY_AND_VALUE',
});
}
} else {
tagsInGroup.push({
key: tagKey,
type: 'KEY_AND_VALUE',
});
}
}
}
return tagsInGroup;
}
}

function deploymentGroupName2Arn(applicationName: string, deploymentGroupName: string): string {
Expand Down
89 changes: 89 additions & 0 deletions packages/@aws-cdk/aws-codedeploy/test/test.deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,94 @@ export = {

test.done();
},

'can be created with a single EC2 instance tag set with a single value'(test: Test) {
const stack = new cdk.Stack();

new codedeploy.ServerDeploymentGroup(stack, 'DeploymentGroup', {
ec2InstanceTags: new codedeploy.InstanceTagSet(
{
'some-key': ['some-value'],
'other-key': [],
},
),
});

expect(stack).to(haveResource('AWS::CodeDeploy::DeploymentGroup', {
"Ec2TagSet": {
"Ec2TagSetList": [
{
"Ec2TagGroup": [
{
"Key": "some-key",
"Value": "some-value",
"Type": "KEY_AND_VALUE",
},
{
"Key": "other-key",
"Type": "KEY_AND_VALUE",
},
],
},
],
},
}));

test.done();
},

'can be created with two on-premise instance tag sets with multiple values'(test: Test) {
const stack = new cdk.Stack();

new codedeploy.ServerDeploymentGroup(stack, 'DeploymentGroup', {
onPremiseInstanceTags: new codedeploy.InstanceTagSet(
{
'some-key': ['some-value', 'another-value'],
},
{
'other-key': [],
},
),
});

expect(stack).to(haveResource('AWS::CodeDeploy::DeploymentGroup', {
"OnPremisesTagSet": {
"OnPremisesTagSetList": [
{
"OnPremisesTagGroup": [
{
"Key": "some-key",
"Value": "some-value",
"Type": "KEY_AND_VALUE",
},
{
"Key": "some-key",
"Value": "another-value",
"Type": "KEY_AND_VALUE",
},
],
},
{
"OnPremisesTagGroup": [
{
"Key": "other-key",
"Type": "KEY_AND_VALUE",
},
],
},
],
},
}));

test.done();
},

'cannot be created with an instance tag set containing 4 instance tag groups'(test: Test) {
test.throws(() => {
new codedeploy.InstanceTagSet({}, {}, {}, {});
}, /3/i);

test.done();
},
},
};

0 comments on commit 859a86d

Please sign in to comment.