luban 0.11.6 → 0.12.1

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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/lib/luban/deployment/cli/application/base.rb +3 -3
  4. data/lib/luban/deployment/cli/application/constructor.rb +1 -0
  5. data/lib/luban/deployment/cli/application/docker/dockerable.rb +46 -0
  6. data/lib/luban/deployment/cli/application/docker/dockerizer.rb +277 -0
  7. data/lib/luban/deployment/cli/application/docker/templates/Dockerfile.erb +33 -0
  8. data/lib/luban/deployment/cli/application/docker/templates/docker-compose-env.erb +1 -0
  9. data/lib/luban/deployment/cli/application/docker/templates/docker-compose.yml.erb +9 -0
  10. data/lib/luban/deployment/cli/application/docker.rb +2 -0
  11. data/lib/luban/deployment/cli/application/publisher.rb +4 -16
  12. data/lib/luban/deployment/cli/application/repository.rb +1 -1
  13. data/lib/luban/deployment/cli/application/worker.rb +6 -1
  14. data/lib/luban/deployment/cli/application.rb +1 -1
  15. data/lib/luban/deployment/cli/command.rb +2 -2
  16. data/lib/luban/deployment/cli/package/base.rb +1 -1
  17. data/lib/luban/deployment/cli/package/installer/install.rb +11 -9
  18. data/lib/luban/deployment/cli/package/worker.rb +17 -4
  19. data/lib/luban/deployment/configuration/core.rb +2 -5
  20. data/lib/luban/deployment/helpers/configuration.rb +2 -2
  21. data/lib/luban/deployment/parameters.rb +44 -2
  22. data/lib/luban/deployment/runner.rb +3 -2
  23. data/lib/luban/deployment/templates/application/config/deploy/__stage.rb.erb +2 -0
  24. data/lib/luban/deployment/templates/application/config/deploy.rb.erb +4 -0
  25. data/lib/luban/deployment/templates/crontab_header.erb +0 -1
  26. data/lib/luban/deployment/templates/header.erb +0 -1
  27. data/lib/luban/deployment/templates/project/.gitignore +1 -1
  28. data/lib/luban/deployment/templates/project/Lubanfile.rb.erb +2 -1
  29. data/lib/luban/deployment/version.rb +1 -1
  30. data/lib/luban/deployment/worker/paths.rb +12 -13
  31. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: db55acc88588f2c564a629a5a9f0e6eb00def437
4
- data.tar.gz: 81e4811583bf759f8f0bf8539fabe3191802b8fc
3
+ metadata.gz: 410b9b5e5e7b9fbc389290fa45951741ad84dcb5
4
+ data.tar.gz: a55967147d22fb2d87b00b60cde50f9ff8bdd563
5
5
  SHA512:
6
- metadata.gz: 69785dba1dc35b6b0f3f127d7b80386f734f6e24c775776c38ed8f4502900f7f961d62cf53f9f74e4dd508cce4347c598d9bfb364386f61990159c86e7a82dd5
7
- data.tar.gz: cc6266cea980f62d9d929d242891a9b283cd41da65226cdf03f0c7abd1ed6c653b3d1f74a1f637a8f7bf9d1eca56c9b69d42495c1c6ba89a542ae3da9c3cea80
6
+ metadata.gz: d75e1599d8dd7d377cf5c3385d0b9e75e32338c45aa9190548696933dcc2f59c99ac7951afc7c78f8c3227e2205ea98d185b20fb9fe1320cacd38926fcaae03a
7
+ data.tar.gz: 1bc91fc605e99ad1c5ab5fa4a91f84e4e5b9499990870679e65d8c59fd749bc409feff9ea15f9819573869155abef20b76d07e34299f8ab64a14b81fc13856e3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Change log
2
2
 
3
+ ## Version 0.12.1 (Feb 09, 2017)
4
+
5
+ Minor enhancements:
6
+ * Added build context in docker compose file template
7
+ * Used docker-compose to build application
8
+
9
+ ## Version 0.12.0 (Feb 08, 2017)
10
+
11
+ New features
12
+ * Supported Docker deployment
13
+ * Handled docker options for remote connectivity properly
14
+ * Docker options could be set per stage config as well as per app server
15
+
16
+ Minor enhancements:
17
+ * Refactored common paths into module Luban::Deployment::Package::Worker::Base
18
+ * Defined root paths for docker, releases, packages and deployment projects
19
+ * Restructured symlinks for vendor/cache and vendor/bundle
20
+ * Deprecated deployment release log
21
+ * Minor bug fixes and code cleanup
22
+
23
+ ## Version 0.11.6 (Feb 07, 2017)
24
+
25
+ Bug fixes:
26
+ * Corrected symlink creations for profiles when deploying releases
27
+
3
28
  ## Version 0.11.6 (Feb 07, 2017)
