orchestration 0.2.8 → 0.3.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
2
  SHA1:
3
- metadata.gz: 776a11504e5b33803ff0375a1d168b08567b8e97
4
- data.tar.gz: 52a848059b2fb338222b72cc00590f6d3760ae13
3
+ metadata.gz: 13a569a8391d7110efc2606ba1d486e29e342080
4
+ data.tar.gz: c5eed32f638f89dce179cd93c8f634504fe628d2
5
5
  SHA512:
6
- metadata.gz: a549fe23607afe2b5b0e46e28956a64f0dde1f43fcd900b6458cad298a0f05073c6aa1899908aaf8e978de940beb19414d3374471b2edfe8a4c1729ae50b97b0
7
- data.tar.gz: be3f1f287527ae67f1ca236aba5d1e2acd68cf34136916943c6a284e634330b1bea89c81aabcc6b3b5936c90e882f4e33fbb4cbd18cfc80d998d2033f03ea1de
6
+ metadata.gz: 91481f33e8f48bfabe18ab3c36fab7381060c631a62da15f3806197f7ec3ef08815a93790d132cf8431606eb6d110792f86c26fe3b7783a2e347a61f6e05a0cc
7
+ data.tar.gz: 32f5222a028460e9d5bb5b4477dae935a83692d7f50dae1e62d0b24b19fb3fb4db5c38453f2a1f9a787502868bb45d0a0284d9a99d331507c7cef9278ef7f7ac
data/.gitignore CHANGED
@@ -19,8 +19,7 @@ spec/dummy/log/*
19
19
  !spec/dummy/log/.keep
20
20
  spec/dummy/.gitignore
21
21
  spec/dummy/Makefile
22
- spec/dummy/docker/*
23
- spec/dummy/docker-compose.yml
22
+ spec/dummy/orchestration/*
24
23
  spec/dummy/config/unicorn.rb
25
24
 
26
25
  orchestration-*.gem
@@ -0,0 +1,2 @@
1
+ ignore:
2
+ - i18n
data/Makefile CHANGED
@@ -3,3 +3,4 @@
3
3
  test:
4
4
  ./bin/rspec
5
5
  ./bin/rubocop
6
+ ./bin/strong_versions
data/README.md CHANGED
@@ -18,7 +18,7 @@ Containers are automatically created for the following dependencies:
18
18
  Add this line to your application's Gemfile:
19
19
 
20
20
  ```ruby
21
- gem 'orchestration', '~> 0.2.8'
21
+ gem 'orchestration', '~> 0.3.0'
22
22
  ```
23
23
 
24
24
  And then build your bundle:
@@ -32,11 +32,14 @@ $ bundle install
32
32
 
33
33
  A _Rake_ task is provided to generate the following files:
34
34
 
35
- * `Makefile` - provides easy access to all _Orchestration_ utilities.
36
35
  * `.gitignore` - ensures any unwanted files created by _Orchestration_ do not clutter your project's version control system.
37
- * `docker/Dockerfile` - a ready-to-use _Docker_ build script which should need minimal (if any) modification to build your _Rails_ project.
38
- * `docker-compose.yml` - a custom-made set of services to allow you to run your application's dependencies locally.
39
36
  * `.orchestration.yml` - _Orchestration_ internal configuration, e.g. _Docker_ username.
37
+ * `Makefile` - Adds `orchestration/Makefile` as an `include` to avoid clobbering any existing _make_ commands.
38
+ * `orchestration/docker-compose.yml` - a custom-made set of services to allow you to run your application's dependencies locally.
39
+ * `orchestration/Dockerfile` - a ready-to-use _Docker_ build script which should need minimal (if any) modification to build your _Rails_ project.
40
+ * `orchestration/entrypoint.sh` - Container setup for your Docker application.
41
+ * `orchestration/Makefile` - provides easy access to all _Orchestration_ utilities.
42
+ * `orchestration/yaml.bash` - A _bash_ _YAML_ parser (used by _make_ utilities).
40
43
 
41
44
  ### Building and pushing your project as a _Docker_ image
42
45
 
@@ -47,7 +50,7 @@ If your project has any dependencies on private _Git_ repositories then you wil
47
50
  * [GitHub](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/)
48
51
  * [Bitbucket](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html)
49
52
 
50
- Create a file named `.env` in the same directory as your `docker-compose.yml` and add one or both of the following (note that _Bitbucket_ and _GitHub_ use a different format):
53
+ Create a file named `.env` in your project's root directory and add one or both of the following (note that _Bitbucket_ and _GitHub_ use a different format):
51
54
 
52
55
  ```bash
53
56
  BUNDLE_BITBUCKET__ORG=<bitbucket-username>:<app-password>
data/TODO CHANGED
@@ -1,15 +1,19 @@
1
- Be aware of yarn and include build steps in Dockerfile if present. Use dashboard
2
- front end as a reference.
3
-
4
1
  Provide volumes for databases and mount appropriate directories for adapter
5
2
 
6
3
  Refactor docker-compose services - these really belong in
7
4
  lib/orchestration/services/<service-name>/docker_compose.rb
8
5
 
9
- Add a note to README to handle `RAILS_LOG_TO_STDOUT` in development -
10
- unfortunately Rails ignores this value in development mode. (It's configured in
11
- config/environments/production.rb)
12
-
13
6
  Standardise on log formats - by policy or recommendation ?
14
7
 
15
8
  Redis support
9
+
10
+ Stop supporting development mode. Provide a docker-compose.yml for loading
11
+ development and test dependencies and expect user to run Rails application
12
+ locally.
13
+
14
+ Build a docker-compose.production.yml for running application in
15
+ production (i.e. including application as a service and removing local port
16
+ bindings).
17
+
18
+ Make docker-compose file additive - detect existing services and add new ones
19
+ rather than overwriting.
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'strong_versions' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("strong_versions", "strong_versions")
@@ -1,6 +1,7 @@
1
1
  en:
2
2
  orchestration:
3
3
  attempt_limit: "Unable to reconnect after %{limit} attempts. Aborting."
4
+ default: "default"
4
5
 
5
6
  application:
6
7
  waiting: "Waiting for application: %{config}"
@@ -27,8 +28,15 @@ en:
27
28
  waiting: "Waiting for [%{service}]: %{config}"
28
29
  ready: "[%{service}] is ready."
29
30
 
30
- docker:
31
- username_request: "Enter your Docker registry username (used for tagging images)"
31
+ settings:
32
+ docker:
33
+ username:
34
+ description: "Docker registry username"
35
+ prompt: "username"
36
+
37
+ repository:
38
+ description: "Project name (will be used as Docker registry repository)"
39
+ prompt: "project name"
32
40
 
33
41
  rake:
34
42
  docker:
@@ -9,22 +9,17 @@ module Orchestration
9
9
 
10
10
  def definition
11
11
  {
12
- 'image' => image,
13
- 'entrypoint' => '/entrypoint.sh',
14
- 'command' => %w[
15
- bundle exec unicorn -c /application/config/unicorn.rb
16
- ],
12
+ 'image' => '${DOCKER_USERNAME}/${DOCKER_REPOSITORY}',
17
13
  'environment' => environment,
18
- 'expose' => [8080]
14
+ 'expose' => [8080],
15
+ 'volumes' => [
16
+ "#{@config.env.public_volume}:/app/public/:ro"
17
+ ]
19
18
  }
20
19
  end
21
20
 
22
21
  private
23
22
 
24
- def image
25
- "#{@config.docker_username}/#{@config.application_name}"
26
- end
27
-
28
23
  def environment
29
24
  {
30
25
  'DATABASE_URL' => @config.database_url,
@@ -9,9 +9,12 @@ module Orchestration
9
9
 
10
10
  def definition
11
11
  {
12
- 'image' => 'jwilder/nginx-proxy',
12
+ 'image' => 'rubyorchestration/nginx-proxy',
13
13
  'ports' => %w[3000:80],
14
- 'volumes' => ['/var/run/docker.sock:/tmp/docker.sock:ro']
14
+ 'volumes' => [
15
+ '/var/run/docker.sock:/tmp/docker.sock:ro',
16
+ "#{@config.env.public_volume}:/var/www/public/:ro"
17
+ ]
15
18
  }
16
19
  end
17
20
  end
@@ -3,7 +3,8 @@
3
3
  module Orchestration
4
4
  module DockerCompose
5
5
  class Services
6
- def initialize(options = {})
6
+ def initialize(env, options = {})
7
+ @env = env
7
8
  @configurations = {
8
9
  'application' => options.fetch(:application, nil),
9
10
  'database' => options.fetch(:database, nil),
@@ -14,7 +15,13 @@ module Orchestration
14
15
  end
15
16
 
16
17
  def structure
17
- { 'version' => '3.7', 'services' => services }
18
+ {
19
+ 'version' => '3.7',
20
+ 'services' => services,
21
+ 'volumes' => {
22
+ @env.public_volume => nil
23
+ }
24
+ }
18
25
  end
19
26
 
20
27
  def services
@@ -33,7 +33,7 @@ module Orchestration
33
33
  end
34
34
 
35
35
  def docker_compose_configuration_path
36
- root.join('docker-compose.yml')
36
+ orchestration_root.join('docker-compose.yml')
37
37
  end
38
38
 
39
39
  def docker_compose_config
@@ -44,10 +44,14 @@ module Orchestration
44
44
  docker_compose_configuration_path.file?
45
45
  end
46
46
 
47
- def application_name
47
+ def default_application_name
48
48
  Rails.application.class.parent.name.underscore
49
49
  end
50
50
 
51
+ def application_name
52
+ settings.get('docker.repository')
53
+ end
54
+
51
55
  def settings
52
56
  Settings.new(orchestration_configuration_path)
53
57
  end
@@ -57,5 +61,17 @@ module Orchestration
57
61
 
58
62
  Pathname.new(Dir.pwd)
59
63
  end
64
+
65
+ def orchestration_root
66
+ root.join(orchestration_dir_name)
67
+ end
68
+
69
+ def orchestration_dir_name
70
+ 'orchestration'
71
+ end
72
+
73
+ def public_volume
74
+ "#{application_name}_public"
75
+ end
60
76
  end
61
77
  end
@@ -4,45 +4,56 @@ module Orchestration
4
4
  module FileHelpers
5
5
  private
6
6
 
7
+ def orchestration_dir
8
+ path = @env.orchestration_root
9
+ FileUtils.mkdir(path) unless Dir.exist?(path)
10
+
11
+ path
12
+ end
13
+
7
14
  def template(template_name, context = {})
8
15
  Erubis::Eruby.new(read_template(template_name))
9
16
  .result(context)
10
17
  end
11
18
 
12
- def delete_and_inject_after(path, pattern, replacement)
13
- return write_file(path, pattern + replacement) unless File.exist?(path)
14
-
15
- input = File.read(path)
16
- index = append_index(pattern, input)
17
- output = input[0...index] + pattern + replacement
18
-
19
- return @terminal.write(:identical, relative_path(path)) if input == output
20
-
21
- update_file(path, output)
22
- end
23
-
24
- def append_index(pattern, input)
25
- return 0 if input.empty?
19
+ def inject_if_missing(path, content, index = 0)
20
+ lines = File.exist?(path) ? File.readlines(path).map(&:chomp) : []
21
+ if lines.any? { |line| line == content }
22
+ return @terminal.write(:skip, relative_path(path))
23
+ end
26
24
 
27
- index = input.index(pattern)
28
- index.nil? ? (input.size + 1) : index
25
+ lines.insert(index, content)
26
+ update_file(path, lines.join("\n"))
29
27
  end
30
28
 
31
29
  def relative_path(path)
32
30
  path.relative_path_from(Rails.root).to_s
33
31
  end
34
32
 
33
+ def simple_copy(template_name, dest)
34
+ update_file(dest, template(template_name))
35
+ end
36
+
35
37
  def write_file(path, content, options = {})
36
38
  relpath = relative_path(path)
37
39
  overwrite = options.fetch(:overwrite, true)
38
- return @terminal.write(:skip, relpath) if File.exist?(path) && !overwrite
40
+ present = File.exist?(path)
41
+ return @terminal.write(:skip, relpath) if present && !overwrite
39
42
 
40
43
  File.write(path, content)
41
44
  @terminal.write(:create, relative_path(path))
42
45
  end
43
46
 
44
47
  def update_file(path, content)
48
+ present = File.exist?(path)
49
+ return write_file(path, content) unless present
50
+
51
+ previous_content = File.read(path) if present
45
52
  File.write(path, content)
53
+ if present && previous_content == content
54
+ return @terminal.write(:skip, relative_path(path))
55
+ end
56
+
46
57
  @terminal.write(:update, relative_path(path))
47
58
  end
48
59
 
@@ -11,63 +11,61 @@ module Orchestration
11
11
  super
12
12
  @env = Environment.new
13
13
  @terminal ||= Terminal.new
14
+ @settings = Settings.new(@env.orchestration_configuration_path)
14
15
  end
15
16
 
16
17
  def orchestration_configuration
17
18
  path = @env.orchestration_configuration_path
18
- settings = Settings.new(path)
19
- docker_username(settings)
19
+ ask_setting('docker.username')
20
+ ask_setting('docker.repository', @env.default_application_name)
20
21
  relpath = relative_path(path)
21
- return @terminal.write(:create, relpath) unless settings.exist?
22
- return @terminal.write(:update, relpath) if settings.dirty?
22
+ return @terminal.write(:create, relpath) unless @settings.exist?
23
+ return @terminal.write(:update, relpath) if @settings.dirty?
23
24
 
24
25
  @terminal.write(:skip, relpath)
25
26
  end
26
27
 
27
28
  def makefile
28
- environment = {
29
- app_id: @env.application_name,
30
- wait_commands: wait_commands
31
- }
29
+ environment = { env: @env, wait_commands: wait_commands }
32
30
  content = template('Makefile', environment)
33
- path = @env.root.join('Makefile')
34
- delete_and_inject_after(path, "\n#!!orchestration\n", content)
31
+ path = @env.orchestration_root.join('Makefile')
32
+ path.exist? ? update_file(path, content) : write_file(path, content)
33
+ inject_if_missing(
34
+ @env.root.join('Makefile'),
35
+ 'include orchestration/Makefile'
36
+ )
35
37
  end
36
38
 
37
39
  def dockerfile
38
40
  content = template('Dockerfile', ruby_version: RUBY_VERSION)
39
- write_file(docker_dir.join('Dockerfile'), content, overwrite: false)
41
+ write_file(
42
+ orchestration_dir.join('Dockerfile'),
43
+ content,
44
+ overwrite: false
45
+ )
40
46
  end
41
47
 
42
48
  def entrypoint
43
49
  content = template('entrypoint.sh')
44
- path = docker_dir.join('entrypoint.sh')
50
+ path = orchestration_dir.join('entrypoint.sh')
45
51
  write_file(path, content, overwrite: false)
46
52
  FileUtils.chmod('a+x', path)
47
53
  end
48
54
 
49
55
  def gitignore
50
56
  path = @env.root.join('.gitignore')
51
- entries = [
52
- 'docker/.build/',
53
- 'docker/Gemfile',
54
- 'docker/Gemfile.lock',
55
- 'docker/*.gemspec'
56
- ]
57
+ entries = %w[.build/ Gemfile Gemfile.lock *.gemspec].map do |entry|
58
+ "#{@env.orchestration_dir_name}/#{entry}"
59
+ end
60
+
57
61
  ensure_lines_in_file(path, entries)
58
62
  end
59
63
 
60
64
  def docker_compose
61
- path = @env.root.join('docker-compose.yml')
65
+ path = @env.orchestration_root.join('docker-compose.yml')
62
66
  return if File.exist?(path)
63
67
 
64
- docker_compose = DockerCompose::Services.new(
65
- application: configuration(:application),
66
- database: configuration(:database),
67
- mongo: configuration(:mongo),
68
- rabbitmq: configuration(:rabbitmq),
69
- nginx_proxy: configuration(:nginx_proxy)
70
- )
68
+ docker_compose = DockerCompose::Services.new(@env, service_configurations)
71
69
  write_file(path, docker_compose.structure.to_yaml)
72
70
  end
73
71
 
@@ -77,8 +75,24 @@ module Orchestration
77
75
  write_file(path, content, overwrite: false)
78
76
  end
79
77
 
78
+ def yaml_bash
79
+ simple_copy('yaml.bash', @env.orchestration_root.join('yaml.bash'))
80
+ end
81
+
80
82
  private
81
83
 
84
+ def t(key)
85
+ I18n.t("orchestration.#{key}")
86
+ end
87
+
88
+ def service_configurations
89
+ Hash[
90
+ %i[application database mongo rabbitmq nginx_proxy].map do |key|
91
+ [key, configuration(key)]
92
+ end
93
+ ]
94
+ end
95
+
82
96
  def configuration(service)
83
97
  {
84
98
  application: Services::Application::Configuration,
@@ -99,18 +113,12 @@ module Orchestration
99
113
  ].compact.join(' ')
100
114
  end
101
115
 
102
- def docker_username(settings)
103
- return unless settings.get('docker.username').nil?
104
-
105
- @terminal.write(:setup, I18n.t('orchestration.docker.username_request'))
106
- settings.set('docker.username', @terminal.read('[username]:'))
107
- end
108
-
109
- def docker_dir
110
- path = @env.root.join('docker')
111
- FileUtils.mkdir(path) unless Dir.exist?(path)
116
+ def ask_setting(setting, default = nil)
117
+ return unless @settings.get(setting).nil?
112
118
 
113
- path
119
+ @terminal.write(:setup, t("settings.#{setting}.description"))
120
+ prompt = t("settings.#{setting}.prompt")
121
+ @settings.set(setting, @terminal.read(prompt, default))
114
122
  end
115
123
  end
116
124
  end
@@ -18,7 +18,7 @@ module Orchestration
18
18
  end
19
19
 
20
20
  def application_name
21
- @env.application_name
21
+ @env.settings.get('docker.repository')
22
22
  end
23
23
 
24
24
  def friendly_config
@@ -3,7 +3,7 @@
3
3
  module Orchestration
4
4
  module Services
5
5
  module ConfigurationBase
6
- attr_reader :settings, :service_name
6
+ attr_reader :settings, :service_name, :env
7
7
 
8
8
  def self.included(base)
9
9
  base.extend(ClassMethods)
@@ -5,9 +5,20 @@ RUN apt-get update \
5
5
  && apt-get install -y node.js gosu sendmail \
6
6
  && rm -rf /var/lib/apt/lists/* \
7
7
  && gem install bundler \
8
- && mkdir /application
9
- WORKDIR /application
10
- COPY Gemfile Gemfile.lock ./
11
- RUN bundle install --deployment
8
+ && mkdir /app<%if defined?(Webpacker) %> \
9
+ && curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash \
10
+ && . /root/.bashrc \
11
+ && nvm install 10.11.0 \
12
+ && npm install -g yarn<% end %>
13
+ WORKDIR /app
14
+ COPY .build/Gemfile .build/Gemfile.lock ./
15
+ RUN bundle install --without development test --deployment
16
+ <% if defined?(Webpacker) %>
17
+ COPY .build/package.json .build/yarn.lock ./
18
+ RUN . /root/.bashrc && yarn install
19
+ <% end %>
12
20
  COPY entrypoint.sh /
13
21
  ADD .build/context.tar.gz .
22
+ <% if defined?(Webpacker) %>RUN . /root/.bashrc && yarn install && bundle exec rake assets:precompile<% else %>RUN bundle exec rake assets:precompile<% end %>
23
+ ENTRYPOINT ["/entrypoint.sh"]
24
+ CMD ["bundle", "exec", "unicorn", "-c", "/app/config/unicorn.rb"]
@@ -1,20 +1,10 @@
1
-
2
- # Do not edit this file below this point. Any changes will be overwritten.
3
- #
4
- # Example `test` command which will start and wait for all services before
5
- # running tests:
6
- #
7
- # test: start wait
8
- # bundle exec rspec
9
- # yarn test app/javascript
10
- # bundle exec rubocop
11
- # yarn run eslint app/javascript
12
- #
13
- .PHONY: start stop migrate docker build push start <%= wait_commands %>
1
+ .PHONY: start stop migrate docker build push start logs compose config <%= wait_commands %>
14
2
 
15
3
  ### Container management commands ###
16
4
 
17
- COMPOSE:=HOST_UID=$(shell id -u) docker-compose
5
+ DOCKER_USERNAME:=$(shell bash ./<%= env.orchestration_dir_name %>/yaml.bash docker_username)
6
+ DOCKER_REPOSITORY:=$(shell bash ./<%= env.orchestration_dir_name %>/yaml.bash docker_repository)
7
+ COMPOSE:=HOST_UID=$(shell id -u) DOCKER_USERNAME=${DOCKER_USERNAME} DOCKER_REPOSITORY=${DOCKER_REPOSITORY} docker-compose -p $(shell bash ./<%= env.orchestration_dir_name %>/yaml.bash docker_repository) -f orchestration/docker-compose.yml
18
8
 
19
9
  start:
20
10
  @echo "Starting containers..."
@@ -32,6 +22,15 @@ start-application:
32
22
  @make wait-nginx-proxy wait-application
33
23
  @echo "Application started."
34
24
 
25
+ logs:
26
+ @${COMPOSE} logs
27
+
28
+ config:
29
+ @${COMPOSE} config
30
+
31
+ compose:
32
+ @${COMPOSE} $$cmd
33
+
35
34
  ### Database utility commands ###
36
35
 
37
36
  migrate: wait-database
@@ -67,19 +66,21 @@ GIT_BRANCH:=$(if $(BRANCH),$(BRANCH),$(shell git rev-parse --abbrev-ref HEAD))
67
66
 
68
67
  build:
69
68
  @echo "Preparing build from ${GIT_BRANCH}"
70
- @mkdir -p ./docker/.build
71
- @git show ${GIT_BRANCH}:./Gemfile > ./docker/Gemfile
72
- @git show ${GIT_BRANCH}:./Gemfile.lock > ./docker/Gemfile.lock
69
+ @mkdir -p ./<%= env.orchestration_dir_name %>/.build
70
+ @git show ${GIT_BRANCH}:./Gemfile > ./<%= env.orchestration_dir_name %>/.build/Gemfile
71
+ @git show ${GIT_BRANCH}:./Gemfile.lock > ./<%= env.orchestration_dir_name %>/.build/Gemfile.lock
72
+ <% if defined?(Webpacker) %>@git show ${GIT_BRANCH}:./package.json > ./<%= env.orchestration_dir_name %>/.build/package.json<% end %>
73
+ <% if defined?(Webpacker) %>@git show ${GIT_BRANCH}:./yarn.lock > ./<%= env.orchestration_dir_name %>/.build/yarn.lock<% end %>
73
74
  @echo "Building..."
74
- @git archive --format tar.gz -o docker/.build/context.tar.gz ${GIT_BRANCH}
75
+ @git archive --format tar.gz -o ./<%= env.orchestration_dir_name %>/.build/context.tar.gz ${GIT_BRANCH}
75
76
  @docker build \
76
77
  --build-arg BUNDLE_GITHUB__COM \
77
78
  --build-arg BUNDLE_BITBUCKET__ORG \
78
- -t $(shell bin/rake orchestration:docker:username)/<%= app_id %> \
79
- -t $(shell bin/rake orchestration:docker:username)/<%= app_id %>:$(shell git rev-parse --short --verify ${GIT_BRANCH}) \
80
- ./docker/
79
+ -t ${DOCKER_USERNAME}/${DOCKER_REPOSITORY} \
80
+ -t ${DOCKER_USERNAME}/${DOCKER_REPOSITORY}:$(shell git rev-parse --short --verify ${GIT_BRANCH}) \
81
+ ./<%= env.orchestration_dir_name %>/
81
82
  @echo "Build complete."
82
83
 
83
84
  push: VERSION := $(shell git rev-parse --short --verify ${GIT_BRANCH})
84
85
  push:
85
- docker push $(shell bin/rake orchestration:docker:username)/<%= app_id %>:${VERSION}
86
+ docker push ${DOCKER_USERNAME}/${DOCKER_REPOSITORY}:${VERSION}
@@ -1,7 +1,9 @@
1
1
  #!/bin/sh
2
2
  set -u
3
3
  id owner >/dev/null 2>&1 || useradd -u ${HOST_UID} -m -o owner
4
- mkdir -p /application/tmp/pids
5
- chown -R owner:owner /application/tmp /application/log /application/db
6
- rm -f /application/tmp/pids/unicorn.pid
4
+ mkdir -p /app/tmp/pids
5
+ chown -R owner:owner /app/tmp /app/log /app/db
6
+ rm -f /app/tmp/pids/unicorn.pid
7
+ mkdir -p /var/www/public/
8
+ ln -nfs /app/public/* /var/www/public/
7
9
  exec gosu owner "$@"
@@ -0,0 +1,364 @@
1
+ {{ $CurrentContainer := where $ "ID" .Docker.CurrentContainerID | first }}
2
+
3
+ {{ define "upstream" }}
4
+ {{ if .Address }}
5
+ {{/* If we got the containers from swarm and this container's port is published to host, use host IP:PORT */}}
6
+ {{ if and .Container.Node.ID .Address.HostPort }}
7
+ # {{ .Container.Node.Name }}/{{ .Container.Name }}
8
+ server {{ .Container.Node.Address.IP }}:{{ .Address.HostPort }};
9
+ {{/* If there is no swarm node or the port is not published on host, use container's IP:PORT */}}
10
+ {{ else if .Network }}
11
+ # {{ .Container.Name }}
12
+ server {{ .Network.IP }}:{{ .Address.Port }};
13
+ {{ end }}
14
+ {{ else if .Network }}
15
+ # {{ .Container.Name }}
16
+ {{ if .Network.IP }}
17
+ server {{ .Network.IP }} down;
18
+ {{ else }}
19
+ server 127.0.0.1 down;
20
+ {{ end }}
21
+ {{ end }}
22
+
23
+ {{ end }}
24
+
25
+ # If we receive X-Forwarded-Proto, pass it through; otherwise, pass along the
26
+ # scheme used to connect to this server
27
+ map $http_x_forwarded_proto $proxy_x_forwarded_proto {
28
+ default $http_x_forwarded_proto;
29
+ '' $scheme;
30
+ }
31
+
32
+ # If we receive X-Forwarded-Port, pass it through; otherwise, pass along the
33
+ # server port the client connected to
34
+ map $http_x_forwarded_port $proxy_x_forwarded_port {
35
+ default $http_x_forwarded_port;
36
+ '' $server_port;
37
+ }
38
+
39
+ # If we receive Upgrade, set Connection to "upgrade"; otherwise, delete any
40
+ # Connection header that may have been passed to this server
41
+ map $http_upgrade $proxy_connection {
42
+ default upgrade;
43
+ '' close;
44
+ }
45
+
46
+ # Apply fix for very long server names
47
+ server_names_hash_bucket_size 128;
48
+
49
+ # Default dhparam
50
+ {{ if (exists "/etc/nginx/dhparam/dhparam.pem") }}
51
+ ssl_dhparam /etc/nginx/dhparam/dhparam.pem;
52
+ {{ end }}
53
+
54
+ # Set appropriate X-Forwarded-Ssl header
55
+ map $scheme $proxy_x_forwarded_ssl {
56
+ default off;
57
+ https on;
58
+ }
59
+
60
+ gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
61
+
62
+ log_format vhost '$host $remote_addr - $remote_user [$time_local] '
63
+ '"$request" $status $body_bytes_sent '
64
+ '"$http_referer" "$http_user_agent"';
65
+
66
+ access_log off;
67
+
68
+ {{ if $.Env.RESOLVERS }}
69
+ resolver {{ $.Env.RESOLVERS }};
70
+ {{ end }}
71
+
72
+ {{ if (exists "/etc/nginx/proxy.conf") }}
73
+ include /etc/nginx/proxy.conf;
74
+ {{ else }}
75
+ # HTTP 1.1 support
76
+ proxy_http_version 1.1;
77
+ proxy_buffering off;
78
+ proxy_set_header Host $http_host;
79
+ proxy_set_header Upgrade $http_upgrade;
80
+ proxy_set_header Connection $proxy_connection;
81
+ proxy_set_header X-Real-IP $remote_addr;
82
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
83
+ proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
84
+ proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
85
+ proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
86
+
87
+ # Mitigate httpoxy attack (see README for details)
88
+ proxy_set_header Proxy "";
89
+ {{ end }}
90
+
91
+ {{ $enable_ipv6 := eq (or ($.Env.ENABLE_IPV6) "") "true" }}
92
+ server {
93
+ server_name _; # This is just an invalid value which will never trigger on a real hostname.
94
+ listen 80;
95
+ {{ if $enable_ipv6 }}
96
+ listen [::]:80;
97
+ {{ end }}
98
+ access_log /var/log/nginx/access.log vhost;
99
+ return 503;
100
+ }
101
+
102
+ {{ if (and (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
103
+ server {
104
+ server_name _; # This is just an invalid value which will never trigger on a real hostname.
105
+ listen 443 ssl http2;
106
+ {{ if $enable_ipv6 }}
107
+ listen [::]:443 ssl http2;
108
+ {{ end }}
109
+ access_log /var/log/nginx/access.log vhost;
110
+ return 503;
111
+
112
+ ssl_session_tickets off;
113
+ ssl_certificate /etc/nginx/certs/default.crt;
114
+ ssl_certificate_key /etc/nginx/certs/default.key;
115
+ }
116
+ {{ end }}
117
+
118
+ {{ range $host, $containers := groupByMulti $ "Env.VIRTUAL_HOST" "," }}
119
+
120
+ {{ $host := trim $host }}
121
+ {{ $is_regexp := hasPrefix "~" $host }}
122
+ {{ $upstream_name := when $is_regexp (sha1 $host) $host }}
123
+
124
+ # {{ $host }}
125
+ upstream {{ $upstream_name }} {
126
+
127
+ {{ range $container := $containers }}
128
+ {{ $addrLen := len $container.Addresses }}
129
+
130
+ {{ range $knownNetwork := $CurrentContainer.Networks }}
131
+ {{ range $containerNetwork := $container.Networks }}
132
+ {{ if (and (ne $containerNetwork.Name "ingress") (or (eq $knownNetwork.Name $containerNetwork.Name) (eq $knownNetwork.Name "host"))) }}
133
+ ## Can be connected with "{{ $containerNetwork.Name }}" network
134
+
135
+ {{/* If only 1 port exposed, use that */}}
136
+ {{ if eq $addrLen 1 }}
137
+ {{ $address := index $container.Addresses 0 }}
138
+ {{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }}
139
+ {{/* If more than one port exposed, use the one matching VIRTUAL_PORT env var, falling back to standard web port 80 */}}
140
+ {{ else }}
141
+ {{ $port := coalesce $container.Env.VIRTUAL_PORT "80" }}
142
+ {{ $address := where $container.Addresses "Port" $port | first }}
143
+ {{ template "upstream" (dict "Container" $container "Address" $address "Network" $containerNetwork) }}
144
+ {{ end }}
145
+ {{ else }}
146
+ # Cannot connect to network of this container
147
+ server 127.0.0.1 down;
148
+ {{ end }}
149
+ {{ end }}
150
+ {{ end }}
151
+ {{ end }}
152
+ }
153
+
154
+ {{ $default_host := or ($.Env.DEFAULT_HOST) "" }}
155
+ {{ $default_server := index (dict $host "" $default_host "default_server") $host }}
156
+
157
+ {{/* Get the VIRTUAL_PROTO defined by containers w/ the same vhost, falling back to "http" */}}
158
+ {{ $proto := trim (or (first (groupByKeys $containers "Env.VIRTUAL_PROTO")) "http") }}
159
+
160
+ {{/* Get the NETWORK_ACCESS defined by containers w/ the same vhost, falling back to "external" */}}
161
+ {{ $network_tag := or (first (groupByKeys $containers "Env.NETWORK_ACCESS")) "external" }}
162
+
163
+ {{/* Get the HTTPS_METHOD defined by containers w/ the same vhost, falling back to "redirect" */}}
164
+ {{ $https_method := or (first (groupByKeys $containers "Env.HTTPS_METHOD")) "redirect" }}
165
+
166
+ {{/* Get the SSL_POLICY defined by containers w/ the same vhost, falling back to "Mozilla-Intermediate" */}}
167
+ {{ $ssl_policy := or (first (groupByKeys $containers "Env.SSL_POLICY")) "Mozilla-Intermediate" }}
168
+
169
+ {{/* Get the HSTS defined by containers w/ the same vhost, falling back to "max-age=31536000" */}}
170
+ {{ $hsts := or (first (groupByKeys $containers "Env.HSTS")) "max-age=31536000" }}
171
+
172
+ {{/* Get the VIRTUAL_ROOT By containers w/ use fastcgi root */}}
173
+ {{ $vhost_root := or (first (groupByKeys $containers "Env.VIRTUAL_ROOT")) "/var/www/public" }}
174
+
175
+
176
+ {{/* Get the first cert name defined by containers w/ the same vhost */}}
177
+ {{ $certName := (first (groupByKeys $containers "Env.CERT_NAME")) }}
178
+
179
+ {{/* Get the best matching cert by name for the vhost. */}}
180
+ {{ $vhostCert := (closest (dir "/etc/nginx/certs") (printf "%s.crt" $host))}}
181
+
182
+ {{/* vhostCert is actually a filename so remove any suffixes since they are added later */}}
183
+ {{ $vhostCert := trimSuffix ".crt" $vhostCert }}
184
+ {{ $vhostCert := trimSuffix ".key" $vhostCert }}
185
+
186
+ {{/* Use the cert specified on the container or fallback to the best vhost match */}}
187
+ {{ $cert := (coalesce $certName $vhostCert) }}
188
+
189
+ {{ $is_https := (and (ne $https_method "nohttps") (ne $cert "") (exists (printf "/etc/nginx/certs/%s.crt" $cert)) (exists (printf "/etc/nginx/certs/%s.key" $cert))) }}
190
+
191
+ {{ if $is_https }}
192
+
193
+ {{ if eq $https_method "redirect" }}
194
+ server {
195
+ server_name {{ $host }};
196
+ listen 80 {{ $default_server }};
197
+ {{ if $enable_ipv6 }}
198
+ listen [::]:80 {{ $default_server }};
199
+ {{ end }}
200
+ access_log /var/log/nginx/access.log vhost;
201
+ return 301 https://$host$request_uri;
202
+ }
203
+ {{ end }}
204
+
205
+ server {
206
+ server_name {{ $host }};
207
+ listen 443 ssl http2 {{ $default_server }};
208
+ {{ if $enable_ipv6 }}
209
+ listen [::]:443 ssl http2 {{ $default_server }};
210
+ {{ end }}
211
+ access_log /var/log/nginx/access.log vhost;
212
+
213
+ {{ if eq $network_tag "internal" }}
214
+ # Only allow traffic from internal clients
215
+ include /etc/nginx/network_internal.conf;
216
+ {{ end }}
217
+
218
+ {{ if eq $ssl_policy "Mozilla-Modern" }}
219
+ ssl_protocols TLSv1.2 TLSv1.3;
220
+ ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
221
+ {{ else if eq $ssl_policy "Mozilla-Intermediate" }}
222
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
223
+ ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS';
224
+ {{ else if eq $ssl_policy "Mozilla-Old" }}
225
+ ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
226
+ ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP';
227
+ {{ else if eq $ssl_policy "AWS-TLS-1-2-2017-01" }}
228
+ ssl_protocols TLSv1.2 TLSv1.3;
229
+ ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256';
230
+ {{ else if eq $ssl_policy "AWS-TLS-1-1-2017-01" }}
231
+ ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
232
+ ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA';
233
+ {{ else if eq $ssl_policy "AWS-2016-08" }}
234
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
235
+ ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA';
236
+ {{ else if eq $ssl_policy "AWS-2015-05" }}
237
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
238
+ ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DES-CBC3-SHA';
239
+ {{ else if eq $ssl_policy "AWS-2015-03" }}
240
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
241
+ ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA:DES-CBC3-SHA';
242
+ {{ else if eq $ssl_policy "AWS-2015-02" }}
243
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
244
+ ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:DHE-DSS-AES128-SHA';
245
+ {{ end }}
246
+
247
+ ssl_prefer_server_ciphers on;
248
+ ssl_session_timeout 5m;
249
+ ssl_session_cache shared:SSL:50m;
250
+ ssl_session_tickets off;
251
+
252
+ ssl_certificate /etc/nginx/certs/{{ (printf "%s.crt" $cert) }};
253
+ ssl_certificate_key /etc/nginx/certs/{{ (printf "%s.key" $cert) }};
254
+
255
+ {{ if (exists (printf "/etc/nginx/certs/%s.dhparam.pem" $cert)) }}
256
+ ssl_dhparam {{ printf "/etc/nginx/certs/%s.dhparam.pem" $cert }};
257
+ {{ end }}
258
+
259
+ {{ if (exists (printf "/etc/nginx/certs/%s.chain.pem" $cert)) }}
260
+ ssl_stapling on;
261
+ ssl_stapling_verify on;
262
+ ssl_trusted_certificate {{ printf "/etc/nginx/certs/%s.chain.pem" $cert }};
263
+ {{ end }}
264
+
265
+ {{ if (and (ne $https_method "noredirect") (ne $hsts "off")) }}
266
+ add_header Strict-Transport-Security "{{ trim $hsts }}" always;
267
+ {{ end }}
268
+
269
+ {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }}
270
+ include {{ printf "/etc/nginx/vhost.d/%s" $host }};
271
+ {{ else if (exists "/etc/nginx/vhost.d/default") }}
272
+ include /etc/nginx/vhost.d/default;
273
+ {{ end }}
274
+
275
+ root /var/www/public;
276
+ try_files $uri @application;
277
+
278
+ location @application {
279
+ {{ if eq $proto "uwsgi" }}
280
+ include uwsgi_params;
281
+ uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }};
282
+ {{ else if eq $proto "fastcgi" }}
283
+ root {{ trim $vhost_root }};
284
+ include fastcgi.conf;
285
+ fastcgi_pass {{ trim $upstream_name }};
286
+ {{ else }}
287
+ proxy_pass {{ trim $proto }}://{{ trim $upstream_name }};
288
+ {{ end }}
289
+
290
+ {{ if (exists (printf "/etc/nginx/htpasswd/%s" $host)) }}
291
+ auth_basic "Restricted {{ $host }}";
292
+ auth_basic_user_file {{ (printf "/etc/nginx/htpasswd/%s" $host) }};
293
+ {{ end }}
294
+ {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }}
295
+ include {{ printf "/etc/nginx/vhost.d/%s_location" $host}};
296
+ {{ else if (exists "/etc/nginx/vhost.d/default_location") }}
297
+ include /etc/nginx/vhost.d/default_location;
298
+ {{ end }}
299
+ }
300
+ }
301
+
302
+ {{ end }}
303
+
304
+ {{ if or (not $is_https) (eq $https_method "noredirect") }}
305
+
306
+ server {
307
+ server_name {{ $host }};
308
+ listen 80 {{ $default_server }};
309
+ {{ if $enable_ipv6 }}
310
+ listen [::]:80 {{ $default_server }};
311
+ {{ end }}
312
+ access_log /var/log/nginx/access.log vhost;
313
+
314
+ {{ if eq $network_tag "internal" }}
315
+ # Only allow traffic from internal clients
316
+ include /etc/nginx/network_internal.conf;
317
+ {{ end }}
318
+
319
+ {{ if (exists (printf "/etc/nginx/vhost.d/%s" $host)) }}
320
+ include {{ printf "/etc/nginx/vhost.d/%s" $host }};
321
+ {{ else if (exists "/etc/nginx/vhost.d/default") }}
322
+ include /etc/nginx/vhost.d/default;
323
+ {{ end }}
324
+
325
+ root /var/www/public;
326
+ try_files $uri @application;
327
+
328
+ location @application {
329
+ {{ if eq $proto "uwsgi" }}
330
+ include uwsgi_params;
331
+ uwsgi_pass {{ trim $proto }}://{{ trim $upstream_name }};
332
+ {{ else if eq $proto "fastcgi" }}
333
+ root {{ trim $vhost_root }};
334
+ include fastcgi.conf;
335
+ fastcgi_pass {{ trim $upstream_name }};
336
+ {{ else }}
337
+ proxy_pass {{ trim $proto }}://{{ trim $upstream_name }};
338
+ {{ end }}
339
+
340
+ {{ if (exists (printf "/etc/nginx/vhost.d/%s_location" $host)) }}
341
+ include {{ printf "/etc/nginx/vhost.d/%s_location" $host}};
342
+ {{ else if (exists "/etc/nginx/vhost.d/default_location") }}
343
+ include /etc/nginx/vhost.d/default_location;
344
+ {{ end }}
345
+ }
346
+ }
347
+
348
+ {{ if (and (not $is_https) (exists "/etc/nginx/certs/default.crt") (exists "/etc/nginx/certs/default.key")) }}
349
+ server {
350
+ server_name {{ $host }};
351
+ listen 443 ssl http2 {{ $default_server }};
352
+ {{ if $enable_ipv6 }}
353
+ listen [::]:443 ssl http2 {{ $default_server }};
354
+ {{ end }}
355
+ access_log /var/log/nginx/access.log vhost;
356
+ return 500;
357
+
358
+ ssl_certificate /etc/nginx/certs/default.crt;
359
+ ssl_certificate_key /etc/nginx/certs/default.key;
360
+ }
361
+ {{ end }}
362
+
363
+ {{ end }}
364
+ {{ end }}
@@ -1,6 +1,6 @@
1
1
  listen '0.0.0.0:8080', :tcp_nopush => true
