├── .gitignore
├── LICENSE
├── README.md
├── config
├── config.exs
├── dev.exs
├── prod.exs
└── test.exs
├── doc
├── Error.html
├── FleetApi.Api.html
├── FleetApi.Direct.html
├── FleetApi.Error.html
├── FleetApi.Etcd.html
├── FleetApi.Machine.html
├── FleetApi.Request.html
├── FleetApi.Unit.html
├── FleetApi.UnitOption.html
├── FleetApi.UnitState.html
├── FleetApi.html
├── README.html
├── css
│ ├── elixir.css
│ ├── full_list.css
│ └── style.css
├── exceptions_list.html
├── index.html
├── js
│ ├── app.js
│ ├── full_list.js
│ ├── highlight.pack.js
│ └── jquery.js
├── modules_list.html
├── overview.html
└── protocols_list.html
├── fixture
└── custom_cassettes
│ ├── delete_unit.json
│ ├── etcd_delete_unit.json
│ ├── etcd_get_api_discovery.json
│ ├── etcd_get_unit.json
│ ├── etcd_list_machines.json
│ ├── etcd_list_unit_states.json
│ ├── etcd_list_units.json
│ ├── etcd_list_units_empty.json
│ ├── etcd_list_units_multiple_calls.json
│ ├── etcd_list_units_null.json
│ ├── etcd_list_units_weird_response.json
│ ├── etcd_response_503_response.json
│ ├── etcd_response_no_nodes.json
│ ├── etcd_set_unit_new.json
│ ├── etcd_set_unit_update.json
│ ├── get_api_discovery.json
│ ├── get_unit.json
│ ├── get_unit_empty_options.json
│ ├── get_unit_missing_options.json
│ ├── get_unit_null_options.json
│ ├── list_machines.json
│ ├── list_machines_empty.json
│ ├── list_machines_null.json
│ ├── list_machines_weird_response.json
│ ├── list_unit_states.json
│ ├── list_unit_states_empty.json
│ ├── list_unit_states_null.json
│ ├── list_unit_states_weird_response.json
│ ├── list_units.json
│ ├── list_units_empty.json
│ ├── list_units_null.json
│ ├── list_units_weird_response.json
│ ├── set_unit_new.json
│ └── set_unit_update.json
├── lib
├── fleet_api.ex
└── fleet_api
│ ├── api.ex
│ ├── direct.ex
│ ├── error.ex
│ ├── etcd.ex
│ ├── machine.ex
│ ├── request.ex
│ ├── unit.ex
│ ├── unit_option.ex
│ └── unit_state.ex
├── mix.exs
├── mix.lock
└── test
├── direct_test.exs
├── etcd_test.exs
├── fleet_api_test.exs
└── test_helper.exs
/.gitignore:
--------------------------------------------------------------------------------
1 | /_build
2 | /deps
3 | erl_crash.dump
4 | *.ez
5 | *.beam
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Jordan Day
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FleetApi
2 |
3 | An elixir wrapper for the [Fleet API](https://github.com/coreos/fleet/blob/master/Documentation/api-v1.md). Connect to the API running on one of your fleet cluster nodes using either a direct node URL or an [etcd](https://etcd.io) etcd token.
4 |
5 | [](https://semaphoreci.com/jordanday/fleet-api) [](https://hex.pm/packages/fleet_api)
6 |
7 | ## Usage
8 | ### etcd token
9 |
10 | *Note that this is a config value you can set to override the port used to connect to the Fleet REST API when using an etcd token.*
11 | In your app's config, you can set
12 |
13 | ```elixir
14 | config :fleet_api, :etcd
15 | fix_port_number: true,
16 | api_port: 4001
17 | ```
18 | To get the api to use the correct port, regardless of what might be stored in etcd.
19 |
20 | ```elixir
21 | {:ok, pid} = FleetApi.Etcd.start_link("your etcd token")
22 | {:ok, units} = FleetApi.Etcd.list_units(pid)
23 |
24 | [%FleetApi.Unit{currentState: "launched", desiredState: "launched",
25 | machineID: "820c30c0867844129d63f4409871ba39", name: "subgun-http.service",
26 | options: [%FleetApi.UnitOption{name: "Description", section: "Unit",
27 | value: "subgun"},
28 | %FleetApi.UnitOption{name: "ExecStartPre", section: "Service",
29 | value: "-/usr/bin/docker kill subgun-%i"},
30 | %FleetApi.UnitOption{name: "ExecStartPre", section: "Service",
31 | value: "-/usr/bin/docker rm subgun-%i"}...]
32 | ```
33 |
34 | ### Direct node URL
35 |
36 | ```elixir
37 | {:ok, pid} = FleetApi.Direct.start_link("http://your-node-host-or-ip:7002")
38 | {:ok, units} = FleetApi.Direct.list_units(pid)
39 |
40 | [%FleetApi.Unit{currentState: "launched", desiredState: "launched",
41 | machineID: "820c30c0867844129d63f4409871ba39", name: "subgun-http.service",
42 | options: [%FleetApi.UnitOption{name: "Description", section: "Unit",
43 | value: "subgun"},
44 | %FleetApi.UnitOption{name: "ExecStartPre", section: "Service",
45 | value: "-/usr/bin/docker kill subgun-%i"},
46 | %FleetApi.UnitOption{name: "ExecStartPre", section: "Service",
47 | value: "-/usr/bin/docker rm subgun-%i"}...]
48 | ```
49 |
--------------------------------------------------------------------------------
/config/config.exs:
--------------------------------------------------------------------------------
1 | # This file is responsible for configuring your application
2 | # and its dependencies with the aid of the Mix.Config module.
3 | use Mix.Config
4 |
5 | # This configuration is loaded before any dependency and is restricted
6 | # to this project. If another project depends on this project, this
7 | # file won't be loaded nor affect the parent project. For this reason,
8 | # if you want to provide default values for your application for third-
9 | # party users, it should be done in your mix.exs file.
10 |
11 | # Sample configuration:
12 | #
13 | # config :logger, :console,
14 | # level: :info,
15 | # format: "$date $time [$level] $metadata$message\n",
16 | # metadata: [:user_id]
17 |
18 | # It is also possible to import configuration files, relative to this
19 | # directory. For example, you can emulate configuration per environment
20 | # by uncommenting the line below and defining dev.exs, test.exs and such.
21 | # Configuration from the imported file will override the ones defined
22 | # here (which is why it is important to import them last).
23 | #
24 |
25 | # For some reason, when the nodes register themselves with etcd, they seem to
26 | # give an incorrect port number. Manually override the port used by setting
27 | # `fix_port_number` to true, and providing the correct port in `port_number`.
28 | config :fleet_api, :etcd,
29 | fix_port_number: true,
30 | api_port: 7002
31 |
32 | import_config "#{Mix.env}.exs"
33 |
--------------------------------------------------------------------------------
/config/dev.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # config :fleet_api,
4 | # proxy: {"your-proxy.com", 80}
--------------------------------------------------------------------------------
/config/prod.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
--------------------------------------------------------------------------------
/config/test.exs:
--------------------------------------------------------------------------------
1 | use Mix.Config
2 |
3 | # config :fleet_api,
4 | # proxy: {"your-proxy.com", 80}
--------------------------------------------------------------------------------
/doc/Error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Error
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | Error
31 |
32 |
33 |
34 |
45 |
46 |
47 |
48 | Wraps error messages received from the Fleet API.
49 |
50 |
51 |
52 |
53 |
54 | Source
55 |
56 |
57 |
58 | Summary
59 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | Functions
73 |
74 |
82 |
83 |
86 |
87 | Source
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/doc/FleetApi.Api.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi.Api
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi.Api
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Source
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/doc/FleetApi.Direct.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi.Direct
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi.Direct
31 |
32 |
33 |
34 |
45 |
46 |
47 |
48 | Accesses the Fleet API via a directly-identified node URL.
49 |
50 |
51 |
52 |
53 |
54 | Source
55 |
56 |
57 |
58 | Summary
59 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | Functions
130 |
131 |
139 |
140 |
144 |
145 | Source
146 |
147 |
148 |
149 |
157 |
158 |
162 |
163 | Source
164 |
165 |
166 |
167 |
175 |
176 | Specs:
177 |
178 |
179 | get_node_url(pid) :: String.t
180 |
181 |
182 |
183 |
184 | Retrieves the Fleet node URL based on the URL provided when the GenServer
185 | was started.
186 |
187 |
188 |
189 | Source
190 |
191 |
192 |
193 |
201 |
202 |
206 |
207 | Source
208 |
209 |
210 |
211 |
219 |
220 |
224 |
225 | Source
226 |
227 |
228 |
229 |
237 |
238 |
242 |
243 | Source
244 |
245 |
246 |
247 |
255 |
256 |
260 |
261 | Source
262 |
263 |
264 |
265 |
273 |
274 |
278 |
279 | Source
280 |
281 |
282 |
283 |
291 |
292 |
295 |
296 | Source
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
--------------------------------------------------------------------------------
/doc/FleetApi.Error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi.Error
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi.Error
31 |
32 |
33 |
34 |
47 |
48 |
49 |
50 | Defines a FleetApi.Error
struct, representing erros that may be returned
51 | when making Fleet API calls.
52 | The following fields are public:
53 |
54 | code
- The HTTP status code of the response.
55 |
56 | message
- A human-readable error message explaining the failure.
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | Source
65 |
66 |
67 |
68 | Summary
69 |
76 |
77 |
78 |
79 |
80 | Types ↑
81 |
82 |
83 | t :: %FleetApi.Error{code: term, message: term}
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | Functions
94 |
95 |
103 |
104 | Specs:
105 |
110 |
111 |
114 |
115 | Source
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/doc/FleetApi.Etcd.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi.Etcd
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi.Etcd
31 |
32 |
33 |
34 |
45 |
46 |
47 |
48 | Accesses the Fleet API via a URL discovered through etcd.
49 |
50 |
51 |
52 |
53 |
54 | Source
55 |
56 |
57 |
58 | Summary
59 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | Functions
130 |
131 |
139 |
140 |
144 |
145 | Source
146 |
147 |
148 |
149 |
157 |
158 |
162 |
163 | Source
164 |
165 |
166 |
167 |
175 |
176 | Specs:
177 |
178 |
179 | get_node_url(pid) :: String.t | {:error, any}
180 |
181 |
182 |
183 |
184 | Retrieves a Fleet node URL based on the information stored in etcd, using the
185 | etcd token specified when the GenServer was started.
186 |
187 |
188 |
189 | Source
190 |
191 |
192 |
193 |
201 |
202 |
206 |
207 | Source
208 |
209 |
210 |
211 |
219 |
220 |
224 |
225 | Source
226 |
227 |
228 |
229 |
237 |
238 |
242 |
243 | Source
244 |
245 |
246 |
247 |
255 |
256 |
260 |
261 | Source
262 |
263 |
264 |
265 |
273 |
274 |
278 |
279 | Source
280 |
281 |
282 |
283 |
291 |
292 |
295 |
296 | Source
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
--------------------------------------------------------------------------------
/doc/FleetApi.Machine.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi.Machine
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi.Machine
31 |
32 |
33 |
34 |
47 |
48 |
49 |
50 | Defines a FleetApi.Machine
struct, representing a host in the Fleet
51 | cluster. It uses the host’s machine-id
52 | as a unique identifier.
53 | The following fields are public:
54 |
55 | id
- unique identifier of Machine entity.
56 |
57 | primaryIP
- IP address that should be used to communicate with this host.
58 |
59 | metadata
- dictionary of key-value data published by the machine.
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Source
68 |
69 |
70 |
71 | Summary
72 |
87 |
88 |
89 |
90 |
91 | Types ↑
92 |
93 |
94 | t :: %FleetApi.Machine{id: term, metadata: term, primaryIP: term}
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | Functions
105 |
106 |
114 |
115 | Specs:
116 |
121 |
122 |
125 |
126 | Source
127 |
128 |
129 |
130 |
138 |
139 | Specs:
140 |
145 |
146 |
147 | Checks if this machine is responding to requests by attempting to access the
148 | API discovery endpoint of the Fleet API.
149 |
150 |
151 |
152 | Source
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/doc/FleetApi.Request.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi.Request
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi.Request
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Source
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/doc/FleetApi.Unit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi.Unit
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi.Unit
31 |
32 |
33 |
34 |
47 |
48 |
49 |
50 | Defines a FleetApi.Unit
struct, representing a service in a fleet cluster.
51 | The following fields are public:
52 |
53 | name
- unique identifier of entity.
54 |
55 | options
- list of UnitOption entities.
56 |
57 | desiredState
- state the user wishes the unit to be in (“inactive”, “loaded”, or “launched”).
58 |
59 | currentState
- state the unit is currently in (same possible values as desiredState).
60 |
61 | machineID
- ID of machine to which the unit is scheduled.
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | Source
70 |
71 |
72 |
73 | Summary
74 |
81 |
82 |
83 |
84 |
85 | Types ↑
86 |
87 |
88 | t :: %FleetApi.Unit{currentState: term, desiredState: term, machineID: term, name: term, options: term}
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | Functions
99 |
100 |
108 |
109 | Specs:
110 |
115 |
116 |
119 |
120 | Source
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/doc/FleetApi.UnitOption.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi.UnitOption
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi.UnitOption
31 |
32 |
33 |
34 |
47 |
48 |
49 |
50 | Defines a FleetApi.UnitOption
struct, representing one segment of the information used to describe a unit.
51 | The following fields are public:
52 |
53 | name
- name of option (e.g. “BindsTo”, “After”, “ExecStart”).
54 |
55 | section
- name of section that contains the option (e.g. “Unit”, “Service”, “Socket”).
56 |
57 | value
- value of option (e.g. “/usr/bin/docker run busybox /bin/sleep 1000”).
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | Source
66 |
67 |
68 |
69 | Summary
70 |
77 |
78 |
79 |
80 |
81 | Types ↑
82 |
83 |
84 | t :: %FleetApi.UnitOption{name: term, section: term, value: term}
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | Functions
95 |
96 |
104 |
105 | Specs:
106 |
111 |
112 |
115 |
116 | Source
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/doc/FleetApi.UnitState.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi.UnitState
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi.UnitState
31 |
32 |
33 |
34 |
47 |
48 |
49 |
50 | Defines a FleetApi.UnitState
struct, representing the current state of a particular unit.
51 | The following fields are public:
52 |
53 | name
- unique identifier of entity.
54 |
55 | hash
- SHA1 hash of underlying unit file.
56 |
57 | machineID
- ID of machine from which this state originated.
58 |
59 | systemdLoadState
- load state as reported by systemd.
60 |
61 | systemdActiveState
- active state as reported by systemd.
62 |
63 | systemdSubState
- sub state as reported by systemd.
64 | A unit state represents the current state of a given unit.
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | Source
73 |
74 |
75 |
76 | Summary
77 |
84 |
85 |
86 |
87 |
88 | Types ↑
89 |
90 |
91 | t :: %FleetApi.UnitState{hash: term, machineID: term, name: term, systemdActiveState: term, systemdLoadState: term, systemdSubState: term}
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | Functions
102 |
103 |
111 |
112 | Specs:
113 |
118 |
119 |
122 |
123 | Source
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/doc/FleetApi.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FleetApi
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | FleetApi
31 |
32 | behaviour
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Callbacks
43 |
44 |
45 |
46 |
47 |
48 | This module contains callback declarations for interacting with a Fleet API endpoint.
49 |
50 |
51 |
52 |
53 |
54 | Source
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Callbacks
68 |
69 |
77 |
78 | Specs:
79 |
80 |
81 | delete_unit(pid, unit_name :: String.t ) :: :ok | {:error, any}
82 |
83 |
84 |
85 |
86 | Remove a unit from the Fleet cluster.
87 |
88 |
89 |
90 | Source
91 |
92 |
93 |
94 |
102 |
103 | Specs:
104 |
105 |
106 | get_api_discovery(pid) :: {:ok, Map.t } | {:error, any}
107 |
108 |
109 |
110 |
111 | Retrieve the API Discovery document JSON for the Fleet API.
112 |
113 |
114 |
115 | Source
116 |
117 |
118 |
119 |
127 |
128 | Specs:
129 |
134 |
135 |
136 | Retrieve the details for a specific unit in the Fleet cluster.
137 |
138 |
139 |
140 | Source
141 |
142 |
143 |
144 |
152 |
153 | Specs:
154 |
159 |
160 |
161 | Retrieve the list of nodes currently in the Fleet cluster.
162 |
163 |
164 |
165 | Source
166 |
167 |
168 |
169 |
177 |
178 | Specs:
179 |
184 |
185 |
186 | Get the detailed state information for all the units in the Fleet cluster.
187 | You may optionally provide options machineID
and/or unitName
to filter
188 | the response to a particular host or unit.
189 |
190 |
191 |
192 | Source
193 |
194 |
195 |
196 |
204 |
205 | Specs:
206 |
207 |
208 | list_units(pid) :: {:ok, [FleetApi.Unit.t ]} | {:error, any}
209 |
210 |
211 |
212 |
213 | Retrieve the list of units that the Fleet cluster currently knows about.
214 |
215 |
216 |
217 | Source
218 |
219 |
220 |
221 |
229 |
230 | Specs:
231 |
236 |
237 |
238 | Adds or updates a unit in the Fleet cluster. If the cluster doesn’t contain a
239 | unit with the given name, then a new unit is added to it. If a unit with the
240 | given name exists, it is updated with the new unit definition.
241 |
242 |
243 |
244 | Source
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
--------------------------------------------------------------------------------
/doc/README.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | README
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 | FleetApi
25 | An elixir wrapper for the Fleet API . Connect to the API running on one of your fleet cluster nodes using either a direct node URL or an etcd etcd token.
26 |
27 | Usage
28 | etcd token
29 | Note that this is a config value you can set to override the port used to connect to the Fleet API when using an etcd token.
30 | In your app’s config, you can set
31 | config :fleet_api, :etcd
32 | fix_port_number: true,
33 | api_port: 4001
34 | To get the api to use the correct port, regardless of what might be stored in etcd.
35 | {:ok, pid} = FleetApi.Etcd.start_link("your etcd token")
36 | {:ok, units} = FleetApi.Etcd.list_units(pid)
37 |
38 | [%FleetApi.Unit{currentState: "launched", desiredState: "launched",
39 | machineID: "820c30c0867844129d63f4409871ba39", name: "subgun-http.service",
40 | options: [%FleetApi.UnitOption{name: "Description", section: "Unit",
41 | value: "subgun"},
42 | %FleetApi.UnitOption{name: "ExecStartPre", section: "Service",
43 | value: "-/usr/bin/docker kill subgun-%i"},
44 | %FleetApi.UnitOption{name: "ExecStartPre", section: "Service",
45 | value: "-/usr/bin/docker rm subgun-%i"}...]
46 | Direct node URL
47 | {:ok, pid} = FleetApi.Direct.start_link("http://your-node-host-or-ip:7002")
48 | {:ok, units} = FleetApi.Direct.list_units(pid)
49 |
50 | [%FleetApi.Unit{currentState: "launched", desiredState: "launched",
51 | machineID: "820c30c0867844129d63f4409871ba39", name: "subgun-http.service",
52 | options: [%FleetApi.UnitOption{name: "Description", section: "Unit",
53 | value: "subgun"},
54 | %FleetApi.UnitOption{name: "ExecStartPre", section: "Service",
55 | value: "-/usr/bin/docker kill subgun-%i"},
56 | %FleetApi.UnitOption{name: "ExecStartPre", section: "Service",
57 | value: "-/usr/bin/docker rm subgun-%i"}...]
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/doc/css/elixir.css:
--------------------------------------------------------------------------------
1 | /*
2 | github.com style (c) Vasily Polovnyov
3 | */
4 |
5 | .hljs {
6 | overflow-x: auto;
7 | color: #333;
8 | padding: 0.5em;
9 | border: #ffe0bb dotted 1px;
10 | background: #fffde8;
11 | display: block;
12 | -webkit-text-size-adjust: none;
13 | }
14 |
15 | .hljs-comment,
16 | .diff .hljs-header,
17 | .hljs-javadoc {
18 | color: #998;
19 | font-style: italic;
20 | }
21 |
22 | .hljs-keyword,
23 | .css .rule .hljs-keyword,
24 | .hljs-winutils,
25 | .nginx .hljs-title,
26 | .hljs-subst,
27 | .hljs-request,
28 | .hljs-status {
29 | color: #333;
30 | font-weight: bold;
31 | }
32 |
33 | .hljs-number,
34 | .hljs-hexcolor,
35 | .ruby .hljs-constant {
36 | color: #008080;
37 | }
38 |
39 | .hljs-string,
40 | .hljs-tag .hljs-value,
41 | .hljs-phpdoc,
42 | .hljs-dartdoc,
43 | .tex .hljs-formula {
44 | color: #d14;
45 | }
46 |
47 | .hljs-title,
48 | .hljs-id,
49 | .scss .hljs-preprocessor {
50 | color: #900;
51 | font-weight: bold;
52 | }
53 |
54 | .hljs-list .hljs-keyword,
55 | .hljs-subst {
56 | font-weight: normal;
57 | }
58 |
59 | .hljs-class .hljs-title,
60 | .hljs-type,
61 | .vhdl .hljs-literal,
62 | .tex .hljs-command {
63 | color: #445588;
64 | font-weight: bold;
65 | }
66 |
67 | .hljs-tag,
68 | .hljs-tag .hljs-title,
69 | .hljs-rules .hljs-property,
70 | .django .hljs-tag .hljs-keyword {
71 | color: #000080;
72 | font-weight: normal;
73 | }
74 |
75 | .hljs-attribute,
76 | .hljs-variable,
77 | .lisp .hljs-body {
78 | color: #008080;
79 | }
80 |
81 | .hljs-regexp {
82 | color: #009926;
83 | }
84 |
85 | .hljs-symbol,
86 | .ruby .hljs-symbol .hljs-string,
87 | .lisp .hljs-keyword,
88 | .clojure .hljs-keyword,
89 | .scheme .hljs-keyword,
90 | .tex .hljs-special,
91 | .hljs-prompt {
92 | color: #990073;
93 | }
94 |
95 | .hljs-built_in {
96 | color: #0086b3;
97 | }
98 |
99 | .hljs-preprocessor,
100 | .hljs-pragma,
101 | .hljs-pi,
102 | .hljs-doctype,
103 | .hljs-shebang,
104 | .hljs-cdata {
105 | color: #999;
106 | font-weight: bold;
107 | }
108 |
109 | .hljs-deletion {
110 | background: #fdd;
111 | }
112 |
113 | .hljs-addition {
114 | background: #dfd;
115 | }
116 |
117 | .diff .hljs-change {
118 | background: #0086b3;
119 | }
120 |
121 | .hljs-chunk {
122 | color: #aaa;
123 | }
124 |
--------------------------------------------------------------------------------
/doc/css/full_list.css:
--------------------------------------------------------------------------------
1 | /*** DOCUMENT STRUCTURE: list_template.eex ***
2 | body.frames
3 | section#content [.in_search]
4 | h1#full_list_header
5 | h2#sub_list_header
6 | div#nav
7 | div#search [.loading] > input#search_field
8 | ul#full_list
9 | li.node [.collpased, .search_uncollapsed, .found]
10 | a.toggle
11 | a.object_link
12 | span.node_name
13 | li.docs [.collpased, .search_uncollapsed, .found]
14 | a.toggle
15 | a.object_link
16 | span.node_name
17 | ...
18 | div.no_results
19 | */
20 |
21 | /* DOCUMENT STYLES */
22 | body {
23 | font: 13px "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif;
24 | height: 101%;
25 | margin: 0;
26 | overflow-x: hidden;
27 | }
28 | h1 {
29 | font-size: 1.4em;
30 | margin: 0;
31 | padding: 12px 10px 0;
32 | }
33 | a:link, a:visited {
34 | color: #05a;
35 | text-decoration: none;
36 | }
37 | li {
38 | color: #888;
39 | cursor: pointer;
40 | }
41 | li:hover {
42 | background: #ddd;
43 | }
44 | span.node_name {
45 | font-size: 0.8em;
46 | }
47 |
48 | /*** LEFT FRAME ***/
49 | .frames li {
50 | white-space: nowrap;
51 | cursor: default;
52 | }
53 |
54 | /* HEADERS */
55 | .frames h1 {
56 | margin-top: 0;
57 | }
58 | .frames h2 {
59 | font-size: 0.9em;
60 | margin: 5px 10px 15px;
61 | }
62 |
63 | /* NAVIGATION BAR */
64 | .nav {
65 | margin: 0 0 10px 5px;
66 | font-size: 0.9em;
67 | color: #aaa;
68 | }
69 | .nav a:link,
70 | .nav a:visited {
71 | color: #358;
72 | }
73 | .nav a:hover {
74 | background: transparent;
75 | color: #5af;
76 | }
77 | .nav span {
78 | border-left: 1px solid #ccc;
79 | padding: 0 3px 0 5px;
80 | }
81 | .nav span:first-child {
82 | border-left: 0;
83 | border-radius: 3px;
84 | }
85 | .nav span.selected {
86 | text-decoration: underline;
87 | }
88 |
89 | /* SEARCH BOX */
90 | #search {
91 | font-size: 0.9em;
92 | color: #888;
93 | margin: 3px; margin-left: 10px;
94 | padding-left: 0; padding-right: 24px;
95 | }
96 | #search_field {
97 | width: 180px;
98 | margin-right:35px;
99 | border:2px solid #d8d8e5;
100 | padding:2px 4px;
101 | -moz-box-sizing: border-box;
102 | }
103 | #search.loading {
104 | background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat 188px center;
105 | min-height:18px;
106 | }
107 | #content #no_results {
108 | margin-left: 7px;
109 | padding: 7px 12px;
110 | }
111 |
112 | /* FULL LIST OF CONTENTS */
113 | #full_list {
114 | list-style: none;
115 | margin-left: 0;
116 | padding: 0;
117 | }
118 | #full_list ul {
119 | margin:0;
120 | padding: 0;
121 | }
122 | #full_list li {
123 | margin: 0;
124 | padding: 5px 5px 5px 0;
125 | font-size: 1.1em;
126 | list-style: none;
127 | }
128 | #full_list li.node {
129 | padding-left: 25px;
130 | }
131 | #full_list li.docs {
132 | padding:0;
133 | }
134 | #full_list li.docs li {
135 | padding-left: 25px;
136 | }
137 | #full_list li span.node_name {
138 | display: none;
139 | }
140 | #full_list .no_padding {
141 | padding-left:0;
142 | }
143 | /* while searching */
144 | .in_search #full_list ul {
145 | margin-left:0;}
146 | .in_search #full_list li {
147 | display: none;
148 | }
149 | .in_search #full_list li.found {
150 | display: list-item;
151 | }
152 | .in_search #full_list li a.toggle {
153 | display: none;
154 | }
155 | .in_search #full_list li span.node_name {
156 | display: block;
157 | }
158 | /* collapsed menu */
159 | #full_list .search_uncollapsed,
160 | #full_list .search_uncollapsed ul {
161 | display:block !important;
162 | }
163 | #full_list ul.collapsed ul,
164 | #full_list ul.collapsed li,
165 | #full_list li.collapsed ul,
166 | #full_list li.collapsed li {
167 | display: none;
168 | }
169 | #full_list ul.search_uncollapsed li.found,
170 | #full_list li.search_uncollapsed li.found {
171 | display: list-item;
172 | }
173 | li.deprecated {
174 | text-decoration: line-through;
175 | font-style: italic;
176 | }
177 | li.r1 {
178 | background: #f0f0f0;
179 | }
180 | li.r2 {
181 | background: #fafafa;
182 | }
183 | /* link properties */
184 | li a.toggle {
185 | display: block;
186 | float: left;
187 | position: relative;
188 | left: -5px;
189 | top: 4px;
190 | width: 10px;
191 | height: 9px;
192 | margin-left: -10px;
193 | text-indent: -999px;
194 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left;
195 | cursor: default;
196 | }
197 | li.collapsed a.toggle {
198 | opacity: 0.5;
199 | cursor: default;
200 | background-position: top left;
201 | }
202 | li.clicked {
203 | background: #05a;
204 | color: #ccc;
205 | }
206 | li.clicked a:link, li.clicked a:visited {
207 | color: #eee;
208 | }
209 | li.clicked a.toggle {
210 | opacity: 0.5;
211 | background-position: bottom right;
212 | }
213 | li.collapsed.clicked a.toggle {
214 | background-position: top right;
215 | }
216 |
--------------------------------------------------------------------------------
/doc/css/style.css:
--------------------------------------------------------------------------------
1 | /*** DOCUMENT STRUCTURE: module_template.eex ***
2 | body
3 | section#content
4 | div.breadcrumbs
5 |
6 | h1
7 | small
8 |
9 | ul.summary_links
10 | li > a
11 | ...
12 |
13 | section.docstring#moduledoc
14 | a.view_source
15 |
16 | h2#summary > span.detail_header_links > a.to_top_link
17 | table.summary
18 | tr
19 | td.summary_signature > a
20 | td.summary_synopsis > p
21 | ...
22 |
23 | section.details_list#types_details
24 | h2 > a.to_top_link
25 | div.type_detail
26 | p.typespec > a
27 | ...
28 |
29 | section.details_list#functions_details
30 | h2
31 | section.detail
32 | div.detail_header
33 | span.signature > strong
34 | div.detail_header_links
35 | span.detail_type
36 | a.detail_link
37 | a.to_top_link
38 | ul.spec
39 | li > a
40 | ...
41 | section.docstring
42 | a.view_source
43 | ...
44 |
45 | */
46 |
47 | /* DOCUMENT STYLES */
48 | body {
49 | font: 13px "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif;
50 | padding: 0 20px;
51 | }
52 |
53 | a:link,
54 | a:visited {
55 | color: #05a;
56 | text-decoration: none;
57 | }
58 | a:hover {
59 | color: #27c;
60 | }
61 |
62 | h1 {
63 | font-size: 25px;
64 | border-top: 0;
65 | margin-top: 0;
66 | padding-top: 4px;
67 | }
68 | h1 small {
69 | color: #888;
70 | font-size: 18px;
71 | }
72 | h2 {
73 | padding: 0;
74 | padding-bottom: 3px;
75 | border-bottom: 1px #aaa solid;
76 | font-size: 1.4em;
77 | margin: 1.8em 0 0.5em;
78 | }
79 |
80 | .clear {
81 | clear: both;
82 | }
83 |
84 | table {
85 | border: 1px solid #aaa;
86 | border-collapse: collapse;
87 | margin-top: 1em;
88 | }
89 | table th {
90 | background: #fafafa;
91 | }
92 | table th,
93 | table td {
94 | border: 1px solid #ddd;
95 | padding: 0.4em 1em 0.4em 0.4em;
96 | }
97 | table tr:nth-child(odd) {
98 | background: #f0f0f0;
99 | }
100 | table tr:nth-child(even) {
101 | background: #fafafa;
102 | }
103 |
104 | /* OTHERS */
105 | body.frames {
106 | padding: 0 5px;
107 | }
108 | li.r1 {
109 | background: #f0f0f0;
110 | }
111 | li.r2 {
112 | background: #fafafa;
113 | }
114 | div.breadcrumbs {
115 | padding-bottom: 0.5em;
116 | }
117 |
118 | /* SUMMARY LINKS */
119 | ul.summary_links {
120 | margin: 0 0 1em 0;
121 | padding: 0em;
122 | }
123 | ul.summary_links li {
124 | display: inline-block;
125 | list-style-type: none;
126 | width: 7em;
127 | text-align: center;
128 | background: #f0f0f0;
129 | }
130 |
131 | /* DOCSTRING */
132 | section.docstring,
133 | p.docstring {
134 | margin-right: 6em;
135 | }
136 | .docstring h1,
137 | .docstring h2,
138 | .docstring h3,
139 | .docstring h4 {
140 | padding: 0;
141 | border: 0;
142 | }
143 | .docstring h1 {
144 | font-size: 1.3em;
145 | }
146 | .docstring h2 {
147 | font-size: 1.2em;
148 | }
149 | .docstring h3,
150 | .docstring h4 {
151 | font-size: 1em;
152 | padding-top: 10px;
153 | }
154 | .docstring ul {
155 | padding-left: 20px;
156 | }
157 | .docstring li > p {
158 | margin: 0;
159 | }
160 |
161 | /* SUMMARY */
162 | div.detail_header_links {
163 | float: right;
164 | }
165 | a.to_top_link {
166 | padding-left: 0.3em;
167 | font-size: 1em;
168 | font-weight: normal;
169 | }
170 | table.summary {
171 | border: 0;
172 | border-collapse: separate;
173 | }
174 | table.summary tr:nth-child(odd) {
175 | background: #f0f0f0;
176 | }
177 | table.summary tr:nth-child(even) {
178 | background: #fafafa;
179 | }
180 | table.summary tr td {
181 | border: 0;
182 | padding-top: 0.5em; padding-bottom: 0.5em;
183 | }
184 | td.summary_signature {
185 | padding-right: 0.5em;
186 | }
187 | td.summary_synopsis {
188 | padding-left: 0.5em;
189 | }
190 | td.summary_synopsis p {
191 | margin: 0;
192 | }
193 |
194 | /* DETAILS LIST */
195 | .spec, .typespec {
196 | font: bold 1em Courier, monospace;
197 | }
198 | ul.spec {
199 | padding: 6px 10px 6px 25px;
200 | list-style-type: none;
201 | }
202 | .type_detail {
203 | margin-top: 15px;
204 | padding-top: 0;
205 | }
206 | .type_detail > div.typespec_doc {
207 | margin-left: 3em;
208 | }
209 | .detail {
210 | border-top: 1px dotted #aaa;
211 | margin-top: 15px;
212 | padding-top: 0;
213 | }
214 | .detail:nth-child(2) {
215 | border: 0;
216 | }
217 | div.detail_header {
218 | background: #e5e8ff;
219 | border: 1px solid #d8d8e5;
220 | border-radius: 3px;
221 | margin-top: 18px;
222 | padding: 6px 10px;
223 | }
224 | span.signature {
225 | font: normal 1.1em Monaco, Consolas, Courier, monospace;
226 | }
227 | span.detail_type {
228 | font-style: italic;
229 | font-size: 0.9em;
230 | }
231 | a.detail_link {
232 | padding-left: 0.3em;
233 | }
234 |
--------------------------------------------------------------------------------
/doc/exceptions_list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | List of Exceptions
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/doc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | fleet_api v0.0.15 Documentation
7 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/doc/js/app.js:
--------------------------------------------------------------------------------
1 | function fixOutsideWorldLinks() {
2 | $('a').each(function() {
3 | if (window.location.host != this.host) this.target = '_parent';
4 | });
5 | }
6 |
7 | $(fixOutsideWorldLinks);
8 |
--------------------------------------------------------------------------------
/doc/js/full_list.js:
--------------------------------------------------------------------------------
1 | var inSearch = null;
2 | var defaultSearchItemTimeOut = 0; //set to "0" if not testing
3 | var searchIndex = 0;
4 | var searchCache = [];
5 | var searchString = '';
6 | var regexSearchString = '';
7 | var caseSensitiveMatch = false;
8 | var ignoreKeyCodeMin = 8;
9 | var ignoreKeyCodeMax = 46;
10 | var commandKey = 91;
11 |
12 | RegExp.escape = function(text) {
13 | return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
14 | }
15 |
16 | function fullListSearch() {
17 | // generate cache
18 | searchCache = [];
19 | $('#full_list li').each(function() {
20 | var link = $(this).find('a.object_link:first');
21 | if ( link.attr('title') ) {
22 | var fullName = link.attr('title').split(' ')[0];
23 | searchCache.push({name:link.text(), fullName:fullName, node:$(this), link:link});
24 | }
25 | });
26 |
27 | $('#search input').keypress(function (e) {
28 | if (e.which == 13) {
29 | $('#full_list li.found:first').find('a.object_link:first').click();
30 | }
31 | });
32 |
33 | //$('#search input').keyup(function(evnt) {
34 | $('#search input').bind("keyup search reset change propertychange input paste", function(evnt) {
35 | if ((evnt.keyCode > ignoreKeyCodeMin && evnt.keyCode < ignoreKeyCodeMax)
36 | || evnt.keyCode == commandKey) {
37 | return;
38 | }
39 |
40 | $('#search').addClass('loading');
41 | searchString = this.value;
42 | caseSensitiveMatch = searchString.match(/[A-Z]/) != null;
43 | regexSearchString = RegExp.escape(searchString);
44 | if (searchString === "") {
45 | showAllResults();
46 | }
47 | else {
48 | if (inSearch) {
49 | clearTimeout(inSearch);
50 | }
51 | searchIndex = 0;
52 | lastRowClass = '';
53 | $('#content').addClass('in_search');
54 | $('#no_results').text('');
55 | searchItem();
56 | }
57 | });
58 |
59 | $('#search input').focus();
60 | }
61 |
62 | function showAllResults() {
63 | clearTimeout(inSearch);
64 | inSearch = defaultSearchItemTimeOut;
65 | $('.search_uncollapsed').removeClass('search_uncollapsed');
66 | $('#content').removeClass('in_search');
67 | $('#full_list li').removeClass('found').each(function() {
68 | var link = $(this).find('a.object_link:first');
69 | link.text(link.text());
70 | });
71 | if (clicked) {
72 | clicked.parents('li').each(function() {
73 | $(this).removeClass('collapsed').prev().removeClass('collapsed');
74 | });
75 | }
76 | $('#no_results').text('');
77 | $('#search').removeClass('loading');
78 | highlight();
79 | }
80 |
81 | var lastRowClass = '';
82 | function searchItem() {
83 | for (var i = 0; i < searchCache.length / 50; i++) {
84 | var item = searchCache[searchIndex];
85 | var searchName = (searchString.indexOf('.') != -1 ? item.fullName : item.name);
86 | var matchString = regexSearchString;
87 | var matchRegexp = new RegExp(matchString, caseSensitiveMatch ? "" : "i");
88 | if (searchName.match(matchRegexp) == null) {
89 | item.node.removeClass('found');
90 | }
91 | else {
92 | item.node.addClass('found');
93 | item.node.parents('li').addClass('search_uncollapsed');
94 | item.node.removeClass(lastRowClass).addClass(lastRowClass == 'r1' ? 'r2' : 'r1');
95 | lastRowClass = item.node.hasClass('r1') ? 'r1' : 'r2';
96 | item.link.html(item.name.replace(matchRegexp, "$& "));
97 | }
98 |
99 | if (searchCache.length === searchIndex + 1) {
100 | searchDone();
101 | return;
102 | }
103 | else {
104 | searchIndex++;
105 | }
106 | }
107 | inSearch = setTimeout('searchItem()', defaultSearchItemTimeOut);
108 | }
109 |
110 | function searchDone() {
111 | highlight(true);
112 | if ($('#full_list li.found').size() === 0) {
113 | $('#no_results').text('No results were found.').hide().fadeIn();
114 | }
115 | else {
116 | $('#no_results').text('');
117 | }
118 |
119 | $('#search').removeClass('loading');
120 | clearTimeout(inSearch);
121 | inSearch = null;
122 | }
123 |
124 | clicked = null;
125 | function linkList() {
126 | $('#full_list li, #full_list li a:last').click(function(evt) {
127 | if ($(this).hasClass('toggle')) {
128 | return true;
129 | }
130 |
131 | if (this.tagName.toLowerCase() == "li") {
132 | var toggle = $(this).children('a.toggle');
133 | if (toggle.size() > 0 && evt.pageX < toggle.offset().left) {
134 | toggle.click();
135 | return false;
136 | }
137 | }
138 |
139 | if (clicked) {
140 | clicked.removeClass('clicked');
141 | }
142 |
143 | var win = window.top.frames.main ? window.top.frames.main : window.parent;
144 | if (this.tagName.toLowerCase() == "a") {
145 | clicked = $(this).parent('li').addClass('clicked');
146 | win.location = this.href;
147 | }
148 | else {
149 | clicked = $(this).addClass('clicked');
150 | win.location = $(this).find('a:last').attr('href');
151 | }
152 |
153 | return false;
154 | });
155 | }
156 |
157 | function collapse() {
158 | $('#full_list a.toggle').click(function() {
159 | $(this).parent().toggleClass('collapsed').next().toggleClass('collapsed');
160 | highlight();
161 | return false;
162 | });
163 |
164 | $('#full_list > li.node').each(function() {
165 | $(this).addClass('collapsed').next('li.docs').addClass('collapsed');
166 | });
167 |
168 | highlight();
169 | }
170 |
171 | function highlight(no_padding) {
172 | var n = 1;
173 | $('#full_list a.object_link:visible').each(function() {
174 | var next = n == 1 ? 2 : 1;
175 | var li = $(this).parent();
176 | li.removeClass("r" + next).addClass("r" + n);
177 | no_padding ? li.addClass("no_padding") : li.removeClass("no_padding");
178 | n = next;
179 | });
180 | }
181 |
182 | function escapeShortcut() {
183 | $(document).keydown(function(evt) {
184 | if (evt.which == 27) {
185 | $('#search_frame', window.top.document).slideUp(100);
186 | $('#search a', window.top.document).removeClass('active inactive');
187 | $(window.top).focus();
188 | }
189 | });
190 | }
191 |
192 | $(escapeShortcut);
193 | $(fullListSearch);
194 | $(linkList);
195 | $(collapse);
--------------------------------------------------------------------------------
/doc/modules_list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | List of Modules
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
305 |
306 |
307 |
--------------------------------------------------------------------------------
/doc/overview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Overview
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 | fleet_api v0.0.15
26 |
27 |
28 |
29 | Modules
30 |
31 |
32 |
33 |
34 |
35 |
36 | Modules summary ↑
37 |
38 |
39 | FleetApi
40 |
41 | This module contains callback declarations for interacting with a Fleet API endpoint
42 |
43 |
44 |
45 |
46 | FleetApi.Direct
47 |
48 | Accesses the Fleet API via a directly-identified node URL
49 |
50 |
51 |
52 |
53 | FleetApi.Error
54 |
55 | Defines a FleetApi.Error
struct, representing erros that may be returned
56 | when making Fleet API calls
57 |
58 |
59 |
60 |
61 | FleetApi.Etcd
62 |
63 | Accesses the Fleet API via a URL discovered through etcd
64 |
65 |
66 |
67 |
68 | FleetApi.Machine
69 |
70 | Defines a FleetApi.Machine
struct, representing a host in the Fleet
71 | cluster. It uses the host’s machine-id
72 | as a unique identifier
73 |
74 |
75 |
76 |
77 | FleetApi.Unit
78 |
79 | Defines a FleetApi.Unit
struct, representing a service in a fleet cluster
80 |
81 |
82 |
83 |
84 | FleetApi.UnitOption
85 |
86 | Defines a FleetApi.UnitOption
struct, representing one segment of the information used to describe a unit
87 |
88 |
89 |
90 |
91 | FleetApi.UnitState
92 |
93 | Defines a FleetApi.UnitState
struct, representing the current state of a particular unit
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/doc/protocols_list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | List of Protocols
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/fixture/custom_cassettes/delete_unit.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units/subgun-http.service"
5 | },
6 | "response": {
7 | "status_code": 204,
8 | "headers": {
9 | },
10 | "body": ""
11 | }
12 | }
13 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_delete_unit.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/units\/subgun-http.service/"
29 | },
30 | "response": {
31 | "status_code": 204,
32 | "headers": {
33 | },
34 | "body": ""
35 | }
36 | }
37 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_get_api_discovery.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": "{\"kind\": \"discovery#restDescription\",\"discoveryVersion\": \"v1\",\"id\": \"fleet:v1\",\"name\": \"schema\",\"version\": \"v1\",\"title\": \"fleet API\",\"description\": \"\",\"documentationLink\": \"http://github.com/coreos/fleet\",\"protocol\": \"rest\",\"icons\": {\"x16\": \"\",\"x32\": \"\"},\"labels\": [],\"baseUrl\": \"$ENDPOINT/fleet/v1/\",\"basePath\": \"/fleet/v1/\",\"rootUrl\": \"$ENDPOINT/\",\"servicePath\": \"fleet/v1/\",\"batchPath\": \"batch\",\"parameters\": {},\"auth\": {},\"schemas\": {\"Machine\": {\"id\": \"Machine\",\"type\": \"object\",\"properties\": {\"id\": {\"type\": \"string\"},\"primaryIP\": {\"type\": \"string\"},\"metadata\": {\"type\": \"object\",\"properties\": {},\"additionalProperties\": {\"type\": \"string\"}}}},\"MachinePage\": {\"id\": \"MachinePage\",\"type\": \"object\",\"properties\": {\"machines\": {\"type\": \"array\",\"items\": {\"$ref\": \"Machine\"}},\"nextPageToken\": {\"type\": \"string\"}}},\"UnitOption\": {\"id\": \"UnitOption\",\"type\": \"object\",\"properties\": {\"section\": {\"type\": \"string\"},\"name\": {\"type\": \"string\"},\"value\": {\"type\": \"string\"}}},\"Unit\": {\"id\": \"Unit\",\"type\": \"object\",\"properties\": {\"name\": {\"type\": \"string\"},\"options\": {\"type\": \"array\",\"items\": {\"$ref\": \"UnitOption\"}},\"desiredState\": {\"type\": \"string\",\"enum\": [\"inactive\",\"loaded\",\"launched\"]},\"currentState\": {\"type\": \"string\",\"enum\": [\"inactive\",\"loaded\",\"launched\"]},\"machineID\": {\"type\": \"string\",\"required\": true}}},\"UnitPage\": {\"id\": \"UnitPage\",\"type\": \"object\",\"properties\": {\"units\": {\"type\": \"array\",\"items\": {\"$ref\": \"Unit\"}},\"nextPageToken\": {\"type\": \"string\"}}},\"UnitState\": {\"id\": \"UnitState\",\"type\": \"object\",\"properties\": {\"name\": {\"type\": \"string\"},\"hash\": {\"type\": \"string\"},\"machineID\": {\"type\": \"string\"},\"systemdLoadState\": {\"type\": \"string\"},\"systemdActiveState\": {\"type\": \"string\"},\"systemdSubState\": {\"type\": \"string\"}}},\"UnitStatePage\": {\"id\": \"UnitStatePage\",\"type\": \"object\",\"properties\": {\"states\": {\"type\": \"array\",\"items\": {\"$ref\": \"UnitState\"}},\"nextPageToken\": {\"type\": \"string\"}}}},\"resources\": {\"Machines\": {\"methods\": {\"List\": {\"id\": \"fleet.Machine.List\",\"description\": \"Retrieve a page of Machine objects.\",\"httpMethod\": \"GET\",\"path\": \"machines\",\"parameters\": {\"nextPageToken\": {\"type\": \"string\",\"location\": \"query\"}},\"response\": {\"$ref\": \"MachinePage\"}}}},\"Units\": {\"methods\": {\"List\": {\"id\": \"fleet.Unit.List\",\"description\": \"Retrieve a page of Unit objects.\",\"httpMethod\": \"GET\",\"path\": \"units\",\"parameters\": {\"nextPageToken\": {\"type\": \"string\",\"location\": \"query\"}},\"response\": {\"$ref\": \"UnitPage\"}},\"Get\": {\"id\": \"fleet.Unit.Get\",\"description\": \"Retrieve a single Unit object.\",\"httpMethod\": \"GET\",\"path\": \"units/{unitName}\",\"parameters\": {\"unitName\": {\"type\": \"string\",\"location\": \"path\",\"required\": true}},\"parameterOrder\": [\"unitName\"],\"response\": {\"$ref\": \"Unit\"}},\"Delete\": {\"id\": \"fleet.Unit.Delete\",\"description\": \"Delete the referenced Unit object.\",\"httpMethod\": \"DELETE\",\"path\": \"units/{unitName}\",\"parameters\": {\"unitName\": {\"type\": \"string\",\"location\": \"path\",\"required\": true}},\"parameterOrder\": [\"unitName\"]},\"Set\": {\"id\": \"fleet.Unit.Set\",\"description\": \"Create or update a Unit.\",\"httpMethod\": \"PUT\",\"path\": \"units/{unitName}\",\"parameters\": {\"unitName\": {\"type\": \"string\",\"location\": \"path\",\"required\": true}},\"parameterOrder\": [\"unitName\"],\"request\": {\"$ref\": \"Unit\"}}}},\"UnitState\": {\"methods\": {\"List\": {\"id\": \"fleet.UnitState.List\",\"description\": \"Retrieve a page of UnitState objects.\",\"httpMethod\": \"GET\",\"path\": \"state\",\"parameters\": {\"nextPageToken\": {\"type\": \"string\",\"location\": \"query\"},\"unitName\": {\"type\": \"string\",\"location\": \"query\"},\"machineID\": {\"type\": \"string\",\"location\": \"query\"}},\"response\": {\"$ref\": \"UnitStatePage\"}}}}}}"
24 | }
25 | }
26 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_get_unit.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/units\/subgun-http.service/"
29 | },
30 | "response": {
31 | "status_code": 200,
32 | "headers": {
33 | "Content-Type": "application/json"
34 | },
35 | "body": "{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]}"
36 | }
37 | }
38 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_list_machines.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/machines"
29 | },
30 | "response": {
31 | "status_code": 200,
32 | "headers": {
33 | "Content-Type": "application/json"
34 | },
35 | "body": "{\"machines\":[{\"id\":\"76ffb3a4588c46f3941c073df77be5e9\",\"primaryIP\":\"127.0.0.1\"},{\"id\":\"820c30c0867844129d63f4409871ba39\",\"primaryIP\":\"127.0.0.2\"},{\"id\":\"f439a6a2dd8f43dbad60994cc1fb68f6\",\"primaryIP\":\"127.0.0.3\"}]}"
36 | }
37 | }
38 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_list_unit_states.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/state/"
29 | },
30 | "response": {
31 | "status_code": 200,
32 | "headers": {
33 | "Content-Type": "application/json"
34 | },
35 | "body": "{\"states\":[{\"hash\":\"eef29cad431ad16c8e164400b2f3c85afd73b238\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"systemdActiveState\":\"active\",\"systemdLoadState\":\"loaded\",\"systemdSubState\":\"running\"}]}"
36 | }
37 | }
38 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_list_units.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/units"
29 | },
30 | "response": {
31 | "status_code": 200,
32 | "headers": {
33 | "Content-Type": "application/json"
34 | },
35 | "body": "{\"units\":[{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-http@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]}]}"
36 | }
37 | }
38 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_list_units_empty.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/units/"
29 | },
30 | "response": {
31 | "status_code": 200,
32 | "headers": {
33 | "Content-Type": "application/json"
34 | },
35 | "body": "{\"units\":[]}"
36 | }
37 | }
38 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_list_units_multiple_calls.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.3:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.3:7002\/fleet\/v1\/units"
29 | },
30 | "response": {
31 | "status_code": 200,
32 | "headers": {
33 | "Content-Type": "application/json"
34 | },
35 | "body": "{\"units\":[{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-http@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]}]}"
36 | }
37 | },
38 | {
39 | "request": {
40 | "url": "~r/http:\/\/127.0.0.3:7002\/fleet\/v1\/units"
41 | },
42 | "response": {
43 | "status_code": 200,
44 | "headers": {
45 | "Content-Type": "application/json"
46 | },
47 | "body": "{\"units\":[{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-http@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]}]}"
48 | }
49 | },
50 | {
51 | "request": {
52 | "url": "~r/http:\/\/127.0.0.3:7002\/fleet\/v1\/units"
53 | },
54 | "response": {
55 | "status_code": 200,
56 | "headers": {
57 | "Content-Type": "application/json"
58 | },
59 | "body": "{\"units\":[{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-http@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]}]}"
60 | }
61 | }
62 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_list_units_null.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/units/"
29 | },
30 | "response": {
31 | "status_code": 200,
32 | "headers": {
33 | "Content-Type": "application/json"
34 | },
35 | "body": "{\"units\":null}"
36 | }
37 | }
38 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_list_units_weird_response.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/units/"
29 | },
30 | "response": {
31 | "status_code": 200,
32 | "headers": {
33 | "Content-Type": "application/json"
34 | },
35 | "body": "{}"
36 | }
37 | }
38 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_response_503_response.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 503,
8 | "headers": {
9 | "Content-Length": "0"
10 | },
11 | "body": ""
12 | }
13 | },
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_response_no_nodes.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_set_unit_new.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/units\/test.service/",
29 | "headers": {
30 | "Content-Type": "application/json"
31 | },
32 | "body": "{\"currentState\":null,\"desiredState\":\"launched\",\"machineID\":null,\"name\":\"test.service\",\"options\":[{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/sleep 3000\"}]}"
33 | },
34 | "response": {
35 | "status_code": 201,
36 | "headers": {},
37 | "body": ""
38 | }
39 | }
40 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/etcd_set_unit_update.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "https://discovery.etcd.io/abcd1234"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"action\":\"get\",\"node\":{\"key\":\"/_etcd/registry/abcd1234\",\"dir\":true,\"nodes\":[{\"value\":\"http://127.0.0.1:7001\"},{\"value\":\"http://127.0.0.2:7001\"},{\"value\":\"http://127.0.0.3:7001\"}],\"modifiedIndex\":381975809,\"createdIndex\":381975809}}"
12 | }
13 | },
14 | {
15 | "request": {
16 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/discovery/"
17 | },
18 | "response": {
19 | "status_code": 200,
20 | "headers": {
21 | "Content-Type": "application/json"
22 | },
23 | "body": ""
24 | }
25 | },
26 | {
27 | "request": {
28 | "url": "~r/http:\/\/127.0.0.[1-3]:7002\/fleet\/v1\/units\/test.service/",
29 | "headers": {
30 | "Content-Type": "application/json"
31 | },
32 | "body": "{\"desiredState\":\"launched\"}"
33 | },
34 | "response": {
35 | "status_code": 204,
36 | "headers": {},
37 | "body": ""
38 | }
39 | }
40 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/get_api_discovery.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/discovery"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"kind\": \"discovery#restDescription\",\"discoveryVersion\": \"v1\",\"id\": \"fleet:v1\",\"name\": \"schema\",\"version\": \"v1\",\"title\": \"fleet API\",\"description\": \"\",\"documentationLink\": \"http://github.com/coreos/fleet\",\"protocol\": \"rest\",\"icons\": {\"x16\": \"\",\"x32\": \"\"},\"labels\": [],\"baseUrl\": \"$ENDPOINT/fleet/v1/\",\"basePath\": \"/fleet/v1/\",\"rootUrl\": \"$ENDPOINT/\",\"servicePath\": \"fleet/v1/\",\"batchPath\": \"batch\",\"parameters\": {},\"auth\": {},\"schemas\": {\"Machine\": {\"id\": \"Machine\",\"type\": \"object\",\"properties\": {\"id\": {\"type\": \"string\"},\"primaryIP\": {\"type\": \"string\"},\"metadata\": {\"type\": \"object\",\"properties\": {},\"additionalProperties\": {\"type\": \"string\"}}}},\"MachinePage\": {\"id\": \"MachinePage\",\"type\": \"object\",\"properties\": {\"machines\": {\"type\": \"array\",\"items\": {\"$ref\": \"Machine\"}},\"nextPageToken\": {\"type\": \"string\"}}},\"UnitOption\": {\"id\": \"UnitOption\",\"type\": \"object\",\"properties\": {\"section\": {\"type\": \"string\"},\"name\": {\"type\": \"string\"},\"value\": {\"type\": \"string\"}}},\"Unit\": {\"id\": \"Unit\",\"type\": \"object\",\"properties\": {\"name\": {\"type\": \"string\"},\"options\": {\"type\": \"array\",\"items\": {\"$ref\": \"UnitOption\"}},\"desiredState\": {\"type\": \"string\",\"enum\": [\"inactive\",\"loaded\",\"launched\"]},\"currentState\": {\"type\": \"string\",\"enum\": [\"inactive\",\"loaded\",\"launched\"]},\"machineID\": {\"type\": \"string\",\"required\": true}}},\"UnitPage\": {\"id\": \"UnitPage\",\"type\": \"object\",\"properties\": {\"units\": {\"type\": \"array\",\"items\": {\"$ref\": \"Unit\"}},\"nextPageToken\": {\"type\": \"string\"}}},\"UnitState\": {\"id\": \"UnitState\",\"type\": \"object\",\"properties\": {\"name\": {\"type\": \"string\"},\"hash\": {\"type\": \"string\"},\"machineID\": {\"type\": \"string\"},\"systemdLoadState\": {\"type\": \"string\"},\"systemdActiveState\": {\"type\": \"string\"},\"systemdSubState\": {\"type\": \"string\"}}},\"UnitStatePage\": {\"id\": \"UnitStatePage\",\"type\": \"object\",\"properties\": {\"states\": {\"type\": \"array\",\"items\": {\"$ref\": \"UnitState\"}},\"nextPageToken\": {\"type\": \"string\"}}}},\"resources\": {\"Machines\": {\"methods\": {\"List\": {\"id\": \"fleet.Machine.List\",\"description\": \"Retrieve a page of Machine objects.\",\"httpMethod\": \"GET\",\"path\": \"machines\",\"parameters\": {\"nextPageToken\": {\"type\": \"string\",\"location\": \"query\"}},\"response\": {\"$ref\": \"MachinePage\"}}}},\"Units\": {\"methods\": {\"List\": {\"id\": \"fleet.Unit.List\",\"description\": \"Retrieve a page of Unit objects.\",\"httpMethod\": \"GET\",\"path\": \"units\",\"parameters\": {\"nextPageToken\": {\"type\": \"string\",\"location\": \"query\"}},\"response\": {\"$ref\": \"UnitPage\"}},\"Get\": {\"id\": \"fleet.Unit.Get\",\"description\": \"Retrieve a single Unit object.\",\"httpMethod\": \"GET\",\"path\": \"units/{unitName}\",\"parameters\": {\"unitName\": {\"type\": \"string\",\"location\": \"path\",\"required\": true}},\"parameterOrder\": [\"unitName\"],\"response\": {\"$ref\": \"Unit\"}},\"Delete\": {\"id\": \"fleet.Unit.Delete\",\"description\": \"Delete the referenced Unit object.\",\"httpMethod\": \"DELETE\",\"path\": \"units/{unitName}\",\"parameters\": {\"unitName\": {\"type\": \"string\",\"location\": \"path\",\"required\": true}},\"parameterOrder\": [\"unitName\"]},\"Set\": {\"id\": \"fleet.Unit.Set\",\"description\": \"Create or update a Unit.\",\"httpMethod\": \"PUT\",\"path\": \"units/{unitName}\",\"parameters\": {\"unitName\": {\"type\": \"string\",\"location\": \"path\",\"required\": true}},\"parameterOrder\": [\"unitName\"],\"request\": {\"$ref\": \"Unit\"}}}},\"UnitState\": {\"methods\": {\"List\": {\"id\": \"fleet.UnitState.List\",\"description\": \"Retrieve a page of UnitState objects.\",\"httpMethod\": \"GET\",\"path\": \"state\",\"parameters\": {\"nextPageToken\": {\"type\": \"string\",\"location\": \"query\"},\"unitName\": {\"type\": \"string\",\"location\": \"query\"},\"machineID\": {\"type\": \"string\",\"location\": \"query\"}},\"response\": {\"$ref\": \"UnitStatePage\"}}}}}}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/get_unit.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units/subgun-http.service"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/get_unit_empty_options.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units/subgun-http.service"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"options\":[]}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/get_unit_missing_options.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units/subgun-http.service"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\"}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/get_unit_null_options.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units/subgun-http.service"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"options\":null}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_machines.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/machines"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"machines\":[{\"id\":\"76ffb3a4588c46f3941c073df77be5e9\",\"primaryIP\":\"127.0.0.1\"},{\"id\":\"820c30c0867844129d63f4409871ba39\",\"primaryIP\":\"127.0.0.2\"},{\"id\":\"f439a6a2dd8f43dbad60994cc1fb68f6\",\"primaryIP\":\"127.0.0.3\"}]}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_machines_empty.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/machines"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"machines\":[]}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_machines_null.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/machines"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"machines\":null}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_machines_weird_response.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/machines"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_unit_states.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/state"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"states\":[{\"hash\":\"eef29cad431ad16c8e164400b2f3c85afd73b238\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"systemdActiveState\":\"active\",\"systemdLoadState\":\"loaded\",\"systemdSubState\":\"running\"}]}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_unit_states_empty.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/state"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"states\":[]}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_unit_states_null.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/state"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"states\":null}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_unit_states_weird_response.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/state"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_units.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"units\":[{\"currentState\":\"launched\",\"desiredState\":\"launched\",\"machineID\":\"820c30c0867844129d63f4409871ba39\",\"name\":\"subgun-http.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-http@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-%i\"},{\"name\":\"Conflicts\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@*.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]},{\"currentState\":\"inactive\",\"desiredState\":\"launched\",\"machineID\":\"76ffb3a4588c46f3941c073df77be5e9\",\"name\":\"subgun-presence@.service\",\"options\":[{\"name\":\"Description\",\"section\":\"Unit\",\"value\":\"subgun presence service\"},{\"name\":\"BindsTo\",\"section\":\"Unit\",\"value\":\"subgun-http@%i.service\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker kill subgun-presence-%i\"},{\"name\":\"ExecStartPre\",\"section\":\"Service\",\"value\":\"-/usr/bin/docker rm subgun-presence-%i\"},{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/docker run --rm --name subgun-presence-%i -e AWS_ACCESS_KEY=AKIAIBC5MW3ONCW6J2XQ -e AWS_SECRET_KEY=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 -e AWS_REGION=us-east-1 -e ELB_NAME=bcwaldon-fleet-lb quay.io/coreos/elb-presence\"},{\"name\":\"ExecStop\",\"section\":\"Service\",\"value\":\"/usr/bin/docker stop subgun-presence-%i\"},{\"name\":\"MachineOf\",\"section\":\"X-Fleet\",\"value\":\"subgun-http@%i.service\"}]}]}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_units_empty.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"units\":[]}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_units_null.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{\"units\":null}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/list_units_weird_response.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units"
5 | },
6 | "response": {
7 | "status_code": 200,
8 | "headers": {
9 | "Content-Type": "application/json"
10 | },
11 | "body": "{}"
12 | }
13 | }
14 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/set_unit_new.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units/test.service",
5 | "headers": {
6 | "Content-Type": "application/json"
7 | },
8 | "body": "{\"currentState\":null,\"desiredState\":\"launched\",\"machineID\":null,\"name\":\"test.service\",\"options\":[{\"name\":\"ExecStart\",\"section\":\"Service\",\"value\":\"/usr/bin/sleep 3000\"}]}"
9 | },
10 | "response": {
11 | "status_code": 201,
12 | "headers": {},
13 | "body": ""
14 | }
15 | }
16 | ]
--------------------------------------------------------------------------------
/fixture/custom_cassettes/set_unit_update.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "request": {
4 | "url": "http://localhost:7002/fleet/v1/units/test.service",
5 | "headers": {
6 | "Content-Type": "application/json"
7 | },
8 | "body": "{\"desiredState\":\"launched\"}"
9 | },
10 | "response": {
11 | "status_code": 204,
12 | "headers": {},
13 | "body": ""
14 | }
15 | }
16 | ]
--------------------------------------------------------------------------------
/lib/fleet_api.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi do
2 | @moduledoc """
3 | This module contains callback declarations for interacting with a Fleet API endpoint.
4 | """
5 | use Behaviour
6 |
7 | @doc """
8 | Retrieve the list of units that the Fleet cluster currently knows about.
9 | """
10 | defcallback list_units(pid) :: {:ok, [FleetApi.Unit.t]} | {:error, any}
11 |
12 | @doc """
13 | Retrieve the details for a specific unit in the Fleet cluster.
14 | """
15 | defcallback get_unit(pid, unit_name :: String.t) :: {:ok, FleetApi.Unit.t} | {:error, any}
16 |
17 | @doc """
18 | Remove a unit from the Fleet cluster.
19 | """
20 | defcallback delete_unit(pid, unit_name :: String.t) :: :ok | {:error, any}
21 |
22 | @doc """
23 | Adds or updates a unit in the Fleet cluster. If the cluster doesn't contain a
24 | unit with the given name, then a new unit is added to it. If a unit with the
25 | given name exists, it is updated with the new unit definition.
26 | """
27 | defcallback set_unit(pid, unit_name :: String.t, FleetApi.Unit.t) :: :ok | {:error, any}
28 |
29 | @doc """
30 | Get the detailed state information for all the units in the Fleet cluster.
31 |
32 | You may optionally provide options `machineID` and/or `unitName` to filter
33 | the response to a particular host or unit.
34 | """
35 | defcallback list_unit_states(pid, opts :: [{atom, String.t}]) :: {:ok, [FleetApi.UnitState.t]} | {:error, any}
36 |
37 | @doc """
38 | Retrieve the list of nodes currently in the Fleet cluster.
39 | """
40 | defcallback list_machines(pid) :: {:ok, [FleetApi.Machine.t]} | {:error, any}
41 |
42 | @doc """
43 | Retrieve the API Discovery document JSON for the Fleet API.
44 | """
45 | defcallback get_api_discovery(pid) :: {:ok, Map.t} | {:error, any}
46 |
47 | defmacro __using__(_) do
48 | quote do
49 | use FleetApi.Api
50 | @behaviour FleetApi
51 |
52 | # To handle errors that may occur inside get_node_url, we'll wrap any
53 | # calls to API functions with call_with_url, which will either return
54 | # with the error info, or pass the resolved URL on down to the API func.
55 | defp call_with_url({:error, reason}, _fn), do: {:error, reason}
56 |
57 | defp call_with_url(node_url, fun) do
58 | fun.(node_url)
59 | end
60 |
61 | def list_units(pid) do
62 | pid
63 | |> get_node_url
64 | |> call_with_url(&api_list_units/1)
65 | end
66 |
67 | def get_unit(pid, unit_name) do
68 | pid
69 | |> get_node_url
70 | |> call_with_url(&(api_get_unit(&1, unit_name)))
71 | end
72 |
73 | def delete_unit(pid, unit_name) do
74 | pid
75 | |> get_node_url
76 | |> call_with_url(&(api_delete_unit(&1, unit_name)))
77 | end
78 |
79 | def set_unit(pid, unit_name, unit) do
80 | pid
81 | |> get_node_url
82 | |> call_with_url(&(api_set_unit(&1, unit_name, unit)))
83 | end
84 |
85 | def list_unit_states(pid, opts \\ []) do
86 | pid
87 | |> get_node_url
88 | |> call_with_url(&(api_list_unit_states(&1, opts)))
89 | end
90 |
91 | def list_machines(pid) do
92 | pid
93 | |> get_node_url
94 | |> call_with_url(&api_list_machines/1)
95 | end
96 |
97 | def get_api_discovery(pid) do
98 | pid
99 | |> get_node_url
100 | |> call_with_url(&api_discovery/1)
101 | end
102 |
103 | @doc """
104 | Retrieves the Fleet API node URL, based on either etcd discovery or direct setting of the node url.
105 | """
106 | defcallback get_node_url(pid) :: String.t
107 | end
108 | end
109 | end
110 |
--------------------------------------------------------------------------------
/lib/fleet_api/api.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Api do
2 | @moduledoc false
3 | defmacro __using__(_) do
4 | quote do
5 | use FleetApi.Request
6 | alias FleetApi.Unit
7 | alias FleetApi.UnitOption
8 | alias FleetApi.UnitState
9 | alias FleetApi.Machine
10 | alias FleetApi.Error
11 |
12 | defp add_query_param(url, name, value) do
13 | separator = if String.contains?(url, "?"), do: "&", else: "?"
14 |
15 | url <> separator <> name <> "=" <> value
16 | end
17 |
18 | defp paginated_request(method, url, headers, body, expected_status \\ [200], resp_bodies \\ [], next_page_token \\ "") do
19 | request_url = if next_page_token == "" do
20 | url
21 | else
22 | add_query_param(url, "nextPageToken", next_page_token)
23 | end
24 |
25 | case request(method, request_url, headers, body, expected_status) do
26 | {:ok, %{"nextPageToken" => token} = resp_body} ->
27 | paginated_request(method, url, headers, body, expected_status, [resp_body | resp_bodies], token)
28 | {:ok, resp_body} ->
29 | result = [resp_body | resp_bodies]
30 | |> Enum.reverse
31 |
32 | {:ok, result}
33 | error -> error
34 | end
35 | end
36 |
37 |
38 | @spec api_list_units(String.t) :: {:ok, [FleetApi.Unit.t]} | {:error, any}
39 | defp api_list_units(node_url) do
40 | case paginated_request(:get, node_url <> "/fleet/v1/units", [], "") do
41 | {:ok, resp_bodies} ->
42 | units = resp_bodies
43 | |> Enum.flat_map(fn resp -> resp["units"] || [] end)
44 | |> Enum.filter(fn unit -> unit != nil end)
45 | |> Enum.map(&Unit.from_map/1)
46 | {:ok, units}
47 | other -> other
48 | end
49 | end
50 |
51 |
52 | @spec api_get_unit(String.t, String.t) :: {:ok, FleetApi.Unit.t} | {:error, any}
53 | defp api_get_unit(node_url, unit_name) do
54 | case request(:get, node_url <> "/fleet/v1/units/" <> unit_name, [], "") do
55 | {:ok, resp_body} ->
56 | unit = resp_body
57 | |> Unit.from_map
58 | {:ok, unit}
59 | other -> other
60 | end
61 | end
62 |
63 |
64 | @spec api_delete_unit(String.t, String.t) :: :ok | {:error, any}
65 | defp api_delete_unit(node_url, unit_name) do
66 | case request(:delete, node_url <> "/fleet/v1/units/" <> unit_name, [], "", [204]) do
67 | {:ok, _} -> :ok
68 | other -> other
69 | end
70 | end
71 |
72 |
73 | @spec api_set_unit(String.t, String.t, FleetApi.Unit.t) :: :ok | {:error, any}
74 | defp api_set_unit(node_url, unit_name, unit) do
75 | case request(:put, node_url <> "/fleet/v1/units/" <> unit_name, [{"Content-Type", "application/json"}], Poison.encode!(unit), [201, 204]) do
76 | {:ok, _} -> :ok
77 | other -> other
78 | end
79 | end
80 |
81 |
82 | @spec api_list_unit_states(String.t, [{atom, String.t}]) :: {:ok, [FleetApi.UnitState.t]} | {:error, any}
83 | defp api_list_unit_states(node_url, opts \\ []) do
84 | url = node_url <> "/fleet/v1/state"
85 | machine_id = Keyword.get(opts, :machine_id)
86 | unit_name = Keyword.get(opts, :unit_name)
87 |
88 | url = cond do
89 | machine_id && unit_name -> url <> "?machineID=" <> machine_id <> "&unitName=" <> unit_name
90 | machine_id -> url <> "?machineID=" <> machine_id
91 | unit_name -> url <> "?unitName=" <> unit_name
92 | true -> url
93 | end
94 |
95 | case paginated_request(:get, url, [], "") do
96 | {:ok, resp_bodies} ->
97 | states = resp_bodies
98 | |> Enum.flat_map(fn resp -> resp["states"] || [] end)
99 | |> Enum.map(&UnitState.from_map/1)
100 | {:ok, states}
101 | other -> other
102 | end
103 | end
104 |
105 |
106 | @spec api_list_machines(String.t) :: {:ok, [FleetApi.Machine.t]} | {:error, any}
107 | defp api_list_machines(node_url) do
108 | case paginated_request(:get, node_url <> "/fleet/v1/machines", [], "") do
109 | {:ok, resp_bodies} ->
110 | machines = resp_bodies
111 | |> Enum.flat_map(fn resp -> resp["machines"] || [] end)
112 | |> Enum.map(&Machine.from_map/1)
113 |
114 | {:ok, machines}
115 | other -> other
116 | end
117 | end
118 |
119 | @spec api_discovery(String.t) :: {:ok, Map.t} | {:error, any}
120 | defp api_discovery(node_url) do
121 | case request(:get, node_url <> "/fleet/v1/discovery") do
122 | {:ok, discovery} -> {:ok, discovery}
123 | other -> other
124 | end
125 | end
126 | end
127 | end
128 | end
--------------------------------------------------------------------------------
/lib/fleet_api/direct.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Direct do
2 | @moduledoc """
3 | Accesses the Fleet API via a directly-identified node URL.
4 | """
5 | use FleetApi
6 | use GenServer
7 |
8 | ## GenServer initialization
9 |
10 | def start_link(node_url) do
11 | GenServer.start_link(__MODULE__, node_url)
12 | end
13 |
14 | def init(node_url) do
15 | {:ok, node_url}
16 | end
17 |
18 | @doc """
19 | Retrieves the Fleet node URL based on the URL provided when the GenServer
20 | was started.
21 | """
22 | @spec get_node_url(pid) :: String.t
23 | def get_node_url(pid) do
24 | GenServer.call(pid, :get_node_url)
25 | end
26 |
27 | def handle_call(:get_node_url, _from, node_url) do
28 | {:reply, node_url, node_url}
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/lib/fleet_api/error.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Error do
2 | @moduledoc """
3 | Defines a `FleetApi.Error` struct, representing erros that may be returned
4 | when making Fleet API calls.
5 |
6 | The following fields are public:
7 |
8 | * `code` - The HTTP status code of the response.
9 | * `message` - A human-readable error message explaining the failure.
10 | """
11 | @type t :: %__MODULE__{}
12 | defstruct code: nil, message: nil
13 |
14 | @spec from_map(%{String.t => any}) :: FleetApi.Error.t
15 | def from_map(error_map) do
16 | %__MODULE__{
17 | code: error_map["error"]["code"],
18 | message: error_map["error"]["message"]
19 | }
20 | end
21 | end
--------------------------------------------------------------------------------
/lib/fleet_api/etcd.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Etcd do
2 | @moduledoc """
3 | Accesses the Fleet API via a URL discovered through etcd.
4 | """
5 | require Logger
6 | use FleetApi
7 | use GenServer
8 |
9 | @port_regex ~r/(:\d+)/
10 |
11 | ## GenServer initialization
12 | def start_link(etcd_token) do
13 | GenServer.start_link(__MODULE__, etcd_token)
14 | end
15 |
16 | def init(etcd_token) do
17 | {:ok, %{etcd_token: etcd_token, last_updated: nil, nodes: []}}
18 | end
19 |
20 | @doc """
21 | Retrieves a Fleet node URL based on the information stored in etcd, using the
22 | etcd token specified when the GenServer was started.
23 | """
24 | @spec get_node_url(pid) :: String.t | {:error, any}
25 | def get_node_url(pid) do
26 | case GenServer.call(pid, :get_node_url, 60_000) do
27 | {:ok, node_url} ->
28 | node_url
29 | |> fix_etcd_node_url
30 |
31 | error -> error
32 | end
33 | end
34 |
35 | defp fix_etcd_node_url(node_url) do
36 | config = Application.get_env(:fleet_api, :etcd)
37 | if config[:fix_port_number] do
38 | Regex.replace(@port_regex, node_url, ":#{config[:api_port]}", global: false)
39 | else
40 | node_url
41 | end
42 | end
43 |
44 | def handle_call(:get_node_url, _from, state) do
45 | case get_state(state) do
46 | {:ok, state} ->
47 | case get_valid_node(state.nodes) do
48 | {nil, nodes} ->
49 | Logger.error "[FleetApi] Node list contained no valid nodes!"
50 | {:reply, {:error, :no_valid_nodes}, Map.put(state, :nodes, nodes)}
51 | {node_url, nodes} ->
52 | Logger.debug "[FleetApi] Confirmed node #{inspect node_url} was valid."
53 | {:reply, {:ok, node_url}, Map.put(state, :nodes, nodes)}
54 | end
55 | {:error, reason} ->
56 | {:reply, {:error, reason}, state}
57 | end
58 | end
59 |
60 | # validates the provided state is relevant, and if not, attempts to retrieve
61 | # new state data from etcd.io up to 5 times before failing.
62 | @spec get_state(Map.t, integer) :: {:ok, Map.t} | {:error, any}
63 | defp get_state(state, attempts \\ 0) do
64 | if valid_state?(state) do
65 | {:ok, state}
66 | else
67 | Logger.debug "[FleetApi] Refreshing list of etcd nodes, attempt: #{attempts}."
68 | case refresh_nodes(state.etcd_token) do
69 | {:ok, nodes} ->
70 | node_maps = for node_url <- nodes, do: %{ url: node_url, is_valid: nil }
71 | Logger.debug "[FleetApi] Successfully retrieved list of #{length nodes} etcd nodes."
72 | {:ok, %{state | nodes: node_maps, last_updated: :os.timestamp}}
73 | {:error, reason} ->
74 | if attempts < 5 do
75 | get_state(state, attempts + 1)
76 | else
77 | Logger.error "[FleetApi] Couldn't refresh list of etcd nodes after 5 attempts. Failing."
78 | {:error, reason}
79 | end
80 | end
81 | end
82 | end
83 |
84 | @spec refresh_nodes(String.t) :: [String.t]
85 | defp refresh_nodes(etcd_token) do
86 | Logger.debug "[FleetApi] Refreshing nodes for etcd token: #{etcd_token}"
87 | try do
88 | case request(:get, "https://discovery.etcd.io/#{etcd_token}", [{"Accept", "application/json"}]) do
89 | {:ok, %{"node" => node}} ->
90 | nodes = for n <- node["nodes"] || [], do: n["value"]
91 | {:ok, nodes}
92 | {:error, error} ->
93 | Logger.error "[FleetApi] An error occurred refreshing the list of etcd nodes: #{inspect error}."
94 | {:error, error.reason}
95 | end
96 | rescue e ->
97 | Logger.error "[FleetApi] An exception was raised during the request to etcd: #{inspect e}"
98 | Logger.debug "[FleetApi] Issuing a request to google just to check httpoison..."
99 | test_httpoison_request()
100 |
101 | {:error, e}
102 | catch e ->
103 | Logger.error "[FleetApi] refresh_node request threw: #{inspect e}."
104 | {:error, e}
105 | end
106 | end
107 |
108 | defp test_httpoison_request() do
109 | try do
110 | case request(:get, "https://google.com", [], "", 200..399, false) do
111 | {:ok, result} ->
112 | Logger.debug "[FleetApi] google.com request succeeded: #{inspect result}"
113 | {:error, error} ->
114 | Logger.warn "[FleetApi] google.com request failed: #{inspect error}"
115 | end
116 | rescue e ->
117 | Logger.warn "[FleetApi] google.com request raised an exception: #{inspect e}"
118 | catch e ->
119 | Logger.error "[FleetApi] google.com request threw: #{inspect e}."
120 | end
121 | end
122 |
123 | # finds the first node for which the discovery endpoint returns data.
124 | @spec get_valid_node([Map.t]) :: {String.t | nil, [Map.t]}
125 | defp get_valid_node(nodes) do
126 | Logger.debug "[FleetApi] Finding a valid node..."
127 | filtered = Enum.filter(nodes, fn node -> node.is_valid != false end)
128 | get_valid_node(nodes, filtered)
129 | end
130 |
131 | @spec get_valid_node([Map.t], [Map.t]) :: {String.t | nil, [Map.t]}
132 | defp get_valid_node(nodes, candidates) when length(candidates) > 0 do
133 | # Seed the RNG
134 | :random.seed(:os.timestamp)
135 | node = candidates
136 | |> Enum.shuffle
137 | |> List.first
138 |
139 | if node.is_valid == true do
140 | {node.url, nodes}
141 | else
142 | is_valid = validate_node(node.url)
143 |
144 | # Update our nodes list now that we know if this node is valid or not
145 | index = Enum.find_index(nodes, fn n -> n.url == node.url end)
146 | node = Map.put(node, :is_valid, is_valid)
147 | nodes = List.replace_at(nodes, index, node)
148 |
149 | if is_valid do
150 | {node.url, nodes}
151 | else
152 | # Since this node isn't valid, recurse back into get_valid_nodes to try
153 | # to find a valid node.
154 | get_valid_node(nodes)
155 | end
156 | end
157 | end
158 |
159 | defp get_valid_node(nodes, candidates) when length(candidates) == 0 do
160 | Logger.warn "[FleetApi] All nodes have been checked, and no valid nodes were found."
161 | {nil, nodes}
162 | end
163 |
164 | defp validate_node(node_url) do
165 | node_url
166 | |> fix_etcd_node_url
167 | |> api_discovery
168 | |> case do
169 | {:ok, _discovery} -> true
170 | _ -> false
171 | end
172 | end
173 |
174 | @spec valid_state?(Map.t) :: boolean
175 | defp valid_state?(state) do
176 | valid_token = state.etcd_token != nil && String.length(String.strip(state.etcd_token)) > 0
177 |
178 | # Check that we've refreshed in the last 10 minutes
179 | valid_time = state.last_updated != nil && :timer.now_diff(:os.timestamp, state.last_updated) < 600_000_000
180 |
181 | valid_nodes = state.nodes != nil && length(state.nodes) > 0
182 |
183 | valid_token && valid_time && valid_nodes
184 | end
185 | end
--------------------------------------------------------------------------------
/lib/fleet_api/machine.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Machine do
2 | @moduledoc """
3 | Defines a `FleetApi.Machine` struct, representing a host in the Fleet
4 | cluster. It uses the host's [machine-id](http://www.freedesktop.org/software/systemd/man/machine-id.html)
5 | as a unique identifier.
6 |
7 | The following fields are public:
8 |
9 | * `id` - unique identifier of Machine entity.
10 | * `primaryIP` - IP address that should be used to communicate with this host.
11 | * `metadata` - dictionary of key-value data published by the machine.
12 | """
13 | @type t :: %__MODULE__{}
14 | defstruct id: nil, primaryIP: nil, metadata: nil
15 |
16 | @spec from_map(%{String.t => any}) :: FleetApi.Machine.t
17 | def from_map(machine_map) do
18 | %__MODULE__{
19 | id: machine_map["id"],
20 | primaryIP: machine_map["primaryIP"],
21 | metadata: machine_map["metadata"]
22 | }
23 | end
24 |
25 | @doc """
26 | Checks if this machine is responding to requests by attempting to access the
27 | API discovery endpoint of the Fleet API.
28 | """
29 | @spec reachable?(FleetApi.Machine.t, integer) :: boolean
30 | def reachable?(machine, port \\ 7002) do
31 | {:ok, pid} = FleetApi.Direct.start_link("http://#{machine.primaryIP}:#{port}")
32 |
33 | case FleetApi.Direct.get_api_discovery(pid) do
34 | {:ok, _} -> true
35 | _ -> false
36 | end
37 | end
38 | end
--------------------------------------------------------------------------------
/lib/fleet_api/request.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Request do
2 | @moduledoc false
3 | defmacro __using__(_) do
4 | quote do
5 | require Logger
6 | # Issue a request to the specified url, optionally passing a list of header
7 | # tuples and a body. The method argument specifies the HTTP method in the
8 | # form of an atom, e.g. :get, :post, :delete, etc.
9 | @spec request(atom, String.t, [tuple], String.t, [integer], boolean) :: {:ok, any} | {:error, any}
10 | defp request(method, url, headers \\ [], body \\ "", expected_status \\ [200], parse_response \\ true) do
11 | default_options = [recv_timeout: 30_000]
12 | options = case Application.get_env(:fleet_api, :proxy) do
13 | nil -> default_options
14 | proxy_opts -> [hackney: [proxy: proxy_opts]] ++ default_options
15 | end
16 |
17 | {_, _, request_id} = :os.timestamp()
18 |
19 | Logger.debug "[FleetApi] issuing request #{request_id} to #{url}"
20 |
21 | case HTTPoison.request(method, url, body, headers, options) do
22 | {:ok, %HTTPoison.Response{:status_code => status} = response} when status in 400..599 ->
23 | Logger.error "[FleetApi] request #{request_id} to #{url} returned status code #{inspect status}"
24 | if String.length(response.body) != 0 do
25 | error = response.body
26 | |> Poison.decode!
27 | |> FleetApi.Error.from_map
28 | {:error, %{reason: error}}
29 | else
30 | {:error, %{reason: "Received #{status} response."}}
31 | end
32 | {:ok, %HTTPoison.Response{status_code: status} = response} ->
33 | if status in expected_status do
34 | Logger.debug "[FleetApi] request #{request_id} to #{url} succeeded with status code #{inspect status}"
35 | if String.length(response.body) != 0 && parse_response do
36 | {:ok, Poison.decode!(response.body)}
37 | else
38 | {:ok, response}
39 | end
40 | else
41 | Logger.error "[FleetApi] request #{request_id} to #{url} returned status code #{inspect status}"
42 | {:error, %{reason: "Expected response status in #{inspect expected_status} but got #{status}."}}
43 | end
44 | error ->
45 | Logger.error "[FleetApi] request #{request_id} to #{url} did not complete. Error: #{inspect error}."
46 | error
47 | end
48 | end
49 | end
50 | end
51 | end
--------------------------------------------------------------------------------
/lib/fleet_api/unit.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Unit do
2 | @moduledoc """
3 | Defines a `FleetApi.Unit` struct, representing a service in a fleet cluster.
4 |
5 | The following fields are public:
6 |
7 | * `name` - unique identifier of entity.
8 | * `options` - list of UnitOption entities.
9 | * `desiredState` - state the user wishes the unit to be in ("inactive", "loaded", or "launched").
10 | * `currentState` - state the unit is currently in (same possible values as desiredState).
11 | * `machineID` - ID of machine to which the unit is scheduled.
12 | """
13 | @type t :: %__MODULE__{}
14 | alias FleetApi.UnitOption
15 |
16 | defstruct name: nil, options: [], desiredState: nil, currentState: nil, machineID: nil
17 |
18 | @spec from_map(%{String.t => any}) :: FleetApi.Unit.t
19 | def from_map(unit_map) do
20 | %__MODULE__{
21 | name: unit_map["name"],
22 | options: (unit_map["options"] || []) |> Enum.map(&UnitOption.from_map/1),
23 | desiredState: unit_map["desiredState"],
24 | currentState: unit_map["currentState"],
25 | machineID: unit_map["machineID"]
26 | }
27 | end
28 | end
--------------------------------------------------------------------------------
/lib/fleet_api/unit_option.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.UnitOption do
2 | @moduledoc """
3 | Defines a `FleetApi.UnitOption` struct, representing one segment of the information used to describe a unit.
4 |
5 | The following fields are public:
6 |
7 | * `name` - name of option (e.g. "BindsTo", "After", "ExecStart").
8 | * `section` - name of section that contains the option (e.g. "Unit", "Service", "Socket").
9 | * `value` - value of option (e.g. "/usr/bin/docker run busybox /bin/sleep 1000").
10 | """
11 | @type t :: %__MODULE__{}
12 |
13 | defstruct section: nil, name: nil, value: nil
14 |
15 | @spec from_map(%{String.t => any}) :: FleetApi.UnitOption.t
16 | def from_map(option_map) do
17 | %__MODULE__{
18 | section: option_map["section"],
19 | name: option_map["name"],
20 | value: option_map["value"]
21 | }
22 | end
23 | end
--------------------------------------------------------------------------------
/lib/fleet_api/unit_state.ex:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.UnitState do
2 | @moduledoc """
3 | Defines a `FleetApi.UnitState` struct, representing the current state of a particular unit.
4 |
5 | The following fields are public:
6 |
7 | * `name` - unique identifier of entity.
8 | * `hash` - SHA1 hash of underlying unit file.
9 | * `machineID` - ID of machine from which this state originated.
10 | * `systemdLoadState` - load state as reported by systemd.
11 | * `systemdActiveState` - active state as reported by systemd.
12 | * `systemdSubState` - sub state as reported by systemd.
13 | A unit state represents the current state of a given unit.
14 | """
15 | @type t :: %__MODULE__{}
16 |
17 | defstruct name: nil, hash: nil, machineID: nil, systemdLoadState: nil, systemdActiveState: nil, systemdSubState: nil
18 |
19 | @spec from_map(%{String.t => any}) :: FleetApi.UnitState.t
20 | def from_map(state_map) do
21 | %__MODULE__{
22 | name: state_map["name"],
23 | hash: state_map["hash"],
24 | machineID: state_map["machineID"],
25 | systemdLoadState: state_map["systemdLoadState"],
26 | systemdActiveState: state_map["systemdActiveState"],
27 | systemdSubState: state_map["systemdSubState"]
28 | }
29 |
30 | end
31 | end
--------------------------------------------------------------------------------
/mix.exs:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Mixfile do
2 | use Mix.Project
3 |
4 | def project do
5 | [app: :fleet_api,
6 | version: "0.0.15",
7 | elixir: "~> 1.0",
8 | deps: deps,
9 | description: description,
10 | package: package,
11 | docs: [readme: "README.md",
12 | main: "README",
13 | source_url: "https://github.com/jordan0day/fleet-api"]]
14 | end
15 |
16 | # Configuration for the OTP application
17 | #
18 | # Type `mix help compile.app` for more information
19 | def application do
20 | [ applications: [:logger, :httpoison],
21 | env: [etcd: [fix_port_number: true, api_port: 7002]]]
22 | end
23 |
24 | # Dependencies can be Hex packages:
25 | #
26 | # {:mydep, "~> 0.3.0"}
27 | #
28 | # Or git/path repositories:
29 | #
30 | # {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
31 | #
32 | # Type `mix help deps` for more examples and options
33 | defp deps do
34 | [
35 | {:httpoison, "0.7.1"},
36 | {:poison, "1.3.1"},
37 | {:exvcr, "0.4.0", only: :test},
38 | {:earmark, "~> 0.1", only: :dev},
39 | {:ex_doc, "~> 0.7", only: :dev}]
40 | end
41 |
42 | defp description do
43 | "A simple wrapper for the Fleet API. Can be used with etcd tokens or via direct node URLs."
44 | end
45 |
46 | defp package do
47 | [contributors: ["Jordan Day"],
48 | licenses: ["MIT"],
49 | links: %{"GitHub" => "https://github.com/jordan0day/fleet-api.git"}]
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/mix.lock:
--------------------------------------------------------------------------------
1 | %{"earmark": {:hex, :earmark, "0.1.17"},
2 | "ex_doc": {:hex, :ex_doc, "0.7.3"},
3 | "exactor": {:hex, :exactor, "2.1.2"},
4 | "exjsx": {:hex, :exjsx, "3.1.0"},
5 | "exvcr": {:hex, :exvcr, "0.4.0"},
6 | "hackney": {:hex, :hackney, "1.3.0"},
7 | "httpoison": {:hex, :httpoison, "0.7.1"},
8 | "idna": {:hex, :idna, "1.0.2"},
9 | "jsx": {:hex, :jsx, "2.4.0"},
10 | "meck": {:hex, :meck, "0.8.3"},
11 | "poison": {:hex, :poison, "1.3.1"},
12 | "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5"}}
13 |
--------------------------------------------------------------------------------
/test/direct_test.exs:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Direct.Test do
2 | use ExUnit.Case
3 | use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
4 |
5 | import FleetApi.Direct
6 |
7 | setup_all do
8 | ExVCR.Config.cassette_library_dir("fixture/vcr_cassettes", "fixture/custom_cassettes")
9 | :ok
10 | end
11 |
12 | test "list_units" do
13 | use_cassette "list_units", custom: true do
14 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
15 | {:ok, units} = list_units(pid)
16 |
17 | assert 4 == length(units)
18 |
19 | assert %FleetApi.Unit{
20 | currentState: "launched",
21 | desiredState: "launched",
22 | machineID: "820c30c0867844129d63f4409871ba39",
23 | name: "subgun-http.service",
24 | options: [
25 | %FleetApi.UnitOption{
26 | name: "Description",
27 | section: "Unit",
28 | value: "subgun"},
29 | %FleetApi.UnitOption{
30 | name: "ExecStartPre",
31 | section: "Service",
32 | value: "-/usr/bin/docker kill subgun-%i"},
33 | %FleetApi.UnitOption{
34 | name: "ExecStartPre",
35 | section: "Service",
36 | value: "-/usr/bin/docker rm subgun-%i"},
37 | %FleetApi.UnitOption{
38 | name: "ExecStart",
39 | section: "Service",
40 | value: "/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun"},
41 | %FleetApi.UnitOption{
42 | name: "ExecStop",
43 | section: "Service",
44 | value: "/usr/bin/docker stop subgun-%i"},
45 | %FleetApi.UnitOption{
46 | name: "Conflicts",
47 | section: "X-Fleet",
48 | value: "subgun-http@*.service"}]} in units
49 |
50 | assert %FleetApi.Unit{
51 | currentState: "inactive",
52 | desiredState: "launched",
53 | machineID: "76ffb3a4588c46f3941c073df77be5e9",
54 | name: "subgun-http@.service",
55 | options: [
56 | %FleetApi.UnitOption{
57 | name: "Description",
58 | section: "Unit",
59 | value: "subgun"},
60 | %FleetApi.UnitOption{
61 | name: "ExecStartPre",
62 | section: "Service",
63 | value: "-/usr/bin/docker kill subgun-%i"},
64 | %FleetApi.UnitOption{
65 | name: "ExecStartPre",
66 | section: "Service",
67 | value: "-/usr/bin/docker rm subgun-%i"},
68 | %FleetApi.UnitOption{
69 | name: "ExecStart",
70 | section: "Service",
71 | value: "/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun"},
72 | %FleetApi.UnitOption{
73 | name: "ExecStop",
74 | section: "Service",
75 | value: "/usr/bin/docker stop subgun-%i"},
76 | %FleetApi.UnitOption{
77 | name: "Conflicts",
78 | section: "X-Fleet",
79 | value: "subgun-http@*.service"}]} in units
80 | end
81 | end
82 |
83 | test "list_units empty list" do
84 | use_cassette "list_units_empty", custom: true do
85 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
86 | {:ok, units} = list_units(pid)
87 |
88 | assert 0 == length(units)
89 | end
90 | end
91 |
92 | test "list_units nil list instead of empty list" do
93 | use_cassette "list_units_null", custom: true do
94 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
95 | {:ok, units} = list_units(pid)
96 |
97 | assert 0 == length(units)
98 | end
99 | end
100 |
101 | test "list_units no units field in response" do
102 | use_cassette "list_units_weird_response", custom: true do
103 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
104 | {:ok, units} = list_units(pid)
105 |
106 | assert 0 == length(units)
107 | end
108 | end
109 |
110 | test "get_unit" do
111 | use_cassette "get_unit", custom: true do
112 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
113 | {:ok, unit} = get_unit(pid, "subgun-http.service")
114 |
115 | assert "subgun-http.service" == unit.name
116 | assert "launched" == unit.currentState
117 | assert "launched" == unit.desiredState
118 | assert %FleetApi.UnitOption{name: "Description", section: "Unit", value: "subgun"} in unit.options
119 | end
120 | end
121 |
122 | test "get_unit empty options list" do
123 | use_cassette "get_unit_empty_options", custom: true do
124 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
125 | {:ok, unit} = get_unit(pid, "subgun-http.service")
126 |
127 | assert "subgun-http.service" == unit.name
128 | assert "launched" == unit.currentState
129 | assert "launched" == unit.desiredState
130 | assert length(unit.options) == 0
131 | end
132 | end
133 |
134 | test "get_unit null options list" do
135 | use_cassette "get_unit_null_options", custom: true do
136 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
137 | {:ok, unit} = get_unit(pid, "subgun-http.service")
138 |
139 | assert "subgun-http.service" == unit.name
140 | assert "launched" == unit.currentState
141 | assert "launched" == unit.desiredState
142 | assert length(unit.options) == 0
143 | end
144 | end
145 |
146 | test "get_unit missing options list" do
147 | use_cassette "get_unit_missing_options", custom: true do
148 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
149 | {:ok, unit} = get_unit(pid, "subgun-http.service")
150 |
151 | assert "subgun-http.service" == unit.name
152 | assert "launched" == unit.currentState
153 | assert "launched" == unit.desiredState
154 | assert length(unit.options) == 0
155 | end
156 | end
157 |
158 | test "delete_unit" do
159 | use_cassette "delete_unit", custom: true do
160 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
161 | assert :ok = delete_unit(pid, "subgun-http.service")
162 | end
163 | end
164 |
165 | test "list_machines" do
166 | use_cassette "list_machines", custom: true do
167 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
168 | {:ok, machines} = list_machines(pid)
169 |
170 | assert length(machines) == 3
171 |
172 | assert %FleetApi.Machine{
173 | id: "76ffb3a4588c46f3941c073df77be5e9",
174 | metadata: nil,
175 | primaryIP: "127.0.0.1"} in machines
176 |
177 | assert %FleetApi.Machine{
178 | id: "820c30c0867844129d63f4409871ba39",
179 | metadata: nil,
180 | primaryIP: "127.0.0.2"} in machines
181 |
182 | assert %FleetApi.Machine{
183 | id: "f439a6a2dd8f43dbad60994cc1fb68f6",
184 | metadata: nil,
185 | primaryIP: "127.0.0.3"} in machines
186 | end
187 | end
188 |
189 | test "list_machines empty machine list" do
190 | use_cassette "list_machines_empty", custom: true do
191 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
192 | {:ok, machines} = list_machines(pid)
193 |
194 | assert length(machines) == 0
195 | end
196 | end
197 |
198 | test "list_machines null machine list" do
199 | use_cassette "list_machines_null", custom: true do
200 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
201 | {:ok, machines} = list_machines(pid)
202 |
203 | assert length(machines) == 0
204 | end
205 | end
206 |
207 | test "list_machines no machines field in response" do
208 | use_cassette "list_machines_weird_response", custom: true do
209 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
210 | {:ok, machines} = list_machines(pid)
211 |
212 | assert length(machines) == 0
213 | end
214 | end
215 |
216 | test "list_unit_states" do
217 | use_cassette "list_unit_states", custom: true do
218 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
219 | {:ok, states} = list_unit_states(pid)
220 |
221 | assert length(states) == 1
222 |
223 | assert %FleetApi.UnitState{
224 | hash: "eef29cad431ad16c8e164400b2f3c85afd73b238",
225 | machineID: "820c30c0867844129d63f4409871ba39",
226 | name: "subgun-http.service",
227 | systemdActiveState: "active",
228 | systemdLoadState: "loaded",
229 | systemdSubState: "running"} in states
230 | end
231 | end
232 |
233 | test "list_unit_states empty states list" do
234 | use_cassette "list_unit_states_empty", custom: true do
235 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
236 | {:ok, states} = list_unit_states(pid)
237 |
238 | assert length(states) == 0
239 | end
240 | end
241 |
242 | test "list_unit_states null states list" do
243 | use_cassette "list_unit_states_null", custom: true do
244 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
245 | {:ok, states} = list_unit_states(pid)
246 |
247 | assert length(states) == 0
248 | end
249 | end
250 |
251 | test "list_unit_states missing states list" do
252 | use_cassette "list_unit_states_weird_response", custom: true do
253 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
254 | {:ok, states} = list_unit_states(pid)
255 |
256 | assert length(states) == 0
257 | end
258 | end
259 |
260 | test "create unit" do
261 | use_cassette "set_unit_new", custom: true do
262 | unit = %FleetApi.Unit{
263 | name: "test.service",
264 | desiredState: "launched",
265 | options: [
266 | %FleetApi.UnitOption{
267 | name: "ExecStart",
268 | section: "Service",
269 | value: "/usr/bin/sleep 3000"
270 | }
271 | ]
272 |
273 | }
274 |
275 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
276 | assert :ok = set_unit(pid, "test.service", unit)
277 | end
278 | end
279 |
280 | test "update_unit_desired_state" do
281 | use_cassette "set_unit_update", custom: true do
282 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
283 | assert :ok = set_unit(pid, "test.service", "launched")
284 | end
285 | end
286 |
287 | test "get_api_discovery" do
288 | use_cassette "get_api_discovery", custom: true do
289 | {:ok, pid} = FleetApi.Direct.start_link("http://localhost:7002")
290 | {:ok, discovery} = get_api_discovery(pid)
291 |
292 | assert discovery["discoveryVersion"] == "v1"
293 | assert discovery["id"] == "fleet:v1"
294 | assert discovery["title"] == "fleet API"
295 | end
296 | end
297 | end
--------------------------------------------------------------------------------
/test/etcd_test.exs:
--------------------------------------------------------------------------------
1 | defmodule FleetApi.Etcd.Test do
2 | use ExUnit.Case
3 | use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
4 |
5 | import FleetApi.Etcd
6 |
7 | setup_all do
8 | ExVCR.Config.cassette_library_dir("fixture/vcr_cassettes", "fixture/custom_cassettes")
9 | :ok
10 | end
11 |
12 | test "list_units" do
13 | use_cassette "etcd_list_units", custom: true do
14 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
15 | {:ok, units} = list_units(pid)
16 |
17 | assert 4 == length(units)
18 |
19 | assert %FleetApi.Unit{
20 | currentState: "launched",
21 | desiredState: "launched",
22 | machineID: "820c30c0867844129d63f4409871ba39",
23 | name: "subgun-http.service",
24 | options: [
25 | %FleetApi.UnitOption{
26 | name: "Description",
27 | section: "Unit",
28 | value: "subgun"},
29 | %FleetApi.UnitOption{
30 | name: "ExecStartPre",
31 | section: "Service",
32 | value: "-/usr/bin/docker kill subgun-%i"},
33 | %FleetApi.UnitOption{
34 | name: "ExecStartPre",
35 | section: "Service",
36 | value: "-/usr/bin/docker rm subgun-%i"},
37 | %FleetApi.UnitOption{
38 | name: "ExecStart",
39 | section: "Service",
40 | value: "/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun"},
41 | %FleetApi.UnitOption{
42 | name: "ExecStop",
43 | section: "Service",
44 | value: "/usr/bin/docker stop subgun-%i"},
45 | %FleetApi.UnitOption{
46 | name: "Conflicts",
47 | section: "X-Fleet",
48 | value: "subgun-http@*.service"}]} in units
49 |
50 | assert %FleetApi.Unit{
51 | currentState: "inactive",
52 | desiredState: "launched",
53 | machineID: "76ffb3a4588c46f3941c073df77be5e9",
54 | name: "subgun-http@.service",
55 | options: [
56 | %FleetApi.UnitOption{
57 | name: "Description",
58 | section: "Unit",
59 | value: "subgun"},
60 | %FleetApi.UnitOption{
61 | name: "ExecStartPre",
62 | section: "Service",
63 | value: "-/usr/bin/docker kill subgun-%i"},
64 | %FleetApi.UnitOption{
65 | name: "ExecStartPre",
66 | section: "Service",
67 | value: "-/usr/bin/docker rm subgun-%i"},
68 | %FleetApi.UnitOption{
69 | name: "ExecStart",
70 | section: "Service",
71 | value: "/usr/bin/docker run --rm --name subgun-%i -e SUBGUN_LISTEN=127.0.0.1:8080 -e SUBGUN_LISTS=recv@sandbox2398.mailgun.org -e SUBGUN_API_KEY=key-779ru4cibbnhfa1qp7a3apyvwkls7ny7 -p 8080:8080 coreos/subgun"},
72 | %FleetApi.UnitOption{
73 | name: "ExecStop",
74 | section: "Service",
75 | value: "/usr/bin/docker stop subgun-%i"},
76 | %FleetApi.UnitOption{
77 | name: "Conflicts",
78 | section: "X-Fleet",
79 | value: "subgun-http@*.service"}]} in units
80 | end
81 | end
82 |
83 | test "list_units empty list" do
84 | use_cassette "etcd_list_units_empty", custom: true do
85 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
86 | {:ok, units} = list_units(pid)
87 |
88 | assert 0 == length(units)
89 | end
90 | end
91 |
92 | test "list_units nil list instead of empty list" do
93 | use_cassette "etcd_list_units_null", custom: true do
94 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
95 | {:ok, units} = list_units(pid)
96 |
97 | assert 0 == length(units)
98 | end
99 | end
100 |
101 | test "list_units no units field in response" do
102 | use_cassette "etcd_list_units_weird_response", custom: true do
103 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
104 | {:ok, units} = list_units(pid)
105 |
106 | assert 0 == length(units)
107 | end
108 | end
109 |
110 | test "get_unit" do
111 | use_cassette "etcd_get_unit", custom: true do
112 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
113 | {:ok, unit} = get_unit(pid, "subgun-http.service")
114 |
115 | assert "subgun-http.service" == unit.name
116 | assert "launched" == unit.currentState
117 | assert "launched" == unit.desiredState
118 | assert %FleetApi.UnitOption{name: "Description", section: "Unit", value: "subgun"} in unit.options
119 | end
120 | end
121 |
122 | test "delete_unit" do
123 | use_cassette "etcd_delete_unit", custom: true do
124 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
125 | assert :ok = delete_unit(pid, "subgun-http.service")
126 | end
127 | end
128 |
129 | test "list_machines" do
130 | use_cassette "etcd_list_machines", custom: true do
131 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
132 | {:ok, machines} = list_machines(pid)
133 |
134 | assert length(machines) == 3
135 |
136 | assert %FleetApi.Machine{
137 | id: "76ffb3a4588c46f3941c073df77be5e9",
138 | metadata: nil,
139 | primaryIP: "127.0.0.1"} in machines
140 |
141 | assert %FleetApi.Machine{
142 | id: "820c30c0867844129d63f4409871ba39",
143 | metadata: nil,
144 | primaryIP: "127.0.0.2"} in machines
145 |
146 | assert %FleetApi.Machine{
147 | id: "f439a6a2dd8f43dbad60994cc1fb68f6",
148 | metadata: nil,
149 | primaryIP: "127.0.0.3"} in machines
150 | end
151 | end
152 |
153 | test "list_unit_states" do
154 | use_cassette "etcd_list_unit_states", custom: true do
155 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
156 | {:ok, states} = list_unit_states(pid)
157 |
158 | assert length(states) == 1
159 |
160 | assert %FleetApi.UnitState{
161 | hash: "eef29cad431ad16c8e164400b2f3c85afd73b238",
162 | machineID: "820c30c0867844129d63f4409871ba39",
163 | name: "subgun-http.service",
164 | systemdActiveState: "active",
165 | systemdLoadState: "loaded",
166 | systemdSubState: "running"} in states
167 | end
168 | end
169 |
170 | test "create unit" do
171 | use_cassette "etcd_set_unit_new", custom: true do
172 | unit = %FleetApi.Unit{
173 | name: "test.service",
174 | desiredState: "launched",
175 | options: [
176 | %FleetApi.UnitOption{
177 | name: "ExecStart",
178 | section: "Service",
179 | value: "/usr/bin/sleep 3000"
180 | }
181 | ]
182 |
183 | }
184 |
185 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
186 | assert :ok = set_unit(pid, "test.service", unit)
187 | end
188 | end
189 |
190 | test "update_unit_desired_state" do
191 | use_cassette "etcd_set_unit_update", custom: true do
192 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
193 | assert :ok = set_unit(pid, "test.service", "launched")
194 | end
195 | end
196 |
197 | test "get_api_discovery" do
198 | use_cassette "etcd_get_api_discovery", custom: true do
199 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
200 | {:ok, discovery} = get_api_discovery(pid)
201 |
202 | assert discovery["discoveryVersion"] == "v1"
203 | assert discovery["id"] == "fleet:v1"
204 | assert discovery["title"] == "fleet API"
205 | end
206 | end
207 |
208 | test "list_units no etcd nodes available" do
209 | use_cassette "etcd_response_no_nodes", custom: true do
210 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
211 |
212 | assert {:error, :no_valid_nodes} == FleetApi.Etcd.list_units(pid)
213 | end
214 | end
215 |
216 | test "list_units refresh_nodes call gets 503" do
217 | use_cassette "etcd_response_503_response", custom: true do
218 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
219 |
220 | assert {:error, "Received 503 response."} == FleetApi.Etcd.list_units(pid)
221 | end
222 | end
223 |
224 | test "list_units multiple calls only calls etcd and discovery once" do
225 | use_cassette "etcd_list_units_multiple_calls", custom: true do
226 | {:ok, pid} = FleetApi.Etcd.start_link("abcd1234")
227 |
228 | {:ok, units} = list_units(pid)
229 |
230 | assert 4 == length(units)
231 |
232 | {:ok, units} = list_units(pid)
233 | {:ok, units} = list_units(pid)
234 | end
235 | end
236 | end
--------------------------------------------------------------------------------
/test/fleet_api_test.exs:
--------------------------------------------------------------------------------
1 | defmodule FleetApiTest do
2 |
3 | end
--------------------------------------------------------------------------------
/test/test_helper.exs:
--------------------------------------------------------------------------------
1 | ExUnit.start()
2 |
--------------------------------------------------------------------------------