fleet-api 0.9.0 → 1.0.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.
@@ -1,56 +1,39 @@
1
- require 'digest/sha1'
2
-
3
1
  module Fleet
4
2
  class ServiceDefinition
5
3
 
6
- attr_reader :name
7
-
8
- def initialize(name, service_def={})
9
- @name = name
4
+ def initialize(service_def={})
10
5
  @service_def = service_def
11
6
  end
12
7
 
13
- def to_unit
14
- { 'Raw' => raw }
15
- end
16
-
17
- def to_job
8
+ def to_unit(name)
18
9
  {
19
- 'Name' => name,
20
- 'UnitHash' => sha1_byte_array
10
+ 'name' => name,
11
+ 'options' => options
21
12
  }
22
13
  end
23
14
 
24
- def sha1
25
- Digest::SHA1.hexdigest raw
26
- end
27
-
28
15
  private
29
16
 
30
- def raw
31
- raw_string = ''
32
-
33
- @service_def.each do |heading, section|
34
- raw_string += "[#{heading}]\n"
35
-
36
- if section.is_a?(Enumerable)
37
- section.each do |key, value|
38
- if value.is_a?(Enumerable)
39
- value.each { |command| raw_string += "#{key}=#{command}\n" }
40
- else
41
- raw_string += "#{key}=#{value}\n"
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
+ }
42
27
  end
28
+ else
29
+ h << {
30
+ 'section' => section,
31
+ 'name' => name,
32
+ 'value' => value
33
+ }
43
34
  end
44
35
  end
45
-
46
- raw_string += "\n"
47
36
  end
48
-
49
- raw_string.chomp
50
- end
51
-
52
- def sha1_byte_array
53
- Digest::SHA1.digest(raw).unpack('C20')
54
37
  end
55
38
  end
56
39
  end
data/lib/fleet/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Fleet
2
- VERSION = '0.9.0'.freeze unless defined?(Fleet::VERSION)
2
+ VERSION = '1.0.0'.freeze unless defined?(Fleet::VERSION)
3
3
  end
@@ -13,9 +13,8 @@ describe Fleet::Client::Machines do
13
13
  end
14
14
 
15
15
  it 'GETs the Fleet machines key' do
16
- opts = { consistent: true, recursive: true, sorted: true }
17
16
  expect(subject).to receive(:get)
18
- .with('v2/keys/_coreos.com/fleet/machines', opts)
17
+ .with('fleet/v1/machines', nil)
19
18
  .and_return(response)
20
19
 
21
20
  subject.list_machines
@@ -12,10 +12,9 @@ describe Fleet::Client::State do
12
12
  allow(subject).to receive(:get).and_return(response)
13
13
  end
14
14
 
15
- it 'GETs the Fleet state key' do
16
- opts = { consistent: true, recursive: true, sorted: false }
15
+ it 'GETs the state resource' do
17
16
  expect(subject).to receive(:get)
18
- .with('v2/keys/_coreos.com/fleet/state', opts)
17
+ .with('fleet/v1/state', {})
19
18
  .and_return(response)
20
19
 
21
20
  subject.list_states
@@ -25,26 +24,4 @@ describe Fleet::Client::State do
25
24
  expect(subject.list_states).to eql(response)
26
25
  end
27
26
  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
27
  end
@@ -12,65 +12,80 @@ describe Fleet::Client::Unit do
12
12
  allow(subject).to receive(:get).and_return(response)
13
13
  end
14
14
 
15
- it 'GETs the Fleet unit key' do
15
+ it 'GETs all Fleet units' do
16
16
  expect(subject).to receive(:get)
17
- .with("v2/keys/_coreos.com/fleet/unit")
17
+ .with("fleet/v1/units")
18
18
  .and_return(response)
19
19
 
20
20
  subject.list_units
21
21
  end
22
22
 
23
- it 'returns the job response' do
23
+ it 'returns the unit response' do
24
24
  expect(subject.list_units).to eql(response)
25
25
  end
26
26
  end
27
27
 
28
+ describe '#get_unit' do
29
+
30
+ let(:name) { 'foo.service' }
31
+
32
+ before do
33
+ allow(subject).to receive(:get).and_return(response)
34
+ end
35
+
36
+ it 'GETs the Fleet unit' do
37
+ expect(subject).to receive(:get)
38
+ .with("fleet/v1/units/#{name}")
39
+ .and_return(response)
40
+
41
+ subject.get_unit(name)
42
+ end
43
+
44
+ it 'returns the unit response' do
45
+ expect(subject.get_unit(name)).to eql(response)
46
+ end
47
+ end
48
+
28
49
  describe '#create_unit' do