2
2
 
3
- pid '/application/tmp/pids/unicorn.pid'
3
+ pid '/app/tmp/pids/unicorn.pid'
4
4
 
5
5
  preload_app ENV.fetch('UNICORN_PRELOAD_APP', '1') == '1'
6
6
 
@@ -0,0 +1,22 @@
1
+ # https://stackoverflow.com/a/21189044 - thanks.
2
+ function parse_yaml {
3
+ local prefix=$2
4
+ local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
5
+ sed -ne "s|^\($s\):|\1|" \
6
+ -e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
7
+ -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" $1 |
8
+ awk -F$fs '{
9
+ indent = length($1)/2;
10
+ vname[indent] = $2;
11
+ for (i in vname) {if (i > indent) {delete vname[i]}}
12
+ if (length($3) > 0) {
13
+ vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
14
+ printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, $2, $3);
15
+ }
16
+ }'
17
+ }
18
+
19
+ eval $(parse_yaml ./.orchestration.yml)
20
+
21
+ set -u
22
+ echo -n "$(eval echo \$$1)"
@@ -8,7 +8,6 @@ module Orchestration
8
8
  ready: :green,
9
9
  create: :green,
10
10
  update: :yellow,
11
- identical: :blue,
12
11
  status: :blue,
13
12
  setup: :blue,
