orchestration 0.3.17 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/LICENSE +7 -0
  4. data/MANIFEST +76 -0
  5. data/Makefile +3 -3
  6. data/README.md +162 -137
  7. data/Rakefile +2 -2
  8. data/config/locales/en.yml +3 -1
  9. data/lib/orchestration/docker_compose/app_service.rb +84 -13
  10. data/lib/orchestration/docker_compose/compose_configuration.rb +69 -0
  11. data/lib/orchestration/docker_compose/database_service.rb +15 -13
  12. data/lib/orchestration/docker_compose/install_generator.rb +3 -2
  13. data/lib/orchestration/docker_compose/mongo_service.rb +5 -5
  14. data/lib/orchestration/docker_compose/rabbitmq_service.rb +2 -3
  15. data/lib/orchestration/docker_compose.rb +1 -0
  16. data/lib/orchestration/environment.rb +19 -6
  17. data/lib/orchestration/errors.rb +1 -1
  18. data/lib/orchestration/file_helpers.rb +27 -4
  19. data/lib/orchestration/install_generator.rb +85 -20
  20. data/lib/orchestration/services/app/configuration.rb +9 -5
  21. data/lib/orchestration/services/app/healthcheck.rb +1 -22
  22. data/lib/orchestration/services/database/adapters/mysql2.rb +13 -2
  23. data/lib/orchestration/services/database/adapters/postgresql.rb +0 -1
  24. data/lib/orchestration/services/database/configuration.rb +68 -75
  25. data/lib/orchestration/services/database/healthcheck.rb +10 -1
  26. data/lib/orchestration/services/listener/configuration.rb +1 -1
  27. data/lib/orchestration/services/listener/healthcheck.rb +2 -2
  28. data/lib/orchestration/services/{configuration_base.rb → mixins/configuration_base.rb} +15 -13
  29. data/lib/orchestration/services/{healthcheck_base.rb → mixins/healthcheck_base.rb} +3 -2
  30. data/lib/orchestration/services/mixins/http_healthcheck.rb +38 -0
  31. data/lib/orchestration/services/mongo/configuration.rb +37 -63
  32. data/lib/orchestration/services/mongo/healthcheck.rb +3 -32
  33. data/lib/orchestration/services/rabbitmq/configuration.rb +11 -22
  34. data/lib/orchestration/services/rabbitmq/healthcheck.rb +2 -2
  35. data/lib/orchestration/services.rb +3 -2
  36. data/lib/orchestration/templates/Dockerfile.erb +8 -4
  37. data/lib/orchestration/templates/database.yml.erb +32 -0
  38. data/lib/orchestration/templates/deploy.mk.erb +2 -2
  39. data/lib/orchestration/templates/entrypoint.sh.erb +13 -4
  40. data/lib/orchestration/templates/env.erb +10 -2
  41. data/lib/orchestration/templates/healthcheck.rb.erb +56 -0
  42. data/lib/orchestration/templates/makefile_macros.mk.erb +108 -0
  43. data/lib/orchestration/templates/mongoid.yml.erb +18 -0
  44. data/lib/orchestration/templates/orchestration.mk.erb +242 -120
  45. data/lib/orchestration/templates/puma.rb.erb +19 -0
  46. data/lib/orchestration/templates/rabbitmq.yml.erb +12 -0
  47. data/lib/orchestration/templates/unicorn.rb.erb +5 -5
  48. data/lib/orchestration/terminal.rb +13 -15
  49. data/lib/orchestration/version.rb +1 -1
  50. data/lib/orchestration.rb +20 -2
  51. data/lib/tasks/orchestration.rake +3 -1
  52. data/orchestration.gemspec +3 -5
  53. metadata +23 -13
@@ -1,66 +1,107 @@
1
1
  ### Environment setup ###
2
-
3
2
  SHELL:=/bin/bash
4
3
 
5
- -include .env
4
+ <%= macros %>
5
+
6
+ ifdef env_file
7
+ -include ${env_file}
8
+ else
9
+ -include .env
10
+ endif
11
+
6
12
  export
7
13
 
8
14
  ifneq (,$(env))
9
- env:=$(env)
15
+ # `env` set by current shell.
10
16
  else ifneq (,$(RAILS_ENV))
