UNPKG

12.7 kBJavaScriptView Raw
1'use strict';
2
3const getProfile = require('./profile').getProfile;
4const { getFcClient } = require('./client');
5const debug = require('debug')('fun:trigger');
6const _ = require('lodash');
7const ram = require('./ram');
8const util = require('util');
9const { red } = require('colors');
10
11const triggerTypeMapping = {
12 'Datahub': 'datahub',
13 'Timer': 'timer',
14 'HTTP': 'http',
15 'Log': 'log',
16 'OSS': 'oss',
17 'RDS': 'rds',
18 'MNSTopic': 'mns_topic',
19 'TableStore': 'tablestore',
20 'CDN': 'cdn_events'
21};
22
23async function getSourceArn(triggerType, triggerProperties) {
24 const profile = await getProfile();
25
26 if (triggerType === 'Log') {
27 return `acs:log:${profile.defaultRegion}:${profile.accountId}:project/${triggerProperties.LogConfig.Project}`;
28 } else if (triggerType === 'RDS') {
29 return `acs:rds:${profile.defaultRegion}:${profile.accountId}:dbinstance/${triggerProperties.InstanceId}`;
30 } else if (triggerType === 'MNSTopic') {
31 if (triggerProperties.Region !== undefined) {
32 return `acs:mns:${triggerProperties.Region}:${profile.accountId}:/topics/${triggerProperties.TopicName}`;
33 }
34 return `acs:mns:${profile.defaultRegion}:${profile.accountId}:/topics/${triggerProperties.TopicName}`;
35 } else if (triggerType === 'TableStore') {
36 return `acs:ots:${profile.defaultRegion}:${profile.accountId}:instance/${triggerProperties.InstanceName}/table/${triggerProperties.TableName}`;
37 } else if (triggerType === 'OSS') {
38 return `acs:oss:${profile.defaultRegion}:${profile.accountId}:${triggerProperties.BucketName || triggerProperties.bucketName}`;
39 } else if (triggerType === 'CDN') {
40 return `acs:cdn:*:${profile.accountId}`;
41 }
42 return;
43}
44
45async function getTriggerNameList({
46 serviceName,
47 functionName
48}) {
49 const fc = await getFcClient();
50 var listTriggerResponse = await fc.listTriggers(serviceName, functionName);
51
52 var triggerNameArray = [];
53
54 if (listTriggerResponse && listTriggerResponse.data.triggers) {
55 triggerNameArray = listTriggerResponse.data.triggers.map(p => p.triggerName);
56 }
57 return triggerNameArray;
58}
59
60function getTriggerConfig(triggerType, triggerProperties) {
61 if (triggerType === 'Timer') {
62 return {
63 payload: triggerProperties.Payload,
64 cronExpression: triggerProperties.CronExpression,
65 enable: triggerProperties.Enable
66 };
67 } else if (triggerType === 'HTTP') {
68 return {
69 authType: (triggerProperties.AuthType).toLowerCase(),
70 methods: triggerProperties.Methods
71 };
72 } else if (triggerType === 'Log') {
73 const logConfig = triggerProperties.LogConfig;
74 const jobConfig = triggerProperties.JobConfig;
75 const sourceConfig = triggerProperties.SourceConfig;
76
77 return {
78 sourceConfig: {
79 logstore: sourceConfig.Logstore
80 },
81 jobConfig: {
82 maxRetryTime: jobConfig.MaxRetryTime,
83 triggerInterval: jobConfig.TriggerInterval
84 },
85 logConfig: {
86 project: logConfig.Project,
87 logstore: logConfig.Logstore,
88 functionParameter: logConfig.FunctionParameter || {}
89 },
90 Enable: !(triggerProperties.Enable === false)
91 };
92 } else if (triggerType === 'RDS') {
93 return {
94 subscriptionObjects: triggerProperties.SubscriptionObjects,
95 retry: triggerProperties.Retry,
96 concurrency: triggerProperties.Concurrency,
97 eventFormat: triggerProperties.EventFormat
98 };
99 } else if (triggerType === 'MNSTopic') {
100 var notifyContentFormat = 'STREAM';
101 if (triggerProperties.NotifyContentFormat !== undefined) {
102 notifyContentFormat = triggerProperties.NotifyContentFormat;
103 }
104 var notifyStrategy = 'BACKOFF_RETRY';
105 if (triggerProperties.NotifyStrategy !== undefined) {
106 notifyStrategy = triggerProperties.NotifyStrategy;
107 }
108 var triggerCfg = {
109 NotifyContentFormat: notifyContentFormat,
110 NotifyStrategy: notifyStrategy
111 };
112 if (triggerProperties.FilterTag !== undefined) {
113 triggerCfg.FilterTag = triggerProperties.FilterTag;
114 }
115 return triggerCfg;
116 } else if (triggerType === 'TableStore') {
117 return {};
118 } else if (triggerType === 'OSS') {
119 return {
120 events: triggerProperties.Events || triggerProperties.events,
121 filter: triggerProperties.Filter || triggerProperties.filter
122 };
123 } else if (triggerType === 'CDN') {
124 return {
125 eventName: triggerProperties.EventName,
126 eventVersion: triggerProperties.EventVersion,
127 notes: triggerProperties.Notes,
128 filter: _.mapKeys(triggerProperties.Filter, (value, key) => {
129 return _.lowerFirst(key);
130 })
131 };
132 }
133 console.error(`trigger type is ${triggerType} not supported.`);
134}
135
136async function makeInvocationRole(serviceName, functionName, triggerType) {
137 if (triggerType === 'Log') {
138
139 const invocationRoleName = ram.normalizeRoleOrPoliceName(`AliyunFcGeneratedInvocationRole-${serviceName}-${functionName}`);
140
141 const invocationRole = await ram.makeRole(invocationRoleName, true, 'Used for fc invocation', {
142 'Statement': [{
143 'Action': 'sts:AssumeRole',
144 'Effect': 'Allow',
145 'Principal': {
146 'Service': [
147 'log.aliyuncs.com'
148 ]
149 }
150 }],
151 'Version': '1'
152 });
153
154 const policyName = ram.normalizeRoleOrPoliceName(`AliyunFcGeneratedInvocationPolicy-${serviceName}-${functionName}`);
155
156 await ram.makePolicy(policyName, {
157 'Version': '1',
158 'Statement': [{
159 'Action': [
160 'fc:InvokeFunction'
161 ],
162 'Resource': `acs:fc:*:*:services/${serviceName}/functions/*`,
163 'Effect': 'Allow'
164 },
165 {
166 'Action': [
167 'log:Get*',
168 'log:List*',
169 'log:PostLogStoreLogs',
170 'log:CreateConsumerGroup',
171 'log:UpdateConsumerGroup',
172 'log:DeleteConsumerGroup',
173 'log:ListConsumerGroup',
174 'log:ConsumerGroupUpdateCheckPoint',
175 'log:ConsumerGroupHeartBeat',
176 'log:GetConsumerGroupCheckPoint'
177 ],
178 'Resource': '*',
179 'Effect': 'Allow'
180 }
181 ]
182 });
183
184 await ram.attachPolicyToRole(policyName, invocationRoleName, 'Custom');
185 return invocationRole.Role;
186
187 } else if (triggerType === 'RDS' || triggerType === 'MNSTopic') {
188
189 const invocationRoleName = ram.normalizeRoleOrPoliceName(`FunCreateRole-${serviceName}-${functionName}`);
190 var tMap = {
191 'RDS': 'rds',
192 'MNSTopic': 'mns'
193 };
194 var principalService = util.format('%s.aliyuncs.com', tMap[triggerType]);
195
196 const invocationRole = await ram.makeRole(invocationRoleName, true, 'Used for fc invocation', {
197 'Statement': [{
198 'Action': 'sts:AssumeRole',
199 'Effect': 'Allow',
200 'Principal': {
201 'Service': [
202 principalService
203 ]
204 }
205 }],
206 'Version': '1'
207 });
208
209 const policyName = ram.normalizeRoleOrPoliceName(`FunCreatePolicy-${serviceName}-${functionName}`);
210
211 await ram.makePolicy(policyName, {
212 'Version': '1',
213 'Statement': [{
214 'Action': [
215 'fc:InvokeFunction'
216 ],
217 'Resource': `acs:fc:*:*:services/${serviceName}/functions/*`,
218 'Effect': 'Allow'
219 }]
220 });
221
222 await ram.attachPolicyToRole(policyName, invocationRoleName, 'Custom');
223
224 return invocationRole.Role;
225
226 } else if (triggerType === 'TableStore') {
227 const invocationRoleName = ram.normalizeRoleOrPoliceName(`FunCreateRole-${serviceName}-${functionName}`);
228
229 const invocationRole = await ram.makeRole(invocationRoleName, true, 'Used for fc invocation', {
230 'Statement': [{
231 'Action': 'sts:AssumeRole',
232 'Effect': 'Allow',
233 'Principal': {
234 'RAM': [
235 'acs:ram::1604337383174619:root'
236 ]
237 }
238 }],
239 'Version': '1'
240 });
241
242 const invkPolicyName = ram.normalizeRoleOrPoliceName(`FunCreateInvkPolicy-${serviceName}-${functionName}`);
243
244 await ram.makePolicy(invkPolicyName, {
245 'Version': '1',
246 'Statement': [{
247 'Action': [
248 'fc:InvokeFunction'
249 ],
250 'Resource': '*',
251 'Effect': 'Allow'
252 }]
253 });
254
255 await ram.attachPolicyToRole(invkPolicyName, invocationRoleName, 'Custom');
256
257 const otsReadPolicyName = ram.normalizeRoleOrPoliceName(`FunCreateOtsReadPolicy-${serviceName}-${functionName}`);
258
259 await ram.makePolicy(otsReadPolicyName, {
260 'Version': '1',
261 'Statement': [{
262 'Action': [
263 'ots:BatchGet*',
264 'ots:Describe*',
265 'ots:Get*',
266 'ots:List*'
267 ],
268 'Resource': '*',
269 'Effect': 'Allow'
270 }]
271 });
272
273 await ram.attachPolicyToRole(otsReadPolicyName, invocationRoleName, 'Custom');
274
275 return invocationRole.Role;
276 } else if (triggerType === 'OSS') {
277
278 const invocationRoleName = ram.normalizeRoleOrPoliceName(`FunCreateRole-${serviceName}-${functionName}`);
279
280 const invocationRole = await ram.makeRole(invocationRoleName, true, 'Used for fc invocation', {
281 'Statement': [
282 {
283 'Action': 'sts:AssumeRole',
284 'Effect': 'Allow',
285 'Principal': {
286 'Service': [
287 'oss.aliyuncs.com'
288 ]
289 }
290 }
291 ],
292 'Version': '1'
293 });
294
295 const policyName = ram.normalizeRoleOrPoliceName(`FunCreateOSSPolicy-${serviceName}-${functionName}`);
296
297 await ram.makePolicy(policyName, {
298 'Version': '1',
299 'Statement': [{
300 'Action': [
301 'fc:InvokeFunction'
302 ],
303 'Resource': `acs:fc:*:*:services/${serviceName}/functions/*`,
304 'Effect': 'Allow'
305 }]
306 });
307
308 await ram.attachPolicyToRole(policyName, invocationRoleName, 'Custom');
309 return invocationRole.Role;
310
311 } else if (triggerType === 'CDN') {
312
313 const invocationRoleName = ram.normalizeRoleOrPoliceName(`FunCreateRole-${serviceName}-${functionName}`);
314
315 const invocationRole = await ram.makeRole(invocationRoleName, true, 'Used for fc invocation', {
316 'Statement': [
317 {
318 'Action': 'sts:AssumeRole',
319 'Effect': 'Allow',
320 'Principal': {
321 'Service': [
322 'cdn.aliyuncs.com'
323 ]
324 }
325 }
326 ],
327 'Version': '1'
328 });
329
330 const policyName = ram.normalizeRoleOrPoliceName(`FunCreateCDNPolicy-${serviceName}-${functionName}`);
331
332 await ram.makePolicy(policyName, {
333 'Version': '1',
334 'Statement': [{
335 'Action': [
336 'fc:InvokeFunction'
337 ],
338 'Resource': `acs:fc:*:*:services/${serviceName}/functions/*`,
339 'Effect': 'Allow'
340 }]
341 });
342
343 await ram.attachPolicyToRole(policyName, invocationRoleName, 'Custom');
344 return invocationRole.Role;
345 }
346 return;
347}
348
349async function makeTrigger({
350 serviceName,
351 functionName,
352 triggerName,
353 triggerType,
354 triggerProperties
355}) {
356 const fc = await getFcClient();
357 var trigger;
358 try {
359 trigger = await fc.getTrigger(serviceName, functionName, triggerName);
360 } catch (ex) {
361 if (ex.code !== 'TriggerNotFound') {
362 throw ex;
363 }
364 }
365
366 const params = {
367 triggerType: triggerTypeMapping[triggerType],
368 triggerConfig: getTriggerConfig(triggerType, triggerProperties)
369 };
370
371 debug('serviceName is %s, functionName is %s, trigger params is %j', serviceName, functionName, params);
372
373 let invocationRoleArn = triggerProperties.InvocationRole;
374
375 if (!invocationRoleArn) {
376 const invocationRole = await makeInvocationRole(serviceName, functionName, triggerType);
377
378 if (invocationRole) {
379 invocationRoleArn = invocationRole.Arn;
380 }
381 }
382
383 if (invocationRoleArn) {
384 Object.assign(params, {
385 'invocationRole': invocationRoleArn
386 });
387 }
388
389 const sourceArn = await getSourceArn(triggerType, triggerProperties);
390 if (sourceArn) {
391 Object.assign(params, {
392 'sourceArn': sourceArn
393 });
394 }
395
396 if (triggerProperties.Qualifier) {
397 Object.assign(params, {
398 'qualifier': triggerProperties.Qualifier
399 });
400 }
401
402 if (!trigger) {
403 params.triggerName = triggerName;
404 trigger = await fc.createTrigger(serviceName, functionName, params);
405 } else {
406 if (triggerType === 'TableStore' || triggerType === 'MNSTopic') {
407 // no triggerConfig, so no updateTrigger, first delete, then create
408 // await fc.deleteTrigger(serviceName, functionName, triggerName);
409 // params.triggerName = triggerName;
410 // trigger = await fc.createTrigger(serviceName, functionName, params);
411 console.log(red(`\t\tWarning: TableStore and MNSTopic Trigger cann't update`));
412 return;
413 }
414 trigger = await fc.updateTrigger(serviceName, functionName, triggerName, params);
415 }
416
417 return trigger;
418}
419
420module.exports = {
421 getTriggerNameList,
422 getTriggerConfig,
423 makeTrigger,
424 makeInvocationRole
425};
\No newline at end of file