shipitron 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 954b1e50e1911cd893e1770ab496735768bea9be
4
- data.tar.gz: cf5446d33417962c1f70b664bc8e2ca8202cba57
2
+ SHA256:
3
+ metadata.gz: 1b1404f46280ca67a501c2c249f955b266d028466357edb5332c8572ad487e0b
4
+ data.tar.gz: 93d96a64b5aec13d99c3927b593b5c564429ad34f5d7e9aaf162ef9499d52d2f
5
5
  SHA512:
6
- metadata.gz: 57d272d47ed61fc5b4c2329fcc3d16b7ceb0033ee1bf9da18f1db58335ab19c51a4b8c08af43ad0f8321d558bd09c351e23e79fb458f0b623869afa3423c3f5e
7
- data.tar.gz: a7fe7bcf8bd7410c4391d1413dc76f1f3379958508b5b3b80a40128c0a86249bf757b038ea89110aa355b1b1b1a21bd6f9e7a50612d128a78f9c0ecad5246851
6
+ metadata.gz: a5cfd2a66affc37f96d87d96e1311a06cb7deaea52f98a591962772afbe5ef25038cd5a62b718576be367c22d24e15a00261f61ee4fa98620e3790faece8588b
7
+ data.tar.gz: d5c4703312aeb1a64b61544c5a1f6ad5a533e60def6e8b29c09726fce89b974a6dfe939769ee5268f4501cd628c4271148cbe179ec60914767ac72073cf6e738
data/Dockerfile CHANGED
@@ -1,11 +1,11 @@
1
- FROM ruby:2.4.1-alpine as cache
1
+ FROM ruby:2.5.0-alpine3.7 as cache
2
2
  COPY cache/ /tmp/
3
3
  RUN cd /usr/local/bundle && \
4
4
  ([ -f /tmp/bundler-data.tar.gz ] && \
5
5
  tar -zxf /tmp/bundler-data.tar.gz && \
6
6
  rm /tmp/bundler-data.tar.gz) || true
7
7
 
8
- FROM ruby:2.4.1-alpine
8
+ FROM ruby:2.5.0-alpine3.7
9
9
  MAINTAINER Ryan Schlesinger <ryan@outstand.com>
10
10
 
11
11
  RUN addgroup -S shipitron && \
data/Dockerfile.release CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:2.4.1-alpine
1
+ FROM ruby:2.5.0-alpine3.7
2
2
  MAINTAINER Ryan Schlesinger <ryan@outstand.com>
3
3
 
4
4
  RUN addgroup -S shipitron && \
@@ -40,7 +40,7 @@ RUN apk add --no-cache \
40
40
 
41
41
  WORKDIR /app
42
42
 
43
- ENV SHIPITRON_VERSION=0.3.5
43
+ ENV SHIPITRON_VERSION=0.4.0
44
44
 
45
45
  RUN gem install shipitron -v ${SHIPITRON_VERSION} && \
46
46
  mkdir -p /home/shipitron/.ssh && \
data/README.md CHANGED
@@ -15,11 +15,7 @@ applications:
15
15
  - ecs_task: dummy-app
16
16
  container_name: dummy-app
17
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
18
+ cluster_discovery: _ecs-prod._tcp.example.com
23
19
  shipitron_task: shipitron
24
20
  ecs_task_defs:
25
21
  - dummy-app
@@ -44,6 +40,11 @@ applications:
44
40
  - `docker run -it --rm -v $(pwd):/shipitron -v $APP_PATH:/app outstand/shipitron:dev deploy <app> --simulate` to get the arguments for `server_deploy` below