11
- env:=$(RAILS_ENV)
17
+ env=$(RAILS_ENV)
12
18
  else ifneq (,$(RACK_ENV))
13
- env:=$(RACK_ENV)
19
+ env=$(RACK_ENV)
14
20
  else
15
- env:=development
21
+ env=development
16
22
  endif
17
23
 
18
- ifeq (,$(wildcard ./bin/rake))
19
- rake:=RACK_ENV=${env} RAILS_ENV=${env} bundle exec rake
24
+ DOCKER_TAG ?= latest
25
+
26
+ ifneq (,$(wildcard ./bin/rake))
27
+ rake=RACK_ENV=${env} RAILS_ENV=${env} bin/rake
28
+ else ifneq (,$(wildcard ./Gemfile))
29
+ rake=RACK_ENV=${env} RAILS_ENV=${env} bundle exec rake
20
30
  else
21
- rake:=RACK_ENV=${env} RAILS_ENV=${env} bin/rake
31
+ rake=RACK_ENV=${env} RAILS_ENV=${env} rake
22
32
  endif
23
33
 
24
- docker_organization:=$(shell bash ./<%= env.orchestration_dir_name %>/yaml.bash docker_organization)
25
- docker_repository:=$(shell bash ./<%= env.orchestration_dir_name %>/yaml.bash docker_repository)
34
+ ifneq (,$(wildcard ${env_file}))
35
+ rake=. ${env_file} && ${rake}
36
+ endif
26
37
 
27
- compose_base:=env HOST_UID=$(shell id -u) \
28
- DOCKER_ORGANIZATION=${docker_organization} \
29
- DOCKER_REPOSITORY=${docker_repository} \
30
- docker-compose \
31
- -p ${docker_repository}_${env} \
32
- -f <%= env.orchestration_dir_name %>/docker-compose.yml \
38
+ docker_organization=$(shell bash ${orchestration_dir}/yaml.bash docker_organization)
39
+ docker_repository=$(shell bash ${orchestration_dir}/yaml.bash docker_repository)
33
40
 
34
- git_branch:=$(if $(branch),$(branch),$(shell git rev-parse --abbrev-ref HEAD))
35
- git_version:=$(shell git rev-parse --short --verify ${git_branch})
41
+ compose_base=env HOST_UID=$(shell id -u) \
42
+ DOCKER_ORGANIZATION="${docker_organization}" \
43
+ DOCKER_REPOSITORY="${docker_repository}" \
44
+ docker-compose \
45
+ -p "${docker_repository}_${env}" \
46
+ -f "${orchestration_dir}/docker-compose.yml"
36
47
 
37
- compose:=${compose_base} -f <%= env.orchestration_dir_name %>/docker-compose.${env}.yml -f <%= env.orchestration_dir_name %>/docker-compose.override.yml
48
+ git_branch ?= $(if $(branch),$(branch),$(shell git rev-parse --abbrev-ref HEAD))
49
+ git_version ?= $(shell git rev-parse --short --verify ${git_branch})
50
+ docker_image=${docker_organization}/${docker_repository}:${git_version}
38
51
 
39
- ifneq (,$(wildcard <%= env.orchestration_dir_name %>/docker-compose.local.yml))
40
- compose:=${compose} -f <%= env.orchestration_dir_name %>/docker-compose.local.yml
52
+ compose=${compose_base} -f ${orchestration_dir}/docker-compose.${env}.yml -f ${orchestration_dir}/docker-compose.override.yml
53
+ random_str=cat /dev/urandom | LC_ALL=C tr -dc 'a-z' | head -c $1
54
+
55
+ ifneq (,$(wildcard ${orchestration_dir}/docker-compose.local.yml))
56
+ compose:=${compose} -f ${orchestration_dir}/docker-compose.local.yml
41
57
  endif
42
58
 
59
+ all: build
60
+
43
61
  ### Container management commands ###
44
62
 
45
63
  .PHONY: start
46
- start:
47
- @echo "Starting containers..."
64
+ start: _clean-logs
65
+ @$(call print,'${yellow}Starting containers${reset} ...')
48
66
  ifeq (${env},$(filter ${env},test development))
