-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
slack-channel-configuration.ts
329 lines (277 loc) · 10.4 KB
/
slack-channel-configuration.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
import { Construct } from 'constructs';
import { CfnSlackChannelConfiguration } from './chatbot.generated';
import * as cloudwatch from '../../aws-cloudwatch';
import * as notifications from '../../aws-codestarnotifications';
import * as iam from '../../aws-iam';
import * as logs from '../../aws-logs';
import * as sns from '../../aws-sns';
import * as cdk from '../../core';
/**
* Properties for a new Slack channel configuration
*/
export interface SlackChannelConfigurationProps {
/**
* The name of Slack channel configuration
*/
readonly slackChannelConfigurationName: string;
/**
* The permission role of Slack channel configuration
*
* @default - A role will be created.
*/
readonly role?: iam.IRole;
/**
* The ID of the Slack workspace authorized with AWS Chatbot.
*
* To get the workspace ID, you must perform the initial authorization flow with Slack in the AWS Chatbot console.
* Then you can copy and paste the workspace ID from the console.
* For more details, see steps 1-4 in Setting Up AWS Chatbot with Slack in the AWS Chatbot User Guide.
* @see https://docs.aws.amazon.com/chatbot/latest/adminguide/setting-up.html#Setup_intro
*/
readonly slackWorkspaceId: string;
/**
* The ID of the Slack channel.
*
* To get the ID, open Slack, right click on the channel name in the left pane, then choose Copy Link.
* The channel ID is the 9-character string at the end of the URL. For example, ABCBBLZZZ.
*/
readonly slackChannelId: string;
/**
* The SNS topics that deliver notifications to AWS Chatbot.
*
* @default None
*/
readonly notificationTopics?: sns.ITopic[];
/**
* Specifies the logging level for this configuration.
* This property affects the log entries pushed to Amazon CloudWatch Logs.
*
* @default LoggingLevel.NONE
*/
readonly loggingLevel?: LoggingLevel;
/**
* The number of days log events are kept in CloudWatch Logs. When updating
* this property, unsetting it doesn't remove the log retention policy. To
* remove the retention policy, set the value to `INFINITE`.
*
* @default logs.RetentionDays.INFINITE
*/
readonly logRetention?: logs.RetentionDays;
/**
* The IAM role for the Lambda function associated with the custom resource
* that sets the retention policy.
*
* @default - A new role is created.
*/
readonly logRetentionRole?: iam.IRole;
/**
* When log retention is specified, a custom resource attempts to create the CloudWatch log group.
* These options control the retry policy when interacting with CloudWatch APIs.
*
* @default - Default AWS SDK retry options.
*/
readonly logRetentionRetryOptions?: logs.LogRetentionRetryOptions;
/**
* A list of IAM managed policies that are applied as channel guardrails.
* @default - The AWS managed 'AdministratorAccess' policy is applied as a default if this is not set.
*/
readonly guardrailPolicies?: iam.IManagedPolicy[];
}
/**
* Logging levels include ERROR, INFO, or NONE.
*/
export enum LoggingLevel {
/**
* ERROR
*/
ERROR = 'ERROR',
/**
* INFO
*/
INFO = 'INFO',
/**
* NONE
*/
NONE = 'NONE',
}
/**
* Represents a Slack channel configuration
*/
export interface ISlackChannelConfiguration extends cdk.IResource, iam.IGrantable, notifications.INotificationRuleTarget {
/**
* The ARN of the Slack channel configuration
* In the form of arn:aws:chatbot:{region}:{account}:chat-configuration/slack-channel/{slackChannelName}
* @attribute
*/
readonly slackChannelConfigurationArn: string;
/**
* The name of Slack channel configuration
* @attribute
*/
readonly slackChannelConfigurationName: string;
/**
* The permission role of Slack channel configuration
* @attribute
*
* @default - A role will be created.
*/
readonly role?: iam.IRole;
/**
* Adds a statement to the IAM role.
*/
addToRolePolicy(statement: iam.PolicyStatement): void;
/**
* Return the given named metric for this SlackChannelConfiguration
*/
metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric;
}
/**
* Either a new or imported Slack channel configuration
*/
abstract class SlackChannelConfigurationBase extends cdk.Resource implements ISlackChannelConfiguration {
abstract readonly slackChannelConfigurationArn: string;
abstract readonly slackChannelConfigurationName: string;
abstract readonly grantPrincipal: iam.IPrincipal;
abstract readonly role?: iam.IRole;
/**
* Adds extra permission to iam-role of Slack channel configuration
* @param statement
*/
public addToRolePolicy(statement: iam.PolicyStatement): void {
if (!this.role) {
return;
}
this.role.addToPrincipalPolicy(statement);
}
/**
* Return the given named metric for this SlackChannelConfiguration
*/
public metric(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric {
// AWS Chatbot publishes metrics to us-east-1 regardless of stack region
// https://docs.aws.amazon.com/chatbot/latest/adminguide/monitoring-cloudwatch.html
return new cloudwatch.Metric({
namespace: 'AWS/Chatbot',
region: 'us-east-1',
dimensionsMap: {
ConfigurationName: this.slackChannelConfigurationName,
},
metricName,
...props,
});
}
public bindAsNotificationRuleTarget(_scope: Construct): notifications.NotificationRuleTargetConfig {
return {
targetType: 'AWSChatbotSlack',
targetAddress: this.slackChannelConfigurationArn,
};
}
}
/**
* A new Slack channel configuration
*/
export class SlackChannelConfiguration extends SlackChannelConfigurationBase {
/**
* Import an existing Slack channel configuration provided an ARN
* @param scope The parent creating construct
* @param id The construct's name
* @param slackChannelConfigurationArn configuration ARN (i.e. arn:aws:chatbot::1234567890:chat-configuration/slack-channel/my-slack)
*
* @returns a reference to the existing Slack channel configuration
*/
public static fromSlackChannelConfigurationArn(scope: Construct, id: string, slackChannelConfigurationArn: string): ISlackChannelConfiguration {
const re = /^slack-channel\//;
const resourceName = cdk.Arn.extractResourceName(slackChannelConfigurationArn, 'chat-configuration');
if (!cdk.Token.isUnresolved(slackChannelConfigurationArn) && !re.test(resourceName)) {
throw new Error('The ARN of a Slack integration must be in the form: arn:<partition>:chatbot:<region>:<account>:chat-configuration/slack-channel/<slackChannelName>');
}
class Import extends SlackChannelConfigurationBase {
/**
* @attribute
*/
readonly slackChannelConfigurationArn = slackChannelConfigurationArn;
readonly role?: iam.IRole = undefined;
readonly grantPrincipal: iam.IPrincipal;
/**
* Returns a name of Slack channel configuration
*
* NOTE:
* For example: arn:aws:chatbot::1234567890:chat-configuration/slack-channel/my-slack
* The ArnComponents API will return `slack-channel/my-slack`
* It need to handle that to gets a correct name.`my-slack`
*/
readonly slackChannelConfigurationName: string;
constructor(s: Construct, i: string) {
super(s, i);
this.grantPrincipal = new iam.UnknownPrincipal({ resource: this });
// handle slackChannelConfigurationName as specified above
if (cdk.Token.isUnresolved(slackChannelConfigurationArn)) {
this.slackChannelConfigurationName = cdk.Fn.select(1, cdk.Fn.split('slack-channel/', resourceName));
} else {
this.slackChannelConfigurationName = resourceName.substring('slack-channel/'.length);
}
}
}
return new Import(scope, id);
}
/**
* Return the given named metric for All SlackChannelConfigurations
*/
public static metricAll(metricName: string, props?: cloudwatch.MetricOptions): cloudwatch.Metric {
// AWS Chatbot publishes metrics to us-east-1 regardless of stack region
// https://docs.aws.amazon.com/chatbot/latest/adminguide/monitoring-cloudwatch.html
return new cloudwatch.Metric({
namespace: 'AWS/Chatbot',
region: 'us-east-1',
metricName,
...props,
});
}
readonly slackChannelConfigurationArn: string;
readonly slackChannelConfigurationName: string;
readonly role?: iam.IRole;
readonly grantPrincipal: iam.IPrincipal;
/**
* The SNS topic that deliver notifications to AWS Chatbot.
* @attribute
*/
private readonly notificationTopics: sns.ITopic[];
constructor(scope: Construct, id: string, props: SlackChannelConfigurationProps) {
super(scope, id, {
physicalName: props.slackChannelConfigurationName,
});
this.role = props.role || new iam.Role(this, 'ConfigurationRole', {
assumedBy: new iam.ServicePrincipal('chatbot.amazonaws.com'),
});
this.grantPrincipal = this.role;
this.notificationTopics = props.notificationTopics ?? [];
const configuration = new CfnSlackChannelConfiguration(this, 'Resource', {
configurationName: props.slackChannelConfigurationName,
iamRoleArn: this.role.roleArn,
slackWorkspaceId: props.slackWorkspaceId,
slackChannelId: props.slackChannelId,
snsTopicArns: cdk.Lazy.list({ produce: () => this.notificationTopics.map(topic => topic.topicArn) }, { omitEmpty: true } ),
loggingLevel: props.loggingLevel?.toString(),
guardrailPolicies: cdk.Lazy.list({ produce: () => props.guardrailPolicies?.map(policy => policy.managedPolicyArn) }, { omitEmpty: true } ),
});
// Log retention
// AWS Chatbot publishes logs to us-east-1 regardless of stack region https://docs.aws.amazon.com/chatbot/latest/adminguide/cloudwatch-logs.html
if (props.logRetention) {
new logs.LogRetention(this, 'LogRetention', {
logGroupName: `/aws/chatbot/${props.slackChannelConfigurationName}`,
retention: props.logRetention,
role: props.logRetentionRole,
logGroupRegion: 'us-east-1',
logRetentionRetryOptions: props.logRetentionRetryOptions,
});
}
this.slackChannelConfigurationArn = configuration.ref;
this.slackChannelConfigurationName = props.slackChannelConfigurationName;
}
/**
* Adds a SNS topic that deliver notifications to AWS Chatbot.
* @param notificationTopic
*/
public addNotificationTopic(notificationTopic: sns.ITopic): void {
this.notificationTopics.push(notificationTopic);
}
}