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

feat(cdk): adding tags parameter option to cdk deploy command #2185

Merged
merged 29 commits into from
Jun 3, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
98226c1
feat(cdk): adding tags parameter option to cdk deploy command to allo…
IsmaelMartinez Apr 5, 2019
26c8921
feat(cdk) removing duplicated code and adding missing semicolons
IsmaelMartinez Apr 5, 2019
0ee589a
feat(cdk): #2185 Reading the stack metadata to find tags if no tags o…
IsmaelMartinez Apr 8, 2019
6444ba4
Removing print from getTagsFromStackMetadata
IsmaelMartinez Apr 8, 2019
14c08df
feat(cdk): #2185 Changes from PR comments
IsmaelMartinez Apr 11, 2019
71883f2
Changes from PR comments. Fixing build
IsmaelMartinez Apr 11, 2019
9defac8
Correcting copy/paste error and changing the name to TAGS_METADATA_KE…
IsmaelMartinez Apr 11, 2019
e046be6
Correcting copy/paste error and changing the name to TAGS_METADATA_KE…
IsmaelMartinez Apr 11, 2019
caaeff5
WIP with tag aspects
IsmaelMartinez Apr 22, 2019
17addb8
Merge branch 'master' into ismaelmartinez/feat-add-tags-option-cdk-de…
IsmaelMartinez Apr 22, 2019
c504b6f
Merge remote-tracking branch 'upstream/master' into ismaelmartinez/fe…
IsmaelMartinez Apr 24, 2019
ca252b0
WIP
IsmaelMartinez Apr 24, 2019
5e43a64
Adding the tags via properties and the stack.node.apply. WIP
IsmaelMartinez Apr 26, 2019
53f0158
Adding the tags via properties and the stack.node.apply. WIP
IsmaelMartinez Apr 26, 2019
408d7fa
Merge branch 'master' into ismaelmartinez/feat-add-tags-option-cdk-de…
IsmaelMartinez Apr 26, 2019
8eed2c8
changes from comments
IsmaelMartinez May 2, 2019
90fc71f
Only adding the metadata when there are tags
IsmaelMartinez May 3, 2019
d0cc809
Adding some tests for the KeyValue and hasTags in tag-manager
IsmaelMartinez May 3, 2019
bc1bb26
Moving the isTaggable to the Contructor and tidying up after code rev…
IsmaelMartinez May 6, 2019
c1e3e22
Merge remote-tracking branch 'upstream/master' into ismaelmartinez/fe…
IsmaelMartinez May 30, 2019
bbeebd2
Changes to address most of the code review comments
IsmaelMartinez May 31, 2019
196b2ca
Reverting the move of the check for if the resource/stack is taggable…
IsmaelMartinez May 31, 2019
08eb2b3
Fixing the build (alphabeticall order of imports)
IsmaelMartinez May 31, 2019
f0a219e
Moving isTaggable from the constructor to the TagManager
IsmaelMartinez Jun 3, 2019
0e3c101
renaming TAGS_METADATA_KEY to STACK_TAGS_METADATA_KEY and moving it t…
IsmaelMartinez Jun 3, 2019
4d97f7c
Missing fixes from code review changes
IsmaelMartinez Jun 3, 2019
26d1870
Fixing build
IsmaelMartinez Jun 3, 2019
d04c9c1
Fixing an issue with the tags not been populated if pass via the cons…
IsmaelMartinez Jun 3, 2019
bf518e3
Adding docs
IsmaelMartinez Jun 3, 2019
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
5 changes: 3 additions & 2 deletions packages/aws-cdk/bin/cdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ async function parseCommandLineArguments() {
.option('exclusively', { type: 'boolean', alias: 'e', desc: 'only deploy requested stacks, don\'t include dependencies' })
.option('require-approval', { type: 'string', choices: [RequireApproval.Never, RequireApproval.AnyChange, RequireApproval.Broadening], desc: 'what security-sensitive changes need manual approval' }))
.option('ci', { type: 'boolean', desc: 'Force CI detection. Use --no-ci to disable CI autodetection.', default: process.env.CI !== undefined })
.option('tags', { type: 'array', alias: 't', desc: 'tags to add to the stack', nargs: 1, requiresArg: 'KEY=VALUE'})
.command('destroy [STACKS..]', 'Destroy the stack(s) named STACKS', yargs => yargs
.option('exclusively', { type: 'boolean', alias: 'x', desc: 'only deploy requested stacks, don\'t include dependees' })
.option('force', { type: 'boolean', alias: 'f', desc: 'Do not ask for confirmation before destroying the stacks' }))
Expand Down Expand Up @@ -105,7 +106,6 @@ async function initCommandLine() {
proxyAddress: argv.proxy,
ec2creds: argv.ec2creds,
});