49
- @# If our hostname is also known to Docker as a container ID then join
50
- @# the same network as our dependencies. This allows us to run side-car
51
- @# dependencies if we are running in a container (e.g. in Jenkins).
52
- @(docker ps --format "{{.ID}}" | grep -q $(shell hostname) && ${compose} up -d && docker network connect ${docker_repository}_${env}_default $(shell hostname)) || ${compose} up -d
67
+ @${compose} up -d --force-recreate ${services} ${log_progress} || ${fail}
68
+ @[ '${is_container}' == '1' ] && \
69
+ ( \
70
+ docker network connect '${network}' '$(shell hostname)' ${log} \
71
+ || \
72
+ $(call println,'${yellow}Warning${reset}: Unable to join network: "${yellow}${network}${reset}". Container will not be able to connect to dependency services.') \
73
+ ) \
74
+ || ( [ '${is_container}' == '0' ] || ${fail} )
53
75
  else
54
- @${compose} up -d --scale app=$${instances:-1}
76
+ @${compose} up -d --scale app=$${instances:-1} ${services} ${log_progress} || ${fail}
55
77
  endif
56
- @$(MAKE) wait
78
+ @$(call printrawln,' ${green}started${reset} ${tick}')
79
+ @$(call println,'${yellow}Waiting for services to become available${reset} ...')
80
+ ifdef services
81
+ @$(call make,wait services='${services}') 2>${stderr} || ${fail}
82
+ else
83
+ @$(call make,wait) 2>${stderr} || ${fail}
84
+ endif
85
+
86
+ <% services.each do |service| %>
87
+ .PHONY: start-<%= service %>
88
+ start-<%= service %>:
89
+ @$(call make,start services='<%= service %>')
90
+
91
+ <% end %>
57
92
 
58
93
  .PHONY: stop
59
- stop:
60
- @echo "Stopping containers..."
61
- @(docker ps --format "{{.ID}}" | grep -q $(shell hostname) && docker network disconnect ${docker_repository}_${env}_default $(shell hostname))
62
- @${compose} down
63
- @echo "All containers stopped."
94
+ stop: _clean-logs
95
+ @$(call print,'${yellow}Stopping containers${reset} ...')
96
+ @if docker ps --format "{{.ID}}" | grep -q $(shell hostname) ; \
97
+ then \
98
+ ( ${compose} down ${log_progress} || ${fail} ) \
99
+ && \
100
+ ( docker network connect ${docker_repository}_${env}_default $(shell hostname) ${log} || : ) ; \
101
+ else \
102
+ ${compose} down ${log_progress} || ${fail} ; \
103
+ fi
104
+ @$(call printrawln,' ${green}stopped${reset}. ${tick}')
64
105
 
65
106
  .PHONY: logs
66
107
  logs:
@@ -74,78 +115,135 @@ config:
74
115
  compose:
75
116
  @echo ${compose}
76
117
 
118
+ ### Development/Test Utility Commands
119
+
120
+ .PHONY: serve
121
+ serve: env_file ?= ./.env
122
+ serve: rails = RAILS_ENV='${env}' bundle exec rails server ${server}
123
+ serve: _verify_env
124
+ @if [ "${custom_env_file}" == "1" ] && [ ! -f "${env_file}" ] ; \
125
+ then \
126
+ $(call println_error,'${red}Error${reset}: Environment file "${yellow}${env_file}${reset}" not found. ${cross}') ; \
127
+ ${fail} ; \
128
+ fi
129
+ @if [ -f "${env_file}" ] ; \
130
+ then ( \
131
+ $(call println,'${yellow}Environment${reset}: ${green}${env_file}${reset}') && \
132
+ cat '${env_file}' | ${format_env} && \
133
+ $(call println,'') && \
134
+ set -a && . '${env_file}' && set +a && \
135
+ ${rails} \
136
+ ) ; \
137
+ else ${rails} ; \
138
+ fi
139
+
77
140
  .PHONY: test-setup
141
+ test-setup: env := test
78
142
  test-setup:
