1
1
const { Component } = require ( '@serverless/core' )
2
- const { MultiApigw , Scf, Apigw, Cns } = require ( 'tencent-component-toolkit' )
2
+ const { Scf, Apigw, Cns, Cam } = require ( 'tencent-component-toolkit' )
3
3
const { TypeError } = require ( 'tencent-component-toolkit/src/utils/error' )
4
- const { uploadCodeToCos, getDefaultProtocol, deleteRecord , prepareInputs } = require ( './utils' )
4
+ const { uploadCodeToCos, getDefaultProtocol, prepareInputs , deepClone } = require ( './utils' )
5
5
const CONFIGS = require ( './config' )
6
6
7
7
class ServerlessComponent extends Component {
@@ -27,135 +27,153 @@ class ServerlessComponent extends Component {
27
27
}
28
28
29
29
async deployFunction ( credentials , inputs , regionList ) {
30
- const uploadCodeHandler = [ ]
30
+ if ( ! inputs . role ) {
31
+ try {
32
+ const camClient = new Cam ( credentials )
33
+ const roleExist = await camClient . CheckSCFExcuteRole ( )
34
+ if ( roleExist ) {
35
+ inputs . role = 'QCS_SCFExcuteRole'
36
+ }
37
+ } catch ( e ) {
38
+ // no op
39
+ }
40
+ }
41
+
31
42
const outputs = { }
32
43
const appId = this . getAppId ( )
33
44
34
- for ( let eveRegionIndex = 0 ; eveRegionIndex < regionList . length ; eveRegionIndex ++ ) {
35
- const curRegion = regionList [ eveRegionIndex ]
36
- const funcDeployer = async ( ) => {
37
- const code = await uploadCodeToCos ( this , appId , credentials , inputs , curRegion )
38
- const scf = new Scf ( credentials , curRegion )
39
- const tempInputs = {
40
- ...inputs ,
41
- code
42
- }
43
- const scfOutput = await scf . deploy ( tempInputs )
44
- outputs [ curRegion ] = {
45
- functionName : scfOutput . FunctionName ,
46
- runtime : scfOutput . Runtime ,
47
- namespace : scfOutput . Namespace
48
- }
49
-
50
- this . state [ curRegion ] = {
51
- ...( this . state [ curRegion ] ? this . state [ curRegion ] : { } ) ,
52
- ...outputs [ curRegion ]
53
- }
45
+ const funcDeployer = async ( curRegion ) => {
46
+ const code = await uploadCodeToCos ( this , appId , credentials , inputs , curRegion )
47
+ const scf = new Scf ( credentials , curRegion )
48
+ const tempInputs = {
49
+ ...inputs ,
50
+ code
51
+ }
52
+ const scfOutput = await scf . deploy ( deepClone ( tempInputs ) )
53
+ outputs [ curRegion ] = {
54
+ functionName : scfOutput . FunctionName ,
55
+ runtime : scfOutput . Runtime ,
56
+ namespace : scfOutput . Namespace
57
+ }
54
58
55
- // default version is $LATEST
56
- outputs [ curRegion ] . lastVersion = scfOutput . LastVersion
57
- ? scfOutput . LastVersion
58
- : this . state . lastVersion || '$LATEST'
59
-
60
- // default traffic is 1.0, it can also be 0, so we should compare to undefined
61
- outputs [ curRegion ] . traffic =
62
- scfOutput . Traffic !== undefined
63
- ? scfOutput . Traffic
64
- : this . state . traffic !== undefined
65
- ? this . state . traffic
66
- : 1
67
-
68
- if ( outputs [ curRegion ] . traffic !== 1 && scfOutput . ConfigTrafficVersion ) {
69
- outputs [ curRegion ] . configTrafficVersion = scfOutput . ConfigTrafficVersion
70
- this . state . configTrafficVersion = scfOutput . ConfigTrafficVersion
71
- }
59
+ this . state [ curRegion ] = {
60
+ ...( this . state [ curRegion ] ? this . state [ curRegion ] : { } ) ,
61
+ ...outputs [ curRegion ]
62
+ }
72
63
73
- this . state . lastVersion = outputs [ curRegion ] . lastVersion
74
- this . state . traffic = outputs [ curRegion ] . traffic
64
+ // default version is $LATEST
65
+ outputs [ curRegion ] . lastVersion = scfOutput . LastVersion
66
+ ? scfOutput . LastVersion
67
+ : this . state . lastVersion || '$LATEST'
68
+
69
+ // default traffic is 1.0, it can also be 0, so we should compare to undefined
70
+ outputs [ curRegion ] . traffic =
71
+ scfOutput . Traffic !== undefined
72
+ ? scfOutput . Traffic
73
+ : this . state . traffic !== undefined
74
+ ? this . state . traffic
75
+ : 1
76
+
77
+ if ( outputs [ curRegion ] . traffic !== 1 && scfOutput . ConfigTrafficVersion ) {
78
+ outputs [ curRegion ] . configTrafficVersion = scfOutput . ConfigTrafficVersion
79
+ this . state . configTrafficVersion = scfOutput . ConfigTrafficVersion
75
80
}
76
- uploadCodeHandler . push ( funcDeployer ( ) )
81
+
82
+ this . state . lastVersion = outputs [ curRegion ] . lastVersion
83
+ this . state . traffic = outputs [ curRegion ] . traffic
84
+ }
85
+
86
+ for ( let i = 0 ; i < regionList . length ; i ++ ) {
87
+ const curRegion = regionList [ i ]
88
+ await funcDeployer ( curRegion )
77
89
}
78
- await Promise . all ( uploadCodeHandler )
79
90
this . save ( )
80
91
return outputs
81
92
}
82
93
94
+ // try to add dns record
95
+ async tryToAddDnsRecord ( credentials , customDomains ) {
96
+ try {
97
+ const cns = new Cns ( credentials )
98
+ for ( let i = 0 ; i < customDomains . length ; i ++ ) {
99
+ const item = customDomains [ i ]
100
+ if ( item . domainPrefix ) {
101
+ await cns . deploy ( {
102
+ domain : item . subDomain . replace ( `${ item . domainPrefix } .` , '' ) ,
103
+ records : [
104
+ {
105
+ subDomain : item . domainPrefix ,
106
+ recordType : 'CNAME' ,
107
+ recordLine : '默认' ,
108
+ value : item . cname ,
109
+ ttl : 600 ,
110
+ mx : 10 ,
111
+ status : 'enable'
112
+ }
113
+ ]
114
+ } )
115
+ }
116
+ }
117
+ } catch ( e ) {
118
+ console . log ( 'METHOD_tryToAddDnsRecord' , e . message )
119
+ }
120
+ }
121
+
83
122
async deployApigateway ( credentials , inputs , regionList ) {
84
123
if ( inputs . isDisabled ) {
85
124
return { }
86
125
}
87
- const apigw = new MultiApigw ( credentials , regionList )
88
- const oldState = this . state [ regionList [ 0 ] ] || { }
89
- inputs . oldState = {
90
- apiList : oldState . apiList || [ ] ,
91
- customDomains : oldState . customDomains || [ ]
126
+
127
+ const getServiceId = ( instance , region ) => {
128
+ const regionState = instance . state [ region ]
129
+ return inputs . serviceId || ( regionState && regionState . serviceId )
92
130
}
93
- const apigwOutputs = await apigw . deploy ( inputs )
94
- const outputs = { }
95
- Object . keys ( apigwOutputs ) . forEach ( ( curRegion ) => {
96
- const curOutput = apigwOutputs [ curRegion ]
97
- outputs [ curRegion ] = {
98
- serviceId : curOutput . serviceId ,
99
- subDomain : curOutput . subDomain ,
100
- environment : curOutput . environment ,
101
- url : `${ getDefaultProtocol ( inputs . protocols ) } ://${ curOutput . subDomain } /${
102
- curOutput . environment
103
- } /`
104
- }
105
- if ( curOutput . customDomains ) {
106
- outputs [ curRegion ] . customDomains = curOutput . customDomains
107
- }
108
- this . state [ curRegion ] = {
109
- created : curOutput . created ,
110
- ...( this . state [ curRegion ] ? this . state [ curRegion ] : { } ) ,
111
- ...outputs [ curRegion ] ,
112
- apiList : curOutput . apiList
113
- }
114
- } )
115
- this . save ( )
116
- return outputs
117
- }
118
131
119
- async deployCns ( credentials , inputs , regionList , apigwOutputs ) {
120
- const cns = new Cns ( credentials )
121
- const cnsRegion = { }
132
+ const deployTasks = [ ]
133
+ const outputs = { }
122
134
regionList . forEach ( ( curRegion ) => {
123
- const curApigwOutput = apigwOutputs [ curRegion ]
124
- cnsRegion [ curRegion ] = curApigwOutput . subDomain
125
- } )
135
+ const apigwDeployer = async ( ) => {
136
+ const apigw = new Apigw ( credentials , curRegion )
126
137
127
- const state = [ ]
128
- const outputs = { }
129
- const tempJson = { }
130
- for ( let i = 0 ; i < inputs . length ; i ++ ) {
131
- const curCns = inputs [ i ]
132
- for ( let j = 0 ; j < curCns . records . length ; j ++ ) {
133
- curCns . records [ j ] . value =
134
- cnsRegion [ curCns . records [ j ] . value . replace ( 'temp_value_about_' , '' ) ]
135
- }
136
- const tencentCnsOutputs = await cns . deploy ( curCns )
137
- outputs [ curCns . domain ] = tencentCnsOutputs . DNS
138
- ? tencentCnsOutputs . DNS
139
- : 'The domain name has already been added.'
140
- tencentCnsOutputs . domain = curCns . domain
141
- state . push ( tencentCnsOutputs )
142
- }
138
+ const oldState = this . state [ curRegion ] || { }
139
+ const apigwInputs = {
140
+ ...inputs ,
141
+ oldState : {
142
+ apiList : oldState . apiList || [ ] ,
143
+ customDomains : oldState . customDomains || [ ]
144
+ }
145
+ }
146
+ // different region deployment has different service id
147
+ apigwInputs . serviceId = getServiceId ( this , curRegion )
148
+ const apigwOutput = await apigw . deploy ( deepClone ( apigwInputs ) )
149
+ outputs [ curRegion ] = {
150
+ serviceId : apigwOutput . serviceId ,
151
+ subDomain : apigwOutput . subDomain ,
152
+ environment : apigwOutput . environment ,
153
+ url : `${ getDefaultProtocol ( inputs . protocols ) } ://${ apigwOutput . subDomain } /${
154
+ apigwOutput . environment
155
+ } /`
156
+ }
143
157
144
- // 删除serverless创建的但是不在本次列表中
145
- try {
146
- for ( let i = 0 ; i < state . length ; i ++ ) {
147
- tempJson [ state [ i ] . domain ] = state [ i ] . records
148
- }
149
- const recordHistory = this . state . cns || [ ]
150
- for ( let i = 0 ; i < recordHistory . length ; i ++ ) {
151
- const delList = deleteRecord ( tempJson [ recordHistory [ i ] . domain ] , recordHistory [ i ] . records )
152
- if ( delList && delList . length > 0 ) {
153
- await cns . remove ( { deleteList : delList } )
158
+ if ( apigwOutput . customDomains ) {
159
+ // TODO: need confirm add cns authentication
160
+ if ( inputs . autoAddDnsRecord === true ) {
161
+ // await this.tryToAddDnsRecord(credentials, apigwOutput.customDomains)
162
+ }
163
+ outputs [ curRegion ] . customDomains = apigwOutput . customDomains
164
+ }
165
+ this . state [ curRegion ] = {
166
+ created : true ,
167
+ ...( this . state [ curRegion ] ? this . state [ curRegion ] : { } ) ,
168
+ ...outputs [ curRegion ] ,
169
+ apiList : apigwOutput . apiList
154
170
}
155
171
}
156
- } catch ( e ) { }
172
+ deployTasks . push ( apigwDeployer ( ) )
173
+ } )
174
+
175
+ await Promise . all ( deployTasks )
157
176
158
- this . state [ 'cns' ] = state
159
177
this . save ( )
160
178
return outputs
161
179
}
@@ -166,7 +184,7 @@ class ServerlessComponent extends Component {
166
184
const credentials = this . getCredentials ( )
167
185
168
186
// 对Inputs内容进行标准化
169
- const { regionList, functionConf, apigatewayConf, cnsConf } = await prepareInputs (
187
+ const { regionList, functionConf, apigatewayConf } = await prepareInputs (
170
188
this ,
171
189
credentials ,
172
190
inputs
@@ -198,11 +216,6 @@ class ServerlessComponent extends Component {
198
216
outputs [ 'scf' ] = functionOutputs
199
217
}
200
218
201
- // cns depends on apigw, so if disabled apigw, just ignore it.
202
- if ( cnsConf . length > 0 && apigatewayConf . isDisabled !== true ) {
203
- outputs [ 'cns' ] = await this . deployCns ( credentials , cnsConf , regionList , apigwOutputs )
204
- }
205
-
206
219
this . state . region = regionList [ 0 ]
207
220
this . state . regionList = regionList
208
221
this . state . lambdaArn = functionConf . name
0 commit comments