Skip to content

Commit

Permalink
Merge pull request #4 from kayac/desired-count
Browse files Browse the repository at this point in the history
Set desired count at deploy.
  • Loading branch information
fujiwara authored Dec 14, 2017
2 parents 465896e + 8920786 commit 2836341
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 43 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ install: cmd/ecspresso/ecspresso
install cmd/ecspresso/ecspresso ${GOPATH}/bin

test:
go test -race
go test -race .
go test -race ./cmd/ecspresso

get-dep-amd64:
wget -O ${GOPATH}/bin/dep https://github.com/golang/dep/releases/download/v0.3.2/dep-linux-amd64
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Commands:
rollback service
```

For more options for sub-commands, See `ecspresso sub-command --help`.

### Configuration file

YAML format.
Expand Down Expand Up @@ -73,6 +75,16 @@ Events:
2017/11/09 23:23:29 myService/default Service is stable now. Completed!
```

## Scale out/in

To change desired count of the service, specify `--tasks` option.

If `--skip-task-definition` is set, task definition will not be registered.

```console
$ ecspresso deploy --config config.yaml --tasks 10 --skip-task-definition
```

## Example of create

escpresso can create service by `service_definition` JSON file and `task_definition`.
Expand Down
7 changes: 5 additions & 2 deletions cmd/ecspresso/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ func _main() int {

deploy := kingpin.Command("deploy", "deploy service")
deployOption := ecspresso.DeployOption{
DryRun: deploy.Flag("dry-run", "dry-run").Bool(),
DryRun: deploy.Flag("dry-run", "dry-run").Bool(),
DesiredCount: deploy.Flag("tasks", "desired count of tasks").Default("-1").Int64(),
SkipTaskDefinition: deploy.Flag("skip-task-definition", "skip register a new task definition").Bool(),
}

create := kingpin.Command("create", "create service")
createOption := ecspresso.CreateOption{
DryRun: create.Flag("dry-run", "dry-run").Bool(),
DryRun: create.Flag("dry-run", "dry-run").Bool(),
DesiredCount: create.Flag("tasks", "desired count of tasks").Default("1").Int64(),
}

status := kingpin.Command("status", "show status of service")
Expand Down
101 changes: 63 additions & 38 deletions ecspresso.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ import (

var isTerminal = isatty.IsTerminal(os.Stdout.Fd())

const KeepDesiredCount = -1

func taskDefinitionName(t *ecs.TaskDefinition) string {
return fmt.Sprintf("%s:%d", *t.Family, *t.Revision)
}

type App struct {
ecs *ecs.ECS
Service string
Cluster string
TaskDefinition *ecs.TaskDefinition
Registered *ecs.TaskDefinition
config *Config
ecs *ecs.ECS
Service string
Cluster string
config *Config
}

func (d *App) DescribeServicesInput() *ecs.DescribeServicesInput {
Expand Down Expand Up @@ -118,30 +118,35 @@ func (d *App) Create(opt CreateOption) error {
defer cancel()

d.Log("Starting create service")
if err := d.LoadTaskDefinition(d.config.TaskDefinitionPath); err != nil {
td, err := d.LoadTaskDefinition(d.config.TaskDefinitionPath)
if err != nil {
return errors.Wrap(err, "create failed")
}
svd, err := d.LoadServiceDefinition(d.config.ServiceDefinitionPath)
if err != nil {
return errors.Wrap(err, "create failed")
}
svd.DesiredCount = opt.DesiredCount

if *opt.DryRun {
d.Log("task definition:", d.TaskDefinition.String())
d.Log("task definition:", td.String())
d.Log("service definition:", svd.String())
d.Log("DRY RUN OK")
return nil
}

if err := d.RegisterTaskDefinition(ctx); err != nil {
newTd, err := d.RegisterTaskDefinition(ctx, td)
if err != nil {
return errors.Wrap(err, "create failed")
}
svd.TaskDefinition = d.Registered.TaskDefinitionArn
svd.TaskDefinition = newTd.TaskDefinitionArn

if _, err := d.ecs.CreateServiceWithContext(ctx, svd); err != nil {
return errors.Wrap(err, "create failed")
}
d.Log("Service is created")

time.Sleep(3 * time.Second) // wait for service created
if err := d.WaitServiceStable(ctx); err != nil {
return errors.Wrap(err, "create failed")
}
Expand All @@ -155,22 +160,43 @@ func (d *App) Deploy(opt DeployOption) error {
defer cancel()

d.Log("Starting deploy")
if _, err := d.DescribeServiceStatus(ctx, 0); err != nil {
svd, err := d.DescribeServiceStatus(ctx, 0)
if err != nil {
return errors.Wrap(err, "deploy failed")
}
if err := d.LoadTaskDefinition(d.config.TaskDefinitionPath); err != nil {
return errors.Wrap(err, "deploy failed")

var count *int64
if *opt.DesiredCount == KeepDesiredCount {
count = svd.DesiredCount
} else {
count = opt.DesiredCount
}

var tdArn string
if *opt.SkipTaskDefinition {
tdArn = *svd.TaskDefinition
} else {
td, err := d.LoadTaskDefinition(d.config.TaskDefinitionPath)
if err != nil {
return errors.Wrap(err, "deploy failed")
}
if *opt.DryRun {
d.Log("task definition:", td.String())
} else {
newTd, err := d.RegisterTaskDefinition(ctx, td)
if err != nil {
return errors.Wrap(err, "deploy failed")
}
tdArn = *newTd.TaskDefinitionArn
}
}
d.Log("desired count:", *count)
if *opt.DryRun {
d.Log("task definition:", d.TaskDefinition.String())
d.Log("DRY RUN OK")
return nil
}

if err := d.RegisterTaskDefinition(ctx); err != nil {
return errors.Wrap(err, "deploy failed")
}
if err := d.UpdateService(ctx, *d.Registered.TaskDefinitionArn); err != nil {
if err := d.UpdateService(ctx, tdArn, count); err != nil {
return errors.Wrap(err, "deploy failed")
}
if err := d.WaitServiceStable(ctx); err != nil {
Expand Down Expand Up @@ -200,7 +226,7 @@ func (d *App) Rollback(opt RollbackOption) error {
return nil
}

if err := d.UpdateService(ctx, targetArn); err != nil {
if err := d.UpdateService(ctx, targetArn, service.DesiredCount); err != nil {
return errors.Wrap(err, "rollback failed")
}
if err := d.WaitServiceStable(ctx); err != nil {
Expand Down Expand Up @@ -279,7 +305,7 @@ func (d *App) WaitServiceStable(ctx context.Context) error {
return d.ecs.WaitUntilServicesStableWithContext(ctx, d.DescribeServicesInput())
}

func (d *App) UpdateService(ctx context.Context, taskDefinitionArn string) error {
func (d *App) UpdateService(ctx context.Context, taskDefinitionArn string, count *int64) error {
d.Log("Updating service...")

_, err := d.ecs.UpdateServiceWithContext(
Expand All @@ -288,47 +314,46 @@ func (d *App) UpdateService(ctx context.Context, taskDefinitionArn string) error
Service: aws.String(d.Service),
Cluster: aws.String(d.Cluster),
TaskDefinition: aws.String(taskDefinitionArn),
DesiredCount: count,
},
)
return err
}

func (d *App) RegisterTaskDefinition(ctx context.Context) error {
func (d *App) RegisterTaskDefinition(ctx context.Context, td *ecs.TaskDefinition) (*ecs.TaskDefinition, error) {
d.Log("Registering a new task definition...")

out, err := d.ecs.RegisterTaskDefinitionWithContext(
ctx,
&ecs.RegisterTaskDefinitionInput{
ContainerDefinitions: d.TaskDefinition.ContainerDefinitions,
Cpu: d.TaskDefinition.Cpu,
ExecutionRoleArn: d.TaskDefinition.ExecutionRoleArn,
Family: d.TaskDefinition.Family,
Memory: d.TaskDefinition.Memory,
NetworkMode: d.TaskDefinition.NetworkMode,
PlacementConstraints: d.TaskDefinition.PlacementConstraints,
RequiresCompatibilities: d.TaskDefinition.RequiresCompatibilities,
TaskRoleArn: d.TaskDefinition.TaskRoleArn,
Volumes: d.TaskDefinition.Volumes,
ContainerDefinitions: td.ContainerDefinitions,
Cpu: td.Cpu,
ExecutionRoleArn: td.ExecutionRoleArn,
Family: td.Family,
Memory: td.Memory,
NetworkMode: td.NetworkMode,
PlacementConstraints: td.PlacementConstraints,
RequiresCompatibilities: td.RequiresCompatibilities,
TaskRoleArn: td.TaskRoleArn,
Volumes: td.Volumes,
},
)
if err != nil {
return err
return nil, err
}
d.Log("Task definition is registered", taskDefinitionName(out.TaskDefinition))
d.Registered = out.TaskDefinition
return nil
return out.TaskDefinition, nil
}

func (d *App) LoadTaskDefinition(path string) error {
func (d *App) LoadTaskDefinition(path string) (*ecs.TaskDefinition, error) {
d.Log("Creating a new task definition by", path)
c := struct {
TaskDefinition *ecs.TaskDefinition
}{}
if err := config.LoadWithEnvJSON(&c, path); err != nil {
return err
return nil, err
}
d.TaskDefinition = c.TaskDefinition
return nil
return c.TaskDefinition, nil
}

func (d *App) LoadServiceDefinition(path string) (*ecs.CreateServiceInput, error) {
Expand Down
7 changes: 5 additions & 2 deletions options.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package ecspresso

type CreateOption struct {
DryRun *bool
DryRun *bool
DesiredCount *int64
}

type DeployOption struct {
DryRun *bool
DryRun *bool
DesiredCount *int64
SkipTaskDefinition *bool
}

type StatusOption struct {
Expand Down

0 comments on commit 2836341

Please sign in to comment.