motherbrain 1.2.1 → 1.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/lib/mb/api/v1/chef_endpoint.rb +48 -0
- data/lib/mb/api/v1.rb +2 -0
- data/lib/mb/cli_gateway.rb +30 -1
- data/lib/mb/command_runner.rb +2 -2
- data/lib/mb/errors.rb +5 -0
- data/lib/mb/node_querier.rb +57 -0
- data/lib/mb/version.rb +1 -1
- data/motherbrain.gemspec +1 -1
- data/spec/unit/mb/api/v1/chef_endpoint_spec.rb +75 -0
- data/spec/unit/mb/command_runner_spec.rb +16 -1
- data/spec/unit/mb/node_querier_spec.rb +52 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acc003650c5db20ee4a4198443bfc04339a538e9
|
4
|
+
data.tar.gz: ec7dbd88bac26101aa0029882106b775352025f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c55553d715c7e67ac0a8627f3bffec8ce9ae47577c1601aa32242f75dade46acbb1d8614840df5ce8fddba26a028c91d91921fc88e0856aa5d98336e4811a0d6
|
7
|
+
data.tar.gz: 3f7d389d0ddcf5e067c417ada1412ff825710a3219bf83283808ff62bdf48ccf130ff0a5d8d6d97470b3a53e9c03eb1f0d8f9fffe17f8b606ce2bcc5ec233389
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# 1.3.0
|
2
|
+
|
3
|
+
* [#711](https://github.com/RiotGames/motherbrain/pull/711) Implement a new command for upgrading a node or environment's Omnibus Chef installation
|
4
|
+
* [#708](https://github.com/RiotGames/motherbrain/pull/708) Fix a bug when node filtering would reduce the nodes to 0
|
5
|
+
|
1
6
|
# 1.2.1
|
2
7
|
|
3
8
|
* [#705](https://github.com/RiotGames/motherbrain/pull/705) Make connector_for_os public and ensure it is used for environment upgrades
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module MotherBrain::API
|
2
|
+
class V1
|
3
|
+
class ChefEndpoint < MB::API::Endpoint
|
4
|
+
helpers MB::API::Helpers
|
5
|
+
|
6
|
+
rescue_from MB::OmnibusUpgradeError do |ex|
|
7
|
+
rack_response(ex.to_json, 400, "Content-type" => "application/json")
|
8
|
+
end
|
9
|
+
|
10
|
+
namespace 'chef' do
|
11
|
+
|
12
|
+
desc "Remove Chef from node and purge it's data from the Chef server"
|
13
|
+
params do
|
14
|
+
requires :hostname, type: String, desc: "the hostname of the node to purge"
|
15
|
+
optional :skip_chef, type: Boolean, desc: "Skip removing the Chef installation from the node"
|
16
|
+
end
|
17
|
+
post 'purge' do
|
18
|
+
node_querier.async_purge(params[:hostname], params.slice(:skip_chef).freeze)
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Upgrades the provided node and an environment of node's Omnibus Chef installation"
|
22
|
+
params do
|
23
|
+
requires :version, type: String, desc: "the version of omnibus to upgrade to"
|
24
|
+
optional :environment_id, type: String, desc: "an environment to upgrade"
|
25
|
+
optional :host, type: String, desc: "a host to upgrade"
|
26
|
+
optional :prerelease, type: Boolean, desc: "boolean to use a prerelease version of Chef"
|
27
|
+
optional :direct_url, type: String, desc: "a direct URL to a Omnibus binary file"
|
28
|
+
end
|
29
|
+
post 'upgrade' do
|
30
|
+
nodes = nil
|
31
|
+
host = params[:host]
|
32
|
+
environment_id = params[:environment_id]
|
33
|
+
|
34
|
+
raise MB::OmnibusUpgradeError.new("Need to provide one of :environment_id or :host") if host.nil? && environment_id.nil?
|
35
|
+
raise MB::OmnibusUpgradeError.new("Both :environment_id and :host were provided") if !host.nil? && !environment_id.nil?
|
36
|
+
|
37
|
+
if host
|
38
|
+
node_object = Ridley::NodeObject.new(host, automatic: { fqdn: host })
|
39
|
+
nodes = [node_object]
|
40
|
+
elsif environment_id
|
41
|
+
nodes = environment_manager.nodes_for_environment(params[:environment_id])
|
42
|
+
end
|
43
|
+
node_querier.async_upgrade_omnibus(params[:version], nodes, params.slice(:prerelease, :direct_url).freeze)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/mb/api/v1.rb
CHANGED
@@ -6,6 +6,7 @@ module MotherBrain::API
|
|
6
6
|
require_relative 'v1/environments_endpoint'
|
7
7
|
require_relative 'v1/jobs_endpoint'
|
8
8
|
require_relative 'v1/plugins_endpoint'
|
9
|
+
require_relative 'v1/chef_endpoint'
|
9
10
|
|
10
11
|
version 'v1', using: :header, vendor: 'motherbrain'
|
11
12
|
format :json
|
@@ -41,6 +42,7 @@ module MotherBrain::API
|
|
41
42
|
mount V1::JobsEndpoint
|
42
43
|
mount V1::EnvironmentsEndpoint
|
43
44
|
mount V1::PluginsEndpoint
|
45
|
+
mount V1::ChefEndpoint
|
44
46
|
add_swagger_documentation
|
45
47
|
|
46
48
|
if MB.testing?
|
data/lib/mb/cli_gateway.rb
CHANGED
@@ -234,7 +234,8 @@ module MotherBrain
|
|
234
234
|
"template",
|
235
235
|
"purge",
|
236
236
|
"disable",
|
237
|
-
"enable"
|
237
|
+
"enable",
|
238
|
+
"upgrade_omnibus"
|
238
239
|
].freeze
|
239
240
|
|
240
241
|
CREATE_ENVIRONMENT_TASKS = [
|
@@ -334,6 +335,34 @@ module MotherBrain
|
|
334
335
|
CliClient.new(job).display
|
335
336
|
end
|
336
337
|
|
338
|
+
method_option :host,
|
339
|
+
type: :string,
|
340
|
+
desc: "A hostname for the node to be upgraded"
|
341
|
+
method_option :prerelease,
|
342
|
+
type: :boolean,
|
343
|
+
desc: "Boolean to install a prerelease version of Chef",
|
344
|
+
default: false
|
345
|
+
method_option :direct_url,
|
346
|
+
type: :string,
|
347
|
+
desc: "A URL pointing directly to a Chef package to install"
|
348
|
+
desc "upgrade_omnibus VERSION", "Upgrades the Omnibus Chef installation on a Chef Environment of nodes to a specified VERSION."
|
349
|
+
def upgrade_omnibus(version)
|
350
|
+
nodes = nil
|
351
|
+
if options["host"]
|
352
|
+
host = options["host"]
|
353
|
+
node_object = Ridley::NodeObject.new(host, automatic: { fqdn: host })
|
354
|
+
nodes = [node_object]
|
355
|
+
elsif options["environment"]
|
356
|
+
nodes = environment_manager.nodes_for_environment(options["environment"])
|
357
|
+
end
|
358
|
+
if nodes.nil?
|
359
|
+
ui.error "Error - you need to either define a host (--host) or an environment (-e) to operate on."
|
360
|
+
else
|
361
|
+
job = node_querier.async_upgrade_omnibus(version, nodes, options.to_hash.symbolize_keys)
|
362
|
+
CliClient.new(job).display
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
337
366
|
method_option :force,
|
338
367
|
type: :boolean,
|
339
368
|
desc: "Perform HOST enable even if the environment is locked",
|
data/lib/mb/command_runner.rb
CHANGED
@@ -124,10 +124,10 @@ module MotherBrain
|
|
124
124
|
group.nodes(environment)
|
125
125
|
end.uniq
|
126
126
|
|
127
|
-
return unless nodes.any?
|
128
|
-
|
129
127
|
nodes = MB::NodeFilter.filter(node_filter, nodes) if node_filter
|
130
128
|
|
129
|
+
return unless nodes.any?
|
130
|
+
|
131
131
|
if options[:any]
|
132
132
|
nodes = nodes.sample(options[:any])
|
133
133
|
end
|
data/lib/mb/errors.rb
CHANGED
data/lib/mb/node_querier.rb
CHANGED
@@ -279,6 +279,26 @@ module MotherBrain
|
|
279
279
|
job.ticket
|
280
280
|
end
|
281
281
|
|
282
|
+
# Asynchronously upgrade the Omnibus installation of Chef on the given nodes
|
283
|
+
# to a specific version.
|
284
|
+
#
|
285
|
+
# @param [String] version
|
286
|
+
# the version of Chef to upgrade to
|
287
|
+
# @param [Array<Ridley::NodeObject>] nodes
|
288
|
+
# the node(s) to upgrade omnibus on
|
289
|
+
#
|
290
|
+
# @option options [Boolean] :prerelease
|
291
|
+
# whether or not to use a prerelease version of Chef
|
292
|
+
# @option options [String] :direct_url
|
293
|
+
# a URL pointing directly to a Chef package to install
|
294
|
+
#
|
295
|
+
# @return [Mb::JobTicket]
|
296
|
+
def async_upgrade_omnibus(version, nodes, options = {})
|
297
|
+
job = Job.new(:upgrade_omnibus)
|
298
|
+
async(:upgrade_omnibus, job, version, nodes, options)
|
299
|
+
job.ticket
|
300
|
+
end
|
301
|
+
|
282
302
|
# Asynchronously disable a node to stop services @host and prevent
|
283
303
|
# chef-client from being run on @host until @host is reenabled
|
284
304
|
#
|
@@ -353,6 +373,43 @@ module MotherBrain
|
|
353
373
|
job.terminate if job && job.alive?
|
354
374
|
end
|
355
375
|
|
376
|
+
# Upgrades the Omnibus installation of Chef on a specific node(s) to
|
377
|
+
# a specific version.
|
378
|
+
#
|
379
|
+
# @param [MB::Job] job
|
380
|
+
# @param [String] version
|
381
|
+
# the version of Chef to upgrade to
|
382
|
+
# @param [Array<Ridley::NodeObject>] nodes
|
383
|
+
# the node(s) to upgrade omnibus on
|
384
|
+
#
|
385
|
+
# @option options [Boolean] :prerelease
|
386
|
+
# whether or not to use a prerelease version of Chef
|
387
|
+
# @option options [String] :direct_url
|
388
|
+
# a URL pointing directly to a Chef package to install
|
389
|
+
#
|
390
|
+
# @return [MB::Job]
|
391
|
+
def upgrade_omnibus(job, version, nodes, options = {})
|
392
|
+
futures = Array.new
|
393
|
+
options = options.merge(chef_version: version)
|
394
|
+
|
395
|
+
hostnames = nodes.collect(&:public_hostname)
|
396
|
+
job.report_running("Upgrading Omnibus Chef installation on #{hostnames}")
|
397
|
+
|
398
|
+
hostnames.each do |hostname|
|
399
|
+
futures << chef_connection.node.future(:update_omnibus, hostname, options)
|
400
|
+
end
|
401
|
+
|
402
|
+
begin
|
403
|
+
safe_remote { futures.map(&:value) }
|
404
|
+
rescue RemoteCommandError => e
|
405
|
+
job.report_failure
|
406
|
+
end
|
407
|
+
|
408
|
+
job.report_success
|
409
|
+
ensure
|
410
|
+
job.terminate if job && job.alive?
|
411
|
+
end
|
412
|
+
|
356
413
|
# Remove explicit service state on @host and remove disabled entry
|
357
414
|
# from run list to allow chef-client to run on @host
|
358
415
|
#
|
data/lib/mb/version.rb
CHANGED
data/motherbrain.gemspec
CHANGED
@@ -44,7 +44,7 @@ Gem::Specification.new do |s|
|
|
44
44
|
s.add_dependency 'net-ssh'
|
45
45
|
s.add_dependency 'net-sftp'
|
46
46
|
s.add_dependency 'solve', '~> 1.1'
|
47
|
-
s.add_dependency 'ridley-connectors', '~> 2.
|
47
|
+
s.add_dependency 'ridley-connectors', '~> 2.2'
|
48
48
|
s.add_dependency 'thor', '~> 0.18.0'
|
49
49
|
s.add_dependency 'faraday', '~> 0.9'
|
50
50
|
s.add_dependency 'multi_json'
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MB::API::V1::ChefEndpoint do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
before(:all) { MB::RestGateway.start(port: 26101) }
|
7
|
+
after(:all) { MB::RestGateway.stop }
|
8
|
+
let(:app) { MB::RestGateway.instance.app }
|
9
|
+
let(:job) { MB::Job.new(:test) }
|
10
|
+
|
11
|
+
describe "POST /chef/purge" do
|
12
|
+
let(:hostname) { "foo.bar.com" }
|
13
|
+
|
14
|
+
it "returns 201" do
|
15
|
+
node_querier.should_receive(:async_purge).with(hostname, anything()).and_return(job.ticket)
|
16
|
+
json_post "/chef/purge",
|
17
|
+
MultiJson.dump(hostname: hostname)
|
18
|
+
last_response.status.should == 201
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "POST /chef/upgrade" do
|
23
|
+
let(:version) { "1.2.3" }
|
24
|
+
let(:environment_id) { "rpsec_test" }
|
25
|
+
let(:host) { "1.1.1.1" }
|
26
|
+
|
27
|
+
context "when neither environment_id nor host are provided" do
|
28
|
+
it "returns a 400" do
|
29
|
+
json_post "/chef/upgrade",
|
30
|
+
MultiJson.dump(version: version)
|
31
|
+
|
32
|
+
last_response.status.should == 400
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when both environment_id and host are provided" do
|
37
|
+
it "returns a 400" do
|
38
|
+
json_post "/chef/upgrade",
|
39
|
+
MultiJson.dump(version: version, environment_id: environment_id, host: host)
|
40
|
+
|
41
|
+
last_response.status.should == 400
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when host is provided" do
|
46
|
+
let(:node_object) { Ridley::NodeObject.new(host, automatic: { fqdn: host }) }
|
47
|
+
|
48
|
+
it "returns 201" do
|
49
|
+
node_querier.should_receive(:async_upgrade_omnibus).with(version, [node_object], anything()).and_return(job.ticket)
|
50
|
+
|
51
|
+
json_post "/chef/upgrade",
|
52
|
+
MultiJson.dump(version: version, host: host)
|
53
|
+
|
54
|
+
last_response.status.should == 201
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when environment_id is provided" do
|
59
|
+
let(:nodes) { ["node1", "node2", "node3"] }
|
60
|
+
|
61
|
+
before do
|
62
|
+
environment_manager.stub(:nodes_for_environment).and_return(nodes)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns 201" do
|
66
|
+
node_querier.should_receive(:async_upgrade_omnibus).with(version, nodes, anything()).and_return(job.ticket)
|
67
|
+
|
68
|
+
json_post "/chef/upgrade",
|
69
|
+
MultiJson.dump(version: version, environment_id: environment_id)
|
70
|
+
|
71
|
+
last_response.status.should == 201
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -7,7 +7,7 @@ describe MB::CommandRunner do
|
|
7
7
|
described_class.new(job, environment, scope, command_block, node_filter)
|
8
8
|
}
|
9
9
|
|
10
|
-
let(:scope) { MB::Plugin.new(double(valid?: true)) }
|
10
|
+
let(:scope) { MB::Plugin.new(double(valid?: true, name: 'cookbook')) }
|
11
11
|
|
12
12
|
let(:action_1) { double('action_1', name: "action 1", run: nil) }
|
13
13
|
let(:action_2) { double('action_2', name: "action 2", run: nil) }
|
@@ -39,6 +39,7 @@ describe MB::CommandRunner do
|
|
39
39
|
MB::CommandRunner::CleanRoom.stub_chain(:new, :actions).and_return(actions)
|
40
40
|
|
41
41
|
scope.stub(:group!).with("master_group").and_return(master_group)
|
42
|
+
scope.stub(:group!).with("slave_group").and_return(slave_group)
|
42
43
|
end
|
43
44
|
|
44
45
|
describe "#on" do
|
@@ -126,6 +127,20 @@ describe MB::CommandRunner do
|
|
126
127
|
end
|
127
128
|
end
|
128
129
|
|
130
|
+
context "when a group's nodes are filtered to 0" do
|
131
|
+
let(:node_filter) { "c.riotgames.com" }
|
132
|
+
let(:command_block) {
|
133
|
+
proc {
|
134
|
+
on("master_group") {}
|
135
|
+
on("slave_group") {}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
it "skips groups that have all their nodes filtered out" do
|
140
|
+
command_runner
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
129
144
|
context "with max_concurrent: 1" do
|
130
145
|
let(:command_block) {
|
131
146
|
proc {
|
@@ -374,6 +374,58 @@ describe MB::NodeQuerier do
|
|
374
374
|
end
|
375
375
|
end
|
376
376
|
|
377
|
+
describe "#async_upgrade_omnibus" do
|
378
|
+
let(:host) { "192.168.1.1" }
|
379
|
+
let(:nodes) { [Ridley::NodeObject.new(host, automatic: { fqdn: host })] }
|
380
|
+
let(:version) { "11.12.4" }
|
381
|
+
let(:options) { Hash.new }
|
382
|
+
|
383
|
+
it "creates a Job and delegates to #upgrade_omnibus" do
|
384
|
+
ticket = double('ticket')
|
385
|
+
job = double('job', ticket: ticket)
|
386
|
+
MB::Job.should_receive(:new).and_return(job)
|
387
|
+
subject.should_receive(:upgrade_omnibus).with(job, version, nodes, options)
|
388
|
+
|
389
|
+
subject.async_upgrade_omnibus(version, nodes, options)
|
390
|
+
end
|
391
|
+
|
392
|
+
it "returns a JobTicket" do
|
393
|
+
expect(subject.async_purge(host, options)).to be_a(MB::JobRecord)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
describe "#upgrade_omnibus" do
|
398
|
+
let(:host) { "192.168.1.1" }
|
399
|
+
let(:nodes) { [Ridley::NodeObject.new(host, automatic: { fqdn: host })] }
|
400
|
+
let(:version) { "11.12.4" }
|
401
|
+
let(:options) do
|
402
|
+
{
|
403
|
+
chef_version: version
|
404
|
+
}
|
405
|
+
end
|
406
|
+
let(:job) { MB::Job.new(:upgrade_omnibus) }
|
407
|
+
let(:future_stub) { double(Celluloid::Future, value: nil) }
|
408
|
+
|
409
|
+
before do
|
410
|
+
subject.chef_connection.
|
411
|
+
stub_chain(:node, :future).
|
412
|
+
with(:update_omnibus, host, options).
|
413
|
+
and_return(future_stub)
|
414
|
+
end
|
415
|
+
|
416
|
+
context "when there are no errors" do
|
417
|
+
it "reports success" do
|
418
|
+
job.should_receive(:report_success)
|
419
|
+
subject.upgrade_omnibus(job, version, nodes, options)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
it "terminates the job" do
|
424
|
+
subject.upgrade_omnibus(job, version, nodes, options)
|
425
|
+
expect(job).to_not be_alive
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
377
429
|
describe "#async_disable" do
|
378
430
|
let(:host) { "192.168.1.1" }
|
379
431
|
let(:options) { Hash.new }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motherbrain
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamie Winsor
|
@@ -15,7 +15,7 @@ authors:
|
|
15
15
|
autorequire:
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
|
-
date: 2014-05-
|
18
|
+
date: 2014-05-20 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: celluloid
|
@@ -149,14 +149,14 @@ dependencies:
|
|
149
149
|
requirements:
|
150
150
|
- - ~>
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '2.
|
152
|
+
version: '2.2'
|
153
153
|
type: :runtime
|
154
154
|
prerelease: false
|
155
155
|
version_requirements: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
157
|
- - ~>
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: '2.
|
159
|
+
version: '2.2'
|
160
160
|
- !ruby/object:Gem::Dependency
|
161
161
|
name: thor
|
162
162
|
requirement: !ruby/object:Gem::Requirement
|
@@ -388,6 +388,7 @@ files:
|
|
388
388
|
- lib/mb/api/endpoint.rb
|
389
389
|
- lib/mb/api/helpers.rb
|
390
390
|
- lib/mb/api/v1.rb
|
391
|
+
- lib/mb/api/v1/chef_endpoint.rb
|
391
392
|
- lib/mb/api/v1/config_endpoint.rb
|
392
393
|
- lib/mb/api/v1/environments_endpoint.rb
|
393
394
|
- lib/mb/api/v1/jobs_endpoint.rb
|
@@ -517,6 +518,7 @@ files:
|
|
517
518
|
- spec/support/spec_helpers.rb
|
518
519
|
- spec/unit/mb/api/application_spec.rb
|
519
520
|
- spec/unit/mb/api/helpers_spec.rb
|
521
|
+
- spec/unit/mb/api/v1/chef_endpoint_spec.rb
|
520
522
|
- spec/unit/mb/api/v1/config_endpoint_spec.rb
|
521
523
|
- spec/unit/mb/api/v1/environments_endpoint_spec.rb
|
522
524
|
- spec/unit/mb/api/v1/jobs_endpoint_spec.rb
|
@@ -666,6 +668,7 @@ test_files:
|
|
666
668
|
- spec/support/spec_helpers.rb
|
667
669
|
- spec/unit/mb/api/application_spec.rb
|
668
670
|
- spec/unit/mb/api/helpers_spec.rb
|
671
|
+
- spec/unit/mb/api/v1/chef_endpoint_spec.rb
|
669
672
|
- spec/unit/mb/api/v1/config_endpoint_spec.rb
|
670
673
|
- spec/unit/mb/api/v1/environments_endpoint_spec.rb
|
671
674
|
- spec/unit/mb/api/v1/jobs_endpoint_spec.rb
|