etcd-tools 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/lib/etcd-tools/cli/etcd2yaml.rb +4 -8
- data/lib/etcd-tools/cli/etcd_erb.rb +4 -5
- data/lib/etcd-tools/cli/yaml2etcd.rb +5 -9
- data/lib/etcd-tools/erb.rb +4 -4
- data/lib/etcd-tools/etcd.rb +10 -35
- data/lib/etcd-tools/mixins/etcd.rb +108 -0
- data/lib/etcd-tools/mixins/hash.rb +6 -0
- data/lib/etcd-tools/mixins.rb +2 -19
- data/lib/etcd-tools.rb +1 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZTY1MTRhNTAzNzM3MjJhOGE4OWQ4NDE3ODlhNjlhMWQ2NTM2ZjY3NA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YTc4M2EzYThmM2E2ZTMwZjFkZDdjYjRjN2YyMjk5ZTU3MDUwZWY0MQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Nzk1YTA0MThlNWM5NjU3ZTkwZDljODVkYzEwNGJkY2RlM2U5N2MzODIxNzIw
|
10
|
+
ZjJmZGY2NTViYjlkZWU2N2ZmMDIyMTQ2OWMzMjAzMTViOTc4ZGRkYjI0YzIz
|
11
|
+
MTFlNGMxYTMxN2NmYjA5Yjg1Zjg4N2EwYWU2ZGMxYzQyZTc4NTM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NmEyM2MyMGQ4NDhhMGYwMWU3YTRjZGUxOGQwYzA0NGFiZTlkNThlNjJjZmEx
|
14
|
+
ZWE0OTRhYmI2YWJmYTA4YWUyN2E1YjkxYTExMTk2ODM3MTIxNmFiMDFlMWZi
|
15
|
+
ZWE5NDk0ZjhmZjcxMTIxMzhlNTgwMGNhM2NkZDIyNjdkNTY4NzU=
|
@@ -11,7 +11,7 @@ module EtcdTools
|
|
11
11
|
@options = Hash.new
|
12
12
|
|
13
13
|
@options[:url] = ENV['ETCDCTL_ENDPOINT']
|
14
|
-
@options[:url] ||= "http://127.0.0.1:
|
14
|
+
@options[:url] ||= "http://127.0.0.1:2379"
|
15
15
|
@options[:root_path] = "/config"
|
16
16
|
|
17
17
|
OptionParser.new do |opts|
|
@@ -26,9 +26,6 @@ module EtcdTools
|
|
26
26
|
opts.on("-r", "--root-path PATH", "root PATH of ETCD tree to extract the data from [DEFAULT: /config]") do |param|
|
27
27
|
@options[:root_path] = param
|
28
28
|
end
|
29
|
-
opts.on("-v", "--verbose", "run verbosely") do |param|
|
30
|
-
@options[:verbose] = param
|
31
|
-
end
|
32
29
|
opts.on_tail("-h", "--help", "show usage") do |param|
|
33
30
|
puts opts;
|
34
31
|
exit! 0
|
@@ -41,14 +38,13 @@ module EtcdTools
|
|
41
38
|
|
42
39
|
begin
|
43
40
|
@etcd = etcd_connect @options[:url]
|
44
|
-
rescue
|
45
|
-
$stderr.puts "Failed to connect to ETCD
|
46
|
-
$stderr.puts e.message
|
41
|
+
rescue EtcdTools::ClusterConnectError
|
42
|
+
$stderr.puts "Failed to connect to ETCD cluster"
|
47
43
|
exit! 1
|
48
44
|
end
|
49
45
|
|
50
46
|
begin
|
51
|
-
hash =
|
47
|
+
hash = @etcd.get_hash @options[:root_path]
|
52
48
|
puts YAML.dump hash
|
53
49
|
rescue Exception => e
|
54
50
|
$stderr.puts "Import failed"
|
@@ -11,13 +11,13 @@ module EtcdTools
|
|
11
11
|
@options = Hash.new
|
12
12
|
|
13
13
|
@options[:url] = ENV['ETCDCTL_ENDPOINT']
|
14
|
-
@options[:url] ||= "http://127.0.0.1:
|
14
|
+
@options[:url] ||= "http://127.0.0.1:2379"
|
15
15
|
|
16
16
|
OptionParser.new do |opts|
|
17
17
|
opts.banner = "Applies variables from ETCD onto ERB template\n\nUsage: #{$0} [OPTIONS] < template.erb > outfile"
|
18
18
|
opts.separator ""
|
19
19
|
opts.separator "Connection options:"
|
20
|
-
opts.on("-u", "--url URL", "URL endpoint of the ETCD service (ETCDCTL_ENDPOINT envvar also applies) [DEFAULT: http://127.0.0.1:
|
20
|
+
opts.on("-u", "--url URL", "URL endpoint of the ETCD service (ETCDCTL_ENDPOINT envvar also applies) [DEFAULT: http://127.0.0.1:2379]") do |param|
|
21
21
|
@options[:url] = param
|
22
22
|
end
|
23
23
|
opts.separator ""
|
@@ -34,9 +34,8 @@ module EtcdTools
|
|
34
34
|
|
35
35
|
begin
|
36
36
|
@etcd = etcd_connect @options[:url]
|
37
|
-
rescue
|
38
|
-
$stderr.puts "Failed to connect to ETCD
|
39
|
-
$stderr.puts e.message
|
37
|
+
rescue EtcdTools::ClusterConnectError
|
38
|
+
$stderr.puts "Failed to connect to ETCD cluster"
|
40
39
|
exit! 1
|
41
40
|
end
|
42
41
|
|
@@ -11,7 +11,7 @@ module EtcdTools
|
|
11
11
|
@options = Hash.new
|
12
12
|
|
13
13
|
@options[:url] = ENV['ETCDCTL_ENDPOINT']
|
14
|
-
@options[:url] ||= "http://127.0.0.1:
|
14
|
+
@options[:url] ||= "http://127.0.0.1:2379"
|
15
15
|
@options[:root_path] = "/config"
|
16
16
|
|
17
17
|
OptionParser.new do |opts|
|
@@ -26,9 +26,6 @@ module EtcdTools
|
|
26
26
|
opts.on("-r", "--root-path PATH", "root PATH of ETCD tree to inject the data [DEFAULT: /config]") do |param|
|
27
27
|
@options[:root_path] = param
|
28
28
|
end
|
29
|
-
opts.on("-v", "--verbose", "run verbosely") do |param|
|
30
|
-
@options[:verbose] = param
|
31
|
-
end
|
32
29
|
opts.on_tail("-h", "--help", "show usage") do |param|
|
33
30
|
puts opts;
|
34
31
|
exit! 0
|
@@ -49,20 +46,19 @@ module EtcdTools
|
|
49
46
|
|
50
47
|
begin
|
51
48
|
@etcd = etcd_connect @options[:url]
|
52
|
-
rescue
|
53
|
-
$stderr.puts "Failed to connect to ETCD
|
54
|
-
$stderr.puts e.message
|
49
|
+
rescue EtcdTools::ClusterConnectError
|
50
|
+
$stderr.puts "Failed to connect to ETCD cluster"
|
55
51
|
exit! 1
|
56
52
|
end
|
57
53
|
|
58
54
|
begin
|
59
|
-
|
60
|
-
puts "OK"
|
55
|
+
@etcd.set_hash(@hash, @options[:root_path])
|
61
56
|
rescue Exception => e
|
62
57
|
$stderr.puts "Import failed"
|
63
58
|
$stderr.puts e.message
|
64
59
|
exit! 1
|
65
60
|
end
|
61
|
+
puts "OK"
|
66
62
|
end
|
67
63
|
|
68
64
|
end
|
data/lib/etcd-tools/erb.rb
CHANGED
@@ -25,20 +25,20 @@ module EtcdTools
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def value path
|
28
|
-
@etcd.get('/' + path.sub(
|
28
|
+
@etcd.get('/' + path.sub(%r{^/+}, '')).value
|
29
29
|
end
|
30
30
|
|
31
31
|
def keys path
|
32
|
-
path.sub!(
|
32
|
+
path.sub!(%r{^/+}, '')
|
33
33
|
if @etcd.get('/' + path).directory?
|
34
|
-
return @etcd.get('/' + path).children.map
|
34
|
+
return @etcd.get('/' + path).children.map(&:key)
|
35
35
|
else
|
36
36
|
return []
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
def hash path
|
41
|
-
|
41
|
+
@etcd.get_hash path
|
42
42
|
rescue
|
43
43
|
{}
|
44
44
|
end
|
data/lib/etcd-tools/etcd.rb
CHANGED
@@ -2,44 +2,19 @@ require 'etcd'
|
|
2
2
|
require 'etcd-tools/mixins'
|
3
3
|
|
4
4
|
module EtcdTools
|
5
|
+
class ClusterConnectError < Exception
|
6
|
+
end
|
7
|
+
|
5
8
|
module Etcd
|
6
|
-
def etcd_connect(url)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
etcd.
|
9
|
+
def etcd_connect(url, timeout = 2)
|
10
|
+
url = url.split(',')
|
11
|
+
url.each do |u|
|
12
|
+
(host, port) = u.gsub(/^https?:\/\//, '').gsub(/\/$/, '').split(':')
|
13
|
+
etcd = ::Etcd.client(host: host, port: port, read_timeout: timeout)
|
14
|
+
next unless etcd.healthy?
|
11
15
|
return etcd
|
12
|
-
rescue Exception => e
|
13
|
-
raise e #fixme
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def hash2etcd(etcd, hash, path = '')
|
18
|
-
hash.each do |key, value|
|
19
|
-
path = "" if path == '/'
|
20
|
-
etcd_key = path + '/' + key.to_s
|
21
|
-
if value.class == Hash
|
22
|
-
hash2etcd(etcd, value, etcd_key)
|
23
|
-
else
|
24
|
-
etcd.set(etcd_key, value: value)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
rescue Exception => e
|
28
|
-
raise e #fixme
|
29
|
-
end
|
30
|
-
|
31
|
-
def etcd2hash(etcd, path = '')
|
32
|
-
h = {}
|
33
|
-
etcd.get(path).children.each do |child|
|
34
|
-
if etcd.get(child.key).directory?
|
35
|
-
h[child.key.split('/').last.to_s] = etcd2hash etcd, child.key
|
36
|
-
else
|
37
|
-
h[child.key.split('/').last.to_s] = child.value
|
38
|
-
end
|
39
16
|
end
|
40
|
-
|
41
|
-
rescue Exception => e
|
42
|
-
return nil
|
17
|
+
raise EtcdTools::ClusterConnectError
|
43
18
|
end
|
44
19
|
end
|
45
20
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'etcd'
|
2
|
+
require 'etcd/client'
|
3
|
+
|
4
|
+
module Etcd
|
5
|
+
class Client
|
6
|
+
|
7
|
+
attr_reader :cluster
|
8
|
+
|
9
|
+
def initialize(opts = {})
|
10
|
+
@cluster = opts[:cluster] || [{ host: '127.0.0.1', port: 2379 }]
|
11
|
+
if !opts[:host].nil? || !opts[:port].nil?
|
12
|
+
@cluster = [{ host: opts[:host], port: opts[:port] }]
|
13
|
+
end
|
14
|
+
@config = Config.new
|
15
|
+
@config.read_timeout = opts[:read_timeout] || 10
|
16
|
+
@config.use_ssl = opts[:use_ssl] || false
|
17
|
+
@config.verify_mode = opts.key?(:verify_mode) ? opts[:verify_mode] : OpenSSL::SSL::VERIFY_PEER
|
18
|
+
@config.user_name = opts[:user_name] || nil
|
19
|
+
@config.password = opts[:password] || nil
|
20
|
+
@config.ca_file = opts.key?(:ca_file) ? opts[:ca_file] : nil
|
21
|
+
@config.ssl_cert = opts.key?(:ssl_cert) ? opts[:ssl_cert] : nil
|
22
|
+
@config.ssl_key = opts.key?(:ssl_key) ? opts[:ssl_key] : nil
|
23
|
+
yield @config if block_given?
|
24
|
+
end
|
25
|
+
|
26
|
+
def api_execute(path, method, options = {})
|
27
|
+
params = options[:params]
|
28
|
+
case method
|
29
|
+
when :get
|
30
|
+
req = build_http_request(Net::HTTP::Get, path, params)
|
31
|
+
when :post
|
32
|
+
req = build_http_request(Net::HTTP::Post, path, nil, params)
|
33
|
+
when :put
|
34
|
+
req = build_http_request(Net::HTTP::Put, path, nil, params)
|
35
|
+
when :delete
|
36
|
+
req = build_http_request(Net::HTTP::Delete, path, params)
|
37
|
+
else
|
38
|
+
fail "Unknown http action: #{method}"
|
39
|
+
end
|
40
|
+
req.basic_auth(user_name, password) if [user_name, password].all?
|
41
|
+
cluster_http_request(req, options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def cluster_http_request(req, options={})
|
45
|
+
cluster.each do |member|
|
46
|
+
http = build_http_object(member[:host], member[:port], options)
|
47
|
+
begin
|
48
|
+
Log.debug("Invoking: '#{req.class}' against '#{member[:host]}:#{member[:port]}' -> '#{req.path}'")
|
49
|
+
res = http.request(req)
|
50
|
+
Log.debug("Response code: #{res.code}")
|
51
|
+
Log.debug("Response body: #{res.body}")
|
52
|
+
return process_http_request(res)
|
53
|
+
rescue Timeout::Error
|
54
|
+
Log.debug("Timeout")
|
55
|
+
next
|
56
|
+
end
|
57
|
+
fail
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_http_object(host, port, options={})
|
62
|
+
http = Net::HTTP.new(host, port)
|
63
|
+
http.read_timeout = options[:timeout] || read_timeout
|
64
|
+
http.open_timeout = options[:timeout] || read_timeout # <- can't modify Config constant with specific option
|
65
|
+
setup_https(http)
|
66
|
+
http
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_hash(hash, path = '')
|
70
|
+
hash.each do |key, value|
|
71
|
+
path = "" if path == '/'
|
72
|
+
etcd_key = path + '/' + key.to_s
|
73
|
+
if value.class == Hash
|
74
|
+
set_hash(value, etcd_key)
|
75
|
+
else
|
76
|
+
set(etcd_key, value: value)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
rescue Exception => e
|
80
|
+
raise e #fixme
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_hash(path = '')
|
84
|
+
h = {}
|
85
|
+
get(path).children.each do |child|
|
86
|
+
if get(child.key).directory?
|
87
|
+
h[child.key.split('/').last.to_s] = get_hash child.key
|
88
|
+
else
|
89
|
+
h[child.key.split('/').last.to_s] = child.value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return Hash[h.sort]
|
93
|
+
rescue Exception => e
|
94
|
+
raise e
|
95
|
+
end
|
96
|
+
|
97
|
+
def members
|
98
|
+
members = JSON.parse(api_execute(version_prefix + '/members', :get).body)['members']
|
99
|
+
Hash[members.map{|member| [ member['id'], member.tap { |h| h.delete('id') }]}]
|
100
|
+
end
|
101
|
+
|
102
|
+
def healthy?
|
103
|
+
JSON.parse(api_execute('/health', :get).body)['health'] == 'true'
|
104
|
+
rescue
|
105
|
+
false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/etcd-tools/mixins.rb
CHANGED
@@ -1,19 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
4
|
-
self.merge(second, &merger)
|
5
|
-
end
|
6
|
-
end
|
7
|
-
|
8
|
-
module Etcd
|
9
|
-
class Client
|
10
|
-
def members
|
11
|
-
members = JSON.parse(api_execute(version_prefix + '/members', :get, timeout: 10).body)['members']
|
12
|
-
Hash[members.map{|member| [ member['id'], member.tap { |h| h.delete('id') }]}]
|
13
|
-
end
|
14
|
-
|
15
|
-
def healthy?
|
16
|
-
JSON.parse(api_execute('/health', :get, timeout: 3).body)['health'] == 'true'
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
1
|
+
require 'etcd-tools/mixins/hash.rb'
|
2
|
+
require 'etcd-tools/mixins/etcd.rb'
|
data/lib/etcd-tools.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: etcd-tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Radek 'blufor' Slavicinsky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: etcd
|
@@ -30,12 +30,12 @@ dependencies:
|
|
30
30
|
- - ! '>='
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 0.3.0
|
33
|
-
description: A set of handful command-line utils for ETCD
|
33
|
+
description: A set of handful command-line utils for ETCD + lib extensions
|
34
34
|
email: radek.slavicinsky@gmail.com
|
35
35
|
executables:
|
36
|
+
- etcd2yaml
|
36
37
|
- etcd-erb
|
37
38
|
- yaml2etcd
|
38
|
-
- etcd2yaml
|
39
39
|
extensions: []
|
40
40
|
extra_rdoc_files: []
|
41
41
|
files:
|
@@ -49,6 +49,8 @@ files:
|
|
49
49
|
- lib/etcd-tools/erb.rb
|
50
50
|
- lib/etcd-tools/etcd.rb
|
51
51
|
- lib/etcd-tools/mixins.rb
|
52
|
+
- lib/etcd-tools/mixins/etcd.rb
|
53
|
+
- lib/etcd-tools/mixins/hash.rb
|
52
54
|
homepage: https://github.com/blufor/etcd-tools
|
53
55
|
licenses:
|
54
56
|
- GPLv2
|