shipitron 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.dockerignore +4 -0
- data/.gitignore +4 -0
- data/.rspec +3 -0
- data/Dockerfile +60 -0
- data/Dockerfile.release +49 -0
- data/README.md +44 -10
- data/build_dev.sh +39 -0
- data/exe/shipitron +5 -0
- data/lib/shipitron/cli.rb +132 -0
- data/lib/shipitron/client/bootstrap_application.rb +35 -0
- data/lib/shipitron/client/create_ecs_services.rb +81 -0
- data/lib/shipitron/client/deploy_application.rb +34 -0
- data/lib/shipitron/client/ensure_deploy_not_running.rb +54 -0
- data/lib/shipitron/client/load_application_config.rb +41 -0
- data/lib/shipitron/client/load_templates.rb +45 -0
- data/lib/shipitron/client/register_ecs_task_definitions.rb +75 -0
- data/lib/shipitron/client/run_ecs_tasks.rb +141 -0
- data/lib/shipitron/consul_keys.rb +34 -0
- data/lib/shipitron/consul_lock.rb +28 -0
- data/lib/shipitron/docker_image.rb +23 -0
- data/lib/shipitron/ecs_client.rb +22 -0
- data/lib/shipitron/ecs_task_def.rb +17 -0
- data/lib/shipitron/fetch_bucket.rb +26 -0
- data/lib/shipitron/logger.rb +33 -0
- data/lib/shipitron/mustache_yaml_parser.rb +22 -0
- data/lib/shipitron/parse_templates.rb +32 -0
- data/lib/shipitron/post_build.rb +32 -0
- data/lib/shipitron/server/deploy_application.rb +75 -0
- data/lib/shipitron/server/docker/build_image.rb +25 -0
- data/lib/shipitron/server/docker/configure.rb +35 -0
- data/lib/shipitron/server/docker/push_image.rb +37 -0
- data/lib/shipitron/server/docker/run_build_script.rb +53 -0
- data/lib/shipitron/server/download_build_cache.rb +44 -0
- data/lib/shipitron/server/ecs_task_defs/map_parsed_templates.rb +31 -0
- data/lib/shipitron/server/ecs_task_defs/update_from_params.rb +42 -0
- data/lib/shipitron/server/ecs_task_defs/update_in_place.rb +68 -0
- data/lib/shipitron/server/git/clone_local_copy.rb +46 -0
- data/lib/shipitron/server/git/configure.rb +40 -0
- data/lib/shipitron/server/git/download_cache.rb +56 -0
- data/lib/shipitron/server/git/pull_repo.rb +30 -0
- data/lib/shipitron/server/git/update_cache.rb +52 -0
- data/lib/shipitron/server/git/upload_cache.rb +61 -0
- data/lib/shipitron/server/run_post_build.rb +79 -0
- data/lib/shipitron/server/transform_cli_args.rb +85 -0
- data/lib/shipitron/server/update_ecs_services.rb +105 -0
- data/lib/shipitron/server/update_ecs_task_definitions.rb +47 -0
- data/lib/shipitron/server/upload_build_cache.rb +43 -0
- data/lib/shipitron/smash.rb +10 -0
- data/lib/shipitron/version.rb +1 -1
- data/lib/shipitron.rb +38 -0
- data/scripts/docker-entrypoint.sh +18 -0
- data/scripts/fetch-bundler-data.sh +16 -0
- data/shipitron.gemspec +14 -0
- metadata +236 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26404f4e8acd7b859cc8dc2e74a399ccb08ff293
|
4
|
+
data.tar.gz: 5654cccd96d69d418e468f1a95217d89000f6edf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24a5b2934c357f1204d315c32c7fcba122aad527e165feb4015c5b44f77335f7e7ed5226833216417da210711077204ce9d93f0c7d779ca454781be8713f40ff
|
7
|
+
data.tar.gz: b1978b9a83fae96d8c7d992253f46e0d4ebd87a3943080bdb0d697c36677100a6a27498376d48b415eb58ea690528abc38b6a5080b4eb5045f4ef6cafe97adea
|
data/.dockerignore
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/Dockerfile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
FROM ruby:2.3.1-alpine
|
2
|
+
MAINTAINER Ryan Schlesinger <ryan@outstand.com>
|
3
|
+
|
4
|
+
RUN addgroup -S shipitron && \
|
5
|
+
adduser -S -G shipitron shipitron && \
|
6
|
+
addgroup -g 1101 docker && \
|
7
|
+
addgroup shipitron docker
|
8
|
+
|
9
|
+
ENV GOSU_VERSION 1.9
|
10
|
+
ENV DUMB_INIT_VERSION 1.1.3
|
11
|
+
|
12
|
+
RUN apk add --no-cache ca-certificates gnupg && \
|
13
|
+
mkdir -p /tmp/build && \
|
14
|
+
cd /tmp/build && \
|
15
|
+
gpg --keyserver pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 && \
|
16
|
+
curl -o gosu -L "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64" && \
|
17
|
+
curl -o gosu.asc -L "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64.asc" && \
|
18
|
+
gpg --verify gosu.asc && \
|
19
|
+
chmod +x gosu && \
|
20
|
+
cp gosu /bin/gosu && \
|
21
|
+
curl -O -L https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_amd64 && \
|
22
|
+
curl -O -L https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/sha256sums && \
|
23
|
+
grep dumb-init_${DUMB_INIT_VERSION}_amd64$ sha256sums | sha256sum -c && \
|
24
|
+
chmod +x dumb-init_${DUMB_INIT_VERSION}_amd64 && \
|
25
|
+
cp dumb-init_${DUMB_INIT_VERSION}_amd64 /bin/dumb-init && \
|
26
|
+
cd /tmp && \
|
27
|
+
rm -rf /tmp/build && \
|
28
|
+
apk del gnupg && \
|
29
|
+
rm -rf /root/.gnupg
|
30
|
+
|
31
|
+
RUN apk add --no-cache \
|
32
|
+
build-base \
|
33
|
+
git \
|
34
|
+
openssh \
|
35
|
+
perl \
|
36
|
+
bash
|
37
|
+
|
38
|
+
ENV USE_BUNDLE_EXEC true
|
39
|
+
ENV BUNDLE_GEMFILE /shipitron/Gemfile
|
40
|
+
|
41
|
+
WORKDIR /app
|
42
|
+
COPY Gemfile shipitron.gemspec /shipitron/
|
43
|
+
COPY lib/shipitron/version.rb /shipitron/lib/shipitron/
|
44
|
+
COPY scripts/fetch-bundler-data.sh /shipitron/scripts/fetch-bundler-data.sh
|
45
|
+
|
46
|
+
ARG bundler_data_host
|
47
|
+
RUN /shipitron/scripts/fetch-bundler-data.sh ${bundler_data_host} && \
|
48
|
+
(bundle check || bundle install) && \
|
49
|
+
git config --global push.default simple
|
50
|
+
COPY . /shipitron/
|
51
|
+
RUN ln -s /shipitron/exe/shipitron /usr/local/bin/shipitron && \
|
52
|
+
mkdir -p /home/shipitron/.ssh && \
|
53
|
+
chown shipitron:shipitron /home/shipitron/.ssh && \
|
54
|
+
chmod 700 /home/shipitron/.ssh
|
55
|
+
|
56
|
+
COPY scripts/docker-entrypoint.sh /docker-entrypoint.sh
|
57
|
+
|
58
|
+
ENV DUMB_INIT_SETSID 0
|
59
|
+
ENTRYPOINT ["/docker-entrypoint.sh"]
|
60
|
+
CMD ["help"]
|
data/Dockerfile.release
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
FROM ruby:2.3.1-alpine
|
2
|
+
MAINTAINER Ryan Schlesinger <ryan@outstand.com>
|
3
|
+
|
4
|
+
RUN addgroup -S shipitron && \
|
5
|
+
adduser -S -G shipitron shipitron && \
|
6
|
+
addgroup -g 1101 docker && \
|
7
|
+
addgroup shipitron docker
|
8
|
+
|
9
|
+
ENV GOSU_VERSION 1.9
|
10
|
+
ENV DUMB_INIT_VERSION 1.1.3
|
11
|
+
|
12
|
+
RUN apk add --no-cache ca-certificates gnupg && \
|
13
|
+
mkdir -p /tmp/build && \
|
14
|
+
cd /tmp/build && \
|
15
|
+
gpg --keyserver pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 && \
|
16
|
+
curl -o gosu -L "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64" && \
|
17
|
+
curl -o gosu.asc -L "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64.asc" && \
|
18
|
+
gpg --verify gosu.asc && \
|
19
|
+
chmod +x gosu && \
|
20
|
+
cp gosu /bin/gosu && \
|
21
|
+
curl -O -L https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_amd64 && \
|
22
|
+
curl -O -L https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/sha256sums && \
|
23
|
+
grep dumb-init_${DUMB_INIT_VERSION}_amd64$ sha256sums | sha256sum -c && \
|
24
|
+
chmod +x dumb-init_${DUMB_INIT_VERSION}_amd64 && \
|
25
|
+
cp dumb-init_${DUMB_INIT_VERSION}_amd64 /bin/dumb-init && \
|
26
|
+
cd /tmp && \
|
27
|
+
rm -rf /tmp/build && \
|
28
|
+
apk del gnupg && \
|
29
|
+
rm -rf /root/.gnupg
|
30
|
+
|
31
|
+
RUN apk add --no-cache \
|
32
|
+
git \
|
33
|
+
perl \
|
34
|
+
bash
|
35
|
+
|
36
|
+
WORKDIR /app
|
37
|
+
|
38
|
+
ENV SHIPITRON_VERSION=0.2.0
|
39
|
+
|
40
|
+
RUN gem install shipitron -v ${SHIPITRON_VERSION} && \
|
41
|
+
mkdir -p /home/shipitron/.ssh && \
|
42
|
+
chown shipitron:shipitron /home/shipitron/.ssh && \
|
43
|
+
chmod 700 /home/shipitron/.ssh
|
44
|
+
|
45
|
+
COPY scripts/docker-entrypoint.sh /docker-entrypoint.sh
|
46
|
+
|
47
|
+
ENV DUMB_INIT_SETSID 0
|
48
|
+
ENTRYPOINT ["/docker-entrypoint.sh"]
|
49
|
+
CMD ["help"]
|
data/README.md
CHANGED
@@ -1,13 +1,47 @@
|
|
1
1
|
# shipitron
|
2
2
|
A deployment tool for use with Docker and ECS
|
3
3
|
|
4
|
-
##
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
-
|
10
|
-
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
## Usage
|
5
|
+
|
6
|
+
Example config file:
|
7
|
+
```yaml
|
8
|
+
applications:
|
9
|
+
dummy-app:
|
10
|
+
repository: git@github.com:outstand/dummy-app
|
11
|
+
cache_bucket: bucket
|
12
|
+
image_name: outstand/dummy-app
|
13
|
+
build_script: shipitron/build.sh
|
14
|
+
post_builds:
|
15
|
+
- ecs_task: dummy-app
|
16
|
+
container_name: dummy-app
|
17
|
+
command: echo postbuild
|
18
|
+
ecs_clusters:
|
19
|
+
- name: us-east-1-prod-blue
|
20
|
+
region: us-east-1
|
21
|
+
- name: us-east-1-prod-green
|
22
|
+
region: us-east-1
|
23
|
+
shipitron_task: shipitron
|
24
|
+
ecs_task_defs:
|
25
|
+
- dummy-app
|
26
|
+
ecs_services:
|
27
|
+
- dummy-app
|
28
|
+
```
|
29
|
+
|
30
|
+
- Create shipitron.yml file
|
31
|
+
- `docker run -it --rm -v shipitron.yml:/shipitron/config/shipitron.yml outstand/shipitron:<version> deploy <app>`
|
32
|
+
|
33
|
+
## Development
|
34
|
+
|
35
|
+
- `docker volume create --name shipitron_fog`
|
36
|
+
- `./build_dev.sh`
|
37
|
+
- `docker run -it --rm -v $(pwd):/shipitron -v shipitron_fog:/fog -e FOG_LOCAL=true outstand/shipitron:dev rspec spec` to run specs
|
38
|
+
- `docker run -it --rm -v $(pwd):/shipitron outstand/shipitron:dev deploy <app>` to run client side
|
39
|
+
- `docker run -it --rm -v $(pwd):/shipitron outstand/shipitron:dev deploy <app> --simulate` to get the arguments for `server_deploy` below
|
40
|
+
- `docker run -it --rm --dns 10.10.10.2 -v /path/to/shipitron:/shipitron -v $(pwd):/app -v /bin/docker:/bin/docker -v /var/run/docker.sock:/var/run/docker.sock -v shipitron_fog:/fog -e FOG_LOCAL=true -e CONSUL_HOST=consul outstand/shipitron:dev server_deploy --name dummy-app --repository git@github.com:outstand/dummy-app --bucket outstand-shipitron --image-name outstand/dummy-app --region us-east-1 --cluster-name us-east-1-prod-blue --ecs-task-defs dummy-app --ecs-services dummy-app --build-script shipitron/build.sh --post-builds 'ecs_task:dummy-app,container_name:dummy-app,command:echo postbuild' --ecs-task-def-templates LS0tCmZhbWlseTogZHVtbXktYXBwCmNvbnRhaW5lcl9kZWZpbml0aW9uczoKICAtIG5hbWU6IGR1bW15LWFwcAogICAgaW1hZ2U6IG91dHN0YW5kL2R1bW15LWFwcDp7e3RhZ319CiAgICBtZW1vcnk6IDEyOAogICAgZXNzZW50aWFsOiB0cnVlCiAgICBwb3J0X21hcHBpbmdzOgogICAgICAtIGNvbnRhaW5lcl9wb3J0OiA4MAogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gbmFtZTogU0VSVklDRV84MF9OQU1FCiAgICAgICAgdmFsdWU6IGR1bW15Cg== --ecs-service-templates LS0tCmNsdXN0ZXI6IHt7Y2x1c3Rlcn19CnNlcnZpY2VfbmFtZTogZHVtbXktYXBwCnRhc2tfZGVmaW5pdGlvbjogZHVtbXktYXBwe3tyZXZpc2lvbn19CmRlc2lyZWRfY291bnQ6IHt7Y291bnR9fQojcm9sZToge3tyb2xlfX0KZGVwbG95bWVudF9jb25maWd1cmF0aW9uOgogIG1heGltdW1fcGVyY2VudDogMjAwCiAgbWluaW11bV9oZWFsdGh5X3BlcmNlbnQ6IDUwCg== --debug` to run server side (dummy-app is an example)
|
41
|
+
|
42
|
+
To release a new version:
|
43
|
+
- Update the version number in `version.rb` and `Dockerfile.release` and commit the result.
|
44
|
+
- `./build_dev.sh`
|
45
|
+
- `docker run -it --rm -v ~/.gitconfig:/root/.gitconfig -v ~/.gitconfig.user:/root/.gitconfig.user -v ~/.ssh/id_rsa:/root/.ssh/id_rsa -v ~/.gem:/root/.gem -w /shipitron outstand/shipitron:dev rake release`
|
46
|
+
- `docker build -t outstand/shipitron:VERSION -f Dockerfile.release .`
|
47
|
+
- `docker push outstand/shipitron:VERSION`
|
data/build_dev.sh
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -e -x
|
3
|
+
|
4
|
+
build_image=outstand/shipitron:dev
|
5
|
+
dockerfile=Dockerfile
|
6
|
+
bundler_data_dir=tmp
|
7
|
+
|
8
|
+
bundler_data_container=''
|
9
|
+
tar_container=''
|
10
|
+
|
11
|
+
function cleanup {
|
12
|
+
if [ -n "$bundler_data_container" ]; then
|
13
|
+
docker stop bundler-data
|
14
|
+
docker rm -fv bundler-data
|
15
|
+
fi
|
16
|
+
|
17
|
+
if [ -n "$tar_container" ]; then
|
18
|
+
docker rm -fv ${tar_container}
|
19
|
+
fi
|
20
|
+
|
21
|
+
rm -f ${bundler_data_dir}/cidfile
|
22
|
+
}
|
23
|
+
|
24
|
+
trap cleanup EXIT
|
25
|
+
|
26
|
+
build_args=''
|
27
|
+
mkdir -p ${bundler_data_dir}
|
28
|
+
|
29
|
+
if [ -f $(pwd)/${bundler_data_dir}/bundler-data.tar.gz ]; then
|
30
|
+
docker run --name bundler-data -v $(pwd)/${bundler_data_dir}/bundler-data.tar.gz:/usr/share/nginx/html/bundler-data.tar.gz:ro -d nginx:stable-alpine
|
31
|
+
bundler_data_container=bundler-data
|
32
|
+
build_args="--build-arg bundler_data_host=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' bundler-data)"
|
33
|
+
fi
|
34
|
+
|
35
|
+
docker build -t ${build_image} -f ${dockerfile} ${build_args} .
|
36
|
+
|
37
|
+
docker run -t --cidfile=${bundler_data_dir}/cidfile -w /usr/local/bundle ${build_image} tar -zcf /tmp/bundler-data.tar.gz .
|
38
|
+
tar_container=$(cat ${bundler_data_dir}/cidfile)
|
39
|
+
docker cp ${tar_container}:/tmp/bundler-data.tar.gz ${bundler_data_dir}/bundler-data.tar.gz
|
data/exe/shipitron
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'shipitron'
|
3
|
+
|
4
|
+
module Shipitron
|
5
|
+
class CLI < Thor
|
6
|
+
desc 'version', 'Print out the version string'
|
7
|
+
def version
|
8
|
+
require 'shipitron/version'
|
9
|
+
say Shipitron::VERSION.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'deploy <app>', 'Deploys the app'
|
13
|
+
option :config_file, default: 'shipitron/config.yml'
|
14
|
+
option :secrets_file, default: 'shipitron/secrets.yml'
|
15
|
+
option :ember, type: :boolean, default: false
|
16
|
+
option :ember_only, type: :boolean, default: false
|
17
|
+
option :debug, type: :boolean, default: false
|
18
|
+
option :simulate, type: :boolean, default: false
|
19
|
+
def deploy(app)
|
20
|
+
setup(
|
21
|
+
config_file: options[:config_file],
|
22
|
+
secrets_file: options[:secrets_file]
|
23
|
+
)
|
24
|
+
|
25
|
+
require 'shipitron/client/deploy_application'
|
26
|
+
result = Client::DeployApplication.call(
|
27
|
+
application: app,
|
28
|
+
simulate: options[:simulate]
|
29
|
+
)
|
30
|
+
|
31
|
+
if result.failure?
|
32
|
+
result.errors.each do |error|
|
33
|
+
Logger.fatal error
|
34
|
+
end
|
35
|
+
Logger.fatal 'Deploy failed.'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'server_deploy', 'Server-side component of deploy'
|
40
|
+
option :name, required: true
|
41
|
+
option :repository, required: true
|
42
|
+
option :branch, default: 'master'
|
43
|
+
option :bucket, required: true
|
44
|
+
option :image_name, required: true
|
45
|
+
option :region, required: true
|
46
|
+
option :cluster_name, required: true
|
47
|
+
option :ecs_task_defs, type: :array, required: true
|
48
|
+
option :ecs_task_def_templates, type: :array, default: []
|
49
|
+
option :ecs_services, type: :array, required: true
|
50
|
+
option :ecs_service_templates, type: :array, default: []
|
51
|
+
option :build_script, default: nil
|
52
|
+
option :post_builds, type: :array
|
53
|
+
option :secrets_file, default: 'shipitron/secrets.yml'
|
54
|
+
option :debug, type: :boolean, default: false
|
55
|
+
def server_deploy
|
56
|
+
setup(
|
57
|
+
secrets_file: options[:secrets_file]
|
58
|
+
)
|
59
|
+
|
60
|
+
require 'shipitron/server/transform_cli_args'
|
61
|
+
cli_args = Server::TransformCliArgs.call!(
|
62
|
+
application: options[:name],
|
63
|
+
repository_url: options[:repository],
|
64
|
+
repository_branch: options[:branch],
|
65
|
+
s3_cache_bucket: options[:bucket],
|
66
|
+
image_name: options[:image_name],
|
67
|
+
region: options[:region],
|
68
|
+
cluster_name: options[:cluster_name],
|
69
|
+
ecs_task_defs: options[:ecs_task_defs],
|
70
|
+
ecs_task_def_templates: options[:ecs_task_def_templates],
|
71
|
+
ecs_services: options[:ecs_services],
|
72
|
+
ecs_service_templates: options[:ecs_service_templates],
|
73
|
+
build_script: options[:build_script],
|
74
|
+
post_builds: options[:post_builds]
|
75
|
+
).cli_args
|
76
|
+
|
77
|
+
require 'shipitron/server/deploy_application'
|
78
|
+
result = Server::DeployApplication.call(
|
79
|
+
cli_args
|
80
|
+
)
|
81
|
+
|
82
|
+
if result.failure?
|
83
|
+
result.errors.each do |error|
|
84
|
+
Logger.fatal error
|
85
|
+
end
|
86
|
+
Logger.fatal 'Deploy failed.'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
desc 'bootstrap <app>', 'Bootstrap ECS task definitions and services'
|
91
|
+
option :region, required: true
|
92
|
+
option :cluster_name, required: true
|
93
|
+
option :service_count, type: :numeric, default: 3
|
94
|
+
option :task_def_dir, default: 'shipitron/ecs_task_defs'
|
95
|
+
option :service_dir, default: 'shipitron/ecs_services'
|
96
|
+
option :secrets_file, default: 'shipitron/secrets.yml'
|
97
|
+
option :debug, type: :boolean, default: false
|
98
|
+
def bootstrap(app)
|
99
|
+
setup(
|
100
|
+
secrets_file: options[:secrets_file]
|
101
|
+
)
|
102
|
+
|
103
|
+
require 'shipitron/client/bootstrap_application'
|
104
|
+
result = Client::BootstrapApplication.call(
|
105
|
+
application: app,
|
106
|
+
region: options[:region],
|
107
|
+
cluster_name: options[:cluster_name],
|
108
|
+
service_count: options[:service_count],
|
109
|
+
task_def_directory: options[:task_def_dir],
|
110
|
+
service_directory: options[:service_dir]
|
111
|
+
)
|
112
|
+
|
113
|
+
if result.failure?
|
114
|
+
result.errors.each do |error|
|
115
|
+
Logger.fatal error
|
116
|
+
end
|
117
|
+
Logger.fatal 'Bootstrap failed.'
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
def setup(config_file:nil, secrets_file:nil)
|
123
|
+
$stdout.sync = true
|
124
|
+
if options[:debug] == false
|
125
|
+
Logger.level = :info
|
126
|
+
end
|
127
|
+
|
128
|
+
Shipitron.config_file = config_file unless config_file.nil?
|
129
|
+
Shipitron.secrets_file = secrets_file unless secrets_file.nil?
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'shipitron'
|
2
|
+
require 'shipitron/client/register_ecs_task_definitions'
|
3
|
+
require 'shipitron/client/create_ecs_services'
|
4
|
+
|
5
|
+
module Shipitron
|
6
|
+
module Client
|
7
|
+
class BootstrapApplication
|
8
|
+
include Metaractor
|
9
|
+
include Interactor::Organizer
|
10
|
+
|
11
|
+
required :application
|
12
|
+
required :region
|
13
|
+
required :cluster_name
|
14
|
+
required :service_count
|
15
|
+
required :task_def_directory
|
16
|
+
required :service_directory
|
17
|
+
|
18
|
+
organize [
|
19
|
+
RegisterEcsTaskDefinitions,
|
20
|
+
CreateEcsServices
|
21
|
+
]
|
22
|
+
|
23
|
+
def call
|
24
|
+
Logger.info "==> Bootstrapping #{application}"
|
25
|
+
super
|
26
|
+
Logger.info "==> Done"
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def application
|
31
|
+
context.application
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'shipitron'
|
2
|
+
require 'shipitron/ecs_client'
|
3
|
+
require 'shipitron/mustache_yaml_parser'
|
4
|
+
|
5
|
+
module Shipitron
|
6
|
+
module Client
|
7
|
+
class CreateEcsServices
|
8
|
+
include Metaractor
|
9
|
+
include EcsClient
|
10
|
+
|
11
|
+
required :region
|
12
|
+
required :service_directory
|
13
|
+
required :cluster_name
|
14
|
+
required :service_count
|
15
|
+
|
16
|
+
def call
|
17
|
+
Logger.info 'Creating ECS services'
|
18
|
+
|
19
|
+
service_defs = Pathname.new(service_directory)
|
20
|
+
unless service_defs.directory?
|
21
|
+
fail_with_error!(
|
22
|
+
message: "service directory '#{service_directory}' does not exist"
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
service_defs.find do |path|
|
27
|
+
next if path.directory?
|
28
|
+
|
29
|
+
service_def = Smash.load(
|
30
|
+
path.to_s,
|
31
|
+
parser: MustacheYamlParser.new(
|
32
|
+
context: {
|
33
|
+
cluster: cluster_name,
|
34
|
+
revision: nil, # ECS will default to latest ACTIVE
|
35
|
+
count: service_count
|
36
|
+
}
|
37
|
+
)
|
38
|
+
).merge(
|
39
|
+
client_token: SecureRandom.uuid
|
40
|
+
)
|
41
|
+
|
42
|
+
Logger.info "Creating service '#{service_def.service_name}'"
|
43
|
+
Logger.debug "Service definition: #{service_def.to_h}"
|
44
|
+
begin
|
45
|
+
ecs_client(region: region).create_service(
|
46
|
+
service_def.to_h
|
47
|
+
)
|
48
|
+
rescue Aws::ECS::Errors::InvalidParameterException => e
|
49
|
+
raise if e.message != 'Creation of service was not idempotent.'
|
50
|
+
|
51
|
+
Logger.info "Service '#{service_def.service_name}' already exists."
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Logger.info 'Done'
|
56
|
+
rescue Aws::ECS::Errors::ServiceError => e
|
57
|
+
fail_with_errors!(messages: [
|
58
|
+
"Error: #{e.message}",
|
59
|
+
e.backtrace.join("\n")
|
60
|
+
])
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def region
|
65
|
+
context.region
|
66
|
+
end
|
67
|
+
|
68
|
+
def service_directory
|
69
|
+
context.service_directory
|
70
|
+
end
|
71
|
+
|
72
|
+
def cluster_name
|
73
|
+
context.cluster_name
|
74
|
+
end
|
75
|
+
|
76
|
+
def service_count
|
77
|
+
context.service_count
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'shipitron'
|
2
|
+
require 'shipitron/client/load_application_config'
|
3
|
+
require 'shipitron/client/load_templates'
|
4
|
+
require 'shipitron/client/ensure_deploy_not_running'
|
5
|
+
require 'shipitron/client/run_ecs_tasks'
|
6
|
+
|
7
|
+
module Shipitron
|
8
|
+
module Client
|
9
|
+
class DeployApplication
|
10
|
+
include Metaractor
|
11
|
+
include Interactor::Organizer
|
12
|
+
|
13
|
+
required :application
|
14
|
+
|
15
|
+
organize [
|
16
|
+
LoadApplicationConfig,
|
17
|
+
LoadTemplates,
|
18
|
+
EnsureDeployNotRunning,
|
19
|
+
RunEcsTasks
|
20
|
+
]
|
21
|
+
|
22
|
+
def call
|
23
|
+
Logger.info "==> Deploying #{application}"
|
24
|
+
super
|
25
|
+
Logger.info "==> Done"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def application
|
30
|
+
context.application
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'shipitron'
|
2
|
+
require 'shipitron/ecs_client'
|
3
|
+
|
4
|
+
# Note: This is a best effort client side check to make sure there
|
5
|
+
# isn't a deploy running. The server side check has more guarantees.
|
6
|
+
|
7
|
+
module Shipitron
|
8
|
+
module Client
|
9
|
+
class EnsureDeployNotRunning
|
10
|
+
include Metaractor
|
11
|
+
include EcsClient
|
12
|
+
|
13
|
+
required :clusters
|
14
|
+
optional :simulate
|
15
|
+
|
16
|
+
def call
|
17
|
+
return if simulate?
|
18
|
+
|
19
|
+
clusters.each do |cluster|
|
20
|
+
%w[PENDING RUNNING].each do |status|
|
21
|
+
begin
|
22
|
+
response = ecs_client(region: cluster.region).list_tasks(
|
23
|
+
cluster: cluster.name,
|
24
|
+
started_by: 'shipitron',
|
25
|
+
max_results: 1,
|
26
|
+
desired_status: status
|
27
|
+
)
|
28
|
+
if !response.task_arns.empty?
|
29
|
+
fail_with_errors!(messages: [
|
30
|
+
'Shipitron says "THERE CAN BE ONLY ONE"',
|
31
|
+
'Deploy is already running.'
|
32
|
+
])
|
33
|
+
end
|
34
|
+
rescue Aws::ECS::Errors::ClusterNotFoundException
|
35
|
+
fail_with_errors!(messages: [
|
36
|
+
'Shipitron says "PUNY HUMAN IS MISSING A CLUSTER"',
|
37
|
+
"Cluster '#{cluster.name}' not found in region #{cluster.region}."
|
38
|
+
])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def clusters
|
46
|
+
context.clusters
|
47
|
+
end
|
48
|
+
|
49
|
+
def simulate?
|
50
|
+
context.simulate == true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'shipitron'
|
2
|
+
require 'shipitron/post_build'
|
3
|
+
|
4
|
+
module Shipitron
|
5
|
+
module Client
|
6
|
+
class LoadApplicationConfig
|
7
|
+
include Metaractor
|
8
|
+
|
9
|
+
required :application
|
10
|
+
|
11
|
+
def call
|
12
|
+
context.repository_url = config.repository
|
13
|
+
context.s3_cache_bucket = config.cache_bucket
|
14
|
+
context.image_name = config.image_name
|
15
|
+
context.build_script = config.build_script
|
16
|
+
context.post_builds = begin
|
17
|
+
if config.post_builds.nil?
|
18
|
+
[]
|
19
|
+
else
|
20
|
+
config.post_builds.map {|pb| PostBuild.new(pb) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
context.clusters = config.ecs_clusters
|
24
|
+
context.shipitron_task = config.shipitron_task
|
25
|
+
context.ecs_task_defs = config.ecs_task_defs
|
26
|
+
context.ecs_services = config.ecs_services
|
27
|
+
context.ecs_task_def_dir = config.ecs_task_def_dir
|
28
|
+
context.ecs_service_dir = config.ecs_service_dir
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def application
|
33
|
+
context.application
|
34
|
+
end
|
35
|
+
|
36
|
+
def config
|
37
|
+
@config ||= Shipitron.config.applications[application]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'shipitron'
|
2
|
+
|
3
|
+
module Shipitron
|
4
|
+
module Client
|
5
|
+
class LoadTemplates
|
6
|
+
include Metaractor
|
7
|
+
|
8
|
+
required :ecs_task_def_dir
|
9
|
+
required :ecs_service_dir
|
10
|
+
|
11
|
+
def call
|
12
|
+
context.ecs_task_def_templates = load_templates(ecs_task_def_dir)
|
13
|
+
context.ecs_service_templates = load_templates(ecs_service_dir)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def ecs_task_def_dir
|
18
|
+
context.ecs_task_def_dir
|
19
|
+
end
|
20
|
+
|
21
|
+
def ecs_service_dir
|
22
|
+
context.ecs_service_dir
|
23
|
+
end
|
24
|
+
|
25
|
+
def load_templates(dir)
|
26
|
+
search_path = Pathname.new(dir)
|
27
|
+
unless search_path.directory?
|
28
|
+
fail_with_error!(
|
29
|
+
message: "directory '#{dir}' does not exist"
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
templates = []
|
34
|
+
search_path.find do |path|
|
35
|
+
next if path.directory?
|
36
|
+
|
37
|
+
templates << path.read
|
38
|
+
end
|
39
|
+
|
40
|
+
Logger.debug "Templates loaded: #{templates.inspect}"
|
41
|
+
templates
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|