luban 0.11.6 → 0.12.1

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