Skip to content

Commit

Permalink
closes #92
Browse files Browse the repository at this point in the history
  • Loading branch information
cmawhorter committed Jun 10, 2020
1 parent 8253dcb commit a31659a
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 31 deletions.
2 changes: 1 addition & 1 deletion cli/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const loadAccountId = async () => {
};

yargs.middleware(async argv => {
const command = argv._[0];
// const command = argv._[0];
const { account, profile, region, config, project } = argv;
// if not using cwd we'll chdir to the target just to keep things simple
if (project) {
Expand Down
12 changes: 6 additions & 6 deletions cli/commands/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const builder = {
// publish: {
// describe: 'Publish a new aliased version of the lambda function. Defaults to date; provide a value to override',
// },
refresh: {
configuration: {
type: 'boolean',
default: true,
describe: 'Update the function configuration in addition to updating code. This only applies after the function was created (all new functions have their configuration updated as part of creating)',
Expand All @@ -38,12 +38,12 @@ export const builder = {
};

export async function handler(argv) {
const { betty, output, upload } = argv;
ok(output || upload, 'either --output or --upload required');
const { betty, output, upload, configuration } = argv;
ok(output || upload || configuration, 'either --output, --upload, or --configuration required');
const task = new LambdaUpdateTask({
outputPath: true === argv.output ? process.cwd() : argv.output,
upload: argv.upload,
updateConfiguration: argv.refresh,
outputPath: true === output ? process.cwd() : output,
upload,
updateConfiguration: configuration,
});
if (argv.dryRun) {
logger.write(logger.chalk.bold.grey('Context'));
Expand Down
4 changes: 4 additions & 0 deletions lib/aws/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
// but we'll just wrap callbacks in our own promise support and be done with it
export async function invokeAsync(client, method, ...args) {
return await new Promise((resolve, reject) => {
if (typeof client[method] !== 'function') {
reject(new Error(`target aws client has method matching "${method}"`));
return;
}
client[method](...args, (err, result) => {
if (err) {
reject(err);
Expand Down
4 changes: 2 additions & 2 deletions lib/aws/roles.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ export async function getAttachedPolicies(roleName) {

export async function attachManagedPolicy(roleName, policyArn) {
const data = await getAttachedPolicies(roleName);
const existingPolicies = data.AttachedPolicies
const policyAlreadyAttached = data.AttachedPolicies
.filter(policy =>
policy.PolicyArn === policyArn);
if (existingPolicies.length === 0) {
if (policyAlreadyAttached.length > 0) {
return null;
}
const params = {
Expand Down
4 changes: 4 additions & 0 deletions lib/resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export class Resource {
return this.data.name;
}

get description() {
return this.data.description;
}

get region() {
let result;
if (this.data.region) {
Expand Down
51 changes: 30 additions & 21 deletions lib/tasks/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ export class OutputUpdateTask extends Task {

async _before(betty) {
const { distPath } = betty.context;
await this._bundle(distPath);
if (distPath) {
await this._bundle(distPath);
}
}

async _run(betty) {
Expand All @@ -90,11 +92,14 @@ const LAMBDA_TARGET_STANDARD = 'lambda';
const LAMBDA_TARGET_EDGE = 'edge';

export class LambdaUpdateTask extends OutputUpdateTask {
static buildDeadLetterQueueConfig(dlq, dlq_service, { region, account }) {
static buildDeadLetterQueueConfig(dlq, dlq_service, { region, account } = {}) {
if (isArn(dlq)) {
return dlq;
}
else {
ok(dlq_service, 'dlq_service required');
ok(region, 'region required');
ok(account, 'account required');
return createArn({
service: dlq_service,
region,
Expand Down Expand Up @@ -175,7 +180,7 @@ export class LambdaUpdateTask extends OutputUpdateTask {
// aliasVersion,
updateConfiguration,
inlineAssetPolicyName = 'combined-assets',
}) {
} = {}) {
super({ outputPath });
this.upload = upload;
this.updateConfiguration = updateConfiguration;
Expand Down Expand Up @@ -241,11 +246,11 @@ export class LambdaUpdateTask extends OutputUpdateTask {
// async _deleteFunction(region) {
// }

async _processFunction(betty, region) {
async _processFunction(betty, region, client) {
const {
resource,
awsAccountId: account } = betty.context;
const _client = LambdaUpdateTask.lambdaClient(region);
const _client = client || LambdaUpdateTask.lambdaClient(region);
const functionName = resource.name;
const exists = await this._readFunction(_client, functionName);
const writeParams = LambdaUpdateTask.buildLambdaWriteParams(resource, {
Expand Down Expand Up @@ -273,52 +278,56 @@ export class LambdaUpdateTask extends OutputUpdateTask {
// }
}

async _loadServiceRole(betty) {
async _loadServiceRole(betty, rolesClient = Roles) {
if (!this._serviceRoleArn) {
const data = await Roles.createLambdaRole(betty.context.awsAccountId, betty.resource.data.name);
const data = await rolesClient.createLambdaRole(betty.context.awsAccountId, betty.resource.data.name);
this._serviceRoleArn = data.Role.Arn;
}
}

async _writeInlinePolicy(betty) {
async _writeInlinePolicy(betty, rolesClient = Roles, policiesClient = Policies) {
const { name, assets } = betty.resource.data;
if (!Array.isArray(assets) || assets.length === 0) {
return;
throw new Error('no assets to attach');
}
const policyName = this.inlineAssetPolicyName;
const policyDocument = Policies.documentFromAssets(assets, betty.resource.regions);
await Roles.attachInlinePolicy(name, policyName, policyDocument);
const policyDocument = policiesClient.documentFromAssets(assets, betty.resource.regions);
await rolesClient.attachInlinePolicy(name, policyName, policyDocument);
}

async _attachManagedPolicies(betty) {
async _attachManagedPolicies(betty, rolesClient = Roles, policiesClient = Policies) {
const { name, resources } = betty.resource.data;
const resourceKeys = Object.keys(resources || {});
if (resourceKeys.length === 0) {
return;
throw new Error('no managed policies to attach');
}
for (const resourceName of resourceKeys) {
const policyArn = Policies.createManagedPolicyArnForResource(betty.context.awsAccountId, resourceName);
await Roles.attachManagedPolicy(name, policyArn);
const policyArn = policiesClient.createManagedPolicyArnForResource(betty.context.awsAccountId, resourceName);
await rolesClient.attachManagedPolicy(name, policyArn);
}
}

async _writeManagedPolicy(betty) {
async _writeManagedPolicy(betty, policiesClient = Policies) {
const { name, policy } = betty.resource.data;
// even if doesn't exist we still create it as a placeholder
const policyDocument = Policies.documentFromAssets(policy || [], betty.resource.regions);
await Policies.createManagedPolicy(betty.context.awsAccountId, name, policyDocument);
const policyDocument = policiesClient.documentFromAssets(policy || [], betty.resource.regions);
await policiesClient.createManagedPolicy(betty.context.awsAccountId, name, policyDocument);
}

async _attachExectionRole(awsAccountId, functionName, rolesClient = Roles) {
await rolesClient.attachAwsLambdaBasicExecutionRole(awsAccountId, functionName, this._serviceRoleArn);
}

async _before(betty) {
// we need to have parent create the bundle first
await super._before(betty);
await this._loadServiceRole(betty);
await Roles.attachAwsLambdaBasicExecutionRole(betty.context.awsAccountId, betty.resource.data.name, this._serviceRoleArn);
await this._attachExectionRole(betty.context.awsAccountId, betty.resource.data.name);
// inline policies
if (betty.resource.data.assets) {
if ((betty.resource.data.assets || []).length > 0) {
await this._writeInlinePolicy(betty);
}
if (betty.resource.data.resources) {
if (Object.keys(betty.resource.data.resources || {}).length > 0) {
await this._attachManagedPolicies(betty);
}
await this._writeManagedPolicy(betty);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bty",
"version": "2.0.0",
"version": "2.0.0-alpha1",
"description": "Simple command line utility for developing and deploying AWS Lambda functions.",
"main": "./lib/main.js",
"bin": {
Expand Down
1 change: 1 addition & 0 deletions test/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
assert: true,
chai: true,
expect: true,
ok: true,
},
rules: {
'no-console': 1,
Expand Down
2 changes: 2 additions & 0 deletions test/lib/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ global.assert = require('assert');
global.chai = require('chai');
global.expect = global.chai.expect;

global.ok = global.assert.ok;

require('reify');
Loading

0 comments on commit a31659a

Please sign in to comment.