-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
158 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |