Skip to content

Commit

Permalink
CloudWatch: add Metric.grantMetricPutData
Browse files Browse the repository at this point in the history
This adds a static helper function on `Metric` to grant
metric writing permissions to IAM identities.

Also move the `parseStatistics` function to a private
source file so the unexported types it uses won't break
the jsii build.

Fixes #214.
  • Loading branch information
Rico Huijbers committed Jul 9, 2018
1 parent a273f71 commit f241cac
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 53 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
## [UNRELEASED]

* CloudWatch: add `Metric.grantPutMetricData()` to give `PutMetricData` permissions to IAM
identities. ([#258])
* [FIXED] `cdk docs` works but a message __Unknown command: docs__ is printed ([#256])

[#258]: https://github.com/awslabs/aws-cdk/pull/258

## 0.7.3 - 2018-07-09

### Highlights
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk/cloudwatch/lib/alarm.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Arn, Construct, Token } from '@aws-cdk/core';
import { cloudwatch } from '@aws-cdk/resources';
import { HorizontalAnnotation } from './graph';
import { Dimension, Metric, parseStatistic, Statistic, Unit } from './metric';
import { Dimension, Metric, Statistic, Unit } from './metric';
import { parseStatistic } from './util.statistic';

/**
* Properties for Alarms
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk/cloudwatch/lib/graph.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AwsRegion, Token } from "@aws-cdk/core";
import { Alarm } from "./alarm";
import { Metric, parseStatistic } from "./metric";
import { Metric } from "./metric";
import { parseStatistic } from './util.statistic';
import { ConcreteWidget } from "./widget";

/**
Expand Down
66 changes: 16 additions & 50 deletions packages/@aws-cdk/cloudwatch/lib/metric.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Construct } from "@aws-cdk/core";
import { Construct, PolicyStatement } from "@aws-cdk/core";
import { IIdentityResource } from "@aws-cdk/iam";
import { Alarm, ComparisonOperator, TreatMissingData } from "./alarm";
import { parseStatistic } from './util.statistic';

export type DimensionHash = {[dim: string]: any};

Expand Down Expand Up @@ -80,6 +82,19 @@ export interface MetricProps {
* alarms and graphs.
*/
export class Metric {
/**
* Grant permissions to the given identity to write metrics.
*
* @param identity The IAM identity to give permissions to.
*/
public static grantPutMetricData(identity?: IIdentityResource) {
if (!identity) { return; }

identity.addToPolicy(new PolicyStatement()
.addAllResources()
.addAction("cloudwatch:PutMetricData"));
}

public readonly dimensions?: DimensionHash;
public readonly namespace: string;
public readonly metricName: string;
Expand Down Expand Up @@ -366,53 +381,4 @@ function ifUndefined<T>(x: T | undefined, def: T | undefined): T | undefined {
return x;
}
return def;
}

interface SimpleStatistic {
type: 'simple';
statistic: Statistic;
}

interface PercentileStatistic {
type: 'percentile';
percentile: number;
}

/**
* Parse a statistic, returning the type of metric that was used (simple or percentile)
*/
export function parseStatistic(stat: string): SimpleStatistic | PercentileStatistic {
const lowerStat = stat.toLowerCase();

// Simple statistics
const statMap: {[k: string]: Statistic} = {
average: Statistic.Average,
avg: Statistic.Average,
minimum: Statistic.Minimum,
min: Statistic.Minimum,
maximum: Statistic.Maximum,
max: Statistic.Maximum,
samplecount: Statistic.SampleCount,
n: Statistic.SampleCount,
sum: Statistic.Sum,
};

if (lowerStat in statMap) {
return {
type: 'simple',
statistic: statMap[lowerStat]
};
}

// Percentile statistics
const re = /^p([\d.]+)$/;
const m = re.exec(lowerStat);
if (m) {
return {
type: 'percentile',
percentile: parseFloat(m[1])
};
}

throw new Error(`Not a valid statistic: '${stat}', must be one of Average | Minimum | Maximum | SampleCount | Sum | pNN.NN`);
}
49 changes: 49 additions & 0 deletions packages/@aws-cdk/cloudwatch/lib/util.statistic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Statistic } from "./metric";

export interface SimpleStatistic {
type: 'simple';
statistic: Statistic;
}

export interface PercentileStatistic {
type: 'percentile';
percentile: number;
}
/**
* Parse a statistic, returning the type of metric that was used (simple or percentile)
*/
export function parseStatistic(stat: string): SimpleStatistic | PercentileStatistic {
const lowerStat = stat.toLowerCase();

// Simple statistics
const statMap: {[k: string]: Statistic} = {
average: Statistic.Average,
avg: Statistic.Average,
minimum: Statistic.Minimum,
min: Statistic.Minimum,
maximum: Statistic.Maximum,
max: Statistic.Maximum,
samplecount: Statistic.SampleCount,
n: Statistic.SampleCount,
sum: Statistic.Sum,
};

if (lowerStat in statMap) {
return {
type: 'simple',
statistic: statMap[lowerStat]
};
}

// Percentile statistics
const re = /^p([\d.]+)$/;
const m = re.exec(lowerStat);
if (m) {
return {
type: 'percentile',
percentile: parseFloat(m[1])
};
}

throw new Error(`Not a valid statistic: '${stat}', must be one of Average | Minimum | Maximum | SampleCount | Sum | pNN.NN`);
}
3 changes: 2 additions & 1 deletion packages/@aws-cdk/cloudwatch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
},
"dependencies": {
"@aws-cdk/core": "^0.7.3-beta",
"@aws-cdk/resources": "^0.7.3-beta"
"@aws-cdk/resources": "^0.7.3-beta",
"@aws-cdk/iam": "^0.7.3-beta"
}
}
33 changes: 33 additions & 0 deletions packages/@aws-cdk/cloudwatch/test/test.metrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { expect, haveResource } from '@aws-cdk/assert';
import { Anyone, Stack } from '@aws-cdk/core';
import { Role } from '@aws-cdk/iam';
import { Test } from 'nodeunit';
import { Metric } from '../lib';

export = {
'metric grant'(test: Test) {
// GIVEN
const stack = new Stack();
const role = new Role(stack, 'SomeRole', {
assumedBy: new Anyone()
});

// WHEN
Metric.grantPutMetricData(role);

// THEN
expect(stack).to(haveResource('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: "cloudwatch:PutMetricData",
Effect: "Allow",
Resource: "*"
}
],
},
}));

test.done();
}
};

0 comments on commit f241cac

Please sign in to comment.