1 | const globby = require( "globby" );
|
2 | const fs = require( "fs" );
|
3 | const request = require( "request" );
|
4 | const path = require( "path" );
|
5 | const AWS = require( "aws-sdk" );
|
6 | const _ = require( "lodash" );
|
7 | const cmd = require( "node-cmd" );
|
8 |
|
9 | function addLambdaEnvironmentVariablesToProcess ( environmentVariables ) {
|
10 | if ( environmentVariables ) {
|
11 | Object.keys( environmentVariables ).forEach( ( key ) => {
|
12 | process.env[ key ] = environmentVariables[ key ];
|
13 | });
|
14 | }
|
15 | }
|
16 |
|
17 | function authenticate () {
|
18 |
|
19 | return new Promise( ( resolve, reject ) => {
|
20 |
|
21 | if ( process.env.COLLY__USE_BASTION ) {
|
22 |
|
23 | console.log( "Authenticating via bastion servers..." );
|
24 |
|
25 | authenticateAgainstBastionService()
|
26 | .then( resolve );
|
27 | return;
|
28 |
|
29 | }
|
30 |
|
31 | if ( process.env.AWS_PROFILE ) {
|
32 |
|
33 | console.log( "Authenticating via local AWS profile..." );
|
34 | resolve();
|
35 | return;
|
36 |
|
37 | }
|
38 |
|
39 | reject( "No login credentials supplied" );
|
40 |
|
41 | });
|
42 |
|
43 | }
|
44 |
|
45 | function authenticateAgainstBastionService() {
|
46 |
|
47 | return new Promise( ( resolve, reject ) => {
|
48 |
|
49 | const projectConfig = getProjectConfig();
|
50 | const certPath = path.resolve( projectConfig.bastionService.certPath );
|
51 | const requestOptions = {
|
52 | url: projectConfig.bastionService.endpoint,
|
53 | agentOptions: {
|
54 | cert: fs.readFileSync( certPath ),
|
55 | key: fs.readFileSync( certPath ),
|
56 | ca: fs.readFileSync( projectConfig.bastionService.cloudServicesRoot )
|
57 | }
|
58 | };
|
59 |
|
60 | request.get( requestOptions, function ( error, response, body ) {
|
61 |
|
62 | if ( error || ( response && response.statusCode !== 200 ) ) {
|
63 |
|
64 | const statusCode = ( response && response.statusCode ) ? response.statusCode : 'no code';
|
65 | const errorMessage = `Unable to authenticate to AWS using the wormhole (Code: ${statusCode})`;
|
66 |
|
67 | reject( errorMessage );
|
68 |
|
69 | } else {
|
70 |
|
71 | const credentials = JSON.parse(body);
|
72 |
|
73 | process.env.AWS_ACCESS_KEY_ID = credentials.accessKeyId;
|
74 | process.env.AWS_SECRET_ACCESS_KEY = credentials.secretAccessKey;
|
75 | process.env.AWS_SESSION_TOKEN = credentials.sessionToken;
|
76 |
|
77 | resolve();
|
78 |
|
79 | }
|
80 |
|
81 | });
|
82 |
|
83 | });
|
84 |
|
85 | }
|
86 |
|
87 | function everythingAfterTheLastDot( dotDelimitedString ) {
|
88 | return dotDelimitedString.split(".").pop();
|
89 | }
|
90 |
|
91 | function getLambdaName ( nameOverride ) {
|
92 |
|
93 | const appendedToName = anyEnvButLive();
|
94 |
|
95 | return ( nameOverride || getLambdaConfigFile().name ) + appendedToName;
|
96 |
|
97 | }
|
98 |
|
99 | function anyEnvButLive () {
|
100 | return ( process.env.ENV !== "live" ) ? process.env.ENV.toUpperCase() : "";
|
101 | }
|
102 |
|
103 | function chooseProjectFile( envFiles, env ) {
|
104 | if ( env.toLowerCase() in envFiles ) {
|
105 | return envFiles[ env.toLowerCase() ];
|
106 | } else {
|
107 | console.log( "no env value defined" );
|
108 | throw new Error("`--env` parameter value has no matching colly file");
|
109 | }
|
110 | }
|
111 |
|
112 | function getLambdaConfigFilePath () {
|
113 | return `${process.env.COLLY__PROJECT_DIR}/${process.env.COLLY__LAMBDA_NAME}/function.json`;
|
114 | }
|
115 |
|
116 | function getLambdaConfigFile () {
|
117 | return JSON.parse( fs.readFileSync( getLambdaConfigFilePath() ) );
|
118 | }
|
119 |
|
120 | function getLambdaHandlerName () {
|
121 | const config = getLambdaConfigFile();
|
122 | return everythingAfterTheLastDot( config.handler );
|
123 | }
|
124 |
|
125 | function listEnvFiles () {
|
126 |
|
127 | const path = `${process.env.COLLY__PROJECT_DIR}/colly*.json`;
|
128 | let opts = {
|
129 | "dot": true
|
130 | };
|
131 | if ( path.substring(0,1) === "/" ) {
|
132 | opts.cwd = "/";
|
133 | }
|
134 | const relativePaths = globby.sync( path );
|
135 | let envFiles = {};
|
136 | relativePaths.forEach( ( relativePath ) => {
|
137 |
|
138 | const fileName = relativePath.split( "/" ).pop();
|
139 | const fileNameParts = fileName.split(".");
|
140 | let envName;
|
141 | if ( fileName === "colly.json" ) {
|
142 | envName = "live";
|
143 | }
|
144 |
|
145 | if ( fileNameParts.length > 2 ) {
|
146 | envName = fileNameParts[ 1 ];
|
147 | }
|
148 |
|
149 | envFiles[ envName ] = fileName;
|
150 |
|
151 | });
|
152 | return envFiles;
|
153 | }
|
154 |
|
155 | function getProjectConfigFilePath () {
|
156 | return `${process.env.COLLY__PROJECT_DIR}/${ chooseProjectFile( listEnvFiles(), process.env.ENV ) }`;
|
157 | }
|
158 |
|
159 | function getProjectConfig() {
|
160 | return JSON.parse( fs.readFileSync( getProjectConfigFilePath() ) );
|
161 | }
|
162 |
|
163 | function getLambdaFilePath( altStartOfPath ) {
|
164 |
|
165 | const startOfPath = altStartOfPath || process.env.COLLY__PROJECT_DIR;
|
166 |
|
167 | const config = getLambdaConfigFile( process.env.COLLY__LAMBDA_NAME );
|
168 |
|
169 | const relativePathToLambdaFile = config.handler.split( "." ).slice( 0, -1 ).join( "." ) + ".js";
|
170 |
|
171 | return startOfPath + "/" + relativePathToLambdaFile;
|
172 |
|
173 | }
|
174 |
|
175 | function copyAllFilesToDistDir () {
|
176 | return new Promise( ( resolve, reject ) => {
|
177 | const webpack = require( "webpack" );
|
178 | const config = getLambdaConfigFile( process.env.COLLY__LAMBDA_NAME );
|
179 | const webpackOutput = getLambdaFilePath( "./dist" );
|
180 | webpack({
|
181 | "context": process.env.COLLY__PROJECT_DIR,
|
182 | "entry": getLambdaFilePath(),
|
183 | "output": {
|
184 | "filename": webpackOutput,
|
185 | "libraryTarget": "commonjs"
|
186 | },
|
187 | "target": "node",
|
188 | "externals": [ "aws-sdk" ]
|
189 | }, ( err, stats ) => {
|
190 | if ( err || stats.hasErrors() ) {
|
191 | reject( err );
|
192 | }
|
193 | console.log( stats.toString( {
|
194 | colors: true
|
195 | } ) );
|
196 | resolve( `./dist/${process.env.COLLY__LAMBDA_NAME}` );
|
197 | });
|
198 | });
|
199 | }
|
200 |
|
201 | function setOptions ( cliOptions ) {
|
202 |
|
203 | if ( cliOptions.env ) {
|
204 | process.env.ENV = cliOptions.env;
|
205 | }
|
206 |
|
207 | if ( cliOptions.name ) {
|
208 | process.env.COLLY__LAMBDA_NAME = cliOptions.name;
|
209 | }
|
210 |
|
211 | if ( cliOptions.event ) {
|
212 | process.env.COLLY__LAMBDA_EVENT_FILE = cliOptions.event;
|
213 | }
|
214 |
|
215 | if ( typeof cliOptions.local === "boolean" ) {
|
216 | process.env.COLLY__RUN_LAMBDA_LOCAL = cliOptions.local;
|
217 | }
|
218 |
|
219 | if ( cliOptions.use_bastion ) {
|
220 | process.env.COLLY__USE_BASTION = cliOptions.use_bastion;
|
221 | }
|
222 |
|
223 | if ( cliOptions.aws_profile ) {
|
224 | process.env.AWS_PROFILE = cliOptions.aws_profile;
|
225 | }
|
226 |
|
227 | if ( !process.env.COLLY__PROJECT_DIR ) {
|
228 | process.env.COLLY__PROJECT_DIR = process.cwd();
|
229 | }
|
230 |
|
231 | }
|
232 |
|
233 | function setAwsRegion () {
|
234 | const projectConfig = getProjectConfig();
|
235 | AWS.config.region = projectConfig.region;
|
236 | }
|
237 |
|
238 | function lastItemInArray ( item, arr ) {
|
239 | return _.last( arr ) === item;
|
240 | }
|
241 |
|
242 | function addValueToLambdaConfig ( DotDelimitedProperty, value ) {
|
243 |
|
244 | let config = getLambdaConfigFile( process.env.LAMBDA_NAME );
|
245 |
|
246 | const propertyChain = DotDelimitedProperty.split( "." );
|
247 |
|
248 | let referencedPropertyToEdit = config;
|
249 |
|
250 | propertyChain.forEach( ( property, i, a ) => {
|
251 |
|
252 | if ( !( property in referencedPropertyToEdit ) ) {
|
253 | referencedPropertyToEdit[ property ] = {};
|
254 | }
|
255 |
|
256 | if ( lastItemInArray( property, propertyChain ) ) {
|
257 | referencedPropertyToEdit[ property ] = value;
|
258 | } else {
|
259 | referencedPropertyToEdit = referencedPropertyToEdit[ property ];
|
260 | }
|
261 |
|
262 | });
|
263 |
|
264 | fs.writeFileSync( getLambdaConfigFilePath( process.env.LAMBDA_NAME ), JSON.stringify( config, null, " " ) );
|
265 |
|
266 | }
|
267 |
|
268 | function zipFile ( package ) {
|
269 |
|
270 | return new Promise( ( resolve, reject ) => {
|
271 |
|
272 | console.log( "Zipping the webpack output... " );
|
273 |
|
274 | cmd.get( `cd dist && zip -9 -r ${process.env.COLLY__LAMBDA_NAME}.zip ${process.env.COLLY__LAMBDA_NAME}`, ( err, stdout ) => {
|
275 |
|
276 | console.log( stdout );
|
277 |
|
278 | resolve( `${package}.zip` );
|
279 |
|
280 | });
|
281 |
|
282 | });
|
283 |
|
284 | }
|
285 |
|
286 | module.exports = {
|
287 | "addLambdaEnvironmentVariablesToProcess": addLambdaEnvironmentVariablesToProcess,
|
288 | "addValueToLambdaConfig": addValueToLambdaConfig,
|
289 | "anyEnvButLive": anyEnvButLive,
|
290 | "authenticate": authenticate,
|
291 | "chooseProjectFile": chooseProjectFile,
|
292 | "copyAllFilesToDistDir": copyAllFilesToDistDir,
|
293 | "everythingAfterTheLastDot": everythingAfterTheLastDot,
|
294 | "getLambdaConfigFile": getLambdaConfigFile,
|
295 | "getLambdaConfigFilePath": getLambdaConfigFilePath,
|
296 | "getLambdaFilePath": getLambdaFilePath,
|
297 | "getLambdaHandlerName": getLambdaHandlerName,
|
298 | "getLambdaName": getLambdaName,
|
299 | "getProjectConfig": getProjectConfig,
|
300 | "listEnvFiles": listEnvFiles,
|
301 | "setAwsRegion": setAwsRegion,
|
302 | "setOptions": setOptions,
|
303 | "zipFile": zipFile
|
304 | } |
\ | No newline at end of file |