diplomatic_bag 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +24 -0
- data/README.md +356 -0
- data/features/configuration.feature +9 -0
- data/features/step_definitions/setup_diplomat.rb +24 -0
- data/features/step_definitions/test_key_value.rb +9 -0
- data/lib/diplomat/acl.rb +81 -0
- data/lib/diplomat/agent.rb +42 -0
- data/lib/diplomat/check.rb +109 -0
- data/lib/diplomat/configuration.rb +28 -0
- data/lib/diplomat/datacenter.rb +21 -0
- data/lib/diplomat/error.rb +15 -0
- data/lib/diplomat/event.rb +166 -0
- data/lib/diplomat/health.rb +81 -0
- data/lib/diplomat/kv.rb +263 -0
- data/lib/diplomat/lock.rb +54 -0
- data/lib/diplomat/maintenance.rb +41 -0
- data/lib/diplomat/members.rb +14 -0
- data/lib/diplomat/node.rb +43 -0
- data/lib/diplomat/nodes.rb +22 -0
- data/lib/diplomat/query.rb +87 -0
- data/lib/diplomat/rest_client.rb +278 -0
- data/lib/diplomat/service.rb +111 -0
- data/lib/diplomat/session.rb +75 -0
- data/lib/diplomat/status.rb +22 -0
- data/lib/diplomat/version.rb +3 -0
- data/lib/diplomat.rb +62 -0
- data/lib/diplomatic_bag/datacenters.rb +11 -0
- data/lib/diplomatic_bag/info.rb +32 -0
- data/lib/diplomatic_bag/nodes.rb +28 -0
- data/lib/diplomatic_bag/service.rb +20 -0
- data/lib/diplomatic_bag/services.rb +38 -0
- data/lib/diplomatic_bag.rb +7 -0
- metadata +89 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 641df0432390b52215d6063148e94b402ea200fa5a424ca2499c98aa8ba2d88a
|
4
|
+
data.tar.gz: 4a0ddc8cc86c54a6e52ed1a6b387a21ed206c1fc2743196b3e143cc06db169b7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0f1568f519ef9b7b685bd07905b60ba441051a928c3ec11e0a1b1ae5bae0c4ff15096749c6ac55a52d82a2d34640b99558b5a5bd1cd708e383dfbd59a19240a3
|
7
|
+
data.tar.gz: 34193eac2e23dff911c8c8845a0998102f0a88bafd5e4d9104c29c184d2d934bfd1bd376217a240cf76383efd25787a3779070f449045c0f73db998087ecf960
|
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Copyright (c) 2014, Diplomat project contributors
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
* Redistributions of source code must retain the above copyright
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
8
|
+
* Redistributions in binary form must reproduce the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
10
|
+
documentation and/or other materials provided with the distribution.
|
11
|
+
* Neither the name of the Ruby FFI project nor the
|
12
|
+
names of its contributors may be used to endorse or promote products
|
13
|
+
derived from this software without specific prior written permission.
|
14
|
+
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
16
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
17
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
19
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
20
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
21
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
22
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
23
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
24
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,356 @@
|
|
1
|
+
# Diplomat
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/diplomat.svg)](https://rubygems.org/gems/diplomat) [![Gem](https://img.shields.io/gem/dt/diplomat.svg)](https://rubygems.org/gems/diplomat/versions/2.0.0) [![Build Status](https://travis-ci.org/WeAreFarmGeek/diplomat.svg?branch=master)](https://travis-ci.org/WeAreFarmGeek/diplomat) [![Code Climate](https://codeclimate.com/github/johnhamelink/diplomat.svg)](https://codeclimate.com/github/WeAreFarmGeek/diplomat) [![Inline docs](http://inch-ci.org/github/wearefarmgeek/diplomat.svg?branch=master)](http://inch-ci.org/github/wearefarmgeek/diplomat)
|
3
|
+
### A HTTP Ruby API for [Consul](http://www.consul.io/)
|
4
|
+
|
5
|
+
![Diplomacy Board Game](http://i.imgur.com/Nkuy4b7.jpg)
|
6
|
+
|
7
|
+
|
8
|
+
## FAQ
|
9
|
+
|
10
|
+
#### What's Diplomat for?
|
11
|
+
|
12
|
+
Diplomat allows any ruby application to interact with [Consul's](http://www.consul.io/) distributed key value store, and also receive information about services currently available in the Consul cluster.
|
13
|
+
|
14
|
+
#### Does it work in rails?
|
15
|
+
|
16
|
+
Yup! In fact, we're using it in all of our rails production apps instead of any previous case where it'd be right to use environment variables according to [12Factor configuration principals](http://12factor.net/config). This gives us the ability to scale up without making any changes to the actual project codebase, and to move applications around the cluster with ease.
|
17
|
+
|
18
|
+
Here's what a production database.yml file might look like:
|
19
|
+
|
20
|
+
```erb
|
21
|
+
<% if Rails.env.production? %>
|
22
|
+
production:
|
23
|
+
adapter: postgresql
|
24
|
+
encoding: unicode
|
25
|
+
host: <%= Diplomat::Service.get('postgres').Address %>
|
26
|
+
database: <%= Diplomat::Kv.get('project/db/name') %>
|
27
|
+
pool: 5
|
28
|
+
username: <%= Diplomat::Kv.get('project/db/user') %>
|
29
|
+
password: <%= Diplomat::Kv.get('project/db/pass') %>
|
30
|
+
port: <%= Diplomat::Service.get('postgres').ServicePort %>
|
31
|
+
<% end %>
|
32
|
+
```
|
33
|
+
|
34
|
+
#### Why would I use Consul over ZooKeeper, Doozerd, etcd, Nagios, Sensu, SmartStack, SkyDNS, Chef, Puppet, Ansible, etc?
|
35
|
+
|
36
|
+
[Read up what makes Consul different here](http://www.consul.io/intro/vs/index.html)
|
37
|
+
|
38
|
+
#### How do I install Consul?
|
39
|
+
|
40
|
+
[See here](http://www.consul.io/intro/). I managed to roll it out on my production machines with the help of [Ansible](http://www.ansible.com/) in one working day.
|
41
|
+
|
42
|
+
### Which versions of Ruby does Diplomat support? Where did my ruby 1.9 compatibility go?
|
43
|
+
|
44
|
+
Check out [Travis](https://travis-ci.org/WeAreFarmGeek/diplomat) to see which versions of ruby we currently test when we're making builds.
|
45
|
+
|
46
|
+
We've dropped ruby 1.9 support. You can still depend on Diplomat by directly using the `ruby-1.9-compatible` branch on github, although be advised it's not actively maintained anymore.
|
47
|
+
|
48
|
+
## Usage
|
49
|
+
|
50
|
+
[The most up to date place to read about the API is here.](http://rubydoc.info/github/WeAreFarmGeek/diplomat)
|
51
|
+
|
52
|
+
Here's a few examples of how diplomat works:
|
53
|
+
|
54
|
+
### Key Values
|
55
|
+
|
56
|
+
#### Setting
|
57
|
+
|
58
|
+
Setting the value of a key is easy as pie:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
foo = Diplomat::Kv.put('foo', 'bar')
|
62
|
+
# => "bar"
|
63
|
+
```
|
64
|
+
|
65
|
+
#### Getting
|
66
|
+
|
67
|
+
Getting the value of a key is just as simple:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
foo = Diplomat::Kv.get('foo')
|
71
|
+
# => "bar"
|
72
|
+
```
|
73
|
+
|
74
|
+
Or retrieve a value from another datacenter:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
foo = Diplomat::Kv.get('foo', :dc => 'dc-west')
|
78
|
+
# => "baz"
|
79
|
+
```
|
80
|
+
|
81
|
+
You can also retrieve values recursively:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
Diplomat::Kv.put('foo/a', 'lorem')
|
85
|
+
Diplomat::Kv.put('foo/b', 'ipsum')
|
86
|
+
Diplomat::Kv.put('foo/c', 'dolor')
|
87
|
+
|
88
|
+
Diplomat::Kv.get('foo/', recurse: true)
|
89
|
+
# => [{:key=>"foo/a", :value=>"lorem"}, {:key=>"foo/b", :value=>"ipsum"}, {:key=>"foo/c", :value=>"dolor"}]
|
90
|
+
```
|
91
|
+
|
92
|
+
|
93
|
+
Or list all available keys:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
Diplomat::Kv.get('/', :keys => true) # => ['foo/a', 'foo/b']
|
97
|
+
```
|
98
|
+
You can convert the consul data to a ruby hash
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
Diplomat::Kv.put('foo/a', 'lorem')
|
102
|
+
Diplomat::Kv.put('foo/b', 'ipsum')
|
103
|
+
Diplomat::Kv.put('foo/c', 'dolor')
|
104
|
+
|
105
|
+
Diplomat::Kv.get('foo/', recurse: true, convert_to_hash: true)
|
106
|
+
# => {"foo"=>{"a"=>"lorem", "b"=>"ipsum", "c"=>"dolor"}}
|
107
|
+
```
|
108
|
+
|
109
|
+
### Nodes
|
110
|
+
|
111
|
+
#### Getting
|
112
|
+
|
113
|
+
Look up a node:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
foo_service = Diplomat::Node.get('foo')
|
117
|
+
# => {"Node"=>{"Node"=>"foobar", "Address"=>"10.1.10.12"}, "Services"=>{"consul"=>{"ID"=>"consul", "Service"=>"consul", "Tags"=>nil, "Port"=>8300}, "redis"=>{"ID"=>"redis", "Service"=>"redis", "Tags"=>["v1"], "Port"=>8000}}}
|
118
|
+
```
|
119
|
+
|
120
|
+
Get all nodes:
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
nodes = Diplomat::Node.get_all
|
124
|
+
# => [#<OpenStruct Address="10.1.10.12", Node="foo">, #<OpenStruct Address="10.1.10.13", Node="bar">]
|
125
|
+
```
|
126
|
+
|
127
|
+
Get all nodes for a particular datacenter
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
nodes = Diplomat::Node.get_all({ :dc => 'My_Datacenter' })
|
131
|
+
# => [#<OpenStruct Address="10.1.10.12", Node="foo">, #<OpenStruct Address="10.1.10.13", Node="bar">]
|
132
|
+
```
|
133
|
+
|
134
|
+
Register a node:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
Diplomat::Node.register({ :Node => "app1", :Address => "10.0.0.2" })
|
138
|
+
# => true
|
139
|
+
```
|
140
|
+
|
141
|
+
De-register a node:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
Diplomat::Node.deregister({ :Node => "app1", :Address => "10.0.0.2" })
|
145
|
+
# => true
|
146
|
+
```
|
147
|
+
|
148
|
+
### Services
|
149
|
+
|
150
|
+
#### Getting
|
151
|
+
|
152
|
+
Looking up a service is easy as pie:
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
foo_service = Diplomat::Service.get('foo')
|
156
|
+
# => #<OpenStruct Node="hotel", Address="1.2.3.4", ServiceID="hotel_foo", ServiceName="foo", ServiceTags=["foo"], ServicePort=5432>
|
157
|
+
```
|
158
|
+
Or if you have multiple nodes per service:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
foo_service = Diplomat::Service.get('foo', :all)
|
162
|
+
# => [#<OpenStruct Node="hotel", Address="1.2.3.4", ServiceID="hotel_foo", ServiceName="foo", ServiceTags=["foo"], ServicePort=5432>,#<OpenStruct Node="indigo", Address="1.2.3.5", ServiceID="indigo_foo", ServiceName="foo", ServiceTags=["foo"], ServicePort=5432>]
|
163
|
+
```
|
164
|
+
|
165
|
+
Or if you want to find services for a particular datacenter
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
foo_service = Diplomat::Service.get('foo', :all, { :dc => 'My_Datacenter'})
|
169
|
+
# => [#<OpenStruct Node="hotel", Address="1.2.3.4", ServiceID="hotel_foo", ServiceName="foo", ServiceTags=["foo"], ServicePort=5432>,#<OpenStruct Node="indigo", Address="1.2.3.5", ServiceID="indigo_foo", ServiceName="foo", ServiceTags=["foo"], ServicePort=5432>]
|
170
|
+
```
|
171
|
+
|
172
|
+
If you wish to list all the services on consul:
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
services = Diplomat::Service.get_all
|
176
|
+
# => #<OpenStruct consul=[], foo=[], bar=[]>
|
177
|
+
```
|
178
|
+
|
179
|
+
If you wish to list all the services for a specific datacenter:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
services = Diplomat::Service.get_all({ :dc => 'My_Datacenter' })
|
183
|
+
# => #<OpenStruct consul=[], foo=[], bar=[]>
|
184
|
+
```
|
185
|
+
|
186
|
+
### Datacenters
|
187
|
+
|
188
|
+
Getting a list of datacenters is quite simple and gives you the option to extract all services out of
|
189
|
+
all accessible datacenters if you need to.
|
190
|
+
|
191
|
+
```ruby
|
192
|
+
datacenters = Diplomat::Datacenter.get()
|
193
|
+
# => ["DC1", "DC2"]
|
194
|
+
```
|
195
|
+
|
196
|
+
### Sessions
|
197
|
+
|
198
|
+
Creating a session:
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
sessionid = Diplomat::Session.create({:Node => "server1", :Name => "my-lock"})
|
202
|
+
# => "fc5ca01a-c317-39ea-05e8-221da00d3a12"
|
203
|
+
```
|
204
|
+
Or destroying a session:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
Diplomat::Session.destroy("fc5ca01a-c317-39ea-05e8-221da00d3a12")
|
208
|
+
```
|
209
|
+
|
210
|
+
Renew a session:
|
211
|
+
```ruby
|
212
|
+
Diplomat::Session.renew(sessionid)
|
213
|
+
```
|
214
|
+
|
215
|
+
List sessions:
|
216
|
+
```ruby
|
217
|
+
Diplomat::Session.list.each {|session| puts "#{session["ID"]} #{session["Name"]}"}
|
218
|
+
```
|
219
|
+
|
220
|
+
### Locks
|
221
|
+
|
222
|
+
Acquire a lock:
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
sessionid = Diplomat::Session.create({:Node => "server1", :Name => "my-lock"})
|
226
|
+
lock_acquired = Diplomat::Lock.acquire("/key/to/lock", sessionid)
|
227
|
+
# => true
|
228
|
+
```
|
229
|
+
Or wait for a lock to be acquired:
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
sessionid = Diplomat::Session.create({:hostname => "server1", :ipaddress => "4.4.4.4"})
|
233
|
+
lock_acquired = Diplomat::Lock.wait_to_acquire("/key/to/lock", sessionid)
|
234
|
+
```
|
235
|
+
|
236
|
+
Release a lock:
|
237
|
+
|
238
|
+
```ruby
|
239
|
+
Diplomat::Lock.release("/key/to/lock", sessionid )
|
240
|
+
```
|
241
|
+
|
242
|
+
### Events
|
243
|
+
|
244
|
+
Fire an event:
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
Diplomat::Event.fire('do_something', 'payload')
|
248
|
+
```
|
249
|
+
|
250
|
+
List all events with a certain name received by the local agent:
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
Diplomat::Event.get_all('do_something')
|
254
|
+
```
|
255
|
+
|
256
|
+
Get the latest event with a certain name received by the local agent:
|
257
|
+
|
258
|
+
```ruby
|
259
|
+
Diplomat::Event.get('do_something')
|
260
|
+
```
|
261
|
+
|
262
|
+
Iterate through the events with a certain name received by the local agent:
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
events = Enumerator.new do |y|
|
266
|
+
ret = {token: :first}
|
267
|
+
while ret = begin Diplomat::Event.get('do_something', ret[:token], :reject) rescue nil end
|
268
|
+
y.yield(ret[:value])
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
events.each{ |e| puts e }
|
273
|
+
```
|
274
|
+
|
275
|
+
### Status
|
276
|
+
|
277
|
+
Returns information about the status of the Consul cluster.
|
278
|
+
|
279
|
+
Get the raft leader for the datacenter in which the local consul agent is running
|
280
|
+
|
281
|
+
```ruby
|
282
|
+
Diplomat::Status.leader()
|
283
|
+
```
|
284
|
+
|
285
|
+
Get an array of Raft peers for the datacenter in which the agent is running
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
Diplomat::Status.peers()
|
289
|
+
```
|
290
|
+
|
291
|
+
### Maintenance mode
|
292
|
+
|
293
|
+
Enable maintenance mode on a host, with optional reason and DC (requires access to local agent)
|
294
|
+
|
295
|
+
```ruby
|
296
|
+
Diplomat::Maintenance.enable(true, 'doing stuff', :dc => 'abc')
|
297
|
+
```
|
298
|
+
|
299
|
+
Determine if a host has maintenance mode enabled
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
Diplomat::Maintenance.enabled('foobar')
|
303
|
+
# => { :enabled => true, :reason => 'doing stuff' }
|
304
|
+
```
|
305
|
+
|
306
|
+
### Custom configuration
|
307
|
+
|
308
|
+
You can create a custom configuration using the following syntax:
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
Diplomat.configure do |config|
|
312
|
+
# Set up a custom Consul URL
|
313
|
+
config.url = "http://localhost:8888"
|
314
|
+
# Set up a custom Faraday Middleware
|
315
|
+
config.middleware = MyCustomMiddleware
|
316
|
+
# Set extra Faraday configuration options and custom access token (ACL)
|
317
|
+
config.options = {ssl: {version: :TLSv1_2}, headers: {"X-Consul-Token" => "xxxxxxxx-yyyy-zzzz-1111-222222222222"}}
|
318
|
+
end
|
319
|
+
```
|
320
|
+
|
321
|
+
This is traditionally kept inside the `config/initializers` directory if you're using rails. The middleware allows you to customise what happens when faraday sends and receives data. This can be useful if you want to instrument your use of diplomat, for example. You can read more about Faraday's custom middleware [here](http://stackoverflow.com/a/20973008).
|
322
|
+
|
323
|
+
Alternatively, configuration settings can be overriden at each method call allowing for instance to address different consul agents, with some other token.
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
Diplomat::Service.get('foo', { http_addr: 'http://consu01:8500' })
|
327
|
+
Diplomat::Service.get('foo', { http_addr: 'http://consu02:8500' })
|
328
|
+
Diplomat::Kv.put('key/path', 'value', { http_addr: 'http://localhost:8500', dc: 'dc1', token: '111-222-333-444-555' })
|
329
|
+
```
|
330
|
+
|
331
|
+
Most common options are:
|
332
|
+
* dc: target datacenter
|
333
|
+
* token: identity used to perform the corresponding action
|
334
|
+
* http_addr: to target a remote consul node
|
335
|
+
* stale: use consistency mode that allows any server to service the read regardless of whether it is the leader
|
336
|
+
|
337
|
+
### Todo
|
338
|
+
|
339
|
+
- [ ] Updating Docs with latest changes
|
340
|
+
- [ ] Using custom objects for response objects (instead of openStruct)
|
341
|
+
- [ ] PUTing and DELETEing services
|
342
|
+
- [x] Custom SSL Cert Middleware for faraday
|
343
|
+
- [x] Allowing the custom configuration of the consul url to connect to
|
344
|
+
- [x] Deleting Keys
|
345
|
+
- [x] Listing available services
|
346
|
+
- [x] Health
|
347
|
+
- [x] Members
|
348
|
+
- [x] Status
|
349
|
+
- [x] Datacenter support for services
|
350
|
+
- [x] Ruby 1.8 support
|
351
|
+
- [x] Events
|
352
|
+
|
353
|
+
|
354
|
+
## Enjoy!
|
355
|
+
|
356
|
+
![Photo Copyright "merlinmann" https://www.flickr.com/photos/merlin/. All rights reserved.](http://i.imgur.com/3mBwzR9.jpg)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Feature: Configuration
|
2
|
+
|
3
|
+
Scenario: I'm Setting up Diplomat with a default config
|
4
|
+
Given I am setting up a default diplomat
|
5
|
+
Then I should be able to get and put keys
|
6
|
+
|
7
|
+
Scenario: I'm Setting up Diplomat with a custom config
|
8
|
+
Given I am setting up a custom diplomat
|
9
|
+
Then I should be able to get and put keys
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'diplomat'
|
2
|
+
|
3
|
+
Given 'I am setting up a default diplomat' do
|
4
|
+
end
|
5
|
+
|
6
|
+
Given 'I am setting up a custom diplomat' do
|
7
|
+
class StubMiddleware # :nodoc:
|
8
|
+
def initialize(app, options = {})
|
9
|
+
@app = app
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
@app.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
expect do
|
19
|
+
Diplomat.configure do |config|
|
20
|
+
config.url = 'http://localhost:8500'
|
21
|
+
config.middleware = StubMiddleware
|
22
|
+
end
|
23
|
+
end.to_not raise_error
|
24
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Then 'I should be able to get and put keys' do
|
2
|
+
# High-fructose Corn Syrup
|
3
|
+
Diplomat.put('drink', 'Irn Bru')
|
4
|
+
expect(Diplomat.get('drink')).to eq('Irn Bru')
|
5
|
+
|
6
|
+
# Sugar
|
7
|
+
Diplomat::Kv.put('cake', 'Sponge')
|
8
|
+
expect(Diplomat::Kv.get('cake')).to eq('Sponge')
|
9
|
+
end
|
data/lib/diplomat/acl.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul ACL API endpoint
|
3
|
+
class Acl < Diplomat::RestClient
|
4
|
+
@access_methods = %i[list info create destroy update]
|
5
|
+
attr_reader :id, :type, :acl
|
6
|
+
|
7
|
+
# Get Acl info by ID
|
8
|
+
# @param id [String] ID of the Acl to get
|
9
|
+
# @param options [Hash] options parameter hash
|
10
|
+
# @return [Hash]
|
11
|
+
# rubocop:disable PerceivedComplexity
|
12
|
+
def info(id, options = {}, not_found = :reject, found = :return)
|
13
|
+
@id = id
|
14
|
+
@options = options
|
15
|
+
custom_params = []
|
16
|
+
custom_params << use_consistency(options)
|
17
|
+
|
18
|
+
raw = send_get_request(@conn_no_err, ["/v1/acl/info/#{id}"], options, custom_params)
|
19
|
+
|
20
|
+
if raw.status == 200 && raw.body.chomp != 'null'
|
21
|
+
case found
|
22
|
+
when :reject
|
23
|
+
raise Diplomat::AclAlreadyExists, id
|
24
|
+
when :return
|
25
|
+
@raw = raw
|
26
|
+
return parse_body
|
27
|
+
end
|
28
|
+
elsif raw.status == 200 && raw.body.chomp == 'null'
|
29
|
+
case not_found
|
30
|
+
when :reject
|
31
|
+
raise Diplomat::AclNotFound, id
|
32
|
+
when :return
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
else
|
36
|
+
raise Diplomat::UnknownStatus, "status #{raw.status}: #{raw.body}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# rubocop:enable PerceivedComplexity
|
40
|
+
|
41
|
+
# List all Acls
|
42
|
+
# @param options [Hash] options parameter hash
|
43
|
+
# @return [List] list of [Hash] of Acls
|
44
|
+
def list(options = {})
|
45
|
+
@raw = send_get_request(@conn_no_err, ['/v1/acl/list'], options)
|
46
|
+
parse_body
|
47
|
+
end
|
48
|
+
|
49
|
+
# Update an Acl definition, create if not present
|
50
|
+
# @param value [Hash] Acl definition, ID field is mandatory
|
51
|
+
# @param options [Hash] options parameter hash
|
52
|
+
# @return [Hash] The result Acl
|
53
|
+
def update(value, options = {})
|
54
|
+
raise Diplomat::IdParameterRequired unless value['ID'] || value[:ID]
|
55
|
+
|
56
|
+
custom_params = use_cas(@options)
|
57
|
+
@raw = send_put_request(@conn, ['/v1/acl/update'], options, value, custom_params)
|
58
|
+
parse_body
|
59
|
+
end
|
60
|
+
|
61
|
+
# Create an Acl definition
|
62
|
+
# @param value [Hash] Acl definition, ID field is mandatory
|
63
|
+
# @param options [Hash] options parameter hash
|
64
|
+
# @return [Hash] The result Acl
|
65
|
+
def create(value, options = {})
|
66
|
+
custom_params = use_cas(@options)
|
67
|
+
@raw = send_put_request(@conn, ['/v1/acl/create'], options, value, custom_params)
|
68
|
+
parse_body
|
69
|
+
end
|
70
|
+
|
71
|
+
# Destroy an ACl token by its id
|
72
|
+
# @param ID [String] the Acl ID
|
73
|
+
# @param options [Hash] options parameter hash
|
74
|
+
# @return [Bool]
|
75
|
+
def destroy(id, options = {})
|
76
|
+
@id = id
|
77
|
+
@raw = send_put_request(@conn, ["/v1/acl/destroy/#{@id}"], options, nil)
|
78
|
+
@raw.body.chomp == 'true'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module Diplomat
|
5
|
+
# Agent API endpoint methods
|
6
|
+
# @see https://www.consul.io/docs/agent/http/agent.html
|
7
|
+
class Agent < Diplomat::RestClient
|
8
|
+
@access_methods = %i[self checks services members]
|
9
|
+
|
10
|
+
# Get agent configuration
|
11
|
+
# @param options [Hash] options parameter hash
|
12
|
+
# @return [OpenStruct] all data associated with the node
|
13
|
+
def self(options = {})
|
14
|
+
ret = send_get_request(@conn, ['/v1/agent/self'], options)
|
15
|
+
JSON.parse(ret.body).tap { |node| OpenStruct.new node }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get local agent checks
|
19
|
+
# @param options [Hash] options parameter hash
|
20
|
+
# @return [OpenStruct] all agent checks
|
21
|
+
def checks(options = {})
|
22
|
+
ret = send_get_request(@conn, ['/v1/agent/checks'], options)
|
23
|
+
JSON.parse(ret.body).tap { |node| OpenStruct.new node }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Get local agent services
|
27
|
+
# @param options [Hash] options parameter hash
|
28
|
+
# @return [OpenStruct] all agent services
|
29
|
+
def services(options = {})
|
30
|
+
ret = send_get_request(@conn, ['/v1/agent/services'], options)
|
31
|
+
JSON.parse(ret.body).tap { |node| OpenStruct.new node }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Get cluster members (as seen by the agent)
|
35
|
+
# @param options [Hash] options parameter hash
|
36
|
+
# @return [OpenStruct] all members
|
37
|
+
def members(options = {})
|
38
|
+
ret = send_get_request(@conn, ['/v1/agent/members'], options)
|
39
|
+
JSON.parse(ret.body).map { |node| OpenStruct.new node }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Diplomat
|
2
|
+
# Methods for interacting with the Consul check API endpoint
|
3
|
+
class Check < Diplomat::RestClient
|
4
|
+
@access_methods = %i[checks register_script register_ttl
|
5
|
+
deregister pass warn fail]
|
6
|
+
|
7
|
+
# Get registered checks
|
8
|
+
# @return [OpenStruct] all data associated with the service
|
9
|
+
def checks(options = {})
|
10
|
+
ret = send_get_request(@conn, ['/v1/agent/checks'], options)
|
11
|
+
JSON.parse(ret.body)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Register a check
|
15
|
+
# @param check_id [String] the unique id of the check
|
16
|
+
# @param name [String] the name
|
17
|
+
# @param notes [String] notes about the check
|
18
|
+
# @param args [String[]] command to be run for check
|
19
|
+
# @param interval [String] frequency (with units) of the check execution
|
20
|
+
# @param options [Hash] options parameter hash
|
21
|
+
# @return [Integer] Status code
|
22
|
+
# rubocop:disable ParameterLists
|
23
|
+
def register_script(check_id, name, notes, args, interval, options = {})
|
24
|
+
unless args.is_a?(Array)
|
25
|
+
raise(Diplomat::DeprecatedArgument, 'Script usage is deprecated, replace by an array of args')
|
26
|
+
end
|
27
|
+
|
28
|
+
definition = JSON.generate(
|
29
|
+
'ID' => check_id,
|
30
|
+
'Name' => name,
|
31
|
+
'Notes' => notes,
|
32
|
+
'Args' => args,
|
33
|
+
'Interval' => interval
|
34
|
+
)
|
35
|
+
ret = send_put_request(@conn, ['/v1/agent/check/register'], options, definition)
|
36
|
+
ret.status == 200
|
37
|
+
end
|
38
|
+
# rubocop:enable ParameterLists
|
39
|
+
|
40
|
+
# Register a TTL check
|
41
|
+
# @param check_id [String] the unique id of the check
|
42
|
+
# @param name [String] the name
|
43
|
+
# @param notes [String] notes about the check
|
44
|
+
# @param ttl [String] time (with units) to mark a check down
|
45
|
+
# @param options [Hash] options parameter hash
|
46
|
+
# @return [Boolean] Success
|
47
|
+
def register_ttl(check_id, name, notes, ttl, options = {})
|
48
|
+
definition = JSON.generate(
|
49
|
+
'ID' => check_id,
|
50
|
+
'Name' => name,
|
51
|
+
'Notes' => notes,
|
52
|
+
'TTL' => ttl
|
53
|
+
)
|
54
|
+
ret = send_put_request(@conn, ['/v1/agent/check/register'], options, definition)
|
55
|
+
ret.status == 200
|
56
|
+
end
|
57
|
+
|
58
|
+
# Deregister a check
|
59
|
+
# @param check_id [String] the unique id of the check
|
60
|
+
# @param options [Hash] options parameter hash
|
61
|
+
# @return [Integer] Status code
|
62
|
+
def deregister(check_id, options = {})
|
63
|
+
ret = send_put_request(@conn, ["/v1/agent/check/deregister/#{check_id}"], options, nil)
|
64
|
+
ret.status == 200
|
65
|
+
end
|
66
|
+
|
67
|
+
# Update a TTL check
|
68
|
+
# @param check_id [String] the unique id of the check
|
69
|
+
# @param status [String] status of the check. Valid values are "passing", "warning", and "critical"
|
70
|
+
# @param output [String] human-readable message will be passed through to the check's Output field
|
71
|
+
# @param options [Hash] options parameter hash
|
72
|
+
# @return [Integer] Status code
|
73
|
+
def update_ttl(check_id, status, output = nil, options = {})
|
74
|
+
definition = JSON.generate(
|
75
|
+
'Status' => status,
|
76
|
+
'Output' => output
|
77
|
+
)
|
78
|
+
ret = send_put_request(@conn, ["/v1/agent/check/update/#{check_id}"], options, definition)
|
79
|
+
ret.status == 200
|
80
|
+
end
|
81
|
+
|
82
|
+
# Pass a check
|
83
|
+
# @param check_id [String] the unique id of the check
|
84
|
+
# @param output [String] human-readable message will be passed through to the check's Output field
|
85
|
+
# @param options [Hash] options parameter hash
|
86
|
+
# @return [Integer] Status code
|
87
|
+
def pass(check_id, output = nil, options = {})
|
88
|
+
update_ttl(check_id, 'passing', output, options)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Warn a check
|
92
|
+
# @param check_id [String] the unique id of the check
|
93
|
+
# @param output [String] human-readable message will be passed through to the check's Output field
|
94
|
+
# @param options [Hash] options parameter hash
|
95
|
+
# @return [Integer] Status code
|
96
|
+
def warn(check_id, output = nil, options = {})
|
97
|
+
update_ttl(check_id, 'warning', output, options)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Fail a check
|
101
|
+
# @param check_id [String] the unique id of the check
|
102
|
+
# @param output [String] human-readable message will be passed through to the check's Output field
|
103
|
+
# @param options [Hash] options parameter hash
|
104
|
+
# @return [Integer] Status code
|
105
|
+
def fail(check_id, output = nil, options = {})
|
106
|
+
update_ttl(check_id, 'critical', output, options)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|