@gammarers/aws-daily-cost-usage-report-stack 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +4144 -0
- package/API.md +964 -0
- package/LICENSE +202 -0
- package/README.md +63 -0
- package/assets/funcs/cost-reporter.lambda/index.js +18835 -0
- package/assets/funcs/cost-reporter.lambda/index.js.map +7 -0
- package/lib/funcs/cost-reporter-function.d.ts +13 -0
- package/lib/funcs/cost-reporter-function.js +23 -0
- package/lib/funcs/cost-reporter.lambda.d.ts +13 -0
- package/lib/funcs/cost-reporter.lambda.js +103 -0
- package/lib/funcs/lib/get-billing-command.d.ts +31 -0
- package/lib/funcs/lib/get-billing-command.js +158 -0
- package/lib/funcs/lib/get-date-range.d.ts +6 -0
- package/lib/funcs/lib/get-date-range.js +22 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +102 -0
- package/package.json +158 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as lambda from 'aws-cdk-lib/aws-lambda';
|
|
2
|
+
import { Construct } from 'constructs';
|
|
3
|
+
/**
|
|
4
|
+
* Props for CostReporterFunction
|
|
5
|
+
*/
|
|
6
|
+
export interface CostReporterFunctionProps extends lambda.FunctionOptions {
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* An AWS Lambda function which executes src/funcs/cost-reporter.
|
|
10
|
+
*/
|
|
11
|
+
export declare class CostReporterFunction extends lambda.Function {
|
|
12
|
+
constructor(scope: Construct, id: string, props?: CostReporterFunctionProps);
|
|
13
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CostReporterFunction = void 0;
|
|
4
|
+
// ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const lambda = require("aws-cdk-lib/aws-lambda");
|
|
7
|
+
/**
|
|
8
|
+
* An AWS Lambda function which executes src/funcs/cost-reporter.
|
|
9
|
+
*/
|
|
10
|
+
class CostReporterFunction extends lambda.Function {
|
|
11
|
+
constructor(scope, id, props) {
|
|
12
|
+
super(scope, id, {
|
|
13
|
+
description: 'src/funcs/cost-reporter.lambda.ts',
|
|
14
|
+
...props,
|
|
15
|
+
runtime: new lambda.Runtime('nodejs20.x', lambda.RuntimeFamily.NODEJS),
|
|
16
|
+
handler: 'index.handler',
|
|
17
|
+
code: lambda.Code.fromAsset(path.join(__dirname, '../../assets/funcs/cost-reporter.lambda')),
|
|
18
|
+
});
|
|
19
|
+
this.addEnvironment('AWS_NODEJS_CONNECTION_REUSE_ENABLED', '1', { removeInEdge: true });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.CostReporterFunction = CostReporterFunction;
|
|
23
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29zdC1yZXBvcnRlci1mdW5jdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mdW5jcy9jb3N0LXJlcG9ydGVyLWZ1bmN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDZFQUE2RTtBQUM3RSw2QkFBNkI7QUFDN0IsaURBQWlEO0FBU2pEOztHQUVHO0FBQ0gsTUFBYSxvQkFBcUIsU0FBUSxNQUFNLENBQUMsUUFBUTtJQUN2RCxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQWlDO1FBQ3pFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFO1lBQ2YsV0FBVyxFQUFFLG1DQUFtQztZQUNoRCxHQUFHLEtBQUs7WUFDUixPQUFPLEVBQUUsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRSxNQUFNLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQztZQUN0RSxPQUFPLEVBQUUsZUFBZTtZQUN4QixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUseUNBQXlDLENBQUMsQ0FBQztTQUM3RixDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsY0FBYyxDQUFDLHFDQUFxQyxFQUFFLEdBQUcsRUFBRSxFQUFFLFlBQVksRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzFGLENBQUM7Q0FDRjtBQVhELG9EQVdDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gfn4gR2VuZXJhdGVkIGJ5IHByb2plbi4gVG8gbW9kaWZ5LCBlZGl0IC5wcm9qZW5yYy50cyBhbmQgcnVuIFwibnB4IHByb2plblwiLlxuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIGxhbWJkYSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuXG4vKipcbiAqIFByb3BzIGZvciBDb3N0UmVwb3J0ZXJGdW5jdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvc3RSZXBvcnRlckZ1bmN0aW9uUHJvcHMgZXh0ZW5kcyBsYW1iZGEuRnVuY3Rpb25PcHRpb25zIHtcbn1cblxuLyoqXG4gKiBBbiBBV1MgTGFtYmRhIGZ1bmN0aW9uIHdoaWNoIGV4ZWN1dGVzIHNyYy9mdW5jcy9jb3N0LXJlcG9ydGVyLlxuICovXG5leHBvcnQgY2xhc3MgQ29zdFJlcG9ydGVyRnVuY3Rpb24gZXh0ZW5kcyBsYW1iZGEuRnVuY3Rpb24ge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wcz86IENvc3RSZXBvcnRlckZ1bmN0aW9uUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIGRlc2NyaXB0aW9uOiAnc3JjL2Z1bmNzL2Nvc3QtcmVwb3J0ZXIubGFtYmRhLnRzJyxcbiAgICAgIC4uLnByb3BzLFxuICAgICAgcnVudGltZTogbmV3IGxhbWJkYS5SdW50aW1lKCdub2RlanMyMC54JywgbGFtYmRhLlJ1bnRpbWVGYW1pbHkuTk9ERUpTKSxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5oYW5kbGVyJyxcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vYXNzZXRzL2Z1bmNzL2Nvc3QtcmVwb3J0ZXIubGFtYmRhJykpLFxuICAgIH0pO1xuICAgIHRoaXMuYWRkRW52aXJvbm1lbnQoJ0FXU19OT0RFSlNfQ09OTkVDVElPTl9SRVVTRV9FTkFCTEVEJywgJzEnLCB7IHJlbW92ZUluRWRnZTogdHJ1ZSB9KTtcbiAgfVxufSJdfQ==
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Context } from 'aws-lambda';
|
|
2
|
+
export interface EventInput {
|
|
3
|
+
readonly Type: EventInputType;
|
|
4
|
+
}
|
|
5
|
+
export declare enum EventInputType {
|
|
6
|
+
ACCOUNTS = "Accounts",
|
|
7
|
+
SERVICES = "Services"
|
|
8
|
+
}
|
|
9
|
+
export interface MessageAttachmentField {
|
|
10
|
+
readonly title: string;
|
|
11
|
+
readonly value: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const handler: (event: EventInput, context: Context) => Promise<string | Error>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handler = exports.EventInputType = void 0;
|
|
4
|
+
const client_cost_explorer_1 = require("@aws-sdk/client-cost-explorer");
|
|
5
|
+
const web_api_1 = require("@slack/web-api");
|
|
6
|
+
const aws_lambda_errors_1 = require("@yicr/aws-lambda-errors");
|
|
7
|
+
const get_billing_command_1 = require("./lib/get-billing-command");
|
|
8
|
+
const get_date_range_1 = require("./lib/get-date-range");
|
|
9
|
+
var EventInputType;
|
|
10
|
+
(function (EventInputType) {
|
|
11
|
+
EventInputType["ACCOUNTS"] = "Accounts";
|
|
12
|
+
EventInputType["SERVICES"] = "Services";
|
|
13
|
+
})(EventInputType || (exports.EventInputType = EventInputType = {}));
|
|
14
|
+
const ceClient = new client_cost_explorer_1.CostExplorerClient({
|
|
15
|
+
region: 'us-east-1',
|
|
16
|
+
});
|
|
17
|
+
const handler = async (event, context) => {
|
|
18
|
+
console.log(`Event: ${JSON.stringify(event, null, 2)}`);
|
|
19
|
+
console.log(`Context: ${JSON.stringify(context, null, 2)}`);
|
|
20
|
+
// do validation
|
|
21
|
+
if (!process.env.SLACK_TOKEN) {
|
|
22
|
+
throw new aws_lambda_errors_1.MissingEnvironmentVariableError('missing environment variable SLACK_TOKEN.');
|
|
23
|
+
}
|
|
24
|
+
if (!process.env.SLACK_CHANNEL) {
|
|
25
|
+
throw new aws_lambda_errors_1.MissingEnvironmentVariableError('missing environment variable SLACK_CHANNEL.');
|
|
26
|
+
}
|
|
27
|
+
if (!event.Type) {
|
|
28
|
+
throw new aws_lambda_errors_1.MissingInputVariableError('missing input variable Type');
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
if (!Object.values(EventInputType).includes(event.Type)) {
|
|
32
|
+
throw new aws_lambda_errors_1.InvalidInputVariableFormatError('invalid input variable format is Accounts or Services.');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// 👇Calculate Date Range
|
|
36
|
+
const dateRange = new get_date_range_1.GetDateRange();
|
|
37
|
+
console.log(`DateRange::${JSON.stringify(dateRange, null, 2)}`);
|
|
38
|
+
// 👇Get Total Billing
|
|
39
|
+
const totalBilling = await (new get_billing_command_1.GetTotalBilling(ceClient)).execute(dateRange);
|
|
40
|
+
console.log(`TotalBilling: ${JSON.stringify(totalBilling, null, 2)}`);
|
|
41
|
+
const fields = await (async () => {
|
|
42
|
+
switch (event.Type) {
|
|
43
|
+
case EventInputType.ACCOUNTS:
|
|
44
|
+
// 👇Get Accounts Billings
|
|
45
|
+
const accountBillings = await (new get_billing_command_1.GetAccountBillings(ceClient).execute(dateRange));
|
|
46
|
+
console.log(`AccountBillings: ${JSON.stringify(accountBillings, null, 2)}`);
|
|
47
|
+
return accountBillings?.map((value) => {
|
|
48
|
+
return {
|
|
49
|
+
title: value.account,
|
|
50
|
+
value: `${value.amount} ${value.unit}`,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
case EventInputType.SERVICES:
|
|
54
|
+
// 👇Get Service Billings
|
|
55
|
+
const serviceBillings = await (new get_billing_command_1.GetServiceBilling(ceClient)).execute(dateRange);
|
|
56
|
+
console.log(`ServiceBilling: ${JSON.stringify(serviceBillings, null, 2)}`);
|
|
57
|
+
return serviceBillings?.map((value) => {
|
|
58
|
+
return {
|
|
59
|
+
title: value.service,
|
|
60
|
+
value: `${value.amount} ${value.unit}`,
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
})();
|
|
65
|
+
const client = new web_api_1.WebClient(process.env.SLACK_TOKEN);
|
|
66
|
+
const channel = process.env.SLACK_CHANNEL;
|
|
67
|
+
// Send the notification
|
|
68
|
+
await (async () => {
|
|
69
|
+
const result = await client.chat.postMessage({
|
|
70
|
+
channel,
|
|
71
|
+
icon_emoji: ':money-with-wings:',
|
|
72
|
+
text: `AWS Cost Reports (${dateRange.start} - ${dateRange.end})`,
|
|
73
|
+
attachments: [
|
|
74
|
+
{
|
|
75
|
+
title: ':moneybag: Total',
|
|
76
|
+
text: `${totalBilling?.amount} ${totalBilling?.unit}`,
|
|
77
|
+
color: '#ff8c00',
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
if (result.ok) {
|
|
82
|
+
await client.chat.postMessage({
|
|
83
|
+
channel,
|
|
84
|
+
thread_ts: result.ts,
|
|
85
|
+
attachments: [
|
|
86
|
+
{
|
|
87
|
+
color: '#ffd700',
|
|
88
|
+
fields: fields?.map((filed) => {
|
|
89
|
+
return {
|
|
90
|
+
title: `:aws: ${filed.title}`,
|
|
91
|
+
value: filed.value,
|
|
92
|
+
short: false,
|
|
93
|
+
};
|
|
94
|
+
}),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
})();
|
|
100
|
+
return 'OK';
|
|
101
|
+
};
|
|
102
|
+
exports.handler = handler;
|
|
103
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29zdC1yZXBvcnRlci5sYW1iZGEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZnVuY3MvY29zdC1yZXBvcnRlci5sYW1iZGEudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsd0VBQW1FO0FBQ25FLDRDQUEyQztBQUMzQywrREFBc0k7QUFFdEksbUVBQW1HO0FBQ25HLHlEQUFvRDtBQU1wRCxJQUFZLGNBR1g7QUFIRCxXQUFZLGNBQWM7SUFDeEIsdUNBQXFCLENBQUE7SUFDckIsdUNBQXFCLENBQUE7QUFDdkIsQ0FBQyxFQUhXLGNBQWMsOEJBQWQsY0FBYyxRQUd6QjtBQU9ELE1BQU0sUUFBUSxHQUFHLElBQUkseUNBQWtCLENBQUM7SUFDdEMsTUFBTSxFQUFFLFdBQVc7Q0FDcEIsQ0FBQyxDQUFDO0FBRUksTUFBTSxPQUFPLEdBQUcsS0FBSyxFQUFFLEtBQWlCLEVBQUUsT0FBZ0IsRUFBMkIsRUFBRTtJQUM1RixPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN4RCxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUU1RCxnQkFBZ0I7SUFDaEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDN0IsTUFBTSxJQUFJLG1EQUErQixDQUFDLDJDQUEyQyxDQUFDLENBQUM7SUFDekYsQ0FBQztJQUNELElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQy9CLE1BQU0sSUFBSSxtREFBK0IsQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFDO0lBQzNGLENBQUM7SUFDRCxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFD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SUFBSSxFQUFFLHFCQUFxQixTQUFTLENBQUMsS0FBSyxNQUFNLFNBQVMsQ0FBQyxHQUFHLEdBQUc7WUFDaEUsV0FBVyxFQUFFO2dCQUNYO29CQUNFLEtBQUssRUFBRSxrQkFBa0I7b0JBQ3pCLElBQUksRUFBRSxHQUFHLFlBQVksRUFBRSxNQUFNLElBQUksWUFBWSxFQUFFLElBQUksRUFBRTtvQkFDckQsS0FBSyxFQUFFLFNBQVM7aUJBQ2pCO2FBQ0Y7U0FDRixDQUFDLENBQUM7UUFDSCxJQUFJLE1BQU0sQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNkLE1BQU0sTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUM7Z0JBQzVCLE9BQU87Z0JBQ1AsU0FBUyxFQUFFLE1BQU0sQ0FBQyxFQUFFO2dCQUNwQixXQUFXLEVBQUU7b0JBQ1g7d0JBQ0UsS0FBSyxFQUFFLFNBQVM7d0JBQ2hCLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7NEJBQzVCLE9BQU87Z0NBQ0wsS0FBSyxFQUFFLFNBQVMsS0FBSyxDQUFDLEtBQUssRUFBRTtnQ0FDN0IsS0FBSyxFQUFFLEtBQUssQ0FBQyxLQUFLO2dDQUNsQixLQUFLLEVBQUUsS0FBSzs2QkFDYixDQUFDO3dCQUNKLENBQUMsQ0FBQztxQkFDSDtpQkFDRjthQUNGLENBQUMsQ0FBQztRQUNMLENBQUM7SUFDSCxDQUFDLENBQUMsRUFBRSxDQUFDO0lBRUwsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDLENBQUM7QUEzRlcsUUFBQSxPQUFPLFdBMkZsQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvc3RFeHBsb3JlckNsaWVudCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1jb3N0LWV4cGxvcmVyJztcbmltcG9ydCB7IFdlYkNsaWVudCB9IGZyb20gJ0BzbGFjay93ZWItYXBpJztcbmltcG9ydCB7IE1pc3NpbmdFbnZpcm9ubWVudFZhcmlhYmxlRXJyb3IsIE1pc3NpbmdJbnB1dFZhcmlhYmxlRXJyb3IsIEludmFsaWRJbnB1dFZhcmlhYmxlRm9ybWF0RXJyb3IgfSBmcm9tICdAeWljci9hd3MtbGFtYmRhLWVycm9ycyc7XG5pbXBvcnQgeyBDb250ZXh0IH0gZnJvbSAnYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyBHZXRBY2NvdW50QmlsbGluZ3MsIEdldFNlcnZpY2VCaWxsaW5nLCBHZXRUb3RhbEJpbGxpbmcgfSBmcm9tICcuL2xpYi9nZXQtYmlsbGluZy1jb21tYW5kJztcbmltcG9ydCB7IEdldERhdGVSYW5nZSB9IGZyb20gJy4vbGliL2dldC1kYXRlLXJhbmdlJztcblxuZXhwb3J0IGludGVyZmFjZSBFdmVudElucHV0IHtcbiAgcmVhZG9ubHkgVHlwZTogRXZlbnRJbnB1dFR5cGU7XG59XG5cbmV4cG9ydCBlbnVtIEV2ZW50SW5wdXRUeXBlIHtcbiAgQUNDT1VOVFMgPSAnQWNjb3VudHMnLFxuICBTRVJWSUNFUyA9ICdTZXJ2aWNlcycsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZUF0dGFjaG1lbnRGaWVsZCB7XG4gIHJlYWRvbmx5IHRpdGxlOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHZhbHVlOiBzdHJpbmc7XG59XG5cbmNvbnN0IGNlQ2xpZW50ID0gbmV3IENvc3RFeHBsb3JlckNsaWVudCh7XG4gIHJlZ2lvbjogJ3VzLWVhc3QtMScsXG59KTtcblxuZXhwb3J0IGNvbnN0IGhhbmRsZXIgPSBhc3luYyAoZXZlbnQ6IEV2ZW50SW5wdXQsIGNvbnRleHQ6IENvbnRleHQpOiBQcm9taXNlPHN0cmluZyB8IEVycm9yPiA9PiB7XG4gIGNvbnNvbGUubG9nKGBFdmVudDogJHtKU09OLnN0cmluZ2lmeShldmVudCwgbnVsbCwgMil9YCk7XG4gIGNvbnNvbGUubG9nKGBDb250ZXh0OiAke0pTT04uc3RyaW5naWZ5KGNvbnRleHQsIG51bGwsIDIpfWApO1xuXG4gIC8vIGRvIHZhbGlkYXRpb25cbiAgaWYgKCFwcm9jZXNzLmVudi5TTEFDS19UT0tFTikge1xuICAgIHRocm93IG5ldyBNaXNzaW5nRW52aXJvbm1lbnRWYXJpYWJsZUVycm9yKCdtaXNzaW5nIGVudmlyb25tZW50IHZhcmlhYmxlIFNMQUNLX1RPS0VOLicpO1xuICB9XG4gIGlmICghcHJvY2Vzcy5lbnYuU0xBQ0tfQ0hBTk5FTCkge1xuICAgIHRocm93IG5ldyBNaXNzaW5nRW52aXJvbm1lbnRWYXJpYWJsZUVycm9yKCdtaXNzaW5nIGVudmlyb25tZW50IHZhcmlhYmxlIFNMQUNLX0NIQU5ORUwuJyk7XG4gIH1cbiAgaWYgKCFldmVudC5UeXBlKSB7XG4gICAgdGhyb3cgbmV3IE1pc3NpbmdJbnB1dFZhcmlhYmxlRXJyb3IoJ21pc3NpbmcgaW5wdXQgdmFyaWFibGUgVHlwZScpO1xuICB9IGVsc2Uge1xuICAgIGlmICghT2JqZWN0LnZhbHVlcyhFdmVudElucHV0VHlwZSkuaW5jbHVkZXMoZXZlbnQuVHlwZSkpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkSW5wdXRWYXJpYWJsZUZvcm1hdEVycm9yKCdpbnZhbGlkIGlucHV0IHZhcmlhYmxlIGZvcm1hdCBpcyBBY2NvdW50cyBvciBTZXJ2aWNlcy4nKTtcbiAgICB9XG4gIH1cblxuICAvLyDwn5GHQ2FsY3VsYXRlIERhdGUgUmFuZ2VcbiAgY29uc3QgZGF0ZVJhbmdlID0gbmV3IEdldERhdGVSYW5nZSgpO1xuICBjb25zb2xlLmxvZyhgRGF0ZVJhbmdlOjoke0pTT04uc3RyaW5naWZ5KGRhdGVSYW5nZSwgbnVsbCwgMil9YCk7XG5cbiAgLy8g8J+Rh0dldCBUb3RhbCBCaWxsaW5nXG4gIGNvbnN0IHRvdGFsQmlsbGluZyA9IGF3YWl0IChuZXcgR2V0VG90YWxCaWxsaW5nKGNlQ2xpZW50KSkuZXhlY3V0ZShkYXRlUmFuZ2UpO1xuICBjb25zb2xlLmxvZyhgVG90YWxCaWxsaW5nOiAke0pTT04uc3RyaW5naWZ5KHRvdGFsQmlsbGluZywgbnVsbCwgMil9YCk7XG5cbiAgY29uc3QgZmllbGRzOiBNZXNzYWdlQXR0YWNobWVudEZpZWxkW10gfCB1bmRlZmluZWQgPSBhd2FpdCAoYXN5bmMgKCkgPT4ge1xuICAgIHN3aXRjaCAoZXZlbnQuVHlwZSkge1xuICAgICAgY2FzZSBFdmVudElucHV0VHlwZS5BQ0NPVU5UUzpcbiAgICAgICAgLy8g8J+Rh0dldCBBY2NvdW50cyBCaWxsaW5nc1xuICAgICAgICBjb25zdCBhY2NvdW50QmlsbGluZ3MgPSBhd2FpdCAobmV3IEdldEFjY291bnRCaWxsaW5ncyhjZUNsaWVudCkuZXhlY3V0ZShkYXRlUmFuZ2UpKTtcbiAgICAgICAgY29uc29sZS5sb2coYEFjY291bnRCaWxsaW5nczogJHtKU09OLnN0cmluZ2lmeShhY2NvdW50QmlsbGluZ3MsIG51bGwsIDIpfWApO1xuICAgICAgICByZXR1cm4gYWNjb3VudEJpbGxpbmdzPy5tYXAoKHZhbHVlKSA9PiB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHRpdGxlOiB2YWx1ZS5hY2NvdW50LFxuICAgICAgICAgICAgdmFsdWU6IGAke3ZhbHVlLmFtb3VudH0gJHt2YWx1ZS51bml0fWAsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgICBjYXNlIEV2ZW50SW5wdXRUeXBlLlNFUlZJQ0VTOlxuICAgICAgICAvLyDwn5GHR2V0IFNlcnZpY2UgQmlsbGluZ3NcbiAgICAgICAgY29uc3Qgc2VydmljZUJpbGxpbmdzID0gYXdhaXQgKG5ldyBHZXRTZXJ2aWNlQmlsbGluZyhjZUNsaWVudCkpLmV4ZWN1dGUoZGF0ZVJhbmdlKTtcbiAgICAgICAgY29uc29sZS5sb2coYFNlcnZpY2VCaWxsaW5nOiAke0pTT04uc3RyaW5naWZ5KHNlcnZpY2VCaWxsaW5ncywgbnVsbCwgMil9YCk7XG4gICAgICAgIHJldHVybiBzZXJ2aWNlQmlsbGluZ3M/Lm1hcCgodmFsdWUpID0+IHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdGl0bGU6IHZhbHVlLnNlcnZpY2UsXG4gICAgICAgICAgICB2YWx1ZTogYCR7dmFsdWUuYW1vdW50fSAke3ZhbHVlLnVuaXR9YCxcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICB9XG4gIH0pKCk7XG5cbiAgY29uc3QgY2xpZW50ID0gbmV3IFdlYkNsaWVudChwcm9jZXNzLmVudi5TTEFDS19UT0tFTik7XG5cbiAgY29uc3QgY2hhbm5lbCA9IHByb2Nlc3MuZW52LlNMQUNLX0NIQU5ORUw7XG5cbiAgLy8gU2VuZCB0aGUgbm90aWZpY2F0aW9uXG4gIGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY2xpZW50LmNoYXQucG9zdE1lc3NhZ2Uoe1xuICAgICAgY2hhbm5lbCxcbiAgICAgIGljb25fZW1vamk6ICc6bW9uZXktd2l0aC13aW5nczonLFxuICAgICAgdGV4dDogYEFXUyBDb3N0IFJlcG9ydHMgKCR7ZGF0ZVJhbmdlLnN0YXJ0fSAtICR7ZGF0ZVJhbmdlLmVuZH0pYCxcbiAgICAgIGF0dGFjaG1lbnRzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICB0aXRsZTogJzptb25leWJhZzogVG90YWwnLFxuICAgICAgICAgIHRleHQ6IGAke3RvdGFsQmlsbGluZz8uYW1vdW50fSAke3RvdGFsQmlsbGluZz8udW5pdH1gLFxuICAgICAgICAgIGNvbG9yOiAnI2ZmOGMwMCcsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICAgIGlmIChyZXN1bHQub2spIHtcbiAgICAgIGF3YWl0IGNsaWVudC5jaGF0LnBvc3RNZXNzYWdlKHtcbiAgICAgICAgY2hhbm5lbCxcbiAgICAgICAgdGhyZWFkX3RzOiByZXN1bHQudHMsXG4gICAgICAgIGF0dGFjaG1lbnRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgY29sb3I6ICcjZmZkNzAwJyxcbiAgICAgICAgICAgIGZpZWxkczogZmllbGRzPy5tYXAoKGZpbGVkKSA9PiB7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdGl0bGU6IGA6YXdzOiAke2ZpbGVkLnRpdGxlfWAsXG4gICAgICAgICAgICAgICAgdmFsdWU6IGZpbGVkLnZhbHVlLFxuICAgICAgICAgICAgICAgIHNob3J0OiBmYWxzZSxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcbiAgICB9XG4gIH0pKCk7XG5cbiAgcmV0dXJuICdPSyc7XG59O1xuXG4iXX0=
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { CostExplorerClient } from '@aws-sdk/client-cost-explorer';
|
|
2
|
+
import { GetDateRange } from './get-date-range';
|
|
3
|
+
export interface TotalBilling {
|
|
4
|
+
readonly unit: string;
|
|
5
|
+
readonly amount: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class GetTotalBilling {
|
|
8
|
+
private client;
|
|
9
|
+
constructor(client: CostExplorerClient);
|
|
10
|
+
execute: (dateRange: GetDateRange) => Promise<TotalBilling | undefined>;
|
|
11
|
+
}
|
|
12
|
+
export interface ServiceBilling {
|
|
13
|
+
readonly service: string;
|
|
14
|
+
readonly unit: string;
|
|
15
|
+
readonly amount: number;
|
|
16
|
+
}
|
|
17
|
+
export declare class GetServiceBilling {
|
|
18
|
+
private client;
|
|
19
|
+
constructor(client: CostExplorerClient);
|
|
20
|
+
execute: (dateRange: GetDateRange, nextPageToken?: string) => Promise<ServiceBilling[] | undefined>;
|
|
21
|
+
}
|
|
22
|
+
export interface AccountBilling {
|
|
23
|
+
readonly account: string;
|
|
24
|
+
readonly amount: number;
|
|
25
|
+
readonly unit: string;
|
|
26
|
+
}
|
|
27
|
+
export declare class GetAccountBillings {
|
|
28
|
+
private client;
|
|
29
|
+
constructor(client: CostExplorerClient);
|
|
30
|
+
execute: (dateRange: GetDateRange, nextPageToken?: string) => Promise<AccountBilling[] | undefined>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetAccountBillings = exports.GetServiceBilling = exports.GetTotalBilling = void 0;
|
|
4
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
5
|
+
const client_cost_explorer_1 = require("@aws-sdk/client-cost-explorer");
|
|
6
|
+
class GetTotalBilling {
|
|
7
|
+
constructor(client) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
this.execute = async (dateRange) => {
|
|
10
|
+
const input = {
|
|
11
|
+
TimePeriod: {
|
|
12
|
+
Start: dateRange.start,
|
|
13
|
+
End: dateRange.end,
|
|
14
|
+
},
|
|
15
|
+
Granularity: 'MONTHLY',
|
|
16
|
+
Metrics: [
|
|
17
|
+
'AMORTIZED_COST',
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
console.log(`TotalBilling:Command:Input:${JSON.stringify(input)}`);
|
|
21
|
+
return this.client.send(new client_cost_explorer_1.GetCostAndUsageCommand(input))
|
|
22
|
+
.then((data) => {
|
|
23
|
+
if (data && data.ResultsByTime && data.ResultsByTime.length === 1) {
|
|
24
|
+
const cost = Object(data.ResultsByTime[0]).Total.AmortizedCost;
|
|
25
|
+
const result = {
|
|
26
|
+
unit: cost.Unit,
|
|
27
|
+
amount: cost.Amount,
|
|
28
|
+
};
|
|
29
|
+
console.log(`TotalBilling:Command:Output(Shaped):${JSON.stringify(result)}`);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
})
|
|
34
|
+
.catch((error) => {
|
|
35
|
+
console.log('Error caught...');
|
|
36
|
+
console.log(`Error:${JSON.stringify(error)}`);
|
|
37
|
+
return undefined;
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
;
|
|
42
|
+
}
|
|
43
|
+
exports.GetTotalBilling = GetTotalBilling;
|
|
44
|
+
class GetServiceBilling {
|
|
45
|
+
constructor(client) {
|
|
46
|
+
this.client = client;
|
|
47
|
+
this.execute = async (dateRange, nextPageToken) => {
|
|
48
|
+
const input = {
|
|
49
|
+
NextPageToken: nextPageToken,
|
|
50
|
+
TimePeriod: {
|
|
51
|
+
Start: dateRange.start,
|
|
52
|
+
End: dateRange.end,
|
|
53
|
+
},
|
|
54
|
+
Granularity: 'MONTHLY',
|
|
55
|
+
Metrics: [
|
|
56
|
+
'AMORTIZED_COST',
|
|
57
|
+
],
|
|
58
|
+
GroupBy: [
|
|
59
|
+
{
|
|
60
|
+
Type: 'DIMENSION',
|
|
61
|
+
Key: 'SERVICE',
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
console.log(`ServiceBillings:Command:Input:${JSON.stringify(input)}`);
|
|
66
|
+
return this.client.send(new client_cost_explorer_1.GetCostAndUsageCommand(input))
|
|
67
|
+
.then(async (data) => {
|
|
68
|
+
const billings = [];
|
|
69
|
+
if (data.ResultsByTime && data.ResultsByTime.length === 1) {
|
|
70
|
+
for (const item of Object(data.ResultsByTime[0]).Groups) {
|
|
71
|
+
billings.push({
|
|
72
|
+
service: item.Keys[0],
|
|
73
|
+
unit: item.Metrics.AmortizedCost.Unit,
|
|
74
|
+
amount: item.Metrics.AmortizedCost.Amount,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
console.log(`ServiceBillings:Command:Output(Shaped):${JSON.stringify(billings)}`);
|
|
78
|
+
if (data.NextPageToken) {
|
|
79
|
+
const nextBillings = await this.execute(dateRange, data.NextPageToken);
|
|
80
|
+
if (nextBillings) {
|
|
81
|
+
return billings.concat(nextBillings);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return billings;
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
})
|
|
88
|
+
.catch(async (error) => {
|
|
89
|
+
console.log('Error caught...');
|
|
90
|
+
console.log(`Error:${JSON.stringify(error)}`);
|
|
91
|
+
return undefined;
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
;
|
|
96
|
+
}
|
|
97
|
+
exports.GetServiceBilling = GetServiceBilling;
|
|
98
|
+
class GetAccountBillings {
|
|
99
|
+
constructor(client) {
|
|
100
|
+
this.client = client;
|
|
101
|
+
this.execute = async (dateRange, nextPageToken) => {
|
|
102
|
+
const input = {
|
|
103
|
+
NextPageToken: nextPageToken,
|
|
104
|
+
TimePeriod: {
|
|
105
|
+
Start: dateRange.start,
|
|
106
|
+
End: dateRange.end,
|
|
107
|
+
},
|
|
108
|
+
Granularity: 'MONTHLY',
|
|
109
|
+
Metrics: [
|
|
110
|
+
'AMORTIZED_COST',
|
|
111
|
+
],
|
|
112
|
+
GroupBy: [
|
|
113
|
+
{
|
|
114
|
+
Type: 'DIMENSION',
|
|
115
|
+
Key: 'LINKED_ACCOUNT',
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
console.log(`AccountBillings:Command:Input:${JSON.stringify(input)}`);
|
|
120
|
+
return this.client.send(new client_cost_explorer_1.GetCostAndUsageCommand(input))
|
|
121
|
+
.then(async (data) => {
|
|
122
|
+
const billings = [];
|
|
123
|
+
if (data.ResultsByTime && data.ResultsByTime.length === 1) {
|
|
124
|
+
const groups = Object(data.ResultsByTime[0]).Groups;
|
|
125
|
+
const dimensionValueAttributes = data.DimensionValueAttributes;
|
|
126
|
+
for (const item of groups) {
|
|
127
|
+
for (const attr of dimensionValueAttributes) {
|
|
128
|
+
if (item.Keys[0] === attr.Value) {
|
|
129
|
+
billings.push({
|
|
130
|
+
account: `${attr.Value} (${attr.Attributes.description})`,
|
|
131
|
+
unit: item.Metrics.AmortizedCost.Unit,
|
|
132
|
+
amount: item.Metrics.AmortizedCost.Amount,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
console.log(`AccountBillings:Command:Output(Shaped):${JSON.stringify(billings)}`);
|
|
138
|
+
if (data.NextPageToken) {
|
|
139
|
+
const nextBillings = await this.execute(dateRange, data.NextPageToken);
|
|
140
|
+
if (nextBillings) {
|
|
141
|
+
return billings.concat(nextBillings);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return billings;
|
|
145
|
+
}
|
|
146
|
+
return undefined;
|
|
147
|
+
})
|
|
148
|
+
.catch(async (error) => {
|
|
149
|
+
console.log('Error caught...');
|
|
150
|
+
console.log(`Error:${JSON.stringify(error)}`);
|
|
151
|
+
return undefined;
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
;
|
|
156
|
+
}
|
|
157
|
+
exports.GetAccountBillings = GetAccountBillings;
|
|
158
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LWJpbGxpbmctY29tbWFuZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9mdW5jcy9saWIvZ2V0LWJpbGxpbmctY29tbWFuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2REFBNkQ7QUFDN0Qsd0VBQXNKO0FBUXRKLE1BQWEsZUFBZTtJQUUxQixZQUNVLE1BQTBCO1FBQTFCLFdBQU0sR0FBTixNQUFNLENBQW9CO1FBRzdCLFlBQU8sR0FBRyxLQUFLLEVBQUUsU0FBdUIsRUFBcUMsRUFBRTtZQUNwRixNQUFNLEtBQUssR0FBZ0M7Z0JBQ3pDLFVBQVUsRUFBRTtvQkFDVixLQUFLLEVBQUUsU0FBUyxDQUFDLEtBQUs7b0JBQ3RCLEdBQUcsRUFBRSxTQUFTLENBQUMsR0FBRztpQkFDbkI7Z0JBQ0QsV0FBVyxFQUFFLFNBQVM7Z0JBQ3RCLE9BQU8sRUFBRTtvQkFDUCxnQkFBZ0I7aUJBQ2pCO2FBQ0YsQ0FBQztZQUNGLE9BQU8sQ0FBQyxHQUFHLENBQUMsOEJBQThCLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ25FLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSw2Q0FBc0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztpQkFDdkQsSUFBSSxDQUFDLENBQUMsSUFBa0MsRUFBRSxFQUFFO2dCQUMzQyxJQUFJLElBQUksSUFBSSxJQUFJLENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUNsRSxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUM7b0JBQy9ELE1BQU0sTUFBTSxHQUFpQjt3QkFDM0IsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJO3dCQUNmLE1BQU0sRUFBRSxJQUFJLENBQUMs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LE9BQU8sU0FBUyxDQUFDO1lBQ25CLENBQUMsQ0FBQztpQkFDRCxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFO2dCQUNyQixPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLENBQUM7Z0JBQy9CLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDOUMsT0FBTyxTQUFTLENBQUM7WUFDbkIsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDLENBQUM7SUF0REMsQ0FBQztJQUFBLENBQUM7Q0F1RE47QUExREQsZ0RBMERDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0IHsgQ29zdEV4cGxvcmVyQ2xpZW50LCBHZXRDb3N0QW5kVXNhZ2VDb21tYW5kLCBHZXRDb3N0QW5kVXNhZ2VDb21tYW5kSW5wdXQsIEdldENvc3RBbmRVc2FnZUNvbW1hbmRPdXRwdXQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtY29zdC1leHBsb3Jlcic7XG5pbXBvcnQgeyBHZXREYXRlUmFuZ2UgfSBmcm9tICcuL2dldC1kYXRlLXJhbmdlJztcblxuZXhwb3J0IGludGVyZmFjZSBUb3RhbEJpbGxpbmcge1xuICByZWFkb25seSB1bml0OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGFtb3VudDogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgR2V0VG90YWxCaWxsaW5nIHtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGNsaWVudDogQ29zdEV4cGxvcmVyQ2xpZW50LFxuICApIHt9O1xuXG4gIHB1YmxpYyBleGVjdXRlID0gYXN5bmMgKGRhdGVSYW5nZTogR2V0RGF0ZVJhbmdlKTogUHJvbWlzZTxUb3RhbEJpbGxpbmcgfCB1bmRlZmluZWQ+ID0+IHtcbiAgICBjb25zdCBpbnB1dDogR2V0Q29zdEFuZFVzYWdlQ29tbWFuZElucHV0ID0ge1xuICAgICAgVGltZVBlcmlvZDoge1xuICAgICAgICBTdGFydDogZGF0ZVJhbmdlLnN0YXJ0LFxuICAgICAgICBFbmQ6IGRhdGVSYW5nZS5lbmQsXG4gICAgICB9LFxuICAgICAgR3JhbnVsYXJpdHk6ICdNT05USExZJyxcbiAgICAgIE1ldHJpY3M6IFtcbiAgICAgICAgJ0FNT1JUSVpFRF9DT1NUJyxcbiAgICAgIF0sXG4gICAgfTtcbiAgICBjb25zb2xlLmxvZyhgVG90YWxCaWxsaW5nOkNvbW1hbmQ6SW5wdXQ6JHtKU09OLnN0cmluZ2lmeShpbnB1dCl9YCk7XG4gICAgcmV0dXJuIHRoaXMuY2xpZW50LnNlbmQobmV3IEdldENvc3RBbmRVc2FnZUNvbW1hbmQoaW5wdXQpKVxuICAgICAgLnRoZW4oKGRhdGE6IEdldENvc3RBbmRVc2FnZUNvbW1hbmRPdXRwdXQpID0+IHtcbiAgICAgICAgaWYgKGRhdGEgJiYgZGF0YS5SZXN1bHRzQnlUaW1lICYmIGRhdGEuUmVzdWx0c0J5VGltZS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBjb25zdCBjb3N0ID0gT2JqZWN0KGRhdGEuUmVzdWx0c0J5VGltZVswXSkuVG90YWwuQW1vcnRpemVkQ29zdDtcbiAgICAgICAgICBjb25zdCByZXN1bHQ6IFRvdGFsQmlsbGluZyA9IHtcbiAgICAgICAgICAgIHVuaXQ6IGNvc3QuVW5pdCxcbiAgICAgICAgICAgIGFtb3VudDogY29zdC5BbW91bnQsXG4gICAgICAgICAgfTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgVG90YWxCaWxsaW5nOkNvbW1hbmQ6T3V0cHV0KFNoYXBlZCk6JHtKU09OLnN0cmluZ2lmeShyZXN1bHQpfWApO1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdFcnJvciBjYXVnaHQuLi4nKTtcbiAgICAgICAgY29uc29sZS5sb2coYEVycm9yOiR7SlNPTi5zdHJpbmdpZnkoZXJyb3IpfWApO1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfSk7XG4gIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VydmljZUJpbGxpbmcge1xuICByZWFkb25seSBzZXJ2aWNlOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHVuaXQ6IHN0cmluZztcbiAgcmVhZG9ubHkgYW1vdW50OiBudW1iZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBHZXRTZXJ2aWNlQmlsbGluZyB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgY2xpZW50OiBDb3N0RXhwbG9yZXJDbGllbnQsXG4gICkge307XG5cbiAgcHVibGljIGV4ZWN1dGUgPSBhc3luYyAoZGF0ZVJhbmdlOiBHZXREYXRlUmFuZ2UsIG5leHRQYWdlVG9rZW4/OiBzdHJpbmcpOiBQcm9taXNlPFNlcnZpY2VCaWxsaW5nW10gfCB1bmRlZmluZWQ+ID0+IHtcbiAgICBjb25zdCBpbnB1dDogR2V0Q29zdEFuZFVzYWdlQ29tbWFuZElucHV0ID0ge1xuICAgICAgTmV4dFBhZ2VUb2tlbjogbmV4dFBhZ2VUb2tlbixcbiAgICAgIFRpbWVQZXJpb2Q6IHtcbiAgICAgICAgU3RhcnQ6IGRhdGVSYW5nZS5zdGFydCxcbiAgICAgICAgRW5kOiBkYXRlUmFuZ2UuZW5kLFxuICAgICAgfSxcbiAgICAgIEdyYW51bGFyaXR5OiAnTU9OVEhMWScsXG4gICAgICBNZXRyaWNzOiBbXG4gICAgICAgICdBTU9SVElaRURfQ09TVCcsXG4gICAgICBdLFxuICAgICAgR3JvdXBCeTogW1xuICAgICAgICB7XG4gICAgICAgICAgVHlwZTogJ0RJTUVOU0lPTicsXG4gICAgICAgICAgS2V5OiAnU0VSVklDRScsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH07XG4gICAgY29uc29sZS5sb2coYFNlcnZpY2VCaWxsaW5nczpDb21tYW5kOklucHV0OiR7SlNPTi5zdHJpbmdpZnkoaW5wdXQpfWApO1xuICAgIHJldHVybiB0aGlzLmNsaWVudC5zZW5kKG5ldyBHZXRDb3N0QW5kVXNhZ2VDb21tYW5kKGlucHV0KSlcbiAgICAgIC50aGVuKGFzeW5jIChkYXRhKSA9PiB7XG4gICAgICAgIGNvbnN0IGJpbGxpbmdzOiBTZXJ2aWNlQmlsbGluZ1tdID0gW107XG4gICAgICAgIGlmIChkYXRhLlJlc3VsdHNCeVRpbWUgJiYgZGF0YS5SZXN1bHRzQnlUaW1lLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBPYmplY3QoZGF0YS5SZXN1bHRzQnlUaW1lWzBdKS5Hcm91cHMpIHtcbiAgICAgICAgICAgIGJpbGxpbmdzLnB1c2goe1xuICAgICAgICAgICAgICBzZXJ2aWNlOiBpdGVtLktleXNbMF0sXG4gICAgICAgICAgICAgIHVuaXQ6IGl0ZW0uTWV0cmljcy5BbW9ydGl6ZWRDb3N0LlVuaXQsXG4gICAgICAgICAgICAgIGFtb3VudDogaXRlbS5NZXRyaWNzLkFtb3J0aXplZENvc3QuQW1vdW50LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnNvbGUubG9nKGBTZXJ2aWNlQmlsbGluZ3M6Q29tbWFuZDpPdXRwdXQoU2hhcGVkKToke0pTT04uc3RyaW5naWZ5KGJpbGxpbmdzKX1gKTtcbiAgICAgICAgICBpZiAoZGF0YS5OZXh0UGFnZVRva2VuKSB7XG4gICAgICAgICAgICBjb25zdCBuZXh0QmlsbGluZ3MgPSBhd2FpdCB0aGlzLmV4ZWN1dGUoZGF0ZVJhbmdlLCBkYXRhLk5leHRQYWdlVG9rZW4pO1xuICAgICAgICAgICAgaWYgKG5leHRCaWxsaW5ncykge1xuICAgICAgICAgICAgICByZXR1cm4gYmlsbGluZ3MuY29uY2F0KG5leHRCaWxsaW5ncyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBiaWxsaW5ncztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfSlcbiAgICAgIC5jYXRjaChhc3luYyAoZXJyb3IpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coJ0Vycm9yIGNhdWdodC4uLicpO1xuICAgICAgICBjb25zb2xlLmxvZyhgRXJyb3I6JHtKU09OLnN0cmluZ2lmeShlcnJvcil9YCk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9KTtcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBY2NvdW50QmlsbGluZyB7XG4gIHJlYWRvbmx5IGFjY291bnQ6IHN0cmluZztcbiAgcmVhZG9ubHkgYW1vdW50OiBudW1iZXI7XG4gIHJlYWRvbmx5IHVuaXQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGNsYXNzIEdldEFjY291bnRCaWxsaW5ncyB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgY2xpZW50OiBDb3N0RXhwbG9yZXJDbGllbnQsXG4gICkge307XG5cbiAgcHVibGljIGV4ZWN1dGUgPSBhc3luYyAoZGF0ZVJhbmdlOiBHZXREYXRlUmFuZ2UsIG5leHRQYWdlVG9rZW4/OiBzdHJpbmcpOiBQcm9taXNlPEFjY291bnRCaWxsaW5nW10gfCB1bmRlZmluZWQ+ID0+IHtcbiAgICBjb25zdCBpbnB1dDogR2V0Q29zdEFuZFVzYWdlQ29tbWFuZElucHV0ID0ge1xuICAgICAgTmV4dFBhZ2VUb2tlbjogbmV4dFBhZ2VUb2tlbixcbiAgICAgIFRpbWVQZXJpb2Q6IHtcbiAgICAgICAgU3RhcnQ6IGRhdGVSYW5nZS5zdGFydCxcbiAgICAgICAgRW5kOiBkYXRlUmFuZ2UuZW5kLFxuICAgICAgfSxcbiAgICAgIEdyYW51bGFyaXR5OiAnTU9OVEhMWScsXG4gICAgICBNZXRyaWNzOiBbXG4gICAgICAgICdBTU9SVElaRURfQ09TVCcsXG4gICAgICBdLFxuICAgICAgR3JvdXBCeTogW1xuICAgICAgICB7XG4gICAgICAgICAgVHlwZTogJ0RJTUVOU0lPTicsXG4gICAgICAgICAgS2V5OiAnTElOS0VEX0FDQ09VTlQnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9O1xuICAgIGNvbnNvbGUubG9nKGBBY2NvdW50QmlsbGluZ3M6Q29tbWFuZDpJbnB1dDoke0pTT04uc3RyaW5naWZ5KGlucHV0KX1gKTtcbiAgICByZXR1cm4gdGhpcy5jbGllbnQuc2VuZChuZXcgR2V0Q29zdEFuZFVzYWdlQ29tbWFuZChpbnB1dCkpXG4gICAgICAudGhlbihhc3luYyAoZGF0YSkgPT4ge1xuICAgICAgICBjb25zdCBiaWxsaW5nczogQWNjb3VudEJpbGxpbmdbXSA9IFtdO1xuICAgICAgICBpZiAoZGF0YS5SZXN1bHRzQnlUaW1lICYmIGRhdGEuUmVzdWx0c0J5VGltZS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBjb25zdCBncm91cHMgPSBPYmplY3QoZGF0YS5SZXN1bHRzQnlUaW1lWzBdKS5Hcm91cHM7XG4gICAgICAgICAgY29uc3QgZGltZW5zaW9uVmFsdWVBdHRyaWJ1dGVzID0gZGF0YS5EaW1lbnNpb25WYWx1ZUF0dHJpYnV0ZXMhO1xuICAgICAgICAgIGZvciAoY29uc3QgaXRlbSBvZiBncm91cHMpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgYXR0ciBvZiBkaW1lbnNpb25WYWx1ZUF0dHJpYnV0ZXMpIHtcbiAgICAgICAgICAgICAgaWYgKGl0ZW0uS2V5c1swXSA9PT0gYXR0ci5WYWx1ZSkge1xuICAgICAgICAgICAgICAgIGJpbGxpbmdzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgYWNjb3VudDogYCR7YXR0ci5WYWx1ZX0gKCR7YXR0ci5BdHRyaWJ1dGVzIS5kZXNjcmlwdGlvbn0pYCxcbiAgICAgICAgICAgICAgICAgIHVuaXQ6IGl0ZW0uTWV0cmljcy5BbW9ydGl6ZWRDb3N0LlVuaXQsXG4gICAgICAgICAgICAgICAgICBhbW91bnQ6IGl0ZW0uTWV0cmljcy5BbW9ydGl6ZWRDb3N0LkFtb3VudCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zb2xlLmxvZyhgQWNjb3VudEJpbGxpbmdzOkNvbW1hbmQ6T3V0cHV0KFNoYXBlZCk6JHtKU09OLnN0cmluZ2lmeShiaWxsaW5ncyl9YCk7XG4gICAgICAgICAgaWYgKGRhdGEuTmV4dFBhZ2VUb2tlbikge1xuICAgICAgICAgICAgY29uc3QgbmV4dEJpbGxpbmdzID0gYXdhaXQgdGhpcy5leGVjdXRlKGRhdGVSYW5nZSwgZGF0YS5OZXh0UGFnZVRva2VuKTtcbiAgICAgICAgICAgIGlmIChuZXh0QmlsbGluZ3MpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGJpbGxpbmdzLmNvbmNhdChuZXh0QmlsbGluZ3MpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gYmlsbGluZ3M7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goYXN5bmMgKGVycm9yKSA9PiB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdFcnJvciBjYXVnaHQuLi4nKTtcbiAgICAgICAgY29uc29sZS5sb2coYEVycm9yOiR7SlNPTi5zdHJpbmdpZnkoZXJyb3IpfWApO1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfSk7XG4gIH07XG59Il19
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetDateRange = void 0;
|
|
4
|
+
class GetDateRange {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.dateFormatString = (date) => {
|
|
7
|
+
return (date.getFullYear()) + '-' + ('00' + (date.getMonth() + 1)).slice(-2) + '-' + ('00' + (date.getDate())).slice(-2);
|
|
8
|
+
};
|
|
9
|
+
const now = new Date(Date.now());
|
|
10
|
+
if (now.getDate() === 1) {
|
|
11
|
+
// Last month
|
|
12
|
+
this.start = this.dateFormatString(new Date(now.getFullYear(), now.getMonth() - 1, 1));
|
|
13
|
+
this.end = this.dateFormatString(new Date(now.getFullYear(), now.getMonth(), 0));
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
this.start = this.dateFormatString(new Date(now.getFullYear(), now.getMonth(), 1));
|
|
17
|
+
this.end = this.dateFormatString(new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.GetDateRange = GetDateRange;
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LWRhdGUtcmFuZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZnVuY3MvbGliL2dldC1kYXRlLXJhbmdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLE1BQWEsWUFBWTtJQUt2QjtRQVlRLHFCQUFnQixHQUFHLENBQUMsSUFBVSxFQUFVLEVBQUU7WUFDaEQsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDM0gsQ0FBQyxDQUFDO1FBYkEsTUFBTSxHQUFHLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDakMsSUFBSSxHQUFHLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDeEIsYUFBYTtZQUNiLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsRUFBRSxHQUFHLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdkYsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxFQUFFLEdBQUcsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25GLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxFQUFFLEdBQUcsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ25GLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsRUFBRSxHQUFHLENBQUMsUUFBUSxFQUFFLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbkcsQ0FBQztJQUNILENBQUM7Q0FLRjtBQXBCRCxvQ0FvQkMiLCJzb3VyY2VzQ29udGVudCI6WyJcblxuZXhwb3J0IGNsYXNzIEdldERhdGVSYW5nZSB7XG5cbiAgcHVibGljIHN0YXJ0OiBzdHJpbmc7XG4gIHB1YmxpYyBlbmQ6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBjb25zdCBub3cgPSBuZXcgRGF0ZShEYXRlLm5vdygpKTtcbiAgICBpZiAobm93LmdldERhdGUoKSA9PT0gMSkge1xuICAgICAgLy8gTGFzdCBtb250aFxuICAgICAgdGhpcy5zdGFydCA9IHRoaXMuZGF0ZUZvcm1hdFN0cmluZyhuZXcgRGF0ZShub3cuZ2V0RnVsbFllYXIoKSwgbm93LmdldE1vbnRoKCkgLSAxLCAxKSk7XG4gICAgICB0aGlzLmVuZCA9IHRoaXMuZGF0ZUZvcm1hdFN0cmluZyhuZXcgRGF0ZShub3cuZ2V0RnVsbFllYXIoKSwgbm93LmdldE1vbnRoKCksIDApKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zdGFydCA9IHRoaXMuZGF0ZUZvcm1hdFN0cmluZyhuZXcgRGF0ZShub3cuZ2V0RnVsbFllYXIoKSwgbm93LmdldE1vbnRoKCksIDEpKTtcbiAgICAgIHRoaXMuZW5kID0gdGhpcy5kYXRlRm9ybWF0U3RyaW5nKG5ldyBEYXRlKG5vdy5nZXRGdWxsWWVhcigpLCBub3cuZ2V0TW9udGgoKSwgbm93LmdldERhdGUoKSAtIDEpKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGRhdGVGb3JtYXRTdHJpbmcgPSAoZGF0ZTogRGF0ZSk6IHN0cmluZyA9PiB7XG4gICAgcmV0dXJuIChkYXRlLmdldEZ1bGxZZWFyKCkpICsgJy0nICsgKCcwMCcgKyAoZGF0ZS5nZXRNb250aCgpICsgMSkpLnNsaWNlKC0yKSArICctJyArICgnMDAnICsgKGRhdGUuZ2V0RGF0ZSgpKSkuc2xpY2UoLTIpO1xuICB9O1xufSJdfQ==
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Stack } from 'aws-cdk-lib';
|
|
2
|
+
import { Construct } from 'constructs';
|
|
3
|
+
export interface DailyCostUsageReportStackProps {
|
|
4
|
+
readonly slackToken: string;
|
|
5
|
+
readonly slackChannel: string;
|
|
6
|
+
readonly scheduleTimezone?: string;
|
|
7
|
+
readonly costGroupType: CostGroupType;
|
|
8
|
+
}
|
|
9
|
+
export declare enum CostGroupType {
|
|
10
|
+
ACCOUNTS = "Accounts",
|
|
11
|
+
SERVICES = "Services"
|
|
12
|
+
}
|
|
13
|
+
export declare class DailyCostUsageReportStack extends Stack {
|
|
14
|
+
constructor(scope: Construct, id: string, props: DailyCostUsageReportStackProps);
|
|
15
|
+
}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.DailyCostUsageReportStack = exports.CostGroupType = void 0;
|
|
5
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
6
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
7
|
+
const iam = require("aws-cdk-lib/aws-iam");
|
|
8
|
+
const scheduler = require("aws-cdk-lib/aws-scheduler");
|
|
9
|
+
const cost_reporter_function_1 = require("./funcs/cost-reporter-function");
|
|
10
|
+
var CostGroupType;
|
|
11
|
+
(function (CostGroupType) {
|
|
12
|
+
CostGroupType["ACCOUNTS"] = "Accounts";
|
|
13
|
+
CostGroupType["SERVICES"] = "Services";
|
|
14
|
+
})(CostGroupType || (exports.CostGroupType = CostGroupType = {}));
|
|
15
|
+
class DailyCostUsageReportStack extends aws_cdk_lib_1.Stack {
|
|
16
|
+
constructor(scope, id, props) {
|
|
17
|
+
super(scope, id);
|
|
18
|
+
// 👇Get current account & region
|
|
19
|
+
// const account = Stack.of(this).account;
|
|
20
|
+
// const region = cdk.Stack.of(this).region;
|
|
21
|
+
// 👇Lambda Exec Role
|
|
22
|
+
const lambdaExecutionRole = new iam.Role(this, 'LambdaExecutionRole', {
|
|
23
|
+
roleName: undefined,
|
|
24
|
+
description: '',
|
|
25
|
+
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
|
|
26
|
+
managedPolicies: [
|
|
27
|
+
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
|
|
28
|
+
],
|
|
29
|
+
inlinePolicies: {
|
|
30
|
+
['get-cost-usage']: new iam.PolicyDocument({
|
|
31
|
+
statements: [
|
|
32
|
+
new iam.PolicyStatement({
|
|
33
|
+
effect: iam.Effect.ALLOW,
|
|
34
|
+
actions: [
|
|
35
|
+
'ce:GetCostAndUsage',
|
|
36
|
+
],
|
|
37
|
+
resources: ['*'],
|
|
38
|
+
}),
|
|
39
|
+
],
|
|
40
|
+
}),
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
// 👇Lambda Function
|
|
44
|
+
const lambdaFunction = new cost_reporter_function_1.CostReporterFunction(this, 'CostReporterFunction', {
|
|
45
|
+
functionName: undefined,
|
|
46
|
+
description: 'A function to archive logs s3 bucket from CloudWatch Logs.',
|
|
47
|
+
environment: {
|
|
48
|
+
//BUCKET_NAME: logArchiveBucket.bucketName,
|
|
49
|
+
SLACK_TOKEN: props.slackToken,
|
|
50
|
+
SLACK_CHANNEL: props.slackChannel,
|
|
51
|
+
},
|
|
52
|
+
role: lambdaExecutionRole,
|
|
53
|
+
timeout: aws_cdk_lib_1.Duration.seconds(45),
|
|
54
|
+
});
|
|
55
|
+
// 👇EventBridge Scheduler IAM Role
|
|
56
|
+
const schedulerExecutionRole = new iam.Role(this, 'SchedulerExecutionRole', {
|
|
57
|
+
roleName: undefined,
|
|
58
|
+
assumedBy: new iam.ServicePrincipal('scheduler.amazonaws.com'),
|
|
59
|
+
inlinePolicies: {
|
|
60
|
+
['lambda-invoke-policy']: new iam.PolicyDocument({
|
|
61
|
+
statements: [
|
|
62
|
+
new iam.PolicyStatement({
|
|
63
|
+
effect: iam.Effect.ALLOW,
|
|
64
|
+
actions: [
|
|
65
|
+
'lambda:InvokeFunction',
|
|
66
|
+
],
|
|
67
|
+
resources: [
|
|
68
|
+
lambdaFunction.functionArn,
|
|
69
|
+
`${lambdaFunction.functionArn}:*`,
|
|
70
|
+
],
|
|
71
|
+
}),
|
|
72
|
+
],
|
|
73
|
+
}),
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
// 👇Schedule
|
|
77
|
+
new scheduler.CfnSchedule(this, 'Schedule', {
|
|
78
|
+
name: undefined,
|
|
79
|
+
description: 'aws account const reports.',
|
|
80
|
+
state: 'ENABLED',
|
|
81
|
+
//groupName: scheduleGroup.name, // default
|
|
82
|
+
flexibleTimeWindow: {
|
|
83
|
+
mode: 'OFF',
|
|
84
|
+
},
|
|
85
|
+
scheduleExpressionTimezone: props.scheduleTimezone ?? 'UTC',
|
|
86
|
+
scheduleExpression: 'cron(1 9 * * ? *)',
|
|
87
|
+
target: {
|
|
88
|
+
arn: lambdaFunction.functionArn,
|
|
89
|
+
roleArn: schedulerExecutionRole.roleArn,
|
|
90
|
+
input: JSON.stringify({ Type: props.costGroupType }),
|
|
91
|
+
retryPolicy: {
|
|
92
|
+
maximumEventAgeInSeconds: 60,
|
|
93
|
+
maximumRetryAttempts: 0,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.DailyCostUsageReportStack = DailyCostUsageReportStack;
|
|
100
|
+
_a = JSII_RTTI_SYMBOL_1;
|
|
101
|
+
DailyCostUsageReportStack[_a] = { fqn: "@gammarers/aws-daily-cost-usage-report-stack.DailyCostUsageReportStack", version: "2.0.0" };
|
|
102
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSw2Q0FBOEM7QUFDOUMsMkNBQTJDO0FBQzNDLHVEQUF1RDtBQUV2RCwyRUFBc0U7QUFTdEUsSUFBWSxhQUdYO0FBSEQsV0FBWSxhQUFhO0lBQ3ZCLHNDQUFxQixDQUFBO0lBQ3JCLHNDQUFxQixDQUFBO0FBQ3ZCLENBQUMsRUFIVyxhQUFhLDZCQUFiLGFBQWEsUUFHeEI7QUFFRCxNQUFhLHlCQUEwQixTQUFRLG1CQUFLO0lBQ2xELFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBcUM7UUFDN0UsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixpQ0FBaUM7UUFDakMsMENBQTBDO1FBQzFDLDRDQUE0QztRQUU1QyxxQkFBcUI7UUFDckIsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLHFCQUFxQixFQUFFO1lBQ3BFLFFBQVEsRUFBRSxTQUFTO1lBQ25CLFdBQVcsRUFBRSxFQUFFO1lBQ2YsU0FBUyxFQUFFLElBQUksR0FBRyxDQUFDLGdCQUFnQixDQUFDLHNCQUFzQixDQUFDO1lBQzNELGVBQWUsRUFBRTtnQkFDZixHQUFHLENBQUMsYUFBYSxDQUFDLHdCQUF3QixDQUFDLDBDQUEwQyxDQUFDO2FBQ3ZGO1lBQ0QsY0FBYyxFQUFFO2dCQUNkLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxjQUFjLENBQUM7b0JBQ3pDLFVBQVUsRUFBRTt3QkFDVixJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUM7NEJBQ3RCLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUs7NEJBQ3hCLE9BQU8sRUFBRTtnQ0FDUCxvQkFBb0I7NkJBQ3JCOzRCQUNELFNBQVMsRUFBRSxDQUFDLEdBQUcsQ0FBQzt5QkFDakIsQ0FBQztxQkFDSDtpQkFDRixDQUFDO2FBQ0g7U0FDRixDQUFDLENBQUM7UUFFSCxvQkFBb0I7UUFDcEIsTUFBTSxjQUFjLEdBQUcsSUFBSSw2Q0FBb0IsQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLEVBQUU7WUFDNUUsWUFBWSxFQUFFLFNBQVM7WUFDdkIsV0FBVyxFQUFFLDREQUE0RDtZQUN6RSxXQUFXLEVBQUU7Z0JBQ1gsMkNBQTJDO2dCQUMzQyxXQUFXLEVBQUUsS0FBSyxDQUFDLFVBQVU7Z0JBQzdCLGFBQWEsRUFBRSxLQUFLLENBQUMsWUFBWTthQUNsQztZQUNELElBQUksRUFBRSxtQkFBbUI7WUFDekIsT0FBTyxFQUFFLHNCQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztTQUM5QixDQUFDLENBQUM7UUFFSCxtQ0FBbUM7UUFDbkMsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLHdCQUF3QixFQUFFO1lBQzFFLFFBQVEsRUFBRSxTQUFTO1lBQ25CLFNBQVMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyx5QkFBeUIsQ0FBQztZQUM5RCxjQUFjLEVBQUU7Z0JBQ2QsQ0FBQyxzQkFBc0IsQ0FBQyxFQUFFLElBQUksR0FBRyxDQUFDLGNBQWMsQ0FBQztvQkFDL0MsVUFBVSxFQUFFO3dCQUNWLElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQzs0QkFDdEIsTUFBTSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSzs0QkFDeEIsT0FBTyxFQUFFO2dDQUNQLHVCQUF1Qjs2QkFDeEI7NEJBQ0QsU0FBUyxFQUFFO2dDQUNULGNBQWMsQ0FBQyxXQUFXO2dDQUMxQixHQUFHLGNBQWMsQ0FBQyxXQUFXLElBQUk7NkJBQ2xDO3lCQUNGLENBQUM7cUJBQ0g7aUJBQ0YsQ0FBQzthQUNIO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsYUFBYTtRQUNiLElBQUksU0FBUyxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsVUFBVSxFQUFFO1lBQzFDLElBQUksRUFBRSxTQUFTO1lBQ2YsV0FBVyxFQUFFLDRCQUE0QjtZQUN6QyxLQUFLLEVBQUUsU0FBUztZQUNoQiwyQ0FBMkM7WUFDM0Msa0JBQWtCLEVBQUU7Z0JBQ2xCLElBQUksRUFBRSxLQUFLO2FBQ1o7WUFDRCwwQkFBMEIsRUFBRSxLQUFLLENBQUMsZ0JBQWdCLElBQUksS0FBSztZQUMzRCxrQkFBa0IsRUFBRSxtQkFBbUI7WUFDdkMsTUFBTSxFQUFFO2dCQUNOLEdBQUcsRUFBRSxjQUFjLENBQUMsV0FBVztnQkFDL0IsT0FBTyxFQUFFLHNCQUFzQixDQUFDLE9BQU87Z0JBQ3ZDLEtBQUssRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQztnQkFDcEQsV0FBVyxFQUFFO29CQUNYLHdCQUF3QixFQUFFLEVBQUU7b0JBQzVCLG9CQUFvQixFQUFFLENBQUM7aUJBQ3hCO2FBQ0Y7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDOztBQXZGSCw4REF5RkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEdXJhdGlvbiwgU3RhY2sgfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgKiBhcyBpYW0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgKiBhcyBzY2hlZHVsZXIgZnJvbSAnYXdzLWNkay1saWIvYXdzLXNjaGVkdWxlcic7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IENvc3RSZXBvcnRlckZ1bmN0aW9uIH0gZnJvbSAnLi9mdW5jcy9jb3N0LXJlcG9ydGVyLWZ1bmN0aW9uJztcblxuZXhwb3J0IGludGVyZmFjZSBEYWlseUNvc3RVc2FnZVJlcG9ydFN0YWNrUHJvcHMge1xuICByZWFkb25seSBzbGFja1Rva2VuOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHNsYWNrQ2hhbm5lbDogc3RyaW5nO1xuICByZWFkb25seSBzY2hlZHVsZVRpbWV6b25lPzogc3RyaW5nO1xuICByZWFkb25seSBjb3N0R3JvdXBUeXBlOiBDb3N0R3JvdXBUeXBlO1xufVxuXG5leHBvcnQgZW51bSBDb3N0R3JvdXBUeXBlIHtcbiAgQUNDT1VOVFMgPSAnQWNjb3VudHMnLFxuICBTRVJWSUNFUyA9ICdTZXJ2aWNlcycsXG59XG5cbmV4cG9ydCBjbGFzcyBEYWlseUNvc3RVc2FnZVJlcG9ydFN0YWNrIGV4dGVuZHMgU3RhY2sge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogRGFpbHlDb3N0VXNhZ2VSZXBvcnRTdGFja1Byb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIC8vIPCfkYdHZXQgY3VycmVudCBhY2NvdW50ICYgcmVnaW9uXG4gICAgLy8gY29uc3QgYWNjb3VudCA9IFN0YWNrLm9mKHRoaXMpLmFjY291bnQ7XG4gICAgLy8gY29uc3QgcmVnaW9uID0gY2RrLlN0YWNrLm9mKHRoaXMpLnJlZ2lvbjtcblxuICAgIC8vIPCfkYdMYW1iZGEgRXhlYyBSb2xlXG4gICAgY29uc3QgbGFtYmRhRXhlY3V0aW9uUm9sZSA9IG5ldyBpYW0uUm9sZSh0aGlzLCAnTGFtYmRhRXhlY3V0aW9uUm9sZScsIHtcbiAgICAgIHJvbGVOYW1lOiB1bmRlZmluZWQsXG4gICAgICBkZXNjcmlwdGlvbjogJycsXG4gICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnbGFtYmRhLmFtYXpvbmF3cy5jb20nKSxcbiAgICAgIG1hbmFnZWRQb2xpY2llczogW1xuICAgICAgICBpYW0uTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUoJ3NlcnZpY2Utcm9sZS9BV1NMYW1iZGFCYXNpY0V4ZWN1dGlvblJvbGUnKSxcbiAgICAgIF0sXG4gICAgICBpbmxpbmVQb2xpY2llczoge1xuICAgICAgICBbJ2dldC1jb3N0LXVzYWdlJ106IG5ldyBpYW0uUG9saWN5RG9jdW1lbnQoe1xuICAgICAgICAgIHN0YXRlbWVudHM6IFtcbiAgICAgICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgJ2NlOkdldENvc3RBbmRVc2FnZScsXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIHJlc291cmNlczogWycqJ10sXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICBdLFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICAvLyDwn5GHTGFtYmRhIEZ1bmN0aW9uXG4gICAgY29uc3QgbGFtYmRhRnVuY3Rpb24gPSBuZXcgQ29zdFJlcG9ydGVyRnVuY3Rpb24odGhpcywgJ0Nvc3RSZXBvcnRlckZ1bmN0aW9uJywge1xuICAgICAgZnVuY3Rpb25OYW1lOiB1bmRlZmluZWQsXG4gICAgICBkZXNjcmlwdGlvbjogJ0EgZnVuY3Rpb24gdG8gYXJjaGl2ZSBsb2dzIHMzIGJ1Y2tldCBmcm9tIENsb3VkV2F0Y2ggTG9ncy4nLFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgLy9CVUNLRVRfTkFNRTogbG9nQXJjaGl2ZUJ1Y2tldC5idWNrZXROYW1lLFxuICAgICAgICBTTEFDS19UT0tFTjogcHJvcHMuc2xhY2tUb2tlbixcbiAgICAgICAgU0xBQ0tfQ0hBTk5FTDogcHJvcHMuc2xhY2tDaGFubmVsLFxuICAgICAgfSxcbiAgICAgIHJvbGU6IGxhbWJkYUV4ZWN1dGlvblJvbGUsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDQ1KSxcbiAgICB9KTtcblxuICAgIC8vIPCfkYdFdmVudEJyaWRnZSBTY2hlZHVsZXIgSUFNIFJvbGVcbiAgICBjb25zdCBzY2hlZHVsZXJFeGVjdXRpb25Sb2xlID0gbmV3IGlhbS5Sb2xlKHRoaXMsICdTY2hlZHVsZXJFeGVjdXRpb25Sb2xlJywge1xuICAgICAgcm9sZU5hbWU6IHVuZGVmaW5lZCxcbiAgICAgIGFzc3VtZWRCeTogbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCdzY2hlZHVsZXIuYW1hem9uYXdzLmNvbScpLFxuICAgICAgaW5saW5lUG9saWNpZXM6IHtcbiAgICAgICAgWydsYW1iZGEtaW52b2tlLXBvbGljeSddOiBuZXcgaWFtLlBvbGljeURvY3VtZW50KHtcbiAgICAgICAgICBzdGF0ZW1lbnRzOiBbXG4gICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICAgICAgICdsYW1iZGE6SW52b2tlRnVuY3Rpb24nLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAgICAgICAgICBsYW1iZGFGdW5jdGlvbi5mdW5jdGlvbkFybixcbiAgICAgICAgICAgICAgICBgJHtsYW1iZGFGdW5jdGlvbi5mdW5jdGlvbkFybn06KmAsXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICBdLFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICAvLyDwn5GHU2NoZWR1bGVcbiAgICBuZXcgc2NoZWR1bGVyLkNmblNjaGVkdWxlKHRoaXMsICdTY2hlZHVsZScsIHtcbiAgICAgIG5hbWU6IHVuZGVmaW5lZCxcbiAgICAgIGRlc2NyaXB0aW9uOiAnYXdzIGFjY291bnQgY29uc3QgcmVwb3J0cy4nLFxuICAgICAgc3RhdGU6ICdFTkFCTEVEJyxcbiAgICAgIC8vZ3JvdXBOYW1lOiBzY2hlZHVsZUdyb3VwLm5hbWUsIC8vIGRlZmF1bHRcbiAgICAgIGZsZXhpYmxlVGltZVdpbmRvdzoge1xuICAgICAgICBtb2RlOiAnT0ZGJyxcbiAgICAgIH0sXG4gICAgICBzY2hlZHVsZUV4cHJlc3Npb25UaW1lem9uZTogcHJvcHMuc2NoZWR1bGVUaW1lem9uZSA/PyAnVVRDJyxcbiAgICAgIHNjaGVkdWxlRXhwcmVzc2lvbjogJ2Nyb24oMSA5ICogKiA/ICopJyxcbiAgICAgIHRhcmdldDoge1xuICAgICAgICBhcm46IGxhbWJkYUZ1bmN0aW9uLmZ1bmN0aW9uQXJuLFxuICAgICAgICByb2xlQXJuOiBzY2hlZHVsZXJFeGVjdXRpb25Sb2xlLnJvbGVBcm4sXG4gICAgICAgIGlucHV0OiBKU09OLnN0cmluZ2lmeSh7IFR5cGU6IHByb3BzLmNvc3RHcm91cFR5cGUgfSksXG4gICAgICAgIHJldHJ5UG9saWN5OiB7XG4gICAgICAgICAgbWF4aW11bUV2ZW50QWdlSW5TZWNvbmRzOiA2MCxcbiAgICAgICAgICBtYXhpbXVtUmV0cnlBdHRlbXB0czogMCxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxufSJdfQ==
|