fleet-api 0.0.1 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -0
- data/Gemfile.lock +3 -3
- data/LICENSE +1 -1
- data/README.md +113 -0
- data/fleet-api.gemspec +4 -2
- data/lib/fleet/client.rb +18 -16
- data/lib/fleet/version.rb +1 -1
- data/spec/fleet/client_spec.rb +86 -54
- metadata +13 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ded5145e7361d7b0e441c91f3811a783a11ec94e
|
4
|
+
data.tar.gz: b544579b3f35b5764b4a863618d0b96b38c68442
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b748b4fc6014400b8228415d432045d379ba191469a80e08c534bf16180126ee4a37f1d6b074043d2d86aa9e82eaac4fcd12a5a907fb94256028a87562d6cf08
|
7
|
+
data.tar.gz: 512d2230352cfa529fbeb4a7c412fab72bde79b68660f6047d1fe5f81a76a25464b85ee3d3939c60b5d56357927a86d1c3e8a5a8fc83547f6e80c1a2cae39dce
|
data/.travis.yml
ADDED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
fleet-api (0.0
|
4
|
+
fleet-api (0.5.0)
|
5
5
|
faraday (= 0.8.9)
|
6
6
|
faraday_middleware (= 0.9.0)
|
7
7
|
|
@@ -44,5 +44,5 @@ DEPENDENCIES
|
|
44
44
|
fleet-api!
|
45
45
|
rake
|
46
46
|
rspec (~> 3.0)
|
47
|
-
simplecov
|
48
|
-
simplecov-rcov
|
47
|
+
simplecov (~> 0.9.0)
|
48
|
+
simplecov-rcov (~> 0.2.3)
|
data/LICENSE
CHANGED
@@ -186,7 +186,7 @@ Apache License
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
187
187
|
identification within third-party archives.
|
188
188
|
|
189
|
-
Copyright
|
189
|
+
Copyright 2014 CenturyLink
|
190
190
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
192
192
|
you may not use this file except in compliance with the License.
|
data/README.md
CHANGED
@@ -1,2 +1,115 @@
|
|
1
1
|
fleet-api
|
2
2
|
=========
|
3
|
+
|
4
|
+
Provides a Ruby wrapper around the CoreOS Fleet API.
|
5
|
+
|
6
|
+
The client allows programmatic access to most of the *fleetctl* commands including the ability to load, start, stop, unload and destroy unit files.
|
7
|
+
|
8
|
+
At this point, there is no official Fleet API (though one is [in the works](https://github.com/coreos/fleet/blob/master/Documentation/api-v1-alpha.md)) so this library mimcs the behavior of the *fleetctl* command line tool and simply writes data to the [etcd]() key-value-store. The Fleet daemon reads data out of specific keys in etcd and processes it as appropiate.
|
9
|
+
|
10
|
+
As work on the actual Fleet API progresses, this library will be refactored to use the real API.
|
11
|
+
|
12
|
+
An alternative implementation is available in the [cloudspace/ruby-fleetctl](https://github.com/cloudspace/ruby-fleetctl) gem. The *ruby-fleetctl* gem takes a different approach and uses SSH to interact directly with the *fleetctl* binary to send commands. Our approach of writing directly to etcd cuts out the *fleetctl* middleman but is in more danger of being broken by future releases since we're effectively using a "private API".
|
13
|
+
|
14
|
+
The current version of the *fleet-api* gem is known to work with version 0.5.0 of Fleet which ships with the the current stable version of CoreOS (367.1.0)
|
15
|
+
|
16
|
+
### Installation
|
17
|
+
|
18
|
+
Install the gem directly:
|
19
|
+
|
20
|
+
gem install fleet-api
|
21
|
+
|
22
|
+
Alternatively, add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
gem 'fleet-api', require: 'fleet'
|
25
|
+
|
26
|
+
|
27
|
+
### Usage
|
28
|
+
|
29
|
+
Configure the URL for the etcd API:
|
30
|
+
|
31
|
+
require 'fleet'
|
32
|
+
|
33
|
+
Fleet.configure do |fleet|
|
34
|
+
fleet.fleet_api_url = 'http://10.1.42.1:4001'
|
35
|
+
end
|
36
|
+
|
37
|
+
If you don't provide an explicit value for the `.fleet_api_url` attribute, it will default to using the value of the `FLEETCTL_ENDPOINT` environment variable.
|
38
|
+
|
39
|
+
**Note: since this Fleet API is not yet available in the stable version of CoreOS, the URL value provided must be the endpoint for the etcd API.**
|
40
|
+
|
41
|
+
#### Service Definitions
|
42
|
+
|
43
|
+
When submitting a service definition to the `Fleet::Client` you must convert your [unit file](http://www.freedesktop.org/software/systemd/man/systemd.unit.html) into a Ruby hash. Each section in the unit file is represented as a key/value pair in the hash where the key is the name of the section and the value is another hash containing all the statements for that section.
|
44
|
+
|
45
|
+
For example, look at the following unit file.
|
46
|
+
|
47
|
+
[Unit]
|
48
|
+
Description=Useless infinite loop
|
49
|
+
|
50
|
+
[Service]
|
51
|
+
ExecStart=/bin/bash -c "while true; do sleep 1; done"
|
52
|
+
|
53
|
+
This unit file would be represented as the following Ruby hash.
|
54
|
+
|
55
|
+
{
|
56
|
+
'Unit' => {
|
57
|
+
'Description' => 'Useless infinite loop'
|
58
|
+
},
|
59
|
+
'Service' => {
|
60
|
+
'ExecStart' => "/bin/bash -c \"while true; do sleep 1; done\""
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
#### Loading a Unit File
|
65
|
+
|
66
|
+
Equivalent of `fleetctl load`:
|
67
|
+
|
68
|
+
service = {
|
69
|
+
'Unit' => {
|
70
|
+
'Description' => 'Useless infinite loop'
|
71
|
+
},
|
72
|
+
'Service' => {
|
73
|
+
'ExecStart' => "/bin/bash -c \"while true; do sleep 1; done\""
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
client = Fleet.new
|
78
|
+
client.load('forever.service', service)
|
79
|
+
|
80
|
+
Note that the name you pass-in as the first parameter to the `.load` method should end in ".service"
|
81
|
+
|
82
|
+
#### Starting a Service
|
83
|
+
|
84
|
+
Equivalent of `fleetctl start`:
|
85
|
+
|
86
|
+
client = Fleet.new
|
87
|
+
client.start('forever.service')
|
88
|
+
|
89
|
+
#### Stopping a Service
|
90
|
+
|
91
|
+
Equivalent of `fleetctl stop`:
|
92
|
+
|
93
|
+
client = Fleet.new
|
94
|
+
client.stop('forever.service')
|
95
|
+
|
96
|
+
#### Unloading a Unit File
|
97
|
+
|
98
|
+
Equivalent of `fleetctl unload`:
|
99
|
+
|
100
|
+
client = Fleet.new
|
101
|
+
client.unload('forever.service')
|
102
|
+
|
103
|
+
#### Destroying a Service
|
104
|
+
|
105
|
+
Equivalent of `fleetctl destroy`:
|
106
|
+
|
107
|
+
client = Fleet.new
|
108
|
+
client.destroy('forever.service')
|
109
|
+
|
110
|
+
#### Retrieving Service Status
|
111
|
+
|
112
|
+
Equivalent of `fleetctl status`:
|
113
|
+
|
114
|
+
client = Fleet.new
|
115
|
+
client.status('forever.service')
|
data/fleet-api.gemspec
CHANGED
@@ -7,16 +7,18 @@ Gem::Specification.new do |gem|
|
|
7
7
|
gem.summary = 'A simple REST client for the CoreOS Fleet API'
|
8
8
|
gem.homepage = 'https://github.com/centurylinklabs/fleet-api'
|
9
9
|
gem.license = 'Apache 2'
|
10
|
+
gem.platform = Gem::Platform::RUBY
|
10
11
|
gem.files = `git ls-files`.split($\)
|
11
12
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
12
13
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
14
|
gem.name = 'fleet-api'
|
14
15
|
gem.require_paths = %w(lib)
|
15
16
|
gem.version = Fleet::VERSION
|
17
|
+
gem.required_ruby_version = '>= 1.9.3'
|
16
18
|
gem.add_dependency 'faraday', '= 0.8.9'
|
17
19
|
gem.add_dependency 'faraday_middleware', '= 0.9.0'
|
18
20
|
gem.add_development_dependency 'rake'
|
19
21
|
gem.add_development_dependency 'rspec', '~> 3.0'
|
20
|
-
gem.add_development_dependency 'simplecov'
|
21
|
-
gem.add_development_dependency 'simplecov-rcov'
|
22
|
+
gem.add_development_dependency 'simplecov', '~> 0.9.0'
|
23
|
+
gem.add_development_dependency 'simplecov-rcov', '~> 0.2.3'
|
22
24
|
end
|
data/lib/fleet/client.rb
CHANGED
@@ -12,7 +12,7 @@ module Fleet
|
|
12
12
|
|
13
13
|
FLEET_PATH = 'v2/keys/_coreos.com/fleet'
|
14
14
|
MAX_RETRIES = 10
|
15
|
-
SLEEP_TIME = (
|
15
|
+
SLEEP_TIME = (4.0 / MAX_RETRIES.to_f)
|
16
16
|
|
17
17
|
attr_accessor(*Configuration::VALID_OPTIONS_KEYS)
|
18
18
|
|
@@ -30,24 +30,26 @@ module Fleet
|
|
30
30
|
include Fleet::Client::State
|
31
31
|
include Fleet::Client::Unit
|
32
32
|
|
33
|
-
def load(name, service_def=
|
33
|
+
def load(name, service_def=nil)
|
34
34
|
|
35
|
-
|
36
|
-
service_def
|
37
|
-
|
35
|
+
if service_def
|
36
|
+
unless service_def.is_a?(ServiceDefinition)
|
37
|
+
service_def = ServiceDefinition.new(name, service_def)
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
begin
|
41
|
+
create_unit(service_def.sha1, service_def.to_unit)
|
42
|
+
rescue Fleet::PreconditionFailed
|
43
|
+
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
45
|
+
begin
|
46
|
+
create_job(service_def.name, service_def.to_job)
|
47
|
+
rescue Fleet::PreconditionFailed
|
48
|
+
end
|
47
49
|
end
|
48
50
|
|
49
|
-
update_job_target_state(
|
50
|
-
wait_for_load_state(
|
51
|
+
update_job_target_state(name, :loaded)
|
52
|
+
wait_for_load_state(name, 'loaded')
|
51
53
|
end
|
52
54
|
|
53
55
|
def start(service_name)
|
@@ -69,7 +71,7 @@ module Fleet
|
|
69
71
|
wait_for_load_state(service_name, :no_state)
|
70
72
|
end
|
71
73
|
|
72
|
-
def
|
74
|
+
def status(service_name)
|
73
75
|
fleet_state = get_state(service_name)
|
74
76
|
service_states = JSON.parse(fleet_state['node']['value'])
|
75
77
|
service_states.each_with_object({}) do |(k, v), hash|
|
@@ -86,7 +88,7 @@ module Fleet
|
|
86
88
|
def wait_for_load_state(service_name, target_state='loaded')
|
87
89
|
result = MAX_RETRIES.times do
|
88
90
|
begin
|
89
|
-
break target_state if
|
91
|
+
break target_state if status(service_name)[:load_state] == target_state
|
90
92
|
rescue Fleet::NotFound
|
91
93
|
# :no_state is a special case of target state that indicates we
|
92
94
|
# expect the state to not be found at all (useful when waiting for
|
data/lib/fleet/version.rb
CHANGED
data/spec/fleet/client_spec.rb
CHANGED
@@ -32,85 +32,117 @@ describe Fleet::Client do
|
|
32
32
|
{ 'node' => { 'value' => '{ "loadState": "loaded" }' } }
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
context 'when a service definition is provided' do
|
36
|
+
before do
|
37
|
+
allow(subject).to receive(:create_unit).and_return(nil)
|
38
|
+
allow(subject).to receive(:create_job).and_return(nil)
|
39
|
+
allow(subject).to receive(:update_job_target_state).and_return(nil)
|
40
|
+
allow(subject).to receive(:get_state).and_return(fleet_state)
|
41
|
+
allow(Fleet::ServiceDefinition).to receive(:new).and_return(sd)
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
44
|
+
it 'invokes #create_unit' do
|
45
|
+
expect(subject).to receive(:create_unit)
|
46
|
+
.with(sd.sha1, sd.to_unit)
|
46
47
|
|
47
|
-
|
48
|
-
|
48
|
+
subject.load(name, service_def)
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
it 'invokes #create_job' do
|
52
|
+
expect(subject).to receive(:create_job)
|
53
|
+
.with(sd.name, sd.to_job)
|
53
54
|
|
54
|
-
|
55
|
-
|
55
|
+
subject.load(name, service_def)
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
58
|
+
it 'invokes #update_job_target_state' do
|
59
|
+
expect(subject).to receive(:update_job_target_state)
|
60
|
+
.with(sd.name, :loaded)
|
60
61
|
|
61
|
-
|
62
|
-
|
62
|
+
subject.load(name, service_def)
|
63
|
+
end
|
63
64
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
it 'checks the job state' do
|
66
|
+
expect(subject).to receive(:get_state).with(sd.name)
|
67
|
+
subject.load(name, service_def)
|
68
|
+
end
|
68
69
|
|
69
|
-
|
70
|
+
context 'when #create_unit raises PreconditionFailed' do
|
70
71
|
|
71
|
-
|
72
|
-
|
73
|
-
|
72
|
+
before do
|
73
|
+
allow(subject).to receive(:create_unit)
|
74
|
+
.and_raise(Fleet::PreconditionFailed.new('boom'))
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'does not blow up' do
|
78
|
+
expect { subject.load(name, service_def) }.to_not raise_error
|
79
|
+
end
|
74
80
|
end
|
75
81
|
|
76
|
-
|
77
|
-
|
82
|
+
context 'when #create_unit raises something other than PreconditionFailed' do
|
83
|
+
|
84
|
+
before do
|
85
|
+
allow(subject).to receive(:create_unit)
|
86
|
+
.and_raise(Fleet::BadRequest.new('boom'))
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'propagates the error' do
|
90
|
+
expect { subject.load(name, service_def) }.to(raise_error(Fleet::BadRequest))
|
91
|
+
end
|
78
92
|
end
|
79
|
-
end
|
80
93
|
|
81
|
-
|
94
|
+
context 'when #create_job raises PreconditionFailed' do
|
82
95
|
|
83
|
-
|
84
|
-
|
85
|
-
|
96
|
+
before do
|
97
|
+
allow(subject).to receive(:create_job)
|
98
|
+
.and_raise(Fleet::PreconditionFailed.new('boom'))
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'does not blow up' do
|
102
|
+
expect { subject.load(name, service_def) }.to_not raise_error
|
103
|
+
end
|
86
104
|
end
|
87
105
|
|
88
|
-
|
89
|
-
|
106
|
+
context 'when #create_job raises something other than PreconditionFailed' do
|
107
|
+
|
108
|
+
before do
|
109
|
+
allow(subject).to receive(:create_job)
|
110
|
+
.and_raise(Fleet::BadRequest.new('boom'))
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'propagates the error' do
|
114
|
+
expect { subject.load(name, service_def) }.to(raise_error(Fleet::BadRequest))
|
115
|
+
end
|
90
116
|
end
|
91
117
|
end
|
92
118
|
|
93
|
-
context 'when
|
119
|
+
context 'when no service definition is provided' do
|
94
120
|
|
95
121
|
before do
|
96
|
-
allow(subject).to receive(:
|
97
|
-
|
122
|
+
allow(subject).to receive(:update_job_target_state).and_return(nil)
|
123
|
+
allow(subject).to receive(:get_state).and_return(fleet_state)
|
98
124
|
end
|
99
125
|
|
100
|
-
it 'does
|
101
|
-
expect
|
126
|
+
it 'does NOT invoke #create_unit' do
|
127
|
+
expect(subject).to_not receive(:create_unit)
|
128
|
+
subject.load(name)
|
102
129
|
end
|
103
|
-
end
|
104
130
|
|
105
|
-
|
131
|
+
it 'does NOT invoke #create_job' do
|
132
|
+
expect(subject).to_not receive(:create_job)
|
133
|
+
subject.load(name)
|
134
|
+
end
|
106
135
|
|
107
|
-
|
108
|
-
|
109
|
-
.
|
136
|
+
it 'invokes #update_job_target_state' do
|
137
|
+
expect(subject).to receive(:update_job_target_state)
|
138
|
+
.with(sd.name, :loaded)
|
139
|
+
|
140
|
+
subject.load(name)
|
110
141
|
end
|
111
142
|
|
112
|
-
it '
|
113
|
-
expect
|
143
|
+
it 'checks the job state' do
|
144
|
+
expect(subject).to receive(:get_state).with(sd.name)
|
145
|
+
subject.load(name)
|
114
146
|
end
|
115
147
|
end
|
116
148
|
end
|
@@ -223,7 +255,7 @@ describe Fleet::Client do
|
|
223
255
|
end
|
224
256
|
end
|
225
257
|
|
226
|
-
describe '#
|
258
|
+
describe '#status' do
|
227
259
|
|
228
260
|
let(:service_name) { 'foo.service' }
|
229
261
|
|
@@ -237,11 +269,11 @@ describe Fleet::Client do
|
|
237
269
|
|
238
270
|
it 'retrieves service state from the fleet client' do
|
239
271
|
expect(subject).to receive(:get_state).with(service_name)
|
240
|
-
subject.
|
272
|
+
subject.status(service_name)
|
241
273
|
end
|
242
274
|
|
243
275
|
it 'returns the state hash w/ normalized keys' do
|
244
|
-
expect(subject.
|
276
|
+
expect(subject.status(service_name)).to eq(load: 'loaded', run: 'running')
|
245
277
|
end
|
246
278
|
end
|
247
279
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fleet-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- CenturyLink
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -70,30 +70,30 @@ dependencies:
|
|
70
70
|
name: simplecov
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 0.9.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 0.9.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: simplecov-rcov
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: 0.2.3
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: 0.2.3
|
97
97
|
description: A simple REST client for the CoreOS Fleet API
|
98
98
|
email:
|
99
99
|
- clt-labs-futuretech@centurylink.com
|
@@ -102,6 +102,7 @@ extensions: []
|
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
104
|
- ".gitignore"
|
105
|
+
- ".travis.yml"
|
105
106
|
- Gemfile
|
106
107
|
- Gemfile.lock
|
107
108
|
- LICENSE
|
@@ -144,7 +145,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
144
145
|
requirements:
|
145
146
|
- - ">="
|
146
147
|
- !ruby/object:Gem::Version
|
147
|
-
version:
|
148
|
+
version: 1.9.3
|
148
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
150
|
requirements:
|
150
151
|
- - ">="
|
@@ -152,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
153
|
version: '0'
|
153
154
|
requirements: []
|
154
155
|
rubyforge_project:
|
155
|
-
rubygems_version: 2.
|
156
|
+
rubygems_version: 2.2.0
|
156
157
|
signing_key:
|
157
158
|
specification_version: 4
|
158
159
|
summary: A simple REST client for the CoreOS Fleet API
|