1
1
const { Component } = require ( '@serverless/core' )
2
+ const ensureObject = require ( 'type/object/ensure' )
2
3
const ensureIterable = require ( 'type/iterable/ensure' )
3
4
const ensureString = require ( 'type/string/ensure' )
4
- const { MultiApigw, Scf, Cos, Cns } = require ( 'tencent-component-toolkit' )
5
+ const { MultiApigw, Scf, Apigw , Cos, Cns } = require ( 'tencent-component-toolkit' )
5
6
const { packageExpress, generateId } = require ( './utils' )
6
7
7
8
const DEFAULTS = {
8
9
handler : 'sl_handler.handler' ,
9
10
runtime : 'Nodejs8.9' ,
10
11
exclude : [ '.git/**' , '.gitignore' , '.DS_Store' ] ,
11
12
timeout : 3 ,
12
- memorySize : 128
13
+ memorySize : 128 ,
14
+ namespace : 'default'
13
15
}
14
16
15
17
class Express extends Component {
18
+ getDefaultProtocol ( protocols ) {
19
+ if ( protocols . map ( ( i ) => i . toLowerCase ( ) ) . includes ( 'https' ) ) {
20
+ return 'https'
21
+ }
22
+ return 'http'
23
+ }
24
+
16
25
mergeJson ( sourceJson , targetJson ) {
17
26
for ( const eveKey in sourceJson ) {
18
27
if ( targetJson . hasOwnProperty ( eveKey ) ) {
@@ -48,39 +57,59 @@ class Express extends Component {
48
57
49
58
async prepareInputs ( inputs = { } ) {
50
59
// 对function inputs进行标准化
51
- const tempFunctionConf = inputs . functionConf ? inputs . functionConf : undefined
60
+ const tempFunctionConf = inputs . functionConf ? inputs . functionConf : { }
52
61
const fromClientRemark = `tencent-express`
62
+ const regionList = inputs . region
63
+ ? typeof inputs . region == 'string'
64
+ ? [ inputs . region ]
65
+ : inputs . region
66
+ : [ 'ap-guangzhou' ]
67
+
68
+ // chenck state function name
69
+ const stateFunctionName = this . state [ regionList [ 0 ] ] && this . state [ regionList [ 0 ] ] . functionName
70
+ // check state service id
71
+ const stateServiceId = this . state [ regionList [ 0 ] ] && this . state [ regionList [ 0 ] ] . serviceId
53
72
54
73
const functionConf = {
74
+ code :
75
+ typeof inputs . src === 'object'
76
+ ? inputs . src
77
+ : {
78
+ src : inputs . src
79
+ } ,
55
80
name :
56
81
ensureString ( inputs . functionName , { isOptional : true } ) ||
57
- this . state . functionName ||
82
+ stateFunctionName ||
58
83
`express_component_${ generateId ( ) } ` ,
59
- code :
60
- ensureString ( tempFunctionConf && tempFunctionConf . src ? tempFunctionConf . src : inputs . src , {
61
- isOptional : true
62
- } ) || process . cwd ( ) ,
63
- region : inputs . region
64
- ? typeof inputs . region == 'string'
65
- ? [ inputs . region ]
66
- : inputs . region
67
- : [ 'ap-guangzhou' ] ,
68
- handler : ensureString (
69
- tempFunctionConf && tempFunctionConf . handler ? tempFunctionConf . handler : inputs . handler ,
70
- { default : DEFAULTS . handler }
84
+ region : regionList ,
85
+ handler : ensureString ( tempFunctionConf . handler ? tempFunctionConf . handler : inputs . handler , {
86
+ default : DEFAULTS . handler
87
+ } ) ,
88
+ runtime : ensureString ( tempFunctionConf . runtime ? tempFunctionConf . runtime : inputs . runtime , {
89
+ default : DEFAULTS . runtime
90
+ } ) ,
91
+ namespace : ensureString (
92
+ tempFunctionConf . namespace ? tempFunctionConf . namespace : inputs . namespace ,
93
+ { default : DEFAULTS . namespace }
71
94
) ,
72
- runtime : ensureString (
73
- tempFunctionConf && tempFunctionConf . runtime ? tempFunctionConf . runtime : inputs . runtime ,
74
- { default : DEFAULTS . runtime }
95
+ description : ensureString (
96
+ tempFunctionConf . description ? tempFunctionConf . description : inputs . description ,
97
+ {
98
+ default : DEFAULTS . description
99
+ }
75
100
) ,
76
101
fromClientRemark
77
102
}
103
+ functionConf . tags = ensureObject ( tempFunctionConf . tags ? tempFunctionConf . tags : inputs . tag , {
104
+ default : null
105
+ } )
106
+
78
107
functionConf . include = ensureIterable (
79
- tempFunctionConf && tempFunctionConf . include ? tempFunctionConf . include : inputs . include ,
108
+ tempFunctionConf . include ? tempFunctionConf . include : inputs . include ,
80
109
{ default : [ ] , ensureItem : ensureString }
81
110
)
82
111
functionConf . exclude = ensureIterable (
83
- tempFunctionConf && tempFunctionConf . exclude ? tempFunctionConf . exclude : inputs . exclude ,
112
+ tempFunctionConf . exclude ? tempFunctionConf . exclude : inputs . exclude ,
84
113
{ default : [ ] , ensureItem : ensureString }
85
114
)
86
115
functionConf . exclude . push ( '.git/**' , '.gitignore' , '.serverless' , '.DS_Store' )
@@ -104,7 +133,7 @@ class Express extends Component {
104
133
apigatewayConf . fromClientRemark = fromClientRemark
105
134
apigatewayConf . serviceName = inputs . serviceName
106
135
apigatewayConf . description = `Serverless Framework Tencent-Express Component`
107
- apigatewayConf . serviceId = inputs . serviceId
136
+ apigatewayConf . serviceId = inputs . serviceId || stateServiceId
108
137
apigatewayConf . region = functionConf . region
109
138
apigatewayConf . protocols = apigatewayConf . protocols || [ 'http' ]
110
139
apigatewayConf . environment = apigatewayConf . environment ? apigatewayConf . environment : 'release'
@@ -179,37 +208,36 @@ class Express extends Component {
179
208
}
180
209
181
210
return {
182
- region : functionConf . region ,
183
- functionConf : functionConf ,
184
- apigatewayConf : apigatewayConf ,
185
- cnsConf : cnsConf
211
+ regionList ,
212
+ functionConf,
213
+ apigatewayConf,
214
+ cnsConf
186
215
}
187
216
}
188
217
189
218
async uploadCodeToCos ( credentials , inputs , region , filePath ) {
190
219
// 创建cos对象
191
220
const cos = new Cos ( credentials , region )
192
221
// 创建存储桶 + 设置生命周期
193
- if ( ! inputs . code || ! inputs . code . bucket ) {
194
- inputs . code = { }
222
+ if ( ! inputs . code . bucket ) {
195
223
inputs . code . bucket = `sls-cloudfunction-${ region } -code`
196
224
await cos . deploy ( {
197
225
bucket : inputs . code . bucket ,
198
- force : true
199
- // lifecycle: [
200
- // {
201
- // status: 'Enabled',
202
- // id: 'deleteObject',
203
- // filter: '',
204
- // expiration: { days: '10' },
205
- // abortIncompleteMultipartUpload: { daysAfterInitiation: '10' }
206
- // }
207
- // ]
226
+ force : true ,
227
+ lifecycle : [
228
+ {
229
+ status : 'Enabled' ,
230
+ id : 'deleteObject' ,
231
+ filter : '' ,
232
+ expiration : { days : '10' } ,
233
+ abortIncompleteMultipartUpload : { daysAfterInitiation : '10' }
234
+ }
235
+ ]
208
236
} )
209
237
}
210
238
211
239
// 上传代码
212
- if ( ! inputs . code || inputs . code . object ) {
240
+ if ( ! inputs . code . object ) {
213
241
const object = `${ inputs . name } -${ Math . floor ( Date . now ( ) / 1000 ) } .zip`
214
242
inputs . code . object = object
215
243
await cos . upload ( {
@@ -218,39 +246,46 @@ class Express extends Component {
218
246
key : inputs . code . object
219
247
} )
220
248
}
249
+ this . state . bucket = inputs . code . bucket
250
+ this . state . object = inputs . code . object
251
+
221
252
return {
222
253
bucket : inputs . code . bucket ,
223
254
object : inputs . code . object
224
255
}
225
256
}
226
257
227
258
async deployFunction ( credentials , inputs , regionList ) {
228
- // 打包代码
229
- // todo 打包这里还没有仔细看,可能这样用的不对
230
- const packageDir = await packageExpress ( this , inputs )
259
+ // if set bucket and object not pack code
260
+ let packageDir
261
+ if ( ! inputs . code . bucket || ! inputs . code . object ) {
262
+ packageDir = await packageExpress ( this , inputs )
263
+ }
231
264
232
265
// 上传代码到COS
233
266
const uploadCodeHandler = [ ]
234
267
const outputs = { }
268
+
235
269
for ( let eveRegionIndex = 0 ; eveRegionIndex < regionList . length ; eveRegionIndex ++ ) {
270
+ const curRegion = regionList [ eveRegionIndex ]
236
271
const funcDeployer = async ( ) => {
237
- const { bucket, object } = await this . uploadCodeToCos (
238
- credentials ,
239
- inputs ,
240
- regionList [ eveRegionIndex ] ,
241
- packageDir
242
- )
243
- const scf = new Scf ( credentials , regionList [ eveRegionIndex ] )
272
+ const code = await this . uploadCodeToCos ( credentials , inputs , curRegion , packageDir )
273
+ const scf = new Scf ( credentials , curRegion )
244
274
const tempInputs = {
245
275
...inputs ,
246
- code : {
247
- bucket,
248
- object
249
- }
276
+ code
277
+ }
278
+ const scfOutput = await scf . deploy ( tempInputs )
279
+ outputs [ curRegion ] = {
280
+ functionName : scfOutput . FunctionName ,
281
+ runtime : scfOutput . Runtime ,
282
+ namespace : scfOutput . Namespace
250
283
}
251
- console . log ( 'tempInputs' , tempInputs )
252
284
253
- outputs [ regionList [ eveRegionIndex ] ] = await scf . deploy ( tempInputs )
285
+ this . state [ curRegion ] = {
286
+ ...( this . state [ curRegion ] ? this . state [ curRegion ] : { } ) ,
287
+ ...outputs [ curRegion ]
288
+ }
254
289
}
255
290
uploadCodeHandler . push ( funcDeployer ( ) )
256
291
}
@@ -261,7 +296,31 @@ class Express extends Component {
261
296
262
297
async deployApigateway ( credentials , inputs , regionList ) {
263
298
const apigw = new MultiApigw ( credentials , regionList )
264
- const outputs = await apigw . deploy ( inputs )
299
+ inputs . oldState = {
300
+ apiList : ( this . state [ regionList [ 0 ] ] && this . state [ regionList [ 0 ] ] . apiList ) || [ ]
301
+ }
302
+ const apigwOutputs = await apigw . deploy ( inputs )
303
+ const outputs = { }
304
+ Object . keys ( apigwOutputs ) . forEach ( ( curRegion ) => {
305
+ const curOutput = apigwOutputs [ curRegion ]
306
+ outputs [ curRegion ] = {
307
+ serviceId : curOutput . serviceId ,
308
+ subDomain : curOutput . subDomain ,
309
+ environment : curOutput . environment ,
310
+ url : `${ this . getDefaultProtocol ( inputs . protocols ) } ://${ curOutput . subDomain } /${
311
+ curOutput . environment
312
+ } /`
313
+ }
314
+ if ( curOutput . customDomains ) {
315
+ outputs [ curRegion ] . customDomains = curOutput . customDomains
316
+ }
317
+ this . state [ curRegion ] = {
318
+ created : curOutput . created ,
319
+ ...( this . state [ curRegion ] ? this . state [ curRegion ] : { } ) ,
320
+ ...outputs [ curRegion ] ,
321
+ apiList : curOutput . apiList
322
+ }
323
+ } )
265
324
return outputs
266
325
}
267
326
@@ -271,20 +330,13 @@ class Express extends Component {
271
330
}
272
331
273
332
async deploy ( inputs ) {
274
- console . log ( '++++++++++' )
275
- console . log ( 'state' , this . state )
276
- console . log ( '++++++++++' )
277
-
278
333
console . log ( `Deploying Express App...` )
279
334
280
335
// 获取腾讯云密钥信息
281
336
const credentials = this . credentials . tencent
282
337
283
338
// 对Inputs内容进行标准化
284
- const { region, functionConf, apigatewayConf, cnsConf } = await this . prepareInputs ( inputs )
285
-
286
- // 获取地域列表
287
- const regionList = typeof inputs . region == 'string' ? [ inputs . region ] : inputs . region
339
+ const { regionList, functionConf, apigatewayConf, cnsConf } = await this . prepareInputs ( inputs )
288
340
289
341
// 部署函数 + API网关
290
342
const outputs = { }
@@ -307,21 +359,36 @@ class Express extends Component {
307
359
return outputs
308
360
}
309
361
310
- async remove ( ) {
311
- // const clients = getClients(
312
- // process.env.SERVERLESS_PLATFORM_VENDOR === 'tencent'
313
- // ? this.credentials.tencent
314
- // : this.credentials.aws,
315
- // this.state.region
316
- // )
317
- //
318
- // await removeAllRoles(this, clients)
319
- // await removeLambda(this, clients)
320
- // await removeDomain(this, clients)
321
- // await removeApi(this, clients)
322
- //
323
- // this.state = {}
324
- // return {}
362
+ async remove ( inputs = { } ) {
363
+ console . log ( `Removing Express App...` )
364
+
365
+ const { regionList } = await this . prepareInputs ( inputs )
366
+ const { state } = this
367
+ const credentials = this . credentials . tencent
368
+ const removeHandlers = [ ]
369
+ for ( let i = 0 ; i < regionList . length ; i ++ ) {
370
+ const curRegion = regionList [ i ]
371
+ const curState = state [ curRegion ]
372
+ const scf = new Scf ( credentials , curRegion )
373
+ const apigw = new Apigw ( credentials , curRegion )
374
+ const handler = async ( ) => {
375
+ await scf . remove ( {
376
+ functionName : curState . functionName ,
377
+ namespace : curState . namespace
378
+ } )
379
+ await apigw . remove ( {
380
+ created : curState . created ,
381
+ environment : curState . environment ,
382
+ serviceId : curState . serviceId ,
383
+ apiList : curState . apiList ,
384
+ customDomains : curState . customDomains
385
+ } )
386
+ }
387
+ removeHandlers . push ( handler ( ) )
388
+ }
389
+
390
+ await Promise . all ( removeHandlers )
391
+ this . state = { }
325
392
}
326
393
}
327
394
0 commit comments