feat(redshift-alpha): directly add parameters to a parameter group or indirectly through a cluster#20944
Conversation
…ParameterGroup or indirectly through a Cluster
…un/aws-cdk into dynamic-redshift-parameter-groups
comcalvi
left a comment
There was a problem hiding this comment.
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?
…o extend ClusterParameterGroupBase
|
Going off of some of my previous comments I updated the Import class in |
|
@comcalvi Do you mind re-reviewing this PR? |
TheRealAmazonKendra
left a comment
There was a problem hiding this comment.
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.
| } | ||
|
|
||
| public addToParameterGroup(_name: string, _value: string): AddParameterResult { | ||
| return { parameterAddedResult: AddParameterResultStatus.IMPORTED_RESOURCE_FAILURE }; |
There was a problem hiding this comment.
Why does this just plain return a failure?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Why can't we add parameters to imported Clusters?
There was a problem hiding this comment.
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
comcalvi
left a comment
There was a problem hiding this comment.
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.
| } | ||
|
|
||
| public addToParameterGroup(_name: string, _value: string): AddParameterResult { | ||
| return { parameterAddedResult: AddParameterResultStatus.IMPORTED_RESOURCE_FAILURE }; |
There was a problem hiding this comment.
Why can't we add parameters to imported Clusters?
| } else if (this.parameterGroup) { | ||
| return this.parameterGroup.addParameter(name, value); | ||
| } else { | ||
| return { parameterAddedResult: AddParameterResultStatus.IMPORTED_RESOURCE_FAILURE }; |
There was a problem hiding this comment.
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.
| public abstract readonly clusterParameterGroupName: string; | ||
|
|
||
| public addParameter(_name: string, _value: string): AddParameterResult { | ||
| return { parameterAddedResult: AddParameterResultStatus.IMPORTED_RESOURCE_FAILURE }; |
There was a problem hiding this comment.
I agree. The add operation should not default to failure. Failure should be the exception.
| */ | ||
| public static fromClusterParameterGroupName(scope: Construct, id: string, clusterParameterGroupName: string): IClusterParameterGroup { | ||
| class Import extends Resource implements IClusterParameterGroup { | ||
| class Import extends ClusterParameterGroupBase { |
There was a problem hiding this comment.
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.
Pull request has been modified.
| /** | ||
| * Identifier of the cluster | ||
| */ | ||
| protected clusterIdentifier: string; |
There was a problem hiding this comment.
| protected clusterIdentifier: string; | |
| protected clusterId: string; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
We should use clusterName instead of creating this new field.
There was a problem hiding this comment.
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).
|
|
||
| const defaultPort = ec2.Port.tcp(this.clusterEndpoint.port); | ||
| this.connections = new ec2.Connections({ securityGroups, defaultPort }); | ||
| this.clusterIdentifier = props.clusterName ?? Names.uniqueResourceName(this, {}); |
There was a problem hiding this comment.
clusterName here would never be undefined because it's being set to the ref.
There was a problem hiding this comment.
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
Co-authored-by: Kendra Neil <53584728+TheRealAmazonKendra@users.noreply.github.com>
Pull request has been modified.
|
@Mergifyio update |
✅ Branch has been successfully updated |
TheRealAmazonKendra
left a comment
There was a problem hiding this comment.
Looks like the integ tests still need to be updated with the output from the suggested changes.
Pull request has been modified.
TheRealAmazonKendra
left a comment
There was a problem hiding this comment.
Some requested changes still not addressed.
|
I believe they have been addressed, the comments look to be on outdated code |
Pull request has been modified.
|
@TheRealAmazonKendra Can you re-review this? I believe I've addressed the requested changes |
TheRealAmazonKendra
left a comment
There was a problem hiding this comment.
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.
| ```ts fixture=cluster | ||
| cluster.addToParameterGroup('enable_user_activity_logging', 'true'); | ||
| ``` |
There was a problem hiding this comment.
This isn't rendering correctly. I suspect that the issue is the fixture=cluster piece causing it.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Actually I think none of the fixtures (even the default) are loading properly for the redshift alpha library
| 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`, |
There was a problem hiding this comment.
I think now that you are using this.cluster.clusterIdentifier, Names.uniqueResourceId is no longer needed in this context.
There was a problem hiding this comment.
The clusterIdentifier can be undefined. It's being set to the optional clusterName prop
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Removed the Names.uniqueResourceName and falling back to the default
| encryptionKey: new kms.Key(stack, 'custom-kms-key'), | ||
| }); | ||
|
|
||
| cluster.addToParameterGroup('enable_user_activity_logging', 'true'); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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())
Co-authored-by: Kendra Neil <53584728+TheRealAmazonKendra@users.noreply.github.com>
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}).`); |
There was a problem hiding this comment.
Let's add the name of the parameter group in here in case the user has an app with multiple.
There was a problem hiding this comment.
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}).`);There was a problem hiding this comment.
See my most recent comment below.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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`, |
There was a problem hiding this comment.
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; | |||
There was a problem hiding this comment.
This isn't a parameter group name?
Pull request has been modified.
|
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 CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
|
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). |
… 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*
Closes #20656
This PR enables users to directly add parameters to a
ClusterParameterGroupor indirectly through aCluster. 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 aAddParameterResultStatuswhich let's developers handle failure cases more elegantly.Ex. On
SUCCESSorSAME_VALUE_FAILUREdo nothing, but onCONFLICTING_VALUE_FAILUREorIMPORTED_RESOURCE_FAILUREthrow 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:
New Features
yarn integto deploy the infrastructure and generate the snapshot (i.e.yarn integwithout--dry-run)?By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license