Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0d0e316
add network configuration input
Feb 23, 2023
d116e4f
temporarily remove network configuration
Feb 24, 2023
87e39c7
update ignore attributes
Feb 24, 2023
4f9a202
update actions and package.json
Feb 24, 2023
54f1d2a
update actions and package.json
Feb 24, 2023
697146e
update actions and package.json
Feb 24, 2023
b136e0a
update actions and package.json
Feb 24, 2023
941d3f2
add network configuration to action
Feb 28, 2023
dde7364
update package.yml
Feb 28, 2023
3d19be0
add createArrayFromString function
Feb 28, 2023
340a137
specify launch type as fargate in runTask
Mar 1, 2023
21e5bea
code cleanup in index.js
Mar 1, 2023
2eac7a6
update readme
Mar 1, 2023
9e51756
update createArrayFromString function
Mar 1, 2023
8336a44
chore: Update dist
Mar 1, 2023
81ae1b8
fix copy/paste error in usage example
leslie-corbalt Jun 16, 2023
212eb97
update actions/checkout to v3
leslie-corbalt Jun 16, 2023
898f090
run on workflow_dispatch
leslie-corbalt Jun 16, 2023
f9ebca7
run on push to lbk- branch
leslie-corbalt Jun 16, 2023
2d1cd9a
Revert "run on push to lbk- branch"
leslie-corbalt Jun 16, 2023
9ade922
Merge pull request #1 from Enterprise-CMCS/lbk-update-action
hsoule-corbalt Jun 16, 2023
3a23933
run the task before registering the task definition
leslie-corbalt Sep 6, 2023
9e99206
update README
leslie-corbalt Sep 8, 2023
63c7bf9
fix tag on example usage
leslie-corbalt Sep 8, 2023
f43f04a
Merge pull request #2 from Enterprise-CMCS/lbk-run-first-register-second
leslie-corbalt Sep 8, 2023
d0e41e1
chore: Update dist
Sep 8, 2023
fb4a89a
add code.json and generate-codejson.yml
leslie-corbalt Jul 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions .github/workflows/check.yml

This file was deleted.

26 changes: 26 additions & 0 deletions .github/workflows/generate-codejson.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Generate code.json
on:
schedule:
- cron: "0 0 1 * *" # monthly

jobs:
update-code-json:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Generate token from GitHub App
id: create_token
uses: tibdex/[email protected]
with:
app_id: ${{ secrets.PR_PERMS_APP_ID }}
private_key: ${{ secrets.PR_PERMS_APP_SECRET }}

- name: Update code.json
uses: DSACMS/[email protected]
with:
GITHUB_TOKEN: ${{ steps.create_token.outputs.token }}
BRANCH: "main"
18 changes: 15 additions & 3 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
on:
workflow_dispatch:
push:
branches:
- master
paths-ignore:
- "**.md"
pull_request:
paths-ignore:
- "**.md"

name: Package
name: Package Action

jobs:
check:
name: Package distribution file
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
ref: master

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16

- name: Package
run: |
node -v
npm ci
npm test
npm run package
- name: Commit
run: |
Expand Down
24 changes: 19 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
## Amazon ECS "Run Task" Action for GitHub Actions