79
- @$(MAKE) start migrate env=test
143
+ @$(call make,start env=test)
144
+ ifneq (,$(wildcard config/database.yml))
145
+ ${rake} db:create || :
146
+ ifneq (,$(wildcard db/structure.sql))
147
+ ${rake} db:structure:load
148
+ else ifneq (,$(wildcard db/schema.rb))
149
+ ${rake} db:schema:load
150
+ endif
151
+
152
+ ${rake} db:migrate
153
+ endif
154
+
155
+ .PHONY: dump
156
+ dump:
157
+ @$(call println)
158
+ @$(call println,'${yellow}Captured${reset} ${green}stdout${reset} ${yellow}and${reset} ${red}stderr${reset} ${yellow}log data${reset}:')
159
+ @$(call println)
160
+ @echo
161
+ @test -f '${stdout}' && ( \
162
+ $(call hr,${green}) ; \
163
+ $(call println,'${gray}${stdout}${reset}') ; \
164
+ $(call hr,${green}) ; \
165
+ echo ; cat '${stdout}' ; echo ; \
166
+ $(call hr,${green}) ; \
167
+ )
168
+
169
+ @test -f '${stdout}' && ( \
170
+ echo ; \
171
+ $(call hr,${red}) ; \
172
+ $(call println,'${gray}${stderr}${reset}') ; \
173
+ $(call hr,${red}) ; \
174
+ echo ; cat '${stderr}' ; echo ; \
175
+ $(call hr,${red}) ; \
176
+ )
177
+
178
+ .PHONY: image
179
+ image:
180
+ @echo ${docker_image}
80
181
 
81
182
  ### Deployment utility commands ###
82
183
 
83
184
  .PHONY: bundle
84
185
  bundle:
85
- @echo 'Building deployment bundle...'
86
- @rm -rf <%= env.orchestration_dir_name %>/.deploy/
87
- @mkdir -p <%= env.orchestration_dir_name %>/.deploy/${docker_repository}/
186
+ ifndef path
187
+ @$(warning Missing `path` parameter; using `./bundle.tar`. Set a custom path with `make bundle path=/tmp/bundle.tar`)
188
+ endif
189
+ @rm -rf ${orchestration_dir}/.deploy/
190
+ @mkdir -p ${orchestration_dir}/.deploy/${docker_repository}/
88
191
  @sed -e "s/%%VERSION%%/${git_version}/g" \
89
192
  -e "s/%%REPOSITORY%%/${docker_repository}/g" \
90
193
  -e "s/%%ORGANIZATION%%/${docker_organization}/g" \
91
- <%= env.orchestration_dir_name %>/deploy.mk > \
92
- <%= env.orchestration_dir_name %>/.deploy/${docker_repository}/Makefile
93
- @cp <%= env.orchestration_dir_name %>/docker-compose.yml \
94
- <%= env.orchestration_dir_name %>/docker-compose.production.yml \
95
- <%= env.orchestration_dir_name %>/docker-compose.override.yml \
96
- <%= env.orchestration_dir_name %>/.deploy/${docker_repository}/
97
- @tar -C <%= env.orchestration_dir_name %>/.deploy -cf ./deploy.tar ./${docker_repository}
98
- @echo 'Deployment bundle written to ./deploy.tar'
194
+ ${orchestration_dir}/deploy.mk > \
195
+ ${orchestration_dir}/.deploy/${docker_repository}/Makefile
196
+ @cp ${orchestration_dir}/docker-compose.yml \
197
+ ${orchestration_dir}/docker-compose.production.yml \
198
+ ${orchestration_dir}/docker-compose.override.yml \
199
+ ${orchestration_dir}/.deploy/${docker_repository}/
200
+ @bundle_path="${path}" ; tar -C '${orchestration_dir}/.deploy' -cf "$${bundle_path:-./bundle.tar}" ./${docker_repository}
99
201
 
100
202
  .PHONY: deploy
101
- deploy:
102
203
  ifndef manager