14
13
  input: :red,
@@ -21,13 +20,22 @@ module Orchestration
21
20
  STDOUT.print colorize(desc, output, color_name)
22
21
  end
23
22
 
24
- def read(message)
25
- write(:input, message + ' ', nil, false)
26
- STDIN.gets.chomp
23
+ def read(message, default = nil)
24
+ write(:input, prompt(message, default), nil, false)
25
+ result = STDIN.gets.chomp.strip
26
+ return default if result.empty?
27
+
28
+ result
27
29
  end
28
30
 
29
31
  private
30
32
 
33
+ def prompt(message, default)
34
+ return "(#{message}): " if default.nil?
35
+
36
+ "(#{message}) [#{I18n.t('orchestration.default')}: #{default}]: "
37
+ end
38
+
31
39
  def colorize(desc, message, color_name)
32
40
  color = if color_name.nil?
33
41
  COLOR_MAP.fetch(desc)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Orchestration
4
- VERSION = '0.2.8'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -42,5 +42,6 @@ Gem::Specification.new do |spec|
42
42
  spec.add_development_dependency 'rspec-its', '~> 1.2'
43
43
  spec.add_development_dependency 'rubocop', '~> 0.59.2'
44
44
  spec.add_development_dependency 'sqlite3', '~> 1.3'