29
50
 
30
- let(:sha) { '33ef9ba9029c' }
31
- let(:unit_def) { { exec_start: '/bin/bash' } }
51
+ let(:name) { 'foo.service' }
52
+ let(:options) { { exec_start: '/bin/bash' } }
32
53
 
33
54
  before do
34
55
  allow(subject).to receive(:put).and_return(response)
35
56
  end
36
57
 
37
58
  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
59
  expect(subject).to receive(:put)
44
- .with("v2/keys/_coreos.com/fleet/unit/#{sha}", opts)
60
+ .with("fleet/v1/units/#{name}", options)
45
61
  .and_return(response)
46
62
 
47
- subject.create_unit(sha, unit_def)
63
+ subject.create_unit(name, options)
48
64
  end
49
65
 
50
- it 'returns the job response' do
51
- expect(subject.create_unit(sha, unit_def)).to eql(response)
66
+ it 'returns the unit response' do
67
+ expect(subject.create_unit(name, options)).to eql(response)
52
68
  end
53
69
  end
54
70
 
55
71
  describe '#delete_unit' do
56
72
 
57
- let(:sha) { '33ef9ba9029c' }
73
+ let(:name) { 'foo.service' }
58
74
 
59
75
  before do
60
76
  allow(subject).to receive(:delete).and_return(response)
61
77
  end
62
78
 
63
- it 'DELETEs the named Fleet unit key' do
64
- opts = { dir: false, recursive: false }
79
+ it 'DELETEs the named Fleet unit' do
65
80
  expect(subject).to receive(:delete)
66
- .with("v2/keys/_coreos.com/fleet/unit/#{sha}", opts)
81
+ .with("fleet/v1/units/#{name}")
67
82
  .and_return(response)
68
83
 
69
- subject.delete_unit(sha)
84
+ subject.delete_unit(name)
70
85
  end
71
86
 
72
87
  it 'returns the job response' do
73
- expect(subject.delete_unit(sha)).to eql(response)
88
+ expect(subject.delete_unit(name)).to eql(response)
74
89
  end
75
90
  end
76
91
  end
@@ -27,28 +27,24 @@ describe Fleet::Client do
27
27
 
28
28
  let(:machine_list) do
29
29
  {
30
- 'node' => {
31
- 'nodes' => [
32
- {
33
- 'nodes' => [
34
- { 'value' => '{"ID":"123","PublicIP":"1.1.1.1"}' }
35
- ]
36
- }
37
- ]
38
- }
30
+ 'machines' => [
31
+ { 'id' => '123', 'primaryIP' => '1.1.1.1' }
32
+ ]
39
33
  }
40
34
  end
41
35
 
42
36
  let(:state_list) do
43
37
  {
44
- 'node' => {
45
- 'nodes' => [
46
- {
47
- 'key' => '/_coreos.com/fleet/state/foo.service',
48
- 'value' => '{"loadState":"a","activeState":"b","subState":"c","machineState":{"ID":"123"}}'
49
- }
50
- ]
51
- }
38
+ 'states' => [
39
+ {
40
+ 'hash' => 'abc123',
41
+ 'machineID' => '123',
42
+ 'name' => 'foo.service',
43
+ 'systemdActiveState' => 'b',
44
+ 'systemdLoadState' => 'a',
45
+ 'systemdSubState' => 'c'
46
+ }
47
+ ]
52
48
  }
53
49
  end
54
50
 
@@ -69,8 +65,8 @@ describe Fleet::Client do
69
65
 
70
66
  it 'returns the list of units' do