103
- @$(error Missing `manager` parameter: `make deploy manager=swarm-manager.example.com`)
104
- else
105
- @echo 'Deploying stack via ${manager}...'
106
- endif
107
-
108
- ifndef env_file
109
- $(MAKE) bundle \
110
- && workdir=$$(mktemp -d) \
111
- && mv deploy.tar $${workdir}/ \
112
- && cd $${workdir} \
113
- && tar xf deploy.tar \
114
- && cd ${docker_repository} \
115
- && tar -cf - . | ssh ${manager} 'cd $$(mktemp -d) && chmod 0700 . && cat - | tar -x && make deploy-stack && rm -r $$(pwd)'
116
- else
117
- $(MAKE) bundle \
118
- && workdir=$$(mktemp -d) \
119
- && mv deploy.tar $${workdir}/ \
120
- && cd $${workdir} \
121
- && tar xf deploy.tar \
122
- && cd ${docker_repository} \
123
- && cp "${env_file}" ./.env \
124
- && tar -cf - . | ssh ${manager} 'cd $$(mktemp -d) && chmod 0700 . && cat - | tar -x && make deploy-stack && rm -r $$(pwd)'
125
- endif
126
-
127
- ### Database utility commands ###
128
-
129
- .PHONY: migrate
130
- migrate:
131
- @echo "Running migrations..."
132
- @(${rake} db:create && ${rake} db:migrate) || ${rake} db:migrate
133
- @echo "Migrations complete."
134
-
135
- .PHONY: migrate-container
136
- migrate-container:
137
- @echo "[app] Running migrations..."
138
- ifdef env_file
139
- @cp ${env_file} ./.env
204
+ @$(call println_error,'Missing `manager` parameter: `make deploy manager=swarm-manager.example.cor`')
140
205
  endif
141
- ${compose} run --rm app bundle exec rake db:migrate
142
- @echo "[app] Migrations complete."
206
+ deploy: env := production
207
+ deploy: project_name = ${docker_repository}_${env}
208
+ deploy: path = $(shell mktemp -d)
209
+ deploy: RAILS_ENV = ${env}
210
+ deploy: RACK_ENV = ${env}
211
+ deploy: DOCKER_TAG = ${git_version}
212
+ deploy:
213
+ @$(call println,'${yellow}Deploying stack via${reset} ${green}${manager}${reset} ...') && \
214
+ ( \
215
+ $(call make,_verify_compose env_file=${env_file} env=${env}) && \
216
+ $(call make,bundle path='${path}/bundle.tar') ${log} && \
217
+ cd '${path}' ${log} && \
218
+ tar xf './bundle.tar' ${log} && \
219
+ cd '${docker_repository}' ${log} && \
220
+ ( [ -z '${env_file}' ] || cp '${env_file}' './.env' ${log} ) && \
221
+ $(call println,'${yellow}Deployment environment${reset}:') && \
222
+ ( test -f '.env' && cat '.env' | ${format_env} || : ) && \
223
+ echo 'DOCKER_ORGANIZATION=${docker_organization}' >> './.env' && \
224
+ echo 'DOCKER_REPOSITORY=${docker_repository}' >> './.env' && \
225
+ echo 'DOCKER_TAG=${git_version}' >> ./.env && \
226
+ $(call println,'') && \
227
+ $(call println,'${yellow}Application image${reset}: ${cyan}${docker_image}${reset}') && \
228
+ ${compose} config 2>${stderr} | ssh "${manager}" 'docker stack deploy --prune --with-registry-auth -c - "${project_name}"' ${log} && \
229
+ ( [ -z "${path}" ] || rm -rf "${path}" ${log} ) \
230
+ ) \
231
+ || ${fail}
232
+
233
+ @$(call println,'${yellow}Deployment${reset} ${green}complete${reset}. ${tick}')
143
234
 
144
235
  ### Service healthcheck commands ###
145
236
 
146
237
  .PHONY: wait
147
- wait: <%= wait_commands.join(' ') %>
148
- @echo "All Containers ready."
238
+ <% services.each do |service| %>
239
+ ifneq (,$(findstring <%= service %>,${services}))
240
+ wait: wait-<%= service %>
241
+ endif
242
+ <% end %>
243
+ ifndef services
244
+ wait: <%= services.map { |command| "wait-#{command}" }.join(' ') %>
245
+ endif
246
+ @$(call println,'${yellow}All services${reset} ${green}ready${reset}. ${tick}')
149
247
 
150
248
  ## Generic Listener healthcheck for TCP services ##
151
249
 
@@ -154,23 +252,13 @@ wait-listener:
154
252
 
155
253
  ## Test/development wait commands
156
254
 
