Repository: aliyun/fun
Pull request #200 (2019-04-24 06:23:27)

Sunfeiyu/support cdn trigger
#189  cdn 触发器

vangie: CDN 触发器的 Spec 已经有了么？
tanhe123: > CDN 触发器的 Spec 已经有了么？

https://github.com/aliyun/fun/pull/199/files

Patch:
diff --git a/README.md b/README.md
index ff579f7..bd3e363 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,7 @@ Fun 作为一个命令行工具，内置了多个子命令，比如 config、loc
     - [开发函数计算的正确姿势 —— Api 本地运行调试](https://yq.aliyun.com/articles/683685): 介绍了如何在通过 API 在本地运行、单步调试函数。
   - **部署**：关于如何快速部署云服务的文章。
     - [开发函数计算的正确姿势 —— 部署 API 网关](https://yq.aliyun.com/articles/689185)：介绍了如何部署 API 网关 + 函数计算应用。
+    - [开发函数计算的正确姿势 —— OSS 触发器](https://yq.aliyun.com/articles/699379)：介绍了如何部署 OSS 触发器 + 函数计算应用。
   - **实战**：关于如何利用 init、local、install、deploy 等命令，快速开发一款 Serverless 应用的文章。
     - [开发函数计算的正确姿势 —— 爬虫](https://yq.aliyun.com/articles/672624): 通过一个实战场景，介绍了如何利用 Fun 工具从头开始开发一个 Serverless 应用。
     - [开发函数计算的正确姿势 —— 排查超时问题](https://yq.aliyun.com/articles/672627): 从一个 bug 出发，介绍了各种排查问题的技巧。
diff --git a/examples/cdn-trigger/index.py b/examples/cdn-trigger/index.py
new file mode 100644
index 0000000..c5b2142
--- /dev/null
+++ b/examples/cdn-trigger/index.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+import logging
+
+def handler(event, context):
+  logger = logging.getLogger()
+  logger.info('cdn trigger event = %s', event)
+  return 'hello world'
\ No newline at end of file
diff --git a/examples/cdn-trigger/template.yml b/examples/cdn-trigger/template.yml
new file mode 100644
index 0000000..38a18ed
--- /dev/null
+++ b/examples/cdn-trigger/template.yml
@@ -0,0 +1,24 @@
+ROSTemplateFormatVersion: '2015-09-01'
+Transform: 'Aliyun::Serverless-2018-04-03'
+Resources:
+  cdn-test-service:
+    Type: 'Aliyun::Serverless::Service'
+    Properties: 
+      Description: 'cdn trigger test'
+
+    cdn-test-function:
+      Type: 'Aliyun::Serverless::Function'
+      Properties:
+        Handler: index.handler
+        Runtime: python2.7
+        CodeUri: './'
+      Events:
+        cdn-trigger-name: # trigger name
+          Type: CDN # trigger type
+          Properties:
+            eventName: CachedObjectsRefreshed
+            eventVersion: '1.0.0'
+            notes: cdn events trigger test
+            filter: 
+              domain: ['cdn-trigger.sunfeiyu.top']
+               
\ No newline at end of file
diff --git a/lib/deploy/deploy-support.js b/lib/deploy/deploy-support.js
index fa71ece..a0f8770 100644
--- a/lib/deploy/deploy-support.js
+++ b/lib/deploy/deploy-support.js
@@ -466,7 +466,8 @@ const triggerTypeMapping = {
   'OSS': 'oss',
   'RDS': 'rds',
   'MNSTopic': 'mns_topic',
-  'TableStore': 'tablestore'
+  'TableStore': 'tablestore',
+  'CDN' : 'cdn_events'
 };
 
 async function getSourceArn(triggerType, triggerProperties) {
@@ -485,8 +486,9 @@ async function getSourceArn(triggerType, triggerProperties) {
     return `acs:ots:${profile.defaultRegion}:${profile.accountId}:instance/${triggerProperties.InstanceName}/table/${triggerProperties.TableName}`;
   } else if (triggerType === 'OSS') {
     return `acs:oss:${profile.defaultRegion}:${profile.accountId}:${triggerProperties.bucketName}`;
+  } else if (triggerType === 'CDN') {
+    return `acs:cdn:*:${profile.accountId}`;
   }
-
   return;
 }
 
@@ -553,7 +555,13 @@ function getTriggerConfig(triggerType, triggerProperties) {
       events : triggerProperties.events,
       filter : triggerProperties.filter
     };
-   
+  } else if (triggerType === 'CDN') {
+    return {
+      eventName : triggerProperties.eventName,
+      eventVersion : triggerProperties.eventVersion,
+      notes : triggerProperties.notes,
+      filter : triggerProperties.filter
+    };
   }
   console.error(`trigger type is ${triggerType} not supported.`);
 }
@@ -733,6 +741,40 @@ async function makeInvocationRole(serviceName, functionName, triggerType) {
     await ram.attachPolicyToRole(policyName, invocationRoleName, 'Custom');
     return invocationRole.Role;
 
+  } else if (triggerType === 'CDN') {
+
+    const invocationRoleName = ram.normalizeRoleOrPoliceName(`FunCreateRole-${serviceName}-${functionName}`);
+
+    const invocationRole = await ram.makeRole(invocationRoleName, true, 'Used for fc invocation', {
+      'Statement': [
+        {
+          'Action': 'sts:AssumeRole',
+          'Effect': 'Allow',
+          'Principal': {
+            'Service': [
+              'cdn.aliyuncs.com'
+            ]
+          }
+        }
+      ],
+      'Version': '1'
+    });
+
+    const policyName = ram.normalizeRoleOrPoliceName(`FunCreateCDNPolicy-${serviceName}-${functionName}`);
+
+    await ram.makePolicy(policyName, {
+      'Version': '1',
+      'Statement': [{
+        'Action': [
+          'fc:InvokeFunction'
+        ],
+        'Resource': `acs:fc:*:*:services/${serviceName}/functions/*`,
+        'Effect': 'Allow'
+      }]
+    });
+
+    await ram.attachPolicyToRole(policyName, invocationRoleName, 'Custom');
+    return invocationRole.Role;
   }
   return;
 }


Test patch:
diff --git a/test/deploy/deploy-by-tpl.test.js b/test/deploy/deploy-by-tpl.test.js
index e000858..0bb5c58 100644
--- a/test/deploy/deploy-by-tpl.test.js
+++ b/test/deploy/deploy-by-tpl.test.js
@@ -497,6 +497,53 @@ describe('deploy', () => {
     });
   });
 