45
41
  - `docker run -it --rm --dns 10.10.10.2 -v $(pwd):/shipitron -v $APP_PATH:/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)
46
42
 
43
+ Running a dev version in production:
44
+ - `docker push outstand/shipitron:dev`
45
+ - Update config to use `shipitron_task: shipitron-dev`
46
+ - `docker run -it --rm -v $(pwd):/shipitron -v $APP_PATH:/app outstand/shipitron:dev deploy <app> --debug`
47
+
47
48
  To release a new version:
48
49
  - Update the version number in `version.rb` and `Dockerfile.release` and commit the result.
49
50
  - `./build_dev.sh`
data/lib/shipitron/cli.rb CHANGED
@@ -12,8 +12,6 @@ module Shipitron
12
12
  desc 'deploy <app>', 'Deploys the app'
13
13
  option :config_file, default: 'shipitron/config.yml'
14
14
  option :secrets_file, default: 'shipitron/secrets.yml'
15
- option :ember, type: :boolean, default: false
16
- option :ember_only, type: :boolean, default: false
17
15
  option :debug, type: :boolean, default: false
18
16
  option :simulate, type: :boolean, default: false
19
17
  def deploy(app)
@@ -42,8 +40,9 @@ module Shipitron
42
40
  option :repository_branch, default: 'master'
43
41
  option :bucket, required: true
44
42
  option :image_name, required: true
43
+ option :named_tag, default: 'latest'
45
44
  option :region, required: true
46
- option :cluster_name, required: true
45
+ option :clusters, type: :array, required: true
47
46
  option :ecs_task_defs, type: :array, required: true
48
47
  option :ecs_task_def_templates, type: :array, default: []
49
48
  option :ecs_services, type: :array, default: []
@@ -64,8 +63,9 @@ module Shipitron
64
63
  repository_branch: options[:repository_branch],
65
64
  s3_cache_bucket: options[:bucket],
66
65
  image_name: options[:image_name],
66
+ named_tag: options[:named_tag],
67
67
  region: options[:region],
68
- cluster_name: options[:cluster_name],
68
+ clusters: options[:clusters],
69
69
  ecs_task_defs: options[:ecs_task_defs],
70
70
  ecs_task_def_templates: options[:ecs_task_def_templates],
71
71
  ecs_services: options[:ecs_services],
@@ -90,7 +90,7 @@ module Shipitron
90
90
  desc 'bootstrap <app>', 'Bootstrap ECS task definitions and services'
91
91
  option :region, required: true
92
92
  option :cluster_name, required: true
93
- option :service_count, type: :numeric, default: 3
93
+ option :service_count, type: :numeric, default: 0
94
94
  option :task_def_dir, default: 'shipitron/ecs_task_defs'
95
95
  option :service_dir, default: 'shipitron/ecs_services'
96
96
  option :secrets_file, default: 'shipitron/secrets.yml'
@@ -1,6 +1,7 @@
1
1
  require 'shipitron'
2
2
  require 'shipitron/client/load_application_config'
3
3
  require 'shipitron/client/load_templates'
4
+ require 'shipitron/client/fetch_clusters'
4
5
  require 'shipitron/client/ensure_deploy_not_running'
5
6
  require 'shipitron/client/run_ecs_tasks'
6
7
 
@@ -11,10 +12,12 @@ module Shipitron
11
12
  include Interactor::Organizer
12
13
 
13
14
  required :application
15
+ optional :simulate
14
16
 
15
17
  organize [
16
18
  LoadApplicationConfig,
17
19
  LoadTemplates,
20
+ FetchClusters,
18
21
  EnsureDeployNotRunning,
19
22
  RunEcsTasks
20
23
  ]
@@ -0,0 +1,43 @@
1
+ require 'shipitron'
2
+ require 'resolv'
3
+
4
+ module Shipitron
5
+ module Client
6
+ class FetchClusters
7
+ include Metaractor
8
+
9
+ required :cluster_discovery
10
+
11
+ def call
12
+ resources = dns_resources.sort! do |a,b|
13
+ (a.priority <=> b.priority).yield_self do |prio|
14
+ if prio == 0
15
+ b.weight <=> a.weight
16
+ else
17
+ prio
18
+ end
19
+ end
20
+ end
21
+
22
+ context.clusters = resources.map do |r|
23
+ Smash.new(
24
+ name: r.target[0].to_s,
25
+ region: r.target[1].to_s
26
+ )
27
+ end
28
+
29
+ Logger.debug "Clusters: #{context.clusters.inspect}"
30
+ end
31
+
32
+ private
33
+ def dns_resources
34
+ Resolv::DNS.open do |dns|
35
+ dns.getresources(
36
+ context.cluster_discovery,
37
+ Resolv::DNS::Resource::IN::SRV
38
+ )
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -13,6 +13,7 @@ module Shipitron
13
13
  context.repository_branch = config.repository_branch
14
14
  context.s3_cache_bucket = config.cache_bucket
15
15
  context.image_name = config.image_name
16
+ context.named_tag = config.named_tag
16
17
  context.build_script = config.build_script
17
18
  context.post_builds = begin
18
19
  if config.post_builds.nil?
@@ -21,7 +22,7 @@ module Shipitron
21
22
  config.post_builds.map {|pb| PostBuild.new(pb) }
22
23
  end
23
24
  end
24
- context.clusters = config.ecs_clusters
25
+ context.cluster_discovery = config.cluster_discovery
25
26
  context.shipitron_task = config.shipitron_task
26
27
  context.ecs_task_defs = config.ecs_task_defs
27
28
  context.ecs_services = config.ecs_services
@@ -23,7 +23,7 @@ module Shipitron
23
23
  end
24
24
 
25
25
  def load_templates(dir)
26
- return [] if dir.nil?
26
+ return {} if dir.nil?
27
27
 
28
28
  search_path = Pathname.new(dir)
29
29
  unless search_path.directory?
@@ -32,11 +32,12 @@ module Shipitron
32
32
  )
33
33
  end
34
34
 
35
- templates = []
35
+ templates = {}
36
36
  search_path.find do |path|
37
37
  next if path.directory?
38
+ next if path.extname != '.yml'
38
39
 
39
- templates << path.read
40
+ templates[path.basename('.yml').to_s] = path.read
40
41
  end
41
42
 
42
43
  Logger.debug "Templates loaded: #{templates.inspect}"
@@ -2,6 +2,8 @@ require 'shipitron'
2
2
  require 'shipitron/ecs_client'
3
3
  require 'shellwords'
4
4
  require 'base64'
5
+ require 'tty-table'
6
+ require 'pastel'
5
7
 
6
8
  module Shipitron
7
9
  module Client
@@ -15,6 +17,7 @@ module Shipitron
15
17
  required :repository_url
16
18
  required :s3_cache_bucket
17
19
  required :image_name
20
+ required :named_tag
18
21
  required :ecs_task_defs
19
22
  optional :ecs_task_def_templates
20
23
  optional :ecs_services
@@ -26,48 +29,63 @@ module Shipitron
26
29
 
27
30
  before do
28
31
  context.post_builds ||= []
29
- context.ecs_task_def_templates ||= []
32
+ context.ecs_task_def_templates ||= {}
30
33
  context.ecs_services ||= []
31
- context.ecs_service_templates ||= []
34
+ context.ecs_service_templates ||= {}
32
35
  end
33
36
 
34
37
  def call
35
38
  Logger.info "Skipping ECS run_task calls due to --simulate" if simulate?
36
39
 
37
- clusters.each do |cluster|
38
- begin
39
- if simulate?
40
- command_args(cluster)
41
- next
40
+ Logger.info "Deploying to:"
41
+ pastel = Pastel.new
42
+ table = TTY::Table.new do |t|
43
+ clusters.each_with_index do |cluster, i|
44
+ if i == 0
45
+ t << [pastel.yellow('*'), cluster.name, cluster.region, '[' + pastel.green('shipitron') + ']']
46
+ else
47
+ t << ['', cluster.name, cluster.region, '']
42
48
  end
49
+ end
50
+ end
51
+ table.render.each_line do |line|
52
+ Logger.info line.chomp
53
+ end
43
54
 
44
- response = ecs_client(region: cluster.region).run_task(
45
- cluster: cluster.name,
46
- task_definition: shipitron_task,
47
- overrides: {
48
- container_overrides: [
49
- {
50
- name: 'shipitron',
51
- command: command_args(cluster)
52
- }
53
- ]
54
- },
55
- count: 1,
56
- started_by: 'shipitron'
57
- )
55
+ cluster = clusters.first
58
56
 
59
- if !response.failures.empty?
60
- response.failures.each do |failure|
61
- fail_with_error! message: "ECS run_task failure: #{failure.arn}: #{failure.reason}"
62
- end
63
- end
57
+ begin
58
+ if simulate?
59
+ command_args(cluster)
60
+ return
61
+ end
64
62
 
65
- rescue Aws::ECS::Errors::ServiceError => e
66
- fail_with_errors!(messages: [
67
- "Error: #{e.message}",
68
- e.backtrace.join("\n")
69
- ])
63
+ response = ecs_client(region: cluster.region).run_task(
64
+ cluster: cluster.name,
65
+ task_definition: shipitron_task,
66
+ overrides: {
67
+ container_overrides: [
68
+ {
69
+ name: 'shipitron',
70
+ command: command_args(cluster)
71
+ }
72
+ ]
73
+ },
74
+ count: 1,
75
+ started_by: 'shipitron'
76
+ )
77
+
78
+ if !response.failures.empty?
79
+ response.failures.each do |failure|
80
+ fail_with_error! message: "ECS run_task failure: #{failure.arn}: #{failure.reason}"
81
+ end
70
82
  end
83
+
84
+ rescue Aws::ECS::Errors::ServiceError => e
85
+ fail_with_errors!(messages: [
86
+ "Error: #{e.message}",
87
+ e.backtrace.join("\n")
88
+ ])
71
89
  end
72
90
  end
73
91
 
@@ -84,59 +102,66 @@ module Shipitron
84
102
  context.shipitron_task
85
103
  end
86
104
 
87
- def escape(str)
88
- Shellwords.escape(str)
89
- end
90
-
91
- def escaped(sym)
92
- escape(context[sym])
93
- end
94
-
95
105
  def command_args(cluster)
96
106
  [
97
107
  'server_deploy',
98
- '--name', escaped(:application),
99
- '--repository', escaped(:repository_url),
100
- '--bucket', escaped(:s3_cache_bucket),
101
- '--image-name', escaped(:image_name),
102
- '--region', escape(cluster.region),
103
- '--cluster-name', escape(cluster.name),
108
+ '--name', context.application,
109
+ '--repository', context.repository_url,
110
+ '--bucket', context.s3_cache_bucket,
111
+ '--image-name', context.image_name,
112
+ '--named-tag', context.named_tag,
113
+ '--region', cluster.region,
104
114
  ].tap do |ary|
115
+ ary << '--clusters'
116
+ ary.concat(context.clusters.map(&:name))
117
+
105
118
  ary << '--ecs-task-defs'
106
- ary.concat(context.ecs_task_defs.each {|s| escape(s)})
119
+ ary.concat(context.ecs_task_defs)
107
120
 
108
121
  unless context.ecs_services.empty?
109
122
  ary << '--ecs-services'
110
- ary.concat(context.ecs_services.each {|s| escape(s)})
123
+ ary.concat(context.ecs_services)
111
124
  end
112
125
 
113
126
  if context.build_script != nil
114
- ary.concat ['--build-script', escaped(:build_script)]
127
+ ary.concat ['--build-script', context.build_script]
115
128
  end
116
129
 
117
130
  if !context.post_builds.empty?
118
131
  ary << '--post-builds'
119
- ary.concat(context.post_builds.map(&:to_s).each {|s| escape(s)})
132
+ ary.concat(context.post_builds.map(&:to_s))
120
133
  end
121
134
 
122
135
  if !context.ecs_task_def_templates.empty?
123
136
  ary << '--ecs-task-def-templates'
124
- ary.concat(context.ecs_task_def_templates.map {|t| Base64.urlsafe_encode64(t)})
137
+ ary.concat(
138
+ context.ecs_task_def_templates.map do |name, data|
139
+ if context.ecs_task_defs.include?(name)
140
+ Base64.urlsafe_encode64(data)
141
+ end
142
+ end.compact
143
+ )
125
144
  end
126
145
 
127
146
  if !context.ecs_service_templates.empty?
128
147
  ary << '--ecs-service-templates'
129
- ary.concat(context.ecs_service_templates.map {|t| Base64.urlsafe_encode64(t)})
148
+ ary.concat(
149
+ context.ecs_service_templates.map do |name, data|
150
+ if context.ecs_services.include?(name)
151
+ Base64.urlsafe_encode64(data)
152
+ end
153
+ end.compact
154
+ )
130
155
  end
131
156
 
132
157
  unless context.repository_branch.nil?
133
- ary.concat ['--repository-branch', escaped(:repository_branch)]
158
+ ary.concat ['--repository-branch', context.repository_branch]
134
159
  end
135
160
 
136
161
  if simulate?
137
- Logger.info "server_deploy command: #{ary.join(' ')}"
162
+ Logger.info "server_deploy command: #{ary.shelljoin}"
138
163
  else
139
- Logger.debug "server_deploy command: #{ary.join(' ')}"
164
+ Logger.debug "server_deploy command: #{ary.shelljoin}"
140
165
  end
141
166
  end
142
167
  end
@@ -1,4 +1,4 @@
1
- require 'aws-sdk'
1
+ require 'aws-sdk-ecs'
2
2
 
3
3
  module Shipitron
4
4
  module EcsClient
@@ -20,8 +20,9 @@ module Shipitron
20
20
  required :repository_url
21
21
  required :s3_cache_bucket
22
22
  required :docker_image
23
+ required :named_tag
23
24
  required :region
24
- required :cluster_name
25
+ required :clusters
25
26
  required :ecs_task_defs
26
27
  optional :ecs_task_def_templates
27
28
  optional :ecs_services
@@ -15,7 +15,11 @@ module Shipitron
15
15
  end
16
16
 
17
17
  def call
18
- docker_auth = fetch_key!(key: "shipitron/#{application}/docker_auth")
18
+ docker_auth = begin
19
+ key = fetch_key(key: "shipitron/#{application}/docker_auth")
20
+ key = fetch_key!(key: 'shipitron/docker_auth') if key.nil?
21
+ key
22
+ end
19
23
  auth_file = Pathname.new('/home/shipitron/.docker/config.json')
20
24
  auth_file.parent.mkpath
21
25
  auth_file.open('wb') do |file|
@@ -7,11 +7,12 @@ module Shipitron
7
7
  include Metaractor
8
8
 
9
9
  required :docker_image
10
+ required :named_tag
10
11
 
11
12
  def call
12
- Logger.info "Pushing docker image #{docker_image} and #{docker_image.name_with_tag(:latest)}"
13
+ Logger.info "Pushing docker image #{docker_image} and #{docker_image.name_with_tag(named_tag)}"
13
14
 
14
- Logger.info `docker tag #{docker_image} #{docker_image.name_with_tag(:latest)}`
15
+ Logger.info `docker tag #{docker_image} #{docker_image.name_with_tag(named_tag)}`
15
16
  if $? != 0
