Skip to content

Commit

Permalink
Add ECS deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
qbart committed Nov 9, 2021
1 parent 67f3805 commit 36f2fbe
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 2 deletions.
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
module github.com/Selleo/cli

go 1.13

require (
github.com/aws/aws-sdk-go v1.42.0 // indirect
github.com/urfave/cli/v2 v2.3.0
github.com/wzshiming/ctc v1.2.3 // indirect
)
34 changes: 34 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aws/aws-sdk-go v1.42.0 h1:BMZws0t8NAhHFsfnT3B40IwD13jVDG5KerlRksctVIw=
github.com/aws/aws-sdk-go v1.42.0/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/wzshiming/ctc v1.2.3 h1:q+hW3IQNsjIlOFBTGZZZeIXTElFM4grF4spW/errh/c=
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae h1:tpXvBXC3hpQBDCc9OojJZCQMVRAbT3TTdUMP8WguXkY=
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
120 changes: 118 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,127 @@
package main

import (
"context"
"fmt"
"os"

"github.com/Selleo/cli/selleo"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/urfave/cli/v2"
"github.com/wzshiming/ctc"
)

type AwsEcsDeployInput struct {
Region *string
Cluster *string
Service *string
DockerImage *string
}

func main() {
fmt.Println("Selleo", selleo.Version)
app := &cli.App{
Commands: []*cli.Command{
{
Name: "aws",
Usage: "AWS cloud commands",
Subcommands: []*cli.Command{
{
Name: "ecs",
Usage: "Elastic Container Service",
Subcommands: []*cli.Command{
{
Name: "deploy",
Usage: "Deploy new image to service. This will replace all container tasks.",
Flags: []cli.Flag{
&cli.StringFlag{Name: "region", Usage: "AWS region", Required: true},
&cli.StringFlag{Name: "cluster", Usage: "ECS cluster ID", Required: true},
&cli.StringFlag{Name: "service", Usage: "ECS service ID", Required: true},
&cli.StringFlag{Name: "docker-image", Usage: "Docker image to replace task definition with", Required: true},
},
Action: func(c *cli.Context) error {
actionInput := AwsEcsDeployInput{
Region: aws.String(c.String("region")),
Cluster: aws.String(c.String("cluster")),
Service: aws.String(c.String("service")),
DockerImage: aws.String(c.String("docker-image")),
}

ses, err := session.NewSession(&aws.Config{Region: actionInput.Region})
if err != nil {
return fmt.Errorf("Failed to initiate new session: %w", err)
}
svc := ecs.New(ses)

// 1. fetch running task
serviceOut, err := svc.DescribeServicesWithContext(context.TODO(), &ecs.DescribeServicesInput{
Cluster: actionInput.Cluster,
Services: []*string{actionInput.Service},
})

if err != nil {
return fmt.Errorf("Failed to fetch current running task: %w", err)
}

if len(serviceOut.Services) == 0 {
return fmt.Errorf("No service definition found")
}
if len(serviceOut.Services) != 1 {
// this should not happen because we defined only 1 service in input but stays for sanity check
return fmt.Errorf("Ambigious match, found more than 1 service")
}

var taskDefinition *string
for _, s := range serviceOut.Services {
taskDefinition = s.TaskDefinition
}

// 2. build new task definition
taskDefinitionOut, err := svc.DescribeTaskDefinitionWithContext(context.TODO(), &ecs.DescribeTaskDefinitionInput{
TaskDefinition: taskDefinition,
})

containerDefinitions := []*ecs.ContainerDefinition{}
for _, container := range taskDefinitionOut.TaskDefinition.ContainerDefinitions {
container.Image = actionInput.DockerImage
containerDefinitions = append(containerDefinitions, container)
}

// 3. register new task revision
registerOut, err := svc.RegisterTaskDefinitionWithContext(context.TODO(), &ecs.RegisterTaskDefinitionInput{
ContainerDefinitions: containerDefinitions,
Family: taskDefinitionOut.TaskDefinition.Family,
})
if err != nil {
return fmt.Errorf("Failed to register new task revision: %w", err)
}
arn := registerOut.TaskDefinition.TaskDefinitionArn

// 4. update ecs service with new task arn
updateOut, err := svc.UpdateServiceWithContext(context.TODO(), &ecs.UpdateServiceInput{
Cluster: actionInput.Cluster,
Service: actionInput.Service,
TaskDefinition: arn,
})
if err != nil {
return fmt.Errorf("Failed to update service with new task revision: %w", err)
}

fmt.Fprintf(c.App.Writer, "%sNew deployment for service `%s` created%s\n", ctc.ForegroundGreen, *updateOut.Service.ServiceName, ctc.Reset)

return nil
},
},
},
},
},
},
},
}

err := app.Run(os.Args)
if err != nil {
fmt.Fprintf(app.ErrWriter, "%s%v%s\n", ctc.ForegroundRed, err, ctc.Reset)
os.Exit(1)
}
}

0 comments on commit 36f2fbe

Please sign in to comment.