motherbrain 0.0.0.placeholder → 0.13.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.ruby-version +1 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +196 -0
- data/COMMANDS.md +9 -0
- data/CONTRIBUTING.md +24 -0
- data/Dockerfile +26 -0
- data/Gemfile +60 -2
- data/Guardfile +30 -0
- data/LICENSE +10 -0
- data/MANIFESTS.md +90 -0
- data/OPERATORS_GUIDE.md +195 -0
- data/PLUGINS.md +268 -0
- data/README.md +304 -16
- data/Thorfile +123 -0
- data/VAGRANT.md +116 -0
- data/bin/boot +9 -0
- data/bin/mb +5 -0
- data/bin/mbsrv +5 -0
- data/config.json +32 -0
- data/features/cli/bootstrap_command/configurable_scripts.feature +32 -0
- data/features/cli/configure_command.feature +57 -0
- data/features/cli/environment_command/create_command.feature +22 -0
- data/features/cli/environment_command/destroy_command.feature +33 -0
- data/features/cli/environment_command/from_command.feature +29 -0
- data/features/cli/environment_command/list_command.feature +0 -0
- data/features/cli/node_limiting.feature +47 -0
- data/features/cli/plugin_command/list_command.feature +46 -0
- data/features/cli/service_command/service_command.feature +21 -0
- data/features/cli/template_command.feature +10 -0
- data/features/cli/validate_config.feature +46 -0
- data/features/step_definitions/bootstrap_steps.rb +57 -0
- data/features/step_definitions/chef_server_steps.rb +3 -0
- data/features/step_definitions/configuration_steps.rb +18 -0
- data/features/step_definitions/core_cli_steps.rb +33 -0
- data/features/step_definitions/environment_steps.rb +43 -0
- data/features/step_definitions/node_steps.rb +3 -0
- data/features/step_definitions/plugin_steps.rb +15 -0
- data/features/step_definitions/template_steps.rb +7 -0
- data/features/support/env.rb +68 -0
- data/lib/mb/api.rb +8 -0
- data/lib/mb/api/application.rb +7 -0
- data/lib/mb/api/endpoint.rb +5 -0
- data/lib/mb/api/helpers.rb +38 -0
- data/lib/mb/api/v1.rb +56 -0
- data/lib/mb/api/v1/config_endpoint.rb +12 -0
- data/lib/mb/api/v1/environments_endpoint.rb +174 -0
- data/lib/mb/api/v1/jobs_endpoint.rb +31 -0
- data/lib/mb/api/v1/plugins_endpoint.rb +90 -0
- data/lib/mb/api/validators.rb +5 -0
- data/lib/mb/api/validators/sem_ver.rb +18 -0
- data/lib/mb/application.rb +148 -0
- data/lib/mb/berkshelf.rb +50 -0
- data/lib/mb/bootstrap.rb +9 -0
- data/lib/mb/bootstrap/manager.rb +250 -0
- data/lib/mb/bootstrap/manifest.rb +131 -0
- data/lib/mb/bootstrap/routine.rb +199 -0
- data/lib/mb/bootstrap/template.rb +73 -0
- data/lib/mb/bootstrap/worker.rb +227 -0
- data/lib/mb/chef.rb +6 -0
- data/lib/mb/chef/config.rb +69 -0
- data/lib/mb/chef/run_list_item.rb +115 -0
- data/lib/mb/chef_mutex.rb +304 -0
- data/lib/mb/clean_room_base.rb +39 -0
- data/lib/mb/cli.rb +50 -0
- data/lib/mb/cli/base.rb +51 -0
- data/lib/mb/cli/shell.rb +29 -0
- data/lib/mb/cli/shell/basic.rb +11 -0
- data/lib/mb/cli/shell/color.rb +11 -0
- data/lib/mb/cli/shell/ext.rb +41 -0
- data/lib/mb/cli/sub_command.rb +95 -0
- data/lib/mb/cli/sub_command/component.rb +56 -0
- data/lib/mb/cli/sub_command/plugin.rb +232 -0
- data/lib/mb/cli_client.rb +178 -0
- data/lib/mb/cli_gateway.rb +426 -0
- data/lib/mb/cli_gateway/sub_commands.rb +3 -0
- data/lib/mb/cli_gateway/sub_commands/environment.rb +124 -0
- data/lib/mb/cli_gateway/sub_commands/plugin.rb +148 -0
- data/lib/mb/command.rb +88 -0
- data/lib/mb/command_invoker.rb +235 -0
- data/lib/mb/command_invoker/worker.rb +40 -0
- data/lib/mb/command_runner.rb +233 -0
- data/lib/mb/component.rb +245 -0
- data/lib/mb/config.rb +275 -0
- data/lib/mb/config_manager.rb +75 -0
- data/lib/mb/console.rb +35 -0
- data/lib/mb/cookbook_metadata.rb +73 -0
- data/lib/mb/core_ext.rb +3 -0
- data/lib/mb/core_ext/dir.rb +37 -0
- data/lib/mb/core_ext/enumerable.rb +48 -0
- data/lib/mb/core_ext/file.rb +24 -0
- data/lib/mb/core_ext/signal.rb +11 -0
- data/lib/mb/environment_manager.rb +195 -0
- data/lib/mb/error_handler.rb +212 -0
- data/lib/mb/errors.rb +693 -0
- data/lib/mb/file_system.rb +60 -0
- data/lib/mb/file_system/tempfile.rb +25 -0
- data/lib/mb/gear.rb +154 -0
- data/lib/mb/gears.rb +8 -0
- data/lib/mb/gears/dynamic_service.rb +218 -0
- data/lib/mb/gears/jmx.rb +24 -0
- data/lib/mb/gears/jmx/action.rb +46 -0
- data/lib/mb/gears/mysql.rb +20 -0
- data/lib/mb/gears/mysql/action.rb +190 -0
- data/lib/mb/gears/service.rb +163 -0
- data/lib/mb/gears/service/action.rb +58 -0
- data/lib/mb/gears/service/action_runner.rb +161 -0
- data/lib/mb/grape_ext.rb +3 -0
- data/lib/mb/grape_ext/endpoint.rb +13 -0
- data/lib/mb/group.rb +143 -0
- data/lib/mb/job.rb +183 -0
- data/lib/mb/job/state_machine.rb +34 -0
- data/lib/mb/job/states.rb +46 -0
- data/lib/mb/job_manager.rb +96 -0
- data/lib/mb/job_record.rb +67 -0
- data/lib/mb/job_ticket.rb +25 -0
- data/lib/mb/lock_manager.rb +116 -0
- data/lib/mb/logging.rb +134 -0
- data/lib/mb/logging/basic_format.rb +31 -0
- data/lib/mb/manifest.rb +128 -0
- data/lib/mb/mixin.rb +3 -0
- data/lib/mb/mixin/attribute_setting.rb +265 -0
- data/lib/mb/mixin/coded_exit.rb +49 -0
- data/lib/mb/mixin/locks.rb +54 -0
- data/lib/mb/mixin/services.rb +100 -0
- data/lib/mb/node_filter.rb +97 -0
- data/lib/mb/node_querier.rb +527 -0
- data/lib/mb/plugin.rb +300 -0
- data/lib/mb/plugin_manager.rb +589 -0
- data/lib/mb/provisioner.rb +186 -0
- data/lib/mb/provisioner/manager.rb +213 -0
- data/lib/mb/provisioner/manifest.rb +125 -0
- data/lib/mb/provisioner/provision_data.rb +96 -0
- data/lib/mb/provisioners.rb +5 -0
- data/lib/mb/provisioners/aws.rb +395 -0
- data/lib/mb/rest_gateway.rb +72 -0
- data/lib/mb/ridley_ext.rb +5 -0
- data/lib/mb/ridley_ext/cookbook_object.rb +15 -0
- data/lib/mb/srv_ctl.rb +183 -0
- data/lib/mb/test.rb +104 -0
- data/lib/mb/thor_ext.rb +49 -0
- data/lib/mb/upgrade.rb +6 -0
- data/lib/mb/upgrade/manager.rb +85 -0
- data/lib/mb/upgrade/worker.rb +149 -0
- data/lib/mb/version.rb +1 -1
- data/lib/motherbrain.rb +166 -2
- data/man/man_helper.rb +81 -0
- data/man/mb.1 +494 -0
- data/man/mb.1.html +300 -0
- data/man/mb.1.ronn.erb +62 -0
- data/motherbrain.gemspec +56 -20
- data/scripts/node_name.rb +14 -0
- data/spec/fixtures/cb_metadata.json +7 -0
- data/spec/fixtures/cb_metadata.rb +14 -0
- data/spec/fixtures/fake_id_rsa +27 -0
- data/spec/fixtures/fake_key.pem +27 -0
- data/spec/fixtures/myface-0.1.0/metadata.rb +14 -0
- data/spec/fixtures/myface-0.1.0/motherbrain.rb +0 -0
- data/spec/fixtures/test_env.json +15 -0
- data/spec/spec_helper.rb +67 -0
- data/spec/support/actor_mocking.rb +7 -0
- data/spec/support/berkshelf.rb +24 -0
- data/spec/support/chef_server.rb +102 -0
- data/spec/support/doubles.rb +11 -0
- data/spec/support/klass.rb +10 -0
- data/spec/support/matchers/each.rb +12 -0
- data/spec/support/matchers/error_codes.rb +5 -0
- data/spec/support/matchers/exit_codes.rb +57 -0
- data/spec/support/matchers/jobs.rb +11 -0
- data/spec/support/spec_helpers.rb +145 -0
- data/spec/unit/mb/api/application_spec.rb +11 -0
- data/spec/unit/mb/api/helpers_spec.rb +5 -0
- data/spec/unit/mb/api/v1/config_endpoint_spec.rb +19 -0
- data/spec/unit/mb/api/v1/environments_endpoint_spec.rb +71 -0
- data/spec/unit/mb/api/v1/jobs_endpoint_spec.rb +24 -0
- data/spec/unit/mb/api/v1/plugins_endpoint_spec.rb +298 -0
- data/spec/unit/mb/api/v1_spec.rb +37 -0
- data/spec/unit/mb/api/validators/sem_ver_spec.rb +5 -0
- data/spec/unit/mb/application_spec.rb +19 -0
- data/spec/unit/mb/berkshelf_spec.rb +38 -0
- data/spec/unit/mb/bootstrap/manager_spec.rb +347 -0
- data/spec/unit/mb/bootstrap/manifest_spec.rb +333 -0
- data/spec/unit/mb/bootstrap/routine_spec.rb +393 -0
- data/spec/unit/mb/bootstrap/template_spec.rb +100 -0
- data/spec/unit/mb/bootstrap/worker_spec.rb +194 -0
- data/spec/unit/mb/chef/config_spec.rb +33 -0
- data/spec/unit/mb/chef/run_list_item_spec.rb +34 -0
- data/spec/unit/mb/chef_mutex_spec.rb +314 -0
- data/spec/unit/mb/clean_room_base_spec.rb +31 -0
- data/spec/unit/mb/cli/base_spec.rb +43 -0
- data/spec/unit/mb/cli/shell/basic_spec.rb +5 -0
- data/spec/unit/mb/cli/shell/color_spec.rb +5 -0
- data/spec/unit/mb/cli/shell/ext_spec.rb +11 -0
- data/spec/unit/mb/cli/shell_spec.rb +38 -0
- data/spec/unit/mb/cli/sub_command/base_spec.rb +102 -0
- data/spec/unit/mb/cli/sub_command/component_spec.rb +5 -0
- data/spec/unit/mb/cli/sub_command/plugin_spec.rb +91 -0
- data/spec/unit/mb/cli/sub_command_spec.rb +43 -0
- data/spec/unit/mb/cli/ui.rb +0 -0
- data/spec/unit/mb/cli_client_spec.rb +51 -0
- data/spec/unit/mb/cli_gateway_spec.rb +386 -0
- data/spec/unit/mb/command_invoker/worker_spec.rb +43 -0
- data/spec/unit/mb/command_invoker_spec.rb +230 -0
- data/spec/unit/mb/command_runner_spec.rb +299 -0
- data/spec/unit/mb/command_spec.rb +76 -0
- data/spec/unit/mb/component_spec.rb +185 -0
- data/spec/unit/mb/config_manager_spec.rb +31 -0
- data/spec/unit/mb/config_spec.rb +408 -0
- data/spec/unit/mb/cookbook_metadata_spec.rb +89 -0
- data/spec/unit/mb/core_ext/dir_spec.rb +92 -0
- data/spec/unit/mb/core_ext/enumerable_spec.rb +104 -0
- data/spec/unit/mb/core_ext/file_spec.rb +58 -0
- data/spec/unit/mb/core_ext/signal_spec.rb +24 -0
- data/spec/unit/mb/environment_manager_spec.rb +166 -0
- data/spec/unit/mb/error_handler_spec.rb +173 -0
- data/spec/unit/mb/errors_spec.rb +132 -0
- data/spec/unit/mb/file_system/tempfile_spec.rb +14 -0
- data/spec/unit/mb/file_system_spec.rb +69 -0
- data/spec/unit/mb/gear_spec.rb +125 -0
- data/spec/unit/mb/gears/dynamic_service_spec.rb +187 -0
- data/spec/unit/mb/gears/jmx/action_spec.rb +34 -0
- data/spec/unit/mb/gears/jmx_spec.rb +32 -0
- data/spec/unit/mb/gears/mysql/action_spec.rb +118 -0
- data/spec/unit/mb/gears/mysql_spec.rb +21 -0
- data/spec/unit/mb/gears/service/action_runner_spec.rb +182 -0
- data/spec/unit/mb/gears/service/action_spec.rb +44 -0
- data/spec/unit/mb/gears/service_spec.rb +124 -0
- data/spec/unit/mb/group_spec.rb +280 -0
- data/spec/unit/mb/job_manager_spec.rb +56 -0
- data/spec/unit/mb/job_record_spec.rb +60 -0
- data/spec/unit/mb/job_spec.rb +201 -0
- data/spec/unit/mb/locks_manager_spec.rb +88 -0
- data/spec/unit/mb/logging_spec.rb +133 -0
- data/spec/unit/mb/manifest_spec.rb +105 -0
- data/spec/unit/mb/mixin/attribute_setting_spec.rb +180 -0
- data/spec/unit/mb/mixin/coded_exit_spec.rb +25 -0
- data/spec/unit/mb/mixin/locks_spec.rb +32 -0
- data/spec/unit/mb/mixin/services_spec.rb +75 -0
- data/spec/unit/mb/node_filter_spec.rb +86 -0
- data/spec/unit/mb/node_querier_spec.rb +532 -0
- data/spec/unit/mb/plugin_manager_spec.rb +724 -0
- data/spec/unit/mb/plugin_spec.rb +247 -0
- data/spec/unit/mb/provisioner/manager_spec.rb +141 -0
- data/spec/unit/mb/provisioner/manifest_spec.rb +182 -0
- data/spec/unit/mb/provisioner/provision_data_spec.rb +113 -0
- data/spec/unit/mb/provisioner_spec.rb +251 -0
- data/spec/unit/mb/provisioners/aws_spec.rb +392 -0
- data/spec/unit/mb/provisioners/environment_factory_spec.rb +108 -0
- data/spec/unit/mb/rest_gateway_spec.rb +13 -0
- data/spec/unit/mb/ridley_ext/cookbook_object_spec.rb +105 -0
- data/spec/unit/mb/srv_ctl_spec.rb +142 -0
- data/spec/unit/mb/upgrade/manager_spec.rb +37 -0
- data/spec/unit/mb/upgrade/worker_spec.rb +219 -0
- data/spec/unit/motherbrain_spec.rb +58 -0
- data/templates/bootstrap.json +8 -0
- data/templates/motherbrain.rb +44 -0
- metadata +694 -15
- data/Rakefile +0 -1
@@ -0,0 +1,304 @@
|
|
1
|
+
module MotherBrain
|
2
|
+
# Allows for motherbrain clients to lock a chef resource. A mutex is created
|
3
|
+
# with a type and name. Sending #lock to the mutex will then store a data bag
|
4
|
+
# item with mutex, the requestor's client_name, and the current time. An
|
5
|
+
# attempt to lock an already-locked mutex will fail if the lock is owned by
|
6
|
+
# someone else, or succeed if the lock is owned by the current user.
|
7
|
+
#
|
8
|
+
# @example Creating a mutex and obtaining a lock
|
9
|
+
#
|
10
|
+
# mutex = ChefMutex.new(chef_environment: "my_environment")
|
11
|
+
#
|
12
|
+
# mutex.lock # => true
|
13
|
+
# # do stuff
|
14
|
+
# mutex.unlock # => true
|
15
|
+
#
|
16
|
+
# @example Running a block within an obtained lock
|
17
|
+
#
|
18
|
+
# mutex = ChefMutex.new(chef_environment: "my_environment")
|
19
|
+
#
|
20
|
+
# mutex.synchronize do
|
21
|
+
# # do stuff
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
class ChefMutex
|
25
|
+
class << self
|
26
|
+
# Create a new ChefMutex and run the given block of code within it. Terminate the
|
27
|
+
# ChefMutex after the block of code finishes executing.
|
28
|
+
#
|
29
|
+
# @see {ChefMutex#initialize}, {ChefMutex#synchronize}
|
30
|
+
def synchronize(options, &block)
|
31
|
+
mutex = new(options)
|
32
|
+
mutex.synchronize(&block)
|
33
|
+
ensure
|
34
|
+
mutex.terminate
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
include Celluloid
|
39
|
+
include Celluloid::Notifications
|
40
|
+
include MB::Logging
|
41
|
+
include MB::Mixin::Services
|
42
|
+
|
43
|
+
extend Forwardable
|
44
|
+
|
45
|
+
DATA_BAG = "_motherbrain_locks_".freeze
|
46
|
+
|
47
|
+
LOCK_TYPES = [
|
48
|
+
:chef_environment
|
49
|
+
]
|
50
|
+
|
51
|
+
attr_reader :type
|
52
|
+
attr_reader :name
|
53
|
+
|
54
|
+
attr_reader :force
|
55
|
+
attr_reader :job
|
56
|
+
attr_reader :report_job_status
|
57
|
+
attr_reader :unlock_on_failure
|
58
|
+
|
59
|
+
execute_block_on_receiver :synchronize
|
60
|
+
|
61
|
+
finalizer :finalize_callback
|
62
|
+
|
63
|
+
# @option options [#to_s] :chef_environment
|
64
|
+
# The name of the environment to lock
|
65
|
+
# @option options [Boolean] :force (false)
|
66
|
+
# Force the lock to be written, even if it already exists.
|
67
|
+
# @option options [MotherBrain::Job] :job
|
68
|
+
# A job that will receive status updates during lock/unlock
|
69
|
+
# @option options [Boolean] :report_job_status (false)
|
70
|
+
# @option options [Boolean] :unlock_on_failure (true)
|
71
|
+
# If false and the block raises an error, the lock will persist.
|
72
|
+
def initialize(options = {})
|
73
|
+
options = options.reverse_merge(
|
74
|
+
force: false,
|
75
|
+
unlock_on_failure: true
|
76
|
+
)
|
77
|
+
|
78
|
+
type, name = options.find { |key, value| LOCK_TYPES.include? key }
|
79
|
+
|
80
|
+
@type = type
|
81
|
+
@name = name
|
82
|
+
@force = options[:force]
|
83
|
+
@job = options[:job]
|
84
|
+
@report_job_status = options[:report_job_status]
|
85
|
+
@unlock_on_failure = options[:unlock_on_failure]
|
86
|
+
|
87
|
+
lock_manager.register(Actor.current)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @return [String]
|
91
|
+
def data_bag_id
|
92
|
+
result = to_s.dup
|
93
|
+
|
94
|
+
result.downcase!
|
95
|
+
result.gsub! /[^\w]+/, "-" # dasherize
|
96
|
+
result.gsub! /^-+|-+$/, "" # remove dashes from beginning/end
|
97
|
+
|
98
|
+
result
|
99
|
+
end
|
100
|
+
|
101
|
+
# @return [String]
|
102
|
+
def to_s
|
103
|
+
"#{type}:#{name}"
|
104
|
+
end
|
105
|
+
|
106
|
+
# Attempts to create a lock. Fails if the lock already exists.
|
107
|
+
#
|
108
|
+
# @return [Boolean]
|
109
|
+
def lock
|
110
|
+
unless type
|
111
|
+
raise InvalidLockType, "Must pass a valid lock type (#{LOCK_TYPES})"
|
112
|
+
end
|
113
|
+
|
114
|
+
log.info { "Locking #{to_s}" }
|
115
|
+
|
116
|
+
if job
|
117
|
+
job.set_status "Locking #{to_s}"
|
118
|
+
job.report_running if report_job_status
|
119
|
+
end
|
120
|
+
|
121
|
+
report(attempt_lock)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns whether or not the object is locked.
|
125
|
+
#
|
126
|
+
# @return [Boolean]
|
127
|
+
def locked?
|
128
|
+
!!read
|
129
|
+
end
|
130
|
+
|
131
|
+
# Obtains a lock, runs the block, and releases the lock when the block
|
132
|
+
# completes. Raises a ResourceLocked error if the lock was unobtainable.
|
133
|
+
# If the block raises an error, the resource is unlocked, unless
|
134
|
+
# unlock_on_failure: true is passed in to the option hash.
|
135
|
+
#
|
136
|
+
# @raise [MotherBrain::ResourceLocked] if the lock is unobtainable
|
137
|
+
#
|
138
|
+
# @return [Boolean]
|
139
|
+
def synchronize
|
140
|
+
unless lock
|
141
|
+
current_lock = read
|
142
|
+
|
143
|
+
err = "Resource #{current_lock['id']} locked by #{current_lock['client_name']}"
|
144
|
+
err << " since #{current_lock['time']} (PID #{current_lock['process_id']})"
|
145
|
+
|
146
|
+
raise ResourceLocked.new(err)
|
147
|
+
end
|
148
|
+
|
149
|
+
yield
|
150
|
+
|
151
|
+
unlock
|
152
|
+
rescue => ex
|
153
|
+
ex = ex.respond_to?(:cause) ? ex.cause : ex
|
154
|
+
|
155
|
+
unless ex.is_a?(ResourceLocked)
|
156
|
+
unlock if unlock_on_failure
|
157
|
+
end
|
158
|
+
|
159
|
+
abort(ex)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Attempts to unlock the lock. Fails if the lock doesn't exist, or if it is
|
163
|
+
# held by someone else
|
164
|
+
#
|
165
|
+
# @return [Boolean]
|
166
|
+
def unlock
|
167
|
+
if job
|
168
|
+
job.report_running if report_job_status
|
169
|
+
job.set_status("Unlocking #{to_s}")
|
170
|
+
end
|
171
|
+
|
172
|
+
attempt_unlock
|
173
|
+
|
174
|
+
report(true)
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
def finalize_callback
|
180
|
+
lock_manager.async.unregister(Actor.current) if lock_manager.alive?
|
181
|
+
end
|
182
|
+
|
183
|
+
# Reports a job status
|
184
|
+
# @param [Object] result
|
185
|
+
# @return [Object] result
|
186
|
+
def report(result)
|
187
|
+
if job && report_job_status
|
188
|
+
job.report_boolean(result)
|
189
|
+
end
|
190
|
+
|
191
|
+
result
|
192
|
+
end
|
193
|
+
|
194
|
+
# Check to see if the passed in lock was created by us
|
195
|
+
#
|
196
|
+
# @param [Hash] current_lock the lock data obtained from #read
|
197
|
+
# @return [Boolean]
|
198
|
+
def our_lock?(current_lock)
|
199
|
+
return nil unless current_lock
|
200
|
+
return false unless current_lock["client_name"] == client_name
|
201
|
+
return false unless current_lock["process_id"] == Process.pid
|
202
|
+
true
|
203
|
+
end
|
204
|
+
|
205
|
+
# @return [Boolean]
|
206
|
+
def attempt_lock
|
207
|
+
unless self.force
|
208
|
+
current_lock = read
|
209
|
+
return our_lock?(current_lock) if current_lock
|
210
|
+
end
|
211
|
+
|
212
|
+
write
|
213
|
+
end
|
214
|
+
|
215
|
+
# @return [Boolean]
|
216
|
+
def attempt_unlock
|
217
|
+
unless self.force
|
218
|
+
current_lock = read
|
219
|
+
|
220
|
+
return unless current_lock && our_lock?(current_lock)
|
221
|
+
end
|
222
|
+
|
223
|
+
delete
|
224
|
+
end
|
225
|
+
|
226
|
+
# @return [String]
|
227
|
+
def client_name
|
228
|
+
Application.ridley.client_name
|
229
|
+
end
|
230
|
+
|
231
|
+
# @return [Ridley::ChainLink]
|
232
|
+
def data_bag
|
233
|
+
Application.ridley.data_bag
|
234
|
+
end
|
235
|
+
|
236
|
+
# Delete the lock from the data bag.
|
237
|
+
#
|
238
|
+
# @return [Boolean]
|
239
|
+
def delete
|
240
|
+
return true unless locks
|
241
|
+
|
242
|
+
result = locks.delete(data_bag_id)
|
243
|
+
|
244
|
+
lock_manager.unregister(Actor.current)
|
245
|
+
|
246
|
+
result
|
247
|
+
rescue
|
248
|
+
lock_manager.register(Actor.current)
|
249
|
+
end
|
250
|
+
|
251
|
+
# Create our data bag if it doesn't already exist
|
252
|
+
def ensure_data_bag_exists
|
253
|
+
data_bag.create(name: DATA_BAG) unless locks
|
254
|
+
end
|
255
|
+
|
256
|
+
# @return [Ridley::DBIChainLink] if the data bag exists
|
257
|
+
# @return [nil] if it does not
|
258
|
+
def locks
|
259
|
+
result = data_bag.find(DATA_BAG)
|
260
|
+
|
261
|
+
return unless result
|
262
|
+
|
263
|
+
result.item
|
264
|
+
end
|
265
|
+
|
266
|
+
# Read the lock from the data bag.
|
267
|
+
#
|
268
|
+
# @return [Hash] if the lock exists
|
269
|
+
# @return [nil] if it does not
|
270
|
+
def read
|
271
|
+
return unless locks
|
272
|
+
|
273
|
+
result = locks.find(data_bag_id)
|
274
|
+
|
275
|
+
result.to_hash if result
|
276
|
+
end
|
277
|
+
|
278
|
+
def unregister_lock
|
279
|
+
lock_manager.unregister(Actor.current)
|
280
|
+
end
|
281
|
+
|
282
|
+
# Write the lock to the data bag.
|
283
|
+
#
|
284
|
+
# @return [Boolean]
|
285
|
+
def write
|
286
|
+
ensure_data_bag_exists
|
287
|
+
|
288
|
+
result = locks.new(
|
289
|
+
id: data_bag_id,
|
290
|
+
type: type,
|
291
|
+
name: name,
|
292
|
+
client_name: client_name,
|
293
|
+
process_id: Process.pid,
|
294
|
+
time: Time.now
|
295
|
+
).save
|
296
|
+
|
297
|
+
lock_manager.register(Actor.current)
|
298
|
+
|
299
|
+
result
|
300
|
+
rescue
|
301
|
+
lock_manager.unregister(Actor.current)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MotherBrain
|
2
|
+
class CleanRoomBase
|
3
|
+
class << self
|
4
|
+
# Create a DSL writer function that will assign the a given value
|
5
|
+
# to the real object of this clean room.
|
6
|
+
#
|
7
|
+
# @param [Symbol] attribute
|
8
|
+
def dsl_attr_writer(attribute)
|
9
|
+
class_eval do
|
10
|
+
define_method(attribute) do |value|
|
11
|
+
set_attribute(attribute, value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
include MB::Logging
|
18
|
+
|
19
|
+
# @param [Object] real_model
|
20
|
+
def initialize(real_model, &block)
|
21
|
+
@real_model = real_model
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :real_model
|
27
|
+
|
28
|
+
def set_attribute(name, value)
|
29
|
+
real_model.send("#{name}=", value)
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_missing(method_name, *args, &block)
|
33
|
+
ErrorHandler.wrap PluginSyntaxError,
|
34
|
+
backtrace: caller,
|
35
|
+
method_name: method_name,
|
36
|
+
text: "'#{method_name}' is not a valid keyword"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/mb/cli.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module MotherBrain
|
2
|
+
module Cli
|
3
|
+
autoload :Base, 'mb/cli/base'
|
4
|
+
autoload :Shell, 'mb/cli/shell'
|
5
|
+
autoload :SubCommand, 'mb/cli/sub_command'
|
6
|
+
|
7
|
+
# This is the main entry point for the CLI. It exposes the method {#execute!} to
|
8
|
+
# start the CliGateway.
|
9
|
+
#
|
10
|
+
# @note the arity of {#initialize} and {#execute!} are extremely important for testing purposes. It
|
11
|
+
# is a requirement to perform in-process testing with Aruba. In process testing is much faster
|
12
|
+
# than spawning a new Ruby process for each test.
|
13
|
+
class Runner
|
14
|
+
# @param [Array] argv
|
15
|
+
# @param [IO] stdin
|
16
|
+
# @param [IO] stdout
|
17
|
+
# @param [IO] stderr
|
18
|
+
# @param [Kernel] kernel
|
19
|
+
def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
|
20
|
+
@argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
|
21
|
+
end
|
22
|
+
|
23
|
+
# Start the CLI Gateway
|
24
|
+
def execute!
|
25
|
+
MB::CliGateway.start(@argv)
|
26
|
+
rescue MBError => ex
|
27
|
+
ui.error ex
|
28
|
+
@kernel.exit(ex.exit_code)
|
29
|
+
rescue Ridley::Errors::ConnectionFailed => ex
|
30
|
+
ui.error "[ERROR] Unable to connect to the configured Chef server: #{ex.message}."
|
31
|
+
ui.error "[ERROR] Check your configuration and network settings and try again."
|
32
|
+
@kernel.exit(MB::ChefConnectionError.exit_code)
|
33
|
+
rescue Thor::Error => ex
|
34
|
+
ui.error ex.message
|
35
|
+
@kernel.exit(1)
|
36
|
+
rescue Errno::EPIPE
|
37
|
+
# This happens if a thor command is piped to something like `head`,
|
38
|
+
# which closes the pipe when it's done reading. This will also
|
39
|
+
# mean that if the pipe is closed, further unnecessary
|
40
|
+
# computation will not occur.
|
41
|
+
@kernel.exit(0)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [MB::Cli::Shell::Color, MB::Cli::Shell::Basic]
|
45
|
+
def ui
|
46
|
+
@ui ||= MB::Cli::Shell.shell.new
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/mb/cli/base.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module MotherBrain
|
2
|
+
module Cli
|
3
|
+
class Base < Thor
|
4
|
+
include Thor::Actions
|
5
|
+
include MB::Mixin::CodedExit
|
6
|
+
include MB::Mixin::Services
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# Registers a SubCommand with this Cli::Base class
|
10
|
+
#
|
11
|
+
# @param [MB::Cli::SubCommand] klass
|
12
|
+
def register_subcommand(klass)
|
13
|
+
self.register(klass, klass.name.gsub('-', '_'), klass.usage.gsub('-', '_'), klass.description)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [MB::Cli::Shell::Color, MB::Cli::Shell::Basic]
|
17
|
+
def ui
|
18
|
+
@ui ||= MB::Cli::Shell.shell.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
no_tasks do
|
23
|
+
# @param [MB::Job] job
|
24
|
+
def display_job(job)
|
25
|
+
CliClient.new(job).display
|
26
|
+
end
|
27
|
+
# @note from Jamie: Increased verbosity for Michael Ivey. This is pretty much the most important line of code
|
28
|
+
# in this entire codebase so DO NOT REMOVE.
|
29
|
+
alias_method :display_job_status_and_wait_until_it_is_done_while_providing_user_feedback, :display_job
|
30
|
+
|
31
|
+
# @return [MB::Cli::Shell::Color, MB::Cli::Shell::Basic]
|
32
|
+
def ui
|
33
|
+
self.class.ui
|
34
|
+
end
|
35
|
+
|
36
|
+
def requires_one_of(*valid_options)
|
37
|
+
valid_options = valid_options.flatten
|
38
|
+
|
39
|
+
return if options.slice(*valid_options).any?
|
40
|
+
|
41
|
+
valid_cli_arguments = valid_options.map { |key|
|
42
|
+
key.to_s.dasherize.prepend('--')
|
43
|
+
}
|
44
|
+
|
45
|
+
ui.say "Requires one of #{valid_cli_arguments.join(', ')}"
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/mb/cli/shell.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module MotherBrain
|
2
|
+
module Cli
|
3
|
+
module Shell
|
4
|
+
autoload :Basic, 'mb/cli/shell/basic'
|
5
|
+
autoload :Color, 'mb/cli/shell/color'
|
6
|
+
autoload :Ext, 'mb/cli/shell/ext'
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_writer :shell
|
10
|
+
|
11
|
+
# Returns the shell used in the motherbrain CLI. If you are in a Unix platform
|
12
|
+
# it will use a colored shell, otherwise it will use a color-less one.
|
13
|
+
#
|
14
|
+
# @return [Shell::Basic, Shell::Color]
|
15
|
+
def shell
|
16
|
+
@shell ||= if ENV['MB_SHELL'] && ENV['MB_SHELL'].size > 0
|
17
|
+
Shell.const_get(ENV['MB_SHELL'].capitalize)
|
18
|
+
elsif Buff::Platform.windows? && !ENV['ANSICON']
|
19
|
+
Shell::Basic
|
20
|
+
else
|
21
|
+
Shell::Color
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
::Thor::Base.shell = shell
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|