71
67
  expected = [{
72
- name: 'foo.service',
73
- load_state: 'a',
68
+ name: 'foo.service',
69
+ load_state: 'a',
74
70
  active_state: 'b',
75
71
  sub_state: 'c',
76
72
  machine_id: '123',
@@ -85,51 +81,25 @@ describe Fleet::Client do
85
81
 
86
82
  let(:name) { 'foo.service' }
87
83
  let(:service_def) { { 'Unit' => { 'Description' => 'bar' } } }
88
- let(:sd) { Fleet::ServiceDefinition.new(name, service_def) }
84
+ let(:sd) { Fleet::ServiceDefinition.new(service_def) }
85
+ let(:response) { double(:response) }
89
86
 
90
87
  context 'when a service definition is provided' do
91
88
  before do
92
- allow(subject).to receive(:create_unit).and_return(nil)
93
- allow(subject).to receive(:create_job).and_return(nil)
94
- allow(subject).to receive(:update_job_target_state).and_return(nil)
89
+ allow(subject).to receive(:create_unit).and_return(response)
95
90
  allow(Fleet::ServiceDefinition).to receive(:new).and_return(sd)
96
91
  end
97
92
 
98
93
  it 'invokes #create_unit' do
99
94
  expect(subject).to receive(:create_unit)
100
- .with(sd.sha1, sd.to_unit)
95
+ .with(name, sd.to_unit(name))
101
96
 
102
97
  subject.load(name, service_def)
103
98
  end
104
99
 
105
- it 'invokes #create_job' do
106
- expect(subject).to receive(:create_job)
107
- .with(sd.name, sd.to_job)
108
-
109
- subject.load(name, service_def)
110
- end
111
-
112
- it 'invokes #update_job_target_state' do
113
- expect(subject).to receive(:update_job_target_state)
114
- .with(sd.name, :loaded)
115
-
116
- subject.load(name, service_def)
117
- end
118
-
119
- context 'when sync=true is set' do
120
-
121
- let(:fleet_state) do
122
- { 'node' => { 'value' => '{ "loadState": "loaded" }' } }
123
- end
124
-
125
- before do
126
- allow(subject).to receive(:get_state).and_return(fleet_state)
127
- end
128
-
129
- it 'checks the job state' do
130
- expect(subject).to receive(:get_state).with(sd.name)
131
- subject.load(name, service_def, sync=true)
132
- end
100
+ it 'returns the #create_unit response' do
101
+ r = subject.load(name, service_def)
102
+ expect(r).to eq response
133
103
  end
134
104
 
135
105
  context 'when #create_unit raises PreconditionFailed' do
@@ -155,36 +125,12 @@ describe Fleet::Client do
155
125
  expect { subject.load(name, service_def) }.to(raise_error(Fleet::BadRequest))
156
126
  end
157
127
  end
158
-
159
- context 'when #create_job raises PreconditionFailed' do
160
-
161
- before do
162
- allow(subject).to receive(:create_job)
163
- .and_raise(Fleet::PreconditionFailed.new('boom'))
164
- end
165
-
166
- it 'does not blow up' do
167
- expect { subject.load(name, service_def) }.to_not raise_error
168
- end
169
- end
170
-
171
- context 'when #create_job raises something other than PreconditionFailed' do
172
-
173
- before do
174
- allow(subject).to receive(:create_job)
175
- .and_raise(Fleet::BadRequest.new('boom'))
176
- end
177
-
178
- it 'propagates the error' do
179
- expect { subject.load(name, service_def) }.to(raise_error(Fleet::BadRequest))
180
- end
181
- end
182
128
  end
183
129
 
184
130
  context 'when no service definition is provided' do
185
131
 
186
132
  before do
187
- allow(subject).to receive(:update_job_target_state).and_return(nil)
133
+ allow(subject).to receive(:update_unit).and_return(response)
188
134
  end
189
135
 
190
136
  it 'does NOT invoke #create_unit' do
@@ -192,33 +138,12 @@ describe Fleet::Client do
192
138
  subject.load(name)
193
139
  end
194
140
 
195
- it 'does NOT invoke #create_job' do
196
- expect(subject).to_not receive(:create_job)
197
- subject.load(name)
198
- end
199
-
200
- it 'invokes #update_job_target_state' do
201
- expect(subject).to receive(:update_job_target_state)
202
- .with(sd.name, :loaded)
141
+ it 'invokes #update' do
142
+ expect(subject).to receive(:update_unit)
143
+ .with(name, { 'desiredState' => 'loaded', 'name' => name })
203
144
 
204
145
  subject.load(name)
205
146
  end
206
-
207
- context 'when sync=true is set' do
208
-
209
- let(:fleet_state) do
210
- { 'node' => { 'value' => '{ "loadState": "loaded" }' } }
211
- end
212
-
213
- before do
214
- allow(subject).to receive(:get_state).and_return(fleet_state)
215
- end
216
-
217
- it 'checks the job state' do
218
- expect(subject).to receive(:get_state).with(sd.name)
219
- subject.load(name, nil, sync=true)
220
- end
221
- end
222
147
  end
223
148
 
224
149
  context 'when the supplied name is invalid' do
@@ -235,12 +160,12 @@ describe Fleet::Client do
235
160
  let(:service_name) { 'foo.service' }
236
161
 
237
162
  before do
238
- allow(subject).to receive(:update_job_target_state)
163
+ allow(subject).to receive(:update_unit).and_return(nil)
239
164
  end
240
165
 
241
- it 'invokes #update_job_target_state' do
242
- expect(subject).to receive(:update_job_target_state)
243
- .with(service_name, :launched)
166
+ it 'invokes #update_unit' do
167
+ expect(subject).to receive(:update_unit)
168
+ .with(service_name, { 'desiredState' => 'launched', 'name' => service_name })
244
169
 
245
170
  subject.start(service_name)
246
171
  end
@@ -250,111 +175,47 @@ describe Fleet::Client do
250
175
  let(:service_name) { 'foo.service' }
251
176
 
252
177
  before do
253
- allow(subject).to receive(:update_job_target_state)
178
+ allow(subject).to receive(:update_unit).and_return(nil)
254
179
  end
255
180
 
256
- it 'invokes #update_job_target_state' do
257
- expect(subject).to receive(:update_job_target_state)
258
- .with(service_name, :loaded)
181
+ it 'invokes #update_unit' do
182
+ expect(subject).to receive(:update_unit)
183
+ .with(service_name, { 'desiredState' => 'loaded', 'name' => service_name })
259
184
 
260
185
  subject.stop(service_name)
261
186
  end
262
-
263
- context 'when sync=true is set' do
264
-
265
- let(:fleet_state) do
266
- { 'node' => { 'value' => '{ "load_state": "loaded" }' } }
267
- end
268
-
269
- before do
270
- allow(subject).to receive(:get_state).and_return(fleet_state)
271
- end
272
-
273
- it 'checks the job state' do
274
- expect(subject).to receive(:get_state).with(service_name)
275
- subject.stop(service_name, sync=true)
276
- end
277
- end
278
187
  end
279
188
 
280
189
  describe '#unload' do
281
190
  let(:service_name) { 'foo.service' }
282
191
 
283
192
  before do
284
- allow(subject).to receive(:update_job_target_state)
193
+ allow(subject).to receive(:update_unit).and_return(nil)
285
194
  end
286
195
 
287
- it 'invokes #update_job_target_state' do
288
- expect(subject).to receive(:update_job_target_state)
289
- .with(service_name, :inactive)
196
+ it 'invokes #update_unit' do
197
+ expect(subject).to receive(:update_unit)
198
+ .with(service_name, { 'desiredState' => 'inactive', 'name' => service_name })
290
199
 
291
200
  subject.unload(service_name)
292
201
  end
293
-
294
- context 'when sync=true is set' do
295
-
296
- before do
297
- allow(subject).to receive(:get_state).and_raise(Fleet::NotFound, 'boom')
298
- end
299
-
300
- it 'checks the job state' do
301
- expect(subject).to receive(:get_state).with(service_name)
302
- subject.unload(service_name, sync=true)
303
- end
304
-
305
- context 'when the unload state cannot be achieved' do
306
-
307
- let(:fleet_state) do
308
- { 'node' => { 'value' => '{ "load_state": "loaded" }' } }
309
- end
310
-
311
- before do
312
- allow(subject).to receive(:get_state).and_return(fleet_state)
313
- allow(subject).to receive(:sleep)
314
- end
315
-
316
- it 're-checks the state 20 times' do
317
- expect(subject).to receive(:get_state).exactly(20).times
318
- subject.unload(service_name, sync=true) rescue nil
319
- end
320
-
321
- it 'raises an error' do
322
- expect do
323
- subject.unload(service_name, sync=true)
324
- end.to raise_error(Fleet::Error)
325
- end
326
-
327
- end
328
- end
329
202
  end
330
203
 
331
204
  describe '#destroy' do
332
205
  let(:service_name) { 'foo.service' }
333
206
 
334
207
  before do
335
- allow(subject).to receive(:delete_job).and_return(nil)
208
+ allow(subject).to receive(:delete_unit).and_return(nil)
336
209
  end
337
210
 
338
211
  it 'invokes #delete_job' do
339
212
 
340
- expect(subject).to receive(:delete_job)
213
+ expect(subject).to receive(:delete_unit)
341
214
  .with(service_name)
342
215
  .and_return(nil)
343
216
 
344
217
  subject.destroy(service_name)
345
218
  end
346
-
347
- context 'when sync=true is set' do
348
-
349
- before do
350
- allow(subject).to receive(:get_state).and_raise(Fleet::NotFound, 'boom')
351
- end
352
-
353
- it 'checks the job state' do
354
- expect(subject).to receive(:get_state).with(service_name)
355
- subject.destroy(service_name, sync=true)
356
- end
357
- end
358
219
  end
359
220
 
360
221
  describe '#status' do
@@ -362,20 +223,59 @@ describe Fleet::Client do
362
223
  let(:service_name) { 'foo.service' }
363
224
 
364
225
  let(:fleet_state) do
365
- { 'node' => { 'value' => '{"load": "loaded", "run": "running"}' } }
226
+ { 'currentState' => 'launched' }
366
227
  end
367
228
 
368
229
  before do
369
- allow(subject).to receive(:get_state).and_return(fleet_state)
230
+ allow(subject).to receive(:get_unit).and_return(fleet_state)
370
231
  end
371
232
 
372
233
  it 'retrieves service state from the fleet client' do
373
- expect(subject).to receive(:get_state).with(service_name)
234
+ expect(subject).to receive(:get_unit).with(service_name)
374
235
  subject.status(service_name)
375
236
  end
376
237
 
377
- it 'returns the state hash w/ normalized keys' do
378
- expect(subject.status(service_name)).to eq(load: 'loaded', run: 'running')
238
+ it 'returns the symbolized state' do
239
+ expect(subject.status(service_name)).to eq(:launched)
240
+ end
241
+ end
242
+
243
+ describe '#get_unit_state' do
244
+
245
+ let(:service_name) { 'foo.service' }
246
+
247
+ let(:states) do
248
+ { 'states' => [] }
249
+ end
250
+
251
+ before do
252
+ allow(subject).to receive(:list_states).and_return(states)
253
+ end
254
+
255
+ it 'retrieves the states from the fleet API' do
256
+ expect(subject).to receive(:list_states).with({ unitName: service_name })
257
+ subject.get_unit_state(service_name)
258
+ end
259
+
260
+ context 'when unit is found' do
261
+
262
+ let(:states) do
263
+ { 'states' => [{ 'name' => 'foo.service' }, {}] }
264
+ end
265
+
266
+ it 'returns the first matching state hash' do
267
+ expect(subject.get_unit_state(service_name)).to eq(states['states'].first)
268
+ end
269
+ end
270
+
271
+ context 'when unit is NOT found' do
272
+
273
+ let(:states) { {} }
274
+
275
+ it 'returns the first matching state hash' do
276
+ expect { subject.get_unit_state(service_name) }.to(
277
+ raise_error(Fleet::NotFound))
278
+ end
379
279
  end
380
280
  end
381
281
  end
@@ -13,15 +13,15 @@ describe Fleet::Configuration do
13
13
 
14
14
  describe 'default values' do
15
15
 
16
- describe 'adapter' do
17
- it 'is matches DEFAULT_ADAPTER' do
18
- expect(subject.adapter).to eq Fleet::Configuration::DEFAULT_ADAPTER
16
+ describe 'fleet_api_url' do
17
+ it 'is matches DEFAULT_FLEET_API_URL' do
18
+ expect(subject.fleet_api_url).to eq Fleet::Configuration::DEFAULT_FLEET_API_URL
19
19
  end
20
20
  end
21
21
 
22
- describe 'fleet_api_url' do
23
- it 'is matches DEFAULT_ETCD_API_URL' do
24
- expect(subject.fleet_api_url).to eq Fleet::Configuration::DEFAULT_ETCD_API_URL
22
+ describe 'fleet_api_version' do
23
+ it 'is matches DEFAULT_FLEET_API_VERSION' do
24
+ expect(subject.fleet_api_version).to eq Fleet::Configuration::DEFAULT_FLEET_API_VERSION
25
25
  end
26
26
  end
27
27