Skip to content

Commit

Permalink
- adding batch execution role per batch job
Browse files Browse the repository at this point in the history
- adding ability to add Iam role statements to batch job
- setting up package json
  • Loading branch information
simonobe committed Oct 17, 2019
1 parent 427d172 commit f0492ad
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 77 deletions.
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ServerlessAWSBatch {
'getBatchInstanceManagementRoleLogicalId': batchenvironment.getBatchInstanceManagementRoleLogicalId,
'getBatchInstanceManagementProfileLogicalId': batchenvironment.getBatchInstanceManagementProfileLogicalId,
'getBatchSpotFleetManagementRoleLogicalId': batchenvironment.getBatchSpotFleetManagementRoleLogicalId,
'getBatchJobExecutionRoleLogicalId': batchenvironment.getBatchJobExecutionRoleLogicalId,
'getBatchJobExecutionRoleLogicalId': batchtask.getBatchJobExecutionRoleLogicalId,
'getLambdaScheduleExecutionRoleLogicalId': batchenvironment.getLambdaScheduleExecutionRoleLogicalId,
'getBatchComputeEnvironmentLogicalId': batchenvironment.getBatchComputeEnvironmentLogicalId,
'getBatchJobQueueLogicalId': batchenvironment.getBatchJobQueueLogicalId,
Expand Down
62 changes: 0 additions & 62 deletions lib/batchenvironment.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,6 @@ function getBatchSpotFleetManagementRoleLogicalId() {
return "IamRoleBatchSpotFleetManagement";
}

/**
* @returns {string} "IamRoleBatchJobExecution"
*/
function getBatchJobExecutionRoleLogicalId() {
return "IamRoleBatchJobExecution";
}

/**
* @returns {string} "IamRoleLambdaScheduleExecution"
*/
Expand Down Expand Up @@ -209,58 +202,6 @@ function generateBatchSpotFleetRole() {
}
}

/**
* Generates an IAM Service Role Object that will be used to run the jobs from the job definition
*/
function generateBatchJobExecutionRole() {
const batchJobExecutionRoleName = `BatchJobRole-${this.provider.getRegion()}-${this.provider.getStage()}-${this.provider.serverless.service.service}`.substring(0, 64);
const batchJobExecutionRoleTemplate = `
{
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "${batchJobExecutionRoleName}",
"Path": "/",
"AssumeRolePolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
}
}
`;

// Merge our iamRoleStatements into this role
const batchJobExecutionRole = JSON.parse(batchJobExecutionRoleTemplate);
if (this.serverless.service.provider.hasOwnProperty('iamRoleStatements')) {
_.merge(
batchJobExecutionRole.Properties,
{
"Policies": [
{
"PolicyName": "batch-job-execution-policies",
"PolicyDocument": {
"Version": "2008-10-17",
"Statement": this.serverless.service.provider.iamRoleStatements
}
}
]
}
)
}

// Setup the JobQueue to push tasks to
return {
[this.provider.naming.getBatchJobExecutionRoleLogicalId()]: batchJobExecutionRole
};
}

/**
* Generates the IAM Role that can be used by our lambda "schedule batch" functions
Expand Down Expand Up @@ -423,7 +364,6 @@ function generateAWSBatchTemplate() {
const newBatchServiceRoleObject = generateBatchServiceRole.bind(this)();
const newBatchInstanceManagementRoleObject = generateBatchInstanceRole.bind(this)();
const newBatchSpotFleetManagementObject = generateBatchSpotFleetRole.bind(this)();
const newBatchJobExecutionRoleObject = generateBatchJobExecutionRole.bind(this)();
const newLambdaScheduleExecutionRoleObject = generateLambdaScheduleExecutionRole.bind(this)();
const newBatchJobQueueObject = generateBatchJobQueue.bind(this)();
const newBatchComputeEnvironmentObject = generateBatchComputeEnvironment.bind(this)();
Expand All @@ -434,7 +374,6 @@ function generateAWSBatchTemplate() {
newBatchServiceRoleObject,
newBatchInstanceManagementRoleObject,
newBatchSpotFleetManagementObject,
newBatchJobExecutionRoleObject,
newLambdaScheduleExecutionRoleObject,
newBatchJobQueueObject,
newBatchComputeEnvironmentObject,
Expand All @@ -448,7 +387,6 @@ module.exports = {
getBatchInstanceManagementRoleLogicalId,
getBatchInstanceManagementProfileLogicalId,
getBatchSpotFleetManagementRoleLogicalId,
getBatchJobExecutionRoleLogicalId,
getLambdaScheduleExecutionRoleLogicalId,
getBatchComputeEnvironmentLogicalId,
getBatchJobQueueLogicalId,
Expand Down
105 changes: 97 additions & 8 deletions lib/batchtask.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ function getJobDefinitionLogicalId(functionName) {
: logicalId;
}

/**
* @returns {string} "IamRoleBatchJobExecution"
*/
function getBatchJobExecutionRoleLogicalId(functionName) {
let logicalId = `IamRoleBatchJobExecution${functionName.charAt(0).toUpperCase()}${functionName.slice(1)}`;
return logicalId.length > 64
? logicalId.substring(0, 64)
: logicalId;
}