+  it('deploy cdn-trigger', async () => {
+    await deploy('cdn-trigger');
+
+    assert.calledWith(deploySupport.makeService, {
+      description: 'cdn trigger test',
+      internetAccess: null,
+      logConfig: {},
+      role: '',
+      serviceName: 'cdn-test-service',
+      vpcConfig: {},
+      nasConfig: {}
+    });
+    assert.calledWith(deploySupport.makeFunction,
+      path.join(process.cwd(), 'examples', 'cdn-trigger'), {
+        codeUri: './',
+        handler: 'index.handler',
+        initializer: undefined,
+        description: undefined,
+        functionName: 'cdn-test-function',
+        memorySize: undefined,
+        runtime: 'python2.7',
+        serviceName: 'cdn-test-service',
+        timeout: undefined,
+        initializationTimeout: undefined,
+        environmentVariables: undefined
+      });
+    assert.calledWith(deploySupport.makeTrigger, {
+      serviceName: 'cdn-test-service',
+      functionName: 'cdn-test-function',
+      triggerName: 'cdn-trigger-name',
+      triggerType: 'CDN',
+      triggerProperties: {
+        'eventName': 'CachedObjectsRefreshed',
+        'eventVersion': '1.0.0',
+        'notes': 'cdn events trigger test',
+        'filter': {
+          'domain': [
+            'cdn-trigger.sunfeiyu.top'
+          ]
+        }},
+    });
+    assert.calledWith(deploySupport.getTriggerNameList, {
+      serviceName: 'cdn-test-service',
+      functionName: 'cdn-test-function'
+    });
+  });
+
   it('deploy mnsTopic-trigger', async () => {
     await deploy('mnsTopic-trigger');
 
diff --git a/test/deploy/deploy-support.test.js b/test/deploy/deploy-support.test.js
index 8590406..b85c683 100644
--- a/test/deploy/deploy-support.test.js
+++ b/test/deploy/deploy-support.test.js
@@ -587,6 +587,46 @@ describe('make invocation role', () => {
 
     expect(role).to.be('generated-role-name');
   });
+
+  it('makeInvocationRole of cdn', async () => {
+    const role = await deploySupport.makeInvocationRole('cdn-service_name', 'cdn-function_name', 'CDN');
+
+    assert.calledOnce(ram.makeRole);
+    assert.calledWith(ram.makeRole,
+      'FunCreateRole-cdn-service-name-cdn-function-name',
+      true,
+      'Used for fc invocation',
+      {
+        Statement: [
+          {
+            'Action': 'sts:AssumeRole',
+            'Effect': 'Allow',
+            'Principal': {
+              'Service': [
+                'cdn.aliyuncs.com'
+              ]
+            }
+          }
+        ],
+        Version: '1'
+      });
+
+    assert.calledWith(ram.makePolicy, 'FunCreateCDNPolicy-cdn-service-name-cdn-function-name',
+      {
+        Statement:[{
+          'Action': [
+            'fc:InvokeFunction'
+          ],
+          'Resource': `acs:fc:*:*:services/cdn-service_name/functions/*`,
+          'Effect': 'Allow'
+        }],
+        Version: '1'
+      });
+    assert.calledOnce(ram.attachPolicyToRole);
+    assert.calledWith(ram.attachPolicyToRole, 'FunCreateCDNPolicy-cdn-service-name-cdn-function-name', 'FunCreateRole-cdn-service-name-cdn-function-name', 'Custom');
+
+    expect(role).to.be('generated-role-name');
+  });
 });
 
 describe('test getFunCodeAsBase64', () => {