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

Feature Add Ability to Tag Subnets #458

Closed
wants to merge 3 commits into from

Conversation

moofish32
Copy link
Contributor

@moofish32 moofish32 commented Jul 31, 2018

This adds the ability to configure tags on subnets.

  • By default all subnets now will have a Name tag so that they show up nicely in the UI
  • Tags added to SubnetConfiguration will be applied to all subnets created

Questions:

  • Are there issues with the default?
  • Docs still go in the README for now?
  • Test was a bit painful, is there something we should extract?
  • Do we need to support modification of the tags via the VpcSubnet classes? This would appear to be difficult with constructor based creation flow. Update - we can support this with the cdk.Token function capability. I will modify to add this, unless I'm told this is the wrong path. I will follow a pattern similar to attachToClassicLB in auto-scaling-group.ts

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.

`SubnetConfiguration` interfaces; add a default `Name` tag if
none are provided
…id changing VpcSubnetRef because that caused additional breaks in Java code
Copy link
Contributor Author

@moofish32 moofish32 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the addTags function to VpcSubnet

I also made a few comments about the implementation that I was not positive I did correctly.

* The AWS resource tags to associate with the Subnet.
*
*/
tags?: cdk.Tag[];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everywhere I exposed to the customer I tried to use cdk.Tag but internally I need to use cdk.Token to get the lazy evaluation. I'm not sure if this is the right pattern or not?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make more sense for this to just be { [key: string]: any }?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should I never use cdk.Tag the { [key: string]: any } was my original thought. Then I found VpcNetworkProps used tags?: cdk.Tag[] so I pivoted. So two questions:

  • should we not use cdk.Tag in any L2s?
  • is there any reason this is not { [key: string]: string } I don't have a use case yet, but seems to rigid?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should deprecate cdk.Tag. Not sure what value it brings to this world...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eladb and the second question here about { [key: string]: string } vs any?

