luban 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +37 -0
  6. data/Rakefile +1 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +7 -0
  9. data/exe/luban +3 -0
  10. data/lib/luban/deployment/cli/application/authenticator.rb +106 -0
  11. data/lib/luban/deployment/cli/application/base.rb +179 -0
  12. data/lib/luban/deployment/cli/application/builder.rb +67 -0
  13. data/lib/luban/deployment/cli/application/publisher.rb +215 -0
  14. data/lib/luban/deployment/cli/application/repository.rb +175 -0
  15. data/lib/luban/deployment/cli/application/scm/git.rb +49 -0
  16. data/lib/luban/deployment/cli/application/scm/rsync.rb +47 -0
  17. data/lib/luban/deployment/cli/application.rb +5 -0
  18. data/lib/luban/deployment/cli/command.rb +360 -0
  19. data/lib/luban/deployment/cli/package/binary.rb +241 -0
  20. data/lib/luban/deployment/cli/package/dependency.rb +49 -0
  21. data/lib/luban/deployment/cli/package/dependency_set.rb +71 -0
  22. data/lib/luban/deployment/cli/package/installer/core.rb +98 -0
  23. data/lib/luban/deployment/cli/package/installer/install.rb +330 -0
  24. data/lib/luban/deployment/cli/package/installer/paths.rb +81 -0
  25. data/lib/luban/deployment/cli/package/installer.rb +3 -0
  26. data/lib/luban/deployment/cli/package/service.rb +17 -0
  27. data/lib/luban/deployment/cli/package/worker.rb +43 -0
  28. data/lib/luban/deployment/cli/package.rb +6 -0
  29. data/lib/luban/deployment/cli/project.rb +94 -0
  30. data/lib/luban/deployment/cli.rb +4 -0
  31. data/lib/luban/deployment/configuration/core.rb +67 -0
  32. data/lib/luban/deployment/configuration/filter.rb +54 -0
  33. data/lib/luban/deployment/configuration/question.rb +38 -0
  34. data/lib/luban/deployment/configuration/server.rb +70 -0
  35. data/lib/luban/deployment/configuration/server_set.rb +86 -0
  36. data/lib/luban/deployment/configuration.rb +5 -0
  37. data/lib/luban/deployment/error.rb +5 -0
  38. data/lib/luban/deployment/helpers/configuration.rb +159 -0
  39. data/lib/luban/deployment/helpers/utils.rb +180 -0
  40. data/lib/luban/deployment/helpers.rb +2 -0
  41. data/lib/luban/deployment/packages/bundler.rb +81 -0
  42. data/lib/luban/deployment/packages/git.rb +37 -0
  43. data/lib/luban/deployment/packages/openssl.rb +59 -0
  44. data/lib/luban/deployment/packages/ruby.rb +125 -0
  45. data/lib/luban/deployment/packages/rubygems.rb +89 -0
  46. data/lib/luban/deployment/packages/yaml.rb +33 -0
  47. data/lib/luban/deployment/parameters.rb +160 -0
  48. data/lib/luban/deployment/runner.rb +99 -0
  49. data/lib/luban/deployment/templates/envrc.erb +30 -0
  50. data/lib/luban/deployment/templates/unset_envrc.erb +28 -0
  51. data/lib/luban/deployment/version.rb +5 -0
  52. data/lib/luban/deployment/worker/base.rb +71 -0
  53. data/lib/luban/deployment/worker/controller.rb +11 -0
  54. data/lib/luban/deployment/worker/local.rb +19 -0
  55. data/lib/luban/deployment/worker/remote.rb +55 -0
  56. data/lib/luban/deployment/worker/task.rb +25 -0
  57. data/lib/luban/deployment/worker.rb +4 -0
  58. data/lib/luban/deployment.rb +8 -0
  59. data/lib/luban.rb +4 -0
  60. data/luban.gemspec +29 -0
  61. metadata +174 -0