4
29
 
5
30
  Bug fixes:
@@ -163,8 +163,8 @@ module Luban
163
163
 
164
164
  def build(args:, opts:)
165
165
  show_app_environment
166
- install_all!(args: args, opts: opts)
167
166
  build_repositories(args: args, opts: opts)
167
+ install_all!(args: args, opts: opts)
168
168
  end
169
169
 
170
170
  def destroy(args:, opts:)
@@ -357,7 +357,7 @@ module Luban
357
357
  opts[:release][:tag] ||=
358
358
  release_tag(args: {}, opts: opts.merge(repository: source.merge(version: version)))
359
359
  end
360
- dispatch_task :release_tag, to: :repository, as: :release_tag, locally: true
360
+ dispatch_task :release_tag, to: :repository, locally: true
361
361
 
362
362
  def show_app_environment
363
363
  puts "#{display_name} in #{parent.class.name}"
@@ -421,7 +421,7 @@ module Luban
421
421
  dispatch_task :deploy_cronjobs!, to: :crontab, as: :deploy_cronjobs
422
422
 
423
423
  def print_summary(result)
424
- result.each do |entry|
424
+ Array(result).each do |entry|
425
425
  s = entry[:summary]
426
426
  puts " [#{entry[:hostname]}] #{s[:status]} #{s[:name]} (#{s[:published]})"
427
427
  puts " [#{entry[:hostname]}] #{s[:alert]}" unless s[:alert].nil?
@@ -41,6 +41,7 @@ module Luban
41
41
  assure_dirs(downloads_path, archived_logs_path,
42
42
  tmp_path, app_bin_path, app_tmp_path,
43
43
  releases_path, packages_path, shared_path)
44
+ assure_dirs(docker_path) if dockerized?
44
45
  end
45
46
 
46
47
  def create_envrc_files
@@ -0,0 +1,46 @@
1
+ module Luban
2
+ module Deployment
3
+ class Application
4
+ module Dockerable
5
+ def self.prepended(base)
6
+ base.dispatch_task :init_docker!, to: :dockerizer, as: :init_docker, locally: true
7
+ base.dispatch_task :dockerize_application!, to: :dockerizer, as: :dockerize_application, locally: true
8
+ base.dispatch_task :build_application!, to: :dockerizer, as: :build_application, locally: true
9
+ base.dispatch_task :distribute_application!, to: :dockerizer, as: :distribute_application
10
+ end
11
+
12
+ def deploy(args:, opts:)
13
+ super
14
+ dockerize_application!(args: args, opts: opts)[:build].tap do |build|
15
+ build_application!(args: args, opts: opts.merge(build: build))
16
+ distribute_application!(args: args, opts: opts.merge(build: build))
17
+ end
18
+ end
19
+
20
+ def init_profiles(args:, opts:)
21
+ super
22
+ init_docker!(args: args,
23
+ opts: opts.merge(default_docker_templates_path: default_docker_templates_path,
24
+ docker_templates_path: config_finder[:application].templates_path))
25
+ end
26
+
27
+ def default_docker_templates_path
28
+ @default_docker_template_path ||= base_templates_path(__FILE__)
29
+ end
30
+
31
+ protected
32
+
33
+ %i(setup! install_all! uninstall_all! destroy!
34
+ binstubs! which! whence!
35
+ cleanup_packages! cleanup_application!
36
+ show_current_packages! show_summary_packages! get_summary
37
+ publish_release! deprecate_published_release!
38
+ deploy_profile!).each do |action|
39
+ define_method("#{action}") do |args:, opts:|
40
+ super(args: args, opts: opts.merge(locally: true))
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,277 @@
1
+ module Luban
2
+ module Deployment
3
+ class Application
4
+ class Dockerizer < Worker
5
+ attr_reader :build
6
+
7
+ DefaultRevisionSize = 12
8
+
9
+ def docker_templates_path
10
+ task.opts.docker_templates_path
11
+ end
12
+
13
+ def default_docker_templates_path
14
+ task.opts.default_docker_templates_path
15
+ end
16
+
17
+ def default_docker_tcp_port; docker_tls_verify? ? "2376" : "2375"; end
18
+
19
+ def docker_tls_verify?;
20
+ host[:docker_tls_verify].nil? ? docker_tls_verify : host[:docker_tls_verify]
21
+ end
22
+
23
+ def docker_ca_cert_path; docker_cert_path.join("ca.pem"); end
24
+ def docker_client_cert_path; docker_cert_path.join("cert.pem"); end
25
+ def tls_key_path; docker_cert_path.join("key.pem"); end
26
+
27
+ def tls_options
28
+ ["--tlsverify", "--tlscacert #{docker_ca_cert_path}",
29
+ "--tlscert #{docker_client_cert_path}", "--tlskey #{tls_key_path}"]
30
+ end
31
+
32
+ def docker_host
33
+ unix_socket = host[:docker_unix_socket] || docker_unix_socket
34
+ if unix_socket.nil?
35
+ tcp_port = host[:docker_tcp_port] || docker_tcp_port || default_docker_tcp_port
36
+ "tcp://#{hostname}:#{tcp_port}"
37
+ else
38
+ "unix://#{unix_socket}"
39
+ end
40
+ end
41
+
42
+ def docker_options
43
+ @docker_options ||= ["-H #{docker_host}"].concat(docker_tls_verify? ? tls_options : [])
44
+ end
45
+
46
+ def revision_size
47
+ task.opts.revision_size || DefaultRevisionSize
48
+ end
49
+
50
+ def init_docker
51
+ puts " Initializing #{application_name} docker profile"
52
+ docker_templates.each do |path|
53
+ print " - #{path}"
54
+ src_path = default_docker_templates_path.join(path)
55
+ dst_path = docker_templates_path.join(path)
56
+ if file?(dst_path)
57
+ puts " [skipped]"
58
+ else
59
+ upload!(src_path, dst_path)
60
+ puts " [created]"
61
+ end
62
+ end
63
+ end
64
+
65
+ def dockerize_application
66
+ rmdir(build[:path]) if force?
67
+ dockerize_application!
68
+ case build[:status]
69
+ when :succeeded
70
+ update_result "Successfully dockerized #{build[:image_tag]}."
71
+ when :skipped
72
+ update_result "Skipped! ALREADY dockerized #{build[:image_tag]}.", status: :skipped
73
+ else
74
+ update_result "FAILED to dockerize #{build[:image_tag]}.", status: :failed, level: :error
75
+ end
76
+ update_result build: build
77
+ end
78
+
79
+ def get_image_id(docker_options = [])
80
+ capture(:docker, docker_options.join(' '), :images, "-q", build[:image_tag])
81
+ end
82
+
83
+ def built?
84
+ !(build[:image_id] = get_image_id).empty?
85
+ end
86
+
87
+ def build_application
88
+ if built?
89
+ update_result "Skipped! ALREADY built #{build[:image_tag]}.", status: :skipped
90
+ return
91
+ end
92
+ output = compose_application!
93
+
94
+ if built?
95
+ update_result "Successfully built #{build[:image_tag]}."
96
+ else
97
+ update_result "FAILED to build #{build[:image_tag]}: #{output}.",
98
+ status: :failed, level: :error
99
+ end
100
+ end
101
+
102
+ def distributed?
103
+ build[:image_id] == get_image_id(docker_options)
104
+ end
105
+
106
+ def distribute_application
107
+ if distributed?
108
+ update_result "Skipped! ALREADY distributed #{build[:image_tag]}.", status: :skipped
109
+ return
110
+ end
111
+ output = distribute_application!
112
+
113
+ if distributed?
114
+ update_result "Successfully distributed #{build[:image_tag]}."
115
+ else
116
+ update_result "FAILED to distribute #{build[:image_tag]}: #{output}",
117
+ status: :failed, level: :error
118
+ end
119
+ end
120
+
121
+ protected
122
+
123
+ def init
124
+ super
125
+ @build = task.opts.build || init_build
126
+ end
127
+
128
+ def init_build
129
+ (@build = {}).tap do |b|
130
+ b[:path] = build_path
131
+ b[:context] = context_path
132
+ b[:dockerfile] = dockerfile
133
+ b[:compose_file] = compose_file
134
+ b[:compose_env_file] = compose_env_file
135
+ b[:sources] = init_build_sources
136
+ b[:archives] = init_build_archives
137
+ b[:revision] = compose_revision
138
+ b[:image_tag] = image_tag(b[:revision])
139
+ end
140
+ end
141
+
142
+ def init_build_sources
143
+ sources = { packages: packages_path }
144
+ releases = get_releases(releases_path)
145
+ if (v = releases.delete(:vendor))
146
+ sources[:vendor] = v
147
+ end
148
+ sources.merge!(releases)
149
+ profile_path = releases_path.dirname.join('profile')
150
+ profile = directory?(profile_path) ? get_releases(profile_path) : {}
151
+ sources[stage.to_sym] = app_path
152
+ sources.merge!(profile)
153
+ sources.inject({}) do |srcs, (name, path)|
154
+ md5 = md5_for_dir(path)
155
+ srcs[name] = { path: path, md5: md5, tag: md5[0, revision_size] }
156
+ srcs
157
+ end
158
+ end
159
+
160
+ def compose_revision
161
+ require 'digest/md5'
162
+ build[:sources].inject(revisions = '') { |r, (_, src)| r += src[:md5] }
163
+ Digest::MD5.hexdigest(revisions)[0, revision_size]
164
+ end
165
+
166
+ def init_build_archives
167
+ build[:sources].each_key.inject(build[:archives] = {}) do |archives, name|
168
+ archives[name] = { path: archive_file_path("#{name}-#{build[:sources][name][:tag]}") }
169
+ archives
170
+ end
171
+ end
172
+
173
+ def archive_file_name(name)
174
+ "#{project}-#{application}-#{name}.#{archive_file_extname}"
175
+ end
176
+
177
+ def archive_file_extname; "tar.xz"; end
178
+
179
+ def archive_file_path(name)
180
+ build[:context].join(archive_file_name(name))
181
+ end
182
+
183
+ def build_path; docker_path.join("build-#{stage}-#{build_tag}"); end
184
+ def context_path; build_path.join('context'); end
185
+ def image_tag(revision); "#{project}-#{application}-#{stage}:#{build_tag}-#{revision}"; end
186
+ def dockerfile; build[:context].join("Dockerfile"); end
187
+ def compose_file; build[:path].join("docker-compose.yml"); end
188
+ def compose_env_file; build[:path].join(".env"); end
189
+
190
+ def get_releases(path)
191
+ capture(:ls, '-xtd', path.join('*')).split.
192
+ collect { |p| File.basename(p) }.
193
+ inject({}) { |r, t| r[t.to_sym] = path.join(t); r }
194
+ end
195
+
196
+ def dockerize_application!
197
+ assure_dirs(build[:context])
198
+ package_application!
199
+ render_dockerfile
200
+ render_compose_env_file
201
+ render_compose_file
202
+ build[:status] = status
203
+ end
204
+
205
+ def package_application!
206
+ build[:archives].each_pair do |name, archive|
207
+ source = build[:sources][name]
208
+ archive[:status] =
209
+ if file?(archive[:path]) and archive[:path].basename.to_s =~ /#{source[:tag]}/
210
+ :skipped
211
+ else
212
+ execute(:tar, "-cJf", archive[:path], source[:path]) ? :succeeded : :failed
213
+ end
214
+ end
215
+ end
216
+
217
+ def render_dockerfile
218
+ upload_by_template(file_to_upload: build[:dockerfile],
219
+ template_file: find_template_file('Dockerfile.erb'),
220
+ auto_revision: true)
221
+ end
222
+
223
+ def render_compose_env_file
224
+ upload_by_template(file_to_upload: build[:compose_env_file],
225
+ template_file: find_template_file('docker-compose-env.erb'),
226
+ auto_revision: true)
227
+ end
228
+
229
+ def render_compose_file
230
+ upload_by_template(file_to_upload: build[:compose_file],
231
+ template_file: find_template_file('docker-compose.yml.erb'),
232
+ auto_revision: true)
233
+ end
234
+
235
+ def status
236
+ build[:archives].each_value.inject(:skipped) do |status, archive|
237
+ if archive[:status] == :failed
238
+ status = :failed; break
239
+ end
240
+ if archive[:status] == :succeeded
241
+ status = :succeeded
242
+ end
243
+ status
244
+ end
245
+ end
246
+
247
+ def build_application!
248
+ within build[:context] do
249
+ capture(:docker, :build, "-t", build[:image_tag], ".", "2>&1")
250
+ end
251
+ end
252
+
253
+ def compose_application!
254
+ within build[:path] { capture(:"docker-compose", :build, "2>&1") }
255
+ end
256
+
257
+ def distribute_application!
258
+ capture(:docker, :save, build[:image_tag], "|",
259
+ :docker, docker_options.join(' '), "load", "2>&1")
260
+ end
261
+
262
+ def remove_image!(docker_options = [], image_id)
263
+ execute(:docker, docker_options.join(' '), :rmi, image_id, "2>/dev/null")
264
+ end
265
+
266
+ def docker_templates(format: "erb")
267
+ @docker_templates ||=
268
+ if default_docker_templates_path.directory?
269
+ Dir.chdir(default_docker_templates_path) { Dir["**/*.#{format}"] }
270
+ else
271
+ []
272
+ end
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,33 @@
1
+ FROM <%= base_image %>
2
+ MAINTAINER <%= author['name'] %> <%= author['email'].inspect %>
3
+
4
+ RUN adduser -ms /bin/bash <%= luban_user %> && \
5
+ mkdir <%= luban_root_path %> && \
6
+ chown -R <%= luban_user %>:<%= luban_user %> <%= luban_root_path %>
7
+
8
+ <% build[:archives].each_value do |archive| -%>
9
+ ADD <%= archive[:path].basename %> /
10
+ <% end -%>
11
+
12
+ RUN ln -sf /usr/share/zoneinfo/<%= timezone %> /etc/localtime && \
13
+ echo "source <%= envrc_file %>" >> /home/<%= luban_user %>/.bashrc
14
+
15
+ <% build[:archives].each_value do |archive| -%>
16
+ ADD <%= archive[:path].basename %> /
17
+ <% end -%>
18
+
19
+ LABEL luban.project="<%= project %>" \
20
+ luban.application="<%= project %>" \
21
+ luban.stage="<%= stage %>" \
22
+ <%- build[:sources].each_pair do |name, source| -%>
23
+ luban.<%= name %>_tag="<%= source[:tag] %>" \
24
+ <%- end -%>
25
+ luban.build_tag="<%= build_tag %>" \
26
+ luban.bulid_rev="<%= build[:revision] %>"
27
+ luban.luban_user="<%= luban_user %>" \
28
+ luban.luban_root_path="<%= luban_root_path %>"
29
+
30
+ USER <%= luban_user %>
31
+ WORKDIR /home/<%= luban_user %>
32
+
33
+ CMD ["/bin/bash"]
@@ -0,0 +1 @@
1
+ COMPOSE_PROJECT_NAME="<%= project %>"
@@ -0,0 +1,9 @@
1
+ version: "3"
2
+
3
+ services:
4
+ <%= application %>:
5
+ build: ./context
6
+ image: <%= build[:image_tag] %>
7
+ entrypoint: /bin/bash
8
+ stdin_open: true
9
+ tty: true
@@ -0,0 +1,2 @@
1
+ require_relative 'docker/dockerable'
2
+ require_relative 'docker/dockerizer'
@@ -25,20 +25,16 @@ module Luban
25
25
  @releases_path ||= super.dirname.join(release_type)
