Skip to content

Commit 9b1a731

Browse files
authored
Merge pull request #78 from aliyun/add_custom_domain_support
add custom domain support
2 parents 1e20f30 + dbe5eb2 commit 9b1a731

9 files changed

Lines changed: 204 additions & 32 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
ROSTemplateFormatVersion: '2015-09-01'
2+
Transform: 'Aliyun::Serverless-2018-04-03'
3+
Resources:
4+
fun.cn-shanghai.1221968287646227.cname-test.fc.aliyun-inc.com:
5+
Type: 'Aliyun::Serverless::CustomDomain'
6+
Properties:
7+
Protocol: HTTP
8+
RouteConfig:
9+
routes:
10+
'/a':
11+
serviceName: serviceA
12+
functionName: functionA
13+
'/b':
14+
serviceName: serviceB
15+
functionName: functionB
16+

lib/deploy/deploy-by-tpl.js

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ const readFile = util.promisify(fs.readFile);
1616

1717
let {
1818
makeApi, makeApiTrigger, makeFunction,
19-
makeGroup, makeOtsTable, makeOtsInstance,
19+
makeGroup, makeOtsTable, makeOtsInstance,
2020
makeOtsTrigger, makeService, makeTrigger,
21-
makeSlsProject, makeLogstore, makeLogstoreIndex
21+
makeSlsProject, makeLogstore, makeLogstoreIndex, makeCustomDomain
2222
} = require('./deploy-support');
2323

2424
let {
@@ -89,7 +89,7 @@ async function deployFunctions(serviceName, serviceDefinition) {
8989
if ((v || {}).Type === 'Aliyun::Serverless::Function') {
9090
console.log(`\tWaiting for function ${k} to be deployed...`);
9191
await deployFunction(serviceName, k, v);
92-
console.log(green(`\tfunction ${k} deploy success` ));
92+
console.log(green(`\tfunction ${k} deploy success`));
9393
}
9494
}
9595
}
@@ -98,16 +98,16 @@ async function deployPolicy(serviceName, roleName, policy, curCount) {
9898
if (typeof policy === 'string') {
9999
await attachPolicyToRole(policy, roleName);
100100
return curCount;
101-
}
101+
}
102102

103103
const profile = await getProfile();
104104

105105
const policyName = nomalizeRoleOrPoliceName(`AliyunFcGeneratedServicePolicy-${profile.defaultRegion}-${serviceName}${curCount}`);
106106

107107
await makeAndAttachPolicy(policyName, policy, roleName);
108-
108+
109109
return curCount + 1;
110-
110+
111111
}
112112

113113
async function deployPolicies(serviceName, roleName, policies) {
@@ -141,6 +141,7 @@ async function deployFcService(serviceName, serviceDefinition) {
141141
} catch(ex) {
142142
throw new Error('The role you provided is not correct. You must provide the correct role arn.');
143143
}
144+
144145
createRoleIfNotExist = false;
145146
} else {
146147
roleName = `aliyunfcgeneratedrole-${profile.defaultRegion}-${serviceName}`;
@@ -150,11 +151,11 @@ async function deployFcService(serviceName, serviceDefinition) {
150151

151152
const role = await makeRole(roleName, createRoleIfNotExist);
152153

153-
if ( ! roleArn && policies ) { // if roleArn exist, then ignore polices
154+
if (!roleArn && policies) { // if roleArn exist, then ignore polices
154155
await deployPolicies(serviceName, roleName, policies);
155156
}
156157

157-
if ( ! roleArn && vpcConfig) {
158+
if (!roleArn && vpcConfig) {
158159
await attachPolicyToRole('AliyunECSNetworkInterfaceManagementAccess', roleName);
159160
}
160161

@@ -177,7 +178,7 @@ async function deployFcService(serviceName, serviceDefinition) {
177178
}
178179
} else if (logConfig.LogStore || logConfig.Project) {
179180
throw new Error('LogStore and Project must both exist');
180-
}
181+
}
181182

182183
await makeService({
183184
serviceName,
@@ -187,7 +188,7 @@ async function deployFcService(serviceName, serviceDefinition) {
187188
logConfig,
188189
vpcConfig
189190
});
190-
191+
191192
await deployFunctions(serviceName, serviceDefinition);
192193
}
193194

@@ -213,11 +214,30 @@ async function deployLogstore(projectName, logstoreDefinition) {
213214

214215
await deployLogstoreDefaultIndex(projectName, logstoreName);
215216

216-
console.log(green(`\tlog serivce logstore ${logstoreName} deploy success` ));
217+
console.log(green(`\tlog serivce logstore ${logstoreName} deploy success`));
217218
}
218219
}
219220
}
220221