@@ -0,0 +1,330 @@
1
+ module Luban
2
+ module Deployment
3
+ module Package
4
+ class Installer
5
+ class InstallFailure < Luban::Deployment::Error; end
6
+
7
+ def required_packages
8
+ @required_packages ||=
9
+ self.class.package_class(package_name).
10
+ required_packages_for(package_major_version)
11
+ end
12
+
13
+ def configure_executable
14
+ @configure_executable ||= './configure'
15
+ end
16
+
17
+ def installed?
18
+ raise NotImplementedError, "#{self.class.name}#installed? is an abstract method."
19
+ end
20
+
21
+ def validate_download_url
22
+ info "Validating download URL for #{package_full_name}"
23
+ validate_download_url!
24
+ end
25
+
26
+ def install
27
+ info "Installing #{package_full_name}"
28
+ if installed?
29
+ if force?
30
+ install!
31
+ else
32
+ update_result "Skipped! #{package_full_name} has been installed ALREADY.",
33
+ status: :skipped
34
+ return
35
+ end
36
+ else
37
+ install!
38
+ end
39
+
40
+ if installed?
41
+ update_result "Successfully installed #{package_full_name}."
42
+ else
43
+ update_result "Failed to install #{package_full_name}. " +
44
+ "Please check install log for details: #{install_log_file_path}",
45
+ status: :failed, level: :error
46
+ end
47
+ end
48
+
49
+ def uninstall
50
+ info "Uninstalling #{package_full_name}"
51
+ if installed?
52
+ if current? and !force?
53
+ update_result "Skippped! #{package_full_name} is the current version in use. " +
54
+ "Please switch to other version before uninstalling this version or " +
55
+ "use -f to force uninstalling.",
56
+ status: :skipped, level: :warn
57
+ else
58
+ uninstall!
59
+ update_result "#{package_full_name} is uninstalled. "
60
+ end
61
+ else
62
+ message = "#{package_full_name} is NOT installed.",
63
+ if directory?(install_path) or directory?(build_path)
64
+ if force?
65
+ uninstall!
66
+ update_result message +
67
+ "Cleaned up leftover of #{package_full_name} from last installation."
68
+ else
69
+ update_result message +
70
+ "But leftover from last installation is found. " +
71
+ "Use -f to force clean it up."
72
+ end
73
+ else
74
+ update_result "Skipped! #{message}"
75
+ end
76
+ end
77
+ end
78
+
79
+ def cleanup_all
80
+ cleanup_temp!
81
+ cleanup_logs!
82
+ update_result "Cleaned up temporary files in #{package_full_name} installation"
83
+ end
84
+
85
+ def get_summary
86
+ status = if current_symlinked?
87
+ current? ? " *" : "s*"
88
+ else
89
+ current? ? "c*" : " "
90
+ end
91
+
92
+ if installed?
93
+ installed = '(installed)'
94
+ alert = case status
95
+ when "s*"
96
+ "Alert! #{package_full_name} is not the current version but symlinked IMPROPERLY. " +
97
+ "Run \"binstubs\" to fix it."
98
+ when "c*"
99
+ "Alert! #{package_full_name} is set as current version but NOT symlinked properly. " +
100
+ "Run \"binstubs\" to fix it."
101
+ end
102
+ else
103
+ installed = '(NOT installed)'
104
+ alert = nil
105
+ end
106
+ update_result summary: { name: package_full_name, installed: installed,
107
+ status: status, alert: alert }
108
+ end
109
+
110
+ def update_binstubs
111
+ if current?
112
+ if installed?
113
+ update_binstubs!
114
+ update_result "Updated #{package_name} binstubs with current version #{package_version}"
115
+ else
116
+ update_result "Skipped! #{package_full_name} is NOT installed yet. Please install it first.",
117
+ status: :failed, level: :error
118
+ end
119
+ else
120
+ if current_symlinked?
121
+ remove_binstubs!
122
+ remove_symlinks!
123
+ update_result "Removed #{package_name} binstubs with version #{package_version}. " +
124
+ "Current version of #{package_name} is NOT specified.",
125
+ level: :warn
126
+ end
127
+ end
128
+ end
129
+
130
+ def which_current
131
+ get_summary
132
+ task.result.summary[:executable] = "Not found"
133
+ if current? and current_symlinked? and
134
+ file?(executable = File.join(readlink(current_path), 'bin', task.args.executable))
135
+ task.result.summary[:executable] = executable
136
+ end
137
+ end
138
+
139
+ def whence_origin
140
+ get_summary
141
+ task.result.summary[:executable] = "Not found"
142
+ if file?(executable = bin_path.join(task.args.executable))
143
+ task.result.summary[:executable] = executable
144
+ end
145
+ end
146
+
147
+ protected
148
+
149
+ def before_install
150
+ bootstrap
151
+ unless installed? or file?(src_file_path)
152
+ validate_download_url
153
+ end
154
+ install_required_packages(:before_install)
155
+ end
156
+
157
+ def after_install
158
+ install_required_packages(:after_install)
159
+ update_binstubs!
160
+ end
161
+
162
+ def install_required_packages(type)
163
+ required_packages[type].each do |d|
164
+ self.class.worker_class(:installer, package: d.name).new(
165
+ config: config, backend: backend,
166
+ cmd: :install, args: {},
167
+ opts: d.options.merge(name: d.name, version: d.version, parent: self)
168
+ ).run
169
+ end
170
+ end
171
+
172
+ def validate_download_url!
173
+ unless url_exists?(download_url)
174
+ raise InstallFailure,
175
+ "Package #{package_full_name} is NOT found from url: #{download_url}."
176
+ end
177
+ end
178
+
179
+ def install!
180
+ download_package
181
+ uncompress_package
182
+ assure_dirs(build_path)
183
+ within build_path do
184
+ with compose_build_env_variables do
185
+ build_package
186
+ end
187
+ end
188
+ cleanup_build!
189
+ end
190
+
191
+ def uninstall!
192
+ if current?
193
+ remove_binstubs!
194
+ remove_symlinks!
195
+ end
196
+ rmdir(install_path)
197
+ cleanup_temp!
198
+ cleanup_logs!
199
+ end
200
+
201
+ def cleanup_temp!
202
+ Luban::Deployment::Package::DependencyTypes.each do |type|
203
+ required_packages[type].each do |d|
204
+ self.class.worker_class(:installer, package: d.name).new(
205
+ config: config, backend: backend,
206
+ cmd: :cleanup_all, args: {},
207
+ opts: d.options.merge(name: d.name, version: d.version, parent: self)
208
+ ).run
209
+ end
210
+ end
211
+ cleanup_build!
212
+ end
213
+
214
+ def cleanup_build!
215
+ rmdir(build_path)
216
+ end
217
+
218
+ def cleanup_logs!
219
+ rmdir(install_log_path)
220
+ end
221
+
222
+ def update_binstubs!
223
+ remove_binstubs!
224
+ remove_symlinks!
225
+ create_symlinks!
226
+ create_binstubs!
227
+ end
228
+
229
+ def create_symlinks!
230
+ ln(install_path, current_path)
231
+ end
232
+
233
+ def create_binstubs!
234
+ return unless directory?(bin_path)
235
+ find_cmd = "find #{bin_path}/* -type f -print && find #{bin_path}/* -type l -print"
236
+ capture(find_cmd).split("\n").each do |bin|
237
+ ln(bin, app_bin_path.join(File.basename(bin)))
238
+ end
239
+ end
240
+
241
+ def remove_symlinks!
242
+ return unless symlink?(current_path)
243
+ execute "[ -h #{current_path} ] && rm -f #{current_path}; true"
244
+ end
245
+
246
+ def remove_binstubs!
247
+ return unless directory?(current_bin_path)
248
+ find_cmd = "find #{current_bin_path}/* -type f -print && find #{current_bin_path}/* -type l -print"
249
+ capture(find_cmd).split("\n").each do |bin|
250
+ bin_symlink = app_bin_path.join(File.basename(bin))
251
+ execute "[ -h #{bin_symlink} ] && rm -f #{bin_symlink}; true"
252
+ end
253
+ end
254
+
255
+ def bootstrap
256
+ assure_dirs(etc_path, tmp_path, app_bin_path, install_path, install_log_path)
257
+ end
258
+
259
+ def download_package
260
+ info "Downloading #{package_full_name} source package"
261
+ if file?(src_file_path)
262
+ info "#{package_full_name} is downloaded ALREADY"
263
+ else
264
+ download_package!
265
+ end
266
+ end
267
+
268
+ def download_package!
269
+ unless test("curl -L -o #{src_file_path} #{download_url} >> #{install_log_file_path} 2>&1")
270
+ rm(src_file_path)
271
+ abort_action('download')
272
+ end
273
+ end
274
+
275
+ def uncompress_package
276
+ info "Uncompressing #{package_full_name} source package"
277
+ uncompress_package!
278
+ end
279
+
280
+ def uncompress_package!
281
+ unless test("tar -xzf #{src_file_path} -C #{package_tmp_path} >> #{install_log_file_path} 2>&1")
282
+ abort_action('uncompress')
283
+ end
284
+ end
285
+
286
+ def build_package
287
+ configure_package
288
+ make_package
289
+ install_package
290
+ end
291
+
292
+ def configure_package
293
+ info "Configuring #{package_full_name}"
294
+ abort_action('configure') unless configure_package!
295
+ end
296
+
297
+ def configure_package!
298
+ test(configure_executable,
299
+ "#{compose_build_options} >> #{install_log_file_path} 2>&1")
300
+ end
301
+
302
+ def make_package
303
+ info "Making #{package_full_name}"
304
+ abort_action('make') unless make_package!
305
+ end
306
+
307
+ def make_package!
308
+ test(:make, ">> #{install_log_file_path} 2>&1")
309
+ end
310
+
311
+ def install_package
312
+ info "Installing #{package_full_name}"
313
+ abort_action('install') unless install_package!
314
+ end
315
+
316
+ def install_package!
317
+ test(:make, "install >> #{install_log_file_path} 2>&1")
318
+ end
319
+
320
+ def abort_action(action)
321
+ cleanup_temp!
322
+ task.result.status = :failed
323
+ task.result.message = "Failed to #{action} package #{package_full_name}." +
324
+ "Please check install log for details: #{install_log_file_path}"
325
+ raise InstallFailure, task.result.message
326
+ end
327
+ end
328
+ end
329
+ end
330
+ end
@@ -0,0 +1,81 @@
1
+ module Luban
2
+ module Deployment
3
+ module Package
4
+ class Installer
5
+ DefaultSrcFileExtName = 'tar.gz'
6
+
7
+ def src_file_name
8
+ @src_file_name ||= "#{package_full_name}.#{src_file_extname}"
9
+ end
10
+
11
+ def src_file_extname
12
+ @src_file_extname ||= DefaultSrcFileExtName
13
+ end
14
+
15
+ def src_file_path
16
+ @src_file_path ||= tmp_path.join(src_file_name)
17
+ end
18
+
19
+ def source_repo
20
+ raise NotImplementedError, "#{self.class.name}#source_repo is an abstract method."
21
+ end
22
+
23
+ def download_from_source?
24
+ lubhub_repo.nil?
25
+ end
26
+
27
+ def download_from_lubhub?
28
+ !lubhub_repo.nil?
29
+ end
30
+
31
+ def download_repo
32
+ @download_repo ||= download_from_source? ? source_repo : lubhub_repo
33
+ end
34
+
35
+ def source_url_root
36
+ raise NotImplementedError, "#{self.class.name}#source_url_root is an abstract method."
37
+ end
38
+
39
+ def download_url_root
40
+ @download_url_root ||= download_from_source? ? source_url_root : package_name
41
+ end
42
+
43
+ def download_url
44
+ @download_url ||= File.join(download_repo, download_url_root, src_file_name)
45
+ end
46
+
47
+ def install_path
48
+ @install_path ||= package_path.join('versions', package_version)
49
+ end
50
+
51
+ def bin_path
52
+ @bin_path ||= install_path.join('bin')
53
+ end
54
+
55
+ def lib_path
56
+ @lib_path ||= install_path.join('lib')
57
+ end
58
+
59
+ def include_path
60
+ @include_path ||= install_path.join('include')
61
+ end
62
+
63
+ def build_path
64
+ @build_path ||= package_tmp_path.join(package_full_name)
65
+ end
66
+
67
+ def install_log_path
68
+ @install_log_path ||= package_path.join('log').join(package_full_name)
69
+ end
70
+
71
+ def install_log_file_path
72
+ @install_log_file_path ||= install_log_path.join(install_log_file_name)
73
+ end
74
+
75
+ def install_log_file_name
76
+ @install_log_file_name ||= "#{package_full_name}-install-#{Time.now.strftime("%Y%m%d-%H%M%S")}.log"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'installer/core'
2
+ require_relative 'installer/paths'
3
+ require_relative 'installer/install'
@@ -0,0 +1,17 @@
1
+ module Luban
2
+ module Deployment
3
+ module Package
4
+ class Service < Binary
5
+ include Luban::Deployment::Command::Tasks::Deploy
6
+ include Luban::Deployment::Command::Tasks::Control
7
+
8
+ %i(deploy).each do |m|
9
+ define_task_method(m, worker: :deployer)
10
+ end
11
+
12
+ protected
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ module Luban
2
+ module Deployment
3
+ module Package
4
+ class Worker < Luban::Deployment::Worker::Remote
5
+ class << self
6
+ def package_class(package)
7
+ Luban::Deployment::Package::Base.package_class(package)
8
+ end
9
+
10
+ def worker_class(worker, **opts)
11
+ Luban::Deployment::Package::Base.worker_class(worker, **opts)
12
+ end
13
+ end
14
+
15
+ def package_name; task.opts.name; end
16
+ def package_full_name; "#{package_name}-#{package_version}"; end
17
+
18
+ def package_version; task.opts.version; end
19
+ def package_major_version; task.opts.major_version; end
20
+ def package_patch_level; task.opts.patch_level; end
21
+
22
+ def child?; !task.opts.parent.nil?; end
23
+ def parent; task.opts.parent; end
24
+
25
+ def current_path
26
+ @current_path ||= app_path.join(package_name)
27
+ end
28
+
29
+ def current_bin_path
30
+ @current_bin_path ||= current_path.join('bin')
31
+ end
32
+
33
+ def package_path
34
+ @package_path ||= luban_install_path.join('pkg', package_name)
35
+ end
36
+
37
+ def package_tmp_path
38
+ @package_tmp_path ||= package_path.join('tmp')
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,6 @@
1
+ require_relative 'package/dependency'
2
+ require_relative 'package/dependency_set'
3
+ require_relative 'package/binary'
4
+ require_relative 'package/service'
5
+ require_relative 'package/worker'
6
+ require_relative 'package/installer'
@@ -0,0 +1,94 @@
1
+ module Luban
2
+ module Deployment
3
+ class Project < Luban::Deployment::Command
4
+ using Luban::CLI::CoreRefinements
5
+ include Luban::Deployment::Parameters::Project
6
+ include Luban::Deployment::Command::Tasks::Install
7
+ include Luban::Deployment::Command::Tasks::Deploy
8
+ include Luban::Deployment::Command::Tasks::Control
9
+
10
+ attr_reader :apps
11
+
12
+ def display_name; @display_name ||= "#{stage} #{project.camelcase}"; end
13
+
14
+ def package_users_for(package_name, package_version, exclude: [], servers: [])
15
+ apps.values.inject([]) do |package_users, app|
16
+ if !exclude.include?(app.name) and
17
+ app.use_package?(package_name, package_version, servers: servers)
18
+ package_users << app.display_name
19
+ end
20
+ package_users
21
+ end
22
+ end
23
+
24
+ def password_for(user)
25
+ @passwords_mutex.synchronize do
26
+ if @passwords[user].nil?
27
+ @passwords[user] = ask(prompt: "Password for #{user}", echo: false)
28
+ end
29
+ @passwords[user]
30
+ end
31
+ end
32
+
33
+ %i(installable? deployable? controllable?).each do |method|
34
+ define_method(method) do
35
+ apps.values.any? { |app| app.send(__method__) }
36
+ end
37
+ end
38
+
39
+ %i(build destroy_project cleanup binstubs
40
+ show_current show_summary which whence
41
+ ).each do |action|
42
+ define_method(action) do |args:, opts:|
43
+ apps.each_value do |app|
44
+ app.send(__method__, args: args, opts: opts) if app.installable?
45
+ end
46
+ end
47
+ end
48
+
49
+ alias_method :destroy, :destroy_project
50
+
51
+ protected
52
+
53
+ def validate_parameters
54
+ super
55
+ validate_project_parameters
56
+ end
57
+
58
+ def set_default_parameters
59
+ super
60
+ set_default :stage, self.class.name.split('::').first.snakecase
61
+ set_default :project, self.class.name.split('::').last.snakecase
62
+ set_default_project_parameters
63
+ @passwords = {}
64
+ @passwords_mutex = Mutex.new
65
+ end
66
+
67
+ def load_libraries
68
+ applications.each do |app|
69
+ require "#{work_dir}/apps/#{app}/lib/application"
70
+ end
71
+ end
72
+
73
+ def application_base_class(app)
74
+ Object.const_get("#{project}:#{app}".camelcase)
75
+ end
76
+
77
+ def setup_cli
78
+ setup_applications
79
+ super
80
+ end
81
+
82
+ def setup_descriptions
83
+ desc "Manage apps in #{display_name}"
84
+ end
85
+
86
+ def setup_applications
87
+ @apps = {}
88
+ applications.map(&:to_sym).each do |app|
89
+ @apps[app] = command(app, base: application_base_class(app))
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,4 @@
1
+ require_relative 'cli/command'
2
+ require_relative 'cli/project'
3
+ require_relative 'cli/application'
4
+ require_relative 'cli/package'
@@ -0,0 +1,67 @@
1
+ module Luban
2
+ module Deployment
3
+ class Configuration
4
+ attr_reader :variables
5
+ attr_reader :servers
6
+
7
+ def initialize
8
+ @variables = {}
9
+ @servers = ServerSet.new
10
+ end
11
+
12
+ def set(key, value)
13
+ @variables[key] = value
14
+ end
15
+
16
+ def set_default(key, value)
17
+ set(key, value) unless @variables.has_key?(key)
18
+ end
19
+
20
+ def delete(key)
21
+ @variables[key] = value
22
+ end
23
+
24
+ def fetch(key, default = nil, &blk)
25
+ value = if block_given?
26
+ @variables.fetch(key, &blk)
27
+ else
28
+ @variables.fetch(key, default)
29
+ end
30
+ while callable_without_parameters?(value)
31
+ value = set(key, value.call)
32
+ end
33
+ return value
34
+ end
35
+
36
+ def keys
37
+ @variables.keys
38
+ end
39
+
40
+ def role(name, hosts, **properties)
41
+ if name == :all
42
+ raise ArgumentError, 'Reserved role name, :all, is NOT allowed to use.'
43
+ end
44
+ @servers.add_hosts_for_role(name, hosts, properties)
45
+ end
46
+
47
+ def server(name, **properties)
48
+ new_server = servers.add_host(name, properties)
49
+ if new_server
50
+ new_server.ssh_options = fetch(:ssh_options) || {}
51
+ end
52
+ end
53
+
54
+ def ask(key=nil, default:, prompt: nil, echo: true)
55
+ Question.new(default: default, prompt: prompt, echo: echo).call.tap do |answer|
56
+ set(key, answer) unless key.nil?
57
+ end
58
+ end
59
+
60
+ protected
61
+
62
+ def callable_without_parameters?(x)
63
+ x.respond_to?(:call) && (!x.respond_to?(:arity) || x.arity == 0)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,54 @@
1
+ module Luban
2
+ module Deployment
3
+ class Configuration
4
+ def roles(*names)
5
+ opts = names.last.is_a?(::Hash) ? names.pop : {}
6
+ filter_servers(servers.find_by_roles(filter_roles(names), opts))
7
+ end
8
+
9
+ def release_roles(*names)
10
+ if names.last.is_a?(Hash)
11
+ names.last.merge(:exclude => :no_release)
12
+ else
13
+ names << { :exclude => :no_release }
14
+ end
15
+ roles(*names)
16
+ end
17
+
18
+ def primary(role)
19
+ servers.find_primary(role)
20
+ end
21
+
22
+ protected
23
+
24
+ def filter_roles(_roles)
25
+ available_roles = (env_filter(:roles) | config_filter(:roles)).map(&:to_sym)
26
+ available_roles = servers.available_roles if available_roles.empty?
27
+ if _roles.include?(:all)
28
+ available_roles
29
+ else
30
+ _roles.select { |name| available_roles.include?(name) }
31
+ end
32
+ end
33
+
34
+ def filter_servers(_servers)
35
+ filter_hosts = env_filter(:hosts) | config_filter(:hosts)
36
+ if filter_hosts.empty?
37
+ _servers
38
+ else
39
+ _servers.select { |server| filter_hosts.include?(server.hostname) }
40
+ end
41
+ end
42
+
43
+ def env_filter(type)
44
+ type = type.to_s.upcase
45
+ ENV[type].nil? ? [] : ENV[type].split(',')
46
+ end
47
+
48
+ def config_filter(type)
49
+ filter = fetch(:filter) || fetch(:select)
50
+ filter.nil? ? [] : filter.fetch(type, [])
51
+ end
52
+ end
53
+ end
54
+ end