Skip to content

Commit

Permalink
added support for parameter substitution
Browse files Browse the repository at this point in the history
added de-registering of old tasks
  • Loading branch information
reflog committed Jan 17, 2018
1 parent 3506c0d commit 459c3aa
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 39 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sh text eol=lf
29 changes: 16 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,24 @@ Tiny Go CLI Program to run a one-shot (single execution) script on ECS. Think of
usage: ecs-oneshot-task --cluster=CLUSTER --task-json=TASK-JSON [<flags>]
Flags:
--help Show context-sensitive help (also try --help-long
and --help-man).
--debug Enable debug mode.
-c, --cluster=CLUSTER Name of the ECS cluster
-t, --wait=5m How long to wait for task to finish
-n, --task-name="oneshot" Name of the task to create in the cluster
-j, --task-json=TASK-JSON JSON file with task definition describing the
container running the task
--help Show context-sensitive help (also try --help-long
and --help-man).
--debug Enable debug mode.
-c, --cluster=CLUSTER Name of the ECS cluster
-t, --wait=5m How long to wait for task to finish
-n, --task-name="oneshot" Name of the task to create in the cluster
-j, --task-json=TASK-JSON JSON file with task definition describing the
container running the task
--pass-aws-keys Add AWS keys to task's environment.
-p, --params=PARAMS ... Parameter that can be used inside the JSON file
using Go templating
-k, --aws-access-key-id=AWS-ACCESS-KEY-ID
AWS Access Key ID to use (overrides environment)
AWS Access Key ID to use (overrides environment)
-s, --aws-secret-key=AWS-SECRET-KEY
AWS Secret Access Key to use (overrides
environment)
--version Show application version.
AWS Secret Access Key to use (overrides
environment)
-r, --aws-region=AWS-REGION AWS Region to user (overrides environment)
--version Show application version.
```

Expand Down
12 changes: 7 additions & 5 deletions container/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
FROM alpine:3.5
FROM ubuntu
ARG S3_PATH
ENV S3_PATH=$S3_PATH
RUN apk add --update \
python \
py-pip \
&& rm -rf /var/cache/apk/*

RUN apt-get update -qq && \
apt-get -yqq install mysql-client python-pip git software-properties-common curl && \
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
apt-get install git-lfs && \
apt-get clean && rm -rf /var/lib/apt/lists/*

RUN pip install awscli

Expand Down
2 changes: 1 addition & 1 deletion container/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ else
aws s3 cp $S3_PATH /tmp/oneshot.sh
chmod +x /tmp/oneshot.sh
echo "executing..."
./tmp/oneshot.sh
. /tmp/oneshot.sh
fi
2 changes: 1 addition & 1 deletion input.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"environment": [
{
"name": "S3_PATH",
"value": "s3://some_bucket/some_script.sh"
"value": "{{.path}}"
}
],
"mountPoints": [],
Expand Down
71 changes: 52 additions & 19 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"bytes"
"encoding/json"
"fmt"
"log"
"strings"
"time"

"text/template"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ecs"
"gopkg.in/alecthomas/kingpin.v2"
"log"
"strings"
"time"
)

func logErrorAndFail(err error) {
Expand Down Expand Up @@ -44,23 +47,48 @@ var (
cluster = kingpin.Flag("cluster", "Name of the ECS cluster").Short('c').Required().String()
waitDuration = kingpin.Flag("wait", "How long to wait for task to finish").Short('t').Default("5m").Duration()
taskName = kingpin.Flag("task-name", "Name of the task to create in the cluster").Default("oneshot").Short('n').String()
taskJson = kingpin.Flag("task-json", "JSON file with task definition describing the container running the task").Required().Short('j').File()
taskJSON = kingpin.Flag("task-json", "JSON file with task definition describing the container running the task").Required().Short('j').File()
passAwsKeys = kingpin.Flag("pass-aws-keys", "Add AWS keys to task's environment.").Bool()
params = kingpin.Flag("params", "Parameter that can be used inside the JSON file using Go templating").Short('p').StringMap()

awsKey = kingpin.Flag("aws-access-key-id", "AWS Access Key ID to use (overrides environment)").Short('k').Envar("AWS_ACCESS_KEY_ID").Required().String()
awsSecret = kingpin.Flag("aws-secret-key", "AWS Secret Access Key to use (overrides environment)").Short('s').Envar("AWS_SECRET_ACCESS_KEY").Required().String()
awsRegion = kingpin.Flag("aws-region", "AWS Region to user (overrides environment)").Short('r').Envar("AWS_REGION").Required().String()
)

func deregisterTask(svc *ecs.ECS, taskArn *string) {
_, err := svc.DeregisterTaskDefinition(&ecs.DeregisterTaskDefinitionInput{
TaskDefinition: taskArn,
})
logErrorAndFail(err)
log.Printf("DeRegistered %v successfully", *taskArn)
}

func main() {
kingpin.Version("0.0.1")
kingpin.Parse()

logLevel := aws.LogLevel(aws.LogOff)
var err error

if *debug {
logLevel = aws.LogLevel(aws.LogDebugWithRequestErrors | aws.LogDebugWithHTTPBody)
}

buf := new(bytes.Buffer)
_, err = buf.ReadFrom(*taskJSON)
logErrorAndFail(err)

tmpl, err := template.New("json").Parse(buf.String())
if err != nil {
panic(err)
}
templatedBuf := &bytes.Buffer{}
err = tmpl.Execute(templatedBuf, *params)
logErrorAndFail(err)

creds := credentials.NewStaticCredentials(*awsKey, *awsSecret, "")
sess, err := session.NewSession(&aws.Config{Credentials: creds, LogLevel: logLevel})
sess, err := session.NewSession(&aws.Config{Credentials: creds, Region: awsRegion, LogLevel: logLevel})
logErrorAndFail(err)

svc := ecs.New(sess)
Expand All @@ -75,17 +103,28 @@ func main() {
logErrorAndFail(err)

if len(taskList.TaskDefinitionArns) > 0 {
log.Fatalf("A task family with such name (%v) already exists! Sorry :(", *taskName)
log.Printf("A previous task family with such name (%v) already exists!", *taskName)
deregisterTask(svc, taskList.TaskDefinitionArns[0])
}

def := ecs.RegisterTaskDefinitionInput{}

buf := new(bytes.Buffer)
buf.ReadFrom(*taskJson)
err = json.Unmarshal(buf.Bytes(), &def)
log.Printf(templatedBuf.String())
err = json.Unmarshal(templatedBuf.Bytes(), &def)
logErrorAndFail(err)
def.Family = taskName

def.Family = taskName
if *passAwsKeys {
def.ContainerDefinitions[0].Environment = append(def.ContainerDefinitions[0].Environment, &ecs.KeyValuePair{
Name: aws.String("AWS_ACCESS_KEY_ID"),
Value: awsKey,
}, &ecs.KeyValuePair{
Name: aws.String("AWS_SECRET_ACCESS_KEY"),
Value: awsSecret,
}, &ecs.KeyValuePair{
Name: aws.String("AWS_REGION"),
Value: awsRegion,
})
}
log.Printf("Registering task definition...")
registrationResult, err := svc.RegisterTaskDefinition(&def)
logErrorAndFail(err)
Expand All @@ -94,13 +133,7 @@ func main() {

taskArn := aws.String(fmt.Sprintf("%s:%d", *taskName, *registrationResult.TaskDefinition.Revision))

defer func() {
_, err = svc.DeregisterTaskDefinition(&ecs.DeregisterTaskDefinitionInput{
TaskDefinition: taskArn,
})
logErrorAndFail(err)
log.Printf("DeRegistered %v successfully", *taskArn)
}()
defer deregisterTask(svc, taskArn)

clusterName := aws.String(*cluster)
result, err := svc.RunTask(&ecs.RunTaskInput{
Expand Down Expand Up @@ -128,7 +161,7 @@ func main() {
if err = svc.WaitUntilTasksStopped(waitParam); err == nil {
break
}
waitedTime := time.Now().Sub(startWaitTime)
waitedTime := time.Since(startWaitTime)
if waitedTime > *waitDuration {
log.Fatalf("Aborting due to time out, task still running after %s or another error: %v", shortDur(waitedTime), err)
}
Expand Down

0 comments on commit 459c3aa

Please sign in to comment.