/**
* Transforms a function object into a "JobDefinition" object that can be used to run this function inside a Batch task
*/
Expand All @@ -40,16 +50,20 @@ function compileBatchTask(functionName) {
"Type": "container"
}
}
updateContainerProperties.bind(this)(newFunction, functionObject);
updateContainerProperties.bind(this)(newFunction, functionObject, functionName);
updateRetryStrategy.bind(this)(newFunction, functionObject);
updateTimeout.bind(this)(newFunction, functionObject);

// generate role for a batchjob execution based on custom iam statements
const newBatchJobExecutionRoleObject = generateBatchJobExecutionRole.bind(this)(functionName, functionObject)

// Add it to our compiled cloud formation templates
_.merge(
this.serverless.service.provider.compiledCloudFormationTemplate.Resources,
{
[getJobDefinitionLogicalId(functionName)]: newFunction
}
},
newBatchJobExecutionRoleObject
);

// Now replace the original lambda function with code to invoke this batch task
Expand Down Expand Up @@ -85,16 +99,16 @@ function compileBatchTask(functionName) {
}
}
}
)

);
_.unset(this.serverless.service.functions, `${functionName}.iamRoleStatements`)
return BbPromise.resolve();
}

/**
* Generates a container properties configuration and adds it to the newFunction object
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-batch-jobdefinition-containerproperties.html
*/
function updateContainerProperties(newFunction, functionObject) {
function updateContainerProperties(newFunction, functionObject, functionName) {
newFunction.Properties.ContainerProperties = _.merge(
{},
functionObject.batch.ContainerProperties
Expand Down Expand Up @@ -125,7 +139,7 @@ function updateContainerProperties(newFunction, functionObject) {

if (! newFunction.Properties.ContainerProperties.hasOwnProperty('JobRoleArn')) {
newFunction.Properties.ContainerProperties.JobRoleArn = {
Ref: this.provider.naming.getBatchJobExecutionRoleLogicalId()
Ref: this.provider.naming.getBatchJobExecutionRoleLogicalId(functionName)
};
}

Expand Down Expand Up @@ -255,7 +269,81 @@ async function generateLambdaScheduleArtifact(functionName) {

return await response;
}
/**
* Generate Batch job execution role per batch job
*/
function generateBatchJobExecutionRole(functionName, functionObject) {
const batchJobExecutionRoleName = `BatchJobRole-${this.provider.getRegion()}-${this.provider.getStage()}-${this.provider.serverless.service.service}-${functionName}`.substring(0, 64);
const batchJobExecutionRoleTemplate = `
{
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": "${batchJobExecutionRoleName}",
"Path": "/",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
}
}
`;

// Merge our iamRoleStatements into this role
const batchJobExecutionRole = JSON.parse(batchJobExecutionRoleTemplate);
if (this.serverless.service.provider.hasOwnProperty('iamRoleStatements')) {
_.merge(
batchJobExecutionRole.Properties,
{
"Policies": [
{
"PolicyName": "batch-job-execution-policies",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": this.serverless.service.provider.iamRoleStatements
}
}
]
}
)
}

// Merge in custom iamRoleStatements from lambda function definition
if (functionObject.hasOwnProperty('iamRoleStatements')) {
_.mergeWith(
batchJobExecutionRole.Properties,
{
"Policies": [
{
"PolicyName": "batch-job-custom-policies",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": functionObject.iamRoleStatements
}
}
]
},
(objValue, srcValue) => {
if (_.isArray(objValue)) {
return objValue.concat(srcValue);
}
}
)
}

// Setup the JobQueue to push tasks to
return {
[this.provider.naming.getBatchJobExecutionRoleLogicalId(functionName)]: batchJobExecutionRole
};
}

/**
* Iterates through all of our functions, starting the compile to JobDefinition if needed
Expand All @@ -270,5 +358,6 @@ function compileBatchTasks() {

module.exports = {
compileBatchTasks,
getJobDefinitionLogicalId
};
getJobDefinitionLogicalId,
getBatchJobExecutionRoleLogicalId
};
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
{
"name": "serverless-aws-batch",
"version": "1.0.2",
"name": "@cellense/serverless-aws-batch",
"version": "1.0.0",
"description": "Serverless Framework Plugin for interacting with AWS Batch",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/justinram11/serverless-aws-batch.git"
"url": "git+https://github.com/simonobe/serverless-aws-batch.git"
},
"keywords": [
"serverless",
"aws",
"batch",
"python"
],
"author": "Justin Ramsey",
"author": "Simon Obetko",
"license": "MIT",
"bugs": {
"url": "https://github.com/justinram11/serverless-aws-batch/issues"
"url": "https://github.com/simonobe/serverless-aws-batch/issues"
},
"homepage": "https://github.com/justinram11/serverless-aws-batch#readme",
"homepage": "https://github.com/simonobe/serverless-aws-batch#readme",
"dependencies": {
"bluebird": "^3.5.3",
"cross-spawn": "^6.0.5",
Expand Down

0 comments on commit f0492ad

Please sign in to comment.