Skip to content

Commit 2602a3e

Browse files
authored
Merge pull request #13 from alertlogic/update_function_config
lambda config update
2 parents 9ecedc1 + 1fa4924 commit 2602a3e

File tree

6 files changed

+577
-8
lines changed

6 files changed

+577
-8
lines changed

al_aws.js

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
const AWS = require('aws-sdk');
1313
const moment = require('moment');
14+
const async = require('async');
1415

1516
const AWS_STATISTICS_PERIOD_MINUTES = 15;
1617
const MAX_ERROR_MSG_LEN = 1024;
@@ -33,6 +34,40 @@ var selfUpdate = function (callback) {
3334
});
3435
};
3536

37+
var getS3ConfigChanges = function(callback) {
38+
var s3 = new AWS.S3();
39+
40+
var params = {
41+
Bucket: process.env.aws_lambda_s3_bucket,
42+
Key: process.env.aws_lambda_update_config_name
43+
};
44+
s3.getObject(params, function(err, object) {
45+
if (err) {
46+
return callback(err);
47+
} else {
48+
try {
49+
let config = JSON.parse(object.Body.toString());
50+
return callback(null, config);
51+
} catch(ex) {
52+
return callback('Unable to parse config cahnges.')
53+
}
54+
}
55+
});
56+
};
57+
58+
var getLambdaConfig = function(callback) {
59+
var lambda = new AWS.Lambda();
60+
var params = {
61+
FunctionName: process.env.AWS_LAMBDA_FUNCTION_NAME
62+
};
63+
64+
lambda.getFunctionConfiguration(params, callback);
65+
};
66+
67+
var updateLambdaConfig = function(config, callback) {
68+
var lambda = new AWS.Lambda();
69+
lambda.updateFunctionConfiguration(config, callback);
70+
};
3671

3772
//DEPRECATED FUNCTION
3873
//please use statistics_templates.js instead
@@ -126,13 +161,16 @@ var setEnv = function(vars, callback) {
126161

127162
module.exports = {
128163
selfUpdate : selfUpdate,
164+
getS3ConfigChanges : getS3ConfigChanges,
165+
updateLambdaConfig : updateLambdaConfig,
166+
getLambdaConfig : getLambdaConfig,
129167
arnToName : arnToName,
130168
arnToAccId : arnToAccId,
131169
setEnv : setEnv,
132-
170+
133171
//DEPRECATED FUNCTIONS
134172
//please use statistics_templates.js instead
135173
getMetricStatistics : getMetricStatistics,
136174
getLambdaMetrics : getLambdaMetrics,
137-
getKinesisMetrics : getKinesisMetrics
175+
getKinesisMetrics : getKinesisMetrics,
138176
};

al_aws_collector.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const moment = require('moment');
1414
const zlib = require('zlib');
1515
const async = require('async');
1616
const response = require('cfn-response');
17+
const deepEqual = require('deep-equal');
1718

1819
const m_alCollector = require('al-collector-js');
1920
const m_alAws = require('./al_aws');
@@ -246,10 +247,116 @@ class AlAwsCollector {
246247
],
247248
callback);
248249
}
250+
251+
update(callback) {
252+
let collector = this;
253+
254+
async.waterfall([
255+
collector.selfUpdate,
256+
function(asyncCallback) {
257+
// Run config update only if the config file is known
258+
if (process.env.aws_lambda_update_config_name) {
259+
collector.selfConfigUpdate(asyncCallback);
260+
} else {
261+
asyncCallback(null)
262+
}
263+
}
264+
], callback);
265+
}
249266

250267
selfUpdate(callback) {
251268
m_alAws.selfUpdate(callback);
252269
}
270+
271+
selfConfigUpdate(callback) {
272+
let collector = this;
273+
274+
async.waterfall([
275+
function(asyncCallback) {
276+
m_alAws.getS3ConfigChanges(function(err, config) {
277+
asyncCallback(err, config);
278+
});
279+
},
280+
function(newValues, asyncCallback) {
281+
m_alAws.getLambdaConfig(function(err, currentConfig) {
282+
asyncCallback(err, newValues, currentConfig);
283+
});
284+
},
285+
function(newValues, currentConfig, asyncCallback) {
286+
collector._applyConfigChanges(newValues, currentConfig, function(err, newConfig) {
287+
asyncCallback(err, newConfig, currentConfig);
288+
});
289+
},
290+
function(newConfig, currentConfig, asyncCallback) {
291+
if (collector._isConfigDifferent(newConfig, currentConfig)) {
292+
let updateConfig = collector._filterDisallowedConfigParams(newConfig);
293+
m_alAws.updateLambdaConfig(updateConfig, asyncCallback);
294+
} else {
295+
asyncCallback(null);
296+
}
297+
}
298+
],
299+
function(err, config) {
300+
if (err) {
301+
console.info('Lambda self-update config error: ', err);
302+
} else {
303+
if (config !== undefined) {
304+
console.info('Lambda self-update config successful. Config: ', config);
305+
} else {
306+
console.info('Lambda self-update config nothing to update');
307+
}
308+
}
309+
callback(err, config);
310+
});
311+
}
312+
313+
_applyConfigChanges(newValues, config, callback) {
314+
var jsonConfig = JSON.stringify(config);
315+
var newConfig = JSON.parse(jsonConfig);
316+
317+
try {
318+
Object.keys(newValues).forEach(
319+
function(item) {
320+
let path = newValues[item]['path'];
321+
let value = newValues[item]['value'];
322+
this._changeObject(newConfig, path, value);
323+
}, this); //lexical scoping
324+
return callback(null, newConfig);
325+
}
326+
catch(ex) {
327+
return callback('Unable to apply new config values');
328+
}
329+
}
330+
331+
_changeObject(obj, path, value) {
332+
if (typeof path == 'string') {
333+
return this._changeObject(obj, path.split('.'), value);
334+
}
335+
else if (path.length == 1) {
336+
return obj[path[0]] = value;
337+
} else {
338+
return this._changeObject(obj[path[0]], path.slice(1), value);
339+
}
340+
}
341+
342+
_isConfigDifferent(config1, config2) {
343+
return !deepEqual(config1, config2);
344+
}
345+
346+
_filterDisallowedConfigParams(config) {
347+
var newConfig = JSON.parse(JSON.stringify(config));
348+
// These are not either allowed to update or we don't have enough permission.
349+
delete(newConfig.FunctionArn);
350+
delete(newConfig.Role);
351+
delete(newConfig.CodeSize);
352+
delete(newConfig.LastModified);
353+
delete(newConfig.CodeSha256);
354+
delete(newConfig.Version);
355+
if (newConfig.VpcConfig)
356+
delete(newConfig.VpcConfig.VpcId);
357+
delete(newConfig.MasterArn);
358+
return newConfig;
359+
}
253360
}
254361

255362
module.exports = AlAwsCollector;

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"al-collector-js": "git://github.com/alertlogic/al-collector-js#master",
2525
"cfn-response": "*",
2626
"async": "*",
27-
"moment": "^2.19.2"
27+
"moment": "^2.19.2",
28+
"deep-equal": "*"
2829
},
2930
"author": "Alert Logic Inc."
3031
}

0 commit comments

Comments
 (0)