Skip to content
This repository has been archived by the owner on Apr 6, 2024. It is now read-only.

Part 1: Implement deploy command; update services #2

Merged
merged 8 commits into from
Nov 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
linters:
disable-all: true
enable:
- vet
- revive
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ build:

clean:
rm -rf ${BIN_DIR}

lint:
golangci-lint run

test:
go test -v ./...
100 changes: 100 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,110 @@
# ECS Toolkit

## Configuration

### AWS Credentials

The AWS SDK used internally uses its default credential chain to find AWS
credentials. The SDK detects and uses the built-in providers automatically,
without requiring manual configuration. For example, if you use IAM roles for
Amazon EC2 instances, it automatically use the instance’s credentials. For more
information on setting up AWS credentials, see "[Configuring the AWS
CLI][aws-configuration-cli]" and "[Configuring the AWS SDK for Go
V2][aws-configuration-sdk]".

### Config File

The config file for an application would look like what you see below:

```yaml
---
version: v1
cluster: <name of cluster>
tasks:
- name: <task-definition-1-name>
containers:
- <container-1-name>
- name: <task-definition-2-name>
containers:
- <container-1-name>
- <container-2-name>
# add as many containers as needed
# add as many tasks as needed
services:
- name: <service-1-name>
containers:
- <container-1-name>
- name: <service-2-name>
containers:
- <container-1-name>
- name: <service-3-name>
containers:
- <container-1-name>
# add as many services as needed
```

## Usage

By default, the tool will use the config file located at `.ecs-toolkit.yml` but
you can specify an alternative using the `--config` flag. With that, it's easy
to deploy your application using the `deploy` command. For example:

```console
$ ecs-toolkit -l debug deploy --image-tag=49779134ca1dcef21f0b5123d3d5c2f4f47da650
2022-11-17T18:48:15+02:00 DBG log level set to debug
2022-11-17T18:48:15+02:00 INF using config file: .ecs-toolkit.yml
2022-11-17T18:48:15+02:00 INF reading .ecs-toolkit.yml config file
2022-11-17T18:48:15+02:00 INF parsing config file
2022-11-17T18:48:15+02:00 INF validating config file
2022-11-17T18:48:15+02:00 INF starting deployment of services cluster=shipatlas
2022-11-17T18:48:15+02:00 INF fetching service profiles: hub-web-server, hub-worker, hub-worker-scheduler cluster=shipatlas
2022-11-17T18:48:17+02:00 WRN some services missing, limiting to: hub-web-server cluster=shipatlas
2022-11-17T18:48:17+02:00 INF fetching service task definition profile cluster=shipatlas service=hub-web-server
2022-11-17T18:48:17+02:00 INF building new task definition from hub-web-server:98 cluster=shipatlas service=hub-web-server
2022-11-17T18:48:17+02:00 DBG container image registry: 995655197720.dkr.ecr.us-east-1.amazonaws.com cluster=shipatlas container=rails service=hub-web-server
2022-11-17T18:48:17+02:00 DBG container image name: shipatlas/hub cluster=shipatlas container=rails service=hub-web-server
2022-11-17T18:48:17+02:00 INF old container image tag: 49779134ca1dcef21f0b5123d3d5c2f4f47da650 cluster=shipatlas container=rails service=hub-web-server
2022-11-17T18:48:17+02:00 INF new container image tag: 49779134ca1dcef21f0b5123d3d5c2f4f47da650 cluster=shipatlas container=rails service=hub-web-server
2022-11-17T18:48:17+02:00 WRN skipping container image tag update, no changes cluster=shipatlas container=rails service=hub-web-server
2022-11-17T18:48:17+02:00 WRN skipping registering new task definition, no changes cluster=shipatlas service=hub-web-server
2022-11-17T18:48:17+02:00 WRN skipping service update, no changes cluster=shipatlas service=hub-web-server
2022-11-17T18:48:17+02:00 INF checking if all services are stable cluster=shipatlas
SDK 2022/11/17 18:48:17 DEBUG attempting waiter request, attempt count: 1
2022-11-17T18:48:17+02:00 INF completed deployment of services cluster=shipatlas
```