{ Key: 'AddedTag', Value: 'NewThing' },
])
));
(myVpc.publicSubnets as VpcSubnet[]).forEach((subnet) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to change vpc.publicSubnets to be type VpcSubnet instead of VpcSubnetRef because that made a lot of sense based on both file location and the change I am making. However, this breaks part of the java test cases. Is that an indication of an agreed to convention that is for now required or is that open for debate?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

publicSubnets is part of the API of VpcNetworkRef which can represent either a VPC defined in your stack or an imported VPC, which is a very important use case (see #506). Therefore, we also want the subnets to use the XxxRef version, so they represent a more abstract notion.

There's a little bit of documentation about imports under the AWS Construct Library topic in our docs. We should probably improve it...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RE: Imports

I was under the impression (from reading the Importing section of https://awslabs.github.io/aws-cdk/refs/_aws-cdk_aws-certificatemanager.html) that you had to export a construct before you could import it

Copy link
Contributor

@eladb eladb Aug 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XxxRef.import() static methods accept a set of props. If you can satisfy them, you can instantiate an XxxRef. For example, BucketRef.import asks for two (optional) attributes: bucketName and bucketArn. If you provide one of them, the other can be deduced, so:

const importedBucket = Bucket.import(this, 'MyImportedBucket', { bucketName: 'my_bucket' });

Would return a BucketRef instance associated with an existing bucket named my_bucket.

Other resources may have different heuristics for imports (for example, VPCs need much more information in order to be usable).

When you export something, it will produce a set of Outputs and return a set of Fn::ImportValue tokens that match the same set of props needed for import, so you can export/import across stack boundaries:

const exportedFoo = fooBucket.export();

// then in another stack:
const importedFoo = Bucket.import(this, 'ImportedFoo', exportedFoo);

Should we expand on the this topic?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a stab at updating the topic. Watch for a new PR soon.

@PaulMaddox
Copy link
Contributor

Thank you for adding this. I was just creating a CDK project to deploy some K8s/EKS stuff and realised I was blocked as EKS requires specific tags on subnets to indicate to K8s their purpose.

+1 for the default Name tag being created if not overridden by the user. I wonder if this is something we could introduce elsewhere / make more generic in the future.

@eladb
Copy link
Contributor

eladb commented Aug 2, 2018

@moofish32 sorry we haven't been super responsive. We are heads down with the launch this week. We'll get back to you with feedback next week. In the meantime, see #91 for some initial discussion on cross-cutting tag support. I am not saying we need to implement this right now, but maybe worth chiming in on the discussion if you have some insights

@moofish32 moofish32 mentioned this pull request Aug 2, 2018
@moofish32
Copy link
Contributor Author

@PaulMaddox -- I have some interest in EKS, ping me in gitter chat if you want to discuss. In particular I'm curious on your Service Broker thoughts and potentially replacing the ansible aspect with CDK.

@moofish32
Copy link
Contributor Author

@eladb @PaulMaddox @rix0rrr -- coming back to this issue from the comment. I'm open to requesting merge here. I think I can pick up #91 now that @eladb enlightened me. I lean towards merge because I think #91 will take more review time and the team is quite busy; with this @PaulMaddox can move forward with some EKS use cases. I'll of course clean this up and I don't see any reason it would be a breaking change when we close #91.


/**
* The AWS resource tags to associate with the Subnet.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant newline

* The AWS resource tags to associate with the Subnet.
*
*/
tags?: cdk.Tag[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make more sense for this to just be { [key: string]: any }?

@@ -400,7 +407,8 @@ export class VpcNetwork extends VpcNetworkRef {
vpcId: this.vpcId,
cidrBlock: this.networkBuilder.addSubnet(cidrMask),
mapPublicIpOnLaunch: (subnetConfig.subnetType === SubnetType.Public),
};
tags: subnetConfig.tags,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation?

/**
* The AWS resource tags to associate with the Subnet.
*/
tags?: cdk.Tag[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map == { [key: string]: any}?

/**
* The tags for this subnet
*/
private readonly tags: cdk.Token[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to store these as Tokens internally. Just store a hash and initialize it like this:

this.tags = {
  Name: this.path,
  ...(this.props.tags || {}) // if props.tags contains "Name" it will be overridden by the splat
};

Then use a token to "lazy render" to CloudFormation:

const subnet = new cloudformation.SubnetResource(this, 'Subnet', {
    // ...
    tags: new Token(() => Object.keys(this.tags).map(key => ({ key, value: this.tags[key] })))
};

(you can also create a helper function if you think it's more readable)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have this in my work for #91 - thinking it might be better just to MVP that solution and only enable VPC first. I need to pivot away from cdk.Tag as mentioned above.

if (props.tags !== undefined) {
this.tags = props.tags.map( tag => new cdk.Token(tag) );
if (props.tags.filter( tag => tag.key === 'Name' ).length !== 1) {
this.tags.push(new cdk.Token({key: 'Name', value: name}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use this.path instead of name as the default. name is a local logical identity and path is globally unique within the stack, and provides much more context.

Copy link
Contributor Author

@moofish32 moofish32 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple of questions.

* The AWS resource tags to associate with the Subnet.
*
*/
tags?: cdk.Tag[];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should I never use cdk.Tag the { [key: string]: any } was my original thought. Then I found VpcNetworkProps used tags?: cdk.Tag[] so I pivoted. So two questions:

  • should we not use cdk.Tag in any L2s?
  • is there any reason this is not { [key: string]: string } I don't have a use case yet, but seems to rigid?

/**
* The AWS resource tags to associate with the Subnet.
*/
tags?: cdk.Tag[];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map == { [key: string]: any}?

/**
* The tags for this subnet
*/
private readonly tags: cdk.Token[] = [];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have this in my work for #91 - thinking it might be better just to MVP that solution and only enable VPC first. I need to pivot away from cdk.Tag as mentioned above.

moofish32 added a commit to moofish32/aws-cdk that referenced this pull request Aug 23, 2018
Fixes aws#91, Closes aws#458 (as obsolete)

The TagManager is a class Construct authors can use to implement tagging
consistently. The manager provides the ability to propagate tags from
parents to child, override parent tags in the child, set default tags on
the child that can be overwritten by parents, and block tags from
parents.

Adding tagging support for the Vpc and Subnet constructs.
moofish32 added a commit to moofish32/aws-cdk that referenced this pull request Aug 24, 2018
Fixes aws#91, Closes aws#458 (as obsolete)

The TagManager is a class Construct authors can use to implement tagging
consistently. The manager provides the ability to propagate tags from
parents to child, override parent tags in the child, set default tags on
the child that can be overwritten by parents, and block tags from
parents.

Adding tagging support for the Vpc and Subnet constructs.
@moofish32
Copy link
Contributor Author

Closing this PR in favor #538

@moofish32 moofish32 closed this Aug 27, 2018
eladb pushed a commit that referenced this pull request Sep 3, 2018
Construct authors can use `TagManager` implement tagging consistently. 
The manager provides the ability to propagate tags from
parents to child, override parent tags in the child, set default tags on
the child that can be overwritten by parents, and block tags from
parents.

Fixes #91, Closes #458 (as obsolete)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants