motherbrain 1.3.0 → 1.4.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/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
         |