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