fleet-api 0.0.1
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 +7 -0
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +48 -0
- data/LICENSE +201 -0
- data/README.md +2 -0
- data/Rakefile +8 -0
- data/fleet-api.gemspec +22 -0
- data/lib/fleet/client/job.rb +44 -0
- data/lib/fleet/client/state.rb +25 -0
- data/lib/fleet/client/unit.rb +32 -0
- data/lib/fleet/client.rb +116 -0
- data/lib/fleet/configuration.rb +44 -0
- data/lib/fleet/connection.rb +23 -0
- data/lib/fleet/error.rb +42 -0
- data/lib/fleet/request.rb +56 -0
- data/lib/fleet/service_definition.rb +63 -0
- data/lib/fleet/version.rb +3 -0
- data/lib/fleet.rb +15 -0
- data/lib/middleware/response/raise_error.rb +37 -0
- data/spec/fleet/client/job_spec.rb +123 -0
- data/spec/fleet/client/state_spec.rb +50 -0
- data/spec/fleet/client/unit_spec.rb +76 -0
- data/spec/fleet/client_spec.rb +247 -0
- data/spec/fleet/configuration_spec.rb +46 -0
- data/spec/fleet/connection_spec.rb +75 -0
- data/spec/fleet/error_spec.rb +29 -0
- data/spec/fleet/request_spec.rb +128 -0
- data/spec/fleet/service_definition_spec.rb +86 -0
- data/spec/fleet_spec.rb +87 -0
- data/spec/middleware/response/raise_error_spec.rb +90 -0
- data/spec/spec_helper.rb +9 -0
- metadata +171 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'fleet/version'
|
2
|
+
|
3
|
+
module Fleet
|
4
|
+
module Request
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
[:get, :head, :put, :post, :delete].each do |method|
|
9
|
+
define_method(method) do |path, options={}, headers={}|
|
10
|
+
request(connection, method, path, options, headers)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def request(connection, method, path, options, headers)
|
15
|
+
options ||= {}
|
16
|
+
|
17
|
+
response = connection.send(method) do |request|
|
18
|
+
request.options[:open_timeout] = open_timeout
|
19
|
+
request.options[:timeout] = read_timeout
|
20
|
+
request.headers = {
|
21
|
+
user_agent: user_agent,
|
22
|
+
accept: 'application/json'
|
23
|
+
}.merge(headers)
|
24
|
+
|
25
|
+
request.path = URI.escape(path)
|
26
|
+
|
27
|
+
case method
|
28
|
+
when :delete, :get, :head
|
29
|
+
request.params = options unless options.empty?
|
30
|
+
when :post, :put
|
31
|
+
if options.key?(:querystring)
|
32
|
+
request.params = options[:querystring]
|
33
|
+
request.body = options[:body]
|
34
|
+
else
|
35
|
+
request.body = options unless options.empty?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
response.body
|
41
|
+
rescue Faraday::Error::ConnectionFailed => ex
|
42
|
+
raise Fleet::ConnectionError, ex.message
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def user_agent
|
48
|
+
ua_chunks = []
|
49
|
+
ua_chunks << "fleet/#{Fleet::VERSION}"
|
50
|
+
ua_chunks << "(#{RUBY_ENGINE}; #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}; #{RUBY_PLATFORM})"
|
51
|
+
ua_chunks << "faraday/#{Faraday::VERSION}"
|
52
|
+
ua_chunks << "(#{adapter})"
|
53
|
+
ua_chunks.join(' ')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module Fleet
|
4
|
+
class ServiceDefinition
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(name, service_def={})
|
9
|
+
@name = name
|
10
|
+
@service_def = service_def
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_unit
|
14
|
+
{
|
15
|
+
'Contents' => unit_body,
|
16
|
+
'Raw' => raw
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_job
|
21
|
+
{
|
22
|
+
'Name' => name,
|
23
|
+
'UnitHash' => sha1_byte_array
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def sha1
|
28
|
+
Digest::SHA1.hexdigest raw
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def unit_body
|
34
|
+
@service_def.each_with_object({}) do |(heading, section), memo|
|
35
|
+
memo[heading] = section.each_with_object({}) do |(key, value), memo|
|
36
|
+
memo[key] = [value]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def raw
|
42
|
+
raw_string = ''
|
43
|
+
|
44
|
+
@service_def.each do |heading, section|
|
45
|
+
raw_string += "[#{heading}]\n"
|
46
|
+
|
47
|
+
if section.is_a?(Enumerable)
|
48
|
+
section.each do |key, value|
|
49
|
+
raw_string += "#{key}=#{value}\n"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
raw_string += "\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
raw_string.chomp
|
57
|
+
end
|
58
|
+
|
59
|
+
def sha1_byte_array
|
60
|
+
Digest::SHA1.digest(raw).unpack('C20')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/fleet.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'json'
|
3
|
+
require 'fleet/error'
|
4
|
+
|
5
|
+
module Middleware
|
6
|
+
module Response
|
7
|
+
|
8
|
+
class RaiseError < Faraday::Response::Middleware
|
9
|
+
|
10
|
+
def on_complete(env)
|
11
|
+
status = env[:status].to_i
|
12
|
+
return unless (400..600).include?(status)
|
13
|
+
|
14
|
+
error = parse_error(env[:body])
|
15
|
+
|
16
|
+
# Find the error class that matches the HTTP status code. Default to
|
17
|
+
# Error if no matching class exists.
|
18
|
+
class_name = Fleet::Error::HTTP_CODE_MAP.fetch(status, 'Error')
|
19
|
+
|
20
|
+
fail Fleet.const_get(class_name).new(
|
21
|
+
error['message'],
|
22
|
+
error['errorCode'],
|
23
|
+
error['cause'])
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def parse_error(body)
|
29
|
+
JSON.parse(body)
|
30
|
+
rescue StandardError
|
31
|
+
{ 'message' => body }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Faraday.register_middleware :response, raise_error: -> { RaiseError }
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fleet::Client::Job do
|
4
|
+
|
5
|
+
subject { Fleet::Client.new }
|
6
|
+
|
7
|
+
let(:response) { double(:response) }
|
8
|
+
|
9
|
+
describe '#list_jobs' do
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(subject).to receive(:get).and_return(response)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'GETs the Fleet job key' do
|
16
|
+
opts = { consistent: true, recursive: true, sorted: true }
|
17
|
+
expect(subject).to receive(:get)
|
18
|
+
.with('v2/keys/_coreos.com/fleet/job', opts)
|
19
|
+
.and_return(response)
|
20
|
+
|
21
|
+
subject.list_jobs
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns the job response' do
|
25
|
+
expect(subject.list_jobs).to eql(response)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#get_job' do
|
30
|
+
|
31
|
+
let(:service_name) { 'foo.service' }
|
32
|
+
|
33
|
+
before do
|
34
|
+
allow(subject).to receive(:get).and_return(response)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'GETs the named Fleet job key' do
|
38
|
+
opts = { consistent: true, recursive: true, sorted: false }
|
39
|
+
expect(subject).to receive(:get)
|
40
|
+
.with("v2/keys/_coreos.com/fleet/job/#{service_name}/object", opts)
|
41
|
+
.and_return(response)
|
42
|
+
|
43
|
+
subject.get_job(service_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns the job response' do
|
47
|
+
expect(subject.get_job(service_name)).to eql(response)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#create_job' do
|
52
|
+
|
53
|
+
let(:service_name) { 'foo.service' }
|
54
|
+
let(:service_def) { { name: service_name } }
|
55
|
+
|
56
|
+
before do
|
57
|
+
allow(subject).to receive(:put).and_return(response)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'PUTs the service def to the Fleet job key' do
|
61
|
+
opts = {
|
62
|
+
querystring: { 'prevExist' => false },
|
63
|
+
body: { value: service_def.to_json }
|
64
|
+
}
|
65
|
+
|
66
|
+
expect(subject).to receive(:put)
|
67
|
+
.with("v2/keys/_coreos.com/fleet/job/#{service_name}/object", opts)
|
68
|
+
.and_return(response)
|
69
|
+
|
70
|
+
subject.create_job(service_name, service_def)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns the job response' do
|
74
|
+
expect(subject.create_job(service_name, service_def)).to eql(response)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#delete_job' do
|
79
|
+
|
80
|
+
let(:service_name) { 'foo.service' }
|
81
|
+
|
82
|
+
before do
|
83
|
+
allow(subject).to receive(:delete).and_return(response)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'DELETEs the named Fleet job key' do
|
87
|
+
opts = { dir: false, recursive: true }
|
88
|
+
expect(subject).to receive(:delete)
|
89
|
+
.with("v2/keys/_coreos.com/fleet/job/#{service_name}", opts)
|
90
|
+
.and_return(response)
|
91
|
+
|
92
|
+
subject.delete_job(service_name)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns the job response' do
|
96
|
+
expect(subject.delete_job(service_name)).to eql(response)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#update_job_target_state' do
|
101
|
+
|
102
|
+
let(:service_name) { 'foo.service' }
|
103
|
+
let(:state) { :foobared }
|
104
|
+
|
105
|
+
before do
|
106
|
+
allow(subject).to receive(:put).and_return(response)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'PUTs the state to the Fleet job state key' do
|
110
|
+
opts = { value: state }
|
111
|
+
|
112
|
+
expect(subject).to receive(:put)
|
113
|
+
.with("v2/keys/_coreos.com/fleet/job/#{service_name}/target-state", opts)
|
114
|
+
.and_return(response)
|
115
|
+
|
116
|
+
subject.update_job_target_state(service_name, state)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'returns the job response' do
|
120
|
+
expect(subject.update_job_target_state(service_name, state)).to eql(response)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fleet::Client::State do
|
4
|
+
|
5
|
+
subject { Fleet::Client.new }
|
6
|
+
|
7
|
+
let(:response) { double(:response) }
|
8
|
+
|
9
|
+
describe '#list_states' do
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(subject).to receive(:get).and_return(response)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'GETs the Fleet state key' do
|
16
|
+
opts = { consistent: true, recursive: true, sorted: false }
|
17
|
+
expect(subject).to receive(:get)
|
18
|
+
.with('v2/keys/_coreos.com/fleet/state', opts)
|
19
|
+
.and_return(response)
|
20
|
+
|
21
|
+
subject.list_states
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns the state response' do
|
25
|
+
expect(subject.list_states).to eql(response)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#get_state' do
|
30
|
+
|
31
|
+
let(:service_name) { 'foo.service' }
|
32
|
+
|
33
|
+
before do
|
34
|
+
allow(subject).to receive(:get).and_return(response)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'GETs the named Fleet state key' do
|
38
|
+
opts = { consistent: true, recursive: true, sorted: false }
|
39
|
+
expect(subject).to receive(:get)
|
40
|
+
.with("v2/keys/_coreos.com/fleet/state/#{service_name}", opts)
|
41
|
+
.and_return(response)
|
42
|
+
|
43
|
+
subject.get_state(service_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns the state response' do
|
47
|
+
expect(subject.get_state(service_name)).to eql(response)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fleet::Client::Unit do
|
4
|
+
|
5
|
+
subject { Fleet::Client.new }
|
6
|
+
|
7
|
+
let(:response) { double(:response) }
|
8
|
+
|
9
|
+
describe '#list_units' do
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(subject).to receive(:get).and_return(response)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'GETs the Fleet unit key' do
|
16
|
+
expect(subject).to receive(:get)
|
17
|
+
.with("v2/keys/_coreos.com/fleet/unit")
|
18
|
+
.and_return(response)
|
19
|
+
|
20
|
+
subject.list_units
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns the job response' do
|
24
|
+
expect(subject.list_units).to eql(response)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#create_unit' do
|
29
|
+
|
30
|
+
let(:sha) { '33ef9ba9029c' }
|
31
|
+
let(:unit_def) { { exec_start: '/bin/bash' } }
|
32
|
+
|
33
|
+
before do
|
34
|
+
allow(subject).to receive(:put).and_return(response)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'PUTs the unit def to the Fleet unit key' do
|
38
|
+
opts = {
|
39
|
+
querystring: { 'prevExist' => false },
|
40
|
+
body: { value: unit_def.to_json }
|
41
|
+
}
|
42
|
+
|
43
|
+
expect(subject).to receive(:put)
|
44
|
+
.with("v2/keys/_coreos.com/fleet/unit/#{sha}", opts)
|
45
|
+
.and_return(response)
|
46
|
+
|
47
|
+
subject.create_unit(sha, unit_def)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns the job response' do
|
51
|
+
expect(subject.create_unit(sha, unit_def)).to eql(response)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#delete_unit' do
|
56
|
+
|
57
|
+
let(:sha) { '33ef9ba9029c' }
|
58
|
+
|
59
|
+
before do
|
60
|
+
allow(subject).to receive(:delete).and_return(response)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'DELETEs the named Fleet unit key' do
|
64
|
+
opts = { dir: false, recursive: false }
|
65
|
+
expect(subject).to receive(:delete)
|
66
|
+
.with("v2/keys/_coreos.com/fleet/unit/#{sha}", opts)
|
67
|
+
.and_return(response)
|
68
|
+
|
69
|
+
subject.delete_unit(sha)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'returns the job response' do
|
73
|
+
expect(subject.delete_unit(sha)).to eql(response)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'fleet/service_definition'
|
4
|
+
|
5
|
+
describe Fleet::Client do
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
|
9
|
+
after do
|
10
|
+
Fleet.reset
|
11
|
+
end
|
12
|
+
|
13
|
+
Fleet::Configuration::VALID_OPTIONS_KEYS.each do |option|
|
14
|
+
it "inherits default #{option} value from Panamax" do
|
15
|
+
client = Fleet::Client.new
|
16
|
+
expect(client.send(option)).to eql(Fleet.send(option))
|
17
|
+
end
|
18
|
+
|
19
|
+
it "overrides default for #{option} when specified" do
|
20
|
+
client = Fleet::Client.new(option => :foo)
|
21
|
+
expect(client.send(option)).to eql(:foo)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#load' do
|
27
|
+
|
28
|
+
let(:name) { 'foo.service' }
|
29
|
+
let(:service_def) { { 'Unit' => { 'Description' => 'bar' } } }
|
30
|
+
let(:sd) { Fleet::ServiceDefinition.new(name, service_def) }
|
31
|
+
let(:fleet_state) do
|
32
|
+
{ 'node' => { 'value' => '{ "loadState": "loaded" }' } }
|
33
|
+
end
|
34
|
+
|
35
|
+
before do
|
36
|
+
allow(subject).to receive(:create_unit).and_return(nil)
|
37
|
+
allow(subject).to receive(:create_job).and_return(nil)
|
38
|
+
allow(subject).to receive(:update_job_target_state).and_return(nil)
|
39
|
+
allow(subject).to receive(:get_state).and_return(fleet_state)
|
40
|
+
allow(Fleet::ServiceDefinition).to receive(:new).and_return(sd)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'invokes #create_unit' do
|
44
|
+
expect(subject).to receive(:create_unit)
|
45
|
+
.with(sd.sha1, sd.to_unit)
|
46
|
+
|
47
|
+
subject.load(name, service_def)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'invokes #create_job' do
|
51
|
+
expect(subject).to receive(:create_job)
|
52
|
+
.with(sd.name, sd.to_job)
|
53
|
+
|
54
|
+
subject.load(name, service_def)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'invokes #update_job_target_state' do
|
58
|
+
expect(subject).to receive(:update_job_target_state)
|
59
|
+
.with(sd.name, :loaded)
|
60
|
+
|
61
|
+
subject.load(name, service_def)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'checks the job state' do
|
65
|
+
expect(subject).to receive(:get_state).with(sd.name)
|
66
|
+
subject.load(name, service_def)
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when #create_unit raises PreconditionFailed' do
|
70
|
+
|
71
|
+
before do
|
72
|
+
allow(subject).to receive(:create_unit)
|
73
|
+
.and_raise(Fleet::PreconditionFailed.new('boom'))
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'does not blow up' do
|
77
|
+
expect { subject.load(name, service_def) }.to_not raise_error
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when #create_unit raises something other than PreconditionFailed' do
|
82
|
+
|
83
|
+
before do
|
84
|
+
allow(subject).to receive(:create_unit)
|
85
|
+
.and_raise(Fleet::BadRequest.new('boom'))
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'propagates the error' do
|
89
|
+
expect { subject.load(name, service_def) }.to(raise_error(Fleet::BadRequest))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when #create_job raises PreconditionFailed' do
|
94
|
+
|
95
|
+
before do
|
96
|
+
allow(subject).to receive(:create_job)
|
97
|
+
.and_raise(Fleet::PreconditionFailed.new('boom'))
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'does not blow up' do
|
101
|
+
expect { subject.load(name, service_def) }.to_not raise_error
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when #create_job raises something other than PreconditionFailed' do
|
106
|
+
|
107
|
+
before do
|
108
|
+
allow(subject).to receive(:create_job)
|
109
|
+
.and_raise(Fleet::BadRequest.new('boom'))
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'propagates the error' do
|
113
|
+
expect { subject.load(name, service_def) }.to(raise_error(Fleet::BadRequest))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#start' do
|
119
|
+
let(:service_name) { 'foo.service' }
|
120
|
+
|
121
|
+
before do
|
122
|
+
allow(subject).to receive(:update_job_target_state)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'invokes #update_job_target_state' do
|
126
|
+
expect(subject).to receive(:update_job_target_state)
|
127
|
+
.with(service_name, :launched)
|
128
|
+
|
129
|
+
subject.start(service_name)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe '#stop' do
|
134
|
+
let(:service_name) { 'foo.service' }
|
135
|
+
|
136
|
+
let(:fleet_state) do
|
137
|
+
{ 'node' => { 'value' => '{ "load_state": "loaded" }' } }
|
138
|
+
end
|
139
|
+
|
140
|
+
before do
|
141
|
+
allow(subject).to receive(:update_job_target_state)
|
142
|
+
allow(subject).to receive(:get_state).and_return(fleet_state)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'invokes #update_job_target_state' do
|
146
|
+
expect(subject).to receive(:update_job_target_state)
|
147
|
+
.with(service_name, :loaded)
|
148
|
+
|
149
|
+
subject.stop(service_name)
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'checks the job state' do
|
153
|
+
expect(subject).to receive(:get_state).with(service_name)
|
154
|
+
subject.stop(service_name)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe '#unload' do
|
159
|
+
let(:service_name) { 'foo.service' }
|
160
|
+
|
161
|
+
let(:fleet_state) do
|
162
|
+
{ 'node' => { 'value' => '{ "load_state": "not-found" }' } }
|
163
|
+
end
|
164
|
+
|
165
|
+
before do
|
166
|
+
allow(subject).to receive(:update_job_target_state)
|
167
|
+
allow(subject).to receive(:get_state).and_return(fleet_state)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'invokes #update_job_target_state' do
|
171
|
+
expect(subject).to receive(:update_job_target_state)
|
172
|
+
.with(service_name, :inactive)
|
173
|
+
|
174
|
+
subject.unload(service_name)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'checks the job state' do
|
178
|
+
expect(subject).to receive(:get_state).with(service_name)
|
179
|
+
subject.unload(service_name)
|
180
|
+
end
|
181
|
+
|
182
|
+
context 'when the unload state cannot be achieved' do
|
183
|
+
|
184
|
+
before do
|
185
|
+
allow(subject).to receive(:get_state).and_raise(Fleet::NotFound, 'boom')
|
186
|
+
allow(subject).to receive(:sleep)
|
187
|
+
end
|
188
|
+
|
189
|
+
it 're-checks the state 10 times' do
|
190
|
+
expect(subject).to receive(:get_state).exactly(10).times
|
191
|
+
subject.unload(service_name) rescue nil
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'raises an error' do
|
195
|
+
expect do
|
196
|
+
subject.unload(service_name)
|
197
|
+
end.to raise_error(Fleet::Error)
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe '#destroy' do
|
204
|
+
let(:service_name) { 'foo.service' }
|
205
|
+
|
206
|
+
before do
|
207
|
+
allow(subject).to receive(:delete_job).and_return(nil)
|
208
|
+
allow(subject).to receive(:get_state).and_raise(Fleet::NotFound, 'boom')
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'invokes #delete_job' do
|
212
|
+
|
213
|
+
expect(subject).to receive(:delete_job)
|
214
|
+
.with(service_name)
|
215
|
+
.and_return(nil)
|
216
|
+
|
217
|
+
subject.destroy(service_name)
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'checks the job state' do
|
221
|
+
expect(subject).to receive(:get_state).with(service_name)
|
222
|
+
subject.destroy(service_name)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe '#states' do
|
227
|
+
|
228
|
+
let(:service_name) { 'foo.service' }
|
229
|
+
|
230
|
+
let(:fleet_state) do
|
231
|
+
{ 'node' => { 'value' => '{"load": "loaded", "run": "running"}' } }
|
232
|
+
end
|
233
|
+
|
234
|
+
before do
|
235
|
+
allow(subject).to receive(:get_state).and_return(fleet_state)
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'retrieves service state from the fleet client' do
|
239
|
+
expect(subject).to receive(:get_state).with(service_name)
|
240
|
+
subject.states(service_name)
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'returns the state hash w/ normalized keys' do
|
244
|
+
expect(subject.states(service_name)).to eq(load: 'loaded', run: 'running')
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|