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(redshift-alpha): directly add parameters to a parameter group or indirectly through a cluster #20944

Merged
merged 25 commits into from
Sep 9, 2022

Conversation

dontirun
Copy link
Contributor

@dontirun dontirun commented Jul 1, 2022

Closes #20656

This PR enables users to directly add parameters to a ClusterParameterGroup or indirectly through a Cluster. There are a few reasons why this would not succeed, such as the parameter already existing or trying to add parameters to an Imported Parameter Group and/or Cluster. With this in mind, the methods return a AddParameterResultStatus which let's developers handle failure cases more elegantly.

Ex. On SUCCESS or SAME_VALUE_FAILURE do nothing, but on CONFLICTING_VALUE_FAILURE or IMPORTED_RESOURCE_FAILURE throw some sort of error indicating what you need the developer to do in their application to resolve the issue.

This is very useful in the case of vending constructs that take in a Redshift Cluster as an input. See #20656 for more context.

I don't think this is significant enough to be called out in the README with an example, but happy to add one if necessary.


All Submissions:

Adding new Unconventional Dependencies:

  • This PR adds new unconventional dependencies following the process described here

New Features

  • Have you added the new feature to an integration test?
    • Did you use yarn integ to deploy the infrastructure and generate the snapshot (i.e. yarn integ without --dry-run)?

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

@gitpod-io
Copy link

gitpod-io bot commented Jul 1, 2022

@aws-cdk-automation aws-cdk-automation requested a review from a team July 1, 2022 01:24
@github-actions github-actions bot added the p2 label Jul 1, 2022
Copy link
Contributor

@comcalvi comcalvi left a comment

Choose a reason for hiding this comment

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

This is a preliminary pass, as there are some things happening that I don't understand in this PR. Can you please add more detail to the PR description?

packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
@mergify mergify bot dismissed comcalvi’s stale review July 15, 2022 21:34

Pull request has been modified.

@dontirun
Copy link
Contributor Author

Going off of some of my previous comments I updated the Import class in fromClusterParameterGroupName to extend ClusterParameterGroupBase. It didn't affect the unit tests and I think it's a better implementation that is also more consistent with other implementations. I can revert that if needed

@dontirun dontirun requested a review from comcalvi July 15, 2022 22:05
@dontirun
Copy link
Contributor Author

dontirun commented Aug 1, 2022

@comcalvi Do you mind re-reviewing this PR?

Copy link
Contributor

@TheRealAmazonKendra TheRealAmazonKendra left a comment

Choose a reason for hiding this comment

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

New features require a README update. The act of writing the README often helps you assess your approach better and it gives us additional context when reviewing to understand the user experience. Additionally, we generate our documentation from there so it is needed.

I think there are some design issues here and need to be addressed. I also have a lot of questions about what's going on, which tells me that README is especially needed.

packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
@@ -374,6 +393,10 @@ abstract class ClusterBase extends Resource implements ICluster {
targetType: secretsmanager.AttachmentTargetType.REDSHIFT_CLUSTER,
};
}

public addToParameterGroup(_name: string, _value: string): AddParameterResult {
return { parameterAddedResult: AddParameterResultStatus.IMPORTED_RESOURCE_FAILURE };
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does this just plain return a failure?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For addToParameterGroup in the Cluster construct, this method should fail for all imported resources since we can't add parameters to them. The L2 Cluster class is the only class that it wouldn't fail on. Any of the static import methods such as fromClusterAttributes should fail since they are imported resources. In the future there could potentially be more static methods that create imported resources from ClusterBase which inherit this method but I don't think there would be another instantiated Cluster class that extends ClusterBase; so I thought the default should be the failure.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why can't we add parameters to imported Clusters?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In CloudFormation, the Cluster is has a property to specify a Parameter Group name . Parameter Groups don't have a property to tie them to a Cluster. That means that the association must be done on the side of the Cluster. I didn't think we could modify imports like that.

Additionally if we could modify imports, we could be potentially overriding an existing association since a Cluster can only have one parameter group associated with it at a time

packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@comcalvi comcalvi left a comment

Choose a reason for hiding this comment

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

There are some things about this approach that I still don't understand. Overall, I agree with @TheRealAmazonKendra. This is getting closer, but still needs some work.

packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
@@ -374,6 +393,10 @@ abstract class ClusterBase extends Resource implements ICluster {
targetType: secretsmanager.AttachmentTargetType.REDSHIFT_CLUSTER,
};
}