## Development

Below instructions are only necessary if you intend to work on the source code.
For normal usage the above instructions should do.

### Requirements

1. Ensure that you have a [properly configured][golang-quickstart] Go workspace.

### Building

1. Clone the repository.
2. Fetch the dependencies with `go get -v github.com/shipatlas/ecs-toolkit`.
4. Install application dependencies via `make dependencies` (they'll be placed
in `./vendor`).
5. Build and install the binary with `make build`.
6. Run the command e.g. `./bin/ecs-toolkit help` as a basic test.

### Testing

1. Install the `golangci-lint`, [see instructions here][golangci-lint-install].
2. Run linter using `make lint` and test using `make test`.

## License

[ShipAtlas][shipatlas] © 2022. The [MIT License bundled therein][license] is a
permissive license that is short and to the point. It lets people do anything
they want as long as they provide attribution and waive liability.

[aws-configuration-cli]: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html
[aws-configuration-sdk]: https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/
[golang-quickstart]: https://go.dev/doc/tutorial/getting-started
[golangci-lint-install]: https://golangci-lint.run/usage/install/
[license]: https://raw.githubusercontent.com/shipatlas/ecs-toolkit/main/LICENSE
[shipatlas]: https://www.shipatlas.dev
46 changes: 43 additions & 3 deletions cmd/deploy.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,64 @@
package cmd

import (
"context"

"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ecs"
"github.com/rs/zerolog/log"
"github.com/shipatlas/ecs-toolkit/utils"
"github.com/spf13/cobra"
)

type deployOptions struct {
imageTag string
}

var (
deployCmdLong = utils.LongDesc(`
Deploy an application to AWS ECS`)

deployCmdExamples = utils.Examples(`
# Deploy new revision of an application
ecs-toolkit deploy --image-tag=5a853f72`)

deployCmdOptions = &deployOptions{}
)

// deployCmd represents the deploy command
var deployCmd = &cobra.Command{
Use: "deploy",
Short: "Deploy an application to AWS ECS.",
Long: deployCmdLong,
Use: "deploy",
Short: "Deploy an application to AWS ECS.",
Long: deployCmdLong,
Example: deployCmdExamples,
Run: func(cmd *cobra.Command, args []string) {
deployCmdOptions.validate()
deployCmdOptions.run()
},
}

func init() {
rootCmd.AddCommand(deployCmd)

// Local flags, which, will be global for the application.
deployCmd.Flags().StringVarP(&deployCmdOptions.imageTag, "image-tag", "t", "", "image tag to update the container images to")

// Configure required flags, applying to this specific command.
deployCmd.MarkFlagRequired("image-tag")
}

func (options *deployOptions) validate() {
if options.imageTag == "" {
log.Fatal().Msg("image-tag flag must be set and should not be blank")
}
}

func (options *deployOptions) run() {
awsCfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
log.Fatal().Err(err).Msg("unable to load aws config")
}
client := ecs.NewFromConfig(awsCfg)

toolConfig.DeployServices(&options.imageTag, client)
}
6 changes: 3 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type rootOptions struct {
logLevel string
}

var Config = pkg.Config{}
var toolConfig = pkg.Config{}

