Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

# Next

- 2018-01-26 Nate St. Germain (@rockpapergoat) Add option to search all nodes by metadata
Pass a `:meta` hash as an option to `Diplomat::Node.get_all` to filter on metadata.

- 2017-11-09 Josep M. Blanquer (@blanquer) Fix service deregister to use the proper verb (`PUT` instead of `GET`). Consul 1.x seems to
have started enforcing [it](https://www.consul.io/docs/upgrade-specific.html#http-verbs-are-enforced-in-many-http-apis).

Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ Get all nodes for a particular datacenter
nodes = Diplomat::Node.get_all({ :dc => 'My_Datacenter' })
# => [#<OpenStruct Address="10.1.10.12", Node="foo">, #<OpenStruct Address="10.1.10.13", Node="bar">]
```
Get all nodes with specified metadata

NOTE: This requires adding metadata to nodes, either as part of the agent config or via the catalog. Adding multiple metadata attributes effectively is an `AND` operation here.

```ruby
nodes = Diplomat::Node.get_all({ :meta => {'role' => 'server', 'availability_zone' => 'us-east-1d'})
# => [#<OpenStruct Node="i-003b17883f403eda5", Address="10.10.10.210", Datacenter="dev", TaggedAddresses={"lan"=>"10.10.10.210", "wan"=>"10.10.10.210"}, Meta={"availability_zone"=>"us-east-1d", "consul-network-segment"=>"", "environment"=>"dev", "instance_type"=>"t2.small", "ip"=>"10.10.10.210", "lsb_release"=>"16.04", "role"=>"server", "tags"=>""}>]
```

Register a node:

Expand Down Expand Up @@ -180,6 +188,14 @@ services = Diplomat::Service.get_all({ :dc => 'My_Datacenter' })
# => #<OpenStruct consul=[], foo=[], bar=[]>
```

To list all the services associated with specific node metadata:

```ruby
services = Diplomat::Service.get_all({ :meta => {'lsb_release' => '16.04', 'availability_zone' => 'us-east-1a'} })
# => #<OpenStruct consul=[], web=["dev", "testing", "nginx"]>
```


### Datacenters

Getting a list of datacenters is quite simple and gives you the option to extract all services out of
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ end

desc 'Run a bootstrapped consul server for testing'
task :consul do
system('consul agent -server -bootstrap -data-dir=/tmp')
system('consul agent -dev -bootstrap -data-dir=/tmp')
end

task default: %w[style spec]
2 changes: 1 addition & 1 deletion lib/diplomat/kv.rb
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def decode_transaction(transaction) # rubocop:disable Metrics/MethodLength
next unless resp['KV']['Value']
begin
resp['KV']['Value'] = Base64.decode64(resp['KV']['Value'])
rescue # rubocop:disable RescueWithoutErrorClass
rescue StandardError
nil
end
end
Expand Down
12 changes: 9 additions & 3 deletions lib/diplomat/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Node < Diplomat::RestClient

@access_methods = %i[get get_all register deregister]

# Get a node by it's key
# Get a node by its key
# @param key [String] the key
# @param options [Hash] :dc string for dc specific query
# @return [OpenStruct] all data associated with the node
Expand All @@ -23,11 +23,17 @@ def get(key, options = nil)
end

# Get all the nodes
# @param options [Hash] :dc string for dc specific query
# @param options [Hash]
# :dc string for dc specific query
# :meta hash for metadata query
# @return [OpenStruct] the list of all nodes
def get_all(options = nil)
def get_all(options = nil) # rubocop:disable Metrics/AbcSize
url = ['/v1/catalog/nodes']
url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
if options && options[:meta]
url << options[:meta].map { |m| use_named_parameter('node-meta', m.join(':')) }.flatten
Diplomat.configure { |c| c.options = { request: { params_encoder: Faraday::FlatParamsEncoder } } }
end

ret = @conn.get concat_url url
JSON.parse(ret.body).map { |service| OpenStruct.new service }
Expand Down
4 changes: 2 additions & 2 deletions lib/diplomat/rest_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Diplomat
class RestClient
@access_methods = []

# Initialize the fadaray connection
# Initialize the faraday connection
# @param api_connection [Faraday::Connection,nil] supply mock API Connection
def initialize(api_connection = nil)
start_connection api_connection
Expand Down Expand Up @@ -143,7 +143,7 @@ def decode_values
@raw.each_with_object([]) do |acc, el|
begin
acc['Value'] = Base64.decode64(acc['Value'])
rescue # rubocop:disable RescueWithoutErrorClass
rescue StandardError
nil
end
el << acc
Expand Down
12 changes: 9 additions & 3 deletions lib/diplomat/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Service < Diplomat::RestClient

@access_methods = %i[get get_all register deregister register_external deregister_external maintenance]

# Get a service by it's key
# Get a service by its key
# @param key [String] the key
# @param scope [Symbol] :first or :all results
# @param options [Hash] options parameter hash
Expand Down Expand Up @@ -47,12 +47,18 @@ def get(key, scope = :first, options = nil, meta = nil)
# rubocop:enable PerceivedComplexity, MethodLength, CyclomaticComplexity, AbcSize

# Get all the services
# @param options [Hash] :dc Consul datacenter to query
# @param options [Hash]
# :dc Consul datacenter to query
# :meta hash for metadata query
# @return [OpenStruct] the list of all services
def get_all(options = nil)
def get_all(options = nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
url = ['/v1/catalog/services']
url += check_acl_token
url << use_named_parameter('dc', options[:dc]) if options && options[:dc]
if options && options[:meta]
url << options[:meta].map { |m| use_named_parameter('node-meta', m.join(':')) }
Diplomat.configure { |c| c.options = { request: { params_encoder: Faraday::FlatParamsEncoder } } }
end
begin
ret = @conn.get concat_url url
rescue Faraday::ClientError
Expand Down
2 changes: 1 addition & 1 deletion lib/diplomat/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Diplomat
VERSION = '2.0.2'.freeze
VERSION = '2.0.3'.freeze
end
40 changes: 40 additions & 0 deletions spec/node_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@
}
]
end
let(:body_all_with_meta) do
[
{
'Address' => '10.1.10.12',
'Node' => 'foo',
'Meta' => {
'role' => 'redis',
'az' => 'us-east-1a'
}
},
{
'Address' => '10.1.10.13',
'Node' => 'bar',
'Meta' => {
'role' => 'redis',
'az' => 'us-east-1a'
}
}
]
end
let(:body) do
{
'Node' => {
Expand All @@ -83,6 +103,7 @@
}
end
let(:all_with_dc_url) { '/v1/catalog/nodes?dc=dc1' }
let(:all_with_meta_url) { '/v1/catalog/nodes?node-meta=az:us-east-1a&node-meta=role:redis' }
let(:body_all_with_dc) do
[
{
Expand Down Expand Up @@ -112,6 +133,25 @@
end
end

describe 'GET ALL WITH METADATA' do
it 'lists all the nodes with specified metadata' do
json = JSON.generate(body_all_with_meta)

faraday.stub(:get).with(all_with_meta_url).and_return(OpenStruct.new(body: json))

node = Diplomat::Node.new(faraday)
expect(node.get_all(meta: { az: 'us-east-1a', role: 'redis' }).size).to eq(2)
end

it 'lists all the nodes' do
json = JSON.generate(body_all_with_dc)

faraday.stub(:get).with(all_with_dc_url).and_return(OpenStruct.new(body: json))

node = Diplomat::Node.new(faraday)
expect(node.get_all(dc: 'dc1').size).to eq(1)
end
end
describe 'GET' do
let(:cn) do
json = JSON.generate(body)
Expand Down
21 changes: 21 additions & 0 deletions spec/service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@
let(:key_url_with_datacenteroption) { "/v1/catalog/service/#{key}?dc=somedc" }
let(:key_url_with_tagoption) { "/v1/catalog/service/#{key}?tag=sometag" }
let(:services_url_with_datacenteroption) { '/v1/catalog/services?dc=somedc' }
let(:services_url_with_metadata_option) { '/v1/catalog/services?node-meta=lsb_release:16.04&node-meta=availability_zone:us-east-1a' } # rubocop:disable Metrics/LineLength
let(:body) do
[
{
'Node' => 'foo',
'Address' => '10.1.10.12',
'NodeMeta' => {
'lsb_release' => '16.04',
'availability_zone' => 'us-east-1a'
},
'ServiceID' => key,
'ServiceName' => key,
'ServiceTags' => ['sometag'],
Expand All @@ -25,6 +30,10 @@
{
'Node' => 'bar',
'Address' => '10.1.10.13',
'NodeMeta' => {
'lsb_release' => '16.04',
'availability_zone' => 'us-east-1a'
},
'ServiceID' => key,
'ServiceName' => key,
'ServiceTags' => %w[sometag anothertag],
Expand Down Expand Up @@ -202,6 +211,18 @@
expect(service.get_all(options).service1.first).to eq(service_one_tag)
expect(service.get_all(options).service2.first).to eq(service_two_tag)
end
it 'lists all the services for the specified metadata' do
json = JSON.generate(body_all)

faraday.stub(:get).with(services_url_with_metadata_option).and_return(OpenStruct.new(body: json))

options = { meta: { lsb_release: '16.04', availability_zone: 'us-east-1a' } }
service = Diplomat::Service.new(faraday)
expect(service.get_all(options).service1).to be_an(Array)
expect(service.get_all(options).service2).to be_an(Array)
expect(service.get_all(options).service1.first).to eq(service_one_tag)
expect(service.get_all(options).service2.first).to eq(service_two_tag)
end
end

describe 'Register service' do
Expand Down