fleet-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,39 @@
1
+ module Fleet
2
+ class ServiceDefinition
3
+
4
+ def initialize(service_def={})
5
+ @service_def = service_def
6
+ end
7
+
8
+ def to_unit(name)
9
+ {
10
+ 'name' => name,
11
+ 'options' => options
12
+ }
13
+ end
14
+
15
+ private
16
+
17
+ def options
18
+ @service_def.each_with_object([]) do |(section, options), h|
19
+ options.each do |name, value|
20
+ if value.is_a?(Enumerable)
21
+ value.each do |v|
22
+ h << {
23
+ 'section' => section,
24
+ 'name' => name,
25
+ 'value' => v
26
+ }
27
+ end
28
+ else
29
+ h << {
30
+ 'section' => section,
31
+ 'name' => name,
32
+ 'value' => value
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module Fleet
2
+ VERSION = '1.2.0'.freeze unless defined?(Fleet::VERSION)
3
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fleet::Client::Machines do
4
+ subject { Fleet::Client.new }
5
+
6
+ let(:response) { double(:response) }
7
+
8
+ describe '#list_machines' do
9
+ before do
10
+ allow(subject).to receive(:get).and_return(response)
11
+ end
12
+
13
+ it 'GETs the Fleet machines key' do
14
+ expect(subject).to receive(:get)
15
+ .with('fleet/v1/machines')
16
+ .and_return(response)
17
+
18
+ subject.list_machines
19
+ end
20
+
21
+ it 'returns the job response' do
22
+ expect(subject.list_machines).to eql(response)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fleet::Client::State do
4
+ subject { Fleet::Client.new }
5
+
6
+ let(:response) { double(:response) }
7
+
8
+ describe '#list_states' do
9
+ before do
10
+ allow(subject).to receive(:get).and_return(response)
11
+ end
12
+
13
+ it 'GETs the state resource' do
14
+ expect(subject).to receive(:get)
15
+ .with('fleet/v1/state')
16
+ .and_return(response)
17
+
18
+ subject.list_states
19
+ end
20
+
21
+ it 'returns the state response' do
22
+ expect(subject.list_states).to eql(response)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fleet::Client::Unit do
4
+ subject { Fleet::Client.new }
5
+
6
+ let(:response) { double(:response) }
7
+
8
+ describe '#list_units' do
9
+ before do
10
+ allow(subject).to receive(:get).and_return(response)
11
+ end
12
+
13
+ it 'GETs all Fleet units' do
14
+ expect(subject).to receive(:get)
15
+ .with('fleet/v1/units')
16
+ .and_return(response)
17
+
18
+ subject.list_units
19
+ end
20
+
21
+ it 'returns the unit response' do
22
+ expect(subject.list_units).to eql(response)
23
+ end
24
+ end
25
+
26
+ describe '#get_unit' do
27
+ let(:name) { 'foo.service' }
28
+
29
+ before do
30
+ allow(subject).to receive(:get).and_return(response)
31
+ end
32
+
33
+ it 'GETs the Fleet unit' do
34
+ expect(subject).to receive(:get)
35
+ .with("fleet/v1/units/#{name}")
36
+ .and_return(response)
37
+
38
+ subject.get_unit(name)
39
+ end
40
+
41
+ it 'returns the unit response' do
42
+ expect(subject.get_unit(name)).to eql(response)
43
+ end
44
+ end
45
+
46
+ describe '#create_unit' do
47
+ let(:name) { 'foo.service' }
48
+ let(:options) { { exec_start: '/bin/bash' } }
49
+
50
+ before do
51
+ allow(subject).to receive(:put).and_return(response)
52
+ end
53
+
54
+ it 'PUTs the unit def to the Fleet unit key' do
55
+ expect(subject).to receive(:put)
56
+ .with("fleet/v1/units/#{name}", options)
57
+ .and_return(response)
58
+
59
+ subject.create_unit(name, options)
60
+ end
61
+
62
+ it 'returns the unit response' do
63
+ expect(subject.create_unit(name, options)).to eql(response)
64
+ end
65
+ end
66
+
67
+ describe '#delete_unit' do
68
+ let(:name) { 'foo.service' }
69
+
70
+ before do
71
+ allow(subject).to receive(:delete).and_return(response)
72
+ end
73
+
74
+ it 'DELETEs the named Fleet unit' do
75
+ expect(subject).to receive(:delete)
76
+ .with("fleet/v1/units/#{name}")
77
+ .and_return(response)
78
+
79
+ subject.delete_unit(name)
80
+ end
81
+
82
+ it 'returns the job response' do
83
+ expect(subject.delete_unit(name)).to eql(response)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,296 @@
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 '#list' do
27
+
28
+ let(:machine_list) do
29
+ {
30
+ 'machines' => [
31
+ { 'id' => '123', 'primaryIP' => '1.1.1.1' }
32
+ ]
33
+ }
34
+ end
35
+
36
+ let(:state_list) do
37
+ {
38
+ 'states' => [
39
+ {
40
+ 'hash' => 'abc123',
41
+ 'machineID' => '123',
42
+ 'name' => 'foo.service',
43
+ 'systemdActiveState' => 'b',
44
+ 'systemdLoadState' => 'a',
45
+ 'systemdSubState' => 'c'
46
+ }
47
+ ]
48
+ }
49
+ end
50
+
51
+ before do
52
+ allow(subject).to receive(:list_machines).and_return(machine_list)
53
+ allow(subject).to receive(:list_states).and_return(state_list)
54
+ end
55
+
56
+ it 'looks-up the list of machines' do
57
+ expect(subject).to receive(:list_machines)
58
+ subject.list
59
+ end
60
+
61
+ it 'looks-up the list of job states' do
62
+ expect(subject).to receive(:list_states)
63
+ subject.list
64
+ end
65
+
66
+ it 'returns the list of units' do
67
+ expected = [{
68
+ name: 'foo.service',
69
+ load_state: 'a',
70
+ active_state: 'b',
71
+ sub_state: 'c',
72
+ machine_id: '123',
73
+ machine_ip: '1.1.1.1'
74
+ }]
75
+
76
+ expect(subject.list).to eq(expected)
77
+ end
78
+ end
79
+
80
+ describe '#submit' do
81
+ let(:name) { 'foo.service' }
82
+ let(:service_def) { { 'Unit' => { 'Description' => 'bar' } } }
83
+ let(:sd) { Fleet::ServiceDefinition.new(service_def) }
84
+ let(:response) { double(:response) }
85
+
86
+ before do
87
+ allow(subject).to receive(:create_unit).and_return(response)
88
+ allow(Fleet::ServiceDefinition).to receive(:new).and_return(sd)
89
+ end
90
+
91
+ it 'invokes #create_unit' do
92
+ expect(subject).to receive(:create_unit)
93
+ .with(name, sd.to_unit(name))
94
+
95
+ subject.submit(name, service_def)
96
+ end
97
+
98
+ it 'returns the #create_unit response' do
99
+ r = subject.submit(name, service_def)
100
+ expect(r).to eq response
101
+ end
102
+
103
+ context 'when #create_unit raises PreconditionFailed' do
104
+
105
+ before do
106
+ allow(subject).to receive(:create_unit)
107
+ .and_raise(Fleet::PreconditionFailed.new('boom'))
108
+ end
109
+
110
+ it 'does not blow up' do
111
+ expect { subject.submit(name, service_def) }.to_not raise_error
112
+ end
113
+ end
114
+
115
+ context 'when #create_unit raises something other than PreconditionFailed' do
116
+
117
+ before do
118
+ allow(subject).to receive(:create_unit)
119
+ .and_raise(Fleet::BadRequest.new('boom'))
120
+ end
121
+
122
+ it 'propagates the error' do
123
+ expect { subject.submit(name, service_def) }.to(raise_error(Fleet::BadRequest))
124
+ end
125
+ end
126
+
127
+ context 'when the supplied name is invalid' do
128
+
129
+ let(:name) { 'foo!.service' }
130
+
131
+ it 'raises an ArgumentError' do
132
+ expect { subject.submit(name, nil) }.to raise_error(ArgumentError, /only contain/)
133
+ end
134
+ end
135
+ end
136
+
137
+ describe '#load' do
138
+
139
+ let(:name) { 'foo.service' }
140
+ let(:response) { double(:response) }
141
+
142
+ before do
143
+ allow(subject).to receive(:update_unit).and_return(response)
144
+ end
145
+
146
+ it 'does NOT invoke #submit' do
147
+ expect(subject).not_to receive(:submit)
148
+ subject.load(name)
149
+ end
150
+
151
+ it 'invokes #update' do
152
+ expect(subject).to receive(:update_unit)
153
+ .with(name, { 'desiredState' => 'loaded', 'name' => name })
154
+
155
+ subject.load(name)
156
+ end
157
+
158
+ context 'when a service definition is provided' do
159
+
160
+ let(:service_def) { { 'Unit' => { 'Description' => 'bar' } } }
161
+
162
+ before do
163
+ allow(subject).to receive(:submit)
164
+ end
165
+
166
+ it 'invokes #load' do
167
+ expect(subject).to receive(:submit)
168
+ subject.load(name, service_def)
169
+ end
170
+ end
171
+
172
+ end
173
+
174
+ describe '#start' do
175
+ let(:service_name) { 'foo.service' }
176
+
177
+ before do
178
+ allow(subject).to receive(:update_unit).and_return(nil)
179
+ end
180
+
181
+ it 'invokes #update_unit' do
182
+ expect(subject).to receive(:update_unit)
183
+ .with(service_name, { 'desiredState' => 'launched', 'name' => service_name })
184
+
185
+ subject.start(service_name)
186
+ end
187
+ end
188
+
189
+ describe '#stop' do
190
+ let(:service_name) { 'foo.service' }
191
+
192
+ before do
193
+ allow(subject).to receive(:update_unit).and_return(nil)
194
+ end
195
+
196
+ it 'invokes #update_unit' do
197
+ expect(subject).to receive(:update_unit)
198
+ .with(service_name, { 'desiredState' => 'loaded', 'name' => service_name })
199
+
200
+ subject.stop(service_name)
201
+ end
202
+ end
203
+
204
+ describe '#unload' do
205
+ let(:service_name) { 'foo.service' }
206
+
207
+ before do
208
+ allow(subject).to receive(:update_unit).and_return(nil)
209
+ end
210
+
211
+ it 'invokes #update_unit' do
212
+ expect(subject).to receive(:update_unit)
213
+ .with(service_name, { 'desiredState' => 'inactive', 'name' => service_name })
214
+
215
+ subject.unload(service_name)
216
+ end
217
+ end
218
+
219
+ describe '#destroy' do
220
+ let(:service_name) { 'foo.service' }
221
+
222
+ before do
223
+ allow(subject).to receive(:delete_unit).and_return(nil)
224
+ end
225
+
226
+ it 'invokes #delete_job' do
227
+
228
+ expect(subject).to receive(:delete_unit)
229
+ .with(service_name)
230
+ .and_return(nil)
231
+
232
+ subject.destroy(service_name)
233
+ end
234
+ end
235
+
236
+ describe '#status' do
237
+
238
+ let(:service_name) { 'foo.service' }
239
+
240
+ let(:fleet_state) do
241
+ { 'currentState' => 'launched' }
242
+ end
243
+
244
+ before do
245
+ allow(subject).to receive(:get_unit).and_return(fleet_state)
246
+ end
247
+
248
+ it 'retrieves service state from the fleet client' do
249
+ expect(subject).to receive(:get_unit).with(service_name)
250
+ subject.status(service_name)
251
+ end
252
+
253
+ it 'returns the symbolized state' do
254
+ expect(subject.status(service_name)).to eq(:launched)
255
+ end
256
+ end
257
+
258
+ describe '#get_unit_state' do
259
+
260
+ let(:service_name) { 'foo.service' }
261
+
262
+ let(:states) do
263
+ { 'states' => [] }
264
+ end
265
+
266
+ before do
267
+ allow(subject).to receive(:list_states).and_return(states)
268
+ end
269
+
270
+ it 'retrieves the states from the fleet API' do
271
+ expect(subject).to receive(:list_states).with({ unitName: service_name })
272
+ subject.get_unit_state(service_name)
273
+ end
274
+
275
+ context 'when unit is found' do
276
+
277
+ let(:states) do
278
+ { 'states' => [{ 'name' => 'foo.service' }, {}] }
279
+ end
280
+
281
+ it 'returns the first matching state hash' do
282
+ expect(subject.get_unit_state(service_name)).to eq(states['states'].first)
283
+ end
284
+ end
285
+
286
+ context 'when unit is NOT found' do
287
+
288
+ let(:states) { {} }
289
+
290
+ it 'returns the first matching state hash' do
291
+ expect { subject.get_unit_state(service_name) }.to(
292
+ raise_error(Fleet::NotFound))
293
+ end
294
+ end
295
+ end
296
+ end