Runs an Amazon ECS task on ECS cluster.
This action was forked from [smitp/amazon-ecs-run-task](https://github.com/smitp/amazon-ecs-run-task).

**Table of Contents**
This action does two things:

1. It runs the input task definition.
2. After step 1 successfully completes, it registers the task definition.

The reason for registering the task definition *after* running the task is to allow the GITHUB_TOKEN to be used as a task definition envirionment variable.
The task definition is registered only after the GITHUB_TOKEN is no longer valid.

To enable the action to run tasks with `network_mode` set to `awsvpc`, the action accepts subnet ids and security groups as inputs.

## Table of Contents

<!-- toc -->

Expand All @@ -21,16 +31,19 @@ Runs an Amazon ECS task on ECS cluster.

```yaml
- name: Run Task on Amazon ECS
uses: smitp/amazon-ecs-run-task@v1
uses: Enterprise-CMCS/amazon-ecs-run-task@master
with:
task-definition: task-definition.json
task-definition-arn: arn:aws:ecs:us-east-1:12345:task-definition/mytask-dev:42
cluster: my-cluster
count: 1
subnets: subnet-1, subnet-2, subnet-3
security-groups: sg-1, sg-2
started-by: github-actions-${{ github.actor }}
wait-for-finish: true
```

See [action.yml](action.yml) for the full documentation for this action's inputs and outputs.
`security-groups` and `subnets` can be single values or comma separated lists, such as in the example above. See [action.yml](action.yml) for the full documentation for this action's inputs and outputs.

### Task definition file

Expand Down Expand Up @@ -94,9 +107,10 @@ The task definition file can be updated prior to deployment with the new contain
image: ${{ steps.build-image.outputs.image }}

- name: Run Task on Amazon ECS
uses: smitp/amazon-ecs-run-task@v1
uses: Enterprise-CMCS/amazon-ecs-run-task@vXYZ
with:
task-definition: task-definition.json
task-definition-arn: arn:aws:ecs:us-east-1:12345:task-definition/mytask-dev:42
cluster: my-cluster
count: 1
started-by: github-actions-${{ github.actor }}
Expand Down
14 changes: 11 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@ branding:
color: 'orange'
inputs:
task-definition:
description: 'The name of ECS task definition'
description: 'The filename (<file>.json) of the ECS task definition'
required: true
task-definition-arn:
description: 'The ECS task definition ARN'
cluster:
description: "The name of the ECS cluster. Will default to the 'default' cluster"
required: true
count:
description: "The count of tasks to run. Will default to the 1"
description: "The count of tasks to run. Will default to 1"
required: true
security-groups:
description: "The array of security groups to set in the network configuration. Will default to an empty array."
required: false
subnets:
description: "The array of subnets to set in the network configuration. Will default to an empty array."
required: false
started-by:
description: "The value of the task started-by"
required: false
Expand All @@ -28,5 +36,5 @@ outputs:
task-arn:
description: 'The ARN of the ECS task'
runs:
using: 'node12'
using: 'node16'
main: 'dist/index.js'
76 changes: 76 additions & 0 deletions code.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"name": "mac-fc-amazon-ecs-run-task",
"description": "This GitHub Action runs the input task definition.",
"longDescription": "This GitHub Action runs the input task definition. After that successfully completes, it registers the task definition.",
"status": "Production",
"permissions": {
"licenses": [
{
"name": "None",
"URL": "none"
}
],
"usageType": "governmentWideReuse",
"exemptionText": ""
},
"organization": "Centers for Medicare & Medicaid Services",
"repositoryURL": "https://github.com/Enterprise-CMCS/mac-fc-amazon-ecs-run-task",
"projectURL": "",
"repositoryHost": "github.com/CMS-Enterprise",
"repositoryVisibility": "public",
"vcs": "git",
"laborHours": 0,
"reuseFrequency": {
"forks": 790
},
"platforms": [
"linux"
],
"categories": [
"application-development",
"it-development"
],
"softwareType": "standalone/backend",
"languages": [
"JavaScript"
],
"maintenance": "contract",
"contractNumber": "47QTCA21D00AC",
"date": {
"created": "2024-11-24T16:38:00Z",
"lastModified": "",
"metaDataLastUpdated": ""
},
"tags": [
"ecs service",
"ecs task definition",
"ecs task",
"ecs run task",
"ecs register task definition",
"ecs run task GitHub Action"
],
"contact": {
"email": "[email protected]",
"name": "Corbalt"
},
"feedbackMechanisms": [
"https://github.com/Enterprise-CMCS/mac-fc-amazon-ecs-run-task/issues"
],
"localisation": false,
"repositoryType": "tools",
"userInput": false,
"fismaLevel": "Moderate",
"group": "CMCS/DSG",
"projects": [
"ECS Run Task GHA"
],
"systems": [],
"upstream": [],
"subsetInHealthcare": [
"Medicaid"
],
"userType": [
"Government"
],
"maturityModelTier": 2
}
77 changes: 50 additions & 27 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ const IGNORED_TASK_DEFINITION_ATTRIBUTES = [
'taskDefinitionArn',
'requiresAttributes',
'revision',
'status'
'status',
'registeredAt',
'registeredBy',
];

const WAIT_DEFAULT_DELAY_SEC = 5;
Expand Down Expand Up @@ -196,19 +198,26 @@ function cleanNullKeys(obj) {
}