const configuration = new Configuration(argv);
await configuration.load();

Expand Down Expand Up @@ -198,7 +198,8 @@ async function initCommandLine() {
roleArn: args.roleArn,
requireApproval: configuration.settings.get(['requireApproval']),
ci: args.ci,
reuseAssets: args['build-exclude']
reuseAssets: args['build-exclude'],
tags: configuration.settings.get(['tags'])
});

case 'destroy':
Expand Down
27 changes: 27 additions & 0 deletions packages/aws-cdk/lib/api/cxapp/stacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export interface AppStacksProps {
* In a class because it shares some global state
*/
export class AppStacks {

IsmaelMartinez marked this conversation as resolved.
Show resolved Hide resolved
/**
* Since app execution basically always synthesizes all the stacks,
* we can invoke it once and cache the response for subsequent calls.
Expand Down Expand Up @@ -225,6 +226,22 @@ export class AppStacks {
}
}

public getTagsFromStackMetadata(stack: SelectedStack): Tags {
const tags = [];
for (const id of Object.keys(stack.metadata)) {
const metadata = stack.metadata[id];
for (const entry of metadata) {
switch (entry.type) {
IsmaelMartinez marked this conversation as resolved.
Show resolved Hide resolved
case "Tags":
IsmaelMartinez marked this conversation as resolved.
Show resolved Hide resolved
for (const tag of entry.data) {
tags.push(new Tag(tag.key, tag.value));
}
}
}
}
return tags;
}

/**
* Extracts 'aws:cdk:warning|info|error' metadata entries from the stack synthesis
*/
Expand Down Expand Up @@ -373,3 +390,13 @@ export interface SelectedStack extends cxapi.SynthesizedStack {
*/
originalName: string;
}

export type Tags = Tag[];
IsmaelMartinez marked this conversation as resolved.
Show resolved Hide resolved
export class Tag {
public readonly Key: string;
public Value: string;
constructor(key: string, value: string) {
this.Key = key;
this.Value = value;
}
}
5 changes: 4 additions & 1 deletion packages/aws-cdk/lib/api/deploy-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import cxapi = require('@aws-cdk/cx-api');
import aws = require('aws-sdk');
import colors = require('colors/safe');
import uuid = require('uuid');
import { Tags } from "../api/cxapp/stacks";
import { prepareAssets } from '../assets';
import { debug, error, print } from '../logging';
import { toYAML } from '../serialize';
Expand Down Expand Up @@ -32,6 +33,7 @@ export interface DeployStackOptions {
quiet?: boolean;
ci?: boolean;
reuseAssets?: string[];
tags?: Tags;
}

const LARGE_TEMPLATE_SIZE_KB = 50;
Expand Down Expand Up @@ -73,7 +75,8 @@ export async function deployStack(options: DeployStackOptions): Promise<DeploySt
TemplateURL: bodyParameter.TemplateURL,
Parameters: params,
RoleARN: options.roleArn,
Capabilities: [ 'CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND' ]
Capabilities: [ 'CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND' ],
Tags: options.tags
IsmaelMartinez marked this conversation as resolved.
Show resolved Hide resolved
}).promise();
debug('Initiated creation of changeset: %s; waiting for it to finish creating...', changeSet.Id);
const changeSetDescription = await waitForChangeSet(cfn, deployName, changeSetName);
Expand Down
3 changes: 3 additions & 0 deletions packages/aws-cdk/lib/api/deployment-target.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import cxapi = require('@aws-cdk/cx-api');
import { Tags } from "../api/cxapp/stacks";
import { debug } from '../logging';
import { deserializeStructure } from '../serialize';
import { Mode } from './aws-auth/credentials';
Expand Down Expand Up @@ -28,6 +29,7 @@ export interface DeployStackOptions {
ci?: boolean;
toolkitStackName?: string;
reuseAssets?: string[];
tags?: Tags;
}