157
- .PHONY: wait-database
158
- wait-database:
159
- ifeq (${env},$(filter ${env},test development))
160
- @${rake} orchestration:database:wait
161
- endif
255
+ <% services.each do |service| %>
256
+ <% next if service.to_sym == :app %>
257
+ .PHONY: wait-<%= service %>
258
+ wait-<%= service %>:
259
+ @${rake} orchestration:<%= service %>:wait
162
260
 
163
- .PHONY: wait-mongo
164
- wait-mongo:
165
- ifeq (${env},$(filter ${env},test development))
166
- @${rake} orchestration:mongo:wait
167
- endif
168
-
169
- .PHONY: wait-rabbitmq
170
- wait-rabbitmq:
171
- ifeq (${env},$(filter ${env},test development))
172
- @${rake} orchestration:rabbitmq:wait
173
- endif
261
+ <% end %>
174
262
 
175
263
  .PHONY: wait-app
176
264
  wait-app:
@@ -179,23 +267,57 @@ wait-app:
179
267
  ### Docker build commands ###
180
268
 
181
269
  .PHONY: build
270
+ build: context = ${orchestration_dir}/.build/context.tar
182
271
  build:
183
- @echo "Preparing build from ${git_branch}"
184
- @mkdir -p ./<%= env.orchestration_dir_name %>/.build
185
- @git show ${git_branch}:./Gemfile > ./<%= env.orchestration_dir_name %>/.build/Gemfile
186
- @git show ${git_branch}:./Gemfile.lock > ./<%= env.orchestration_dir_name %>/.build/Gemfile.lock
187
- <% if defined?(Webpacker) %> @git show ${git_branch}:./package.json > ./<%= env.orchestration_dir_name %>/.build/package.json<% end %>
188
- <% if defined?(Webpacker) %> @git show ${git_branch}:./yarn.lock > ./<%= env.orchestration_dir_name %>/.build/yarn.lock<% end %>
189
- @echo "Building..."
190
- @git archive --format tar.gz -o ./<%= env.orchestration_dir_name %>/.build/context.tar.gz ${git_branch}
272
+ @$(call print,'${yellow}Preparing build context from${reset} ${cyan}${git_branch}:${git_version}${reset} ... ')
273
+ @mkdir -p ${orchestration_dir}/.build ${log} || ${fail}
274
+ @git show ${git_branch}:./Gemfile > ${orchestration_dir}/.build/Gemfile 2>${stderr} || ${fail}
275
+ @git show ${git_branch}:./Gemfile.lock > ${orchestration_dir}/.build/Gemfile.lock 2>${stderr} || ${fail}
276
+ <% if defined?(Webpacker) %> @git show ${git_branch}:./package.json > ${orchestration_dir}/.build/package.json 2>${stderr} || ${fail}<% end %>
277
+ <% if defined?(Webpacker) %> @git show ${git_branch}:./yarn.lock > ${orchestration_dir}/.build/yarn.lock 2>${stderr} || ${fail}<% end %>
278
+ @git archive --format 'tar' -o '${context}' '${git_branch}' ${log} || ${fail}
279
+ @temp=$$(mktemp -d) ; ( cd "$${temp}" && touch './.orchestration_container_flag' && tar -uvf '${context}' . ) ${log} || ${fail}
280
+ @$(call printrawln,'${green}complete.${reset} ${tick}')
281
+ @$(call print,'${yellow}Building image${reset} ...')
191
282
  @docker build \
192
- --build-arg BUNDLE_GITHUB__COM \
193
- --build-arg BUNDLE_BITBUCKET__ORG \
194
- -t ${docker_organization}/${docker_repository} \
195
- -t ${docker_organization}/${docker_repository}:${git_version} \
196
- ./<%= env.orchestration_dir_name %>/
197
- @echo "Build complete."
283
+ --build-arg BUNDLE_GITHUB__COM \
284
+ --build-arg BUNDLE_BITBUCKET__ORG \
285
+ -t ${docker_organization}/${docker_repository} \
286
+ -t ${docker_organization}/${docker_repository}:${git_version} \
287
+ ${orchestration_dir}/ ${log_progress} || ${fail}
288
+ @$(call printrawln,' ${green}complete${reset}. ${tick}')
289
+ @$(call println,'[${green}tag${reset}] ${cyan}${docker_organization}/${docker_repository}${reset}')
290
+ @$(call println,'[${green}tag${reset}] ${cyan}${docker_organization}/${docker_repository}:${git_version}${reset}')
198
291
 
