orchestration 0.3.17 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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'