-
Notifications
You must be signed in to change notification settings - Fork 4k
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(rds): unify ParameterGroup and ClusterParameterGroup #8959
Conversation
*/ | ||
protected parameters?: { [key: string]: string } = {}; | ||
bindToCluster(options: ParameterGroupClusterBindOptions): ParameterGroupClusterConfig; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General question: What's the advantage of requiring an empty interface as a parameter to the call? You wouldn't be able to add a new required member to that interface without it being a breaking change. I get it's future-proofing, but doesn't seem to add any more backwards compatibility than just omitting the options for now and making an optional options parameter in the future when needed. Am I missing a non-obvious advantage to this approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's mainly for other languages that we support that don't have optional parameters (Java comes to mind).
I don't think making the options
optional in the bindToCluster()
method is a good idea - makes it very inconvenient to actually implement it (you have to constantly check for null
, which is even worse in languages like Java).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK on the null
checks. You're still going to have to either (a) make a breaking change or (b) introduce an optional member to the options
(which will need a null
check). I guess it's the over/under on that degree of awkwardness vs the awkwardness of creating an empty object that (currently) serves no purpose. Again, I'm thinking of the poor Java dev who has to write new ParameterGroupClusterBindOptions()
.
However, I don't have super-strong feelings either way, just wanting to understand your perspective on the general principle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK on the
null
checks. You're still going to have to either (a) make a breaking change or (b) introduce an optional member to theoptions
(which will need anull
check).
Right. But making it optional would require 2 null
checks! Which is twice as irritating 🙂 (Even with an optional parameter, you can't add a required property to ParameterGroupClusterBindOptions
without breaking backwards compatibility).
I guess it's the over/under on that degree of awkwardness vs the awkwardness of creating an empty object that (currently) serves no purpose. Again, I'm thinking of the poor Java dev who has to write
new ParameterGroupClusterBindOptions()
.
But here's the beauty of this - a Java dev will never have to create a ParameterGroupClusterBindOptions
! Notice that bindToCluster
and bindToInstance
are only called in Cluster
and Instance
. So while you might conceivably want to implement bindToCluster()
/ bindToInstance()
, you won't have to call it unless you're doing something really, really crazy (at which point creating an empty ParameterGroupClusterBindOptions
is the least of your problems 😉).
Does this make more sense now in how is this approached here?
|
||
public bindToCluster(_options: ParameterGroupClusterBindOptions): ParameterGroupClusterConfig { | ||
if (!this.clusterCfnGroup) { | ||
const parentScope = this.instanceCfnGroup ?? this; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This maybe deserves a comment. Why parent the scope of one param group onto the other?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's because I want both of the Cfn*
resources to have the ID 'Resource'
, but if one of the bind*()
methods was already called, that would result in a duplicate identifier in the this
scope. Hence this trick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
¯_(ツ)_/¯ I'd add a comment to that effect, unless this is a super-common pattern I haven't seen before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was also thinking - instead of changing the parent, I could change the ID.
So, this would become:
public bindToCluster(_options: ParameterGroupClusterBindOptions): ParameterGroupClusterConfig {
if (!this.clusterCfnGroup) {
const resourceId = this.instanceCfnGroup ? 'SecondResource' : 'Resource';
this.clusterCfnGroup = new CfnDBClusterParameterGroup(this, resourceId, {
description: this.description || `Cluster parameter group for ${this.family}`,
family: this.family,
parameters: Lazy.anyValue({ produce: () => this.parameters }),
});
Is that more clear @njlynch ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to just do this?
public bindToCluster(...) {
this.clusterCfnGroup = new CfnDBClusterParameterGroup(this, 'ClusterParamGroup', {
...
});
}
public bindToInstance(...) {
this.clusterCfnGroup = new CfnDBClusterParameterGroup(this, 'InstanceParamGroup', {
...
});
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i find them both equally readable, but a comment will be handy for posterity as I think it won't be intuitive to a new contributor why we do this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to just do this?
public bindToCluster(...) { this.clusterCfnGroup = new CfnDBClusterParameterGroup(this, 'ClusterParamGroup', { ... }); } public bindToInstance(...) { this.clusterCfnGroup = new CfnDBClusterParameterGroup(this, 'InstanceParamGroup', { ... }); }
Actually, yes.
Since the existing classes use the Resource
IDs, changing them now to 'ClusterParamGroup'
/'InstanceParamGroup'
would cause a replacement of them in customer's CloudFormation Stacks after they upgrade their version of CDK, which is quite a disruptive change.
Also, the name 'Resource'
(and 'Default'
) is treated a little bit especially - it's the return value from the this.node.defaultChild
method (which is often used with escape hatches).
40c3e40
to
b5f9906
Compare
Rebased on top of #8686 , which was merged. |
b5f9906
to
2cb2fa5
Compare
*/ | ||
protected parameters?: { [key: string]: string } = {}; | ||
bindToCluster(options: ParameterGroupClusterBindOptions): ParameterGroupClusterConfig; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK on the null
checks. You're still going to have to either (a) make a breaking change or (b) introduce an optional member to the options
(which will need a null
check). I guess it's the over/under on that degree of awkwardness vs the awkwardness of creating an empty object that (currently) serves no purpose. Again, I'm thinking of the poor Java dev who has to write new ParameterGroupClusterBindOptions()
.
However, I don't have super-strong feelings either way, just wanting to understand your perspective on the general principle.
|
||
public bindToCluster(_options: ParameterGroupClusterBindOptions): ParameterGroupClusterConfig { | ||
if (!this.clusterCfnGroup) { | ||
const parentScope = this.instanceCfnGroup ?? this; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
¯_(ツ)_/¯ I'd add a comment to that effect, unless this is a super-common pattern I haven't seen before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good simplification! added some minor comments
* @param key The key of the parameter to be added | ||
* @param value The value of the parameter to be added | ||
*/ | ||
public addParameter(key: string, value: string): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the use case where the return type would be used?
at a cursory glance, most of the addXyZ
methods return void or a non-primitive type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but if you're going to return void
, you might as well return boolean
(I don't see any downsides in making it return boolean
compared to void
, seems like pure upside to me).
|
||
public bindToCluster(_options: ParameterGroupClusterBindOptions): ParameterGroupClusterConfig { | ||
if (!this.clusterCfnGroup) { | ||
const parentScope = this.instanceCfnGroup ?? this; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i find them both equally readable, but a comment will be handy for posterity as I think it won't be intuitive to a new contributor why we do this
@njlynch @shivlaks thanks for the review! I wanted to run one more thing by you. As you see, the most important parameter when creating the
Thoughts on this idea? |
I'm not familiar enough with the RDS API to see how this works. IInstanceEngine doesn't expose the family today, and the various implementations have a mapping of version to families, rather than just a single family, where version is optional. If you accepted an |
Yes, we of course, we would surface
Yes, but this the situation that we have today already. For example, if you don't specify a version for the Aurora PostgreSQL Engine, it will default to the parameter group family |
cac12ed
to
64b1ba2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the simplification to IEngine
had a couple small comments / questions around them
* When `engineVersion` is specified, return the parameter group family corresponding to that engine version. | ||
* Return undefined if no parameter group family is defined for this engine or for the requested `engineVersion`. | ||
*/ | ||
export function calculateParameterGroupFamily( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having a hard time reconciling this with #9016. In the other PR, parameterGroupFamilies look to be completely removed; will this function be deleted then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. In that PR, the major version is set explicitly for a specific version (instead of being calculated).
* Return undefined if no parameter group family is defined for this engine or for the requested `engineVersion`. | ||
*/ | ||
export function calculateParameterGroupFamily( | ||
parameterGroupFamilies: ParameterGroupFamilyMapping[] | undefined, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(For my own edification): Is there any logical difference between a required parameter that can be undefined vs an optional parameter, especially in cases where all parameters are the same (e.g., no issues with optional parameters needing to be the last ones)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a tiny difference: for a required parameter that can be undefined, you have to always explicitly pass it (even if just the undefined
value), while an optional parameter can be skipped from the call altogether.
return undefined; | ||
} | ||
if (engineVersion !== undefined) { | ||
const family = parameterGroupFamilies.find(x => engineVersion.startsWith(x.engineMajorVersion)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this guaranteed to only match one version? If not, is ordering guaranteed? Below, you sort the families by version, which implies this list isn't (guaranteed) sorted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's guaranteed to match one version, provided the engineMajorVersion
are unique, and not subsets of each other, but this is the case with the currently used major versions (and it makes sense, because it would be weird if 11
and 11.2
were both major versions ;p).
The classes ParameterGroup and ClusterParameterGroup were basically identical; they only differed in the L1 that was created in their scope. Unify the classes by adding a bind()-like protocol between ParameterGroup and cluster/instance, which allows us to only have a single class instead of 2. Fixes aws#8932 BREAKING CHANGE: the class ClusterParameterGroup has been removed - use ParameterGroup instead
64b1ba2
to
a64ba83
Compare
Thank you for contributing! Your pull request will be updated from master 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 master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
The classes ParameterGroup and ClusterParameterGroup were basically identical; they only differed in the L1 that was created in their scope. Unify the classes by adding a bind()-like protocol between ParameterGroup and cluster/instance, which allows us to only have a single class instead of 2. Fixes aws#8932 BREAKING CHANGE: the class ClusterParameterGroup has been removed - use ParameterGroup instead ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
The classes ParameterGroup and ClusterParameterGroup were basically identical;
they only differed in the L1 that was created in their scope.
Unify the classes by adding a bind()-like protocol between ParameterGroup and cluster/instance,
which allows us to only have a single class instead of 2.
Fixes #8932
BREAKING CHANGE: the class ClusterParameterGroup has been removed -
use ParameterGroup instead
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license