45
+ spec.add_development_dependency 'strong_versions', '~> 0.3.1'
45
46
  spec.add_development_dependency 'webmock', '~> 3.4'
46
47
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: orchestration
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Farrell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-16 00:00:00.000000000 Z
11
+ date: 2018-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -248,6 +248,20 @@ dependencies:
248
248
  - - "~>"
249
249
  - !ruby/object:Gem::Version
250
250
  version: '1.3'
251
+ - !ruby/object:Gem::Dependency
252
+ name: strong_versions
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - "~>"
256
+ - !ruby/object:Gem::Version
257
+ version: 0.3.1
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - "~>"
263
+ - !ruby/object:Gem::Version
264
+ version: 0.3.1
251
265
  - !ruby/object:Gem::Dependency
252
266
  name: webmock
253
267
  requirement: !ruby/object:Gem::Requirement
@@ -270,12 +284,14 @@ executables:
270
284
  - rspec
271
285
  - rubocop
272
286
  - setup
287
+ - strong_versions
273
288
  extensions: []
274
289
  extra_rdoc_files: []
275
290
  files:
276
291
  - ".gitignore"
277
292
  - ".rspec"
278
293
  - ".rubocop.yml"
294
+ - ".strong_versions.yml"
279
295
  - ".travis.yml"
280
296
  - Gemfile
281
297
  - Makefile
@@ -286,6 +302,7 @@ files:
286
302
  - bin/rspec
287
303
  - bin/rubocop
288
304
  - bin/setup
305
+ - bin/strong_versions
289
306
  - config/locales/en.yml
290
307
  - lib/Rakefile
291
308
  - lib/orchestration.rb
@@ -331,7 +348,9 @@ files:
331
348
  - lib/orchestration/templates/Dockerfile.erb
332
349
  - lib/orchestration/templates/Makefile.erb
333
350
  - lib/orchestration/templates/entrypoint.sh.erb
351
+ - lib/orchestration/templates/nginx.tmpl.erb
334
352
  - lib/orchestration/templates/unicorn.rb.erb
353
+ - lib/orchestration/templates/yaml.bash.erb
335
354
  - lib/orchestration/terminal.rb
336
355
  - lib/orchestration/version.rb
337
356
  - lib/tasks/orchestration.rake