199
292
  .PHONY: push
200
293
  push:
201
- docker push ${docker_organization}/${docker_repository}:${git_version}
294
+ @$(call print,'${yellow}Pushing${reset} ${cyan}${docker_image}${reset} ...')
295
+ @docker push ${docker_image} ${log_progress} || ${fail}
296
+ @$(call printrawln,' ${green}complete${reset}. ${tick}')
297
+
298
+ ### Internal Commands ###
299
+ #
300
+ .PHONY: _verify_app_image
301
+ _verify_app_image:
302
+ @docker inspect '${docker_image}'
303
+
304
+ .PHONY: _verify_compose
305
+ _verify_compose: _verify_env
306
+ @$(call print,'${yellow}Verifying compose file(s)${reset} ... ')
307
+ @${replace_env}
308
+ @${compose} config ${log} || ${fail}
309
+ @${restore_env}
310
+ @$(call printrawln,'${green}success${reset}. ${tick}')
311
+
312
+ .PHONY: _verify_env
313
+ _verify_env:
314
+ @if [ "${custom_env_file}" == "1" ] && [ ! -f "${env_file}" ] ; \
315
+ then \
316
+ $(call print_error,'${red}Error${reset}: Environment file "${yellow}${env_file}${reset}" not found. ${cross}') ; \
317
+ exit 1 ; \
318
+ fi
319
+
320
+ .PHONY: _clean-logs
321
+ _clean-logs:
322
+ @rm -f '${stdout}' '${stderr}'
323
+ @touch '${stdout}' '${stderr}'
@@ -0,0 +1,19 @@
1
+ environment ENV.fetch('RAILS_ENV') { 'development' }
2
+
3
+ port ENV.fetch('WEB_PORT') { 3000 }
4
+ workers ENV.fetch('WEB_CONCURRENCY') { 4 }
5
+ threads_count = ENV.fetch('RAILS_MAX_THREADS') { 8 }
6
+
7
+ pidfile './tmp/pids/server.pid'
8
+ threads threads_count, threads_count
9
+
10
+ preload_app! if ENV.key?('WEB_PRELOAD_APP')
11
+
12
+ before_fork do
13
+ ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
14
+ end
15
+
16
+ on_worker_boot do
17
+ ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
18
+ end
19
+
@@ -0,0 +1,12 @@
1
+ <% if compose.call('development').services.key?('rabbitmq') %>
2
+ development:
3
+ url: amqp://127.0.0.1:<%= compose.call('development').local_port('rabbitmq') %>
4
+ <% end %>
5
+
6
+ <% if compose.call('test').services.key?('rabbitmq') %>
7
+ test:
8
+ url: amqp://127.0.0.1:<%= compose.call('test').local_port('rabbitmq') %>
9
+ <% end %>
10
+
11
+ production:
12
+ url: <%%= ENV['RABBITMQ_URL'] %>
@@ -1,12 +1,12 @@
1
- listen '0.0.0.0:8080', tcp_nopush: true
1
+ listen "0.0.0.0:#{ENV.fetch('WEB_PORT', '8080')}", tcp_nopush: true
2
2
 
3
- pid '/app/tmp/pids/unicorn.pid'
3
+ pid '/app/tmp/pids/server.pid'
4
4
 
5
- preload_app ENV.fetch('UNICORN_PRELOAD_APP', '1') == '1'
5
+ preload_app ENV.key?('WEB_PRELOAD_APP')
6
6
 
7
- timeout ENV.fetch('UNICORN_TIMEOUT', 60).to_i
7
+ timeout ENV.fetch('WEB_TIMEOUT', 60).to_i
8
8
 
9
- worker_processes ENV.fetch('UNICORN_WORKER_PROCESSES', 8).to_i
9
+ worker_processes ENV.fetch('WEB_CONCURRENCY', 8).to_i
10
10
 
11
11
  before_fork do |_server, _worker|
12
12
  ActiveRecord::Base.connection.disconnect! if defined?(ActiveRecord)
@@ -2,16 +2,17 @@
2
2
 
3
3
  module Orchestration