export interface ProvisionerProps {
Expand Down Expand Up @@ -71,6 +73,7 @@ export class CloudFormationDeploymentTarget implements IDeploymentTarget {
ci: options.ci,
reuseAssets: options.reuseAssets,
toolkitInfo,
tags: options.tags
});
}
}
14 changes: 12 additions & 2 deletions packages/aws-cdk/lib/cdk-toolkit.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import colors = require('colors/safe');
import fs = require('fs-extra');
import { format, promisify } from 'util';
import { AppStacks, ExtendedStackSelection } from "./api/cxapp/stacks";
import { AppStacks, ExtendedStackSelection, Tags } from "./api/cxapp/stacks";
import { IDeploymentTarget } from './api/deployment-target';
import { printSecurityDiff, printStackDiff, RequireApproval } from './diff';
import { data, error, highlight, print, success } from './logging';
Expand Down Expand Up @@ -109,6 +109,10 @@ export class CdkToolkit {
print('%s: deploying...', colors.bold(stack.name));
}

if (!options.tags || options.tags.length === 0) {
options.tags = this.appStacks.getTagsFromStackMetadata(stack);
}

try {
const result = await this.provisioner.deployStack({
stack,
Expand All @@ -117,6 +121,7 @@ export class CdkToolkit {
ci: options.ci,
toolkitStackName: options.toolkitStackName,
reuseAssets: options.reuseAssets,
tags: options.tags
});

const message = result.noOp
Expand Down Expand Up @@ -230,4 +235,9 @@ export interface DeployOptions {
* Reuse the assets with the given asset IDs
*/
reuseAssets?: string[];
}

/**
* Tags to pass to CloudFormation for deployment
*/
tags?: Tags;
}
53 changes: 38 additions & 15 deletions packages/aws-cdk/lib/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import fs = require('fs-extra');
import os = require('os');
import fs_path = require('path');
import yargs = require('yargs');
import { Tag, Tags } from './api/cxapp/stacks';
import { debug, warning } from './logging';
import util = require('./util');

Expand Down Expand Up @@ -177,32 +178,21 @@ export class Context {
* A single bag of settings
*/
export class Settings {

/**
* Parse Settings out of CLI arguments.
* @param argv the received CLI arguments.
* @returns a new Settings object.
*/
public static fromCommandLineArguments(argv: yargs.Arguments): Settings {
const context: any = {};

// Turn list of KEY=VALUE strings into an object
for (const assignment of ((argv as any).context || [])) {
const parts = assignment.split('=', 2);
if (parts.length === 2) {
debug('CLI argument context: %s=%s', parts[0], parts[1]);
if (parts[0].match(/^aws:.+/)) {
throw new Error(`User-provided context cannot use keys prefixed with 'aws:', but ${parts[0]} was provided.`);
}
context[parts[0]] = parts[1];
} else {
warning('Context argument is not an assignment (key=value): %s', assignment);
}
}
const context = this.parseStringContextListToObject(argv);
const tags = this.parseStringTagsListToObject(argv);

return new Settings({
app: argv.app,
browser: argv.browser,
context,
tags,
language: argv.language,
pathMetadata: argv.pathMetadata,
assetMetadata: argv.assetMetadata,
Expand All @@ -221,6 +211,39 @@ export class Settings {
return ret;
}

private static parseStringContextListToObject(argv: yargs.Arguments) {
IsmaelMartinez marked this conversation as resolved.
Show resolved Hide resolved
const context: any = {};

for (const assignment of ((argv as any).context || [])) {
const parts = assignment.split('=', 2);
if (parts.length === 2) {
debug('CLI argument context: %s=%s', parts[0], parts[1]);
if (parts[0].match(/^aws:.+/)) {
throw new Error(`User-provided context cannot use keys prefixed with 'aws:', but ${parts[0]} was provided.`);
}
context[parts[0]] = parts[1];
} else {
warning('Context argument is not an assignment (key=value): %s', assignment);
}
}
return context;
}

private static parseStringTagsListToObject(argv: yargs.Arguments) {
const tags: Tags = [];

for (const assignment of ((argv as any).tags || [])) {
const parts = assignment.split('=', 2);
if (parts.length === 2) {
debug('CLI argument tags: %s=%s', parts[0], parts[1]);
tags.push(new Tag(parts[0], parts[1]));
} else {
warning('Tags argument is not an assignment (key=value): %s', assignment);
}
}
return tags;
}

constructor(private settings: SettingsMap = {}, public readonly readOnly = false) {}

public async load(fileName: string): Promise<this> {
Expand Down