UNPKG

3.33 kBJavaScriptView Raw
1'use strict';
2
3class ServerlessAWSPseudoParameters {
4 constructor(serverless, options) {
5 this.serverless = serverless;
6 this.options = options;
7 this.hooks = {
8 'before:deploy:deploy': this.addParameters.bind(this),
9 };
10 this.skipRegionReplace = get(serverless.service, 'custom.pseudoParameters.skipRegionReplace', false)
11 }
12
13 addParameters() {
14
15 const resources = this.serverless.service.provider.compiledCloudFormationTemplate.Resources;
16 const skipRegionReplace = this.skipRegionReplace;
17 const consoleLog = this.serverless.cli.consoleLog;
18
19 consoleLog(yellow(underline('AWS Pseudo Parameters')));
20
21 if (skipRegionReplace) {
22 consoleLog('Skipping automatic replacement of regions with account region!');
23 }
24
25 // loop through all resources, and check all (string) properties for any #{AWS::}
26 // reference. If found, replace the value with an Fn::Sub reference
27 Object.keys(resources).forEach(identifier => replaceChildNodes(resources[identifier].Properties, identifier));
28
29 function isDict(v) {
30 return typeof v === 'object' && v !== null && !(v instanceof Array) && !(v instanceof Date);
31 }
32
33 function isArray(v) {
34 return Object.prototype.toString.call(v) === '[object Array]'
35 }
36
37 function regions() {
38 return [
39 'eu-west-1',
40 'eu-west-2',
41 'us-east-1',
42 'us-east-2',
43 'us-west-2',
44 'ap-south-1',
45 'ap-northeast-2',
46 'ap-southeast-2',
47 'ap-northeast-1',
48 'eu-central-1'
49 ]
50 }
51
52 function containsRegion(v) {
53 return new RegExp(regions().join("|")).test(v);
54 }
55
56 function replaceChildNodes(dictionary, name) {
57 Object.keys(dictionary).forEach((key) => {
58
59 let value = dictionary[key];
60 // if a region name is mentioned, replace it with a reference (unless we are skipping automatic replacements)
61 if (typeof value === 'string' && !skipRegionReplace && containsRegion(value)) {
62 const regionFinder = new RegExp(regions().join("|"));
63 value = value.replace(regionFinder, '#{AWS::Region}');
64 }
65
66 // we only want to possibly replace strings with an Fn::Sub
67 if (typeof value === 'string' && value.search(/#{AWS::([a-zA-Z]+)}/) >= 0) {
68 const aws_regex = /#{AWS::([a-zA-Z]+)}/g;
69
70 dictionary[key] = {
71 "Fn::Sub": value.replace(aws_regex, '${AWS::$1}')
72 };
73
74 // do some fancy logging
75 let m = aws_regex.exec(value);
76 while (m) {
77 consoleLog('AWS Pseudo Parameter: ' + name + '::' + key + ' Replaced ' + yellow(m[1]) + ' with ' + yellow('${AWS::' + m[1] + '}'));
78 m = aws_regex.exec(value);
79 }
80 }
81
82 // dicts and arrays need to be looped through
83 if (isDict(value) || isArray(value)) {
84 dictionary[key] = replaceChildNodes(value, name + '::' + key);
85 }
86
87 });
88 return dictionary;
89 }
90
91 function yellow(str) {
92 return '\u001B[33m' + str + '\u001B[39m';
93 }
94
95 function underline(str) {
96 return '\u001B[4m' + str + '\u001B[24m';
97 }
98 }
99}
100
101function get(obj, path, def) {
102 return path.split('.').filter(Boolean).every(step => !(step && (obj = obj[step]) === undefined)) ? obj : def;
103}
104
105module.exports = ServerlessAWSPseudoParameters;