diff --git a/action.yml b/action.yml index bffb1cba..d978c300 100644 --- a/action.yml +++ b/action.yml @@ -37,6 +37,12 @@ inputs: command: description: 'The command used by ECS to start the container image' required: false + task-role-arn: + description: 'The full Amazon Resource Name (ARN) of the task role to set for the task definition' + required: false + execution-role-arn: + description: 'The full Amazon Resource Name (ARN) of the execution role to set for the task definition' + required: false env-files: description: 'S3 object arns to set env variables onto the container. You can specify multiple files with multi-line YAML strings.' required: false diff --git a/dist/index.js b/dist/index.js index 6e594a59..bf5c6f03 100644 --- a/dist/index.js +++ b/dist/index.js @@ -51,6 +51,8 @@ async function run() { const logConfigurationOptions = core.getInput("log-configuration-options", { required: false }); const dockerLabels = core.getInput('docker-labels', { required: false }); const command = core.getInput('command', { required: false }); + const taskRoleArn = core.getInput('task-role-arn', { required: false }); + const executionRoleArn = core.getInput('execution-role-arn', { required: false }); //New inputs to fetch task definition const taskDefinitionArn = core.getInput('task-definition-arn', { required: false }) || undefined; @@ -119,6 +121,14 @@ async function run() { containerDef.command = command.split(' ') } + if (taskRoleArn) { + containerDef.taskRoleArn = taskRoleArn; + } + + if (executionRoleArn) { + containerDef.executionRoleArn = executionRoleArn; + } + if (envFiles) { containerDef.environmentFiles = []; envFiles.split('\n').forEach(function (line) { diff --git a/index.js b/index.js index f4cb591d..01c58090 100644 --- a/index.js +++ b/index.js @@ -45,6 +45,8 @@ async function run() { const logConfigurationOptions = core.getInput("log-configuration-options", { required: false }); const dockerLabels = core.getInput('docker-labels', { required: false }); const command = core.getInput('command', { required: false }); + const taskRoleArn = core.getInput('task-role-arn', { required: false }); + const executionRoleArn = core.getInput('execution-role-arn', { required: false }); //New inputs to fetch task definition const taskDefinitionArn = core.getInput('task-definition-arn', { required: false }) || undefined; @@ -113,6 +115,14 @@ async function run() { containerDef.command = command.split(' ') } + if (taskRoleArn) { + containerDef.taskRoleArn = taskRoleArn; + } + + if (executionRoleArn) { + containerDef.executionRoleArn = executionRoleArn; + } + if (envFiles) { containerDef.environmentFiles = []; envFiles.split('\n').forEach(function (line) { diff --git a/index.test.js b/index.test.js index 1c01769f..56fef839 100644 --- a/index.test.js +++ b/index.test.js @@ -47,6 +47,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // docker labels .mockReturnValueOnce('') // command + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('') // task-definition arn .mockReturnValueOnce('') // task-definition family .mockReturnValueOnce('') // task-definition revision @@ -263,6 +265,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // docker labels .mockReturnValueOnce('') // command + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('') // task-definition arn .mockReturnValueOnce('') // task-definition family .mockReturnValueOnce('') // task-definition revision @@ -477,6 +481,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') .mockReturnValueOnce('') .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') .mockReturnValueOnce('SECRET'); await run(); @@ -523,6 +529,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // Docker Labels .mockReturnValueOnce('') // Command Options + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('task-definition-arn') // task definition arn .mockReturnValueOnce('task-definition-family') // task definition family .mockReturnValueOnce(0); // task definition revision @@ -544,6 +552,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // Docker Labels .mockReturnValueOnce('') // Command Options + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('') // task definition arn .mockReturnValueOnce("task-definition-family") // task definition family .mockReturnValueOnce(10); // task definition revision @@ -569,6 +579,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // Docker Labels .mockReturnValueOnce('') // Command Options + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('') // task definition arn .mockReturnValueOnce("task-definition-family") // task definition family .mockReturnValueOnce(0); // task definition revision @@ -595,6 +607,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // Docker Labels .mockReturnValueOnce('') // Command Options + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('task-definition-arn') // task definition arn .mockReturnValueOnce('') // task definition family .mockReturnValueOnce(0); // task definition revision @@ -621,6 +635,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // Docker Labels .mockReturnValueOnce('') // Command Options + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('task-definition-arn') // task definition arn .mockReturnValueOnce('') // task definition family .mockReturnValueOnce(0); //task definition revision @@ -644,6 +660,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // Docker Labels .mockReturnValueOnce('') // Command Options + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('task-definition-arn') //task definition arn .mockReturnValueOnce('task-definition-family') //task definition family .mockReturnValueOnce(10); //task definition revision @@ -667,6 +685,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // Docker Labels .mockReturnValueOnce('') // Command Options + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('task-definition-arn') // task definition arn .mockReturnValueOnce('task-definition-family') // task definition family .mockReturnValueOnce(0); // task definition revision @@ -692,6 +712,8 @@ describe('Render task definition', () => { .mockReturnValueOnce('') // log Configuration Options .mockReturnValueOnce('') // Docker Labels .mockReturnValueOnce('') // Command Options + .mockReturnValueOnce('') // task role arn + .mockReturnValueOnce('') // execution role arn .mockReturnValueOnce('') // task definition arn .mockReturnValueOnce('') // task definition family .mockReturnValueOnce(10); // task definition revision @@ -978,4 +1000,206 @@ describe('Render task definition', () => { }, null, 2) ); }); + + test('renders a task definition task role arn', async () => { + core.getInput = jest + .fn() + .mockReturnValueOnce('task-definition.json') + .mockReturnValueOnce('web') + .mockReturnValueOnce('nginx:latest') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('arn:aws:iam::0123456789:role/task-role'); + + await run(); + + expect(tmp.fileSync).toHaveBeenNthCalledWith(1, { + tmpdir: '/home/runner/work/_temp', + prefix: 'task-definition-', + postfix: '.json', + keep: true, + discardDescriptor: true + }); + + expect(fs.writeFileSync).toHaveBeenNthCalledWith(1, 'new-task-def-file-name', + JSON.stringify({ + family: 'task-def-family', + containerDefinitions: [ + { + name: "web", + image: "nginx:latest", + environment: [ + { + name: "FOO", + value: "bar" + }, + { + name: "DONT-TOUCH", + value: "me" + }, + { + name: "HELLO", + value: "world" + }, + { + name: "EXAMPLE", + value: "here" + } + ], + environmentFiles: [ + { + value: "arn:aws:s3:::s3_bucket_name/envfile_object_name.env", + type: "s3" + } + ], + secrets: [ + { + name: "EXISTING_SECRET", + valueFrom: "arn:aws:ssm:region:0123456789:parameter/existingSecret" + }, + { + name: "SSM_SECRET", + valueFrom: "arn:aws:ssm:region:0123456789:parameter/secret" + }, + { + name: "SM_SECRET", + valueFrom: "arn:aws:secretsmanager:us-east-1:0123456789:secret:secretName" + } + ], + logConfiguration: { + logDriver: "awslogs", + options: { + "awslogs-create-group": "true", + "awslogs-group": "/ecs/web", + "awslogs-region": "us-east-1", + "awslogs-stream-prefix": "ecs" + } + }, + dockerLabels : { + "key1":"value1", + "key2":"value2" + }, + command : ["npm", "start", "--nice", "--please"], + taskRoleArn: "arn:aws:iam::0123456789:role/task-role", + }, + { + name: "sidecar", + image: "hello" + } + ], + tags: [ + { + key: "project", + value: "mytaskdef" + } + ] + }, null, 2) + ); + }); + + test('renders a task definition execution role arn', async () => { + core.getInput = jest + .fn() + .mockReturnValueOnce('task-definition.json') + .mockReturnValueOnce('web') + .mockReturnValueOnce('nginx:latest') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('') + .mockReturnValueOnce('arn:aws:iam::0123456789:role/execution-role'); + + await run(); + + expect(tmp.fileSync).toHaveBeenNthCalledWith(1, { + tmpdir: '/home/runner/work/_temp', + prefix: 'task-definition-', + postfix: '.json', + keep: true, + discardDescriptor: true + }); + + expect(fs.writeFileSync).toHaveBeenNthCalledWith(1, 'new-task-def-file-name', + JSON.stringify({ + family: 'task-def-family', + containerDefinitions: [ + { + name: "web", + image: "nginx:latest", + environment: [ + { + name: "FOO", + value: "bar" + }, + { + name: "DONT-TOUCH", + value: "me" + }, + { + name: "HELLO", + value: "world" + }, + { + name: "EXAMPLE", + value: "here" + } + ], + environmentFiles: [ + { + value: "arn:aws:s3:::s3_bucket_name/envfile_object_name.env", + type: "s3" + } + ], + secrets: [ + { + name: "EXISTING_SECRET", + valueFrom: "arn:aws:ssm:region:0123456789:parameter/existingSecret" + }, + { + name: "SSM_SECRET", + valueFrom: "arn:aws:ssm:region:0123456789:parameter/secret" + }, + { + name: "SM_SECRET", + valueFrom: "arn:aws:secretsmanager:us-east-1:0123456789:secret:secretName" + } + ], + logConfiguration: { + logDriver: "awslogs", + options: { + "awslogs-create-group": "true", + "awslogs-group": "/ecs/web", + "awslogs-region": "us-east-1", + "awslogs-stream-prefix": "ecs" + } + }, + dockerLabels : { + "key1":"value1", + "key2":"value2" + }, + command : ["npm", "start", "--nice", "--please"], + taskRoleArn: "arn:aws:iam::0123456789:role/task-role", + executionRoleArn: "arn:aws:iam::0123456789:role/execution-role", + }, + { + name: "sidecar", + image: "hello" + } + ], + tags: [ + { + key: "project", + value: "mytaskdef" + } + ] + }, null, 2) + ); + }); });