26
26
  end
27
27
 
28
- def releases_log_path
29
- @releases_log_path ||= app_path.join('releases.log')
30
- end
31
-
32
28
  def bundle_config_path
33
- @bundle_config_path ||= shared_path.join('.bundle')
29
+ @bundle_config_path ||= releases_path.join('.bundle')
34
30
  end
35
31
 
36
32
  def bundle_path
37
- @bundle_path ||= shared_path.join('vendor', 'bundle')
33
+ @bundle_path ||= releases_path.join('vendor', 'bundle')
38
34
  end
39
35
 
40
36
  def gems_cache_path
41
- @gems_cache_path ||= shared_path.join('vendor', 'cache')
37
+ @gems_cache_path ||= releases_path.join('vendor', 'cache')
42
38
  end
43
39
 
44
40
  def bundle_without
@@ -102,7 +98,6 @@ module Luban
102
98
  test(:tar, "-xzf #{upload_to} -C #{releases_path}")
103
99
  touch(release_path)
104
100
  create_symlinks
105
- update_releases_log
106
101
  else
107
102
  rmdir(release_path)
108
103
  end
@@ -113,6 +108,7 @@ module Luban
113
108
  def create_symlinks
114
109
  send("create_#{release_type}_symlinks")
115
110
  if has_gemfile?