public addToParameterGroup(_name: string, _value: string): AddParameterResult {
return { parameterAddedResult: AddParameterResultStatus.IMPORTED_RESOURCE_FAILURE };
Copy link
Contributor

Choose a reason for hiding this comment

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

Why can't we add parameters to imported Clusters?

packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
} else if (this.parameterGroup) {
return this.parameterGroup.addParameter(name, value);
} else {
return { parameterAddedResult: AddParameterResultStatus.IMPORTED_RESOURCE_FAILURE };
Copy link
Contributor

Choose a reason for hiding this comment

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

Please throw errors instead of returning failures. However, I still don't understand why these operations default to failures. What about the resource being imported prevents it from succeeding?

Regardless of why it fails for imported resources, the import should not be considered the default behavior anyway. Imports are the 'special-ish' case.

packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
@@ -22,6 +35,10 @@ abstract class ClusterParameterGroupBase extends Resource implements IClusterPar
* The name of the parameter group
*/
public abstract readonly clusterParameterGroupName: string;

public addParameter(_name: string, _value: string): AddParameterResult {
return { parameterAddedResult: AddParameterResultStatus.IMPORTED_RESOURCE_FAILURE };
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree. The add operation should not default to failure. Failure should be the exception.

@@ -51,7 +102,7 @@ export class ClusterParameterGroup extends ClusterParameterGroupBase {
* Imports a parameter group
*/
public static fromClusterParameterGroupName(scope: Construct, id: string, clusterParameterGroupName: string): IClusterParameterGroup {
class Import extends Resource implements IClusterParameterGroup {
class Import extends ClusterParameterGroupBase {
Copy link
Contributor

Choose a reason for hiding this comment

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

The import may implement the abstract methods, but I don't think we need to change this at this time; this is out-of-scope.

@mergify mergify bot dismissed stale reviews from comcalvi and TheRealAmazonKendra August 5, 2022 16:51

Pull request has been modified.

packages/@aws-cdk/aws-redshift/README.md Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/README.md Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/README.md Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/cluster.ts Show resolved Hide resolved
/**
* Identifier of the cluster
*/
protected clusterIdentifier: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
protected clusterIdentifier: string;
protected clusterId: string;

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, is this necessary at all? I only see one place where this is used and this.clusterName could just as easily be used in that place. I'm not seeing the value add.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably not needed. I thought that the clusterIdentifier would make the description in the parameter group a a little nicer.

Given that the cluster is now a field, it could be taken from that as well

Copy link
Contributor

Choose a reason for hiding this comment

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

We should use clusterName instead of creating this new field.

Copy link
Contributor Author

@dontirun dontirun Aug 6, 2022

Choose a reason for hiding this comment

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

That field was removed and replaced with this logic instead. clusterName could not be used since it caused a circular dependency. (Parameter group description field containing a ref to the Cluster, Cluster's group name field containing a ref to the Parameter Group).


if (secret) {
this.secret = secret.attach(this);
}

const defaultPort = ec2.Port.tcp(this.clusterEndpoint.port);
this.connections = new ec2.Connections({ securityGroups, defaultPort });
this.clusterIdentifier = props.clusterName ?? Names.uniqueResourceName(this, {});
Copy link
Contributor

Choose a reason for hiding this comment

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

clusterName here would never be undefined because it's being set to the ref.

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 think this is a case of poorly named variables. props.clusterName != this.clusterName. The clusterName prop is either a string or undefined and is being used as the CfnCluster's clusterIdentifier property

packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-redshift/lib/parameter-group.ts Outdated Show resolved Hide resolved
@mergify mergify bot dismissed TheRealAmazonKendra’s stale review August 6, 2022 04:13

Pull request has been modified.

@TheRealAmazonKendra
Copy link
Contributor

@Mergifyio update

@mergify
Copy link
Contributor

mergify bot commented Aug 6, 2022

update

✅ Branch has been successfully updated

Copy link
Contributor

@TheRealAmazonKendra TheRealAmazonKendra left a comment

Choose a reason for hiding this comment

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

Looks like the integ tests still need to be updated with the output from the suggested changes.

@mergify mergify bot dismissed TheRealAmazonKendra’s stale review August 6, 2022 15:08

Pull request has been modified.

Copy link
Contributor

@TheRealAmazonKendra TheRealAmazonKendra left a comment

Choose a reason for hiding this comment

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

Some requested changes still not addressed.

@dontirun
Copy link
Contributor Author

dontirun commented Aug 6, 2022

I believe they have been addressed, the comments look to be on outdated code

@mergify mergify bot dismissed TheRealAmazonKendra’s stale review August 25, 2022 15:20

Pull request has been modified.

@dontirun
Copy link
Contributor Author

@TheRealAmazonKendra Can you re-review this? I believe I've addressed the requested changes

Copy link
Contributor

@TheRealAmazonKendra TheRealAmazonKendra left a comment

Choose a reason for hiding this comment

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

Thanks for all your work on this! I have several comments below.

Apologies for not thinking about the ability to add multiple parameters at a time in a previous revision, but I'm thinking that if it's a use case that seem likely, going that direction would be significantly better.

packages/@aws-cdk/aws-redshift/lib/cluster.ts Outdated Show resolved Hide resolved
Comment on lines 320 to 322
```ts fixture=cluster
cluster.addToParameterGroup('enable_user_activity_logging', 'true');
```
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't rendering correctly. I suspect that the issue is the fixture=cluster piece causing it.

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'll fix it for the example in this PR and raise an issue. Looking at the documentation it's also not rendering for the other examples using fixture=cluster

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually I think none of the fixtures (even the default) are loading properly for the redshift alpha library

Copy link
Contributor Author

Choose a reason for hiding this comment

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

const param: { [name: string]: string } = {};
param[name] = value;
this.parameterGroup = new ClusterParameterGroup(this, 'ParameterGroup', {
description: `Parameter Group for the ${this.cluster.clusterIdentifier ?? Names.uniqueResourceName(this, {})} Redshift cluster`,
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 now that you are using this.cluster.clusterIdentifier, Names.uniqueResourceId is no longer needed in this context.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The clusterIdentifier can be undefined. It's being set to the optional clusterName prop

Copy link
Contributor

Choose a reason for hiding this comment

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

Right, that happens before this.clusterName is set to this.cluster.ref.

I think that I suggested using Names.uniqueResourceName instead of Names.uniqueResourceId somewhere in here, but since it wasn't used there, it doesn't make sense to use it here. It won't be named that and we'd be giving false information.

You can set

clusterIdentifier: props.clusterName ?? Names.uniqueResourceName(this), {
  maxLength: 63,
  separator: '-',
  allowedSpecialCharacters: '-',
}

up on line 528. That would work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed with the false information.

It looks like the cluster Identifier needs to be unique account wide. So instead of setting the name to with Names.uniqueResourceName I think it might be better to fall back to the paramter group default description if the identifier isn't provided

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the Names.uniqueResourceName and falling back to the default

packages/@aws-cdk/aws-redshift/lib/cluster.ts Show resolved Hide resolved
@@ -32,6 +32,8 @@ const cluster = new redshift.Cluster(stack, 'Cluster', {
encryptionKey: new kms.Key(stack, 'custom-kms-key'),
});

cluster.addToParameterGroup('enable_user_activity_logging', 'true');
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to see more test cases. One where the parameters are added directly in the constructor and one where addParameter() is used. Or rather, addParameters() if you take my suggestion above.

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'll add some more tests to the cluster.test.ts for this. I don't think we need to update the integration test for this (unless we do change to addParameters())

@TheRealAmazonKendra TheRealAmazonKendra changed the title feat(redshift-alpha): directly add parameters to a Parameter Group or indirectly through a Cluster feat(redshift-alpha): directly add parameters to a parameter group or indirectly through a cluster Sep 3, 2022
@mergify mergify bot dismissed TheRealAmazonKendra’s stale review September 3, 2022 11:34

Pull request has been modified.

this.parameters[name] = value;
this.resource.parameters = this.parseParameters();
} else if (existingValue !== value) {
throw new Error(`The parameter group already contains the parameter "${name}", but with a different value (Given: ${value}, Existing: ${existingValue}).`);
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's add the name of the parameter group in here in case the user has an app with multiple.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Parameter groups don't have names, but I agree that it makes sense to identify it somehow , so maybe it makes sense to use Names.uniqueResourceName here

  throw new Error(`The parameter group id "${Names.uniqueResourceName(this, {})}" already contains the parameter "${name}", but with a different value (Given: ${value}, Existing: ${existingValue}).`);

Copy link
Contributor

Choose a reason for hiding this comment

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

See my most recent comment below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this case it's set to the Instrinsic Ref of CfnClusterParameterGroup, so the error message would contain a Token.

Considering that this is runtime error, I think using Names.uniqueResourceName (along with the stack trace) should be helpful enough to locate the problematic parameter group

Copy link
Contributor

Choose a reason for hiding this comment

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

This would be providing the customer with inaccurate information. Sure, it's an approximation, but it's not actually the name of the resource. I suppose the stack trace will have to provide enough information in conjunction with the key value pair they're trying to add.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted back to this message in the latest commit

const param: { [name: string]: string } = {};
param[name] = value;
this.parameterGroup = new ClusterParameterGroup(this, 'ParameterGroup', {
description: `Parameter Group for the ${this.cluster.clusterIdentifier ?? Names.uniqueResourceName(this, {})} Redshift cluster`,
Copy link
Contributor

Choose a reason for hiding this comment

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

Right, that happens before this.clusterName is set to this.cluster.ref.

I think that I suggested using Names.uniqueResourceName instead of Names.uniqueResourceId somewhere in here, but since it wasn't used there, it doesn't make sense to use it here. It won't be named that and we'd be giving false information.

You can set

clusterIdentifier: props.clusterName ?? Names.uniqueResourceName(this), {
  maxLength: 63,
  separator: '-',
  allowedSpecialCharacters: '-',
}

up on line 528. That would work.

@@ -62,17 +63,46 @@ export class ClusterParameterGroup extends ClusterParameterGroupBase {
*/
public readonly clusterParameterGroupName: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't a parameter group name?

@mergify mergify bot dismissed TheRealAmazonKendra’s stale review September 7, 2022 15:12

Pull request has been modified.

@mergify
Copy link
Contributor

mergify bot commented Sep 9, 2022

Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: fa4f365
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@mergify mergify bot merged commit 0ad307b into aws:main Sep 9, 2022
@mergify
Copy link
Contributor

mergify bot commented Sep 9, 2022

Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

Kruspe pushed a commit to DavidSchwarz2/aws-cdk that referenced this pull request Sep 13, 2022
… indirectly through a cluster (aws#20944)

Closes [aws#20656](aws#20656)


This PR enables users to directly add parameters to a `ClusterParameterGroup` or indirectly through a `Cluster`. There are a few reasons why this would not succeed, such as the parameter already existing or trying to add parameters to an Imported Parameter Group and/or Cluster. With this in mind, the methods return a  `AddParameterResultStatus` which let's developers handle failure cases more elegantly.

Ex. On `SUCCESS` or `SAME_VALUE_FAILURE` do nothing, but on `CONFLICTING_VALUE_FAILURE` or `IMPORTED_RESOURCE_FAILURE` throw some sort of error indicating what you need the developer to do in their application to resolve the issue.

This is very useful in the case of vending constructs that take in a Redshift Cluster as an input. See aws#20656 for more context.

I don't think this is significant enough to be called out in the README with an example, but happy to add one if necessary.


----

### All Submissions:

* [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [X] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [X] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
@dontirun dontirun deleted the dynamic-redshift-parameter-groups branch October 10, 2022 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

redshift: dynamically add key/value pairs to parameter groups and clusters
4 participants