var (
rootCmdLong = utils.LongDesc(`
Expand Down Expand Up @@ -85,13 +85,13 @@ func initConfig() {
}

log.Info().Msg("parsing config file")
if err := viper.Unmarshal(&Config); err != nil {
if err := viper.Unmarshal(&toolConfig); err != nil {
log.Fatal().Err(err).Msg("unable to parse config file")
}

log.Info().Msg("validating config file")
validate := validator.New()
err := validate.Struct(&Config)
err := validate.Struct(&toolConfig)
if err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
log.Error().Msg(strings.ToLower(err.Error()))
Expand Down
15 changes: 15 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,33 @@ module github.com/shipatlas/ecs-toolkit
go 1.19

require (
github.com/aws/aws-sdk-go-v2/config v1.18.0
github.com/aws/aws-sdk-go-v2/service/ecs v1.19.0
github.com/go-playground/validator/v10 v10.11.1
github.com/novln/docker-parser v1.0.0
github.com/rs/zerolog v1.28.0
github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.14.0
)

require (
github.com/aws/aws-sdk-go-v2 v1.17.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.0 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.17.2 // indirect
github.com/aws/smithy-go v1.13.4 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
Expand Down
34 changes: 34 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,32 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk=
github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw=
github.com/aws/aws-sdk-go-v2/config v1.18.0 h1:ULASZmfhKR/QE9UeZ7mzYjUzsnIydy/K1YMT6uH1KC0=
github.com/aws/aws-sdk-go-v2/config v1.18.0/go.mod h1:H13DRX9Nv5tAcQvPABrE3dm5XnLp1RC7fVSM3OWiLvA=
github.com/aws/aws-sdk-go-v2/credentials v1.13.0 h1:W5f73j1qurASap+jdScUo4aGzSXxaC7wq1i7CiwhvU8=
github.com/aws/aws-sdk-go-v2/credentials v1.13.0/go.mod h1:prZpUfBu1KZLBLVX482Sq4DpDXGugAre08TPEc21GUg=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 h1:E3PXZSI3F2bzyj6XxUXdTIfvp425HHhwKsFvmzBwHgs=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19/go.mod h1:VihW95zQpeKQWVPGkwT+2+WJNQV8UXFfMTWdU6VErL8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 h1:nBO/RFxeq/IS5G9Of+ZrgucRciie2qpLy++3UGZ+q2E=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 h1:oRHDrwCTVT8ZXi4sr9Ld+EXk7N/KGssOr2ygNeojEhw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 h1:Mza+vlnZr+fPKFKRq/lKGVvM6B/8ZZmNdEopOwSQLms=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26/go.mod h1:Y2OJ+P+MC1u1VKnavT+PshiEuGPyh/7DqxoDNij4/bg=
github.com/aws/aws-sdk-go-v2/service/ecs v1.19.0 h1:1YBaW1OVJfh5HScRrFq+pSoTP03/SzO9Xfyf+iTVKJ4=
github.com/aws/aws-sdk-go-v2/service/ecs v1.19.0/go.mod h1:NpR78BP2STxvF/R1GXLDM4gAEfjz68W/h0nC5b6Jk3s=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 h1:GE25AWCdNUPh9AOJzI9KIJnja7IwUc1WyUqz/JTyJ/I=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19/go.mod h1:02CP6iuYP+IVnBX5HULVdSAku/85eHB2Y9EsFhrkEwU=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 h1:GFZitO48N/7EsFDt8fMa5iYdmWqkUDDB3Eje6z3kbG0=
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vboR0FeJ89OkEy1M9mWbK2ifCI=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 h1:jcw6kKZrtNfBPJkaHrscDOZoe5gvi9wjudnxvozYFJo=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8/go.mod h1:er2JHN+kBY6FcMfcBBKNGCT3CarImmdFzishsqBmSRI=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.2 h1:tpwEMRdMf2UsplengAOnmSIRdvAxf75oUFR+blBr92I=
github.com/aws/aws-sdk-go-v2/service/sts v1.17.2/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4=
github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk=
github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
Expand Down Expand Up @@ -109,6 +135,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
Expand Down Expand Up @@ -136,6 +163,10 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
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 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
Expand All @@ -158,6 +189,8 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/novln/docker-parser v1.0.0 h1:PjEBd9QnKixcWczNGyEdfUrP6GR0YUilAqG7Wksg3uc=
github.com/novln/docker-parser v1.0.0/go.mod h1:oCeM32fsoUwkwByB5wVjsrsVQySzPWkl3JdlTn1txpE=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
Expand Down Expand Up @@ -505,6 +538,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
9 changes: 9 additions & 0 deletions pkg/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,12 @@ type Task struct {
Containers []*string `mapstructure:"containers" validate:"required,min=1,dive"`
Force *bool `mapstructure:"force"`
}

func (config *Config) ServiceNames() []string {
serviceNames := []string{}
for _, service := range config.Services {
serviceNames = append(serviceNames, *service.Name)
}

return serviceNames
}
Loading