111
+ create_linked_dirs(bundle_linked_dirs, from: releases_path, to: shared_path)
116
112
  create_linked_dirs(bundle_linked_dirs, to: release_path)
117
113
  end
118
114
  end
@@ -141,14 +137,6 @@ module Luban
141
137
  create_linked_files(to: release_path)
142
138
  end
143
139
 
144
- def update_releases_log
145
- execute %{echo "[$(date -u)][#{user}] #{release_log_message}" >> #{releases_log_path}}
146
- end
147
-
148
- def release_log_message
149
- "#{release_name} in #{stage} #{project} is published successfully."
150
- end
151
-
152
140
  def cleanup_releases(keep_releases = 1)
153
141
  files = capture(:ls, '-xtd', releases_path.join("#{release_version}-*")).split(" ")
154
142
  if files.count > keep_releases
@@ -214,7 +214,7 @@ module Luban
214
214
  md5_file = gems_path.join("#{gem_file}.md5")
215
215
  gems[gem_name] =
216
216
  if file?(md5_file)
217
- gems[gem_name] = capture(:cat, md5_file)
217
+ capture(:cat, md5_file)
218
218
  else
219
219
  md5_for(gem_file).tap { |md5| execute(:echo, "#{md5} > #{md5_file}") }
220
220
  end
@@ -4,6 +4,7 @@ module Luban
4
4
  class Worker < Luban::Deployment::Worker::Base
5
5
  include Luban::Deployment::Worker::Paths::Remote
6
6
  include Luban::Deployment::Service::Worker::Base
7
+ include Luban::Deployment::Package::Worker::Base
7
8
 
8
9
  def gemfile
9
10
  @gemfile ||= release_path.join('Gemfile')
@@ -19,12 +20,16 @@ module Luban
19
20
  define_method("application_#{method}") { send("target_#{method}") }
20
21
  end
21
22
 
23
+ def docker_path
24
+ @docker_path ||= docker_root_path.join(project, application)
25
+ end
26
+
22
27
  def profile_name; 'app'; end
23
28
 
24
29
  def release_tag; task.opts.release[:tag]; end
25
30
 
26
31
  def releases_path
27
- @releases_path ||= super.join(project, application, 'app')
32
+ @releases_path ||= releases_root_path.join(project, application, 'app')
28
33
  end
29
34
 
30
35
  def release_path
@@ -7,4 +7,4 @@ require_relative 'application/publisher'
7
7
  require_relative 'application/configurator'
8
8
  require_relative 'application/controller'
9
9
  require_relative 'application/crontab'
10
-
10
+ require_relative 'application/docker'
@@ -291,7 +291,7 @@ module Luban
291
291
 
292
292
  def dispatch_task(task, to:, as: task, locally: false, &blk)
293
293
  define_method(task) do |args:, opts:|
294
- run_task(cmd: as, args: args, opts: opts, locally: locally,
294
+ run_task(cmd: as, args: args, opts: opts, locally: locally || opts[:locally],
295
295
  worker_class: self.class.worker_class(to), &blk)
296
296
  end
297
297
 
@@ -356,7 +356,7 @@ module Luban
356
356
 
357
357
  def set_parameters
358
358
  copy_parameters_from_parent(
359
- :luban_roles, :luban_root_path, :work_dir, :apps_path,
359
+ :luban_roles, :luban_root_path, :work_dir, :apps_path, :author,
360
360
  :stages, :applications, :user, :skip_promptless_authen
361
361
  )
362
362
  end
@@ -268,7 +268,7 @@ module Luban
268
268
  end
269
269
 
270
270
  def print_summary(result)
271
- result.each do |entry|
271
+ Array(result).each do |entry|
272
272
  s = entry[:summary]
273
273
  puts " [#{entry[:hostname]}] #{s[:status]} #{s[:name]} (#{s[:installed]})"
274
274
  puts " [#{entry[:hostname]}] #{s[:executable]}" unless s[:executable].nil?
@@ -157,19 +157,21 @@ module Luban
157
157
  end
158
158
 
159
159
  def which_current
160
- get_summary
161
- task.result.summary[:executable] = "Not found"
162
- if current? and current_symlinked? and
163
- file?(executable = File.join(readlink(current_path), 'bin', task.args.executable))
164
- task.result.summary[:executable] = executable
160
+ get_summary.tap do |result|
161
+ result.summary[:executable] = "Not found"
162
+ if current? and current_symlinked? and
163
+ file?(executable = File.join(readlink(current_path), 'bin', task.args.executable))
164
+ result.summary[:executable] = executable
165
+ end
165
166
  end
166
167
  end
167
168
 
168
169
  def whence_origin
169
- get_summary
170
- task.result.summary[:executable] = "Not found"
171
- if file?(executable = bin_path.join(task.args.executable))
172
- task.result.summary[:executable] = executable
170
+ get_summary.tap do |result|
171
+ result.summary[:executable] = "Not found"
172
+ if file?(executable = bin_path.join(task.args.executable))
173
+ result.summary[:executable] = executable
174
+ end
173
175
  end
174
176
  end
175
177
 
@@ -4,6 +4,23 @@ module Luban
4
4
  class Worker < Luban::Deployment::Worker::Base
5
5
  include Luban::Deployment::Worker::Paths::Remote
6
6
 
7
+ module Base
8
+ def packages_path
9
+ @packages_path ||= packages_root_path.join(project, application)
10
+ end
11
+
12
+ def package_install_path(package_name)
13
+ packages_path.join(package_name.to_s, 'versions',
14
+ packages[package_name.to_sym].current_version)
15
+ end
16
+
17
+ def package_bin_path(package_name)
18
+ package_install_path(package_name).join('bin')
19
+ end
20
+ end
21
+
22
+ include Base
23
+
7
24
  class << self
8
25
  def package_class(package)
9
26
  Luban::Deployment::Package::Base.package_class(package)
@@ -41,10 +58,6 @@ module Luban
41
58
  @current_bin_path ||= current_path.join('bin')
42
59
  end
43
60
 
44
- def packages_path
45
- @packages_path ||= super.join(project, application)
46
- end
47
-
48
61
  def package_path
49
62
  @package_path ||= packages_path.join(package_name)
50
63
  end
@@ -45,14 +45,11 @@ module Luban
45
45
  if name == :all
46
46
  raise ArgumentError, 'Reserved role name, :all, is NOT allowed to use.'
47
47
  end
48
- @servers.add_hosts_for_role(name, hosts, properties)
48
+ servers.add_hosts_for_role(name, hosts, properties)
49
49
  end
50
50
 
51
51
  def server(name, **properties)
52
- new_server = servers.add_host(name, properties)
53
- if new_server
54
- new_server.ssh_options = fetch(:ssh_options) || {}
55
- end
52
+ servers.add_host(name, properties)
56
53
  end
57
54
 
58
55
  def ask(key=nil, default:, prompt: nil, echo: true)
@@ -25,11 +25,11 @@ module Luban
25
25
  end
26
26
 
27
27
  def role(name, hosts, **properties)
28
- config.role(name, hosts, properties)
28
+ config.role(name, hosts, properties.merge(local: dockerized?))
29
29
  end
30
30
 
31
31
  def server(name, **properties)
32
- config.server(name, properties)
32
+ config.server(name, properties.merge(local: dockerized?))
33
33
  end
34
34
 
35
35
  def roles(*names)
@@ -26,6 +26,10 @@ module Luban
26
26
  mod.extend(Base)
27
27
  end
28
28
 
29
+ def current_user
30
+ ENV['USER'] || `whoami`.chomp
31
+ end
32
+
29
33
  parameter :luban_roles, default: %i(app)
30
34
  parameter :luban_root_path, default: DefaultLubanRootPath
31
35
 
@@ -36,7 +40,8 @@ module Luban
36
40
  parameter :work_dir
37
41
  parameter :apps_path
38
42
  parameter :project
39
- parameter :user, default: ENV['USER']
43
+ parameter :user, default: -> { current_user }
44
+ parameter :author
40
45
  parameter :config_finder, default: ->{ Hash.new }
41
46
 
42
47
  parameter :skip_promptless_authen, default: false
@@ -44,7 +49,10 @@ module Luban
44
49
  protected
45
50
 
46
51
  def validate_for_user
47
- if user != ENV['USER']
52
+ if user.nil?
53
+ abort "Abort! Please specify the user name: user 'user name'"
54
+ end
55
+ if user != current_user
48
56
  abort "Aborted! Given deployment user (#{user.inspect}) is NOT the current user #{ENV['USER'].inspect}" +
49
57
  "Please switch to the deployment user before any deployments."
50
58
  end
@@ -107,8 +115,32 @@ module Luban
107
115
  end
108
116
  end
109
117
 
118
+ module Docker
119
+ extend Base
120
+
121
+ parameter :luban_user, default: 'luban'
122
+ parameter :build_tag, default: '0.0.0'
123
+ parameter :base_image, default: 'centos:7'
124
+ parameter :timezone, default: 'UTC'
125
+ parameter :docker_tls_verify, default: false
126
+ parameter :docker_cert_path
127
+ parameter :docker_tcp_port
128
+ parameter :docker_unix_socket
129
+
130
+ def validate_for_docker_cert_path
131
+ return if !docker_tls_verify and docker_cert_path.nil?
132
+ if docker_cert_path.is_a?(String)
133
+ docker_cert_path Pathname.new(docker_cert_path)
134
+ end
135
+ unless docker_cert_path.is_a?(Pathname)
136
+ abort "Aborted! Docker cert path should be a String or a Pathname: docker_cert_path 'path to docker certs'"
137
+ end
138
+ end
139
+ end
140
+
110
141
  module Application
111
142
  extend Base
143
+ include Docker
112
144
 
113
145
  DefaultLogrotateMaxAge = 7 # days
114
146
  DefaultLogrotateInterval = 10 # mins
@@ -123,6 +155,16 @@ module Luban
123
155
  @env_name ||= "#{stage}.#{project}/#{application}"
124
156
  end
125
157
 
158
+ def dockerize
159
+ unless dockerized?
160
+ singleton_class.send(:prepend, Luban::Deployment::Application::Dockerable)
161
+ set :dockerized, true
162
+ skip_promptless_authen true
163
+ end
164
+ end
165
+
166
+ def dockerized?; fetch :dockerized; end
167
+
126
168
  def monitor_itself?
127
169
  env_name == process_monitor[:env]
128
170
  end
@@ -10,7 +10,8 @@ module Luban
10
10
  def default_rc
11
11
  @default_rc ||= { 'luban_roles' => %i(app),
12
12
  'luban_root_path' => Parameters::General::DefaultLubanRootPath,
13
- 'stages' => %w(development staging production)
13
+ 'stages' => %w(development staging production),
14
+ 'author' => { 'name' => 'author name', 'email' => 'author@email.com' }
14
15
  }
15
16
  end
16
17
 
@@ -46,7 +47,7 @@ module Luban
46
47
  end
47
48
 
48
49
  def set_default_common_parameters
49
- %i(luban_roles luban_root_path stages).each { |p| set_default p, rc[p.to_s] }
50
+ %i(luban_roles luban_root_path stages author).each { |p| set_default p, rc[p.to_s] }
50
51
  set_default :user, (rc['user'] || ENV['USER'])
51
52
  end
52
53
 
@@ -1,4 +1,6 @@
1
1
  # Deployment configuration for <%= stage %> application <%= application_class_name %>
2
2
 
3
+ # build_tag '0.0.0'
4
+
3
5
  # Application servers
4
6
  role :app, `hostname -f`.chomp
@@ -1 +1,5 @@
1
1
  # Deployment configuration for application <%= application_class_name %>
2
+
3
+ # Turn on docker support
4
+ # dockerize
5
+ # timezone 'Asia/Shanghai'
@@ -1,3 +1,2 @@
1
1
  <%= crontab_open %>
2
2
  # Revision: <%= revision %>
3
- # Created at <%= now %>
@@ -1,4 +1,3 @@
1
1
  # Environment: <%= env_name %>
2
2
  # Revision: <%= revision %>
3
- # Created at <%= now %>
4
3
 
@@ -1,7 +1,7 @@
1
1
  /.bundle/
2
- /Gemfile.lock
3
2
  .luban/
4
3
  vendor/cache/
4
+ vendor/bundle/
5
5
  env_vars.rb
6
6
  .DS_Store
7
7
  .gitkeep
@@ -1,2 +1,3 @@
1
1
  stages %w(<%= stages.join(' ') %>)
2
- project <%= project.inspect %>
2
+ project <%= project.inspect %>
3
+ author name: <%= author['name'] %>, email: <%= author['email'] %>
@@ -1,5 +1,5 @@
1
1
  module Luban
2
2
  module Deployment
3
- VERSION = "0.11.6"
3
+ VERSION = "0.12.1"
4
4
  end
5
5
  end
@@ -17,8 +17,12 @@ module Luban
17
17
  end
18
18
 
19
19
  module Remote
20
- def releases_path
21
- @releases_path ||= luban_root_path.join('releases')
20
+ def deployment_projects_path
21
+ @deployment_projects_path ||= luban_root_path.join('projects')
22
+ end
23
+
24
+ def releases_root_path
25
+ @releases_root_path ||= luban_root_path.join('releases')
22
26
  end
23
27
 
24
28
  def env_path
@@ -38,6 +42,10 @@ module Luban
38
42
  @downloads_path ||= luban_root_path.join('downloads')
39
43
  end
40
44
 
45
+ def docker_root_path
46
+ @docker_root_path ||= luban_root_path.join('docker')
47
+ end
48
+
41
49
  def project_path
42
50
  @project_path ||= env_path.join("#{stage}.#{project}")
43
51
  end
@@ -70,17 +78,8 @@ module Luban
70
78
  @unset_envrc_file ||= app_path.join(".unset_envrc")
71
79
  end
72
80
 
73
- def packages_path
74
- @packages_path ||= luban_root_path.join('packages')
75
- end
76
-
77
- def package_install_path(package_name)
78
- packages_path.join(project, application, package_name.to_s, 'versions',
79
- packages[package_name.to_sym].current_version)
80
- end
81
-
82
- def package_bin_path(package_name)
83
- package_install_path(package_name).join('bin')
81
+ def packages_root_path
82
+ @packages_root_path ||= luban_root_path.join('packages')
84
83
  end
85
84
 
86
85
  def app_archives_path
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: luban
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.6
4
+ version: 0.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rubyist Lei
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-07 00:00:00.000000000 Z
11
+ date: 2017-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: luban-cli
@@ -107,6 +107,12 @@ files:
107
107
  - lib/luban/deployment/cli/application/constructor.rb
108
108
  - lib/luban/deployment/cli/application/controller.rb
109
109
  - lib/luban/deployment/cli/application/crontab.rb
110
+ - lib/luban/deployment/cli/application/docker.rb
111
+ - lib/luban/deployment/cli/application/docker/dockerable.rb
112
+ - lib/luban/deployment/cli/application/docker/dockerizer.rb
113
+ - lib/luban/deployment/cli/application/docker/templates/Dockerfile.erb
114
+ - lib/luban/deployment/cli/application/docker/templates/docker-compose-env.erb
115
+ - lib/luban/deployment/cli/application/docker/templates/docker-compose.yml.erb
110
116
  - lib/luban/deployment/cli/application/publisher.rb
111
117
  - lib/luban/deployment/cli/application/repository.rb
112
118
  - lib/luban/deployment/cli/application/scm/git.rb