motherbrain 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mb/api/v1.rb +28 -6
- data/lib/mb/api/v1/server_control_endpoint.rb +37 -0
- data/lib/mb/application.rb +35 -2
- data/lib/mb/berkshelf.rb +2 -0
- data/lib/mb/errors.rb +26 -0
- data/lib/mb/plugin_manager.rb +5 -0
- data/lib/mb/rest_gateway.rb +7 -2
- data/lib/mb/version.rb +1 -1
- data/spec/unit/mb/api/v1/server_control_endpoint_spec.rb +54 -0
- data/spec/unit/mb/application_spec.rb +14 -0
- data/spec/unit/mb/rest_gateway_spec.rb +15 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfdaf1022206cdd6053520eed112b1fedc5c25a8
|
4
|
+
data.tar.gz: 5b86141638b4849c04c864759e9a0546cca56ff4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3be6473cedd6894ac603158363ddfb0249fa9bea09c747d8ef1957cdb5a82cd0976f56cb5a6857a692929656a2d51aa3128438ff766e1116d61d00b522debda
|
7
|
+
data.tar.gz: 2017c5767c5f3aa705fd9dd991b65b76f4f7b5dd113192702a7eb03911d3c1b8a5a7ca6fd47bac11c3f6a5c2d6157d6c098a376d233f5d87390ef41ff1a1e794
|
data/lib/mb/api/v1.rb
CHANGED
@@ -7,18 +7,21 @@ module MotherBrain::API
|
|
7
7
|
require_relative 'v1/jobs_endpoint'
|
8
8
|
require_relative 'v1/plugins_endpoint'
|
9
9
|
require_relative 'v1/chef_endpoint'
|
10
|
+
require_relative 'v1/server_control_endpoint'
|
10
11
|
|
11
12
|
version 'v1', using: :header, vendor: 'motherbrain'
|
12
13
|
format :json
|
13
14
|
default_format :json
|
14
15
|
|
15
|
-
|
16
|
+
JSON_CONTENT_TYPE = {"Content-type" => "application/json"}
|
17
|
+
|
18
|
+
rescue_from Grape::Exceptions::Validation do |ex|
|
16
19
|
body = MultiJson.encode(
|
17
|
-
status:
|
18
|
-
message:
|
19
|
-
param:
|
20
|
+
status: ex.status,
|
21
|
+
message: ex.message,
|
22
|
+
param: ex.param
|
20
23
|
)
|
21
|
-
rack_response(body,
|
24
|
+
rack_response(body, ex.status, JSON_CONTENT_TYPE)
|
22
25
|
end
|
23
26
|
|
24
27
|
rescue_from :all do |ex|
|
@@ -29,13 +32,31 @@ module MotherBrain::API
|
|
29
32
|
MultiJson.encode(code: -1, message: ex.message)
|
30
33
|
end
|
31
34
|
|
32
|
-
|
35
|
+
http_status_code = if ex.is_a?(MB::APIError)
|
36
|
+
ex.http_status_code
|
37
|
+
else
|
38
|
+
500
|
39
|
+
end
|
40
|
+
|
41
|
+
rack_response(body, http_status_code, JSON_CONTENT_TYPE)
|
33
42
|
end
|
34
43
|
|
35
44
|
before do
|
36
45
|
header['Access-Control-Allow-Origin'] = '*'
|
37
46
|
header['Access-Control-Request-Method'] = '*'
|
38
47
|
header.delete('Transfer-Encoding')
|
48
|
+
|
49
|
+
server_control_endpoint = false
|
50
|
+
MB::API::V1::ServerControlEndpoint.endpoints.each do |endpoint|
|
51
|
+
endpoint.routes.each do |route|
|
52
|
+
if request.path =~ route.route_compiled
|
53
|
+
server_control_endpoint = true
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
raise MB::ApplicationPaused.new if MB::Application.paused? && !server_control_endpoint
|
39
60
|
end
|
40
61
|
|
41
62
|
mount V1::ConfigEndpoint
|
@@ -43,6 +64,7 @@ module MotherBrain::API
|
|
43
64
|
mount V1::EnvironmentsEndpoint
|
44
65
|
mount V1::PluginsEndpoint
|
45
66
|
mount V1::ChefEndpoint
|
67
|
+
mount V1::ServerControlEndpoint
|
46
68
|
add_swagger_documentation
|
47
69
|
|
48
70
|
if MB.testing?
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module MotherBrain::API
|
2
|
+
class V1
|
3
|
+
class ServerControlEndpoint < MB::API::Endpoint
|
4
|
+
helpers MB::Mixin::Services
|
5
|
+
|
6
|
+
desc "resume the server, preventing new requests from being processed"
|
7
|
+
put 'resume' do
|
8
|
+
MB::Application.resume
|
9
|
+
server_status
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "pause the server, preventing new requests from being processed"
|
13
|
+
put 'pause' do
|
14
|
+
MB::Application.pause
|
15
|
+
server_status
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "stop the server"
|
19
|
+
put 'stop' do
|
20
|
+
MB::Application.stop
|
21
|
+
status(202)
|
22
|
+
server_status
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "get the server status"
|
26
|
+
get 'status' do
|
27
|
+
server_status
|
28
|
+
end
|
29
|
+
|
30
|
+
helpers do
|
31
|
+
def server_status
|
32
|
+
{server_status: MB::Application.status}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/mb/application.rb
CHANGED
@@ -28,6 +28,12 @@ module MotherBrain
|
|
28
28
|
# @example running the application in the background
|
29
29
|
# MB::Application.run!(config)
|
30
30
|
module Application
|
31
|
+
module Status
|
32
|
+
RUNNING = :running
|
33
|
+
PAUSED = :paused
|
34
|
+
STOPPING = :stopping
|
35
|
+
end
|
36
|
+
|
31
37
|
class << self
|
32
38
|
extend Forwardable
|
33
39
|
include MB::Mixin::Services
|
@@ -95,7 +101,29 @@ module MotherBrain
|
|
95
101
|
|
96
102
|
# Stop the running application
|
97
103
|
def stop
|
98
|
-
instance.
|
104
|
+
instance.async_interrupt(3)
|
105
|
+
@status = Status::STOPPING
|
106
|
+
end
|
107
|
+
|
108
|
+
# Set the application state to paused. This allows actors to
|
109
|
+
# continue processing, but causes the RestGateway not to accept
|
110
|
+
# new requests.
|
111
|
+
#
|
112
|
+
# See: MotherBrain::API::V1 L51, 'before' block
|
113
|
+
def pause
|
114
|
+
@status = Status::PAUSED
|
115
|
+
end
|
116
|
+
|
117
|
+
def resume
|
118
|
+
@status = Status::RUNNING
|
119
|
+
end
|
120
|
+
|
121
|
+
def paused?
|
122
|
+
status == Status::PAUSED
|
123
|
+
end
|
124
|
+
|
125
|
+
def status
|
126
|
+
@status ||= Status::RUNNING
|
99
127
|
end
|
100
128
|
end
|
101
129
|
|
@@ -135,7 +163,12 @@ module MotherBrain
|
|
135
163
|
@registry[:ridley].async.configure(new_config.to_ridley)
|
136
164
|
end
|
137
165
|
|
138
|
-
def
|
166
|
+
def async_interrupt(delay = 0)
|
167
|
+
future.interrupt(delay)
|
168
|
+
end
|
169
|
+
|
170
|
+
def interrupt(delay = 0)
|
171
|
+
Celluloid.sleep(delay) if delay > 0
|
139
172
|
interrupt_mutex.synchronize do
|
140
173
|
unless interrupted
|
141
174
|
@interrupted = true
|
data/lib/mb/berkshelf.rb
CHANGED
@@ -63,6 +63,8 @@ module MotherBrain
|
|
63
63
|
|
64
64
|
def initialize(berksfile_lock_path)
|
65
65
|
@berksfile_lock = ::Berkshelf::Lockfile.from_file(berksfile_lock_path)
|
66
|
+
rescue ::Berkshelf::LockfileParserError
|
67
|
+
log.warn "Unable to parse Berksfile.lock - maybe it's an old format?"
|
66
68
|
end
|
67
69
|
|
68
70
|
# Return a hash of all of the cookbook versions found in the Berksfile.lock
|
data/lib/mb/errors.rb
CHANGED
@@ -89,6 +89,23 @@ module MotherBrain
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
+
class APIError < MBError
|
93
|
+
DEFAULT_HTTP_STATUS_CODE = 500
|
94
|
+
|
95
|
+
class << self
|
96
|
+
# @param [Integer] code
|
97
|
+
#
|
98
|
+
# @return [Integer]
|
99
|
+
def http_status_code(code = DEFAULT_HTTP_STATUS_CODE)
|
100
|
+
@exit_code ||= code
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def http_status_code
|
105
|
+
self.class.http_status_code
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
92
109
|
# Internal errors
|
93
110
|
class InternalError < MBError
|
94
111
|
exit_code(99)
|
@@ -695,4 +712,13 @@ module MotherBrain
|
|
695
712
|
exit_code(25)
|
696
713
|
error_code(3029)
|
697
714
|
end
|
715
|
+
|
716
|
+
class ApplicationPaused < APIError
|
717
|
+
error_code(3330)
|
718
|
+
http_status_code(503)
|
719
|
+
|
720
|
+
def message
|
721
|
+
"MotherBrain is paused. It will not accept new requests until it is resumed."
|
722
|
+
end
|
723
|
+
end
|
698
724
|
end
|
data/lib/mb/plugin_manager.rb
CHANGED
@@ -322,6 +322,7 @@ module MotherBrain
|
|
322
322
|
scratch_dir = FileSystem.tmpdir("cbplugin")
|
323
323
|
metadata_path = File.join(scratch_dir, CookbookMetadata::JSON_FILENAME)
|
324
324
|
plugin_path = File.join(scratch_dir, Plugin::PLUGIN_FILENAME)
|
325
|
+
lockfile_path = File.join(scratch_dir, Berkshelf::Lockfile::BERKSFILE_LOCK)
|
325
326
|
|
326
327
|
File.write(metadata_path, resource.metadata.to_json)
|
327
328
|
|
@@ -329,6 +330,10 @@ module MotherBrain
|
|
329
330
|
raise PluginLoadError, "failure downloading plugin file for #{resource.name}"
|
330
331
|
end
|
331
332
|
|
333
|
+
unless resource.download_file(:root_file, Berkshelf::Lockfile::BERKSFILE_LOCK, lockfile_path)
|
334
|
+
log.info "No Berksfile.lock found for #{resource.name} - won't be able to use cookbook versions from lockfile"
|
335
|
+
end
|
336
|
+
|
332
337
|
load_file(scratch_dir, options)
|
333
338
|
rescue PluginSyntaxError, PluginLoadError => ex
|
334
339
|
err_msg = "could not load remote plugin #{name} (#{version}): #{ex.message}"
|
data/lib/mb/rest_gateway.rb
CHANGED
@@ -29,7 +29,7 @@ module MotherBrain
|
|
29
29
|
|
30
30
|
include MB::Logging
|
31
31
|
|
32
|
-
DEFAULT_PORT = ENV["PORT"].to_i
|
32
|
+
DEFAULT_PORT = ENV["PORT"] ? ENV["PORT"].to_i : 26100
|
33
33
|
|
34
34
|
DEFAULT_OPTIONS = {
|
35
35
|
host: '0.0.0.0',
|
@@ -59,7 +59,12 @@ module MotherBrain
|
|
59
59
|
options[:Port] = options[:port]
|
60
60
|
|
61
61
|
log.info { "REST Gateway listening on #{options[:host]}:#{options[:port]}" }
|
62
|
-
|
62
|
+
|
63
|
+
begin
|
64
|
+
super(app, options)
|
65
|
+
rescue Errno::EADDRINUSE
|
66
|
+
log.fatal { "Port #{options[:port]} is already in use. Unable to start rest gateway." }
|
67
|
+
end
|
63
68
|
end
|
64
69
|
|
65
70
|
private
|
data/lib/mb/version.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MB::API::V1::ServerControlEndpoint do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
before(:all) { MB::RestGateway.start(port: 26101) }
|
7
|
+
after(:all) { MB::RestGateway.stop }
|
8
|
+
after(:each) { MB::Application.resume }
|
9
|
+
let(:app) { MB::RestGateway.instance.app }
|
10
|
+
|
11
|
+
describe "PUT /pause" do
|
12
|
+
it "pauses the server" do
|
13
|
+
put '/pause'
|
14
|
+
last_response.status.should == 200
|
15
|
+
JSON.parse(last_response.body).should eq("server_status" => "paused")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "prevents actions while the server is paused" do
|
19
|
+
put '/pause'
|
20
|
+
json_post "/environments/environmentname/upgrade",
|
21
|
+
MultiJson.dump(plugin: { name: 'pluginname', version: '1.0.0' })
|
22
|
+
last_response.status.should == 503
|
23
|
+
JSON.parse(last_response.body).should eq("code"=>3330, "message"=>"MotherBrain is paused. It will not accept new requests until it is resumed.")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "PUT /resume" do
|
28
|
+
before do
|
29
|
+
MB::Application.pause
|
30
|
+
end
|
31
|
+
|
32
|
+
it "resumes the server" do
|
33
|
+
put '/resume'
|
34
|
+
last_response.status.should == 200
|
35
|
+
JSON.parse(last_response.body).should eq("server_status" => "running")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "allows actions while the server is resumed" do
|
39
|
+
put '/resume'
|
40
|
+
json_post "/environments/environmentname/upgrade",
|
41
|
+
MultiJson.dump(plugin: { name: 'pluginname', version: '1.0.0' })
|
42
|
+
last_response.status.should == 201
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "PUT /stop" do
|
47
|
+
it "stops the server" do
|
48
|
+
MB::Application.instance.should_receive(:async_interrupt).with(3)
|
49
|
+
put '/stop'
|
50
|
+
last_response.status.should == 202
|
51
|
+
JSON.parse(last_response.body).should eq("server_status" => "stopping")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -15,5 +15,19 @@ describe MB::Application do
|
|
15
15
|
subject.config.should be_a(MB::Config)
|
16
16
|
end
|
17
17
|
end
|
18
|
+
|
19
|
+
describe "::pause" do
|
20
|
+
it "should pause" do
|
21
|
+
subject.pause
|
22
|
+
expect(subject.paused?).to eq(true)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "::resume" do
|
27
|
+
it "should resume" do
|
28
|
+
subject.resume
|
29
|
+
expect(subject.paused?).to eq(false)
|
30
|
+
end
|
31
|
+
end
|
18
32
|
end
|
19
33
|
end
|
@@ -10,4 +10,19 @@ describe MB::RestGateway do
|
|
10
10
|
subject.app.should be_a(MB::API::Application)
|
11
11
|
end
|
12
12
|
end
|
13
|
+
|
14
|
+
describe "constants" do
|
15
|
+
it "should set DEFAULT_PORT to $PORT" do
|
16
|
+
p = 12345
|
17
|
+
ENV["PORT"] = p.to_s
|
18
|
+
load File.join(MB.app_root, "lib", "mb", "rest_gateway.rb")
|
19
|
+
expect(MB::RestGateway::DEFAULT_PORT).to eq(p)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should set DEFAULT_PORT to 26100 if $PORT is not set" do
|
23
|
+
ENV.delete("PORT")
|
24
|
+
load File.join(MB.app_root, "lib", "mb", "rest_gateway.rb")
|
25
|
+
expect(MB::RestGateway::DEFAULT_PORT).to eq(26100)
|
26
|
+
end
|
27
|
+
end
|
13
28
|
end
|
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.4.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-30 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: celluloid
|
@@ -393,6 +393,7 @@ files:
|
|
393
393
|
- lib/mb/api/v1/environments_endpoint.rb
|
394
394
|
- lib/mb/api/v1/jobs_endpoint.rb
|
395
395
|
- lib/mb/api/v1/plugins_endpoint.rb
|
396
|
+
- lib/mb/api/v1/server_control_endpoint.rb
|
396
397
|
- lib/mb/api/validators.rb
|
397
398
|
- lib/mb/api/validators/sem_ver.rb
|
398
399
|
- lib/mb/application.rb
|
@@ -523,6 +524,7 @@ files:
|
|
523
524
|
- spec/unit/mb/api/v1/environments_endpoint_spec.rb
|
524
525
|
- spec/unit/mb/api/v1/jobs_endpoint_spec.rb
|
525
526
|
- spec/unit/mb/api/v1/plugins_endpoint_spec.rb
|
527
|
+
- spec/unit/mb/api/v1/server_control_endpoint_spec.rb
|
526
528
|
- spec/unit/mb/api/v1_spec.rb
|
527
529
|
- spec/unit/mb/api/validators/sem_ver_spec.rb
|
528
530
|
- spec/unit/mb/application_spec.rb
|
@@ -622,7 +624,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
622
624
|
version: '0'
|
623
625
|
requirements: []
|
624
626
|
rubyforge_project:
|
625
|
-
rubygems_version: 2.
|
627
|
+
rubygems_version: 2.0.14
|
626
628
|
signing_key:
|
627
629
|
specification_version: 4
|
628
630
|
summary: An orchestrator for Chef
|
@@ -673,6 +675,7 @@ test_files:
|
|
673
675
|
- spec/unit/mb/api/v1/environments_endpoint_spec.rb
|
674
676
|
- spec/unit/mb/api/v1/jobs_endpoint_spec.rb
|
675
677
|
- spec/unit/mb/api/v1/plugins_endpoint_spec.rb
|
678
|
+
- spec/unit/mb/api/v1/server_control_endpoint_spec.rb
|
676
679
|
- spec/unit/mb/api/v1_spec.rb
|
677
680
|
- spec/unit/mb/api/validators/sem_ver_spec.rb
|
678
681
|
- spec/unit/mb/application_spec.rb
|