4
4
  COLOR_MAP = {
5
- failure: :light_red,
6
- error: :red,
7
- waiting: :yellow,
8
- ready: :green,
9
- create: :green,
10
- update: :yellow,
11
- status: :blue,
12
- setup: :blue,
13
- input: :red,
14
- skip: :light_yellow
5
+ failure: %i[red bright],
6
+ error: %i[red],
7
+ waiting: %i[yellow],
8
+ ready: %i[green],
9
+ create: %i[green],
10
+ update: %i[yellow],
11
+ backup: %i[blue],
12
+ status: %i[blue],
13
+ setup: %i[blue],
14
+ input: %i[red],
15
+ skip: %i[yellow bright]
15
16
  }.freeze
16
17
 
17
18
  class Terminal
@@ -55,11 +56,8 @@ module Orchestration
55
56
  else
56
57
  COLOR_MAP.fetch(color_name)
57
58
  end
58
- desc
59
- .to_s
60
- .rjust(15)
61
- .colorize(mode: :default, color: color)
62
- .concat(' ' + message)
59
+
60
+ Paint[desc.to_s.rjust(15), *color] + ' ' + message
63
61
  end
64
62
 
65
63
  def t(key)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Orchestration
4
- VERSION = '0.3.17'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/orchestration.rb CHANGED
@@ -1,12 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'colorize'
3
+ require 'erb'
4
+ require 'pathname'
5
+ require 'socket'
6
+
7
+ require 'database_url'
4
8
  require 'erubis'
5
9
  require 'i18n'
10
+ require 'paint'
6
11
  begin
7
12
  require 'rails'
8
13
  rescue LoadError
9
- STDERR.puts('Rails not detected; continuing without Rails support.')
14
+ STDERR.puts('[orchestration] Rails not detected; skipping.')
10
15
  end
11
16
 
12
17
  I18n.load_path += Dir[File.join(File.expand_path('..', __dir__),
@@ -33,4 +38,17 @@ module Orchestration
33
38
  def self.rakefile
34
39
  root.join('lib', 'Rakefile')
35
40
  end
41
+
42
+ def self.error(key, options = {})
43
+ STDERR.puts('# Orchestration Error')
44
+ STDERR.puts('# ' + I18n.t("orchestration.#{key}", options))
45
+ end
46
+
47
+ def self.random_local_port
48
+ socket = Socket.new(:INET, :STREAM, 0)
49
+ socket.bind(Addrinfo.tcp('127.0.0.1', 0))
50
+ port = socket.local_address.ip_port
51
+ socket.close
52
+ port
53
+ end
36
54
  end
@@ -18,7 +18,9 @@ namespace :orchestration do
18
18
  namespace :database do
19
19
  desc I18n.t('orchestration.rake.database.wait')
20
20
  task :wait do
21
- Orchestration::Services::Database::Healthcheck.start
21
+ Orchestration::Services::Database::Healthcheck.start(
22
+ nil, nil, init: ENV.key?('init')
23
+ )
22
24
  end
23
25
  end
24
26
 
@@ -16,19 +16,17 @@ Gem::Specification.new do |spec|
16
16
  spec.homepage = url
17
17
 
18
18
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
19
- `git ls-files -z`.split("\x0").reject do |f|
20
- f.match(%r{^(test|spec|features)/})
21
- end
19
+ File.readlines('MANIFEST').map(&:chomp)
22
20
  end
23
21
  spec.bindir = 'bin'
24
22
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
25
23
  spec.require_paths = ['lib']
26
24
 
27
- spec.add_runtime_dependency 'colorize', '~> 0.8.1'
25
+ spec.add_runtime_dependency 'database_url', '~> 0.1.2'
28
26
  spec.add_runtime_dependency 'erubis', '~> 2.7'
29
27
  spec.add_runtime_dependency 'i18n', '>= 0.5'
28
+ spec.add_runtime_dependency 'paint', '~> 2.0'
30
29
  spec.add_runtime_dependency 'thor', '~> 0.20.0'
31
- spec.add_runtime_dependency 'unicorn', '~> 5.4'
32
30
 
33
31
  spec.add_development_dependency 'activerecord', '~> 5.2'
34
32
  spec.add_development_dependency 'betterp', '~> 0.1.3'