16
17
  fail_with_error!(message: 'Docker tag failed.')
17
18
  end
@@ -21,9 +22,9 @@ module Shipitron
21
22
  fail_with_error!(message: 'Docker push failed.')
22
23
  end
23
24
 
24
- Logger.info `docker push #{docker_image.name_with_tag(:latest)}`
25
+ Logger.info `docker push #{docker_image.name_with_tag(named_tag)}`
25
26
  if $? != 0
26
- fail_with_error!(message: 'Docker push (latest) failed.')
27
+ fail_with_error!(message: "Docker push (#{named_tag}) failed.")
27
28
  end
28
29
  end
29
30
 
@@ -31,6 +32,10 @@ module Shipitron
31
32
  def docker_image
32
33
  context.docker_image
33
34
  end
35
+
36
+ def named_tag
37
+ context.named_tag
38
+ end
34
39
  end
35
40
  end
36
41
  end
@@ -17,12 +17,20 @@ module Shipitron
17
17
  end
18
18
 
19
19
  def call
20
- host_key = fetch_key!(key: "shipitron/#{application}/git_host_key")
20
+ host_key = begin
21
+ key = fetch_key(key: "shipitron/#{application}/git_host_key")
22
+ key = fetch_key!(key: 'shipitron/git_host_key') if key.nil?
23
+ key
24
+ end
21
25
  Pathname.new('/home/shipitron/.ssh/known_hosts').open('a') do |file|
