-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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): support performance insights configuration at cluster level #31385
Changes from 1 commit
4e69dda
ab08d5c
fe141a7
2a1d34d
05ba170
2395181
b963715
2854844
f5ae273
217d945
cf56890
b9e1188
a167d1f
c0c937f
e5d5463
80513c1
480ac14
3b39874
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,7 @@ import * as kms from '../../aws-kms'; | |
import * as logs from '../../aws-logs'; | ||
import * as s3 from '../../aws-s3'; | ||
import * as secretsmanager from '../../aws-secretsmanager'; | ||
import { Annotations, ArnFormat, Duration, FeatureFlags, Lazy, RemovalPolicy, Resource, Stack, Token } from '../../core'; | ||
import { Annotations, ArnFormat, Duration, FeatureFlags, Lazy, RemovalPolicy, Resource, Stack, Token, TokenComparison } from '../../core'; | ||
import * as cxapi from '../../cx-api'; | ||
|
||
/** | ||
|
@@ -612,6 +612,16 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { | |
*/ | ||
public readonly performanceInsightsEnabled: boolean; | ||
|
||
/** | ||
* The amount of time, in days, to retain Performance Insights data. | ||
*/ | ||
public readonly performanceInsightRetention?: PerformanceInsightRetention; | ||
|
||
/** | ||
* The AWS KMS key for encryption of Performance Insights data. | ||
*/ | ||
public readonly performanceInsightEncryptionKey?: kms.IKey; | ||
|
||
protected readonly serverlessV2MinCapacity: number; | ||
protected readonly serverlessV2MaxCapacity: number; | ||
|
||
|
@@ -718,11 +728,16 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { | |
|
||
const enablePerformanceInsights = props.enablePerformanceInsights | ||
|| props.performanceInsightRetention !== undefined || props.performanceInsightEncryptionKey !== undefined; | ||
this.performanceInsightsEnabled = enablePerformanceInsights; | ||
if (enablePerformanceInsights && props.enablePerformanceInsights === false) { | ||
throw new Error('`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set'); | ||
} | ||
|
||
this.performanceInsightsEnabled = enablePerformanceInsights; | ||
this.performanceInsightRetention = enablePerformanceInsights | ||
? (props.performanceInsightRetention || PerformanceInsightRetention.DEFAULT) | ||
: undefined; | ||
this.performanceInsightEncryptionKey = props.performanceInsightEncryptionKey; | ||
|
||
this.newCfnProps = { | ||
// Basic | ||
engine: props.engine.engineType, | ||
|
@@ -763,11 +778,9 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { | |
copyTagsToSnapshot: props.copyTagsToSnapshot ?? true, | ||
domain: this.domainId, | ||
domainIamRoleName: this.domainRole?.roleName, | ||
performanceInsightsEnabled: enablePerformanceInsights || props.enablePerformanceInsights, // fall back to undefined if not set | ||
performanceInsightsKmsKeyId: props.performanceInsightEncryptionKey?.keyArn, | ||
performanceInsightsRetentionPeriod: enablePerformanceInsights | ||
? (props.performanceInsightRetention || PerformanceInsightRetention.DEFAULT) | ||
: undefined, | ||
performanceInsightsEnabled: this.performanceInsightsEnabled || props.enablePerformanceInsights, // fall back to undefined if not set | ||
performanceInsightsKmsKeyId: this.performanceInsightEncryptionKey?.keyArn, | ||
performanceInsightsRetentionPeriod: this.performanceInsightRetention, | ||
}; | ||
} | ||
|
||
|
@@ -831,14 +844,10 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { | |
* Perform validations on the cluster instances | ||
*/ | ||
private validateClusterInstances(writer: IAuroraClusterInstance, readers: IAuroraClusterInstance[]): void { | ||
let performanceInsightsDuplicate = false; | ||
|
||
if (writer.type === InstanceType.SERVERLESS_V2) { | ||
this.hasServerlessInstance = true; | ||
} | ||
if (writer.performanceInsightsEnabled && this.performanceInsightsEnabled) { | ||
performanceInsightsDuplicate = true; | ||
} | ||
this.validatePerformanceInsightsSettings(writer); | ||
if (readers.length > 0) { | ||
const sortedReaders = readers.sort((a, b) => a.tier - b.tier); | ||
const highestTierReaders: IAuroraClusterInstance[] = []; | ||
|
@@ -867,9 +876,7 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { | |
if (reader.tier <= 1) { | ||
noFailoverTierInstances = false; | ||
} | ||
if (reader.performanceInsightsEnabled && this.performanceInsightsEnabled) { | ||
performanceInsightsDuplicate = true; | ||
} | ||
this.validatePerformanceInsightsSettings(reader); | ||
} | ||
|
||
const hasOnlyServerlessReaders = hasServerlessReader && !hasProvisionedReader; | ||
|
@@ -905,9 +912,45 @@ abstract class DatabaseClusterNew extends DatabaseClusterBase { | |
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Validate Performance Insights settings | ||
*/ | ||
private validatePerformanceInsightsSettings(instance: IAuroraClusterInstance): void { | ||
// If Performance Insights is enabled on the cluster, the one for each instance will be enabled as well. | ||
if (this.performanceInsightsEnabled && instance.performanceInsightsEnabled === false) { | ||
Annotations.of(this).addWarningV2( | ||
'@aws-cdk/aws-rds:instancePerformanceInsightsOverridden', | ||
`Performance Insights is enabled on cluster '${this.node.id}' at cluster level, but disabled for instance '${instance.node.id}'. `+ | ||
'However, Performance Insights for this instance will also be automatically enabled if enabled at cluster level.', | ||
); | ||
} | ||
|
||
if (performanceInsightsDuplicate) { | ||
throw new Error('Cannot enable Performance Insights on both the cluster and the instances'); | ||
// If `performanceInsightRetention` is enabled on the cluster, the same parameter for each instance must be | ||
// undefined or the same as the value at cluster level. | ||
if ( | ||
this.performanceInsightRetention && | ||
instance.performanceInsightRetention && | ||
instance.performanceInsightRetention !== this.performanceInsightRetention | ||
) { | ||
throw new Error(`\`performanceInsightRetention\` for each instance must be the same as the one at cluster level, got instance '${instance.node.id}': ${instance.performanceInsightRetention}, cluster: ${this.performanceInsightRetention}`); | ||
} | ||
|
||
// If `performanceInsightEncryptionKey` is enabled on the cluster, the same parameter for each instance must be | ||
// undefined or the same as the value at cluster level. | ||
if (this.performanceInsightEncryptionKey && instance.performanceInsightEncryptionKey) { | ||
const clusterKeyArn = this.performanceInsightEncryptionKey.keyArn; | ||
const instanceKeyArn = instance.performanceInsightEncryptionKey.keyArn; | ||
const compared = Token.compareStrings(clusterKeyArn, instanceKeyArn); | ||
|
||
if (compared === TokenComparison.DIFFERENT) { | ||
throw new Error(`\`performanceInsightEncryptionKey\` for each instance must be the same as the one at cluster level, got instance '${instance.node.id}': '${instance.performanceInsightEncryptionKey.keyArn}', cluster: '${this.performanceInsightEncryptionKey.keyArn}'`); | ||
} | ||
// Even if both of cluster and instance keys are unresolved, check if they are the same token. | ||
if (compared === TokenComparison.BOTH_UNRESOLVED && clusterKeyArn !== instanceKeyArn) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure about the validity of this condition 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was certainly wondering about this myself because I had never seen such an implementation. However, I thought that if only one of the values is a token, it is impossible to compare them in any way, but if both are tokens, they can be compared by check whether both are the same token. I thought that excluding this case would diminish the validation as it would mean skipping the most common cases, such as the following. What do you think? new DatabaseCluster(stack, 'Database', {
engine: DatabaseClusterEngine.AURORA,
vpc,
performanceInsightEncryptionKey: new kms.Key(stack, 'Key1'),
writer: ClusterInstance.provisioned('writer', {
performanceInsightEncryptionKey: new kms.Key(stack, 'Key2'),
}),
}); |
||
throw new Error('`performanceInsightEncryptionKey` for each instance must be the same as the one at cluster level'); | ||
} | ||
} | ||
} | ||
|
||
|
@@ -1430,9 +1473,15 @@ function legacyCreateInstances(cluster: DatabaseClusterNew, props: DatabaseClust | |
if (enablePerformanceInsights && instanceProps.enablePerformanceInsights === false) { | ||
throw new Error('`enablePerformanceInsights` disabled, but `performanceInsightRetention` or `performanceInsightEncryptionKey` was set'); | ||
} | ||
if (enablePerformanceInsights && cluster.performanceInsightsEnabled) { | ||
throw new Error('Cannot enable Performance Insights on both the cluster and the instances'); | ||
} | ||
const performanceInsightRetention = enablePerformanceInsights | ||
? (instanceProps.performanceInsightRetention || PerformanceInsightRetention.DEFAULT) | ||
: undefined; | ||
legacyValidatePerformanceInsightsSettingsWithCluster( | ||
cluster, | ||
enablePerformanceInsights, | ||
performanceInsightRetention, | ||
instanceProps.performanceInsightEncryptionKey, | ||
); | ||
|
||
const instanceType = instanceProps.instanceType ?? ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM); | ||
|
||
|
@@ -1469,9 +1518,7 @@ function legacyCreateInstances(cluster: DatabaseClusterNew, props: DatabaseClust | |
(instanceProps.vpcSubnets && instanceProps.vpcSubnets.subnetType === ec2.SubnetType.PUBLIC), | ||
enablePerformanceInsights: enablePerformanceInsights || instanceProps.enablePerformanceInsights, // fall back to undefined if not set | ||
performanceInsightsKmsKeyId: instanceProps.performanceInsightEncryptionKey?.keyArn, | ||
performanceInsightsRetentionPeriod: enablePerformanceInsights | ||
? (instanceProps.performanceInsightRetention || PerformanceInsightRetention.DEFAULT) | ||
: undefined, | ||
performanceInsightsRetentionPeriod: performanceInsightRetention, | ||
// This is already set on the Cluster. Unclear to me whether it should be repeated or not. Better yes. | ||
dbSubnetGroupName: subnetGroup.subnetGroupName, | ||
dbParameterGroupName: instanceParameterGroupConfig?.parameterGroupName, | ||
|
@@ -1514,3 +1561,48 @@ function legacyCreateInstances(cluster: DatabaseClusterNew, props: DatabaseClust | |
function databaseInstanceType(instanceType: ec2.InstanceType) { | ||
return 'db.' + instanceType.toString(); | ||
} | ||
|
||
/** | ||
* Validate Performance Insights settings for legacy instanceProps with cluster level settings | ||
*/ | ||
function legacyValidatePerformanceInsightsSettingsWithCluster( | ||
go-to-k marked this conversation as resolved.
Show resolved
Hide resolved
|
||
cluster: DatabaseClusterNew, | ||
enableInstance: boolean, | ||
instanceRetention?: PerformanceInsightRetention, | ||
instanceKey?: kms.IKey, | ||
): void { | ||
// If Performance Insights is enabled on the cluster, the one for instanceProps will be enabled as well. | ||
if (cluster.performanceInsightsEnabled && enableInstance === false) { | ||
Annotations.of(cluster).addWarningV2( | ||
'@aws-cdk/aws-rds:legacyInstancePerformanceInsightsOverridden', | ||
`Performance Insights is enabled on cluster '${cluster.node.id}' at cluster level, but disabled for instanceProps. `+ | ||
'However, Performance Insights for this instance will also be automatically enabled if enabled at cluster level.', | ||
); | ||
} | ||
|
||
// If `performanceInsightRetention` is enabled on the cluster, the same parameter for instanceProps must be | ||
// undefined or the same as the value at cluster level. | ||
if ( | ||
cluster.performanceInsightRetention && | ||
instanceRetention && | ||
instanceRetention !== cluster.performanceInsightRetention | ||
) { | ||
throw new Error(`\`performanceInsightRetention\` for each instance must be the same as the one at cluster level, got \`instanceProps\`: ${instanceRetention}, cluster: ${cluster.performanceInsightRetention}`); | ||
} | ||
|
||
// If `performanceInsightEncryptionKey` is enabled on the cluster, the same parameter for each instance must be | ||
// undefined or the same as the value at cluster level. | ||
if (cluster.performanceInsightEncryptionKey && instanceKey) { | ||
const clusterKeyArn = cluster.performanceInsightEncryptionKey.keyArn; | ||
const instanceKeyArn = instanceKey.keyArn; | ||
const compared = Token.compareStrings(clusterKeyArn, instanceKeyArn); | ||
|
||
if (compared === TokenComparison.DIFFERENT) { | ||
throw new Error(`\`performanceInsightEncryptionKey\` for each instance must be the same as the one at cluster level, got \`instanceProps\`: '${instanceKey.keyArn}', cluster: '${cluster.performanceInsightEncryptionKey.keyArn}'`); | ||
} | ||
// Even if both of cluster and instance keys are unresolved, check if they are the same token. | ||
if (compared === TokenComparison.BOTH_UNRESOLVED && clusterKeyArn !== instanceKeyArn) { | ||
throw new Error('`performanceInsightEncryptionKey` for each instance must be the same as the one at cluster level'); | ||
} | ||
} | ||
} |
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.
Why is this needed instead of the old way
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 is just to set it to new variables added to the
AuroraClusterInstance
instance variables.L467-469