diplomat-bb 0.2.2
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 +149 -0
- data/features/configuration.feature +9 -0
- data/features/step_definitions/setup_diplomat.rb +22 -0
- data/features/step_definitions/test_key_value.rb +9 -0
- data/lib/diplomat/check.rb +127 -0
- data/lib/diplomat/configuration.rb +18 -0
- data/lib/diplomat/health.rb +101 -0
- data/lib/diplomat/kv.rb +79 -0
- data/lib/diplomat/lock.rb +60 -0
- data/lib/diplomat/members.rb +20 -0
- data/lib/diplomat/rest_client.rb +27 -0
- data/lib/diplomat/service.rb +26 -0
- data/lib/diplomat/session.rb +38 -0
- data/lib/diplomat/version.rb +3 -0
- data/lib/diplomat.rb +40 -0
- metadata +215 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 70431c34cd7188906b4bee0afb835e380a4a5be0
|
4
|
+
data.tar.gz: ea508f7b0801d3183975cc41619f7a420325bc73
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2701f07165a4c5816c751b3c39196b600e0c37ecb71496c8d6030317bbfaabe2baeab7a11815468606d22cc778143db74d3249e7eeff5d6185603eed1b5c5dcc
|
7
|
+
data.tar.gz: 5f66babe29e96e7d982403d84d0ceaa69678a331c1c5cd9aa3bceb3524e71931a65522033fe684d0b03fe6c14581e80bdbfc9cc8b3606f5acec3e5c2992ec419
|
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,149 @@
|
|
1
|
+
# Diplomat
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/diplomat.svg)](http://badge.fury.io/rb/diplomat) [![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.png)](https://codeclimate.com/github/WeAreFarmGeek/diplomat)
|
3
|
+
### A HTTP Ruby API for [Consul](http://www.consul.io/)
|
4
|
+
|
5
|
+
![Diplomacy Boad 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.get('project/db/name') %>
|
27
|
+
pool: 5
|
28
|
+
username: <%= Diplomat.get('project/db/user') %>
|
29
|
+
password: <%= Diplomat.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
|
+
## Usage
|
43
|
+
|
44
|
+
[The most up to date place to read about the API is here.](http://rubydoc.info/github/WeAreFarmGeek/diplomat)
|
45
|
+
|
46
|
+
Here's a few examples of how diplomat works:
|
47
|
+
|
48
|
+
### Key Values
|
49
|
+
|
50
|
+
#### Getting
|
51
|
+
|
52
|
+
Getting the value of a key in the key-value store is as simple as using one of the following:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
foo = Diplomat.get('foo')
|
56
|
+
# => "bar"
|
57
|
+
```
|
58
|
+
|
59
|
+
#### Setting
|
60
|
+
|
61
|
+
Setting the value of a key is just as easy:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
foo = Diplomat.put('foo', 'bar')
|
65
|
+
# => "bar"
|
66
|
+
```
|
67
|
+
|
68
|
+
### Services
|
69
|
+
|
70
|
+
#### Getting
|
71
|
+
|
72
|
+
Looking up a service is easy as pie:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
foo_service = Diplomat::Service.get('foo')
|
76
|
+
# => #<OpenStruct Node="hotel", Address="1.2.3.4", ServiceID="hotel_foo", ServiceName="foo", ServiceTags=["foo"], ServicePort=5432>
|
77
|
+
```
|
78
|
+
Or if you have multiple nodes per service:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
foo_service = Diplomat::Service.get('foo', :all)
|
82
|
+
# => [#<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>]
|
83
|
+
```
|
84
|
+
|
85
|
+
### Sessions
|
86
|
+
|
87
|
+
Creating a session:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
sessionid = Diplomat::Session.create({:hostname => "server1", :ipaddress => "4.4.4.4"})
|
91
|
+
# => "fc5ca01a-c317-39ea-05e8-221da00d3a12"
|
92
|
+
```
|
93
|
+
Or destroying a session:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
Diplomat::Session.destroy("fc5ca01a-c317-39ea-05e8-221da00d3a12")
|
97
|
+
```
|
98
|
+
|
99
|
+
### Locks
|
100
|
+
|
101
|
+
Acquire a lock:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
sessionid = Diplomat::Session.create({:hostname => "server1", :ipaddress => "4.4.4.4"})
|
105
|
+
lock_acquired = Diplomat::Lock.acquire("/key/to/lock", sessionid)
|
106
|
+
# => true
|
107
|
+
```
|
108
|
+
Or wait for a lock to be acquired:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
sessionid = Diplomat::Session.create({:hostname => "server1", :ipaddress => "4.4.4.4"})
|
112
|
+
lock_acquired = Diplomat::Lock.wait_to_acquire("/key/to/lock", sessionid)
|
113
|
+
```
|
114
|
+
|
115
|
+
Releaes a lock:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
Diplomat::Lock.release("/key/to/lock", sessionid )
|
119
|
+
```
|
120
|
+
|
121
|
+
### Custom configuration
|
122
|
+
|
123
|
+
You can create a custom configuration using the following syntax:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
Diplomat.configure do |config|
|
127
|
+
# Set up a custom Consul URL
|
128
|
+
config.url = "localhost:8888"
|
129
|
+
# Set up a custom Faraday Middleware
|
130
|
+
config.middleware = MyCustomMiddleware
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
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).
|
135
|
+
|
136
|
+
### Todo
|
137
|
+
|
138
|
+
- Updating docs with latest changes
|
139
|
+
- PUTting and DELETEing services
|
140
|
+
- Allowing the custom configuration of the consul url to connect to
|
141
|
+
- - ~~Deleting Keys~~ **Needs a test**
|
142
|
+
- ~~Listing available Services~~ **Done**
|
143
|
+
- ~~Health~~ **Done**
|
144
|
+
- ~~Members~~ **Done**
|
145
|
+
- ~~Status~~ **Done**
|
146
|
+
|
147
|
+
## Enjoy!
|
148
|
+
|
149
|
+
![Photo Copyright "merlinmann". All rights reserved.](http://i.imgur.com/3mBwzR9.jpg Photo Copyright "merlinmann" https://www.flickr.com/photos/merlin/. All rights reserved.)
|
@@ -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,22 @@
|
|
1
|
+
require 'diplomat'
|
2
|
+
Given /^I am setting up a default diplomat$/ do
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^I am setting up a custom diplomat$/ do
|
6
|
+
class StubMiddleware
|
7
|
+
def initialize(app, options = {})
|
8
|
+
@app = app
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
def call(env)
|
12
|
+
@app.call(env)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
expect {
|
17
|
+
Diplomat.configure do |config|
|
18
|
+
config.url = "http://localhost:8500"
|
19
|
+
config.middleware = StubMiddleware
|
20
|
+
end
|
21
|
+
}.to_not raise_error
|
22
|
+
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
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module Diplomat
|
5
|
+
class Check < Diplomat::RestClient
|
6
|
+
|
7
|
+
# Get registered checks
|
8
|
+
# @return [OpenStruct] all data associated with the service
|
9
|
+
def checks
|
10
|
+
ret = @conn.get "/v1/agent/checks"
|
11
|
+
return 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 script [String] command to be run for check
|
19
|
+
# @param interval [String] frequency (with units) of the check execution
|
20
|
+
# @param ttl [String] time (with units) to mark a check down
|
21
|
+
# @return [Integer] Status code
|
22
|
+
def register_script check_id, name, notes, script, interval
|
23
|
+
json = JSON.generate(
|
24
|
+
{
|
25
|
+
"ID" => check_id,
|
26
|
+
"Name" => name,
|
27
|
+
"Notes" => notes,
|
28
|
+
"Script" => script,
|
29
|
+
"Interval" => interval
|
30
|
+
}
|
31
|
+
)
|
32
|
+
|
33
|
+
ret = @conn.put do |req|
|
34
|
+
req.url "/v1/agent/check/register"
|
35
|
+
req.body = json
|
36
|
+
end
|
37
|
+
|
38
|
+
return true if ret.status == 200
|
39
|
+
end
|
40
|
+
|
41
|
+
def register_ttl check_id, name, notes, ttl
|
42
|
+
json = JSON.generate(
|
43
|
+
{
|
44
|
+
"ID" => check_id,
|
45
|
+
"Name" => name,
|
46
|
+
"Notes" => notes,
|
47
|
+
"TTL" => ttl,
|
48
|
+
}
|
49
|
+
)
|
50
|
+
|
51
|
+
ret = @conn.put do |req|
|
52
|
+
req.url "/v1/agent/check/register"
|
53
|
+
req.body = json
|
54
|
+
end
|
55
|
+
|
56
|
+
return true if ret.status == 200
|
57
|
+
end
|
58
|
+
|
59
|
+
# Deregister a check
|
60
|
+
# @param check_id [String] the unique id of the check
|
61
|
+
# @return [Integer] Status code
|
62
|
+
def deregister check_id
|
63
|
+
ret = @conn.get "/v1/agent/check/deregister/#{check_id}"
|
64
|
+
return true if ret.status == 200
|
65
|
+
end
|
66
|
+
|
67
|
+
# Pass a check
|
68
|
+
# @param check_id [String] the unique id of the check
|
69
|
+
# @return [Integer] Status code
|
70
|
+
def pass check_id
|
71
|
+
ret = @conn.get "/v1/agent/check/pass/#{check_id}"
|
72
|
+
return true if ret.status == 200
|
73
|
+
end
|
74
|
+
|
75
|
+
# Warn a check
|
76
|
+
# @param check_id [String] the unique id of the check
|
77
|
+
# @return [Integer] Status code
|
78
|
+
def warn check_id
|
79
|
+
ret = @conn.get "/v1/agent/check/warn/#{check_id}"
|
80
|
+
return true if ret.status == 200
|
81
|
+
end
|
82
|
+
|
83
|
+
# Warn a check
|
84
|
+
# @param check_id [String] the unique id of the check
|
85
|
+
# @return [Integer] Status code
|
86
|
+
def fail check_id
|
87
|
+
ret = @conn.get "/v1/agent/check/fail/#{check_id}"
|
88
|
+
return true if ret.status == 200
|
89
|
+
end
|
90
|
+
|
91
|
+
# @note This is sugar, see (#checks)
|
92
|
+
def self.checks
|
93
|
+
Diplomat::Check.new.checks
|
94
|
+
end
|
95
|
+
|
96
|
+
# @note This is sugar, see (#register_script)
|
97
|
+
def self.register_script *args
|
98
|
+
Diplomat::Check.new.register_script *args
|
99
|
+
end
|
100
|
+
|
101
|
+
# @note This is sugar, see (#register_ttl)
|
102
|
+
def self.register_ttl *args
|
103
|
+
Diplomat::Check.new.register_ttl *args
|
104
|
+
end
|
105
|
+
|
106
|
+
# @note This is sugar, see (#deregister)
|
107
|
+
def self.deregister *args
|
108
|
+
Diplomat::Check.new.deregister *args
|
109
|
+
end
|
110
|
+
|
111
|
+
# @note This is sugar, see (#pass)
|
112
|
+
def self.pass *args
|
113
|
+
Diplomat::Check.new.pass *args
|
114
|
+
end
|
115
|
+
|
116
|
+
# @note This is sugar, see (#warn)
|
117
|
+
def self.warn *args
|
118
|
+
Diplomat::Check.new.warn *args
|
119
|
+
end
|
120
|
+
|
121
|
+
# @note This is sugar, see (#fail)
|
122
|
+
def self.fail *args
|
123
|
+
Diplomat::Check.new.fail *args
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Diplomat
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :middleware
|
4
|
+
attr_accessor :url
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@middleware = []
|
8
|
+
@url = "http://localhost:8500"
|
9
|
+
end
|
10
|
+
|
11
|
+
def middleware=(middleware)
|
12
|
+
return @middleware = middleware if middleware.is_a? Array
|
13
|
+
@middleware = [middleware]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module Diplomat
|
5
|
+
class Health < Diplomat::RestClient
|
6
|
+
|
7
|
+
# Get node health
|
8
|
+
# @param n [String] the node
|
9
|
+
# @return [OpenStruct] all data associated with the node
|
10
|
+
def node n
|
11
|
+
ret = @conn.get "/v1/health/node/#{n}"
|
12
|
+
return JSON.parse(ret.body)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Get service checks
|
16
|
+
# @param s [String] the service
|
17
|
+
# @return [OpenStruct] all data associated with the node
|
18
|
+
def checks s
|
19
|
+
ret = @conn.get "/v1/health/checks/#{s}"
|
20
|
+
return JSON.parse(ret.body)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get service health
|
24
|
+
# @param s [String] the service
|
25
|
+
# @return [OpenStruct] all data associated with the node
|
26
|
+
def service s
|
27
|
+
ret = @conn.get "/v1/health/service/#{s}"
|
28
|
+
return JSON.parse(ret.body)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Get service health
|
32
|
+
# @param s [String] the state ("unknown", "passing", "warning", or "critical")
|
33
|
+
# @return [OpenStruct] all data associated with the node
|
34
|
+
def state s
|
35
|
+
ret = @conn.get "/v1/health/state/#{s}"
|
36
|
+
return JSON.parse(ret.body)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Convenience method to get services in unknown state
|
40
|
+
def unknown
|
41
|
+
state("unknown")
|
42
|
+
end
|
43
|
+
|
44
|
+
# Convenience method to get services in passing state
|
45
|
+
def passing
|
46
|
+
state("passing")
|
47
|
+
end
|
48
|
+
|
49
|
+
# Convenience method to get services in warning state
|
50
|
+
def warning
|
51
|
+
state("warning")
|
52
|
+
end
|
53
|
+
|
54
|
+
# Convenience method to get services in critical state
|
55
|
+
def critical
|
56
|
+
state("critical")
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# @note This is sugar, see (#node)
|
61
|
+
def self.node *args
|
62
|
+
Diplomat::Health.new.node *args
|
63
|
+
end
|
64
|
+
|
65
|
+
# @note This is sugar, see (#checks)
|
66
|
+
def self.checks *args
|
67
|
+
Diplomat::Health.new.checks *args
|
68
|
+
end
|
69
|
+
|
70
|
+
# @note This is sugar, see (#service)
|
71
|
+
def self.service *args
|
72
|
+
Diplomat::Health.new.service *args
|
73
|
+
end
|
74
|
+
|
75
|
+
# @note This is sugar, see (#state)
|
76
|
+
def self.state *args
|
77
|
+
Diplomat::Health.new.state *args
|
78
|
+
end
|
79
|
+
|
80
|
+
# @note This is sugar, see (#unknown)
|
81
|
+
def self.unknown
|
82
|
+
Diplomat::Health.new.unknown
|
83
|
+
end
|
84
|
+
|
85
|
+
# @note This is sugar, see (#passing)
|
86
|
+
def self.passing
|
87
|
+
Diplomat::Health.new.passing
|
88
|
+
end
|
89
|
+
|
90
|
+
# @note This is sugar, see (#warning)
|
91
|
+
def self.warning
|
92
|
+
Diplomat::Health.new.warning
|
93
|
+
end
|
94
|
+
|
95
|
+
# @note This is sugar, see (#critical)
|
96
|
+
def self.critical
|
97
|
+
Diplomat::Health.new.critical
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
data/lib/diplomat/kv.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module Diplomat
|
5
|
+
class Kv < Diplomat::RestClient
|
6
|
+
|
7
|
+
attr_reader :key, :value, :raw
|
8
|
+
|
9
|
+
# Get a value by it's key
|
10
|
+
# @param key [String] the key
|
11
|
+
# @return [String] The base64-decoded value associated with the key
|
12
|
+
def get key
|
13
|
+
@key = key
|
14
|
+
@raw = @conn.get "/v1/kv/#{@key}"
|
15
|
+
parse_body
|
16
|
+
return_value
|
17
|
+
end
|
18
|
+
|
19
|
+
# Get a value by it's key
|
20
|
+
# @param key [String] the key
|
21
|
+
# @param value [String] the value
|
22
|
+
# @return [String] The base64-decoded value associated with the key
|
23
|
+
def put key, value
|
24
|
+
@raw = @conn.put do |req|
|
25
|
+
req.url "/v1/kv/#{key}"
|
26
|
+
req.body = value
|
27
|
+
end
|
28
|
+
if @raw.body == "true\n"
|
29
|
+
@key = key
|
30
|
+
@value = value
|
31
|
+
end
|
32
|
+
return @value
|
33
|
+
end
|
34
|
+
|
35
|
+
# Delete a value by it's key
|
36
|
+
# @param key [String] the key
|
37
|
+
# @return [nil]
|
38
|
+
def delete key
|
39
|
+
@key = key
|
40
|
+
@raw = @conn.delete "/v1/kv/#{@key}"
|
41
|
+
return_key
|
42
|
+
return_value
|
43
|
+
end
|
44
|
+
|
45
|
+
# @note This is sugar, see (#get)
|
46
|
+
def self.get *args
|
47
|
+
Diplomat::Kv.new.get *args
|
48
|
+
end
|
49
|
+
|
50
|
+
# @note This is sugar, see (#put)
|
51
|
+
def self.put *args
|
52
|
+
Diplomat::Kv.new.put *args
|
53
|
+
end
|
54
|
+
|
55
|
+
# @note This is sugar, see (#delete)
|
56
|
+
def self.delete *args
|
57
|
+
Diplomat::Kv.new.delete *args
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Parse the body, apply it to the raw attribute
|
63
|
+
def parse_body
|
64
|
+
@raw = JSON.parse(@raw.body).first
|
65
|
+
end
|
66
|
+
|
67
|
+
# Get the key from the raw output
|
68
|
+
def return_key
|
69
|
+
@key = @raw["Key"]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Get the value from the raw output
|
73
|
+
def return_value
|
74
|
+
@value = @raw["Value"]
|
75
|
+
@value = Base64.decode64(@value) unless @value.nil?
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module Diplomat
|
4
|
+
class Lock < Diplomat::RestClient
|
5
|
+
|
6
|
+
# Acquire a lock
|
7
|
+
# @param key [String] the key
|
8
|
+
# @param session [String] the session, generated from Diplomat::Session.create
|
9
|
+
# @return [Boolean] If the lock was acquired
|
10
|
+
def acquire key, session
|
11
|
+
raw = @conn.put do |req|
|
12
|
+
req.url "/v1/kv/#{key}?acquire=#{session}"
|
13
|
+
end
|
14
|
+
return true if raw.body == 'true'
|
15
|
+
return false
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
# wait to aquire a lock
|
20
|
+
# @param key [String] the key
|
21
|
+
# @param session [String] the session, generated from Diplomat::Session.create
|
22
|
+
# @param check_interval [Integer] number of seconds to wait between retries
|
23
|
+
# @return [Boolean] If the lock was acquired
|
24
|
+
def wait_to_acquire key, session, check_interval=10
|
25
|
+
acquired = false
|
26
|
+
while !acquired
|
27
|
+
acquired = self.acquire key, session
|
28
|
+
sleep(check_interval) if !acquired
|
29
|
+
return true if acquired
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Release a lock
|
35
|
+
# @param key [String] the key
|
36
|
+
# @param session [String] the session, generated from Diplomat::Session.create
|
37
|
+
# @return [nil]
|
38
|
+
def release key, session
|
39
|
+
raw = @conn.put do |req|
|
40
|
+
req.url "/v1/kv/#{key}?release=#{session}"
|
41
|
+
end
|
42
|
+
return raw.body
|
43
|
+
end
|
44
|
+
|
45
|
+
# @note This is sugar, see (#acquire)
|
46
|
+
def self.acquire *args
|
47
|
+
Diplomat::Lock.new.acquire *args
|
48
|
+
end
|
49
|
+
|
50
|
+
# @note This is sugar, see (#wait_to_acquire)
|
51
|
+
def self.wait_to_acquire *args
|
52
|
+
Diplomat::Lock.new.wait_to_acquire *args
|
53
|
+
end
|
54
|
+
|
55
|
+
# @note This is sugar, see (#release)
|
56
|
+
def self.release *args
|
57
|
+
Diplomat::Lock.new.release *args
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module Diplomat
|
5
|
+
class Members < Diplomat::RestClient
|
6
|
+
|
7
|
+
# Get all members
|
8
|
+
# @return [OpenStruct] all data associated with the service
|
9
|
+
def get
|
10
|
+
ret = @conn.get "/v1/agent/members"
|
11
|
+
return JSON.parse(ret.body)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @note This is sugar, see (#get)
|
15
|
+
def self.get
|
16
|
+
Diplomat::Members.new.get
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Diplomat
|
5
|
+
class RestClient
|
6
|
+
|
7
|
+
def initialize api_connection=nil
|
8
|
+
start_connection api_connection
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Build the API Client
|
14
|
+
# @param api_connection [Faraday::Connection,nil] supply mock API Connection
|
15
|
+
def start_connection api_connection=nil
|
16
|
+
@conn = api_connection ||= Faraday.new(:url => Diplomat.configuration.url) do |faraday|
|
17
|
+
faraday.request :url_encoded
|
18
|
+
Diplomat.configuration.middleware.each do |middleware|
|
19
|
+
faraday.use middleware
|
20
|
+
end
|
21
|
+
faraday.adapter Faraday.default_adapter
|
22
|
+
faraday.use Faraday::Response::RaiseError
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module Diplomat
|
5
|
+
class Service < Diplomat::RestClient
|
6
|
+
|
7
|
+
# Get a service by it's key
|
8
|
+
# @param key [String] the key
|
9
|
+
# @param scope [Symbol] :first or :all results
|
10
|
+
# @return [OpenStruct] all data associated with the service
|
11
|
+
def get key, scope=:first
|
12
|
+
ret = @conn.get "/v1/catalog/service/#{key}"
|
13
|
+
|
14
|
+
if scope == :all
|
15
|
+
return JSON.parse(ret.body).map { |service| OpenStruct.new service }
|
16
|
+
end
|
17
|
+
return OpenStruct.new JSON.parse(ret.body).first
|
18
|
+
end
|
19
|
+
|
20
|
+
# @note This is sugar, see (#get)
|
21
|
+
def self.get *args
|
22
|
+
Diplomat::Service.new.get *args
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module Diplomat
|
4
|
+
class Session < Diplomat::RestClient
|
5
|
+
|
6
|
+
# Create a new session
|
7
|
+
# @param value [String] json representation of the local node
|
8
|
+
# @return [String] The sesssion id
|
9
|
+
def create value
|
10
|
+
raw = @conn.put do |req|
|
11
|
+
req.url "/v1/session/create"
|
12
|
+
req.body = value
|
13
|
+
end
|
14
|
+
body = JSON.parse(raw.body)
|
15
|
+
return body["ID"]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Destroy a session
|
19
|
+
# @param id [String] session id
|
20
|
+
# @return [nil]
|
21
|
+
def destroy id
|
22
|
+
raw = @conn.put do |req|
|
23
|
+
req.url "/v1/session/destroy/#{id}"
|
24
|
+
end
|
25
|
+
return raw.body
|
26
|
+
end
|
27
|
+
|
28
|
+
# @note This is sugar, see (#create)
|
29
|
+
def self.create *args
|
30
|
+
Diplomat::Session.new.create *args
|
31
|
+
end
|
32
|
+
|
33
|
+
# @note This is sugar, see (#destroy)
|
34
|
+
def self.destroy *args
|
35
|
+
Diplomat::Session.new.destroy *args
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/diplomat.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Diplomat
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
attr_accessor :root_path
|
6
|
+
attr_accessor :lib_path
|
7
|
+
attr_accessor :configuration
|
8
|
+
|
9
|
+
# Internal: Requires internal Faraday libraries.
|
10
|
+
# @param *libs One or more relative String names to Faraday classes.
|
11
|
+
def require_libs(*libs)
|
12
|
+
libs.each do |lib|
|
13
|
+
require "#{lib_path}/#{lib}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
alias require_lib require_libs
|
18
|
+
end
|
19
|
+
|
20
|
+
self.root_path = File.expand_path "..", __FILE__
|
21
|
+
self.lib_path = File.expand_path "../diplomat", __FILE__
|
22
|
+
|
23
|
+
require_libs "configuration", "rest_client", "kv", "service", "members", "check", "health", "session", "lock"
|
24
|
+
self.configuration ||= Diplomat::Configuration.new
|
25
|
+
|
26
|
+
class << self
|
27
|
+
|
28
|
+
# Build optional configuration by yielding a block to configure
|
29
|
+
def configure
|
30
|
+
self.configuration ||= Diplomat::Configuration.new
|
31
|
+
yield(configuration)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def method_missing(name, *args, &block)
|
37
|
+
Diplomat::Kv.new.send(name, *args, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: diplomat-bb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Hamelink
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.9'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.9'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.14'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.14'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: fakes-rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: codeclimate-test-reporter
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.3.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.3.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: fivemat
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: gem-release
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.7'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ~>
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.7'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: cucumber
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ~>
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.3'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.3'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: json
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ~>
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '1.8'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ~>
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '1.8'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: faraday
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ~>
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0.9'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ~>
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0.9'
|
167
|
+
description: Diplomat is a simple wrapper for Consul
|
168
|
+
email:
|
169
|
+
- john@johnhamelink.com
|
170
|
+
executables: []
|
171
|
+
extensions: []
|
172
|
+
extra_rdoc_files: []
|
173
|
+
files:
|
174
|
+
- LICENSE
|
175
|
+
- README.md
|
176
|
+
- features/configuration.feature
|
177
|
+
- features/step_definitions/setup_diplomat.rb
|
178
|
+
- features/step_definitions/test_key_value.rb
|
179
|
+
- lib/diplomat.rb
|
180
|
+
- lib/diplomat/check.rb
|
181
|
+
- lib/diplomat/configuration.rb
|
182
|
+
- lib/diplomat/health.rb
|
183
|
+
- lib/diplomat/kv.rb
|
184
|
+
- lib/diplomat/lock.rb
|
185
|
+
- lib/diplomat/members.rb
|
186
|
+
- lib/diplomat/rest_client.rb
|
187
|
+
- lib/diplomat/service.rb
|
188
|
+
- lib/diplomat/session.rb
|
189
|
+
- lib/diplomat/version.rb
|
190
|
+
homepage: https://github.com/blackboard/diplomat
|
191
|
+
licenses:
|
192
|
+
- BSD
|
193
|
+
metadata: {}
|
194
|
+
post_install_message:
|
195
|
+
rdoc_options: []
|
196
|
+
require_paths:
|
197
|
+
- lib
|
198
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
199
|
+
requirements:
|
200
|
+
- - '>='
|
201
|
+
- !ruby/object:Gem::Version
|
202
|
+
version: '0'
|
203
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
204
|
+
requirements:
|
205
|
+
- - '>='
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: '0'
|
208
|
+
requirements: []
|
209
|
+
rubyforge_project:
|
210
|
+
rubygems_version: 2.0.14
|
211
|
+
signing_key:
|
212
|
+
specification_version: 4
|
213
|
+
summary: Diplomat is a simple wrapper for Consul
|
214
|
+
test_files: []
|
215
|
+
has_rdoc:
|