222+
async function deployCustomDomain(domainName, domainDefinition) {
223+
const properties = (domainDefinition.Properties || {});
224+
const protocol = properties.Protocol;
225+
const tplRouteConfig = properties.RouteConfig.routes;
226+
var routes = [];
227+
var transRoute = Object.entries(tplRouteConfig);
228+
for (var i of transRoute) {
229+
i[1].path = i[0];
230+
routes.push(i[1]);
231+
}
232+
var routeConfig = {};
233+
routeConfig.routes = routes;
234+
235+
await makeCustomDomain({
236+
domainName,
237+
protocol,
238+
routeConfig,
239+
});
240+
}
221241

222242

223243
async function deployLogs(resourcesDefinition) {
@@ -228,20 +248,20 @@ async function deployLogs(resourcesDefinition) {
228248

229249
const description = properties.Description || '';
230250
await makeSlsProject(projectName, description);
231-
251+
232252
await deployLogstore(projectName, v);
233-
console.log(green(`log serivce project ${projectName} deploy success\n` ));
253+
console.log(green(`log serivce project ${projectName} deploy success\n`));
234254
}
235255
}
236256
}
237257

238-
async function deployTablestore(instanceName, resourceDefinition) {
258+
async function deployTablestore(instanceName, resourceDefinition) {
239259
const properties = (resourceDefinition || {}).Properties;
240260
if (properties) {
241261
const clusterType = (properties || {}).ClusterType;
242262
const description = (properties || {}).Description;
243263
await makeOtsInstance(instanceName, clusterType, description);
244-
}
264+
}
245265

246266
for (const [k, v] of Object.entries(resourceDefinition)) {
247267
if ((v || {}).Type === 'Aliyun::Serverless::TableStore::Table') {
@@ -308,7 +328,7 @@ async function deployApigateway(name, { apiDefinition, template, tplPath }) {
308328
if (swaggerContent) {
309329
for (const [k, v] of Object.entries(swaggerContent)) {
310330
if (!['openapi', 'info', 'components'].includes(k)) {
311-
331+
312332
const apiGroup = await makeGroup({
313333
name,
314334
description: `api group for function compute`
@@ -317,12 +337,12 @@ async function deployApigateway(name, { apiDefinition, template, tplPath }) {
317337
const fcDefinition = methodDefinition['x-aliyun-apigateway-fc'];
318338

319339
let roleName;
320-
if ( fcDefinition.role ) {
340+
if (fcDefinition.role) {
321341
roleName = extractFcRole(fcDefinition.role);
322342
} else {
323343
roleName = `AliyunFcGeneratedApiGatewayRole`;
324344
}
325-
345+
326346
const role = await makeRole(roleName, true, 'API Gateway access FunctionCompute', {
327347
'Statement': [
328348
{
@@ -346,7 +366,7 @@ async function deployApigateway(name, { apiDefinition, template, tplPath }) {
346366
const apiName = methodDefinition['x-aliyun-apigateway-api-name'] || `${k.replace(/^\//, '').replace(/(\[|\])/g, '').replace(/\//g, '_')}_${method}`;
347367

348368
const { serviceName, functionName } = extractFcArn(fcDefinition.arn);
349-
369+
350370
const serviceTimeout = fcDefinition.timeout || 3000;
351371

352372
const resultConfig = {
@@ -381,7 +401,7 @@ async function deployApigateway(name, { apiDefinition, template, tplPath }) {
381401
visibility: methodDefinition['x-aliyun-apigateway-visibility'],
382402
requestConfig,
383403
resultConfig,
384-
constantParameters,
404+
constantParameters,
385405
description: methodDefinition['x-aliyun-apigateway-description']
386406
});
387407
}
@@ -408,21 +428,25 @@ async function deploy(tplPath) {
408428
if (resource.Type === 'Aliyun::Serverless::Service') {
409429
console.log(`Waiting for service ${name} to be deployed...`);
410430
await deployFcService(name, resource);
411-
console.log(green(`service ${name} deploy success\n` ));
431+
console.log(green(`service ${name} deploy success\n`));
412432
} else if (resource.Type === 'Aliyun::Serverless::Api') {
413433
console.log(`Waiting for api gateway ${name} to be deployed...`);
414434
await deployApigateway(name, {
415435
apiDefinition: resource,
416436
template: tpl,
417437
tplPath
418438
});
419-
console.log(green(`api gateway ${name} deploy success\n` ));
439+
console.log(green(`api gateway ${name} deploy success\n`));
420440
} else if (resource.Type === 'Aliyun::Serverless::TableStore') {
421441
console.log(`Waiting for table store ${name} to be deployed...`);
422442
await deployTablestore(name, resource);
423-
console.log(green(`table store ${name} deploy success\n` ));
443+
console.log(green(`table store ${name} deploy success\n`));
424444
} else if (resource.Type === 'Aliyun::Serverless::Log') {
425445
// ignore, done by deployLogs
446+
} else if (resource.Type === 'Aliyun::Serverless::CustomDomain') {
447+
console.log(`Waiting for custom domain ${name} to be deployed...`);
448+
await deployCustomDomain(name, resource);
449+
console.log(green(`custom domain ${name} deploy success\n`));
426450
} else {
427451
console.log('unknown resource %s', name);
428452
}

lib/deploy/deploy-support.js

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,50 @@ async function makeTrigger({
522522
return trigger;
523523
}
524524

525+
526+
async function makeCustomDomain({domainName,
527+
protocol,
528+
routeConfig
529+
}) {
530+
const fc = await getFcClient();
531+
var customDomain;
532+
await promiseRetry(async (retry, times) => {
533+
try {
534+
customDomain = await fc.getCustomDomain(domainName);
535+
} catch (ex) {
536+
if (ex.code !== 'DomainNameNotFound') {
537+
console.log(red(`\tretry ${times} times`));
538+
retry(ex);
539+
}
540+
}
541+
}, retryOptions);
542+
543+
const options = {
544+
protocol,
545+
};
546+
547+
if ( routeConfig ) {
548+
Object.assign(options, {
549+
routeConfig
550+
});
551+
}
552+
553+
await promiseRetry(async (retry, times) => {
554+
try {
555+
if (!customDomain) {
556+
customDomain = await fc.createCustomDomain(domainName, options);
557+
} else {
558+
customDomain = await fc.updateCustomDomain(domainName, options);
559+
}
560+
} catch (ex) {
561+
console.log(red(`\tretry ${times} times`));
562+
retry(ex);
563+
}
564+
}, retryOptions);
565+
566+
return customDomain;
567+
}
568+
525569
async function makeGroup(group) {
526570
const ag = await getCloudApiClient();
527571

@@ -849,5 +893,5 @@ module.exports = {
849893
makeApi, makeApiTrigger, makeFunction,
850894
makeGroup, makeOtsTable, makeOtsInstance,
851895
makeOtsTrigger, makeService, makeTrigger, makeSlsProject,
852-
makeLogstore, makeLogstoreIndex
896+
makeLogstore, makeLogstoreIndex, makeCustomDomain
853897
};
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
const customDomainResourceSchema = {
4+
'$id': '/Resources/CustomDomain',
5+
'type': 'object',
6+
'description': 'CustomDomain',
7+
'properties': {
8+
'Type': {
9+
'type': 'string',
10+
'const': 'Aliyun::Serverless::CustomDomain'
11+
},
12+
'Properties': {
13+
'type': 'object',
14+
'properties': {
15+
'Protocol': {
16+
'type': 'string'
17+
},
18+
'RouteConfig': {
19+
'type': 'object',
20+
'properties': {
21+
'Routes': {
22+
'type': 'object',
23+
'patternProperties': {
24+
'^/': {
25+
'anyOf': [
26+
{ '$ref': '/Resources/CustomDomain/PathConfig' }
27+
]
28+
}
29+
}
30+
}
31+
}
32+
}
33+
}
34+
}
35+
},
36+
'required': ['Type']
37+
};
38+
39+
module.exports = customDomainResourceSchema;

lib/validate/schema/path-config.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
const pathConfigResourceSchema = {
4+
'$id': '/Resources/CustomDomain/PathConfig',
5+
'type': 'object',
6+
'properties': {
7+
'Type': {
8+
'type': 'string'
9+
},
10+
'Properties': {
11+
'type': 'object',
12+
'properties': {
13+
'ServiceName': {
14+
'type': 'string'
15+
},
16+
'FunctionName': {
17+
'type': 'string'
18+
}
19+
}
20+
}
21+
}
22+
};
23+
24+
module.exports = pathConfigResourceSchema;

lib/validate/schema/ros.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ const rosSchema = {
1616
'Resources': {
1717
'type': 'object',
1818
'patternProperties': {
19-
'^[a-zA-Z_][a-zA-Z0-9_-]{0,127}$': {
19+
'^[a-zA-Z_][a-zA-Z.0-9_-]{0,127}$': {
2020
anyOf: [
2121
{ '$ref': '/Resources/Service' },
2222
{ '$ref': '/Resources/Api' },
2323
{ '$ref': '/Resources/TableStore' },
24-
{ '$ref': '/Resources/Log' }
24+
{ '$ref': '/Resources/Log' },
25+
{ '$ref': '/Resources/CustomDomain'}
2526
]
2627
}
2728
}

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)