├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .travis.yml ├── Changelog.md ├── README.md ├── deploy ├── lib │ ├── deployFunction.js │ ├── deployFunction.test.js │ ├── deployListFunctions.js │ ├── deployListFunctions.test.js │ ├── deployTrigger.js │ └── deployTrigger.test.js ├── tencentDeploy.js ├── tencentDeploy.test.js ├── tencentDeployFunction.js ├── tencentDeployFunction.test.js ├── tencentDeployList.js ├── tencentDeployList.test.js ├── tencentDeployListFunctions.js └── tencentDeployListFunctions.test.js ├── docs ├── en │ ├── create.md │ ├── credentials.md │ ├── deploy-function.md │ ├── deploy-list.md │ ├── deploy.md │ ├── deploying.md │ ├── events.md │ ├── events │ │ ├── CKafka.md │ │ ├── CMQ.md │ │ ├── COS.md │ │ ├── README.md │ │ ├── apigateway.md │ │ └── timer.md │ ├── functions.md │ ├── info.md │ ├── install.md │ ├── installation.md │ ├── intro.md │ ├── invoke.md │ ├── logs.md │ ├── metrics.md │ ├── packaging.md │ ├── plugins.md │ ├── remove.md │ ├── rollback.md │ ├── services.md │ ├── variables.md │ ├── workflow.md │ └── yaml.md └── zh │ ├── README.md │ ├── yaml.md │ ├── 云端调用.md │ ├── 产品概述.md │ ├── 创建服务.md │ ├── 删除服务.md │ ├── 回滚服务.md │ ├── 常见问题.md │ ├── 应用场景.md │ ├── 快速安装.md │ ├── 打包服务.md │ ├── 日志查看.md │ ├── 服务等级协议.md │ ├── 获取详情.md │ ├── 计费模式.md │ ├── 运行数据统计.md │ ├── 部署函数.md │ ├── 部署列表.md │ ├── 部署服务.md │ └── 配置账号.md ├── examples ├── credentials └── project │ ├── index.js │ ├── package.json │ └── serverless.yml ├── index.js ├── info ├── lib │ ├── displayServiceInfo.js │ └── displayServiceInfo.test.js ├── tencentInfo.js └── tencentInfo.test.js ├── invoke ├── lib │ ├── invokeFunction.js │ └── invokeFunction.test.js ├── tencentInvoke.js └── tencentInvoke.test.js ├── logs ├── lib │ ├── retrieveLogs.js │ └── retrieveLogs.test.js ├── tencentLogs.js └── tencentLogs.test.js ├── metrics ├── lib │ ├── displayMetrics.js │ └── displayMetrics.test.js ├── tencentMetrics.js └── tencentMetrics.test.js ├── package.json ├── prettier.config.js ├── provider ├── tencentProvider.js └── tencentProvider.test.js ├── remove ├── lib │ ├── removeFunction.js │ └── removeFunction.test.js ├── tencentRemove.js └── tencentRemove.test.js ├── rollback ├── lib │ ├── rollbackService.js │ └── rollbackService.test.js ├── tencentRollback.js └── tencentRollback.test.js ├── shared ├── handler.js ├── utils.js └── validate.js ├── templates ├── tencent-go │ ├── Makefile │ ├── gitignore │ ├── index.go │ ├── package.json │ └── serverless.yml ├── tencent-nodejs │ ├── gitignore │ ├── index.js │ ├── package.json │ └── serverless.yml ├── tencent-php │ ├── gitignore │ ├── index.php │ ├── package.json │ └── serverless.yml └── tencent-python │ ├── gitignore │ ├── index.py │ ├── package.json │ └── serverless.yml └── test ├── init.js ├── mocha.opts ├── serverless.js └── tencentCommand.js /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | dist 3 | node_modules 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ['prettier'], 4 | plugins: ['import', 'prettier'], 5 | env: { 6 | es6: true, 7 | jest: true, 8 | node: true 9 | }, 10 | parser: 'babel-eslint', 11 | parserOptions: { 12 | ecmaVersion: 2018, 13 | sourceType: 'module', 14 | ecmaFeatures: { 15 | jsx: true 16 | } 17 | }, 18 | globals: { 19 | on: true // for the Socket file 20 | }, 21 | rules: { 22 | 'array-bracket-spacing': [ 23 | 'error', 24 | 'never', 25 | { 26 | objectsInArrays: false, 27 | arraysInArrays: false 28 | } 29 | ], 30 | 'arrow-parens': ['error', 'always'], 31 | 'arrow-spacing': ['error', { before: true, after: true }], 32 | 'comma-dangle': ['error', 'never'], 33 | curly: 'error', 34 | 'eol-last': 'error', 35 | 'func-names': 'off', 36 | 'id-length': [ 37 | 'error', 38 | { 39 | min: 2, 40 | max: 50, 41 | properties: 'never', 42 | exceptions: ['e', 'i', 'n', 't', 'x', 'y', 'z', '_', '$'] 43 | } 44 | ], 45 | 'no-alert': 'error', 46 | 'no-const-assign': 'error', 47 | 'no-else-return': 'error', 48 | 'no-empty': 'off', 49 | 'no-shadow': 'error', 50 | 'no-undef': 'error', 51 | 'no-unused-vars': 'error', 52 | 'no-use-before-define': 'error', 53 | 'no-useless-constructor': 'error', 54 | 'object-curly-newline': 'off', 55 | 'object-shorthand': 'off', 56 | 'prefer-const': 'error', 57 | 'prefer-destructuring': ['error', { object: true, array: false }], 58 | quotes: [ 59 | 'error', 60 | 'single', 61 | { 62 | allowTemplateLiterals: true, 63 | avoidEscape: true 64 | } 65 | ], 66 | semi: ['error', 'never'], 67 | 'spaced-comment': 'error', 68 | strict: ['error', 'never'], 69 | 'prettier/prettier': 'error' 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | *.log 3 | npm-debug.log 4 | npm-shrinkwrap.json 5 | package-lock.json 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | dist 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like nyc 17 | coverage 18 | /.nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directory 30 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 31 | node_modules 32 | 33 | # IDE stuff 34 | **/.idea 35 | **/.vs 36 | **/*.iml 37 | 38 | # OS stuff 39 | .DS_Store 40 | .tmp 41 | 42 | # Serverless stuff 43 | admin.env 44 | .env 45 | tmp 46 | .coveralls.yml 47 | tmpdirs-serverless 48 | *.zip 49 | tracking-config.json 50 | 51 | # ESLint cache 52 | .eslintcache 53 | 54 | # Misc 55 | jest 56 | 57 | # VIM 58 | *.swp 59 | 60 | # DotNet 61 | obj/ 62 | [Oo]bj/ 63 | 64 | # Tests 65 | !tests/**/*.zip 66 | 67 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | coverage 2 | dist 3 | node_modules 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - '8' 5 | - '9' 6 | - '10' 7 | 8 | sudo: false 9 | 10 | env: 11 | - NODE_ENV=test 12 | 13 | install: 14 | - travis_retry npm install 15 | 16 | script: 17 | - npm test 18 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | # 变更历史 2 | 3 | 4 | ## 2020-02-06 5 | * 优化COS实例创建代码 6 | 7 | ## 2020-02-06 8 | * 修复rollback操作可能出现函数状态错误问题 9 | * 优化函数状态检测部分代码 10 | 11 | ## 2019-11-26 12 | * 更新函数状态,提高部署成功率 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm version](https://badge.fury.io/js/serverless-tencent-scf.svg)](https://badge.fury.io/js/serverless-tencent-scf) 2 | [![Build Status](https://api.travis-ci.com/serverless-tencent/serverless-tencent-scf.svg?branch=master)](https://api.travis-ci.org/serverless-tencent/serverless-tencent-scf) 3 | 4 | [![Serverless Framework Tencent Cloud Plugin](https://s3.amazonaws.com/assets.general.serverless.com/framework_plugin_tencent/readme-provider-tencent-serverless.png)](http://serverless.com) 5 | 6 | 7 | 8 | 9 | # Quick Start 10 | 11 | Complete the steps in this guide to install the Serverless Framework open-source CLI and deploy a sample Service on Tencent Cloud that reports deployment information and operational metrics to the Serverless Framework. 12 | 13 | * [如果您需要中文文档帮助,可以点击此处](./docs/zh) 14 | 15 | * [If you need English Document, you could click here](./docs/en) 16 | 17 | ## Initial Setup 18 | 19 | There are a few prerequisites you need to install and configure: 20 | 21 | - [Install Node.js 6.x or later on your local machine](#install-nodejs-and-npm) 22 | - [Install the Serverless Framework open-source CLI version 1.47.0 or later](#install-the-serverless-framework-open-source-cli) 23 | 24 | If you already have these prerequisites setup you can skip ahead to deploy an example Service. 25 | 26 | ### Install Node.js and NPM 27 | 28 | - Follow these [installation instructions](https://nodejs.org/en/download/). 29 | - At the end, you should be able to run `node -v` from your command line and get a result like this... 30 | 31 | ```sh 32 | $ node -v 33 | vx.x.x 34 | ``` 35 | 36 | - You should also be able to run `npm -v` from your command line and should see... 37 | 38 | ```sh 39 | $ npm -v 40 | x.x.x 41 | ``` 42 | 43 | ### Install the Serverless Framework open-source CLI 44 | 45 | - Run this command in your terminal 46 | 47 | ```sh 48 | npm install -g serverless 49 | ``` 50 | 51 | - After install is complete, you should be able to run `serverless -v` from your command line and get a result like this... 52 | 53 | ```sh 54 | $ serverless -v 55 | x.x.x 56 | ``` 57 | 58 | ## Create and deploy a serverless Service 59 | 60 | Now that you’ve completed your setup, let’s create and deploy a serverless Service. 61 | 62 | ### Create a new Service from a Template 63 | 64 | 1. Use the Serverless Framework open-source CLI to create a new Service with `tencent-nodejs`template. 65 | 66 | ```sh 67 | # Create a new Serverless service/project 68 | $ serverless create --template tencent-nodejs --path my-service 69 | 70 | 2. Install the dependencies 71 | 72 | ```sh 73 | # Change into the newly created directory 74 | $ cd my-service 75 | $ npm install 76 | ``` 77 | 78 | ### Set up the credentials 79 | 80 | [Configure your Tencent Cloud account](./docs/en/credentials.md) to work with the Serverless Framework. 81 | 82 | ### Set up an endpoint 83 | 84 | An Event is anything that can trigger your serverless functions. In this case, you need to define a endpoint in your `serverless.yml` that will trigger your serverless function. 85 | 86 | ```yaml 87 | service: my-service # service name 88 | 89 | provider: # provider information 90 | name: tencent 91 | runtime: Nodejs8.9 92 | credentials: ~/credentials 93 | 94 | plugins: 95 | - serverless-tencent-scf 96 | 97 | functions: 98 | function_one: 99 | handler: index.main_handler 100 | runtime: Nodejs8.9 101 | events: 102 | - apigw: 103 | name: hello_world_apigw 104 | parameters: 105 | stageName: release 106 | serviceId: 107 | httpMethod: ANY 108 | ``` 109 | 110 | * [Click here you could get `Serverless.yml Reference`](./docs/en/yaml.md) 111 | 112 | ### Deploy the Service 113 | 114 | Use this command to deploy your service for the first time and after you make changes to your Functions, Events or Resources in `serverless.yml` and want to deploy all changes within your Service at the same time. 115 | 116 | ```bash 117 | serverless deploy 118 | ``` 119 | More information in [deploy command](./docs/en/deploy.md) 120 | 121 | ### Test your Service 122 | 123 | Replace the URL in the following curl command with your returned endpoint URL, which you can find in the `sls deploy` output, to hit your URL endpoint. 124 | 125 | ```bash 126 | $ curl -X POST https://service-xxxx-1300000000.ap-guangzhou.apigateway.myqcloud.com/release/ 127 | ``` 128 | 129 | ### Invoke your Service's function 130 | 131 | Invokes a Function and returns logs. 132 | 133 | ```bash 134 | serverless invoke -f hello 135 | ``` 136 | More information in [invoke command](./docs/en/invoke.md) 137 | 138 | ### Fetch the Function Logs 139 | 140 | Open up a separate tab in your console and stream all logs for a specific Function using this command. 141 | 142 | ```bash 143 | serverless logs -f hello -t 144 | ``` 145 | 146 | ## Cleanup 147 | 148 | ### Remove your Service 149 | 150 | If at any point you no longer need your Service, you can run the following command to remove the Functions, Events and Resources that were created. This will delete the resources you created and ensure that you don't incur any unexpected charges. 151 | 152 | ```sh 153 | serverless remove 154 | ``` 155 | -------------------------------------------------------------------------------- /deploy/lib/deployFunction.test.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon') 2 | const Serverless = require('../test/serverless') 3 | const DeployFunction = require('./deployFunction') 4 | 5 | describe('DeployFunction@Library', () => { 6 | let deployFunction 7 | let deployFunctionStub 8 | let updateFunctionCodeStub 9 | let createFunctionStub 10 | let getFunctionStub 11 | let updateConfigurationStub 12 | let createTagsStub 13 | let uploadService2CosStub 14 | 15 | let options 16 | let serverless 17 | 18 | beforeEach(() => { 19 | serverless = new Serverless() 20 | options = { 21 | region: 'ap-guangzhou' 22 | } 23 | 24 | deployFunction = new DeployFunction(options, serverless) 25 | 26 | deployFunctionStub = sinon.stub(deployFunction, 'deploy').returns(Promise.resolve()) 27 | updateFunctionCodeStub = sinon 28 | .stub(deployFunction, 'updateFunctionCode') 29 | .returns(Promise.resolve()) 30 | createFunctionStub = sinon.stub(deployFunction, 'createFunction').returns(Promise.resolve()) 31 | getFunctionStub = sinon.stub(deployFunction, 'getFunction').returns(Promise.resolve()) 32 | updateConfigurationStub = sinon 33 | .stub(deployFunction, 'updateConfiguration') 34 | .returns(Promise.resolve()) 35 | createTagsStub = sinon.stub(deployFunction, 'createTags').returns(Promise.resolve()) 36 | uploadService2CosStub = sinon 37 | .stub(deployFunction, 'uploadService2Cos') 38 | .returns(Promise.resolve()) 39 | }) 40 | 41 | afterEach(() => { 42 | deployFunction.deploy.restore() 43 | deployFunction.updateFunctionCode.restore() 44 | deployFunction.createFunction.restore() 45 | deployFunction.getFunction.restore() 46 | deployFunction.updateConfiguration.restore() 47 | deployFunction.createTags.restore() 48 | deployFunction.uploadService2Cos.restore() 49 | }) 50 | 51 | it('should make the deploy function accessible', () => { 52 | deployFunction.should.to.be.an.instanceof(DeployFunction) 53 | }) 54 | 55 | it('should run library deploy function', () => 56 | deployFunction.deploy().then(() => { 57 | deployFunctionStub.calledOnce.should.equal(true) 58 | })) 59 | 60 | it('should run library update function code', () => 61 | deployFunction.updateFunctionCode().then(() => { 62 | updateFunctionCodeStub.calledOnce.should.equal(true) 63 | })) 64 | 65 | it('should run library create function', () => 66 | deployFunction.createFunction().then(() => { 67 | createFunctionStub.calledOnce.should.equal(true) 68 | })) 69 | 70 | it('should run library get function', () => 71 | deployFunction.getFunction().then(() => { 72 | getFunctionStub.calledOnce.should.equal(true) 73 | })) 74 | 75 | it('should run library update configuration', () => 76 | deployFunction.updateConfiguration().then(() => { 77 | updateConfigurationStub.calledOnce.should.equal(true) 78 | })) 79 | 80 | it('should run library create tags', () => 81 | deployFunction.createTags().then(() => { 82 | createTagsStub.calledOnce.should.equal(true) 83 | })) 84 | it('should run library upload service to cos', () => 85 | deployFunction.uploadService2Cos().then(() => { 86 | uploadService2CosStub.calledOnce.should.equal(true) 87 | })) 88 | }) 89 | -------------------------------------------------------------------------------- /deploy/lib/deployListFunctions.js: -------------------------------------------------------------------------------- 1 | const tencentcloud = require('tencentcloud-sdk-nodejs') 2 | const AbstractHandler = require('../../shared/handler') 3 | const models = tencentcloud.scf.v20180416.Models 4 | const util = require('util') 5 | 6 | class InvokeFunction extends AbstractHandler { 7 | functionsList(funcName) { 8 | const req = new models.ListVersionByFunctionRequest() 9 | req.FunctionName = funcName 10 | req.Namespace = 'default' 11 | const handler = util.promisify(this.scfClient.ListVersionByFunction.bind(this.scfClient)) 12 | try { 13 | return handler(req) 14 | } catch (e) { 15 | this.serverless.cli.log('ErrorCode: ' + e.code + ' RequestId: ' + e.requestId) 16 | throw e 17 | } 18 | } 19 | } 20 | 21 | module.exports = InvokeFunction 22 | -------------------------------------------------------------------------------- /deploy/lib/deployListFunctions.test.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon') 2 | const Serverless = require('../test/serverless') 3 | const DeployListFunctions = require('./deployListFunctions') 4 | 5 | describe('DeployListFunctions@Library', () => { 6 | let deployListFunctions 7 | let deployListFunctionsStub 8 | 9 | let options 10 | let serverless 11 | 12 | beforeEach(() => { 13 | serverless = new Serverless() 14 | options = { 15 | region: 'ap-guangzhou' 16 | } 17 | deployListFunctions = new DeployListFunctions(options, serverless) 18 | 19 | deployListFunctionsStub = sinon 20 | .stub(deployListFunctions, 'functionsList') 21 | .returns(Promise.resolve()) 22 | }) 23 | 24 | afterEach(() => { 25 | deployListFunctions.functionsList.restore() 26 | }) 27 | 28 | it('should make the info function accessible', () => { 29 | deployListFunctions.should.to.be.an.instanceof(DeployListFunctions) 30 | }) 31 | 32 | it('should run library functions list', () => 33 | deployListFunctions.functionsList().then(() => { 34 | deployListFunctionsStub.calledOnce.should.equal(true) 35 | })) 36 | }) 37 | -------------------------------------------------------------------------------- /deploy/lib/deployTrigger.test.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon') 2 | const Serverless = require('../test/serverless') 3 | const DeployTrigger = require('./deployTrigger') 4 | 5 | describe('DeployTrigger@Library', () => { 6 | let deployTrigger 7 | let deployTriggerCreateStub 8 | 9 | let options 10 | let serverless 11 | 12 | beforeEach(() => { 13 | serverless = new Serverless() 14 | options = { 15 | region: 'ap-guangzhou' 16 | } 17 | deployTrigger = new DeployTrigger(options, serverless) 18 | 19 | deployTriggerCreateStub = sinon.stub(deployTrigger, 'create').returns(Promise.resolve()) 20 | }) 21 | 22 | afterEach(() => { 23 | deployTrigger.create.restore() 24 | }) 25 | 26 | it('should make the info function accessible', () => { 27 | deployTrigger.should.to.be.an.instanceof(DeployTrigger) 28 | }) 29 | 30 | it('should run library create trigger', () => 31 | deployTrigger.create().then(() => { 32 | deployTriggerCreateStub.calledOnce.should.equal(true) 33 | })) 34 | }) 35 | -------------------------------------------------------------------------------- /deploy/tencentDeploy.js: -------------------------------------------------------------------------------- 1 | const BbPromise = require('bluebird') 2 | const validate = require('../shared/validate') 3 | const utils = require('../shared/utils') 4 | const _ = require('lodash') 5 | const tencentProvider = require('../provider/tencentProvider') 6 | const DeployFunction = require('./lib/deployFunction') 7 | const DeployTrigger = require('./lib/deployTrigger') 8 | const MetricsFunction = require('../metrics/lib/displayMetrics') 9 | 10 | class TencentDeploy { 11 | constructor(serverless, options) { 12 | this.serverless = serverless 13 | this.options = options 14 | this.provider = this.serverless.getProvider('tencent') 15 | 16 | Object.assign(this, validate, utils, tencentProvider) 17 | 18 | this.hooks = { 19 | 'before:deploy:deploy': () => 20 | BbPromise.bind(this) 21 | .then(this.validate) 22 | .then(this.setDefaults), 23 | 24 | 'deploy:deploy': () => BbPromise.bind(this).then(this.deploy) 25 | } 26 | } 27 | 28 | async deploy() { 29 | const provider = new tencentProvider(this.serverless, this.options) 30 | this.options = await provider.getUserCred(this.options) 31 | await provider.getUserAuth(this.options.credentials.tencent_owneruin) 32 | 33 | const services = this.provider.getServiceResource() 34 | const func = new DeployFunction(this.options, this.serverless) 35 | const trigger = new DeployTrigger(this.options, this.serverless) 36 | const MetricsHandler = new MetricsFunction(this.options, this.serverless) 37 | 38 | // upload file to cos 39 | const cosBucket = this.provider.getDeployCosBucket(true) 40 | this.serverless.cli.log( 41 | `Uploading service package to cos[${cosBucket}]. ${services.ServiceZipName}` 42 | ) 43 | await func.uploadPackage2Cos( 44 | cosBucket, 45 | services.ServiceZipName, 46 | this.serverless.service.package.artifact 47 | ) 48 | this.serverless.cli.log( 49 | `Uploaded package successful ${this.serverless.service.package.artifact}` 50 | ) 51 | await func.uploadService2Cos(cosBucket, services.ServiceFileName, services) 52 | 53 | // deploy functions 54 | for (const funcName in services.Resources.default) { 55 | if (funcName == 'Type') { 56 | continue 57 | } 58 | const funcObject = _.cloneDeep(services.Resources.default[funcName]) 59 | funcObject.Name = funcName 60 | funcObject.FuncName = this.provider.getFunctionName(funcName) 61 | 62 | this.serverless.cli.log(`Creating function ${funcObject.FuncName}`) 63 | const oldFunc = await func.deploy('default', funcObject) 64 | this.serverless.cli.log(`Created function ${funcObject.FuncName}`) 65 | 66 | this.serverless.cli.log(`Setting tags for function ${funcObject.FuncName}`) 67 | await func.createTags('default', funcObject.FuncName, funcObject.Properties.Tags) 68 | 69 | if ((await func.checkStatus('default', funcObject)) == false) { 70 | throw `Function ${funcObject.FuncName} create/update failed` 71 | } 72 | 73 | this.serverless.cli.log(`Creating trigger for function ${funcObject.FuncName}`) 74 | await trigger.create( 75 | 'default', 76 | oldFunc ? oldFunc.Triggers : null, 77 | funcObject, 78 | (response, thisTrigger) => { 79 | if (thisTrigger.Type == 'apigw') { 80 | const resultDesc = JSON.parse(response.TriggerDesc) 81 | this.serverless.cli.log( 82 | `Created ${thisTrigger.Type} trigger ${response.TriggerName} for function ${funcObject.FuncName} success. service id ${resultDesc.service.serviceId} url ${resultDesc.service.subDomain}` 83 | ) 84 | } else { 85 | this.serverless.cli.log( 86 | `Created ${thisTrigger.Type} trigger ${response.TriggerName} for function ${funcObject.FuncName} success.` 87 | ) 88 | } 89 | }, 90 | (error) => { 91 | this.serverless.cli.log(error) 92 | } 93 | ) 94 | 95 | this.serverless.cli.log(`Deployed function ${funcObject.FuncName} successful`) 96 | } 97 | 98 | let outputInformation = `Service Information\nservice: ${this.serverless.service.service} \nstage: ${this.provider.options.stage} \nregion: ${this.provider.options.region} \nstack: ${this.serverless.service.service}-${this.provider.options.stage}\n` 99 | 100 | const functionList = await MetricsHandler.functionList( 101 | this.serverless.service.service, 102 | this.options.stage 103 | ) 104 | const functionListData = functionList.Functions || [] 105 | outputInformation = 106 | outputInformation + 'resources: ' + functionListData.length + '\nfunctions: ' 107 | let functionInformation 108 | for (const funcName in services.Resources.default) { 109 | if (funcName == 'Type') { 110 | continue 111 | } 112 | if (this.options.function && this.options.function != funcName) { 113 | continue 114 | } 115 | const funcObject = _.cloneDeep(services.Resources.default[funcName]) 116 | funcObject.Name = funcName 117 | funcObject.FuncName = this.provider.getFunctionName(funcName) 118 | const deployFunctionName = this.provider.getFunctionName(funcName) 119 | outputInformation = outputInformation + ` ${funcName}: ${deployFunctionName}\n` 120 | functionInformation = await func.getFunction('default', deployFunctionName, false) 121 | if (functionInformation.Triggers && functionInformation.Triggers.length > 0) { 122 | for (let i = 0; i <= functionInformation.Triggers.length; i++) { 123 | if ((await func.checkStatus('default', funcObject)) == false) { 124 | throw `Function ${funcObject.FuncName} create/update failed` 125 | } 126 | const thisTrigger = functionInformation.Triggers[i] 127 | try { 128 | if (thisTrigger.Type == 'apigw') { 129 | const triggerDesc = JSON.parse(thisTrigger.TriggerDesc) 130 | outputInformation = 131 | outputInformation + 132 | ` ${triggerDesc.api.requestConfig.method} - ${triggerDesc.service.subDomain}\n` 133 | } 134 | } catch (e) {} 135 | } 136 | } 137 | } 138 | this.serverless.cli.log(outputInformation) 139 | } 140 | } 141 | 142 | module.exports = TencentDeploy 143 | -------------------------------------------------------------------------------- /deploy/tencentDeploy.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const Serverless = require('../test/serverless') 6 | const TencentDeploy = require('./tencentDeploy') 7 | 8 | describe('TencentDeploy', () => { 9 | let serverless 10 | let options 11 | let tencentDeploy 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentDeploy = new TencentDeploy(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentDeploy.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentDeploy.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentDeploy.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let tencentDeployStub 55 | 56 | beforeEach(() => { 57 | validateStub = sinon.stub(tencentDeploy, 'validate').returns(Promise.resolve()) 58 | setDefaultsStub = sinon.stub(tencentDeploy, 'setDefaults').returns(Promise.resolve()) 59 | tencentDeployStub = sinon.stub(tencentDeploy, 'deploy').returns(Promise.resolve()) 60 | }) 61 | 62 | afterEach(() => { 63 | tencentDeploy.validate.restore() 64 | tencentDeploy.setDefaults.restore() 65 | tencentDeploy.deploy.restore() 66 | }) 67 | 68 | it('should run "before:deploy:deploy" promise chain', () => 69 | tencentDeploy.hooks['before:deploy:deploy']().then(() => { 70 | validateStub.calledOnce.should.equal(true) 71 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 72 | })) 73 | 74 | it('should run "deploy:deploy" promise chain', () => 75 | tencentDeploy.hooks['deploy:deploy']().then(() => { 76 | tencentDeployStub.calledOnce.should.equal(true) 77 | })) 78 | }) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /deploy/tencentDeployFunction.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const Serverless = require('../test/serverless') 6 | const TencentDeployFunction = require('./tencentDeployFunction') 7 | 8 | describe('TencentDeployFunction', () => { 9 | let serverless 10 | let options 11 | let tencentDeployFunction 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentDeployFunction = new TencentDeployFunction(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentDeployFunction.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentDeployFunction.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentDeployFunction.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let tencentDeployFunctionStub 55 | let tencentPackageFunctionStub 56 | 57 | beforeEach(() => { 58 | validateStub = sinon.stub(tencentDeployFunction, 'validate').returns(Promise.resolve()) 59 | setDefaultsStub = sinon 60 | .stub(tencentDeployFunction, 'setDefaults') 61 | .returns(Promise.resolve()) 62 | tencentDeployFunctionStub = sinon 63 | .stub(tencentDeployFunction, 'deploy') 64 | .returns(Promise.resolve()) 65 | tencentPackageFunctionStub = sinon 66 | .stub(tencentDeployFunction, 'packageFunction') 67 | .returns(Promise.resolve()) 68 | }) 69 | 70 | afterEach(() => { 71 | tencentDeployFunction.validate.restore() 72 | tencentDeployFunction.setDefaults.restore() 73 | tencentDeployFunction.deploy.restore() 74 | }) 75 | 76 | it('should run "deploy:function:initialize" promise chain', () => 77 | tencentDeployFunction.hooks['deploy:function:initialize']().then(() => { 78 | validateStub.calledOnce.should.equal(true) 79 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 80 | })) 81 | 82 | it('should run "deploy:function:packageFunction" promise chain', () => 83 | tencentDeployFunction.hooks['deploy:function:packageFunction']().then(() => { 84 | tencentPackageFunctionStub.calledOnce.should.equal(true) 85 | })) 86 | 87 | it('should run "deploy:function:deploy" promise chain', () => 88 | tencentDeployFunction.hooks['deploy:function:deploy']().then(() => { 89 | tencentDeployFunctionStub.calledOnce.should.equal(true) 90 | })) 91 | }) 92 | }) 93 | }) 94 | -------------------------------------------------------------------------------- /deploy/tencentDeployList.js: -------------------------------------------------------------------------------- 1 | const BbPromise = require('bluebird') 2 | const validate = require('../shared/validate') 3 | const utils = require('../shared/utils') 4 | const _ = require('lodash') 5 | const tencentProvider = require('../provider/tencentProvider') 6 | const RollbackService = require('../rollback/lib/rollbackService') 7 | 8 | class TencentDeployList { 9 | constructor(serverless, options) { 10 | this.serverless = serverless 11 | this.options = options 12 | this.provider = this.serverless.getProvider('tencent') 13 | 14 | Object.assign(this, validate, utils, tencentProvider) 15 | 16 | this.hooks = { 17 | 'before:deploy:list:log': () => 18 | BbPromise.bind(this) 19 | .then(this.validate) 20 | .then(this.setDefaults), 21 | 'deploy:list:log': () => BbPromise.bind(this).then(this.serviceList) 22 | } 23 | } 24 | 25 | async serviceList() { 26 | const provider = new tencentProvider(this.serverless, this.options) 27 | this.options = await provider.getUserCred(this.options) 28 | await provider.getUserAuth(this.options.credentials.tencent_owneruin) 29 | 30 | const Handler = new RollbackService(this.options, this.serverless) 31 | const fileKeyPrefix = this.serverless.service.service + '-' + this.options.stage 32 | const cosBucket = this.provider.getDeployCosBucket() 33 | const functionList = await Handler.historyList(fileKeyPrefix, cosBucket) 34 | if (functionList.Contents) { 35 | this.serverless.cli.log('Listing deployments:') 36 | for ( 37 | let functionIndex = functionList.Contents.length - 1; 38 | functionIndex >= 0; 39 | functionIndex-- 40 | ) { 41 | try { 42 | /** 43 | * Serverless: ------------- 44 | * Serverless: Timestamp: 1570942070508 45 | * Serverless: Datetime: 2019-10-13T04:47:50.508Z 46 | * Serverless: Files: 47 | * Serverless: - compiled-cloudformation-template.json 48 | * Serverless: - sls-aws.zip 49 | */ 50 | const thisFileKey = functionList.Contents[functionIndex].Key 51 | const thisFunctionJson = await Handler.getCosObject(thisFileKey, cosBucket) 52 | const thisFileJson = JSON.parse(thisFunctionJson.Body.toString('utf-8')) 53 | this.serverless.cli.log('-------------') 54 | this.serverless.cli.log('Timestamp: ' + thisFileJson.CreateTimestamp) 55 | this.serverless.cli.log('Datetime: ' + thisFileJson.CreateTime) 56 | this.serverless.cli.log('Files:') 57 | this.serverless.cli.log('- ' + thisFileJson.ServiceFileName) 58 | this.serverless.cli.log('- ' + thisFileJson.ServiceZipName) 59 | } catch (e) {} 60 | } 61 | } 62 | } 63 | } 64 | 65 | module.exports = TencentDeployList 66 | -------------------------------------------------------------------------------- /deploy/tencentDeployList.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const Serverless = require('../test/serverless') 6 | const TencentDeployList = require('./tencentDeployList') 7 | 8 | describe('TencentDeployList', () => { 9 | let serverless 10 | let options 11 | let tencentDeployList 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentDeployList = new TencentDeployList(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentDeployList.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentDeployList.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentDeployList.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let tencentDeployListStub 55 | 56 | beforeEach(() => { 57 | validateStub = sinon.stub(tencentDeployList, 'validate').returns(Promise.resolve()) 58 | setDefaultsStub = sinon.stub(tencentDeployList, 'setDefaults').returns(Promise.resolve()) 59 | tencentDeployListStub = sinon 60 | .stub(tencentDeployList, 'serviceList') 61 | .returns(Promise.resolve()) 62 | }) 63 | 64 | afterEach(() => { 65 | tencentDeployList.validate.restore() 66 | tencentDeployList.setDefaults.restore() 67 | tencentDeployList.serviceList.restore() 68 | }) 69 | 70 | it('should run "before:deploy:list:log" promise chain', () => 71 | tencentDeployList.hooks['before:deploy:list:log']().then(() => { 72 | validateStub.calledOnce.should.equal(true) 73 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 74 | })) 75 | 76 | it('should run "deploy:list:log" promise chain', () => 77 | tencentDeployList.hooks['deploy:list:log']().then(() => { 78 | tencentDeployListStub.calledOnce.should.equal(true) 79 | })) 80 | }) 81 | }) 82 | }) 83 | -------------------------------------------------------------------------------- /deploy/tencentDeployListFunctions.js: -------------------------------------------------------------------------------- 1 | const BbPromise = require('bluebird') 2 | 3 | const validate = require('../shared/validate') 4 | const utils = require('../shared/utils') 5 | const tencentProvider = require('../provider/tencentProvider') 6 | const ListFunctions = require('./lib/deployListFunctions') 7 | const InfoFunction = require('../info/lib/displayServiceInfo') 8 | 9 | class TencentDeployListFunction { 10 | constructor(serverless, options) { 11 | this.serverless = serverless 12 | this.options = options 13 | this.provider = this.serverless.getProvider('tencent') 14 | 15 | Object.assign(this, validate, utils, tencentProvider) 16 | 17 | this.hooks = { 18 | 'before:deploy:list:functions:log': () => 19 | BbPromise.bind(this) 20 | .then(this.validate) 21 | .then(this.setDefaults), 22 | 23 | 'deploy:list:functions:log': () => BbPromise.bind(this).then(this.functionList) 24 | } 25 | } 26 | 27 | async functionList() { 28 | const provider = new tencentProvider(this.serverless, this.options) 29 | this.options = await provider.getUserCred(this.options) 30 | await provider.getUserAuth(this.options.credentials.tencent_owneruin) 31 | 32 | try { 33 | const infoHandler = new InfoFunction(this.options, this.serverless) 34 | const deployHandler = new ListFunctions(this.options, this.serverless) 35 | const functionList = await infoHandler.info( 36 | this.serverless.service.service, 37 | this.options.stage 38 | ) 39 | const totalData = functionList.Functions || [] 40 | if (totalData.length > 0) { 41 | this.serverless.cli.log('Listing functions:') 42 | this.serverless.cli.log('-------------') 43 | let eveFunctionVersion 44 | for (let eveFunctionIndex = 0; eveFunctionIndex < totalData.length; eveFunctionIndex++) { 45 | eveFunctionVersion = await deployHandler.functionsList( 46 | totalData[eveFunctionIndex].FunctionName 47 | ) 48 | let thisVersionString = totalData[eveFunctionIndex].FunctionName + ': ' 49 | if (eveFunctionVersion.Versions) { 50 | for ( 51 | let eveVersion = 0; 52 | eveVersion < eveFunctionVersion.Versions.length; 53 | eveVersion++ 54 | ) { 55 | thisVersionString = 56 | thisVersionString + eveFunctionVersion.Versions[eveVersion].Version 57 | if (eveVersion < eveFunctionVersion.Versions.length - 1) { 58 | thisVersionString = thisVersionString + ', ' 59 | } 60 | } 61 | this.serverless.cli.log(thisVersionString) 62 | } 63 | } 64 | } 65 | } catch (e) { 66 | this.serverless.cli.log(e) 67 | } 68 | } 69 | } 70 | 71 | module.exports = TencentDeployListFunction 72 | -------------------------------------------------------------------------------- /deploy/tencentDeployListFunctions.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const Serverless = require('../test/serverless') 6 | const TencentDeployListFunctions = require('./tencentDeployListFunctions') 7 | 8 | describe('TencentDeployListFunctions', () => { 9 | let serverless 10 | let options 11 | let tencentDeployListFunctions 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentDeployListFunctions = new TencentDeployListFunctions(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentDeployListFunctions.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentDeployListFunctions.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentDeployListFunctions.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let tencentDeployListFunctionsStub 55 | 56 | beforeEach(() => { 57 | validateStub = sinon.stub(tencentDeployListFunctions, 'validate').returns(Promise.resolve()) 58 | setDefaultsStub = sinon 59 | .stub(tencentDeployListFunctions, 'setDefaults') 60 | .returns(Promise.resolve()) 61 | tencentDeployListFunctionsStub = sinon 62 | .stub(tencentDeployListFunctions, 'functionList') 63 | .returns(Promise.resolve()) 64 | }) 65 | 66 | afterEach(() => { 67 | tencentDeployListFunctions.validate.restore() 68 | tencentDeployListFunctions.setDefaults.restore() 69 | tencentDeployListFunctions.functionList.restore() 70 | }) 71 | 72 | it('should run "before:deploy:list:functions:log" promise chain', () => 73 | tencentDeployListFunctions.hooks['before:deploy:list:functions:log']().then(() => { 74 | validateStub.calledOnce.should.equal(true) 75 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 76 | })) 77 | 78 | it('should run "deploy:list:functions:log" promise chain', () => 79 | tencentDeployListFunctions.hooks['deploy:list:functions:log']().then(() => { 80 | tencentDeployListFunctionsStub.calledOnce.should.equal(true) 81 | })) 82 | }) 83 | }) 84 | }) 85 | -------------------------------------------------------------------------------- /docs/en/create.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Create 3 | 4 | Creates a new service in the current working directory based on the provided template. 5 | 6 | **Create service in current working directory:** 7 | 8 | ```bash 9 | serverless create --template tencent-nodejs 10 | ``` 11 | 12 | **Create service in new folder:** 13 | 14 | ```bash 15 | serverless create --template tencent-nodejs --path myService 16 | ``` 17 | 18 | **Create service in new folder using a custom template:** 19 | 20 | ```bash 21 | serverless create --template-url https://github.com/serverless/serverless/tree/master/lib/plugins/create/templates/tencent-nodejs --path myService 22 | ``` 23 | ## Options 24 | 25 | - `--template` or `-t` The name of one of the available templates. **Required if --template-url and --template-path are not present**. 26 | - `--template-url` or `-u` The name of one of the available templates. **Required if --template and --template-path are not present**. 27 | - `--template-path` The local path of your template. **Required if --template and --template-url are not present**. 28 | - `--path` or `-p` The path where the service should be created. 29 | - `--name` or `-n` the name of the service in `serverless.yml`. 30 | 31 | ## Available Templates 32 | 33 | To see a list of available templates run `serverless create --help` 34 | 35 | Most commonly used templates: 36 | 37 | - tencent-nodejs 38 | - tencent-python 39 | - tencent-php 40 | - tencent-go 41 | 42 | ## Examples 43 | 44 | ### Creating a new service 45 | 46 | ```bash 47 | serverless create --template tencent-nodejs --name my-project 48 | ``` 49 | 50 | This example will generate scaffolding for a service with `Tencent` as a provider and `nodejs8` as runtime. The scaffolding 51 | will be generated in the current working directory. 52 | 53 | Your new service will have a default stage called `dev` and a default region inside that stage called `ap-guangzhou`. 54 | The provider which is used for deployment later on is Tencent Cloud. 55 | 56 | ### Creating a named service in a (new) directory 57 | 58 | ```bash 59 | serverless create --template tencent-nodejs --path tencent-project 60 | ``` 61 | 62 | This example will generate scaffolding for a service with `Tencent` as a provider and `nodejs8` as runtime. The scaffolding 63 | will be generated in the `tencent-project` directory. This directory will be created if not present. Otherwise Serverless 64 | will use the already present directory. 65 | 66 | Additionally Serverless will rename the service according to the path you provide. In this example the service will be 67 | renamed to `tencent-project`. 68 | -------------------------------------------------------------------------------- /docs/en/credentials.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent Cloud - Credentials 3 | 4 | The Serverless Framework needs access to account credentials for your Tencent Cloud account so that it can create and manage resources on your behalf. 5 | 6 | ## Create a Tencent Cloud Account 7 | 8 | If you already have a Tencent Cloud account, skip to the next step to [create an CAM User and Access Key](#create-an-cam-user-and-access-key) 9 | 10 | To create a Tencent Cloud account: 11 | 1. Open https://cloud.tencent.com/, and then choose Sign up. 12 | 2. Follow the online instructions. 13 | - Part of the sign-up procedure involves entering a PIN using the phone keypad. 14 | 15 | 16 | ## Create an IAM User and Access Key 17 | 18 | Services in Tencent Cloud, such as SCF, require that you provide credentials when you access them to ensure that you have permission to access the resources owned by that service. To accomplish this Tencent Cloud recommends that you use Cloud Access Management (CAM). 19 | 20 | You need to create credentials Serverless can use to create resources in your Project. 21 | 1. Login to your account and go to the [Cloud Access Management (CAM) page](https://console.cloud.tencent.com/cam/capi). 22 | 2. Click on **Access Key** and then **Create Key**. 23 | 3. View and copy the **APPID**, **SecretId** & **SecretKey** to a temporary place. (To get the SecretKey, you may need to enter a PIN using the phone keypad.) 24 | 4. Create a file named `credentials` containing the credentials that you have collected. 25 | ```ini 26 | [default] 27 | tencent_secret_id = AKIDteBxxxxxxxxxxnZfk 28 | tencent_secret_key = AKID2qsxxxxxxxxxxxxxtTo 29 | ``` 30 | Save the credentials file to a folder like`~/.tencent/credentials`. Copy the path of the file you saved. 31 | 32 | ## Update `serverless.yml` (optional) 33 | 34 | Open up your `serverless.yml` file and update the `provider` section with 35 | the path to your credentials file (this path needs to be absolute). It should look something like this: 36 | 37 | ```yml 38 | provider: 39 | name: tencent 40 | credentials: ~/.tencent/credentials 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/en/deploy-function.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Deploy Function 3 | 4 | The `sls deploy function` command deploys an individual SCF function when there is any change in the function. This is a much faster way of deploying changes in code. 5 | 6 | ```bash 7 | serverless deploy function -f functionName 8 | ``` 9 | 10 | ## Options 11 | 12 | - `--function` or `-f` The name of the function which should be deployed 13 | - `--stage` or `-s` The stage in your service that you want to deploy to. 14 | - `--region` or `-r` The region in that stage that you want to deploy to. 15 | 16 | ## Examples 17 | 18 | ### Deployment without stage and region options 19 | 20 | ```bash 21 | serverless deploy function --function helloWorld 22 | ``` 23 | 24 | ### Deployment with stage and region options 25 | 26 | ```bash 27 | serverless deploy function --function helloWorld --stage dev --region ap-guangzhou 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/en/deploy-list.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Deploy List 3 | 4 | The `sls deploy list [functions]` command will list information about your deployments. 5 | 6 | You can either see all available deployments in your COS deployment bucket by running `serverless deploy list` or you can see the deployed functions by running `serverless deploy list functions`. 7 | 8 | The displayed information is useful when rolling back a deployment or function via `serverless rollback`. 9 | 10 | ## Options 11 | 12 | - `--stage` or `-s` The stage in your service that you want to deploy to. 13 | - `--region` or `-r` The region in that stage that you want to deploy to. 14 | 15 | ## Examples 16 | 17 | ### List existing deploys 18 | 19 | ```bash 20 | serverless deploy list 21 | ``` 22 | 23 | ### List deployed functions and their versions 24 | 25 | ```bash 26 | serverless deploy list functions 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/en/deploy.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - deploy 3 | 4 | The `sls deploy` command deploys your entire service. Run this command when you have made infrastructure changes (i.e., you edited `serverless.yml`). Use `serverless deploy function -f myFunction` when you have made code changes and you want to quickly upload your updated code to Tencent SCF (Serverless Cloud Functions) or just change function configuration. 5 | 6 | ```bash 7 | serverless deploy 8 | ``` 9 | 10 | ## Options 11 | 12 | - `--config` or `-c` Name of your configuration file, if other than `serverless.yml|.yaml|.js|.json`. 13 | - `--stage` or `-s` The stage in your service that you want to deploy to. 14 | - `--region` or `-r` The region in that stage that you want to deploy to. 15 | - `--package` or `-p` path to a pre-packaged directory and skip packaging step. 16 | - `--function` or `-f` Invoke `deploy function` (see above). Convenience shortcut - cannot be used with `--package`. 17 | 18 | ## Artifacts 19 | 20 | After the `serverless deploy` command runs, the framework runs `serverless package` in the background first then deploys the generated package. During the deployment, the framework creates a COS(Cloud Object Storage) bucket to storage the package by default. 21 | 22 | ## Examples 23 | 24 | ### Deployment without stage and region options 25 | 26 | ```bash 27 | serverless deploy 28 | ``` 29 | 30 | This is the simplest deployment usage possible. With this command Serverless will deploy your service to the defined 31 | provider in the default stage (`dev`) to the default region (`ap-guangzhou`). 32 | 33 | 34 | ### Deployment with stage and region options 35 | 36 | ```bash 37 | serverless deploy --stage pro --region ap-guangzhou 38 | ``` 39 | 40 | With this example we've defined that we want our service to be deployed to the `pro` stage in the region 41 | `ap-guangzhou`. 42 | 43 | ### Deployment from a pre-packaged directory 44 | 45 | ```bash 46 | serverless deploy --package /path/package/directory 47 | ``` 48 | 49 | With this example, the packaging step will be skipped and the framework will start deploying the package from the `/path/package/directory` directory. 50 | -------------------------------------------------------------------------------- /docs/en/deploying.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-SCF - Deploying 3 | 4 | The Serverless Framework was designed to provision your Serverless Cloud Functions, Events and infrastructure Resources safely and quickly. It does this via a couple of methods designed for different types of deployments. 5 | 6 | ## Deploy All 7 | 8 | This is the main method for doing deployments with the Serverless Framework: 9 | 10 | ```bash 11 | serverless deploy 12 | ``` 13 | 14 | Use this method when you have updated your Function, Event or Resource configuration in `serverless.yml` and you want to deploy that change (or multiple changes at the same time) to Tencent Cloud. 15 | 16 | **Note:** You can always enforce a deployment using the `--force` option, or specify a different configuration file name with the the `--config` option. 17 | 18 | 19 | ### Tips 20 | 21 | - Use this in your CI/CD systems, as it is the safest method of deployment. 22 | - You can print the progress during the deployment if you use `verbose` mode, like this: 23 | ``` 24 | serverless deploy --verbose 25 | ``` 26 | - This method defaults to `dev` stage and `ap-guangzhou` region. You can change the default stage and region in your `serverless.yml` file by setting the `stage` and `region` properties inside a `provider` object as the following example shows: 27 | 28 | ```yml 29 | # serverless.yml 30 | 31 | service: service-name 32 | provider: 33 | name: tencent 34 | stage: production 35 | region: ap-beijing 36 | ``` 37 | 38 | - You can also deploy to different stages and regions by passing in flags to the command: 39 | 40 | ``` 41 | serverless deploy --stage production --region ap-beijing 42 | ``` 43 | 44 | - You can specify your own COS bucket which should be used to store all the deployment artifacts. 45 | The `cosBucket` config which is nested under `provider` lets you e.g. set the `name` for this bucket. If you don't provide your own bucket, Serverless will create a bucket which by default. 46 | 47 | 48 | ## Deploy Function 49 | 50 | This deployment method simply overwrites the zip file of the current function on Tencent Cloud. 51 | 52 | ```bash 53 | serverless deploy function --function myFunction 54 | ``` 55 | 56 | ### Tips 57 | 58 | - Use this when you are developing and want to test because it's much faster. 59 | - During development, people will often run this command several times, as opposed to `serverless deploy` which is only run when larger infrastructure provisioning is required. 60 | 61 | Check out the [deploy command docs](../cli-reference/deploy.md) for all details and options. 62 | -------------------------------------------------------------------------------- /docs/en/events.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-SCF - Events 3 | 4 | Simply put, events are the things that trigger your functions to run. 5 | 6 | If you are using Tencent as your provider, all `events` in the service are anything in Tencent Cloud that can trigger an Serverless Cloud Function, like an COS bucket upload, a Cloud Kafka topic, and HTTP endpoints created via API Gateway. 7 | 8 | [View the events section for a list of supported events](./events) 9 | 10 | ## Configuration 11 | 12 | Events belong to each Function and can be found in the `events` property in `serverless.yml`. 13 | 14 | ```yml 15 | # 'functions' in serverless.yml 16 | functions: 17 | createUser: # Function name 18 | handler: handler.createUser # Reference to file handler.js & exported function 'createUser' 19 | events: # All events associated with this function 20 | - timer: 21 | name: timer 22 | parameters: 23 | cronExpression: '*/5 * * * *' 24 | enable: true 25 | ``` 26 | 27 | Events are objects, which can contain event-specific information. 28 | 29 | The `events` property is an array, because it's possible for functions to be triggered by multiple events, as shown. 30 | 31 | You can set multiple Events per Function, as long as that is supported by Tencnet Cloud and doesn't reach the limit. 32 | 33 | ```yml 34 | # 'functions' in serverless.yml 35 | functions: 36 | createUser: # Function name 37 | handler: handler.users # Reference to file handler.js & exported function 'users' 38 | events: # All events associated with this function 39 | - apigw: 40 | name: hello_world_apigw1 41 | parameters: 42 | stageName: release 43 | serviceId: 44 | httpMethod: ANY 45 | - apigw: 46 | name: hello_world_apigw2 47 | parameters: 48 | stageName: test 49 | serviceId: 50 | httpMethod: PUT 51 | ``` 52 | 53 | ## Types 54 | 55 | The Serverless Framework supports all of the Serverless Cloud Function events. Instead of listing them here, we've put them in a separate section, since they have a lot of configurations and functionality. [Check out the events section for more information.](../events) 56 | 57 | ## Deploying 58 | 59 | To deploy or update your Functions, Events and Infrastructure, run `serverless deploy`. 60 | -------------------------------------------------------------------------------- /docs/en/events/CKafka.md: -------------------------------------------------------------------------------- 1 | 2 | # CKafka (Cloud Kafka) 3 | 4 | ## Using a pre-existing CKafka topic 5 | 6 | In the following example we choose a pre-existing CKafka topic with name `ckafka_trigger`. The function will be called every time a message is sent to the `test` topic. 7 | 8 | ```yml 9 | functions: 10 | function_one: 11 | handler: index.main_handler 12 | runtime: Nodejs8.9 13 | events: 14 | - ckafka: 15 | name: ckafka_trigger 16 | parameters: 17 | name: ckafka-2o10hua5 # ckafka-id 18 | topic: test 19 | maxMsgNum: 999 20 | offset: latest 21 | enable: true 22 | ``` 23 | 24 | **Note:** CKafka triggers are enabled by default, and the consumer of CKafka will start to get the message from the `latest` offset. 25 | 26 | ## Event Message Structure for CKafka Trigger 27 | 28 | When the specified CKafka topic receives a message, the backend consumer module of SCF will consume the message and encapsulate the message into an event in JSON format like the one below, which triggers the bound function and pass the data content as input parameters to the function. 29 | 30 | ```json 31 | { 32 | "Records": [ 33 | { 34 | "Ckafka": { 35 | "topic": "test-topic", 36 | "partition":1, 37 | "offset":36, 38 | "msgKey": "None", 39 | "msgBody": "Hello from Ckafka!" 40 | } 41 | }, 42 | { 43 | "Ckafka": { 44 | "topic": "test-topic", 45 | "partition":1, 46 | "offset":37, 47 | "msgKey": "None", 48 | "msgBody": "Hello from Ckafka again!" 49 | } 50 | } 51 | ] 52 | } 53 | ``` -------------------------------------------------------------------------------- /docs/en/events/CMQ.md: -------------------------------------------------------------------------------- 1 | 2 | # CMQ (Cloud Message Queue) 3 | 4 | ## Using a pre-existing topic 5 | 6 | In the following example we choose a pre-existing CMQ topic with name `cmq_trigger`. The function will be called every time a message is sent to the `test-topic` topic. 7 | 8 | ```yml 9 | functions: 10 | function_one: 11 | handler: index.main_handler 12 | runtime: Nodejs8.9 13 | events: 14 | - cmq: 15 | name: cmq_trigger 16 | parameters: 17 | name: test-topic 18 | enable: true 19 | ``` 20 | 21 | **Note:** CMQ triggers are enabled by default. 22 | 23 | ## Event Structure for CMQ Topic Trigger 24 | 25 | When receiving a message, the specified CMQ Topic sends the following event data in JSON format to the bound SCF. 26 | 27 | ```json 28 | { 29 | "Records": [ 30 | { 31 | "CMQ": { 32 | "type": "topic", 33 | "topicOwner":120xxxxx, 34 | "topicName": "testtopic", 35 | "subscriptionName":"xxxxxx", 36 | "publishTime": "1970-01-01T00:00:00.000Z", 37 | "msgId": "123345346", 38 | "requestId":"123345346", 39 | "msgBody": "Hello from CMQ!", 40 | "msgTag": ["tag1","tag2"] 41 | } 42 | } 43 | ] 44 | } 45 | ``` -------------------------------------------------------------------------------- /docs/en/events/COS.md: -------------------------------------------------------------------------------- 1 | 2 | ## COS (Cloud Object Storage) 3 | 4 | 5 | ## Event Definition 6 | 7 | This example sets up a `COS` event which will trigger the `function_one` function whenever an object is uploaded to the `cli-appid.cos.ap-beijing.myqcloud.com` under your account. 8 | 9 | ```yml 10 | # serverless.yml 11 | 12 | functions: 13 | function_one: 14 | handler: index.main_handler 15 | runtime: Nodejs8.9 16 | 17 | events: 18 | - cos: 19 | name: cli-appid.cos.ap-beijing.myqcloud.com 20 | parameters: 21 | bucket: cli-appid.cos.ap-beijing.myqcloud.com 22 | filter: 23 | prefix: filterdir/ 24 | suffix: .jpg 25 | events: cos:ObjectCreated:* 26 | enable: true 27 | ``` 28 | 29 | - Use `events` in COS trigger to set the specific trigger event. In the example, the function is called whenever an object is uploaded to the bucket. 30 | 31 | - Use filter rules to configure COS trigger, In the example, the function is called whenever an image with `.jpg` extension is uploaded to folder `filterdir` in the bucket. 32 | 33 | 34 | See the documentation about the [COS Trigger](https://intl.cloud.tencent.com/document/product/583/9707) to get more detail. 35 | 36 | ## Event Message Structure for COS Trigger 37 | 38 | When an object creation or deletion event occurs in the specified COS bucket, event data will be sent to the bound SCF function in JSON format as shown below. 39 | 40 | ```json 41 | { 42 | "Records": [{ 43 | "cos": { 44 | "cosSchemaVersion": "1.0", 45 | "cosObject": { 46 | "url": "http://testpic-1253970026.cos.ap-chengdu.myqcloud.com/testfile", 47 | "meta": { 48 | "x-cos-request-id": "NWMxOWY4MGFfMjViMjU4NjRfMTUyMV8yNzhhZjM=", 49 | "Content-Type": "" 50 | }, 51 | "vid": "", 52 | "key": "/1253970026/testpic/testfile", 53 | "size": 1029 54 | }, 55 | "cosBucket": { 56 | "region": "cd", 57 | "name": "testpic", 58 | "appid": "1253970026" 59 | }, 60 | "cosNotificationId": "unkown" 61 | }, 62 | "event": { 63 | "eventName": "cos:ObjectCreated:*", 64 | "eventVersion": "1.0", 65 | "eventTime": 1545205770, 66 | "eventSource": "qcs::cos", 67 | "requestParameters": { 68 | "requestSourceIP": "192.168.15.101", 69 | "requestHeaders": { 70 | "Authorization": "q-sign-algorithm=sha1&q-ak=AKIDQm6iUh2NJ6jL41tVUis9KpY5Rgv49zyC&q-sign-time=1545205709;1545215769&q-key-time=1545205709;1545215769&q-header-list=host;x-cos-storage-class&q-url-param-list=&q-signature=098ac7dfe9cf21116f946c4b4c29001c2b449b14" 71 | } 72 | }, 73 | "eventQueue": "qcs:0:lambda:cd:appid/1253970026:default.printevent.$LATEST", 74 | "reservedInfo": "", 75 | "reqid": 179398952 76 | } 77 | }] 78 | } 79 | ``` -------------------------------------------------------------------------------- /docs/en/events/README.md: -------------------------------------------------------------------------------- 1 | # Serverless Tencent SCF Guide 2 | 3 | Welcome to the Serverless Tencent SCF Events Glossary! 4 | 5 | Get started with the [Introduction to the framework](./intro.md) 6 | 7 | If you have questions, join the [chat in Slack](https://serverless.com/slack) or [post over on the forums](https://forum.serverless.com/) 8 | -------------------------------------------------------------------------------- /docs/en/events/apigateway.md: -------------------------------------------------------------------------------- 1 | 2 | # API Gateway 3 | 4 | Tencent Serverless Cloud Functions can create function based API endpoints through API Gateway. 5 | 6 | It might be helpful to read the Tencent Serverless Cloud Functions [Trigger docs](https://intl.cloud.tencent.com/document/product/583/12513) to learn the full functionality. 7 | 8 | ## HTTP Endpoint 9 | 10 | This setup specifies that the function should be run when someone accesses the API gateway via a `POST` request. 11 | 12 | Here's an example: 13 | 14 | ```yml 15 | functions: 16 | function_one: 17 | handler: index.main_handler 18 | runtime: Nodejs8.9 19 | 20 | events: 21 | - apigw: 22 | name: hello_world_apigw 23 | parameters: 24 | stageName: release 25 | serviceId: # if you don't specify an exsiting serviceId, a new service will be created by default. 26 | httpMethod: POST 27 | ``` 28 | 29 | ```javascript 30 | //index.js 31 | exports.main_handler = async (event, context, callback) => { 32 | console.log(event); 33 | return { 34 | isBase64Encoded: false, 35 | statusCode: 200, 36 | headers: { 'Content-Type': 'text/html' }, 37 | body: 'hello world' 38 | } 39 | } 40 | ``` 41 | 42 | ## Event message structures of integration request for API Gateway trigger 43 | 44 | 45 | When an API Gateway trigger receives a request, it sends the event data to the bound function in JSON format as shown below. 46 | 47 | ```json 48 | { 49 | "requestContext": { 50 | "serviceId": "service-f94sy04v", 51 | "path": "/test/{path}", 52 | "httpMethod": "POST", 53 | "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", 54 | "identity": { 55 | "secretId": "abdcdxxxxxxxsdfs" 56 | }, 57 | "sourceIp": "10.0.2.14", 58 | "stage": "release" 59 | }, 60 | "headers": { 61 | "Accept-Language": "en-US,en,cn", 62 | "Accept": "text/html,application/xml,application/json", 63 | "Host": "service-3ei3tii4-251000691.ap-guangzhou.apigateway.myqloud.com", 64 | "User-Agent": "User Agent String" 65 | }, 66 | "body": "{\"test\":\"body\"}", 67 | "pathParameters": { 68 | "path": "value" 69 | }, 70 | "queryStringParameters": { 71 | "foo": "bar" 72 | }, 73 | "headerParameters":{ 74 | "Refer": "10.0.2.14" 75 | }, 76 | "stageVariables": { 77 | "stage": "release" 78 | }, 79 | "path": "/test/value", 80 | "queryString": { 81 | "foo" : "bar", 82 | "bob" : "alice" 83 | }, 84 | "httpMethod": "POST" 85 | } 86 | ``` 87 | -------------------------------------------------------------------------------- /docs/en/events/timer.md: -------------------------------------------------------------------------------- 1 | 2 | # Timer 3 | 4 | The following config will attach a timer trigger and causes the function `function_one` to be called every 5 seconds. The configuration allows you to attach multiple timer triggers to the same function. You can use the `cron` syntax. Take a look at the [Timer documentation](https://intl.cloud.tencent.com/document/product/583/9708) for more details. 5 | 6 | ```yaml 7 | functions: 8 | function_one: 9 | handler: index.main_handler 10 | runtime: Nodejs8.9 11 | 12 | events: 13 | - timer: 14 | name: timer 15 | parameters: 16 | cronExpression: '*/5 * * * *' 17 | enable: true 18 | ``` 19 | 20 | ## Enabling / Disabling 21 | 22 | **Note:** timer triggers are enabled by default. 23 | 24 | This will create and attach a timer for the `function_two` function which is disabled. If enabled it will call the `function_two` function every 1 minutes. 25 | 26 | ```yaml 27 | functions: 28 | function_two: 29 | handler: index.main_handler 30 | runtime: Nodejs8.9 31 | 32 | events: 33 | - timer: 34 | name: timer 35 | parameters: 36 | cronExpression: '0 */1 * * *' 37 | enable: false 38 | ``` 39 | 40 | ## Specify Name of Timer 41 | 42 | Name can be specified for a timer. 43 | 44 | ```yaml 45 | events: 46 | - timer: 47 | name: your-timer-name 48 | ``` 49 | 50 | ## Input Parameters of Timer 51 | 52 | When a timer trigger triggers a function, the following data structures are encapsulated in "event" and passed to the function. In addition, you can specify to pass the "message" for a timer trigger, which is null by default. 53 | 54 | ```json 55 | { 56 | "Type":"timer", 57 | "TriggerName":"EveryDay", 58 | "Time":"2019-02-21T11:49:00Z", 59 | "Message":"user define msg body" 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /docs/en/functions.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-SCF - Functions 3 | 4 | If you are using Tencent as a provider, all _functions_ inside the service are Tencent Serverless Cloud Functions. 5 | 6 | ## Configuration 7 | 8 | All of the functions in your serverless service can be found in `serverless.yml` under the `functions` property. 9 | 10 | ```yml 11 | service: myService # service name 12 | 13 | provider: # provider information 14 | name: tencent 15 | runtime: Nodejs8.9 16 | credentials: ~/credentials 17 | 18 | # you can overwrite defaults here 19 | # stage: dev 20 | # cosBucket: DEFAULT 21 | # role: QCS_SCFExcuteRole 22 | # memorySize: 256 23 | # timeout: 10 24 | # region: ap-shanghai 25 | # environment: 26 | # variables: 27 | # ENV_FIRST: env1 28 | # ENV_SECOND: env2 29 | 30 | plugins: 31 | - serverless-tencent-scf 32 | 33 | functions: 34 | function_one: 35 | handler: index.main_handler 36 | # description: Tencent Serverless Cloud Function 37 | runtime: Nodejs8.9 38 | # memorySilsze: 256 39 | # timeout: 10 40 | # environment: 41 | # variables: 42 | # ENV_FIRST: env1 43 | # ENV_Third: env2 44 | ``` 45 | 46 | The `handler` property points to the file and module containing the code you want to run in your function. 47 | 48 | ```javascript 49 | // index.js 50 | exports.main_handler = async (event, context, callback) => {}; 51 | ``` 52 | 53 | You can add as many functions as you want within this property. 54 | 55 | ```yml 56 | # serverless.yml 57 | 58 | service: myService # service name 59 | 60 | provider: # provider information 61 | name: tencent 62 | runtime: Nodejs8.9 63 | credentials: ~/credentials 64 | 65 | functions: 66 | functionOne: 67 | handler: handler.functionOne 68 | description: optional description for your function 69 | functionTwo: 70 | handler: handler.functionTwo 71 | functionThree: 72 | handler: handler.functionThree 73 | ``` 74 | 75 | Your functions can either inherit their settings from the `provider` property. 76 | 77 | ```yml 78 | # serverless.yml 79 | service: myService 80 | 81 | provider: # provider information 82 | name: tencent 83 | runtime: Nodejs8.9 84 | memorySize: 512 # will be inherited by all functions 85 | 86 | functions: 87 | functionOne: 88 | handler: handler.functionOne 89 | ``` 90 | 91 | Or you can specify properties at the function level. 92 | 93 | ```yml 94 | # serverless.yml 95 | service: myService 96 | 97 | provider: # provider information 98 | name: tencent 99 | runtime: Nodejs8.9 100 | 101 | functions: 102 | functionOne: 103 | handler: handler.functionOne 104 | memorySize: 512 # function specific 105 | ``` 106 | 107 | You can specify an array of functions, which is useful if you separate your functions in to different files: 108 | 109 | ```yml 110 | # serverless.yml 111 | --- 112 | functions: 113 | - ${file(./foo-functions.yml)} 114 | - ${file(./bar-functions.yml)} 115 | ``` 116 | 117 | ```yml 118 | # foo-functions.yml 119 | getFoo: 120 | handler: handler.foo 121 | deleteFoo: 122 | handler: handler.foo 123 | ``` 124 | 125 | ## Permissions 126 | 127 | Every Tencent Serverless Cloud Function needs permission to interact with other Tencent infrastructure resources within your account. These permissions are set via an CAM Role. You can set permission policy statements within this role via the `provider.role` property. 128 | 129 | ```yml 130 | # serverless.yml 131 | service: myService 132 | 133 | provider: # provider information 134 | name: tencent 135 | runtime: Nodejs8.9 136 | credentials: ~/credentials 137 | role: QCS_SCFExcuteRole # SCF default role to interact with other services. 138 | 139 | functions: 140 | functionOne: 141 | handler: handler.functionOne 142 | memorySize: 512 143 | ``` 144 | 145 | The executing role `QCS_SCFExcuteRole` is used to grant the function code permissions to read and operate resources during execution. 146 | 147 | Currently, this role has the following policies: 148 | - QcloudSCFFullAccess 149 | - QcloudCLSFullAccess 150 | 151 | `QcloudSCFFullAccess` is used to allow the code to access and call other functions under the same account during execution. 152 | `QcloudCLSFullAccess` is used to write a function execution log to CLS when the function is executed. 153 | 154 | ## Environment Variables 155 | 156 | You can add environment variable configuration to a specific function in `serverless.yml` by adding an `environment` object property in the function configuration. This object should contain a key-value pairs of string to string: 157 | 158 | ```yml 159 | # serverless.yml 160 | service: myService 161 | provider: 162 | name: tencent 163 | 164 | functions: 165 | hello: 166 | handler: handler.hello 167 | environment: 168 | TABLE_NAME: tableName 169 | ``` 170 | 171 | Or if you want to apply environment variable configuration to all functions in your service, you can add the configuration to the higher level `provider` object. Environment variables configured at the function level are merged with those at the provider level, so your function with specific environment variables will also have access to the environment variables defined at the provider level. If an environment variable with the same key is defined at both the function and provider levels, the function-specific value overrides the provider-level default value. For example: 172 | 173 | ```yml 174 | # serverless.yml 175 | service: myService 176 | provider: 177 | name: tencent 178 | environment: 179 | SYSTEM_NAME: mySystem 180 | TABLE_NAME: tableName1 181 | 182 | functions: 183 | hello: 184 | # this function will have SYSTEM_NAME=mySystem and TABLE_NAME=tableName1 from the provider-level environment config above 185 | handler: handler.hello 186 | users: 187 | # this function will have SYSTEM_NAME=mySystem from the provider-level environment config above 188 | # but TABLE_NAME will be tableName2 because this more specific config will override the default above 189 | handler: handler.users 190 | environment: 191 | TABLE_NAME: tableName2 192 | ``` 193 | 194 | Check out the [Environment Variables](./variables.md) for all the details and options. -------------------------------------------------------------------------------- /docs/en/info.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Info 3 | 4 | Displays information about the deployed service, such as runtime, region, stage and function list. 5 | 6 | ```bash 7 | serverless info 8 | ``` 9 | 10 | ## Options 11 | 12 | - `--stage` or `-s` The stage in your service you want to display information about. 13 | - `--region` or `-r` The region in your stage that you want to display information about. 14 | 15 | ## Provided lifecycle events 16 | 17 | - `info:info` 18 | 19 | ## Examples 20 | 21 | ```bash 22 | $ sls info 23 | Serverless: 24 | 25 | Service Information 26 | service: my-service 27 | stage: dev 28 | region: ap-guangzhou 29 | 30 | Deployed functions: 31 | my-service-dev-function_one 32 | 33 | Undeployed function: 34 | my-service-dev-function_two 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/en/install.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Install 3 | 4 | Installs a service from a GitHub URL in the current working directory. 5 | 6 | ```bash 7 | serverless install --url https://github.com/some/service 8 | ``` 9 | 10 | ## Options 11 | 12 | - `--url` or `-u` The services Git URL. **Required**. 13 | - `--name` or `-n` Name for the service. 14 | 15 | ## Examples 16 | 17 | ### Installing a service from a GitHub URL 18 | 19 | ```bash 20 | serverless install --url https://github.com/tencentcloud/serverless/tencent-nodejs 21 | ``` 22 | 23 | This example will download the .zip file of the `tencent-nodejs` service from GitHub, create a new directory with the name `tencent-nodejs` in the current working directory and unzips the files in this directory. 24 | 25 | ### Installing a service from a GitHub URL with a new service name 26 | 27 | ```bash 28 | serverless install --url https://github.com/tencentcloud/serverless/tencent-nodejs --name my-service 29 | ``` 30 | 31 | This example will download the .zip file of the `tencent-nodejs` service from GitHub, create a new directory with the name `my-service` in the current working directory and unzips the files in this directory and renames the service to `my-service` if `serverless.yml` exists in the service root. 32 | 33 | ### Installing a service from a directory in a GitHub URL 34 | 35 | ```bash 36 | serverless install --url https://github.com/tencentyun/scf-demo-repo/tree/master/Nodejs8.9-HexoDemo 37 | ``` 38 | 39 | This example will download the `Nodejs8.9-HexoDemo` service from GitHub. 40 | -------------------------------------------------------------------------------- /docs/en/installation.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Installation 3 | 4 | ### Installing Node.js 5 | 6 | Serverless is a [Node.js](https://nodejs.org) CLI tool so the first thing you need to do is to install Node.js on your machine. 7 | 8 | Go to the official [Node.js website](https://nodejs.org), download and follow the [installation instructions](https://nodejs.org/en/download/) to install Node.js on your local machine. 9 | 10 | **Note:** Serverless runs on Node v6 or higher. 11 | 12 | You can verify that Node.js is installed successfully by running `node --version` in your terminal. You should see the corresponding Node version number printed out. 13 | 14 | ### Installing the Serverless Framework 15 | 16 | Next, install the Serverless Framework via [npm](https://npmjs.org) which was already installed when you installed Node.js. 17 | 18 | Open up a terminal and type `npm install -g serverless` to install Serverless. 19 | 20 | ```bash 21 | npm install -g serverless 22 | ``` 23 | 24 | Once the installation process is done you can verify that Serverless is installed successfully by running the following command in your terminal: 25 | 26 | ```bash 27 | serverless 28 | ``` 29 | 30 | To see which version of serverless you have installed run: 31 | 32 | ```bash 33 | serverless --version 34 | ``` 35 | 36 | ### Setting up Tencent Cloud 37 | 38 | To run serverless commands that interface with your Tencent Cloud account, you will need to setup your Tencent Cloud account credentials on your machine. 39 | 40 | [Follow these instructions on setting up Tencent Cloud credentials](./credentials.md) 41 | -------------------------------------------------------------------------------- /docs/en/intro.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent SCF - Introduction 3 | 4 | The Serverless Framework helps you develop and deploy your Tencent SCF (Serverless Cloud Function), along with the Tencent infrastructure resources they require. It's a CLI that offers structure, automation and best practices out-of-the-box, allowing you to focus on building sophisticated, event-driven, serverless architectures, comprised of [Functions](#functions) and [Events](#events). 5 | 6 | The Serverless Framework is different from other application frameworks because: 7 | 8 | - It manages your code as well as your infrastructure 9 | - It supports multiple languages (Node.js, Python, PHP, and more) 10 | 11 | ## Core Concepts 12 | 13 | Here are the Framework's main concepts and how they pertain to Tencent Serverless Cloud Functions. 14 | 15 | ### Functions 16 | 17 | A Function is an Tencent Serverless Cloud Function. It's an independent unit of deployment, like a microservice. It's merely code, deployed in the cloud, that is most often written to perform a single job such as: 18 | 19 | - _Saving a user to the database_ 20 | - _Processing a file in a database_ 21 | - _Performing a scheduled task_ 22 | 23 | You can perform multiple jobs in your code, but we don't recommend doing that without good reason. Separation of concerns is best and the Framework is designed to help you easily develop and deploy Functions, as well as manage lots of them. 24 | 25 | ### Events 26 | 27 | Anything that triggers an Tencent SCF to execute is regarded by the Framework as an **Event**. Events are infrastructure events on SCF such as: 28 | 29 | - _An API Gateway HTTP endpoint request (e.g., for a REST API)_ 30 | - _A COS bucket upload (e.g., for an image)_ 31 | - _A scheduled task (e.g., run every 5 minutes)_ 32 | - _And more..._ 33 | 34 | When you define an event for your functions in the Serverless Framework, the Framework will automatically create any infrastructure necessary for that event (e.g., an API Gateway endpoint) and configure your SCF functions to listen to it. 35 | 36 | ### Resources 37 | 38 | **Resources** are Tencent Cloud infrastructure components which your Functions use such as: 39 | 40 | - _An API Gateway Service and API (e.g., for a REST API)_ 41 | - _A COS Bucket (e.g., for saving images or files)_ 42 | - _A Cloud Kafka Topic (e.g., for sending messages)_ 43 | - _And more..._ 44 | 45 | For scheduled task and API Gateway, The Serverless Framework not only deploys your Functions and the Events that trigger them, but it also deploys the Tencent Cloud infrastructure components your Functions depend upon. 46 | 47 | ### Services 48 | 49 | A **Service** is the Framework's unit of organization. You can think of it as a project file, though you can have multiple services for a single application. It's where you define your Functions, the Events that trigger them, and the Resources your Functions use, all in one file entitled `serverless.yml` (or `serverless.json` or `serverless.js`). It looks like this: 50 | 51 | ```yml 52 | # serverless.yml 53 | 54 | service: users 55 | 56 | functions: # Your "Functions" 57 | usersCreate: 58 | events: # The "Events" that trigger this function 59 | - http: post users/create 60 | usersDelete: 61 | events: 62 | - http: delete users/delete 63 | 64 | ``` 65 | 66 | When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` is deployed at once. 67 | 68 | ### Plugins 69 | 70 | You can overwrite or extend the functionality of the Framework using **Plugins**. Every `serverless.yml` can contain a `plugins:` property, which features multiple plugins. 71 | 72 | ```yml 73 | # serverless.yml 74 | 75 | plugins: 76 | - serverless-offline 77 | - serverless-secrets 78 | ``` 79 | -------------------------------------------------------------------------------- /docs/en/invoke.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Invoke 3 | 4 | Invokes deployed function. It allows to send event data to the function, read logs and display other important information of the function invocation. 5 | 6 | ```bash 7 | serverless invoke --function functionName 8 | ``` 9 | 10 | ## Options 11 | 12 | - `--function` or `-f` The name of the function in your service that you want to invoke. **Required**. 13 | - `--stage` or `-s` The stage in your service you want to invoke your function in. 14 | - `--region` or `-r` The region in your stage that you want to invoke your function in. 15 | 16 | ## Examples 17 | 18 | ```bash 19 | serverless invoke --function functionName --stage dev --region ap-guangzhou 20 | ``` 21 | 22 | This example will invoke your deployed function named `functionName` in region `ap-guangzhou` in stage `dev`. This will 23 | output the result of the invocation in your terminal. 24 | -------------------------------------------------------------------------------- /docs/en/logs.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Logs 3 | 4 | Lets you watch the logs of a specific function deployed in Tencent Cloud. 5 | 6 | ```bash 7 | serverless logs -f hello 8 | 9 | # Optionally tail the logs with -t 10 | serverless logs -f hello -t 11 | ``` 12 | 13 | ## Options 14 | 15 | - `--function` or `-f` The function you want to fetch the logs for. **Required** 16 | - `--stage` or `-s` The stage you want to view the function logs for. If not provided, the plugin will use the default stage listed in `serverless.yml`. If that doesn't exist either it'll just fetch the logs from the `dev` stage. 17 | - `--region` or `-r` The region you want to view the function logs for. If not provided, the plugin will use the default region listed in `serverless.yml`. If that doesn't exist either it'll just fetch the logs from the `ap-guangzhou` region. 18 | - `--startTime` A specific unit in time to start fetching logs from (ie: `2019-7-12 00:00:00` ). 19 | - `--tail` or `-t` You can optionally tail the logs and keep listening for new logs in your terminal session by passing this option. 20 | - `--interval` or `-i` If you choose to tail the output, you can control the interval at which the framework polls the logs with this option. The default is `1000`ms. 21 | 22 | ## Examples 23 | 24 | 25 | **Note:** There's a small lag between invoking the function and actually having the log event registered in Tencent Cloud Log Service. So it takes a few seconds for the logs to show up right after invoking the function. 26 | 27 | ```bash 28 | serverless logs -f hello 29 | ``` 30 | 31 | This will fetch the logs from last 10 minutes as startTime was not given. 32 | 33 | 34 | ```bash 35 | serverless logs -f hello -t 36 | ``` 37 | 38 | Serverless will tail the function log output and print new log messages coming in starting from 10 seconds ago. 39 | 40 | -------------------------------------------------------------------------------- /docs/en/metrics.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Metrics 3 | 4 | Lets you watch the metrics of a specific function. 5 | 6 | ```bash 7 | serverless metrics 8 | ``` 9 | 10 | ## Options 11 | 12 | - `--function` or `-f` The function you want to fetch the metrics for. 13 | - `--stage` or `-s` The stage you want to view the function metrics for. If not provided, the plugin will use the default stage listed in `serverless.yml`. If that doesn't exist either it'll just fetch the metrics from the `dev` stage. 14 | - `--region` or `-r` The region you want to view the function metrics for. If not provided, the plugin will use the default region listed in `serverless.yml`. If that doesn't exist either it'll just fetch the metrics from the `ap-guangzhou` region. 15 | - `--startTime` A specific unit in time to start fetching metrics from (ie: `"2019-7-12 00:10:00"`). 16 | - `--endTime` A specific unit in time to end fetching metrics from (ie: `"2019-7-12 00:10:00"`). 17 | 18 | ## Examples 19 | 20 | **Note:** There's a small lag between invoking the function and actually having access to the metrics. It takes a few seconds for the metrics to show up right after invoking the function. 21 | 22 | ### See service wide metrics for the last 24h 23 | 24 | ```bash 25 | serverless metrics 26 | ``` 27 | 28 | Displays service wide metrics for the last 24h. 29 | 30 | ### See service wide metrics for a specific timespan 31 | 32 | ```bash 33 | serverless metrics --startTime "2019-11-01 00:00:00" --endTime "2019-11-02 00:00:00" 34 | ``` 35 | 36 | Displays service wide metrics for the time between November 1, 2019 and November 2, 2019. 37 | 38 | ### See all metrics for the function `hello` of the last 24h 39 | 40 | ```bash 41 | serverless metrics --function hello 42 | ``` 43 | 44 | Displays all `hello` function metrics for the last 24h. 45 | 46 | ### See metrics for the function `hello` of a specific timespan 47 | 48 | ```bash 49 | serverless metrics --function hello --startTime "2019-11-01 00:00:00" --endTime "2019-11-02 00:00:00" 50 | ``` 51 | 52 | Displays all `hello` function metrics for the time between November 1, 2019 and November 2, 2019. 53 | -------------------------------------------------------------------------------- /docs/en/packaging.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-SCF - Packaging 3 | 4 | ## Package CLI Command 5 | 6 | Using the Serverless CLI tool, you can package your project without deploying it to Tencent Cloud. This is best used with CI / CD workflows to ensure consistent deployable artifacts. 7 | 8 | Running the following command will build and save all of the deployment artifacts in the service's .serverless directory: 9 | 10 | ```bash 11 | serverless package 12 | ``` 13 | 14 | However, you can also use the --package option to add a destination path and Serverless will store your deployment artifacts there (./my-artifacts in the following case): 15 | 16 | ```bash 17 | serverless package --package my-artifacts 18 | ``` 19 | 20 | ## Package Configuration 21 | 22 | Sometimes you might like to have more control over your function artifacts and how they are packaged. 23 | 24 | You can use the `package` and `exclude` configuration for more control over the packaging process. 25 | 26 | ### Exclude / include 27 | 28 | Exclude and include allows you to define globs that will be excluded / included from the resulting artifact. If you wish to 29 | include files you can use a glob pattern prefixed with `!` such as `!re-include-me/**` in `exclude` or the dedicated `include` config. 30 | Serverless will run the glob patterns in order. 31 | 32 | At first it will apply the globs defined in `exclude`. After that it'll add all the globs from `include`. This way you can always re-include 33 | previously excluded files and directories. 34 | 35 | By default, serverless will exclude the following patterns: 36 | 37 | - .git/\*\* 38 | - .gitignore 39 | - .DS_Store 40 | - npm-debug.log 41 | - .serverless/\*\* 42 | - .serverless_plugins/\*\* 43 | 44 | and the serverless configuration file being used (i.e. `serverless.yml`) 45 | 46 | ### Examples 47 | 48 | Exclude all node_modules but then re-include a specific modules (in this case node-fetch) using `exclude` exclusively 49 | 50 | ```yml 51 | package: 52 | exclude: 53 | - node_modules/** 54 | - '!node_modules/node-fetch/**' 55 | ``` 56 | 57 | Exclude all files but `handler.js` using `exclude` and `include` 58 | 59 | ```yml 60 | package: 61 | exclude: 62 | - src/** 63 | include: 64 | - src/function/handler.js 65 | ``` 66 | 67 | **Note:** Don't forget to use the correct glob syntax if you want to exclude directories 68 | 69 | ``` 70 | exclude: 71 | - tmp/** 72 | - .git/** 73 | ``` -------------------------------------------------------------------------------- /docs/en/remove.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Remove 3 | 4 | The `sls remove` command will remove the deployed service, defined in your current working directory, from the provider. 5 | 6 | ```bash 7 | serverless remove 8 | ``` 9 | 10 | ## Options 11 | 12 | - `--stage` or `-s` The name of the stage in service, `dev` by default. 13 | - `--region` or `-r` The name of the region in stage, `ap-guangzhou` by default. 14 | 15 | ## Examples 16 | 17 | ### Removal of service in specific stage and region 18 | 19 | ```bash 20 | serverless remove --stage dev --region ap-guangzhou 21 | ``` 22 | 23 | This example will remove the deployed service of your current working directory with the stage `dev` and the region `ap-guangzhou`. 24 | -------------------------------------------------------------------------------- /docs/en/rollback.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-scf - Rollback 3 | 4 | Rollback a service to a specific deployment. 5 | 6 | ```bash 7 | serverless rollback --timestamp timestamp 8 | ``` 9 | 10 | If `timestamp` is not specified, Framework will show your existing deployments. 11 | 12 | ## Options 13 | 14 | - `--timestamp` or `-t` The deployment you want to rollback to. 15 | - `--verbose` or `-v` Shows any history deployment. 16 | 17 | ## Examples 18 | 19 | 20 | At first you want to run `serverless deploy list` to show your existing deployments. This will provide you with a list of the deployments stored in your COS bucket. You can then use the timestamp of one of these deployments to rollback to this specific deployment. 21 | 22 | **Example:** 23 | 24 | ``` 25 | $ sls deploy list 26 | Serverless: Listing deployments: 27 | Serverless: ------------- 28 | Serverless: Timestamp: 1572625699 29 | Serverless: Datetime: 2019-11-01T16:28:19.896Z 30 | Serverless: Files: 31 | Serverless: - my-service-dev-1572625699.json 32 | Serverless: - my-service-dev-SNixdp-2019-11-01-16-28-19.zip 33 | Serverless: ------------- 34 | Serverless: Timestamp: 1572350506 35 | Serverless: Datetime: 2019-10-29T12:01:46.816Z 36 | Serverless: Files: 37 | Serverless: - my-service-dev-1572350506.json 38 | Serverless: - my-service-dev-2SDp7w-2019-10-29-12-01-46.zip 39 | 40 | $ sls rollback -t 1572625699 41 | Serverless: Rollback function my-service-dev-function_one 42 | Serverless: Rollback function my-service-dev-function_one 43 | Serverless: Rollback configure for function my-service-dev-function_one 44 | Serverless: Setting tags for function my-service-dev-function_one 45 | Serverless: Rollback trigger for function my-service-dev-function_one 46 | Serverless: Deployed function my-service-dev-function_one successful 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/en/services.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencnet SCF - Services 3 | 4 | A `service` is like a project. It's where you define your Tencent Serverless Cloud Functions and the `events` that trigger them, all in a file called `serverless.yml`. 5 | 6 | To get started building your first Serverless Framework project, create a `service`. 7 | 8 | ## Organization 9 | 10 | In the beginning of an application, many people use a single Service to define all of the Functions and Events for that project. This is what we recommend in the beginning. 11 | 12 | ```bash 13 | myService/ 14 | serverless.yml # Contains all functions and infrastructure resources 15 | ``` 16 | 17 | However, as your application grows, you can break it out into multiple services. A lot of people organize their services by workflows or data models, and group the functions related to those workflows and data models together in the service. 18 | 19 | ```bash 20 | users/ 21 | serverless.yml # Contains 4 functions that do Users CRUD operations and the Users database 22 | posts/ 23 | serverless.yml # Contains 4 functions that do Posts CRUD operations and the Posts database 24 | comments/ 25 | serverless.yml # Contains 4 functions that do Comments CRUD operations and the Comments database 26 | ``` 27 | 28 | This makes sense since related functions usually use common infrastructure resources, and you want to keep those functions and resources together as a single unit of deployment, for better organization and separation of concerns. 29 | 30 | ## Creation 31 | 32 | To create a service, use the `create` command. You can also pass in a path to create a directory and auto-name your service: 33 | 34 | ```bash 35 | # Create service with Node.js template in the folder ./my-service 36 | serverless create --template tencent-nodejs --path my-service 37 | ``` 38 | 39 | Here are the available runtimes for Tencent Serverless Cloud Function: 40 | 41 | - tencent-nodejs 42 | - tencent-python 43 | - tencent-php 44 | - tencent-go 45 | 46 | 47 | Check out the [create command docs](../cli-reference/create) for all the details and options. 48 | 49 | ## Contents 50 | 51 | You'll see the following files in your working directory: 52 | 53 | - `serverless.yml` 54 | - `index.js` 55 | 56 | ### serverless.yml 57 | 58 | Each `service` configuration is managed in the `serverless.yml` file. The main responsibilities of this file are: 59 | 60 | - Declare a Serverless service 61 | - Define one or more functions in the service 62 | - Define the provider the service will be deployed to (and the runtime if provided) 63 | - Define any custom plugins to be used 64 | - Define events that trigger each function to execute (e.g. HTTP requests) 65 | - Allow events listed in the `events` section to automatically create the resources required for the event upon deployment 66 | - Allow flexible configuration using Serverless Variables 67 | 68 | You can see the name of the service, the provider configuration and the first function inside the `functions` definition. Any further service configuration will be done in this file. 69 | 70 | ```yaml 71 | service: my-service # service name 72 | 73 | provider: # provider information 74 | name: tencent 75 | runtime: Nodejs8.9 76 | credentials: ~/credentials 77 | 78 | plugins: 79 | - serverless-tencent-scf 80 | 81 | functions: 82 | function_one: 83 | handler: index.main_handler 84 | runtime: Nodejs8.9 85 | events: 86 | - apigw: 87 | name: hello_world_apigw 88 | parameters: 89 | stageName: release 90 | serviceId: 91 | httpMethod: ANY 92 | ``` 93 | 94 | ### index.js 95 | 96 | The `index.js` file contains your exported functions. 97 | 98 | ## Deployment 99 | 100 | When you deploy a service, all of the functions, and events in your `serverless.yml` are translated into calls to the Tencent Cloud API to dynamically define those resources. 101 | 102 | To deploy a service, use the `deploy` command: 103 | 104 | ```bash 105 | serverless deploy 106 | ``` 107 | 108 | Check out the [deployment guide](./deploying.md) to learn more about deployments and how they work. Or, check out the [deploy command docs](../cli-reference/deploy.md) for all the details and options. 109 | 110 | ## Removal 111 | 112 | To easily remove your Service on Tencent Cloud, you can use the `remove` command. 113 | 114 | Run `serverless remove` to trigger the removal process. 115 | 116 | Serverless will start the removal and informs you about it's process on the console. A success message is printed once the whole service is removed. 117 | 118 | The removal process will only remove the service on your provider's infrastructure. The service directory will still remain on your local machine so you can still modify and (re)deploy it to another stage, region or provider later on. 119 | 120 | ## Version Pinning 121 | 122 | The Serverless framework is usually installed globally via `npm install -g serverless`. This way you have the Serverless CLI available for all your services. 123 | 124 | Installing tools globally has the downside that the version can't be pinned inside package.json. This can lead to issues if you upgrade Serverless, but your colleagues or CI system don't. You can use a feature in your serverless.yml without worrying that your CI system will deploy with an old version of Serverless. 125 | 126 | ### Pinning a Version 127 | 128 | To configure version pinning define a `frameworkVersion` property in your serverless.yaml. Whenever you run a Serverless command from the CLI it checks if your current Serverless version is matching the `frameworkVersion` range. The CLI uses [Semantic Versioning](http://semver.org/) so you can pin it to an exact version or provide a range. In general we recommend to pin to an exact version to ensure everybody in your team has the exact same setup and no unexpected problems happen. 129 | 130 | ### Examples 131 | 132 | #### Exact Version 133 | 134 | ```yml 135 | # serverless.yml 136 | 137 | frameworkVersion: '=1.0.3' 138 | ``` 139 | 140 | #### Version Range 141 | 142 | ```yml 143 | # serverless.yml 144 | 145 | frameworkVersion: '>=1.0.0 <2.0.0' 146 | ``` 147 | 148 | ## Installing Serverless in an existing service 149 | 150 | If you already have a Serverless service, and would prefer to lock down the framework version using `package.json`, then you can install Serverless as follows: 151 | 152 | ```bash 153 | # from within a service 154 | npm install serverless --save-dev 155 | ``` 156 | 157 | ### Invoking Serverless locally 158 | 159 | To execute the locally installed Serverless executable you have to reference the binary out of the node modules directory. 160 | 161 | Example: 162 | 163 | ``` 164 | node ./node_modules/serverless/bin/serverless deploy 165 | ``` -------------------------------------------------------------------------------- /docs/en/variables.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-SCF Variables 3 | 4 | Variables allow users to dynamically replace config values in `serverless.yml` config. They are especially useful when providing secrets for your service to use and when you are working with multiple stages. 5 | 6 | The Serverless framework provides a powerful variable system which allows you to add dynamic data into your `serverless.yml`. With Serverless Variables, you'll be able to do the following: 7 | 8 | - Reference & load variables from environment variables 9 | 10 | **Note:** You can only use variables in `serverless.yml` property **values**, not property keys. So you can't use variables to generate dynamic logical IDs in the custom resources section for example. 11 | 12 | ## Reference variables from environment variables 13 | 14 | To reference variables from environment variables, use the `${env:someProperty}` syntax in your `serverless.yml`. 15 | 16 | ```yml 17 | service: new-service 18 | 19 | provider: 20 | name: tencent 21 | runtime: Nodejs8.9 22 | credentials: ~/.tencent/credentials 23 | environment: 24 | variables: 25 | ENV_FIRST: ${env:TENCENTCLOUD_APPID} 26 | ``` 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/en/workflow.md: -------------------------------------------------------------------------------- 1 | 2 | # Tencent-SCF Workflow Tips 3 | 4 | Quick recommendations and tips for various processes. 5 | 6 | ### Development Workflow 7 | 8 | 1. Write your functions 9 | 2. Use `serverless deploy` only when you've made changes to `serverless.yml` and in CI/CD systems. 10 | 3. Use `serverless deploy function -f myFunction` to rapidly deploy changes when you are working on a specific Serverless Cloud Function. 11 | 4. Use `serverless invoke -f myFunction` to test your functions on Tencent Cloud. 12 | 5. Open up a separate tab in your console and stream logs in there via `serverless logs -f myFunction -t`. 13 | 6. Write tests to run locally. 14 | 15 | ### Using stages 16 | 17 | - At the very least, use a `dev` and `production` stage. 18 | - Use different Tencent Cloud accounts for stages. 19 | - In larger teams, each member should use a separate Tencent Cloud account and their own stage for development. 20 | 21 | ### Larger Projects 22 | 23 | - Break your application/project into multiple Serverless Services. 24 | - Model your Serverless Services around Data Models or Workflows. 25 | - Keep the Functions and Resources in your Serverless Services to a minimum. 26 | 27 | ## Cheat Sheet 28 | 29 | A handy list of commands to use when developing with the Serverless Framework. 30 | 31 | ##### Create A Service: 32 | 33 | Creates a new Service 34 | 35 | ``` 36 | serverless create -p [SERVICE NAME] -t tencent-nodejs 37 | ``` 38 | 39 | ##### Install A Service 40 | 41 | This is a convenience method to install a pre-made Serverless Service locally by downloading the Github repo and unzipping it. 42 | 43 | ``` 44 | serverless install -u [GITHUB URL OF SERVICE] 45 | ``` 46 | 47 | ##### Deploy All 48 | 49 | Use this when you have made changes to your Functions, Events or Resources in `serverless.yml` or you simply want to deploy all changes within your Service at the same time. 50 | 51 | ``` 52 | serverless deploy -s [STAGE NAME] -r [REGION NAME] -v 53 | ``` 54 | 55 | ##### Deploy Function 56 | 57 | Use this to quickly overwrite your SCF code on Tencent Cloud, allowing you to develop faster. 58 | 59 | ``` 60 | serverless deploy function -f [FUNCTION NAME] -s [STAGE NAME] -r [REGION NAME] 61 | ``` 62 | 63 | ##### Invoke Function 64 | 65 | Invokes a Serverless Cloud Function and returns logs. 66 | 67 | ``` 68 | serverless invoke -f [FUNCTION NAME] -s [STAGE NAME] -r [REGION NAME] -l 69 | ``` 70 | 71 | ##### Streaming Logs 72 | 73 | Open up a separate tab in your console and stream all logs for a specific Function using this command. 74 | 75 | ``` 76 | serverless logs -f [FUNCTION NAME] -s [STAGE NAME] -r [REGION NAME] 77 | ``` 78 | 79 | ##### Info 80 | See information about your deployed/undeployed functions by running the info command in your service directory. 81 | 82 | ``` 83 | serverless info 84 | ``` -------------------------------------------------------------------------------- /docs/en/yaml.md: -------------------------------------------------------------------------------- 1 | # Serverless.yml Reference 2 | Here is a list of all available properties in serverless.yml when the provider is set to tencent. 3 | ```yaml 4 | # Welcome to Serverless! 5 | # 6 | # This file is the main config file for your service. 7 | # It's very minimal at this point and uses default values. 8 | # You can always add more config options for more control. 9 | # We've included some commented out config examples here. 10 | # Just uncomment any of them to get that config option. 11 | # 12 | # For full config options, check the docs: 13 | # docs.serverless.com 14 | # 15 | # Happy Coding! 16 | 17 | service: my-service # service name 18 | 19 | provider: # provider information 20 | name: tencent 21 | runtime: Nodejs8.9 # Nodejs8.9 or Nodejs6.10 22 | credentials: ~/credentials 23 | 24 | # you can overwrite defaults here 25 | # enableRoleAuth: true 26 | # stage: dev 27 | # cosBucket: DEFAULT 28 | # role: QCS_SCFExcuteRole 29 | # memorySize: 256 30 | # timeout: 10 31 | # region: ap-shanghai 32 | # environment: 33 | # variables: 34 | # ENV_FIRST: env1 35 | # ENV_SECOND: env2 36 | # vpcConfig: 37 | # vpcId: test 38 | # subnetId: test 39 | 40 | plugins: 41 | - serverless-tencent-scf 42 | 43 | # you can add packaging information here 44 | #package: 45 | # include: 46 | # - include-me.js 47 | # - include-me-dir/** 48 | # exclude: 49 | # - exclude-me.js 50 | # - exclude-me-dir/** 51 | 52 | functions: 53 | function_one: 54 | handler: index.main_handler 55 | # description: Tencent Serverless Cloud Function 56 | # runtime: Nodejs8.9 # Nodejs8.9 or Nodejs6.10 57 | # memorySize: 256 58 | # timeout: 10 59 | # environment: 60 | # variables: 61 | # ENV_FIRST: env1 62 | # ENV_Third: env2 63 | # vpcConfig: 64 | # vpcId: test 65 | # subnetId: test 66 | # events: 67 | # - timer: 68 | # name: timer 69 | # parameters: 70 | # cronExpression: '*/5 * * * *' 71 | # enable: true 72 | # - cos: 73 | # name: cli-appid.cos.ap-beijing.myqcloud.com 74 | # parameters: 75 | # bucket: cli-appid.cos.ap-beijing.myqcloud.com 76 | # filter: 77 | # prefix: filterdir/ 78 | # suffix: .jpg 79 | # events: cos:ObjectCreated:* 80 | # enable: true 81 | # - apigw: 82 | # name: hello_world_apigw 83 | # parameters: 84 | # stageName: release 85 | # serviceId: 86 | # httpMethod: ANY 87 | # integratedResponse: true 88 | # path: /abc/cde 89 | # enableCORS: true 90 | # serviceTimeout: 10 91 | # - cmq: 92 | # name: cmq_trigger 93 | # parameters: 94 | # name: test-topic-queue 95 | # enable: true 96 | # - ckafka: 97 | # name: ckafka_trigger 98 | # parameters: 99 | # name: ckafka-2o10hua5 100 | # topic: test 101 | # maxMsgNum: 999 102 | # offset: latest 103 | # enable: true 104 | 105 | ``` 106 | -------------------------------------------------------------------------------- /docs/zh/README.md: -------------------------------------------------------------------------------- 1 | ## 操作场景 2 | 您可以通过如下几步,使用 Serverless Framework 开源 CLI 在腾讯云上部署一个服务,完成配置、创建、测试、部署等步骤。 3 | 4 | ## 前提条件 5 | 在使用之前,请确保如下软件已经安装: 6 | - [Node.js](#node)(6.x或以上的版本) 7 | - [Serverless Framework CLI](#cli)(1.57.0或以上的版本) 8 | 9 | 如果这些条件已经满足,您可以跳过此步骤,直接 [开始部署一个服务](#buzhou)。 10 | 11 | 12 | 13 | #### 安装 Node.js 和 NPM 14 | 15 | - 参考 [Node.js 安装指南](https://nodejs.org/zh-cn/download/) 根据您的系统环境进行安装。 16 | - 安装完毕后,通过`node -v` 命令,查看安装好的 Node.js 版本信息: 17 | ```sh 18 | $ node -v 19 | vx.x.x 20 | ``` 21 | - 通过 `npm -v` 命令,查看安装好的 npm 版本信息: 22 | ```sh 23 | $ npm -v 24 | x.x.x 25 | ``` 26 | 27 | 28 | #### 安装 Serverless Framework CLI 29 | 30 | - 在命令行中运行如下命令: 31 | ```sh 32 | npm install -g serverless 33 | ``` 34 | 35 | - 安装完毕后,通过运行 `serverless -v` 命令,查看 Serverless Framework CLI 的版本信息。 36 | ```sh 37 | $ serverless -v 38 | x.x.x 39 | ``` 40 | 41 | 42 | ## 操作步骤 43 | 44 | 完成上述安装准备后,通过如下步骤开始部署一个 Serverless 服务。 45 | 46 | #### 通过模板创建服务 47 | 1. 使用 Serverless Framework 的 `tencent-nodejs` 模板创建一个新的服务。 48 | 通过运行如下命令进行创建,`--path`可以指定服务的路径: 49 | ```sh 50 | # 创建一个serverless服务 51 | $ serverless create --template tencent-nodejs --path my-service 52 | ``` 53 | 2. 安装依赖。 54 | 进入服务所在路径,运行如下命令安装依赖: 55 | ```sh 56 | $ cd my-service 57 | $ npm install 58 | ``` 59 | 60 | #### 配置触发器 61 | 云函数需要通过触发器的事件调用进行触发,因此可以在`serverless.yml`中增加对触发器的配置,以 API 网关触发器为例,配置如下: 62 | ```yaml 63 | service: my-service # service name 64 | 65 | provider: # provider information 66 | name: tencent 67 | runtime: Nodejs8.9 68 | credentials: ~/credentials #如不使用二维码一键登录,密钥字段需要和credentials文件路径一致 69 | 70 | plugins: 71 | - serverless-tencent-scf 72 | 73 | functions: 74 | hello_world: # function name 75 | handler: index.main_handler 76 | runtime: Nodejs8.9 77 | events: 78 | - apigw: 79 | name: hello_world_apigw 80 | parameters: 81 | stageName: release 82 | serviceId: 83 | httpMethod: ANY 84 | ``` 85 | 86 | > 注,Serverless Framework会为控制台中实际部署的函数增加前缀组成函数名称,前缀规范为`service-stage-function`,默认的stage为`dev`。以上述配置为例,配置文件中的函数名称`hello_world`在控制台中的函数名称对应为`my-service-dev-hello_world`。 87 | 88 | #### 部署服务 89 | 通过该命令部署或更新您创建的函数和触发器,资源配置会和`serverless.yml`中保持一致。 90 | ```bash 91 | serverless deploy 92 | ``` 93 | 94 | 如您的账号未[登陆](https://cloud.tencent.com/login)或[注册](https://cloud.tencent.com/register)腾讯云,您可以在运行该命令后,直接用`微信`扫描命令中弹出的二维码,对云账户进行授权登陆和注册。 95 | 96 | 更多部署详情参考 [部署服务](./部署服务.md) 文档。 97 | 98 | #### 测试服务 99 | 100 | 替换如下命令中的链接地址,通过 curl 对其进行测试,该链接可以在`sls deploy`命令执行后获取得到。 101 | ```bash 102 | $ curl -X POST https://service-xxxx-1300000000.ap-guangzhou.apigateway.myqcloud.com/release/ 103 | ``` 104 | 105 | #### 云端调用 106 | 107 | 通过以下命令云端调用函数并且获得日志信息的返回。 108 | 109 | ```bash 110 | serverless invoke -f hello_world 111 | ``` 112 | 更多部署详情参考 [云端调用](./云端调用.md)。 113 | 114 | #### 获取函数日志 115 | 116 | 单独开启一个命令行,输入如下命令,再次云端调用函数,并实时获取函数`hello_world`的云端调用日志信息。 117 | ```bash 118 | serverless logs -f hello_world -t 119 | ``` 120 | 121 | #### 移除服务 122 | 123 | 如果您不再需要此服务,可以通过如下命令一键移除服务,该命令会清理相应函数和触发器资源。 124 | ```sh 125 | serverless remove 126 | ``` 127 | 128 | #### 配置账户信息 129 | 当前默认支持CLI扫描二维码登录,如您希望配置持久的环境变量/秘钥信息,也可以参考 [配置账号](./配置账号.md) 文档。 -------------------------------------------------------------------------------- /docs/zh/yaml.md: -------------------------------------------------------------------------------- 1 | # Serverless.yml 参考 2 | 以下是当提供商设置为tencent时,serverless.yml中所有可用属性的列表。 3 | ```yaml 4 | # Welcome to Serverless! 5 | # 6 | # This file is the main config file for your service. 7 | # It's very minimal at this point and uses default values. 8 | # You can always add more config options for more control. 9 | # We've included some commented out config examples here. 10 | # Just uncomment any of them to get that config option. 11 | # 12 | # For full config options, check the docs: 13 | # docs.serverless.com 14 | # 15 | # Happy Coding! 16 | 17 | service: my-service # service name 18 | 19 | provider: # provider information 20 | name: tencent 21 | runtime: Nodejs8.9 # Nodejs8.9 or Nodejs6.10 22 | credentials: ~/credentials 23 | 24 | # you can overwrite defaults here 25 | # stage: dev 26 | # cosBucket: DEFAULT 27 | # role: QCS_SCFExcuteRole 28 | # memorySize: 256 29 | # timeout: 10 30 | # region: ap-shanghai 31 | # environment: 32 | # variables: 33 | # ENV_FIRST: env1 34 | # ENV_SECOND: env2 35 | # vpcConfig: 36 | # vpcId: test 37 | # subnetId: test 38 | 39 | plugins: 40 | - serverless-tencent-scf 41 | 42 | # you can add packaging information here 43 | #package: 44 | # include: 45 | # - include-me.js 46 | # - include-me-dir/** 47 | # exclude: 48 | # - exclude-me.js 49 | # - exclude-me-dir/** 50 | 51 | functions: 52 | function_one: 53 | handler: index.main_handler 54 | # description: Tencent Serverless Cloud Function 55 | # runtime: Nodejs8.9 # Nodejs8.9 or Nodejs6.10 56 | # memorySize: 256 57 | # timeout: 10 58 | # environment: 59 | # variables: 60 | # ENV_FIRST: env1 61 | # ENV_Third: env2 62 | # vpcConfig: 63 | # vpcId: test 64 | # subnetId: test 65 | # events: 66 | # - timer: 67 | # name: timer 68 | # parameters: 69 | # cronExpression: '*/5 * * * *' 70 | # enable: true 71 | # - cos: 72 | # name: cli-appid.cos.ap-beijing.myqcloud.com 73 | # parameters: 74 | # bucket: cli-appid.cos.ap-beijing.myqcloud.com 75 | # filter: 76 | # prefix: filterdir/ 77 | # suffix: .jpg 78 | # events: cos:ObjectCreated:* 79 | # enable: true 80 | # - apigw: 81 | # name: hello_world_apigw 82 | # parameters: 83 | # stageName: release 84 | # serviceId: 85 | # httpMethod: ANY 86 | # integratedResponse: true 87 | # path: /abc/cde 88 | # enableCORS: true 89 | # serviceTimeout: 10 90 | # - cmq: 91 | # name: cmq_trigger 92 | # parameters: 93 | # name: test-topic-queue 94 | # enable: true 95 | # - ckafka: 96 | # name: ckafka_trigger 97 | # parameters: 98 | # name: ckafka-2o10hua5 99 | # topic: test 100 | # maxMsgNum: 999 101 | # offset: latest 102 | # enable: true 103 | 104 | ``` 105 | -------------------------------------------------------------------------------- /docs/zh/云端调用.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 调用已部署的云函数,支持发送测试数据到云函数,返回函数日志并展示其他调用关键信息。 4 | 5 | ``` 6 | serverless invoke --function functionName 7 | ``` 8 | 9 | 10 | 11 | ## 参数说明 12 | 13 | - `--function` 或 `-f` 已部署到云函数名。 【必填】 14 | - `--stage`或 `-s`目标部署环境,默认为`dev` 15 | - `--region`或`-r` 目标部署区域,默认为 `ap-guangzhou` 16 | 17 | 18 | 19 | 20 | ## 示例 21 | 22 | ### 调用指定函数 23 | 24 | ``` 25 | serverless invoke --function functionName --stage dev --region ap-guangzhou 26 | ``` 27 | 28 | 执行上述命令,调用已部署至广州区域的 `dev` 环境下的 `functionName` 函数,调用结果将输出至终端。 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/zh/产品概述.md: -------------------------------------------------------------------------------- 1 | Serverless Framework 是业界非常受欢迎的无服务器应用框架,开发者无需关心底层资源即可部署完整可用的 Serverless 应用架构。Serverless Framework 具有资源编排、自动伸缩、事件驱动等能力,覆盖编码、调试、测试、部署等全生命周期,帮助开发者通过联动云资源,迅速构建 Serverless 应用。 2 | 3 | Serverless Framework 是一个 标准化、组件化 的 Serverless 应用开发产品,如下图所示: 4 | 5 | ![Serverless Framework架构图](https://main.qcloudimg.com/raw/2c5d24285f2ea19151635d0352dc2a20.png) 6 | 7 | ## 产品功能 8 | #### 应用级框架 9 | Serverless Framework 提供贴合应用场景的框架,开发者根据实际需求选择对应框架后,只需专注于业务逻辑的开发,无需关注底层资源。 10 | 11 | #### 便捷部署 12 | 开发者部署应用时,Serverless Framework 会根据应用特性,自动完成云函数、API 网关、COS 等基础资源的部署和配置,无需再手动部署配置每一项基础资源。 13 | 14 | ## 应用场景 15 | #### 一站式体验 16 | 通过 Serverless Framework,您可以快速创建 Serverless 应用,并完成应用的调试和部署,监控已发布应用运行状态并快速排障。 17 | Serverless Framework 提供多种 Serverless 应用级别的组件,开发者无需关注 Serverless 应用底层资源,选择并下载符合自己业务场景的组件后,编写个性化的业务逻辑即可。 18 | ![](https://main.qcloudimg.com/raw/f4f0af702e134982fd5ef068c31a070e.svg) -------------------------------------------------------------------------------- /docs/zh/创建服务.md: -------------------------------------------------------------------------------- 1 | 在当前目录创建一个示例模板 2 | 3 | ``` 4 | serverless create --template tencent-nodejs 5 | ``` 6 | 7 | 创建完成后,将会在当前目录生成示例代码 `index.js` 和应用描述文件`serverless.yml` 。 8 | 9 | 在指定目录创建示例模板 10 | 11 | ``` 12 | serverless create --template tencent-nodejs --path my-service 13 | ``` 14 | 15 | 16 | 17 | ## 参数 18 | 19 | - `--template` 或 `-t` 模版文件名。必填 20 | - `--path` 或 `-p` 目标目录。 21 | 22 | 23 | 24 | ## 可用模板 25 | 26 | 您可以执行 `serverless create --help` 查看支持的模板列表 。 -------------------------------------------------------------------------------- /docs/zh/删除服务.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 您可以使用`sls remove`命令删除您部署的服务。 4 | 5 | ``` 6 | serverless remove 7 | ``` 8 | 9 | 10 | 11 | ## 参数说明 12 | 13 | - `--stage`或 `-s`目标部署环境,默认为`dev` 14 | - `--region`或`-r` 目标部署区域,默认为 `ap-guangzhou` 15 | 16 | 17 | 18 | ## 示例 19 | 20 | ### 删除指定环境和区域的服务 21 | 22 | ``` 23 | serverless remove --stage dev --region ap-guangzhou 24 | ``` 25 | 26 | 执行上述命令,删除当前工作区定义的已部署至 stage (dev) 和 region(ap-guangzhou)的服务。 27 | 28 | -------------------------------------------------------------------------------- /docs/zh/回滚服务.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 回滚已部署的服务版本。 4 | 5 | ``` 6 | serverless rollback --timestamp timestamp 7 | ``` 8 | 9 | 执行回滚前可以通过`sls rollback -v` 获取已部署的历史版本时间戳。 10 | 11 | ## 参数说明 12 | 13 | - `--timestamp` 或 `-t` 已部署的历史版本时间戳。 14 | - `--verbose`或 `-v` 获取历史部署版本 15 | 16 | 17 | 18 | ## 示例 19 | 20 | 您可以先执行`sls rollback -v` 获取您在 COS 里的历史部署版本,然后指定某一版本进行回滚。 21 | 22 | ``` 23 | $ sls rollback -v 24 | $ sls rollback -t 1571240207 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /docs/zh/常见问题.md: -------------------------------------------------------------------------------- 1 | ### Serverless Framework 和 云函数 SCF 的区别 2 | 云函数(Serverless Cloud Function,SCF)是腾讯云为企业和开发者们提供的无服务器执行环境,帮助您在无需购买和管理服务器的情况下运行代码 。 3 | Serverless Framework 是无服务器应用框架,提供将云函数 SCF ,API 网关,DB 等资源组合的业务框架,开发者可以直接基于框架编写业务逻辑,而无需关注底层资源的配置和管理。 4 | 5 | ### Serverless Framework 提供了哪些应用框架 6 | 目前已提供 REST API 和 基础 website ,更多贴合实际应用场景的框架在持续输出中。 7 | 8 | ### Serverless Framework 报错 "component" input is requires to run custom methods 怎么处理? 9 | 运行Serverless Framework CLI时,如果yaml配置文件中默认引用了component组件,则需要保证文件夹之前为空,才可以正确运行component的安装命令。 10 | 您可以尝试在一个空文件夹中重新运行`serverless create`命令,则不会再出现如下错误。 11 | 12 | ### 云函数执行超时怎么处理? 13 | 14 | 超时客户端会直接断开连接并报错,建议控制函数执行时间,尽量不要把耗时长的操作放在客户端直接调用的云函数内。 15 | 16 | ### 云函数内置模块怎么使用? 17 | 18 | 云函数内置模块已经集成于运行环境,可以直接使用。 19 | 如果内置模块的版本不能满足需求,可以自行安装模块到云函数内,默认会被优先使用。 20 | 目前已支持的内置模块为 request 2.87.1 。 21 | 22 | ### 云函数测试时,部分日志丢失了? 23 | 24 | - 云函数测试时,如果以同步调用的方式(超时时间小于 20 秒),返回的日志最多为 4k,超过 4k 的日志不显示。 25 | - 如果以异步调用的方式(超时时间大于或等于 20 秒),返回的日志最多为 6M,超过 6M 的日志不显示。 -------------------------------------------------------------------------------- /docs/zh/应用场景.md: -------------------------------------------------------------------------------- 1 | 快速创建 serverless 应用,并完成应用的调试,部署,可以监控已发布应用运行状态并快速排障。 2 | 提供多种 serverless 应用级别的组件,开发者无需关注 serverless 应用底层资源,选择并下载符合自己业务场景的组件后,编写个性化的业务逻辑即可。 3 | 4 | ![](https://main.qcloudimg.com/raw/df53277f8825d75b09f9849aca766117.png) -------------------------------------------------------------------------------- /docs/zh/快速安装.md: -------------------------------------------------------------------------------- 1 | ## 环境准备 2 | 3 | - 已安装 `npm` ,如果未安装,可前往[Node.js官网](https://nodejs.org/)下载对应平台的安装程序,版本要求 : Node6 +。安装完成后,执行 `npm -v` 确认是否安装成功。 4 | 5 | 6 | 7 | ## 安装 CLI 8 | 9 | 执行以下命令安装/更新 CLI : 10 | 11 | ``` 12 | # 安装 CLI 13 | npm install -g serverless 14 | ``` 15 | 16 | 17 | 18 | ## 升级 CLI 19 | 20 | 如果已安装过 CLI ,则可以执行以下命令更新: 21 | 22 | ``` 23 | npm update -g serverless 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /docs/zh/打包服务.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 您可以使用`sls package`命令将您的项目代码打包成部署包,会默认生成到项目目录下的 .serverless 目录。您可以通过追加`--package`参数指定打包目录。 4 | 5 | ``` 6 | serverless package 7 | ``` 8 | 9 | 10 | 11 | ## 参数说明 12 | 13 | - `--stage` 或`-s` 目标部署环境,您可以自定义指定诸如`dev`,`pro` 等环境参数,默认为`dev`。部署后,环境参数将追加至云函数名之后,且会作为云函数的标签。 14 | - `--region`或`-r` 目标部署区域,默认为广州 `ap-guangzhou` 15 | - `--package`或`-p` 自定义部署包目录 16 | 17 | 18 | 19 | ## 示例 20 | 21 | ### 默认打包 22 | 23 | ``` 24 | serverless package 25 | ``` 26 | 27 | 执行以上命令,将会默认指定目标部署 stage (dev) 和 region(ap-guangzhou),部署包会生成在您项目下的 .serverless 目录。 28 | 29 | 30 | 31 | ### 指定区域和环境 32 | 33 | ``` 34 | serverless package --stage pro --region ap-shanghai 35 | ``` 36 | 37 | 执行以上命令,将会指定目标部署stage (pro) 和 region(ap-shanghai),部署包会生成在您项目下的 .serverless 目录。 38 | 39 | 40 | 41 | ### 指定目录 42 | 43 | ``` 44 | serverless package --package /path/to/package/directory 45 | ``` 46 | 47 | 执行以上命令,将会指定目标部署stage (dev) 和 region(ap-guangzhou),部署包会生成在目录`/path/to/package/directory` 。 -------------------------------------------------------------------------------- /docs/zh/日志查看.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 查看云端函数运行日志。 4 | 5 | ``` 6 | serverless logs -f hello 7 | 8 | # 查看实时最新日志可以追加参数 -t 9 | serverless logs -f hello -t 10 | ``` 11 | 12 | 13 | 14 | ## 参数说明 15 | 16 | - `--function` 或 `-f` 已部署的云函数名。 【必填】 17 | - `--stage`或 `-s`目标部署环境,如果未指定,则会读取 `serverless.yaml` 里的 `stage` 信息,如果没有,则默认为`dev` 18 | - `--region`或`-r` 目标部署区域,如果未指定,则会读取 `serverless.yaml` 里的 `region` 信息,如果没有,默认为 `ap-guangzhou` 19 | 20 | - `--startTime` 日志开始时间 ,如`"2019-7-12 00:00:00"` 21 | - `--tail` 或 `-t` 实时获取最新日志 22 | - `--interval` 日志输出间隔,当您启用了 tail 功能,您可以控制日志输出频率,默认是 1000 ms 。 23 | 24 | 25 | ## 示例 26 | 27 | ### 获取默认日志 28 | 29 | ``` 30 | serverless logs -f hello 31 | ``` 32 | 33 | 执行上述命令,获取云函数`hello`最近十分钟的调用日志。 34 | 35 | ### 实时日志 36 | 37 | ``` 38 | serverless logs -f hello -t 39 | ``` 40 | 41 | 执行上述命令,获取 10 秒前的日志,并每 10 秒更新一次日志。 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/zh/服务等级协议.md: -------------------------------------------------------------------------------- 1 | **为使用腾讯云云函数服务(以下简称“本服务”),您应当阅读并遵守《云函数服务等级协议》(以下简称“本协议” 或 “SLA”),以及《[腾讯云服务协议](https://cloud.tencent.com/document/product/301/1967)》。本协议包含本服务的术语和定义、服务可用性等级指标、赔偿方案、免责条款等相关内容。请您务必审慎阅读、充分理解各条款内容,限制、免责条款或者其他涉及您重大权益的条款可能会以加粗、加下划线等形式提示您重点注意。** 2 | 3 | **除非您已充分阅读、完全理解并接受本协议所有条款,否则,请您不要购买本服务。您点击“同意”、“下一步”或您的购买、使用等行为或者您以其他任何明示或者默示方式表示接受本协议的,即视为您已阅读并同意本协议的约束。本协议即在您与腾讯云之间产生法律效力,成为对双方均具有约束力的法律文件。** 4 | 5 | ## 1. 术语和定义 6 | #### 1.1 Serverless Framework 7 | 是指腾讯云为您提供的 Serverless 应用框架。 8 | #### 1.2 服务月度 9 | 服务月度是指您购买本服务的服务期限所包含的各个自然月度,如您购买三个月本服务,服务开通之日为3月17日,则包含4个服务月度,其中第1个服务月度是指3月17日到3月31日,第2个服务月度是指4月1日到4月30日,第3个服务月度是指5月1日到5月31日,第4个服务月度是指6月1日到6月16日。服务可用性按服务月度单独核算。 10 | #### 1.3 服务不可用时间 11 | 本服务在单位时间内(5分钟为一个统计粒度)错误率超过5%,视为该单位时间的服务不可用。服务不可用时间根据服务端的错误率来计量。 12 | #### 1.4 错误率 13 | 服务返回失败的请求数量与单位时段内总有效请求数量的比值。 14 | #### 1.5 失败请求 15 | 服务内部错误,包括云函数执行结果中的 InvokeResult 值为-1,HTTP 请求状态码5xx。 16 | 17 | ## 2. 服务可用性 18 | #### 2.1 服务可用性计算方式 19 | 服务可用性 =(1 - 服务不可用时间 / 服务月度内总时间)× 100% 20 | #### 2.2 服务可用性标准 21 | **腾讯云提供的本服务可用性不低于99.95%**,如未达到上述可用性标准(属于免责条款情形的除外),您可以根据本协议第3条约定获得赔偿。 22 | 23 | ## 3. 赔偿方案 24 | 对于本服务,如服务可用性低于标准,您有权按照如下条款约定获得赔偿: 25 | #### 3.1 赔偿标准 26 | (1)赔偿以腾讯云**发放代金券**的形式实现,您应当遵守代金券的使用规则(包括使用期限等,具体以腾讯云官网发布的代金券相关规则为准)。发放的代金券不能折现、不开具发票,仅限您通过您的腾讯云账户购买本服务,不能购买其他的腾讯云服务,您也不可以将代金券进行转让、赠予等。 27 | (2)如果某服务月度没有达到服务可用性标准,赔偿额按照相应未达标服务月度单独计算,**赔偿总额不超过相应未达标服务月度内您就本服务支付的相应月度服务费**(此处的月度服务费不含用代金券、优惠券、服务费减免等抵扣的费用)。 28 | 29 | | 服务月度的服务可用性 | 赔偿代金券金额 | 30 | | ------------------------- | ---------------- | 31 | | 低于99.95%但等于或高于99% | 月度服务费的10% | 32 | | 低于99%但等于或高于95% | 月度服务费的25% | 33 | | 低于95% | 月度服务费的100% | 34 | 35 | #### 3.2 赔偿申请时限 36 | (1)如某服务月度没有达到服务可用性标准,您可以在没有达标的相应服务月度结束后的次月的第五(5)个工作日后,**仅通过您相应账户的工单系统提出赔偿申请**。您提出赔偿申请后腾讯云会进行相应核实,对于服务月度的服务可用性的计算,若双方出现争议的,**双方均同意最终以腾讯云的后台记录为准。** 37 | (2)**您最晚提出赔偿申请的时间不应超过未达标的相应服务月度结束后六十(60)个自然日。**如果您在未达标的相应服务月度结束后的六十(60)日内未提出赔偿申请或者在未达标的相应服务月度结束后的六十(60)日之后才提出赔偿申请或者您通过非本协议约定的方式提出申请的,均视为您自动放弃要求赔偿的权利及向腾讯云主张其他权利的权利,腾讯云有权不受理您的赔偿申请,不对您进行任何赔偿或补偿。 38 | 39 | #### 3.3 赔偿申请材料 40 | 如果您认为本服务未达到服务可用性标准的,您可以按照本服务等级协议中规定的时限发起赔偿申请。您的赔偿申请需至少与下列信息一同提供: 41 | (1)声明不可用事件和时间。 42 | (2)受影响的服务。 43 | (3)请求日志有记录服务中断。 44 | 45 | ## 4. 免责条款 46 | **由以下原因导致的服务不可用,相应服务不可用时间不属于服务不可用的计算范畴和腾讯云的赔偿范畴,腾讯云无须向您承担责任:** 47 | 4.1 腾讯云预先通知您后进行系统维护所引起的。 48 | 4.2 任何腾讯云所属设备以外的网络、设备故障或配置调整引起的。 49 | 4.3 您的应用接口或数据受到攻击或其他不当行为引起的。 50 | 4.4 您维护不当或保密不当致使数据、口令、密码等丢失或泄漏所引起的。 51 | 4.5 由于您的疏忽导致的误操作或由您授权的操作所引起的。 52 | 4.6 您未遵循腾讯云产品使用文档或使用建议引起的。 53 | 4.7 非腾讯云原因造成的服务不可用或服务不达标的情况。 54 | 4.8 属于相关法律法规、相关协议、相关规则或腾讯云单独发布的相关规则、说明等中所述的腾讯云可以免责、免除赔偿责任等的情况。 55 | 56 | ## 5. 其他 57 | 5.1 **双方确认并在此认可:在任何情况下,若您在使用本服务过程中因腾讯云违约原因造成您损失的,腾讯云的违约赔偿总额不超过您已经支付的相应违约服务对应的服务费总额。** 58 | 5.2 腾讯云有权根据变化适时或必要时对本协议条款做出修改,您可以在腾讯云官网的最新版本中查阅相关协议条款。如您不同意腾讯云对协议所做的修改,您有权停止使用本服务,如您继续使用本服务,则视为您接受修改后的协议。 59 | 5.3 本协议作为《腾讯云服务协议》的附属协议,具有与《腾讯云服务协议》同等效力,本协议未约定事项,您需遵守《腾讯云服务协议》的相关约定。若本协议与《腾讯云服务协议》中的条款相冲突或不一致,则以本协议为准,但仅在该冲突或不一致范围内适用(完)。 -------------------------------------------------------------------------------- /docs/zh/获取详情.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 查看云端已部署服务的详细信息: 环境,区域,函数列表 4 | 5 | ``` 6 | serverless info 7 | ``` 8 | 9 | 10 | 11 | ## 参数说明 12 | 13 | - `--stage`或 `-s`目标部署环境,如果未指定,则会读取 `serverless.yaml` 里的 `stage` 信息,如果没有,则默认为`dev` 14 | - `--region`或`-r` 目标部署区域,如果未指定,则会读取 `serverless.yaml` 里的 `region` 信息,如果没有,默认为 `ap-guangzhou` 15 | 16 | 17 | 18 | ## 示例 19 | 20 | **注意:函数调用和运行数据生成之间会有一些延时,函数调用之后几秒才能获取对应数据。** 21 | 22 | 23 | 24 | ### 获取默认运行数据 25 | 26 | ``` 27 | serverless metrics 28 | ``` 29 | 30 | 执行上述命令,获取服务最近 24 小时运行数据统计。 31 | 32 | ### 获取指定时段运行数据 33 | 34 | ``` 35 | serverless metrics --startTime 2019-01-01 --endTime 2019-01-02 36 | ``` 37 | 38 | 执行上述命令,获取 2019-01-01 至 2019-01-02 的服务运行数据。 39 | 40 | ### 获取函数运行数据 41 | 42 | ``` 43 | serverless metrics --function hello 44 | ``` 45 | 46 | 执行上述命令,获取最近 24 小时的函数 `hello` 运行数据。 47 | 48 | ### 获取指定时段函数运行数据 49 | 50 | ``` 51 | serverless metrics --function hello --startTime 2019-01-01 --endTime 2019-01-02 52 | ``` 53 | 54 | 执行上述命令,获取 2019-01-01 至 2019-01-02 的函数 `hello` 运行数据。 55 | 56 | -------------------------------------------------------------------------------- /docs/zh/计费模式.md: -------------------------------------------------------------------------------- 1 | 本服务暂时免费。后续将提供更多类型的套餐,并进行收费。 2 | 3 | 当您遇到问题时,请 [联系我们](https://cloud.tencent.com/about/connect) 寻求相应的帮助。 -------------------------------------------------------------------------------- /docs/zh/运行数据统计.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 查看云端函数运行数据。 4 | 5 | ``` 6 | serverless metrics 7 | ``` 8 | 9 | 10 | 11 | ## 参数说明 12 | 13 | - `--function` 或 `-f` 已部署到云函数名。 【必填】 14 | - `--stage`或 `-s`目标部署环境,如果未指定,则会读取 `serverless.yaml` 里的 `stage` 信息,如果没有,则默认为`dev` 15 | - `--region`或`-r` 目标部署区域,如果未指定,则会读取 `serverless.yaml` 里的 `region` 信息,如果没有,默认为 `ap-guangzhou` 16 | 17 | - `--startTime` 函数运行开始时间 ,如`"2019-7-12 00:00:00"` 18 | - `--endTime` 函数运行结束时间 ,如`"2019-7-12 00:10:00"` 19 | 20 | 21 | 22 | ## 示例 23 | 24 | **注意:函数调用和运行数据生成之间会有一些延时,函数调用之后几秒才能获取对应数据。** 25 | 26 | 27 | 28 | ### 获取默认运行数据 29 | 30 | ``` 31 | serverless metrics 32 | ``` 33 | 34 | 执行上述命令,获取服务最近 24 小时运行数据统计。 35 | 36 | ### 获取指定时段运行数据 37 | 38 | ``` 39 | serverless metrics --startTime 2019-01-01 --endTime 2019-01-02 40 | ``` 41 | 42 | 执行上述命令,获取 2019-01-01 至 2019-01-02 的服务运行数据。 43 | 44 | ### 获取函数运行数据 45 | 46 | ``` 47 | serverless metrics --function hello 48 | ``` 49 | 50 | 执行上述命令,获取最近 24 小时的函数 `hello` 运行数据。 51 | 52 | ### 获取指定时段函数运行数据 53 | 54 | ``` 55 | serverless metrics --function hello --startTime 2019-01-01 --endTime 2019-01-02 56 | ``` 57 | 58 | 执行上述命令,获取 2019-01-01 至 2019-01-02 的函数 `hello` 运行数据。 59 | 60 | -------------------------------------------------------------------------------- /docs/zh/部署函数.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 您可以使用`sls deploy function`命令部署您的某个云函数,当您的云函数代码有变更,您想快速上传或者您想更新云函数配置,您可以使用该命令。 4 | 5 | ``` 6 | serverless deploy function -f functionName 7 | ``` 8 | 9 | 10 | 11 | ## 参数说明 12 | 13 | - `--function`或 `-f` 部署函数名 14 | - `--stage`或 `-s`目标部署环境,默认为`dev` 15 | - `--region`或`-r` 目标部署区域,默认为 `ap-guangzhou` 16 | 17 | 18 | 19 | ## 示例 20 | 21 | ### 默认部署 22 | 23 | ``` 24 | serverless deploy function --function helloWorld 25 | ``` 26 | 27 | 执行以上命令,将会部署函数至 stage (dev) 和 region(ap-guangzhou)。 28 | 29 | 30 | 31 | ### 指定区域和环境 32 | 33 | ``` 34 | serverless deploy function --function helloWorld --stage pro --region ap-shanghai 35 | ``` 36 | 37 | 执行以上命令,将会部署至 stage (pro) 和 region(ap-shanghai)。 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/zh/部署列表.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 您可以使用`sls deploy list [function]`命令查询您的部署信息。 4 | 5 | 如果想要查看您 COS bucket 里的部署包信息,您可以执行 `serverless deploy list`; 6 | 7 | 如果您想要查看已经部署的云函数信息,您可以执行`serverless deploy list functions`. 8 | 9 | 这些展示信息在您想要使用回滚功能`serverless rollback`时会用到。 10 | 11 | 12 | 13 | 14 | ## 参数说明 15 | 16 | - `--stage`或 `-s`目标部署环境,默认为`dev` 17 | - `--region`或`-r` 目标部署区域,默认为 `ap-guangzhou` 18 | 19 | 20 | 21 | ## 示例 22 | 23 | ### 部署列表 24 | 25 | ``` 26 | serverless deploy list 27 | ``` 28 | 29 | 30 | 31 | ### 部署函数列表 32 | 33 | ``` 34 | serverless deploy list functions 35 | ``` 36 | 37 | 执行上述命令,您可以获取已部署的函数名和版本信息。 -------------------------------------------------------------------------------- /docs/zh/部署服务.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 您可以使用`sls deploy`命令部署您的整个服务,当您的服务架构有更新时(如,您修改了 serverless.yaml)您可执行该命令。如果您的云函数代码有变更,您想快速上传或者您想更新云函数配置,您可以使用`serverless deploy function -f myFunction` 命令。 4 | 5 | ``` 6 | serverless deploy 7 | ``` 8 | 9 | 10 | 11 | ## 参数说明 12 | 13 | - `--config` 或`-c` 自定义配置文件名(除`serverless.yml.yaml|.js|.json`之外) 14 | - `--stage`或 `-s`目标部署环境,默认为`dev` 15 | - `--region`或`-r` 目标部署区域,默认为 `ap-guangzhou` 16 | - `--package`或`-p` 自定义部署包路径,指定后将跳过打包步骤 17 | - `--force`强制部署,升级情况下,默认升级代码和配置,触发器默认不升级。加了--force参数会进行触发器的升级 18 | - `--function`或 `-f` 执行 `deploy function`(见上方描述),不可以和`--package`共用 19 | 20 | 21 | 22 | ## 说明 23 | 24 | 执行`serverless deploy`后,Serverless Framework 会先执行 `serverless package` 然后进行部署。 25 | 26 | 部署时,会在您的账号下自动生成 [COS bucket](https://console.cloud.tencent.com/cos5/bucket) 并存储部署包。 27 | 28 | ## 示例 29 | 30 | ### 默认部署 31 | 32 | ``` 33 | serverless deploy 34 | ``` 35 | 36 | 执行以上命令,将会部署至 stage (dev) 和 region(ap-guangzhou)。 37 | 38 | 39 | 40 | ### 指定区域和环境 41 | 42 | ``` 43 | serverless deploy --stage pro --region ap-shanghai 44 | ``` 45 | 46 | 执行以上命令,将会部署至 stage (pro) 和 region(ap-shanghai)。 47 | 48 | 49 | 50 | ### 指定部署包 51 | 52 | ``` 53 | serverless deploy --package /path/to/package/directory 54 | ``` 55 | 56 | 执行以上命令,将会跳过打包步骤,使用`/path/to/package/directory` 下的部署包进行部署。 -------------------------------------------------------------------------------- /docs/zh/配置账号.md: -------------------------------------------------------------------------------- 1 | # 微信扫码授权 2 | 3 | 如您的账号未[登陆](https://cloud.tencent.com/login)或[注册](https://cloud.tencent.com/register)腾讯云,您可以在运行`serverless deploy`云端部署命令后,直接用`微信`扫描命令中弹出的二维码,对云账户进行授权登陆和注册。 4 | 5 | 当前Serverless Framework将获取以下权限: 6 | - COS所有操作 7 | - SCF(云函数)全读写权限 8 | - TAG(标签)全读写权限 9 | - CAM(访问管理)查看角色权限 10 | - CAM(访问管理)创建角色权限 11 | - VPC(私有网络)只读权限 12 | - Monitor(云监控)只读权限 13 | 14 | # 账户秘钥配置授权 15 | 16 | 如您希望配置持久的环境变量/秘钥信息,需要按如下步骤前往控制台配置角色授权。 17 | 18 | ## 前提条件 19 | 20 | - 已注册腾讯云账户。若未注册腾讯云账户,可 [点此](https://cloud.tencent.com/register) 进入注册页面。 21 | 22 | - 已登录 [云函数控制台](https://console.cloud.tencent.com/scf)。 23 | 24 | 25 | 26 | ## 配置文件 27 | 28 | - APPID。通过访问控制台中的【账号中心】>【[账号信息](https://console.cloud.tencent.com/developer)】,可以查询到您的账号 ID。 29 | - SecretID 及 SecretKey:指云 API 的密钥 ID 和密钥 Key。您可以通过登录【[访问管理控制台](https://console.cloud.tencent.com/cam/overview)】,选择【云 API 密钥】>【[API 密钥管理](https://console.cloud.tencent.com/cam/capi)】,获取相关密钥或创建相关密钥。 30 | 31 | 新建文件将账号信息写入 : 32 | 33 | ```ini 34 | [default] 35 | tencent_secret_id = secretid 36 | tencent_secret_key = secretkey 37 | ``` 38 | 39 | 如,我们将该文件命名为`credentials` ,并放入 `~`目录。 40 | 41 | 42 | 43 | ## 使用配置 44 | 45 | 如果已经在本地创建了 serverless 示例模板,则打开模板项目里的 `serverless.yml` 文件,引用配置文件: 46 | 47 | ``` 48 | provider: 49 | name: tencent 50 | runtime: python3.6 51 | credentials: ~/credentials 52 | ``` 53 | 54 | 新建示例模板的教程[参考此处]()。 55 | -------------------------------------------------------------------------------- /examples/credentials: -------------------------------------------------------------------------------- 1 | [default] 2 | tencent_appid = appid 3 | tencent_secret_id = secretid 4 | tencent_secret_key = secretkey 5 | -------------------------------------------------------------------------------- /examples/project/index.js: -------------------------------------------------------------------------------- 1 | exports.main_handler = async (event, context, callback) => { 2 | console.log('%j', event) 3 | return 'hello world' 4 | } 5 | -------------------------------------------------------------------------------- /examples/project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-service", 3 | "version": "0.1.0", 4 | "description": "An example of Tencent Cloud Function using Serverless Framework.", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "license": "MIT", 9 | "dependencies": { 10 | "moment": "^2.18.1" 11 | }, 12 | "devDependencies": { 13 | "serverless-tencent-cloudfunction": "*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/project/serverless.yml: -------------------------------------------------------------------------------- 1 | service: my-service 2 | 3 | provider: 4 | name: tencent 5 | credentials: ~/credentials # 绝对地址,默认为 ~/credentials 6 | stage: test # 阶段,默认为 dev 7 | runtime: Nodejs8.9 # 可以指定腾讯云Serverless Cloud Function支持的Runtime, 默认nodejs8.9 8 | cosBucket: DEFAULT # 可以指定,默认为DEFAULT: sls-cloudfunction-{region} 9 | role: QCS_SCFExcuteRole # 可以指定,默认是QCS_SCFExcuteRole 10 | memorySize: 256 # 默认256M,优先级:函数设置>全局设置>默认设置 11 | timeout: 10 # 默认10s,优先级:函数设置>全局设置>默认设置 12 | region: ap-shanghai # 默认sp-guangzhou,优先级:函数设置>全局设置>默认设置 13 | environment: # 公共环境变量 14 | variables: 15 | ENV_FIRST: env1 16 | ENV_SECOND: env2 17 | 18 | plugins: 19 | - serverless-tencent-cloudfunction 20 | 21 | package: 22 | exclude: 23 | - package-lock.json 24 | - .gitignore 25 | - .git/** 26 | - node_modules/** # exclude all node_modules.... 27 | include: 28 | - node_modules/moment/** # except necessary ones 29 | excludeDevDependencies: false 30 | 31 | 32 | functions: 33 | function_one: 34 | handler: index.main_handler 35 | description: Tencent Serverless Cloud Function 36 | runtime: Python3.6 37 | memorySize: 256 38 | timeout: 10 39 | environment: 40 | variables: 41 | ENV_FIRST: env1 42 | ENV_Third: env2 43 | events: 44 | - timer: 45 | name: timer 46 | parameters: 47 | cronExpression: '*/5 * * * *' 48 | enable: true 49 | - cos: 50 | name: cli-appid.cos.ap-beijing.myqcloud.com 51 | parameters: 52 | bucket: cli-appid.cos.ap-beijing.myqcloud.com 53 | filter: 54 | prefix: filterdir/ 55 | suffix: .jpg 56 | events: cos:ObjectCreated:* 57 | enable: true 58 | - apigw: 59 | name: hello_world_apigw 60 | parameters: 61 | stageName: release 62 | serviceId: 63 | httpMethod: ANY 64 | - cmq: 65 | name: cmq_trigger 66 | parameters: 67 | name: test-topic-queue 68 | enable: true 69 | - ckafka: 70 | name: ckafka_trigger 71 | parameters: 72 | name: ckafka-2o10hua5 73 | topic: test 74 | maxMsgNum: 999 75 | offset: latest 76 | enable: true 77 | function_two: 78 | handler: index.main_handler 79 | description: Tencent Serverless Cloud Function 80 | runtime: python3.6 81 | memorySize: 256 82 | timeout: 10 83 | events: 84 | - timer: 85 | name: timer 86 | parameters: 87 | cronExpression: '*/5 * * * *' 88 | enable: true 89 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const TencentProvider = require('./provider/tencentProvider') 2 | const TencentDeploy = require('./deploy/tencentDeploy') 3 | const TencentDeployFunction = require('./deploy/tencentDeployFunction') 4 | const TencentDeployList = require('./deploy/tencentDeployList') 5 | const TencentMetrics = require('./metrics/tencentMetrics') 6 | const TencentRemove = require('./remove/tencentRemove') 7 | const TencentRollback = require('./rollback/tencentRollback') 8 | const TencentInvoke = require('./invoke/tencentInvoke') 9 | const TencentInfo = require('./info/tencentInfo') 10 | const TencentLogs = require('./logs/tencentLogs') 11 | const TencentDeployListFunctions = require('./deploy/tencentDeployListFunctions') 12 | 13 | class TencentIndex { 14 | constructor(serverless, options) { 15 | this.serverless = serverless 16 | this.options = options 17 | 18 | this.serverless.pluginManager.addPlugin(TencentProvider) 19 | this.serverless.pluginManager.addPlugin(TencentDeploy) 20 | this.serverless.pluginManager.addPlugin(TencentDeployFunction) 21 | this.serverless.pluginManager.addPlugin(TencentDeployList) 22 | this.serverless.pluginManager.addPlugin(TencentDeployListFunctions) 23 | this.serverless.pluginManager.addPlugin(TencentMetrics) 24 | this.serverless.pluginManager.addPlugin(TencentRemove) 25 | this.serverless.pluginManager.addPlugin(TencentRollback) 26 | this.serverless.pluginManager.addPlugin(TencentInvoke) 27 | this.serverless.pluginManager.addPlugin(TencentInfo) 28 | this.serverless.pluginManager.addPlugin(TencentLogs) 29 | } 30 | } 31 | 32 | module.exports = TencentIndex 33 | -------------------------------------------------------------------------------- /info/lib/displayServiceInfo.js: -------------------------------------------------------------------------------- 1 | const tencentcloud = require('tencentcloud-sdk-nodejs') 2 | const AbstractHandler = require('../../shared/handler') 3 | const models = tencentcloud.scf.v20180416.Models 4 | const util = require('util') 5 | 6 | class InfoFunction extends AbstractHandler { 7 | async info(service, stage) { 8 | const req = new models.ListFunctionsRequest() 9 | const body = { 10 | Namespace: 'default', 11 | Filters: [ 12 | { 13 | Name: 'tag-Application', 14 | Values: [service] 15 | }, 16 | { 17 | Name: 'tag-Stage', 18 | Values: [stage] 19 | } 20 | ] 21 | } 22 | 23 | req.from_json_string(JSON.stringify(body)) 24 | const handler = util.promisify(this.scfClient.ListFunctions.bind(this.scfClient)) 25 | try { 26 | return await handler(req) 27 | } catch (e) { 28 | this.serverless.cli.log('ErrorCode: ' + e.code + ' RequestId: ' + e.requestId) 29 | throw e 30 | } 31 | } 32 | } 33 | 34 | module.exports = InfoFunction 35 | -------------------------------------------------------------------------------- /info/lib/displayServiceInfo.test.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon') 2 | const Serverless = require('../test/serverless') 3 | const DisplayServiceInfo = require('./displayServiceInfo') 4 | 5 | describe('DisplayServiceInfo@Library', () => { 6 | let displayServiceInfo 7 | let displayServiceInfoStub 8 | 9 | let options 10 | let serverless 11 | 12 | beforeEach(() => { 13 | serverless = new Serverless() 14 | options = { 15 | region: 'ap-guangzhou' 16 | } 17 | displayServiceInfo = new DisplayServiceInfo(options, serverless) 18 | 19 | displayServiceInfoStub = sinon.stub(displayServiceInfo, 'info').returns(Promise.resolve()) 20 | }) 21 | 22 | afterEach(() => { 23 | displayServiceInfo.info.restore() 24 | }) 25 | 26 | it('should make the info function accessible', () => { 27 | displayServiceInfo.should.to.be.an.instanceof(DisplayServiceInfo) 28 | }) 29 | 30 | it('should run library info function', () => 31 | displayServiceInfo.info().then(() => { 32 | displayServiceInfoStub.calledOnce.should.equal(true) 33 | })) 34 | }) 35 | -------------------------------------------------------------------------------- /info/tencentInfo.js: -------------------------------------------------------------------------------- 1 | const BbPromise = require('bluebird') 2 | const _ = require('lodash') 3 | const validate = require('../shared/validate') 4 | const utils = require('../shared/utils') 5 | const tencentProvider = require('../provider/tencentProvider') 6 | const InfoFunction = require('./lib/displayServiceInfo') 7 | 8 | class TencentInfo { 9 | constructor(serverless, options) { 10 | this.serverless = serverless 11 | this.options = options 12 | this.provider = this.serverless.getProvider('tencent') 13 | 14 | Object.assign(this, validate, utils, tencentProvider) 15 | 16 | this.hooks = { 17 | 'before:info:info': () => 18 | BbPromise.bind(this) 19 | .then(this.validate) 20 | .then(this.setDefaults), 21 | 22 | 'info:info': () => BbPromise.bind(this).then(this.info) 23 | } 24 | } 25 | 26 | async info() { 27 | const provider = new tencentProvider(this.serverless, this.options) 28 | this.options = await provider.getUserCred(this.options) 29 | await provider.getUserAuth(this.options.credentials.tencent_owneruin) 30 | try { 31 | const region = this.options.region 32 | const handler = new InfoFunction(this.options, this.serverless) 33 | 34 | var output = 35 | `\n\nService Information\n` + 36 | `service: ${this.serverless.service.service}\n` + 37 | `stage: ${this.options.stage}\n` + 38 | `region: ${region}\n` 39 | 40 | const result = await handler.info(this.serverless.service.service, this.options.stage) 41 | const totalData = result.Functions || [] 42 | output = output + `\nDeployed functions: \n` 43 | const deployedFunction = new Array() 44 | if (totalData.length > 0) { 45 | for (let eveFunctionIndex = 0; eveFunctionIndex < totalData.length; eveFunctionIndex++) { 46 | output = output + ' ' + totalData[eveFunctionIndex].FunctionName + '\n' 47 | deployedFunction.push(totalData[eveFunctionIndex].FunctionName) 48 | } 49 | } else { 50 | output = output + 'There are no functions deployed yet\n' 51 | } 52 | 53 | output = output + '\nUndeployed function: \n' 54 | const functions = Object.keys(this.serverless.service.functions) 55 | if (functions.length > 0) { 56 | for (let eveFunctionIndex = 0; eveFunctionIndex < functions.length; eveFunctionIndex++) { 57 | const functionName = this.provider.getFunctionName(functions[eveFunctionIndex]) 58 | if (deployedFunction.indexOf(functionName) == -1) { 59 | output = output + ' ' + functions[eveFunctionIndex] + '\n' 60 | } 61 | } 62 | } else { 63 | output = output + 'There are no functions undeployed yet\n' 64 | } 65 | 66 | if (this.options.verbose) { 67 | output = output + '\nServerlessDeploymentBucketName: ' + this.provider.getDeployCosBucket() 68 | } 69 | 70 | this.serverless.cli.log(output) 71 | } catch (e) { 72 | this.serverless.cli.log(e) 73 | } 74 | } 75 | } 76 | 77 | module.exports = TencentInfo 78 | -------------------------------------------------------------------------------- /info/tencentInfo.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const Serverless = require('../test/serverless') 6 | const TencentInfo = require('./tencentInfo') 7 | 8 | describe('TencentInfo', () => { 9 | let serverless 10 | let options 11 | let tencentInfo 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentInfo = new TencentInfo(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentInfo.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentInfo.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentInfo.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let tencentInfoStub 55 | 56 | beforeEach(() => { 57 | validateStub = sinon.stub(tencentInfo, 'validate').returns(Promise.resolve()) 58 | setDefaultsStub = sinon.stub(tencentInfo, 'setDefaults').returns(Promise.resolve()) 59 | tencentInfoStub = sinon.stub(tencentInfo, 'info').returns(Promise.resolve()) 60 | }) 61 | 62 | afterEach(() => { 63 | tencentInfo.validate.restore() 64 | tencentInfo.setDefaults.restore() 65 | tencentInfo.info.restore() 66 | }) 67 | 68 | it('should run "before:info:info" promise chain', () => 69 | tencentInfo.hooks['before:info:info']().then(() => { 70 | validateStub.calledOnce.should.equal(true) 71 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 72 | })) 73 | 74 | it('should run "info:info" promise chain', () => 75 | tencentInfo.hooks['info:info']().then(() => { 76 | tencentInfoStub.calledOnce.should.equal(true) 77 | })) 78 | }) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /invoke/lib/invokeFunction.js: -------------------------------------------------------------------------------- 1 | const tencentcloud = require('tencentcloud-sdk-nodejs') 2 | const AbstractHandler = require('../../shared/handler') 3 | const models = tencentcloud.scf.v20180416.Models 4 | const util = require('util') 5 | 6 | class InvokeFunction extends AbstractHandler { 7 | async invoke(ns, funcName, context) { 8 | const req = new models.InvokeRequest() 9 | const body = { 10 | FunctionName: funcName, 11 | LogType: 'Tail', 12 | ClientContext: context, 13 | Namespace: ns 14 | } 15 | req.from_json_string(JSON.stringify(body)) 16 | const handler = util.promisify(this.scfClient.Invoke.bind(this.scfClient)) 17 | try { 18 | return await handler(req) 19 | } catch (e) { 20 | this.serverless.cli.log('ErrorCode: ' + e.code + ' RequestId: ' + e.requestId) 21 | throw e 22 | } 23 | } 24 | } 25 | 26 | module.exports = InvokeFunction 27 | -------------------------------------------------------------------------------- /invoke/lib/invokeFunction.test.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon') 2 | const Serverless = require('../test/serverless') 3 | const InvokeFunction = require('./invokeFunction') 4 | 5 | describe('InvokeFunction@Library', () => { 6 | let invokeFunction 7 | let invokeFunctionStub 8 | 9 | let options 10 | let serverless 11 | 12 | beforeEach(() => { 13 | serverless = new Serverless() 14 | options = { 15 | region: 'ap-guangzhou' 16 | } 17 | invokeFunction = new InvokeFunction(options, serverless) 18 | 19 | invokeFunctionStub = sinon.stub(invokeFunction, 'invoke').returns(Promise.resolve()) 20 | }) 21 | 22 | afterEach(() => { 23 | invokeFunction.invoke.restore() 24 | }) 25 | 26 | it('should make the invoke function accessible', () => { 27 | invokeFunction.should.to.be.an.instanceof(InvokeFunction) 28 | }) 29 | 30 | it('should run library invoke function', () => 31 | invokeFunction.invoke().then(() => { 32 | invokeFunctionStub.calledOnce.should.equal(true) 33 | })) 34 | }) 35 | -------------------------------------------------------------------------------- /invoke/tencentInvoke.js: -------------------------------------------------------------------------------- 1 | const BbPromise = require('bluebird') 2 | const fs = require('fs') 3 | const validate = require('../shared/validate') 4 | const utils = require('../shared/utils') 5 | const tencentProvider = require('../provider/tencentProvider') 6 | const Invoke = require('./lib/invokeFunction') 7 | 8 | class TencentInvoke { 9 | constructor(serverless, options) { 10 | this.serverless = serverless 11 | this.options = options 12 | this.provider = this.serverless.getProvider('tencent') 13 | 14 | Object.assign(this, validate, utils, tencentProvider) 15 | 16 | this.hooks = { 17 | 'before:invoke:invoke': () => 18 | BbPromise.bind(this) 19 | .then(this.validate) 20 | .then(this.setDefaults), 21 | 'invoke:invoke': () => BbPromise.bind(this).then(this.invoke) 22 | } 23 | } 24 | 25 | async invoke() { 26 | const provider = new tencentProvider(this.serverless, this.options) 27 | this.options = await provider.getUserCred(this.options) 28 | await provider.getUserAuth(this.options.credentials.tencent_owneruin) 29 | try { 30 | const invokeHandler = new Invoke(this.options, this.serverless) 31 | let context = null 32 | if (this.options.data) { 33 | context = this.options.data 34 | } else if (this.options.path) { 35 | context = fs.readFileSync(this.options.path, 'utf-8') 36 | } 37 | const result = await invokeHandler.invoke( 38 | 'default', 39 | this.provider.getFunctionName(this.options.function), 40 | context 41 | ) 42 | // this.serverless.cli.log(JSON.stringify(result.Result)); 43 | const outputStr = 44 | '\n\n' + result.Result.RetMsg + '\n\n----------\nLog: \n' + result.Result.Log 45 | this.serverless.cli.log(outputStr) 46 | } catch (e) { 47 | this.serverless.cli.log(e) 48 | } 49 | } 50 | } 51 | 52 | module.exports = TencentInvoke 53 | -------------------------------------------------------------------------------- /invoke/tencentInvoke.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const TencentInvoke = require('./tencentInvoke') 6 | const Serverless = require('../test/serverless') 7 | 8 | describe('TencentInvoke', () => { 9 | let serverless 10 | let options 11 | let tencentInvoke 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentInvoke = new TencentInvoke(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentInvoke.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentInvoke.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentInvoke.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let invokeFunctionStub 55 | 56 | beforeEach(() => { 57 | validateStub = sinon.stub(tencentInvoke, 'validate').returns(Promise.resolve()) 58 | setDefaultsStub = sinon.stub(tencentInvoke, 'setDefaults').returns(Promise.resolve()) 59 | invokeFunctionStub = sinon.stub(tencentInvoke, 'invoke').returns(Promise.resolve()) 60 | }) 61 | 62 | afterEach(() => { 63 | tencentInvoke.validate.restore() 64 | tencentInvoke.setDefaults.restore() 65 | tencentInvoke.invoke.restore() 66 | }) 67 | 68 | it('should run "before:invoke:invoke" promise chain', () => 69 | tencentInvoke.hooks['before:invoke:invoke']().then(() => { 70 | validateStub.calledOnce.should.equal(true) 71 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 72 | })) 73 | 74 | it('should run "invoke:invoke" promise chain', () => 75 | tencentInvoke.hooks['invoke:invoke']().then(() => { 76 | invokeFunctionStub.calledOnce.should.equal(true) 77 | })) 78 | }) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /logs/lib/retrieveLogs.js: -------------------------------------------------------------------------------- 1 | const tencentcloud = require('tencentcloud-sdk-nodejs') 2 | const AbstractHandler = require('../../shared/handler') 3 | const models = tencentcloud.scf.v20180416.Models 4 | const util = require('util') 5 | 6 | class LogsFunction extends AbstractHandler { 7 | async logs(funcName, startTime, endTime, filter) { 8 | const req = new models.GetFunctionLogsRequest() 9 | const body = { 10 | FunctionName: funcName, 11 | StartTime: startTime, 12 | EndTime: endTime, 13 | Namespace: 'default', 14 | Filter: filter, 15 | Offset: 0, 16 | Limit: 10000, 17 | Qualifier: '$LATEST' 18 | } 19 | req.from_json_string(JSON.stringify(body)) 20 | const handler = util.promisify(this.scfClient.GetFunctionLogs.bind(this.scfClient)) 21 | try { 22 | return await handler(req) 23 | } catch (e) { 24 | this.serverless.cli.log('ErrorCode: ' + e.code + ' RequestId: ' + e.requestId) 25 | throw e 26 | } 27 | } 28 | } 29 | 30 | module.exports = LogsFunction 31 | -------------------------------------------------------------------------------- /logs/lib/retrieveLogs.test.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon') 2 | const Serverless = require('../test/serverless') 3 | const RetrieveLogs = require('./retrieveLogs') 4 | 5 | describe('RetrieveLogs@Library', () => { 6 | let retrieveLogs 7 | let retrieveLogsStub 8 | 9 | let options 10 | let serverless 11 | 12 | beforeEach(() => { 13 | serverless = new Serverless() 14 | options = { 15 | region: 'ap-guangzhou' 16 | } 17 | retrieveLogs = new RetrieveLogs(options, serverless) 18 | 19 | retrieveLogsStub = sinon.stub(retrieveLogs, 'logs').returns(Promise.resolve()) 20 | }) 21 | 22 | afterEach(() => { 23 | retrieveLogs.logs.restore() 24 | }) 25 | 26 | it('should make the logs function accessible', () => { 27 | retrieveLogs.should.to.be.an.instanceof(RetrieveLogs) 28 | }) 29 | 30 | it('should run library logs function', () => 31 | retrieveLogs.logs().then(() => { 32 | retrieveLogsStub.calledOnce.should.equal(true) 33 | })) 34 | }) 35 | -------------------------------------------------------------------------------- /logs/tencentLogs.js: -------------------------------------------------------------------------------- 1 | const BbPromise = require('bluebird') 2 | const _ = require('lodash') 3 | const validate = require('../shared/validate') 4 | const utils = require('../shared/utils') 5 | const tencentProvider = require('../provider/tencentProvider') 6 | const LogsFunction = require('./lib/retrieveLogs') 7 | 8 | class TencentLogs { 9 | constructor(serverless, options) { 10 | this.serverless = serverless 11 | this.options = options 12 | this.provider = this.serverless.getProvider('tencent') 13 | 14 | Object.assign(this, validate, utils, tencentProvider, LogsFunction) 15 | 16 | this.hooks = { 17 | 'before:logs:logs': () => 18 | BbPromise.bind(this) 19 | .then(this.validate) 20 | .then(this.setDefaults), 21 | 22 | 'logs:logs': () => BbPromise.bind(this).then(this.logs) 23 | } 24 | } 25 | 26 | getTimeFunction(fmt, difTime) { 27 | var currentTime = new Date(new Date().getTime() - difTime) 28 | var o = { 29 | 'M+': currentTime.getMonth() + 1, 30 | 'd+': currentTime.getDate(), 31 | 'h+': currentTime.getHours(), 32 | 'm+': currentTime.getMinutes(), 33 | 's+': currentTime.getSeconds(), 34 | 'q+': Math.floor((currentTime.getMonth() + 3) / 3), 35 | S: currentTime.getMilliseconds() 36 | } 37 | if (/(y+)/.test(fmt)) { 38 | fmt = fmt.replace(RegExp.$1, (currentTime.getFullYear() + '').substr(4 - RegExp.$1.length)) 39 | } 40 | for (var k in o) { 41 | if (new RegExp('(' + k + ')').test(fmt)) { 42 | fmt = fmt.replace( 43 | RegExp.$1, 44 | RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length) 45 | ) 46 | } 47 | } 48 | return fmt 49 | } 50 | 51 | async logs() { 52 | const provider = new tencentProvider(this.serverless, this.options) 53 | this.options = await provider.getUserCred(this.options) 54 | await provider.getUserAuth(this.options.credentials.tencent_owneruin) 55 | try { 56 | const timeFormat = 'yyyy-MM-dd hh:mm:ss' 57 | this.serverless.cli.log(`Get function logs...`) 58 | const functionName = this.provider.getFunctionName(this.options.function) 59 | const interval = this.options.interval || 1000 60 | if (this.options.tail) { 61 | const logsList = new Array() 62 | const startTime = this.options.startTime || this.getTimeFunction(timeFormat, interval) 63 | for (let times = 0; times < 100000; times++) { 64 | await utils.sleep(interval) 65 | const handler = new LogsFunction(this.options, this.serverless) 66 | const endTime = this.getTimeFunction('yyyy-MM-dd hh:mm:ss', 0) 67 | const result = await handler.logs( 68 | functionName, 69 | startTime, 70 | endTime, 71 | this.options.filter || {} 72 | ) 73 | const totalData = result.Data || [] 74 | for (var eveLogIndex = 0; eveLogIndex < totalData.length; eveLogIndex++) { 75 | if (logsList.indexOf(totalData[eveLogIndex]['RequestId']) == -1) { 76 | logsList.push(totalData[eveLogIndex]['RequestId']) 77 | const outputStr = 78 | '\nStartTime: ' + 79 | totalData[eveLogIndex].StartTime + 80 | '\nRetMsg: ' + 81 | totalData[eveLogIndex].RetMsg + 82 | '\nRequestId: ' + 83 | totalData[eveLogIndex].RequestId + 84 | '\n\nDuration: ' + 85 | totalData[eveLogIndex].Duration + 86 | '\nBillDuration: ' + 87 | totalData[eveLogIndex].BillDuration + 88 | '\nMemUsage: ' + 89 | totalData[eveLogIndex].MemUsage + 90 | '\n\nLog: ' + 91 | totalData[eveLogIndex].Log + 92 | '\n\n' 93 | this.serverless.cli.log(outputStr) 94 | } 95 | } 96 | } 97 | } else { 98 | const handler = new LogsFunction(this.options, this.serverless) 99 | const result = await handler.logs( 100 | functionName, 101 | this.options.startTime || this.getTimeFunction(timeFormat, 1 * 60 * 60 * 1000), 102 | this.getTimeFunction(timeFormat, 0), 103 | this.options.filter || {} 104 | ) 105 | const totalData = result.Data || [] 106 | for (let eveLogIndex = 0; eveLogIndex < totalData.length; eveLogIndex++) { 107 | this.serverless.cli.log(JSON.stringify(totalData[eveLogIndex], null, 2)) 108 | } 109 | } 110 | } catch (e) { 111 | this.serverless.cli.log(e) 112 | } 113 | } 114 | } 115 | 116 | module.exports = TencentLogs 117 | -------------------------------------------------------------------------------- /logs/tencentLogs.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const TencentLogs = require('./tencentLogs') 6 | const Serverless = require('../test/serverless') 7 | 8 | describe('TencentLogs', () => { 9 | let serverless 10 | let options 11 | let tencentLogs 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentLogs = new TencentLogs(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentLogs.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentLogs.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentLogs.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let logsStub 55 | 56 | beforeEach(() => { 57 | validateStub = sinon.stub(tencentLogs, 'validate').returns(Promise.resolve()) 58 | setDefaultsStub = sinon.stub(tencentLogs, 'setDefaults').returns(Promise.resolve()) 59 | logsStub = sinon.stub(tencentLogs, 'logs').returns(Promise.resolve()) 60 | }) 61 | 62 | afterEach(() => { 63 | tencentLogs.validate.restore() 64 | tencentLogs.setDefaults.restore() 65 | tencentLogs.logs.restore() 66 | }) 67 | 68 | it('should run "before:logs:logs" promise chain', () => 69 | tencentLogs.hooks['before:logs:logs']().then(() => { 70 | validateStub.calledOnce.should.equal(true) 71 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 72 | })) 73 | 74 | it('should run "logs:logs" promise chain', () => 75 | tencentLogs.hooks['logs:logs']().then(() => { 76 | logsStub.calledOnce.should.equal(true) 77 | })) 78 | }) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /metrics/lib/displayMetrics.js: -------------------------------------------------------------------------------- 1 | const tencentcloud = require('tencentcloud-sdk-nodejs') 2 | const AbstractHandler = require('../../shared/handler') 3 | const scf_models = tencentcloud.scf.v20180416.Models 4 | const monitor_models = tencentcloud.monitor.v20180724.Models 5 | const util = require('util') 6 | 7 | class MetricsFunction extends AbstractHandler { 8 | async functionList(service, stage) { 9 | const req = new scf_models.ListFunctionsRequest() 10 | const body = { 11 | Namespace: 'default', 12 | Filters: [ 13 | { 14 | Name: 'tag-Application', 15 | Values: [service] 16 | }, 17 | { 18 | Name: 'tag-Stage', 19 | Values: [stage] 20 | } 21 | ] 22 | } 23 | req.from_json_string(JSON.stringify(body)) 24 | const handler = util.promisify(this.scfClient.ListFunctions.bind(this.scfClient)) 25 | try { 26 | return await handler(req) 27 | } catch (e) { 28 | this.serverless.cli.log('ErrorCode: ' + e.code + ' RequestId: ' + e.requestId) 29 | throw e 30 | } 31 | } 32 | 33 | async getMonitor(functionName, metricName, startTime, endTime) { 34 | const req = new monitor_models.GetMonitorDataRequest() 35 | const body = { 36 | Namespace: 'QCE/SCF_V2', 37 | MetricName: metricName, 38 | StartTime: startTime, 39 | EndTime: endTime, 40 | Instances: [ 41 | { 42 | Dimensions: [ 43 | { 44 | Name: 'functionName', 45 | Value: functionName 46 | }, 47 | { 48 | Name: 'namespace', 49 | Value: 'default' 50 | }, 51 | { 52 | Name: 'version', 53 | Value: '$LATEST' 54 | } 55 | ] 56 | } 57 | ] 58 | } 59 | req.from_json_string(JSON.stringify(body)) 60 | const handler = util.promisify(this.monitorClient.GetMonitorData.bind(this.monitorClient)) 61 | try { 62 | return await handler(req) 63 | } catch (e) { 64 | this.serverless.cli.log('ErrorCode: ' + e.code + ' RequestId: ' + e.requestId) 65 | throw e 66 | } 67 | } 68 | } 69 | 70 | module.exports = MetricsFunction 71 | -------------------------------------------------------------------------------- /metrics/lib/displayMetrics.test.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon') 2 | const Serverless = require('../test/serverless') 3 | const DisplayMetrics = require('./displayMetrics') 4 | 5 | describe('DisplayMetrics@Library', () => { 6 | let displayMetrics 7 | let funcListStub 8 | let getMonitorStub 9 | 10 | let options 11 | let serverless 12 | 13 | beforeEach(() => { 14 | serverless = new Serverless() 15 | options = { 16 | region: 'ap-guangzhou' 17 | } 18 | displayMetrics = new DisplayMetrics(options, serverless) 19 | 20 | funcListStub = sinon.stub(displayMetrics, 'functionList').returns(Promise.resolve()) 21 | getMonitorStub = sinon.stub(displayMetrics, 'getMonitor').returns(Promise.resolve()) 22 | }) 23 | 24 | afterEach(() => { 25 | displayMetrics.functionList.restore() 26 | }) 27 | 28 | it('should make the function list accessible', () => { 29 | displayMetrics.should.to.be.an.instanceof(DisplayMetrics) 30 | }) 31 | 32 | it('should run library function list function', () => 33 | displayMetrics.functionList().then(() => { 34 | funcListStub.calledOnce.should.equal(true) 35 | })) 36 | 37 | it('should run library get monitor function', () => 38 | displayMetrics.getMonitor().then(() => { 39 | getMonitorStub.calledOnce.should.equal(true) 40 | })) 41 | }) 42 | -------------------------------------------------------------------------------- /metrics/tencentMetrics.js: -------------------------------------------------------------------------------- 1 | const BbPromise = require('bluebird') 2 | const _ = require('lodash') 3 | const validate = require('../shared/validate') 4 | const utils = require('../shared/utils') 5 | const tencentProvider = require('../provider/tencentProvider') 6 | const MetricsFunction = require('./lib/displayMetrics') 7 | 8 | class TencentInfo { 9 | constructor(serverless, options) { 10 | this.serverless = serverless 11 | this.options = options 12 | this.provider = this.serverless.getProvider('tencent') 13 | 14 | Object.assign(this, validate, utils, tencentProvider) 15 | 16 | this.hooks = { 17 | 'before:metrics:metrics': () => 18 | BbPromise.bind(this) 19 | .then(this.validate) 20 | .then(this.setDefaults), 21 | 22 | 'metrics:metrics': () => BbPromise.bind(this).then(this.metrics) 23 | } 24 | } 25 | 26 | frontOneHour(fmt, difTime) { 27 | var currentTime = new Date(new Date().getTime() - difTime) 28 | var o = { 29 | 'M+': currentTime.getMonth() + 1, // 月份 30 | 'd+': currentTime.getDate(), // 日 31 | 'h+': currentTime.getHours(), // 小时 32 | 'm+': currentTime.getMinutes(), // 分 33 | 's+': currentTime.getSeconds(), // 秒 34 | 'q+': Math.floor((currentTime.getMonth() + 3) / 3), // 季度 35 | S: currentTime.getMilliseconds() // 毫秒 36 | } 37 | if (/(y+)/.test(fmt)) { 38 | fmt = fmt.replace(RegExp.$1, (currentTime.getFullYear() + '').substr(4 - RegExp.$1.length)) 39 | } 40 | for (var k in o) { 41 | if (new RegExp('(' + k + ')').test(fmt)) { 42 | fmt = fmt.replace( 43 | RegExp.$1, 44 | RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length) 45 | ) 46 | } 47 | } 48 | return fmt 49 | } 50 | 51 | getSum(arrayData) { 52 | let sum = 0 53 | for (let i = 0; i < arrayData.length; i++) { 54 | sum += arrayData[i] 55 | } 56 | return sum 57 | } 58 | 59 | async metrics() { 60 | const provider = new tencentProvider(this.serverless, this.options) 61 | this.options = await provider.getUserCred(this.options) 62 | await provider.getUserAuth(this.options.credentials.tencent_owneruin) 63 | try { 64 | const Handler = new MetricsFunction(this.options, this.serverless) 65 | const functionList = await Handler.functionList( 66 | this.serverless.service.service, 67 | this.options.stage 68 | ) 69 | const functionListData = functionList.Functions || [] 70 | const timeFormat = 'yyyy-MM-dd hh:mm:ss' 71 | 72 | const startTime = this.options.startTime || this.frontOneHour(timeFormat, 24 * 60 * 60 * 1000) 73 | const endTime = this.options.endTime || this.frontOneHour(timeFormat, 0) 74 | const functionInformation = {} 75 | let output = 'Service wide metrics\n' + startTime + ' - ' + endTime + '\n' 76 | if (functionListData.length > 0) { 77 | for ( 78 | let eveFunctionIndex = 0; 79 | eveFunctionIndex < functionListData.length; 80 | eveFunctionIndex++ 81 | ) { 82 | const functionInvocation = await Handler.getMonitor( 83 | functionListData[eveFunctionIndex].FunctionName, 84 | 'Invocation', 85 | startTime, 86 | endTime 87 | ) 88 | const functionError = await Handler.getMonitor( 89 | functionListData[eveFunctionIndex].FunctionName, 90 | 'Error', 91 | startTime, 92 | endTime 93 | ) 94 | const functionOutFlow = await Handler.getMonitor( 95 | functionListData[eveFunctionIndex].FunctionName, 96 | 'OutFlow', 97 | startTime, 98 | endTime 99 | ) 100 | const functionDuration = await Handler.getMonitor( 101 | functionListData[eveFunctionIndex].FunctionName, 102 | 'Duration', 103 | startTime, 104 | endTime 105 | ) 106 | const duration = 107 | this.getSum(functionDuration.DataPoints[0].Values) / 108 | this.getSum(functionInvocation.DataPoints[0].Values) 109 | functionInformation[functionListData[eveFunctionIndex].FunctionName] = { 110 | Invocation: this.getSum(functionInvocation.DataPoints[0].Values), 111 | Error: this.getSum(functionError.DataPoints[0].Values), 112 | OutFlow: this.getSum(functionOutFlow.DataPoints[0].Values), 113 | Duration: duration ? duration : 0 114 | } 115 | } 116 | let serviceInvocation = 0 117 | let serviceError = 0 118 | let serviceOutFlow = 0 119 | let serviceDuration = 0 120 | let functionStr = '' 121 | for (const key in functionInformation) { 122 | serviceInvocation = serviceInvocation + functionInformation[key]['Invocation'] 123 | serviceError = serviceError + functionInformation[key]['Error'] 124 | serviceOutFlow = serviceOutFlow + functionInformation[key]['OutFlow'] 125 | serviceDuration = serviceDuration + functionInformation[key]['Duration'] 126 | functionStr = 127 | functionStr + 128 | ' ' + 129 | key + 130 | ': ' + 131 | '\n Invocations: ' + 132 | functionInformation[key]['Invocation'] + 133 | '\n' + 134 | ' Outflows: ' + 135 | functionInformation[key]['OutFlow'] + 136 | '\n' + 137 | ' Errors: ' + 138 | functionInformation[key]['Error'] + 139 | '\n' + 140 | ' Duration(avg.): ' + 141 | functionInformation[key]['Duration'] + 142 | ' ms\n\n' 143 | } 144 | output = 145 | output + 146 | '\nService:\n Invocations: ' + 147 | serviceInvocation + 148 | '\n' + 149 | ' Outflows: ' + 150 | serviceOutFlow + 151 | '\n' + 152 | ' Errors: ' + 153 | serviceError + 154 | '\n' + 155 | ' Duration(avg.): ' + 156 | serviceDuration + 157 | ' ms\n\nFunctions: \n' + 158 | functionStr 159 | } else { 160 | ;('There are no functions undeployed yet\n') 161 | } 162 | this.serverless.cli.log(output) 163 | } catch (e) { 164 | this.serverless.cli.log(e) 165 | } 166 | } 167 | } 168 | 169 | module.exports = TencentInfo 170 | -------------------------------------------------------------------------------- /metrics/tencentMetrics.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const Serverless = require('../test/serverless') 6 | const TencentMetrics = require('./tencentMetrics') 7 | 8 | describe('TencentMetrics', () => { 9 | let serverless 10 | let options 11 | let tencentMetrics 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentMetrics = new TencentMetrics(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentMetrics.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentMetrics.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentMetrics.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let tencentMetricsStub 55 | 56 | beforeEach(() => { 57 | validateStub = sinon.stub(tencentMetrics, 'validate').returns(Promise.resolve()) 58 | setDefaultsStub = sinon.stub(tencentMetrics, 'setDefaults').returns(Promise.resolve()) 59 | tencentMetricsStub = sinon.stub(tencentMetrics, 'metrics').returns(Promise.resolve()) 60 | }) 61 | 62 | afterEach(() => { 63 | tencentMetrics.validate.restore() 64 | tencentMetrics.setDefaults.restore() 65 | tencentMetrics.metrics.restore() 66 | }) 67 | 68 | it('should run "before:metrics:metrics" promise chain', () => 69 | tencentMetrics.hooks['before:metrics:metrics']().then(() => { 70 | validateStub.calledOnce.should.equal(true) 71 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 72 | })) 73 | 74 | it('should run "metrics:metrics" promise chain', () => 75 | tencentMetrics.hooks['metrics:metrics']().then(() => { 76 | tencentMetricsStub.calledOnce.should.equal(true) 77 | })) 78 | }) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-tencent-scf", 3 | "version": "0.1.37", 4 | "description": "Provider plugin for the Serverless Framework v1.x which adds support for Tencent Cloud Functions.", 5 | "main": "index.js", 6 | "author": "Tencent Cloud, Inc.", 7 | "license": "MIT", 8 | "repository": { 9 | "git": "https://github.com/serverless-tencent/serverless-tencent-scf" 10 | }, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1", 13 | "lint": "eslint . --fix --cache", 14 | "coverage": "jest --coverage" 15 | }, 16 | "homepage": "https://github.com/serverless-tencent/serverless-tencent-scf", 17 | "keywords": [ 18 | "serverless", 19 | "serverless framework", 20 | "serverless applications", 21 | "serverless modules", 22 | "tencent cloud functions", 23 | "iot", 24 | "internet of things", 25 | "serverless.com" 26 | ], 27 | "dependencies": { 28 | "assert": "^2.0.0", 29 | "async": "^2.6.3", 30 | "bluebird": "^3.5.5", 31 | "chai": "^4.2.0", 32 | "chalk": "^2.4.2", 33 | "ci-info": "^2.0.0", 34 | "co": "^4.6.0", 35 | "conf": "^6.0.1", 36 | "cos-nodejs-sdk-v5": "^2.5.12", 37 | "detect-mocha": "^0.1.0", 38 | "filesize": "^5.0.3", 39 | "fs-extra": "^8.1.0", 40 | "ini": "^1.3.4", 41 | "lodash": "^4.17.15", 42 | "mocha": "^6.2.2", 43 | "request": "^2.88.0", 44 | "tencentcloud-sdk-nodejs": "^3.0.87", 45 | "universal-analytics": "^0.4.20", 46 | "tencent-login": "^0.1.6", 47 | "serverless-tencent-tools": "^0.0.11", 48 | "serverless-tencent-auth-tool": "^1.0.18" 49 | }, 50 | "devDependencies": { 51 | "coveralls": "^3.0.5", 52 | "eslint": "^4.19.1", 53 | "eslint-config-airbnb-base": "^11.3.2", 54 | "eslint-plugin-import": "^2.18.1", 55 | "jest": "^24.8.0", 56 | "sinon": "^7.5.0", 57 | "babel-eslint": "9.0.0", 58 | "eslint-config-prettier": "^3.6.0", 59 | "eslint-plugin-prettier": "^3.0.1", 60 | "prettier": "^1.18.2" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'always', 3 | printWidth: 100, 4 | semi: false, 5 | singleQuote: true, 6 | tabWidth: 2, 7 | trailingComma: 'none' 8 | } 9 | -------------------------------------------------------------------------------- /provider/tencentProvider.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('./tencentProvider') 5 | const Serverless = require('../test/serverless') 6 | 7 | describe('TencentProvider@Public', () => { 8 | let readFileSyncStub 9 | let tencentProvider 10 | let serverless 11 | let setProviderStub 12 | let homedirStub 13 | let getFunctionResourceStub 14 | let getServiceResourceStub 15 | let getEnvironmentStub 16 | let getVPCConfigStub 17 | let getCredentialsStub 18 | let getTimerEventStub 19 | let getCOSEventStub 20 | let getAPIGWEventStub 21 | let getCMQEventStub 22 | let getCkafkaEventStub 23 | let getDeployCosBucketStub 24 | 25 | beforeEach(() => { 26 | serverless = new Serverless() 27 | serverless.version = '1.0.0' 28 | setProviderStub = sinon.stub(serverless, 'setProvider').returns() 29 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 30 | tencent_secret_key = PYR4a0HSZ******eVvHRe 31 | tencent_secret_id = AKIDoM*****mxsfOirI 32 | tencent_appid = 12561*****`) 33 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 34 | 35 | const options = { 36 | stage: 'dev', 37 | region: 'ap-guangzhou', 38 | function: 'test' 39 | } 40 | tencentProvider = new TencentProvider(serverless, options) 41 | getFunctionResourceStub = sinon.stub(tencentProvider, 'getFunctionResource').returns(true) 42 | getServiceResourceStub = sinon.stub(tencentProvider, 'getServiceResource').returns(true) 43 | getEnvironmentStub = sinon.stub(tencentProvider, 'getEnvironment').returns(true) 44 | getVPCConfigStub = sinon.stub(tencentProvider, 'getVPCConfig').returns(true) 45 | getCredentialsStub = sinon.stub(tencentProvider, 'getCredentials').returns(true) 46 | getTimerEventStub = sinon.stub(tencentProvider, 'getTimerEvent').returns(true) 47 | getCOSEventStub = sinon.stub(tencentProvider, 'getCOSEvent').returns(true) 48 | getAPIGWEventStub = sinon.stub(tencentProvider, 'getAPIGWEvent').returns(true) 49 | getCMQEventStub = sinon.stub(tencentProvider, 'getCMQEvent').returns(true) 50 | getCkafkaEventStub = sinon.stub(tencentProvider, 'getCkafkaEvent').returns(true) 51 | getDeployCosBucketStub = sinon.stub(tencentProvider, 'getDeployCosBucket').returns(true) 52 | }) 53 | 54 | afterEach(() => { 55 | tencentProvider.getFunctionResource.restore() 56 | tencentProvider.getServiceResource.restore() 57 | tencentProvider.getEnvironment.restore() 58 | tencentProvider.getVPCConfig.restore() 59 | tencentProvider.getCredentials.restore() 60 | tencentProvider.getTimerEvent.restore() 61 | tencentProvider.getCOSEvent.restore() 62 | tencentProvider.getAPIGWEvent.restore() 63 | tencentProvider.getCMQEvent.restore() 64 | tencentProvider.getCkafkaEvent.restore() 65 | tencentProvider.getDeployCosBucket.restore() 66 | serverless.setProvider.restore() 67 | fs.readFileSync.restore() 68 | os.homedir.restore() 69 | }) 70 | 71 | describe('#getProviderName()', () => { 72 | it('should return the provider name', () => { 73 | TencentProvider.getProviderName().should.equal('tencent') 74 | }) 75 | }) 76 | 77 | describe('#constructor()', () => { 78 | it('should store an instance of serverless', () => { 79 | tencentProvider.serverless.should.to.be.an.instanceof(Serverless) 80 | }) 81 | 82 | it('should store an instance of itself', () => { 83 | tencentProvider.provider.should.to.be.an.instanceof(TencentProvider) 84 | }) 85 | 86 | it('should set the provider with the Serverless instance', () => { 87 | setProviderStub.calledOnce.should.equal(true) 88 | }) 89 | }) 90 | 91 | describe('public function', () => { 92 | it('should return a new function resource getFunctionResource()', () => { 93 | tencentProvider.getFunctionResource().should.equal(true) 94 | }) 95 | 96 | it('should return a new service resource getServiceResource()', () => { 97 | tencentProvider.getServiceResource().should.equal(true) 98 | }) 99 | it('should return a function name "test-service-dev-hello"', () => { 100 | tencentProvider.getFunctionName('hello').should.equal('test-service-dev-hello') 101 | }) 102 | it('should return a stage name "dev"', () => { 103 | tencentProvider.getStage().should.equal('dev') 104 | }) 105 | it('should return a region name "ap-guangzhou"', () => { 106 | tencentProvider.getRegion().should.equal('ap-guangzhou') 107 | }) 108 | it('should return a function configure environment', () => { 109 | tencentProvider.getEnvironment().should.equal(true) 110 | }) 111 | it('should return a function vpc configure', () => { 112 | tencentProvider.getVPCConfig().should.equal(true) 113 | }) 114 | it('should return a function credentials configure', () => { 115 | tencentProvider.getCredentials().should.equal(true) 116 | }) 117 | it('should return a function timer trigger', () => { 118 | tencentProvider.getTimerEvent().should.equal(true) 119 | }) 120 | it('should return a function cos trigger', () => { 121 | tencentProvider.getCOSEvent().should.equal(true) 122 | }) 123 | it('should return a function apigw trigger', () => { 124 | tencentProvider.getAPIGWEvent().should.equal(true) 125 | }) 126 | it('should return a function cmq trigger', () => { 127 | tencentProvider.getCMQEvent().should.equal(true) 128 | }) 129 | it('should return a function ckafka trigger', () => { 130 | tencentProvider.getCkafkaEvent().should.equal(true) 131 | }) 132 | it('should return a function cos bucket name', () => { 133 | tencentProvider.getDeployCosBucket().should.equal(true) 134 | }) 135 | }) 136 | }) 137 | -------------------------------------------------------------------------------- /remove/lib/removeFunction.js: -------------------------------------------------------------------------------- 1 | const tencentcloud = require('tencentcloud-sdk-nodejs') 2 | const AbstractHandler = require('../../shared/handler') 3 | const models = tencentcloud.scf.v20180416.Models 4 | const util = require('util') 5 | 6 | class RemoveFunction extends AbstractHandler { 7 | async remove(funcName) { 8 | const req = new models.DeleteFunctionRequest() 9 | const body = { 10 | FunctionName: funcName 11 | } 12 | req.from_json_string(JSON.stringify(body)) 13 | const handler = util.promisify(this.scfClient.DeleteFunction.bind(this.scfClient)) 14 | try { 15 | return await handler(req) 16 | } catch (e) { 17 | this.serverless.cli.log('ErrorCode: ' + e.code + ' RequestId: ' + e.requestId) 18 | throw e 19 | } 20 | } 21 | } 22 | 23 | module.exports = RemoveFunction 24 | -------------------------------------------------------------------------------- /remove/lib/removeFunction.test.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon') 2 | const Serverless = require('../test/serverless') 3 | const RemoveFunction = require('./removeFunction') 4 | 5 | describe('RemoveFunction@Library', () => { 6 | let removeFunction 7 | let removeFunctionStub 8 | 9 | let options 10 | let serverless 11 | 12 | beforeEach(() => { 13 | serverless = new Serverless() 14 | options = { 15 | region: 'ap-guangzhou' 16 | } 17 | removeFunction = new RemoveFunction(options, serverless) 18 | 19 | removeFunctionStub = sinon.stub(removeFunction, 'remove').returns(Promise.resolve()) 20 | }) 21 | 22 | afterEach(() => { 23 | removeFunction.remove.restore() 24 | }) 25 | 26 | it('should make the remove function accessible', () => { 27 | removeFunction.should.to.be.an.instanceof(RemoveFunction) 28 | }) 29 | 30 | it('should run library remove function', () => 31 | removeFunction.remove().then(() => { 32 | removeFunctionStub.calledOnce.should.equal(true) 33 | })) 34 | }) 35 | -------------------------------------------------------------------------------- /remove/tencentRemove.js: -------------------------------------------------------------------------------- 1 | const BbPromise = require('bluebird') 2 | const _ = require('lodash') 3 | const validate = require('../shared/validate') 4 | const utils = require('../shared/utils') 5 | const tencentProvider = require('../provider/tencentProvider') 6 | const RemoveFunction = require('./lib/removeFunction') 7 | 8 | class TencentRemove { 9 | constructor(serverless, options) { 10 | this.serverless = serverless 11 | this.options = options 12 | this.provider = this.serverless.getProvider('tencent') 13 | 14 | Object.assign(this, validate, utils, tencentProvider) 15 | 16 | this.hooks = { 17 | 'before:remove:remove': () => 18 | BbPromise.bind(this) 19 | .then(this.validate) 20 | .then(this.setDefaults), 21 | 22 | 'remove:remove': () => BbPromise.bind(this).then(this.remove) 23 | } 24 | } 25 | 26 | async remove() { 27 | const provider = new tencentProvider(this.serverless, this.options) 28 | this.options = await provider.getUserCred(this.options) 29 | await provider.getUserAuth(this.options.credentials.tencent_owneruin) 30 | try { 31 | const handler = new RemoveFunction(this.options, this.serverless) 32 | const service = this.provider.getServiceResource() 33 | const functions = Object.keys(service.Resources.default).filter((key) => { 34 | if (key != 'Type') { 35 | return key 36 | } 37 | }) 38 | 39 | const len = _.size(functions) 40 | this.serverless.cli.log(`Removing functions...`) 41 | for (let i = 0; i < len; i++) { 42 | const funcName = this.provider.getFunctionName(functions[i]) 43 | this.serverless.cli.log(`Removing function ${funcName}`) 44 | const _ = await handler.remove(funcName) 45 | this.serverless.cli.log(`Removed function ${funcName} successful`) 46 | } 47 | } catch (e) { 48 | this.serverless.cli.log(e) 49 | } 50 | } 51 | } 52 | 53 | module.exports = TencentRemove 54 | -------------------------------------------------------------------------------- /remove/tencentRemove.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const Serverless = require('../test/serverless') 6 | const TencentRemove = require('./tencentRemove') 7 | 8 | describe('TencentRemove', () => { 9 | let serverless 10 | let options 11 | let tencentRemove 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentRemove = new TencentRemove(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentRemove.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentRemove.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentRemove.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let tencentRemoveStub 55 | 56 | beforeEach(() => { 57 | validateStub = sinon.stub(tencentRemove, 'validate').returns(Promise.resolve()) 58 | setDefaultsStub = sinon.stub(tencentRemove, 'setDefaults').returns(Promise.resolve()) 59 | tencentRemoveStub = sinon.stub(tencentRemove, 'remove').returns(Promise.resolve()) 60 | }) 61 | 62 | afterEach(() => { 63 | tencentRemove.validate.restore() 64 | tencentRemove.setDefaults.restore() 65 | tencentRemove.remove.restore() 66 | }) 67 | 68 | it('should run "before:remove:remove" promise chain', () => 69 | tencentRemove.hooks['before:remove:remove']().then(() => { 70 | validateStub.calledOnce.should.equal(true) 71 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 72 | })) 73 | 74 | it('should run "remove:remove" promise chain', () => 75 | tencentRemove.hooks['remove:remove']().then(() => { 76 | tencentRemoveStub.calledOnce.should.equal(true) 77 | })) 78 | }) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /rollback/lib/rollbackService.js: -------------------------------------------------------------------------------- 1 | const tencentcloud = require('tencentcloud-sdk-nodejs') 2 | const tencentcloudcos = require('cos-nodejs-sdk-v5') 3 | const AbstractHandler = require('../../shared/handler') 4 | const scf_models = tencentcloud.scf.v20180416.Models 5 | const util = require('util') 6 | 7 | class RollbackService extends AbstractHandler { 8 | async historyList(fileKey, cosBucket) { 9 | const req = { 10 | Bucket: cosBucket, 11 | Region: this.options.region, 12 | Prefix: fileKey 13 | } 14 | const handler = util.promisify(this.cosClient.getBucket.bind(this.cosClient)) 15 | try { 16 | return await handler(req) 17 | } catch (e) { 18 | this.serverless.cli.log('ErrorCode: ' + e.code + ' RequestId: ' + e.requestId) 19 | throw e 20 | } 21 | } 22 | 23 | async getCosObject(fileKey, cosBucket) { 24 | const req = { 25 | Bucket: cosBucket, 26 | Region: this.options.region, 27 | Key: fileKey 28 | } 29 | const handler = util.promisify(this.cosClient.getObject.bind(this.cosClient)) 30 | try { 31 | return await handler(req) 32 | } catch (e) { 33 | this.serverless.cli.log('ErrorCode: ' + e.code + ' RequestId: ' + e.requestId) 34 | throw e 35 | } 36 | } 37 | } 38 | 39 | module.exports = RollbackService 40 | -------------------------------------------------------------------------------- /rollback/lib/rollbackService.test.js: -------------------------------------------------------------------------------- 1 | const sinon = require('sinon') 2 | const Serverless = require('../test/serverless') 3 | const RollbackService = require('./rollbackService') 4 | 5 | describe('RollbackService@Library', () => { 6 | let rollbackService 7 | let getCosObjectStub 8 | let historyListStub 9 | 10 | let options 11 | let serverless 12 | 13 | beforeEach(() => { 14 | serverless = new Serverless() 15 | options = { 16 | region: 'ap-guangzhou' 17 | } 18 | rollbackService = new RollbackService(options, serverless) 19 | 20 | getCosObjectStub = sinon.stub(rollbackService, 'getCosObject').returns(Promise.resolve()) 21 | 22 | historyListStub = sinon.stub(rollbackService, 'historyList').returns(Promise.resolve()) 23 | }) 24 | 25 | afterEach(() => { 26 | rollbackService.historyList.restore() 27 | rollbackService.getCosObject.restore() 28 | }) 29 | 30 | it('should make the rollback service accessible', () => { 31 | rollbackService.should.to.be.an.instanceof(RollbackService) 32 | }) 33 | 34 | it('should run library get cos object function', () => 35 | rollbackService.getCosObject().then(() => { 36 | getCosObjectStub.calledOnce.should.equal(true) 37 | })) 38 | 39 | it('should run library rollback service function', () => 40 | rollbackService.historyList().then(() => { 41 | historyListStub.calledOnce.should.equal(true) 42 | })) 43 | }) 44 | -------------------------------------------------------------------------------- /rollback/tencentRollback.js: -------------------------------------------------------------------------------- 1 | const BbPromise = require('bluebird') 2 | const _ = require('lodash') 3 | const validate = require('../shared/validate') 4 | const utils = require('../shared/utils') 5 | const tencentProvider = require('../provider/tencentProvider') 6 | const RollbackService = require('./lib/rollbackService') 7 | const DeployFunction = require('../deploy/lib/deployFunction') 8 | const DeployTrigger = require('../deploy/lib/deployTrigger') 9 | 10 | class TencentRollback { 11 | constructor(serverless, options) { 12 | this.serverless = serverless 13 | this.options = options 14 | this.provider = this.serverless.getProvider('tencent') 15 | 16 | Object.assign(this, validate, utils, tencentProvider) 17 | 18 | this.hooks = { 19 | 'before:rollback:rollback': () => 20 | BbPromise.bind(this) 21 | .then(this.validate) 22 | .then(this.setDefaults), 23 | 24 | 'rollback:rollback': () => BbPromise.bind(this).then(this.rollback) 25 | } 26 | } 27 | 28 | async rollback() { 29 | const provider = new tencentProvider(this.serverless, this.options) 30 | this.options = await provider.getUserCred(this.options) 31 | await provider.getUserAuth(this.options.credentials.tencent_owneruin) 32 | const Handler = new RollbackService(this.options, this.serverless) 33 | const fileKeyPrefix = this.serverless.service.service + '-' + this.options.stage 34 | const cosBucket = this.provider.getDeployCosBucket() 35 | const functionList = await Handler.historyList(fileKeyPrefix, cosBucket) 36 | if (this.options.verbose) { 37 | this.serverless.cli.log( 38 | 'Use a timestamp from the deploy list below to rollback to a specific version.\nRun `sls rollback -t YourTimeStampHere`' 39 | ) 40 | if (functionList.Contents) { 41 | this.serverless.cli.log('Listing deployments:') 42 | for ( 43 | let functionIndex = functionList.Contents.length - 1; 44 | functionIndex >= 0; 45 | functionIndex-- 46 | ) { 47 | /** 48 | * Serverless: ------------- 49 | * Serverless: Timestamp: 1570942070508 50 | * Serverless: Datetime: 2019-10-13T04:47:50.508Z 51 | * Serverless: Files: 52 | * Serverless: - compiled-cloudformation-template.json 53 | * Serverless: - sls-aws.zip 54 | */ 55 | try { 56 | const thisFileKey = functionList.Contents[functionIndex].Key 57 | const thisFunctionJson = await Handler.getCosObject(thisFileKey, cosBucket) 58 | const thisFileJson = JSON.parse(thisFunctionJson.Body.toString('utf-8')) 59 | this.serverless.cli.log('-------------') 60 | this.serverless.cli.log('Timestamp: ' + thisFileJson.CreateTimestamp) 61 | this.serverless.cli.log('Datetime: ' + thisFileJson.CreateTime) 62 | this.serverless.cli.log('Files:') 63 | this.serverless.cli.log('- ' + thisFileJson.ServiceFileName) 64 | this.serverless.cli.log('- ' + thisFileJson.ServiceZipName) 65 | } catch (e) {} 66 | } 67 | } 68 | } 69 | 70 | if (this.options.timestamp) { 71 | for (let functionIndex = 0; functionIndex < functionList.Contents.length; functionIndex++) { 72 | try { 73 | const thisFileKey = functionList.Contents[functionIndex].Key 74 | const thisFunctionJson = await Handler.getCosObject(thisFileKey, cosBucket) 75 | const services = JSON.parse(thisFunctionJson.Body.toString('utf-8')) 76 | if (this.options.timestamp.toString() == services.CreateTimestamp.toString()) { 77 | const func = new DeployFunction(this.options, this.serverless) 78 | const trigger = new DeployTrigger(this.options, this.serverless) 79 | for (const funcName in services.Resources.default) { 80 | if (funcName == 'Type') { 81 | continue 82 | } 83 | const funcObject = _.cloneDeep(services.Resources.default[funcName]) 84 | funcObject.Name = funcName 85 | funcObject.FuncName = this.provider.getFunctionName(funcName) 86 | 87 | this.serverless.cli.log(`Rollback function ${funcObject.FuncName}`) 88 | const oldFunc = await func.deploy('default', funcObject) 89 | this.serverless.cli.log(`Rollback function ${funcObject.FuncName}`) 90 | 91 | if ((await func.checkStatus('default', funcObject)) == false) { 92 | throw `Function ${funcObject.FuncName} create/update failed` 93 | } 94 | 95 | this.serverless.cli.log(`Rollback configure for function ${funcObject.FuncName}`) 96 | await func.updateConfiguration('default', oldFunc, funcObject) 97 | 98 | if ((await func.checkStatus('default', funcObject)) == false) { 99 | throw `Function ${funcObject.FuncName} create/update failed` 100 | } 101 | 102 | this.serverless.cli.log(`Setting tags for function ${funcObject.FuncName}`) 103 | await func.createTags('default', funcObject.FuncName, funcObject.Properties.Tags) 104 | 105 | this.serverless.cli.log(`Rollback trigger for function ${funcObject.FuncName}`) 106 | await trigger.create( 107 | 'default', 108 | oldFunc ? oldFunc.Triggers : null, 109 | funcObject, 110 | (response, trigger) => { 111 | if (trigger.Type == 'apigw') { 112 | const resultDesc = JSON.parse(response.TriggerDesc) 113 | this.serverless.cli.log( 114 | `Created ${trigger.Type} trigger ${response.TriggerName} for function ${funcObject.FuncName} success. service id ${resultDesc.service.serviceId} url ${resultDesc.service.subDomain}` 115 | ) 116 | } else { 117 | this.serverless.cli.log( 118 | `Created ${trigger.Type} trigger ${response.TriggerName} for function ${funcObject.FuncName} success.` 119 | ) 120 | } 121 | }, 122 | (error, trigger) => { 123 | this.serverless.cli.log(error) 124 | } 125 | ) 126 | this.serverless.cli.log(`Deployed function ${funcObject.FuncName} successful`) 127 | } 128 | } 129 | } catch (e) {} 130 | } 131 | } 132 | } 133 | } 134 | 135 | module.exports = TencentRollback 136 | -------------------------------------------------------------------------------- /rollback/tencentRollback.test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const os = require('os') 3 | const sinon = require('sinon') 4 | const TencentProvider = require('../provider/tencentProvider') 5 | const Serverless = require('../test/serverless') 6 | const TencentRollback = require('./tencentRollback') 7 | 8 | describe('TencentRollback', () => { 9 | let serverless 10 | let options 11 | let tencentRollback 12 | let readFileSyncStub 13 | let homedirStub 14 | 15 | beforeEach(() => { 16 | serverless = new Serverless() 17 | options = { 18 | stage: 'dev', 19 | region: 'ap-guangzhou', 20 | function: 'test' 21 | } 22 | 23 | readFileSyncStub = sinon.stub(fs, 'readFileSync').returns(`[default] 24 | tencent_secret_key = PYR4a0HSZ******eVvHRe 25 | tencent_secret_id = AKIDoM*****mxsfOirI 26 | tencent_appid = 12561*****`) 27 | homedirStub = sinon.stub(os, 'homedir').returns('/root') 28 | 29 | serverless.setProvider('tencent', new TencentProvider(serverless, options)) 30 | tencentRollback = new TencentRollback(serverless, options) 31 | }) 32 | 33 | afterEach(() => { 34 | fs.readFileSync.restore() 35 | os.homedir.restore() 36 | }) 37 | 38 | describe('#constructor()', () => { 39 | it('should set the serverless instance', () => { 40 | tencentRollback.serverless.should.equal(serverless) 41 | }) 42 | 43 | it('should set options if provided', () => { 44 | tencentRollback.options.should.equal(options) 45 | }) 46 | 47 | it('should make the provider accessible', () => { 48 | tencentRollback.provider.should.to.be.an.instanceof(TencentProvider) 49 | }) 50 | 51 | describe('hooks', () => { 52 | let validateStub 53 | let setDefaultsStub 54 | let tencentRollbackStub 55 | 56 | beforeEach(() => { 57 | validateStub = sinon.stub(tencentRollback, 'validate').returns(Promise.resolve()) 58 | setDefaultsStub = sinon.stub(tencentRollback, 'setDefaults').returns(Promise.resolve()) 59 | tencentRollbackStub = sinon.stub(tencentRollback, 'rollback').returns(Promise.resolve()) 60 | }) 61 | 62 | afterEach(() => { 63 | tencentRollback.validate.restore() 64 | tencentRollback.setDefaults.restore() 65 | tencentRollback.rollback.restore() 66 | }) 67 | 68 | it('should run "before:rollback:rollback" promise chain', () => 69 | tencentRollback.hooks['before:rollback:rollback']().then(() => { 70 | validateStub.calledOnce.should.equal(true) 71 | setDefaultsStub.calledAfter(validateStub).should.equal(true) 72 | })) 73 | 74 | it('should run "rollback:rollback" promise chain', () => 75 | tencentRollback.hooks['rollback:rollback']().then(() => { 76 | tencentRollbackStub.calledOnce.should.equal(true) 77 | })) 78 | }) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /shared/handler.js: -------------------------------------------------------------------------------- 1 | const tencentcloudCos = require('cos-nodejs-sdk-v5') 2 | const tencentcloud = require('tencentcloud-sdk-nodejs') 3 | const ClientProfile = require('tencentcloud-sdk-nodejs/tencentcloud/common/profile/client_profile.js') 4 | const HttpProfile = require('tencentcloud-sdk-nodejs/tencentcloud/common/profile/http_profile.js') 5 | const assert = require('assert') 6 | const { Credential } = tencentcloud.common 7 | const ScfClient = tencentcloud.scf.v20180416.Client 8 | const TagClient = tencentcloud.tag.v20180813.Client 9 | const CamClient = tencentcloud.cam.v20190116.Client 10 | const MonitorClinet = tencentcloud.monitor.v20180724.Client 11 | 12 | class AbstractHandler { 13 | constructor(options, serverless) { 14 | const { credentials, region } = options 15 | const { tencent_appid, tencent_secret_id, tencent_secret_key } = credentials 16 | this.options = options 17 | this.serverless = serverless 18 | this.appid = tencent_appid 19 | this.secret_id = tencent_secret_id 20 | this.secret_key = tencent_secret_key 21 | 22 | assert(options, 'Options should not is empty') 23 | 24 | this._scfClient = AbstractHandler.createScfClient( 25 | tencent_secret_id, 26 | tencent_secret_key, 27 | options 28 | ) 29 | this._camClient = AbstractHandler.createCamClient( 30 | tencent_secret_id, 31 | tencent_secret_key, 32 | options 33 | ) 34 | this._cosClient = AbstractHandler.createCosClient( 35 | tencent_secret_id, 36 | tencent_secret_key, 37 | options 38 | ) 39 | this._tagClient = AbstractHandler.createTagClient( 40 | tencent_secret_id, 41 | tencent_secret_key, 42 | options 43 | ) 44 | this._monitorClient = AbstractHandler.createMonitorClient( 45 | tencent_secret_id, 46 | tencent_secret_key, 47 | options 48 | ) 49 | } 50 | 51 | static getClientInfo(secret_id, secret_key, options) { 52 | const cred = options.token 53 | ? new Credential(secret_id, secret_key, options.token) 54 | : new Credential(secret_id, secret_key) 55 | const httpProfile = new HttpProfile() 56 | httpProfile.reqTimeout = 60 57 | const clientProfile = new ClientProfile('HmacSHA256', httpProfile) 58 | assert(options.region, 'Region should not is empty') 59 | return { 60 | cred: cred, 61 | region: options.region, 62 | clientProfile: clientProfile 63 | } 64 | } 65 | 66 | static createTagClient(secret_id, secret_key, options) { 67 | const info = this.getClientInfo(secret_id, secret_key, options) 68 | const tagCli = new TagClient(info.cred, info.region, info.clientProfile) 69 | tagCli.sdkVersion = 'ServerlessFramework' 70 | return tagCli 71 | } 72 | 73 | static createScfClient(secret_id, secret_key, options) { 74 | const info = this.getClientInfo(secret_id, secret_key, options) 75 | const scfCli = new ScfClient(info.cred, info.region, info.clientProfile) 76 | scfCli.sdkVersion = 'ServerlessFramework' 77 | return scfCli 78 | } 79 | 80 | static createCamClient(secret_id, secret_key, options) { 81 | const info = this.getClientInfo(secret_id, secret_key, options) 82 | const camCli = new CamClient(info.cred, info.region, info.clientProfile) 83 | camCli.sdkVersion = 'ServerlessFramework' 84 | return camCli 85 | } 86 | 87 | static createMonitorClient(secret_id, secret_key, options) { 88 | const info = this.getClientInfo(secret_id, secret_key, options) 89 | const monitorCli = new MonitorClinet(info.cred, info.region, info.clientProfile) 90 | monitorCli.sdkVersion = 'ServerlessFramework' 91 | return monitorCli 92 | } 93 | 94 | static createCosClient(secret_id, secret_key, options) { 95 | const fileParallelLimit = options.fileParallelLimit || 5 96 | const chunkParallelLimit = options.chunkParallelLimit || 8 97 | const chunkSize = options.chunkSize || 1024 * 1024 * 8 98 | const timeout = options.timeout || 120 99 | 100 | return new tencentcloudCos({ 101 | SecretId: secret_id, 102 | SecretKey: secret_key, 103 | FileParallelLimit: fileParallelLimit, 104 | ChunkParallelLimit: chunkParallelLimit, 105 | ChunkSize: chunkSize, 106 | Timeout: timeout * 1000, 107 | TmpSecretId: secret_id, 108 | TmpSecretKey: secret_key, 109 | XCosSecurityToken: options.token, 110 | ExpiredTime: options.timestamp 111 | }) 112 | } 113 | 114 | get monitorClient() { 115 | return this._monitorClient 116 | } 117 | 118 | get cosClient() { 119 | return this._cosClient 120 | } 121 | 122 | get tagClient() { 123 | return this._tagClient 124 | } 125 | 126 | get scfClient() { 127 | return this._scfClient 128 | } 129 | 130 | get camClient() { 131 | return this._camClient 132 | } 133 | } 134 | 135 | module.exports = AbstractHandler 136 | -------------------------------------------------------------------------------- /shared/utils.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash') 2 | const util = require('util') 3 | const BbPromise = require('bluebird') 4 | const crypto = require('crypto') 5 | 6 | module.exports = { 7 | setDefaults() { 8 | this.options.stage = this.provider.getStage() 9 | this.options.region = this.provider.getRegion() 10 | return BbPromise.resolve() 11 | }, 12 | 13 | TC3HMACSHA256(service, req, secretId, secretKey) { 14 | // const ApiService = 'scf'; 15 | const ApiVersion = '2018-04-16' 16 | const ApiTc3Request = 'tc3_request' 17 | const ApiSignedHeaders = 'content-type;host' 18 | 19 | const hosts = { 20 | scf: 'scf.tencentcloudapi.com' 21 | } 22 | 23 | const PrefixInteger = function(num, length) { 24 | return (Array(length).join('0') + num).slice(-length) 25 | } 26 | 27 | const sign = function(key, msg, hex) { 28 | if (hex) { 29 | return crypto 30 | .createHmac('sha256', key) 31 | .update(msg, 'utf8') 32 | .digest('hex') 33 | } 34 | return crypto.createHmac('sha256', key).update(msg, 'utf8') 35 | } 36 | 37 | const newDate = new Date() 38 | const timestamp = Math.ceil(newDate.getTime() / 1000) 39 | const ctype = 'application/json' 40 | const algorithm = 'TC3-HMAC-SHA256' 41 | const payload = JSON.stringify(req) 42 | const canonical_headers = util.format('content-type:%s\nhost:%s\n', ctype, hosts[service]) 43 | const http_request_method = 'POST' 44 | const canonical_uri = '/' 45 | const canonical_querystring = '' 46 | const date = util.format( 47 | '%s-%s-%s', 48 | newDate.getFullYear(), 49 | PrefixInteger(newDate.getMonth() + 1, 2), 50 | PrefixInteger(newDate.getUTCDate(), 2) 51 | ) 52 | 53 | const hashed_request_payload = crypto 54 | .createHash('sha256') 55 | .update(payload, 'utf8') 56 | .digest() 57 | const canonical_request = 58 | http_request_method + 59 | '\n' + 60 | canonical_uri + 61 | '\n' + 62 | canonical_querystring + 63 | '\n' + 64 | canonical_headers + 65 | '\n' + 66 | ApiSignedHeaders + 67 | '\n' + 68 | hashed_request_payload.toString('hex') 69 | 70 | const credential_scope = date + '/' + service + '/' + ApiTc3Request 71 | const hashed_canonical_request = crypto 72 | .createHash('sha256') 73 | .update(canonical_request, 'utf8') 74 | .digest() 75 | const string_to_sign = 76 | algorithm + 77 | '\n' + 78 | timestamp + 79 | '\n' + 80 | credential_scope + 81 | '\n' + 82 | hashed_canonical_request.toString('hex') 83 | 84 | const secret_date = sign('TC3' + secretKey, date, false) 85 | const secret_service = sign(new Buffer(secret_date.digest('hex'), 'hex'), service, false) 86 | const secret_signing = sign( 87 | new Buffer(secret_service.digest('hex'), 'hex'), 88 | ApiTc3Request, 89 | false 90 | ) 91 | const signature = sign(new Buffer(secret_signing.digest('hex'), 'hex'), string_to_sign, true) 92 | 93 | return { 94 | host: hosts[service], 95 | version: ApiVersion, 96 | timestamp: timestamp, 97 | sign: util.format( 98 | '%s Credential=%s/%s, SignedHeaders=%s, Signature=%s', 99 | algorithm, 100 | secretId, 101 | credential_scope, 102 | ApiSignedHeaders, 103 | signature 104 | ) 105 | } 106 | }, 107 | 108 | sleep(ms) { 109 | return new Promise((resolve) => { 110 | setTimeout(resolve, ms) 111 | }) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /shared/validate.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash') 2 | 3 | module.exports = { 4 | validate() { 5 | this.validateServicePath() 6 | this.validateServiceName() 7 | this.validateEventsProperty() 8 | }, 9 | 10 | validateServicePath() { 11 | if (!this.serverless.config.servicePath) { 12 | throw new Error('This command can only be run inside a service directory') 13 | } 14 | return 15 | }, 16 | 17 | validateServiceName() { 18 | const serviceName = this.serverless.service.service 19 | if (!/^[a-zA-Z_][a-zA-Z0-9\-_]*$/.test(serviceName)) { 20 | throw new Error( 21 | `The name of your service ${serviceName} is invalid. A service` + 22 | ' name should consist only of letters, digits, underscores and' + 23 | ' dashes, and it can not start with digits or underscores' 24 | ) 25 | } 26 | if (serviceName.length > 128) { 27 | throw new Error( 28 | `The name of your service ${serviceName} is invalid. A service` + 29 | ' name should not be longer than 128 characters' 30 | ) 31 | } 32 | return 33 | }, 34 | 35 | validateEventsProperty() { 36 | const { functions } = this.serverless.service 37 | _.forEach(functions, (funcObject, funcKey) => { 38 | const supportedEvents = ['apigw', 'cos', 'cmq', 'timer', 'ckafka'] 39 | 40 | for (var eventIndex = 0; eventIndex < funcObject.events.length; eventIndex++) { 41 | const eventType = Object.keys(funcObject.events[eventIndex])[0] 42 | if (supportedEvents.indexOf(eventType) === -1) { 43 | const errorMessage = [ 44 | `Event type "${eventType}" of function "${funcKey}" not supported.`, 45 | ` supported event types are: ${supportedEvents.join(', ')}` 46 | ].join('') 47 | throw new Error(errorMessage) 48 | } 49 | } 50 | }) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /templates/tencent-go/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all deps clean build 2 | all: deps clean build 3 | deps: 4 | go get github.com/tencentyun/scf-go-lib/cloudfunction 5 | 6 | clean: 7 | rm -rf ./index 8 | 9 | build: 10 | GOOS=linux GOARCH=amd64 go build -o ./index . 11 | -------------------------------------------------------------------------------- /templates/tencent-go/gitignore: -------------------------------------------------------------------------------- 1 | # Serverless directories 2 | .serverless 3 | 4 | # golang output binary directory 5 | bin 6 | 7 | # Binaries for programs and plugins 8 | *.exe 9 | *.exe~ 10 | *.dll 11 | *.so 12 | *.dylib 13 | 14 | # Test binary, build with `go test -c` 15 | *.test 16 | 17 | # Output of the go coverage tool, specifically when used with LiteIDE 18 | *.out 19 | -------------------------------------------------------------------------------- /templates/tencent-go/index.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/tencentyun/scf-go-lib/cloudfunction" 7 | ) 8 | 9 | type DefineEvent struct { 10 | Key1 string `json:"key1"` 11 | Key2 string `json:"key2"` 12 | } 13 | 14 | func hello(ctx context.Context, event DefineEvent) (string, error) { 15 | fmt.Println("key1:", event.Key1) 16 | fmt.Println("key2:", event.Key2) 17 | return fmt.Sprintf("Hello World"), nil 18 | } 19 | 20 | func main() { 21 | cloudfunction.Start(hello) 22 | } 23 | -------------------------------------------------------------------------------- /templates/tencent-go/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tencent-golang", 3 | "version": "1.0.0", 4 | "description": "Tencent Serverless Cloud Function example using Golang", 5 | "main": "index.go", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "cloud.tencent.com", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "serverless-tencent-scf": "^0.1.7" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /templates/tencent-go/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: my-service # service name 15 | 16 | provider: # provider information 17 | name: tencent 18 | runtime: Go1 19 | credentials: ~/credentials 20 | 21 | # you can overwrite defaults here 22 | # stage: dev 23 | # cosBucket: DEFAULT 24 | # role: QCS_SCFExcuteRole 25 | # memorySize: 256 26 | # timeout: 10 27 | # region: ap-shanghai 28 | # environment: 29 | # variables: 30 | # ENV_FIRST: env1 31 | # ENV_SECOND: env2 32 | 33 | plugins: 34 | - serverless-tencent-scf 35 | 36 | # you can add packaging information here 37 | #package: 38 | # exclude: 39 | # - ./** 40 | # include: 41 | # - ./bin/** 42 | 43 | functions: 44 | function_one: 45 | handler: main 46 | # description: Tencent Serverless Cloud Function 47 | # runtime: Go1 48 | # memorySize: 256 49 | # timeout: 10 50 | # environment: 51 | # variables: 52 | # ENV_FIRST: env1 53 | # ENV_Third: env2 54 | # events: 55 | # - timer: 56 | # name: timer 57 | # parameters: 58 | # cronExpression: '*/5 * * * *' 59 | # enable: true 60 | # - cos: 61 | # name: cli-appid.cos.ap-beijing.myqcloud.com 62 | # parameters: 63 | # bucket: cli-appid.cos.ap-beijing.myqcloud.com 64 | # filter: 65 | # prefix: filterdir/ 66 | # suffix: .jpg 67 | # events: cos:ObjectCreated:* 68 | # enable: true 69 | # - apigw: 70 | # name: hello_world_apigw 71 | # parameters: 72 | # stageName: release 73 | # serviceId: 74 | # httpMethod: ANY 75 | # - cmq: 76 | # name: cmq_trigger 77 | # parameters: 78 | # name: test-topic-queue 79 | # enable: true 80 | # - ckafka: 81 | # name: ckafka_trigger 82 | # parameters: 83 | # name: ckafka-2o10hua5 84 | # topic: test 85 | # maxMsgNum: 999 86 | # offset: latest 87 | # enable: true 88 | -------------------------------------------------------------------------------- /templates/tencent-nodejs/gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /templates/tencent-nodejs/index.js: -------------------------------------------------------------------------------- 1 | exports.main_handler = (event, context, callback) => { 2 | console.log('%j', event) 3 | callback(null, 'Hello World') 4 | } 5 | -------------------------------------------------------------------------------- /templates/tencent-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tencent-nodejs", 3 | "version": "1.0.0", 4 | "description": "Tencent Serverless Cloud Function example using Nodejs", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "cloud.tencent.com", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "serverless-tencent-scf": "^0.1.7" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /templates/tencent-nodejs/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: my-service # service name 15 | 16 | provider: # provider information 17 | name: tencent 18 | runtime: Nodejs8.9 # Nodejs8.9 or Nodejs6.10 19 | credentials: ~/credentials 20 | 21 | # you can overwrite defaults here 22 | # stage: dev 23 | # cosBucket: DEFAULT 24 | # role: QCS_SCFExcuteRole 25 | # memorySize: 256 26 | # timeout: 10 27 | # region: ap-shanghai 28 | # environment: 29 | # variables: 30 | # ENV_FIRST: env1 31 | # ENV_SECOND: env2 32 | 33 | plugins: 34 | - serverless-tencent-scf 35 | 36 | # you can add packaging information here 37 | #package: 38 | # include: 39 | # - include-me.js 40 | # - include-me-dir/** 41 | # exclude: 42 | # - exclude-me.js 43 | # - exclude-me-dir/** 44 | 45 | functions: 46 | function_one: 47 | handler: index.main_handler 48 | # description: Tencent Serverless Cloud Function 49 | # runtime: Nodejs8.9 # Nodejs8.9 or Nodejs6.10 50 | # memorySize: 256 51 | # timeout: 10 52 | # environment: 53 | # variables: 54 | # ENV_FIRST: env1 55 | # ENV_Third: env2 56 | # events: 57 | # - timer: 58 | # name: timer 59 | # parameters: 60 | # cronExpression: '*/5 * * * *' 61 | # enable: true 62 | # - cos: 63 | # name: cli-appid.cos.ap-beijing.myqcloud.com 64 | # parameters: 65 | # bucket: cli-appid.cos.ap-beijing.myqcloud.com 66 | # filter: 67 | # prefix: filterdir/ 68 | # suffix: .jpg 69 | # events: cos:ObjectCreated:* 70 | # enable: true 71 | # - apigw: 72 | # name: hello_world_apigw 73 | # parameters: 74 | # stageName: release 75 | # serviceId: 76 | # httpMethod: ANY 77 | # - cmq: 78 | # name: cmq_trigger 79 | # parameters: 80 | # name: test-topic-queue 81 | # enable: true 82 | # - ckafka: 83 | # name: ckafka_trigger 84 | # parameters: 85 | # name: ckafka-2o10hua5 86 | # topic: test 87 | # maxMsgNum: 999 88 | # offset: latest 89 | # enable: true 90 | -------------------------------------------------------------------------------- /templates/tencent-php/gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /templates/tencent-php/index.php: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /templates/tencent-php/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tencent-php", 3 | "version": "1.0.0", 4 | "description": "Tencent Serverless Cloud Function example using Php", 5 | "main": "index.php", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "cloud.tencent.com", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "serverless-tencent-scf": "^0.1.7" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /templates/tencent-php/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: my-service # service name 15 | 16 | provider: # provider information 17 | name: tencent 18 | runtime: Php7 # Php7 or Php5 19 | credentials: ~/credentials 20 | 21 | # you can overwrite defaults here 22 | # stage: dev 23 | # cosBucket: DEFAULT 24 | # role: QCS_SCFExcuteRole 25 | # memorySize: 256 26 | # timeout: 10 27 | # region: ap-shanghai 28 | # environment: 29 | # variables: 30 | # ENV_FIRST: env1 31 | # ENV_SECOND: env2 32 | 33 | plugins: 34 | - serverless-tencent-scf 35 | 36 | functions: 37 | function_one_one_one: 38 | handler: index.main_handler 39 | # description: Tencent Serverless Cloud Function 40 | # runtime: Php7 # Php7 or Php5 41 | # memorySize: 256 42 | # timeout: 10 43 | # environment: 44 | # variables: 45 | # ENV_FIRST: env1 46 | # ENV_Third: env2 47 | # events: 48 | # - timer: 49 | # name: timer 50 | # parameters: 51 | # cronExpression: '*/5 * * * *' 52 | # enable: true 53 | # - cos: 54 | # name: cli-appid.cos.ap-beijing.myqcloud.com 55 | # parameters: 56 | # bucket: cli-appid.cos.ap-beijing.myqcloud.com 57 | # filter: 58 | # prefix: filterdir/ 59 | # suffix: .jpg 60 | # events: cos:ObjectCreated:* 61 | # enable: true 62 | # - apigw: 63 | # name: hello_world_apigw 64 | # parameters: 65 | # stageName: release 66 | # serviceId: 67 | # httpMethod: ANY 68 | # - cmq: 69 | # name: cmq_trigger 70 | # parameters: 71 | # name: test-topic-queue 72 | # enable: true 73 | # - ckafka: 74 | # name: ckafka_trigger 75 | # parameters: 76 | # name: ckafka-2o10hua5 77 | # topic: test 78 | # maxMsgNum: 999 79 | # offset: latest 80 | # enable: true 81 | -------------------------------------------------------------------------------- /templates/tencent-python/gitignore: -------------------------------------------------------------------------------- 1 | # Distribution / packaging 2 | .Python 3 | env/ 4 | build/ 5 | develop-eggs/ 6 | dist/ 7 | downloads/ 8 | eggs/ 9 | .eggs/ 10 | lib/ 11 | lib64/ 12 | parts/ 13 | sdist/ 14 | var/ 15 | *.egg-info/ 16 | .installed.cfg 17 | *.egg 18 | 19 | # Serverless directories 20 | .serverless -------------------------------------------------------------------------------- /templates/tencent-python/index.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf8 -*- 2 | 3 | 4 | def main_handler(event, context): 5 | print(str(event)) 6 | return "hello world" 7 | 8 | -------------------------------------------------------------------------------- /templates/tencent-python/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tencent-python", 3 | "version": "1.0.0", 4 | "description": "Tencent Serverless Cloud Function example using Python", 5 | "main": "index.py", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "cloud.tencent.com", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "serverless-tencent-scf": "^0.1.7" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /templates/tencent-python/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: my-service # service name 15 | 16 | provider: # provider information 17 | name: tencent 18 | runtime: Python3.6 # Python3.6 or Python2.7 19 | credentials: ~/credentials 20 | 21 | # you can overwrite defaults here 22 | # stage: dev 23 | # cosBucket: DEFAULT 24 | # role: QCS_SCFExcuteRole 25 | # memorySize: 256 26 | # timeout: 10 27 | # region: ap-shanghai 28 | # environment: 29 | # variables: 30 | # ENV_FIRST: env1 31 | # ENV_SECOND: env2 32 | 33 | plugins: 34 | - serverless-tencent-scf 35 | 36 | # you can add packaging information here 37 | #package: 38 | # include: 39 | # - include-me.py 40 | # - include-me-dir/** 41 | # exclude: 42 | # - exclude-me.py 43 | # - exclude-me-dir/** 44 | 45 | functions: 46 | function_one: 47 | handler: index.main_handler 48 | # description: Tencent Serverless Cloud Function 49 | # runtime: Python3.6 # Python3.6 or Python2.7 50 | # memorySize: 256 51 | # timeout: 10 52 | # environment: 53 | # variables: 54 | # ENV_FIRST: env1 55 | # ENV_Third: env2 56 | # events: 57 | # - timer: 58 | # name: timer 59 | # parameters: 60 | # cronExpression: '*/5 * * * *' 61 | # enable: true 62 | # - cos: 63 | # name: cli-appid.cos.ap-beijing.myqcloud.com 64 | # parameters: 65 | # bucket: cli-appid.cos.ap-beijing.myqcloud.com 66 | # filter: 67 | # prefix: filterdir/ 68 | # suffix: .jpg 69 | # events: cos:ObjectCreated:* 70 | # enable: true 71 | # - apigw: 72 | # name: hello_world_apigw 73 | # parameters: 74 | # stageName: release 75 | # serviceId: 76 | # httpMethod: ANY 77 | # - cmq: 78 | # name: cmq_trigger 79 | # parameters: 80 | # name: test-topic-queue 81 | # enable: true 82 | # - ckafka: 83 | # name: ckafka_trigger 84 | # parameters: 85 | # name: ckafka-2o10hua5 86 | # topic: test 87 | # maxMsgNum: 999 88 | # offset: latest 89 | # enable: true 90 | -------------------------------------------------------------------------------- /test/init.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'test' 2 | 3 | const chai = require('chai') 4 | global.should = chai.should() 5 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --recursive 2 | -r test/init.js 3 | invoke/**/*.test.js 4 | logs/**/*.test.js 5 | remove/**/*.test.js 6 | info/**/*.test.js 7 | metrics/**/*.test.js 8 | rollback/**/*.test.js 9 | deploy/**/*.test.js 10 | provider/**/*.test.js -------------------------------------------------------------------------------- /test/serverless.js: -------------------------------------------------------------------------------- 1 | // mock of the serverless instance 2 | class Serverless { 3 | constructor() { 4 | this.providers = {} 5 | 6 | this.service = { 7 | provider: { 8 | credentials: '' 9 | }, 10 | service: 'test-service' 11 | } 12 | 13 | this.service.getAllFunctions = function() { 14 | return Object.keys(this.functions) 15 | } 16 | 17 | this.service.getFunction = function(funcName) { 18 | this.functions[funcName].name = `${this.service}-dev-${funcName}` 19 | return this.functions[funcName] 20 | } 21 | 22 | this.utils = { 23 | writeFileSync() {}, 24 | readFileSync() {} 25 | } 26 | 27 | this.cli = { 28 | log() {}, 29 | consoleLog() {}, 30 | printDot() {} 31 | } 32 | 33 | this.plugins = [] 34 | this.pluginManager = { 35 | addPlugin: (plugin) => this.plugins.push(plugin) 36 | } 37 | } 38 | 39 | setProvider(name, provider) { 40 | this.providers[name] = provider 41 | } 42 | 43 | getProvider(name) { 44 | return this.providers[name] 45 | } 46 | } 47 | 48 | module.exports = Serverless 49 | -------------------------------------------------------------------------------- /test/tencentCommand.js: -------------------------------------------------------------------------------- 1 | class TencentCommand { 2 | constructor(serverless, options, testSubject) { 3 | this.options = options 4 | this.serverless = serverless 5 | this.provider = this.serverless.getProvider('tencent') 6 | 7 | Object.assign(this, testSubject) 8 | } 9 | } 10 | 11 | module.exports = TencentCommand 12 | --------------------------------------------------------------------------------