22
26
  file.puts(host_key.to_s)
23
27
  end
24
28
 
25
- deploy_key = fetch_key!(key: "shipitron/#{application}/git_deploy_key")
29
+ deploy_key = begin
30
+ key = fetch_key(key: "shipitron/#{application}/git_deploy_key")
31
+ key = fetch_key!(key: 'shipitron/git_deploy_key') if key.nil?
32
+ key
33
+ end
26
34
  Pathname.new('/home/shipitron/.ssh/id_rsa').open('w') do |file|
27
35
  file.puts(deploy_key.to_s)
28
36
  file.chmod(0600)
@@ -25,7 +25,7 @@ module Shipitron
25
25
  else
26
26
  Logger.info 'Fetching new git commits'
27
27
  FileUtils.cd('/home/shipitron/git-cache') do
28
- `git fetch #{Shellwords.escape repository_url} #{Shellwords.escape repository_branch}:#{Shellwords.escape repository_branch}`
28
+ `git fetch -f #{Shellwords.escape repository_url} #{Shellwords.escape repository_branch}:#{Shellwords.escape repository_branch}`
29
29
  end
30
30
  end
31
31
  end
@@ -8,7 +8,7 @@ module Shipitron
8
8
  include EcsClient
9
9
 
10
10
  required :region
