Skip to content

Commit

Permalink
feat(neptune): introduc metric method to cluster and instance
Browse files Browse the repository at this point in the history
related to aws#20248
  • Loading branch information
humanzz committed Sep 11, 2022
1 parent dc07f52 commit 2e112ef
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 10 deletions.
13 changes: 12 additions & 1 deletion packages/@aws-cdk/aws-neptune/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ const cluster = new neptune.DatabaseCluster(this, 'Database', {
});
```

Additionally it is also possible to add replicas using `DatabaseInstance` for an existing cluster.
Additionally, it is also possible to add replicas using `DatabaseInstance` for an existing cluster.

```ts fixture=with-cluster
const replica1 = new neptune.DatabaseInstance(this, 'Instance', {
Expand All @@ -143,3 +143,14 @@ new neptune.DatabaseCluster(this, 'Cluster', {
autoMinorVersionUpgrade: true,
});
```

## Metrics

Both `DatabaseCluster` and `DatabaseInstance` provide a `metric()` method to help with cluster-level and instance-level monitoring.

```ts
cluster.metric('SparqlErrors'); // cluster-level SparqlErrors metric
instance.metric('SparqlErrors') // instance-level SparqlErrors metric
```

For more details on the available metrics, refer to https://docs.aws.amazon.com/neptune/latest/userguide/cw-metrics.html
20 changes: 20 additions & 0 deletions packages/@aws-cdk/aws-neptune/lib/cluster.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
import * as kms from '@aws-cdk/aws-kms';
Expand Down Expand Up @@ -284,6 +285,14 @@ export interface IDatabaseCluster extends IResource, ec2.IConnectable {
* Grant the given identity connection access to the database.
*/
grantConnect(grantee: iam.IGrantable): iam.Grant;

/**
* Return the given named metric associated with this DatabaseCluster instance
*
* @see https://docs.aws.amazon.com/neptune/latest/userguide/cw-metrics.html
* @see https://docs.aws.amazon.com/neptune/latest/userguide/cw-dimensions.html
*/
metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric;
}

/**
Expand Down Expand Up @@ -398,6 +407,17 @@ export abstract class DatabaseClusterBase extends Resource implements IDatabaseC
public grantConnect(grantee: iam.IGrantable): iam.Grant {
return this.grant(grantee, 'neptune-db:*');
}

public metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric {
return new cloudwatch.Metric({
namespace: 'AWS/Neptune',
dimensionsMap: {
DBClusterIdentifier: this.clusterIdentifier,
},
metricName,
...props,
});
}
}

/**
Expand Down
60 changes: 53 additions & 7 deletions packages/@aws-cdk/aws-neptune/lib/instance.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';
Expand Down Expand Up @@ -165,6 +166,14 @@ export interface IDatabaseInstance extends cdk.IResource {
* @attribute Port
*/
readonly dbInstanceEndpointPort: string;

/**
* Return the given named metric associated with this database instance
*
* @see https://docs.aws.amazon.com/neptune/latest/userguide/cw-metrics.html
* @see https://docs.aws.amazon.com/neptune/latest/userguide/cw-dimensions.html
*/
metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric;
}

/**
Expand Down Expand Up @@ -233,27 +242,64 @@ export interface DatabaseInstanceProps {
}

/**
* A database instance
*
* @resource AWS::Neptune::DBInstance
* A new or imported database instance.
*/
export class DatabaseInstance extends cdk.Resource implements IDatabaseInstance {

export abstract class DatabaseInstanceBase extends cdk.Resource implements IDatabaseInstance {
/**
* Import an existing database instance.
*/
public static fromDatabaseInstanceAttributes(scope: Construct, id: string, attrs: DatabaseInstanceAttributes): IDatabaseInstance {
class Import extends cdk.Resource implements IDatabaseInstance {
class Import extends DatabaseInstanceBase implements IDatabaseInstance {
public readonly defaultPort = ec2.Port.tcp(attrs.port);
public readonly instanceIdentifier = attrs.instanceIdentifier;
public readonly dbInstanceEndpointAddress = attrs.instanceEndpointAddress;
public readonly dbInstanceEndpointPort = attrs.port.toString();
public readonly instanceEndpoint = new Endpoint(attrs.instanceEndpointAddress, attrs.port);
}

return new Import(scope, id);
}

/**
* @inheritdoc
*/
public abstract readonly dbInstanceEndpointAddress: string;

/**
* @inheritdoc
*/
public abstract readonly dbInstanceEndpointPort: string;

/**
* @inheritdoc
*/
public abstract readonly instanceEndpoint: Endpoint;

/**
* @inheritdoc
*/
public abstract readonly instanceIdentifier: string;

/**
* @inheritdoc
*/
public metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric {
return new cloudwatch.Metric({
namespace: 'AWS/Neptune',
dimensionsMap: {
DBInstanceIdentifier: this.instanceIdentifier,
},
metricName,
...props,
});
}
}

/**
* A database instance
*
* @resource AWS::Neptune::DBInstance
*/
export class DatabaseInstance extends DatabaseInstanceBase implements IDatabaseInstance {

/**
* The instance's database cluster
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-neptune/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,15 @@
"@types/jest": "^27.5.2"
},
"dependencies": {
"@aws-cdk/aws-cloudwatch": "0.0.0",
"@aws-cdk/aws-ec2": "0.0.0",
"@aws-cdk/aws-iam": "0.0.0",
"@aws-cdk/aws-kms": "0.0.0",
"@aws-cdk/core": "0.0.0",
"constructs": "^10.0.0"
},
"peerDependencies": {
"@aws-cdk/aws-cloudwatch": "0.0.0",
"@aws-cdk/aws-ec2": "0.0.0",
"@aws-cdk/aws-iam": "0.0.0",
"@aws-cdk/aws-kms": "0.0.0",
Expand Down
41 changes: 41 additions & 0 deletions packages/@aws-cdk/aws-neptune/test/cluster.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Match, Template } from '@aws-cdk/assertions';
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
import * as kms from '@aws-cdk/aws-kms';
Expand Down Expand Up @@ -660,6 +661,46 @@ describe('DatabaseCluster', () => {

});

test('metric - constructs metric with correct namespace and dimension and inputs', () => {
// GIVEN
const stack = testStack();
const vpc = new ec2.Vpc(stack, 'VPC');
const cluster = new DatabaseCluster(stack, 'Cluster', {
vpc,
instanceType: InstanceType.R5_LARGE,
});

// WHEN
const metric = cluster.metric('SparqlErrors');
new cloudwatch.Alarm(stack, 'Alarm', {
evaluationPeriods: 1,
threshold: 0,
comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD,
metric: metric,
});

// THEN
expect(metric).toEqual(new cloudwatch.Metric({
namespace: 'AWS/Neptune',
dimensionsMap: {
DBClusterIdentifier: cluster.clusterIdentifier,
},
metricName: 'SparqlErrors',
}));
Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', {
Namespace: 'AWS/Neptune',
MetricName: 'SparqlErrors',
Dimensions: [
{
Name: 'DBClusterIdentifier',
Value: stack.resolve(cluster.clusterIdentifier),
},
],
ComparisonOperator: 'GreaterThanThreshold',
EvaluationPeriods: 1,
Threshold: 0,
});
});
});

function testStack() {
Expand Down
44 changes: 42 additions & 2 deletions packages/@aws-cdk/aws-neptune/test/instance.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Template } from '@aws-cdk/assertions';
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as cdk from '@aws-cdk/core';
import * as constructs from 'constructs';
Expand Down Expand Up @@ -140,6 +141,46 @@ describe('DatabaseInstance', () => {
test('instance type from string throws if missing db prefix', () => {
expect(() => { InstanceType.of('r5.xlarge');}).toThrowError(/instance type must start with 'db.'/);
});

test('metric - constructs metric with correct namespace and dimension and inputs', () => {
// GIVEN
const stack = testStack();
const instance = new DatabaseInstance(stack, 'Instance', {
cluster: stack.cluster,
instanceType: InstanceType.R5_LARGE,
});

// WHEN
const metric = instance.metric('SparqlErrors');
new cloudwatch.Alarm(stack, 'Alarm', {
evaluationPeriods: 1,
threshold: 0,
comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD,
metric: metric,
});

// THEN
expect(metric).toEqual(new cloudwatch.Metric({
namespace: 'AWS/Neptune',
dimensionsMap: {
DBInstanceIdentifier: instance.instanceIdentifier,
},
metricName: 'SparqlErrors',
}));
Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', {
Namespace: 'AWS/Neptune',
MetricName: 'SparqlErrors',
Dimensions: [
{
Name: 'DBInstanceIdentifier',
Value: stack.resolve(instance.instanceIdentifier),
},
],
ComparisonOperator: 'GreaterThanThreshold',
EvaluationPeriods: 1,
Threshold: 0,
});
});
});

class TestStack extends cdk.Stack {
Expand All @@ -160,6 +201,5 @@ class TestStack extends cdk.Stack {
}

function testStack() {
const stack = new TestStack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } });
return stack;
return new TestStack(undefined, undefined, { env: { account: '12345', region: 'us-test-1' } });
}

0 comments on commit 2e112ef

Please sign in to comment.