function removeIgnoredAttributes(taskDef) {
if (IGNORED_TASK_DEFINITION_ATTRIBUTES.length > 0) {
core.warning(`Ignoring properties '${IGNORED_TASK_DEFINITION_ATTRIBUTES}' in the task definition file. ` +
'These properties are returned by the Amazon ECS DescribeTaskDefinition API and may be shown in the ECS console, ' +
'but they are not valid fields when registering a new task definition. ' +
'These fields can be safely removed from your task definition file.');
}

for (var attribute of IGNORED_TASK_DEFINITION_ATTRIBUTES) {
if (taskDef[attribute]) {
core.warning(`Ignoring property '${attribute}' in the task definition file. ` +
'This property is returned by the Amazon ECS DescribeTaskDefinition API and may be shown in the ECS console, ' +
'but it is not a valid field when registering a new task definition. ' +
'This field can be safely removed from your task definition file.');
delete taskDef[attribute];
}
}

return taskDef;
}

function createArrayFromString(str) {
return str.split(/\s+/);
}

async function run() {
try {
const agent = 'amazon-ecs-run-task-for-github-actions'
Expand All @@ -219,49 +228,43 @@ async function run() {

// Get inputs
const taskDefinitionFile = core.getInput('task-definition', { required: true });
const taskDefArnToRun = core.getInput('task-definition-arn', { required: true });
const cluster = core.getInput('cluster', { required: false });
const count = core.getInput('count', { required: true });
const subnets = core.getInput('subnets', { required: false }) || '';
const securityGroups = core.getInput('security-groups', { required: false }) || '';
const startedBy = core.getInput('started-by', { required: false }) || agent;
const waitForFinish = core.getInput('wait-for-finish', { required: false }) || false;
let waitForMinutes = parseInt(core.getInput('wait-for-minutes', { required: false })) || 30;
if (waitForMinutes > MAX_WAIT_MINUTES) {
waitForMinutes = MAX_WAIT_MINUTES;
}

// Register the task definition
core.debug('Registering the task definition');
const taskDefPath = path.isAbsolute(taskDefinitionFile) ?
taskDefinitionFile :
path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile);
const fileContents = fs.readFileSync(taskDefPath, 'utf8');
const taskDefContents = removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents)));
// Run task from the input task definition
const clusterName = cluster ? cluster : 'default';

let registerResponse;
try {
registerResponse = await ecs.registerTaskDefinition(taskDefContents).promise();
} catch (error) {
core.setFailed("Failed to register task definition in ECS: " + error.message);
core.debug("Task definition contents:");
core.debug(JSON.stringify(taskDefContents, undefined, 4));
throw(error);
const networkConfiguration = {
awsvpcConfiguration: {
subnets: createArrayFromString(subnets),
securityGroups: createArrayFromString(securityGroups)
}
}
const taskDefArn = registerResponse.taskDefinition.taskDefinitionArn;
core.setOutput('task-definition-arn', taskDefArn);

const clusterName = cluster ? cluster : 'default';

core.debug(`Running task with ${JSON.stringify({
cluster: clusterName,
taskDefinition: taskDefArn,
taskDefinition: taskDefArnToRun,
count: count,
networkConfiguration: networkConfiguration,
startedBy: startedBy
})}`)

const runTaskResponse = await ecs.runTask({
cluster: clusterName,
taskDefinition: taskDefArn,
taskDefinition: taskDefArnToRun,
count: count,
startedBy: startedBy
networkConfiguration: networkConfiguration,
startedBy: startedBy,
launchType: "FARGATE"
}).promise();

core.debug(`Run task response ${JSON.stringify(runTaskResponse)}`)
Expand All @@ -284,6 +287,26 @@ async function run() {
core.setFailed(error.message);
core.debug(error.stack);
}

// Register the task definition that was used to run the task
core.debug('Registering the task definition');
const taskDefPath = path.isAbsolute(taskDefinitionFile) ?
taskDefinitionFile :
path.join(process.env.GITHUB_WORKSPACE, taskDefinitionFile);
const fileContents = fs.readFileSync(taskDefPath, 'utf8');
const taskDefContents = removeIgnoredAttributes(cleanNullKeys(yaml.parse(fileContents)));

let registerResponse;
try {
registerResponse = await ecs.registerTaskDefinition(taskDefContents).promise();
} catch (error) {
core.setFailed("Failed to register task definition in ECS: " + error.message);
core.debug("Task definition contents:");
core.debug(JSON.stringify(taskDefContents, undefined, 4));
throw(error);
}
const taskDefArn = registerResponse.taskDefinition.taskDefinitionArn;
core.setOutput('task-definition-arn', taskDefArn);
}

async function waitForTasksStopped(ecs, clusterName, taskArns, waitForMinutes) {
Expand Down
Loading