11
- required :cluster_name
11
+ required :clusters
12
12
  optional :post_builds
13
13
 
14
14
  def call
@@ -20,7 +20,7 @@ module Shipitron
20
20
  post_builds.each do |post_build|
21
21
  Logger.info "Running #{post_build.command}"
22
22
  response = ecs_client(region: region).run_task(
23
- cluster: cluster_name,
23
+ cluster: clusters.first,
24
24
  task_definition: post_build.ecs_task,
25
25
  overrides: {
26
26
  container_overrides: [
@@ -45,7 +45,7 @@ module Shipitron
45
45
  Logger.info 'Waiting for task to finish'
46
46
  loop do
47
47
  response = ecs_client(region: region).describe_tasks(
48
- cluster: cluster_name,
48
+ cluster: clusters.first,
49
49
  tasks: [task_arn]
50
50
  )
51
51
  next if response.tasks.empty?
@@ -72,8 +72,8 @@ module Shipitron
72
72
  context.region
73
73
  end
74
74
 
75
- def cluster_name
76
- context.cluster_name
75
+ def clusters
76
+ context.clusters
77
77
  end
78
78
  end
79
79
  end
@@ -14,8 +14,9 @@ module Shipitron
14
14
  optional :repository_branch
15
15
  required :s3_cache_bucket
16
16
  required :image_name
17
+ required :named_tag
17
18
  required :region
18
- required :cluster_name
19
+ required :clusters
19
20
  required :ecs_task_defs
20
21
  optional :ecs_task_def_templates
21
22
  optional :ecs_services
@@ -36,8 +37,9 @@ module Shipitron
36
37
  repository_url
37
38
  repository_branch
38
39
  s3_cache_bucket
40
+ named_tag
39
41
  region
40
- cluster_name
42
+ clusters
41
43
  ecs_services
42
44
  build_script
43
45
  ].each_with_object(cli_args) { |k, args| args[k] = context[k] }
@@ -29,7 +29,12 @@ module Shipitron
29
29
  end
30
30
 
31
31
  def deploy_ref_key
32
- fetch_key!(key: "shipitron/#{application}/deploy_ref_key")
32
+ key = fetch_key(key: "shipitron/#{application}/deploy_ref_key")
33
+ if key.nil?
34
+ key = "shipitron/#{application}/deploy_ref"
35
+ Logger.info "Defaulting deploy_ref_key to #{key}"
36
+ end
37
+ key
33
38
  end
34
39
  end
35
40
  end
@@ -9,7 +9,7 @@ module Shipitron
9
9
  include EcsClient
10
10
 
11
11
  required :region
12
- required :cluster_name
12
+ required :clusters
13
13
  optional :ecs_services
14
14
  required :ecs_task_defs
15
15
  optional :ecs_service_templates
@@ -28,56 +28,57 @@ module Shipitron
28
28
  Logger.info "Updating ECS services [#{ecs_services.join(', ')}] with task definitions [#{ecs_task_defs.map(&:to_s).join(', ')}]"
29
29
 
30
30
  begin
31
- service_templates = ParseTemplates.call!(
32
- templates: ecs_service_templates,
33
- template_context: {
31
+ clusters.each do |cluster_name|
32
+ service_templates = ParseTemplates.call!(
33
+ templates: ecs_service_templates,
34
+ template_context: {
35
+ cluster: cluster_name,
36
+ revision: nil,
37
+ count: nil
38
+ }
39
+ ).parsed_templates
40
+
41
+ service_task_defs = {}
42
+
43
+ # Find all requested services
44
+ services_response = ecs_client(region: region).describe_services(
34
45
  cluster: cluster_name,
35
- revision: nil,
36
- count: nil
37
- }
38
- ).parsed_templates
39
-
40
- service_task_defs = {}
41
-
42
- # Find all requested services
43
- services_response = ecs_client(region: region).describe_services(
44
- cluster: cluster_name,
45
- services: ecs_services
46
- )
47
-
48
- # For each service, find the task definition it references
49
- services_response.services.each do |service|
50
- response = ecs_client(region: region).describe_task_definition(
51
- task_definition: service.task_definition
46
+ services: ecs_services
52
47
  )
53
48
 
54
- # For the task definition, find the locally updated version in ecs_task_defs
55
- ecs_task_def = ecs_task_defs.find {|task| task.name == response.task_definition.family }
56
- service_task_defs[service.service_name] = ecs_task_def
57
- end
49
+ # For each service, find the task definition it references
50
+ services_response.services.each do |service|
51
+ response = ecs_client(region: region).describe_task_definition(
52
+ task_definition: service.task_definition
53
+ )
58
54
 
59
- service_task_defs.each do |ecs_service, ecs_task_def|
60
- Logger.info "Updating #{ecs_service} with #{ecs_task_def}"
55
+ # For the task definition, find the locally updated version in ecs_task_defs
56
+ ecs_task_def = ecs_task_defs.find {|task| task.name == response.task_definition.family }
57
+ service_task_defs[service.service_name] = ecs_task_def
58
+ end
61
59
 
62
- service_params = {
63
- cluster: cluster_name,
64
- service: ecs_service,
65
- task_definition: ecs_task_def.name_with_revision
66
- }
67
-
68
- template = service_templates.find {|t| t.service_name == ecs_service }
69
- if template != nil
70
- if template.deployment_configuration != nil
71
- Logger.debug "Merging deployment config: #{template.deployment_configuration}"
72
- service_params.merge(
73
- deployment_configuration: template.deployment_configuration
74
- )
60
+ service_task_defs.each do |ecs_service, ecs_task_def|
61
+ Logger.info "#{cluster_name}: Updating #{ecs_service} with #{ecs_task_def}"
62
+
63
+ service_params = {
64
+ cluster: cluster_name,
65
+ service: ecs_service,
66
+ task_definition: ecs_task_def.name_with_revision
67
+ }
68
+
69
+ template = service_templates.find {|t| t.service_name == ecs_service }
70
+ if template != nil
71
+ if template.deployment_configuration != nil
72
+ Logger.debug "Merging deployment config: #{template.deployment_configuration}"
73
+ service_params.merge(
74
+ deployment_configuration: template.deployment_configuration
75
+ )
76
+ end
75
77
  end
76
- end
77
78
 
78
- ecs_client(region: region).update_service(service_params)
79
+ ecs_client(region: region).update_service(service_params)
80
+ end
79
81
  end
80
-
81
82
  rescue Aws::ECS::Errors::ServiceError => e
82
83
  fail_with_errors!(messages: [
83
84
  "Error: #{e.message}",
@@ -91,8 +92,8 @@ module Shipitron
91
92
  context.region
92
93
  end
93
94
 
94
- def cluster_name
95
- context.cluster_name
95
+ def clusters
96
+ context.clusters
96
97
  end
97
98
 
98
99
  def ecs_services
@@ -1,3 +1,3 @@
1
1
  module Shipitron
2
- VERSION = '0.3.5'
2
+ VERSION = '0.4.0'
3
3
  end
data/shipitron.gemspec CHANGED
@@ -17,21 +17,23 @@ Gem::Specification.new do |spec|
17
17
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_runtime_dependency 'thor', '~> 0.19'
21
- spec.add_runtime_dependency 'aws-sdk', '~> 2.4'
22
- spec.add_runtime_dependency 'hashie', '~> 3.4'
20
+ spec.add_runtime_dependency 'thor', '~> 0.20'
21
+ spec.add_runtime_dependency 'aws-sdk-ecs', '~> 1.8'
22
+ spec.add_runtime_dependency 'hashie', '~> 3.5'
23
23
  spec.add_runtime_dependency 'metaractor', '~> 0.5'
24
- spec.add_runtime_dependency 'diplomat', '~> 0.18'
25
- spec.add_runtime_dependency 'fog-aws', '~> 0.11'
26
- spec.add_runtime_dependency 'mime-types', '~> 3.0'
27
- spec.add_runtime_dependency 'minitar', '~> 0.5'
24
+ spec.add_runtime_dependency 'diplomat', '~> 2.0'
25
+ spec.add_runtime_dependency 'fog-aws', '~> 2.0'
26
+ spec.add_runtime_dependency 'mime-types', '~> 3.1'
27
+ spec.add_runtime_dependency 'minitar', '~> 0.6'
28
28
  spec.add_runtime_dependency 'mustache', '~> 1.0'
29
- spec.add_runtime_dependency 'tty-command', '~> 0.6'
29
+ spec.add_runtime_dependency 'tty-command', '~> 0.7'
30
+ spec.add_runtime_dependency 'tty-table', '~> 0.9'
31
+ spec.add_runtime_dependency 'pastel', '~> 0.7'
30
32
 
31
- spec.add_development_dependency "bundler", "~> 1.12"
32
- spec.add_development_dependency "rake", "~> 10.0"
33
- spec.add_development_dependency "pry-byebug", "~> 3.4"
34
- spec.add_development_dependency "rspec", "~> 3.4"
33
+ spec.add_development_dependency "bundler", "~> 1.16"
34
+ spec.add_development_dependency "rake", "~> 12.3"
35
+ spec.add_development_dependency "pry-byebug", "~> 3.5"
36
+ spec.add_development_dependency "rspec", "~> 3.7"
35
37
  spec.add_development_dependency "fivemat", "~> 1.3"
36
- spec.add_development_dependency "fog-local", "~> 0.3"
38
+ spec.add_development_dependency "fog-local", "~> 0.4"
37
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shipitron
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Schlesinger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-31 00:00:00.000000000 Z
11
+ date: 2018-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -16,42 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.19'
19
+ version: '0.20'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.19'
26
+ version: '0.20'
27
27
  - !ruby/object:Gem::Dependency
28
- name: aws-sdk
28
+ name: aws-sdk-ecs
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '2.4'
33
+ version: '1.8'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2.4'
40
+ version: '1.8'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: hashie
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.4'
47
+ version: '3.5'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.4'
54
+ version: '3.5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: metaractor
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -72,56 +72,56 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0.18'
75
+ version: '2.0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0.18'
82
+ version: '2.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: fog-aws
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.11'
89
+ version: '2.0'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.11'
96
+ version: '2.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: mime-types
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '3.0'
103
+ version: '3.1'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '3.0'
110
+ version: '3.1'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: minitar
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0.5'
117
+ version: '0.6'
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '0.5'
124
+ version: '0.6'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: mustache
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -142,70 +142,98 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '0.6'
145
+ version: '0.7'
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '0.6'
152
+ version: '0.7'
153
+ - !ruby/object:Gem::Dependency
154
+ name: tty-table
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.9'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.9'
167
+ - !ruby/object:Gem::Dependency
168
+ name: pastel
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.7'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.7'
153
181
  - !ruby/object:Gem::Dependency
154
182
  name: bundler
155
183
  requirement: !ruby/object:Gem::Requirement
156
184
  requirements:
157
185
  - - "~>"
158
186
  - !ruby/object:Gem::Version
159
- version: '1.12'
187
+ version: '1.16'
160
188
  type: :development
161
189
  prerelease: false
162
190
  version_requirements: !ruby/object:Gem::Requirement
163
191
  requirements:
164
192
  - - "~>"
165
193
  - !ruby/object:Gem::Version
166
- version: '1.12'
194
+ version: '1.16'
167
195
  - !ruby/object:Gem::Dependency
168
196
  name: rake
169
197
  requirement: !ruby/object:Gem::Requirement
170
198
  requirements:
171
199
  - - "~>"
172
200
  - !ruby/object:Gem::Version
173
- version: '10.0'
201
+ version: '12.3'
174
202
  type: :development
175
203
  prerelease: false
176
204
  version_requirements: !ruby/object:Gem::Requirement
177
205
  requirements:
178
206
  - - "~>"
179
207
  - !ruby/object:Gem::Version
180
- version: '10.0'
208
+ version: '12.3'
181
209
  - !ruby/object:Gem::Dependency
182
210
  name: pry-byebug
183
211
  requirement: !ruby/object:Gem::Requirement
184
212
  requirements:
185
213
  - - "~>"
186
214
  - !ruby/object:Gem::Version
187
- version: '3.4'
215
+ version: '3.5'
188
216
  type: :development
189
217
  prerelease: false
190
218
  version_requirements: !ruby/object:Gem::Requirement
191
219
  requirements:
192
220
  - - "~>"
193
221
  - !ruby/object:Gem::Version
194
- version: '3.4'
222
+ version: '3.5'
195
223
  - !ruby/object:Gem::Dependency
196
224
  name: rspec
197
225
  requirement: !ruby/object:Gem::Requirement
198
226
  requirements:
199
227
  - - "~>"
200
228
  - !ruby/object:Gem::Version
201
- version: '3.4'
229
+ version: '3.7'
202
230
  type: :development
203
231
  prerelease: false
204
232
  version_requirements: !ruby/object:Gem::Requirement
205
233
  requirements:
206
234
  - - "~>"
207
235
  - !ruby/object:Gem::Version
208
- version: '3.4'
236
+ version: '3.7'
209
237
  - !ruby/object:Gem::Dependency
210
238
  name: fivemat
211
239
  requirement: !ruby/object:Gem::Requirement
@@ -226,14 +254,14 @@ dependencies:
226
254
  requirements:
227
255
  - - "~>"
228
256
  - !ruby/object:Gem::Version
229
- version: '0.3'
257
+ version: '0.4'
230
258
  type: :development
231
259
  prerelease: false
232
260
  version_requirements: !ruby/object:Gem::Requirement
233
261
  requirements:
234
262
  - - "~>"
235
263
  - !ruby/object:Gem::Version
236
- version: '0.3'
264
+ version: '0.4'
237
265
  description:
238
266
  email:
239
267
  - ryan@outstand.com
@@ -259,6 +287,7 @@ files:
259
287
  - lib/shipitron/client/create_ecs_services.rb
260
288
  - lib/shipitron/client/deploy_application.rb
261
289
  - lib/shipitron/client/ensure_deploy_not_running.rb
290
+ - lib/shipitron/client/fetch_clusters.rb
262
291
  - lib/shipitron/client/load_application_config.rb
263
292
  - lib/shipitron/client/load_templates.rb
264
293
  - lib/shipitron/client/register_ecs_task_definitions.rb
@@ -317,7 +346,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
317
346
  version: '0'
318
347
  requirements: []
319
348
  rubyforge_project:
320
- rubygems_version: 2.6.13
349
+ rubygems_version: 2.7.4
321
350
  signing_key:
322
351
  specification_version: 4
323
352
  summary: A deployment tool for use with Docker and ECS.