etcd-tools 0.1.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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTdmMmY3NWMyMmE3NWEyYThiM2RkZDQ1YTkwMTY2MmNhOTM2NzEyMg==
5
+ data.tar.gz: !binary |-
6
+ ZGQyZWVjNzY1YTU1YTJjMDY4MGIyMGE2MTU5MmJiNzJkYzU0MDc0Mw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MjI4ZGQ2ZDFkZmZiMTIxMjg1ZGUzOTI0YWY3NDg4YTFlYTZhYWZhZThhYTM3
10
+ MTk3NGFmYjM1MjViZGY1MmNkOGQwY2Y2ZGYzZjQxOWUwNzhjYTYyODU3ZWM3
11
+ MTI4ZWIxMDA0ZjQ2NDc2ZDFmNDFiYTRhNGM3MjcyNjI1YmY5ODU=
12
+ data.tar.gz: !binary |-
13
+ NDZhZDc3ZjU1OWZiODM3ODQ2ODMxMWU5YTllMWM2ZWJmYjVkYjBmZGYzNTI5
14
+ NmVmY2NiNjY0ZTA5N2I3MzE1NWFmYzY4MTIzMTc3Njc1MGJlYmQwMWE5Y2Fl
15
+ YjY2YTRkOGJhNGZkNjVjOTk0MjdjYmU4NTM1MWY3OTg4ZmVjMTE=
data/bin/etcd-erb ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'etcd-tools/etcd_erb'
3
+ EtcdTools::EtcdERB.new
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'etcd-tools/etcd_watchdog_haproxy'
3
+ app = EtcdTools::Watchdog::HAproxy.new
4
+ app.run
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'etcd-tools/etcd_watchdog_vip'
3
+ app = EtcdTools::VipWatchdog.new
4
+ app.run
data/bin/yaml2etcd ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'etcd-tools/yaml2etcd'
3
+ EtcdTools::Yaml2Etcd.new
@@ -0,0 +1,26 @@
1
+ module EtcdTools
2
+ module EtcdERB
3
+ module Erb
4
+ def result
5
+ super binding
6
+ end
7
+
8
+ def value path
9
+ return @etcd.get('/' + path.sub(/^\//, '')).value
10
+ end
11
+
12
+ def keys path
13
+ path.sub!(/^\//, '')
14
+ if @etcd.get('/' + path).directory?
15
+ return @etcd.get('/' + path).children.map { |key| key.key }
16
+ else
17
+ return []
18
+ end
19
+ end
20
+
21
+ def template
22
+ ARGF.read
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,29 @@
1
+ require 'optparse'
2
+
3
+ module EtcdTools
4
+ module EtcdERB
5
+ module Options
6
+ def optparse
7
+ @options = Hash.new
8
+
9
+ @options[:url] = ENV['ETCDCTL_ENDPOINT']
10
+ @options[:url] ||= "http://127.0.0.1:4001"
11
+
12
+ OptionParser.new do |opts|
13
+ opts.banner = "Applies variables from ETCD onto ERB template\n\nUsage: #{$0} [OPTIONS] < template.erb > outfile"
14
+ opts.separator ""
15
+ opts.separator "Connection options:"
16
+ opts.on("-u", "--url URL", "URL endpoint of the ETCD service (ETCDCTL_ENDPOINT envvar also applies) [DEFAULT: http://127.0.0.1:4001]") do |param|
17
+ @options[:url] = param
18
+ end
19
+ opts.separator ""
20
+ opts.separator "Common options:"
21
+ opts.on_tail("-h", "--help", "show usage") do |param|
22
+ puts opts
23
+ exit! 0
24
+ end
25
+ end.parse!
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,38 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+ require 'etcd'
4
+ require 'etcd-tools/etcd_erb/options'
5
+ require 'etcd-tools/etcd_erb/erb'
6
+
7
+ module EtcdTools
8
+ class EtcdERB < ERB
9
+
10
+ include EtcdTools::EtcdERB::Options
11
+ include EtcdTools::EtcdERB::Erb
12
+
13
+ attr_reader :etcd
14
+
15
+ def initialize
16
+ self.optparse
17
+ @etcd = self.class.connect(@options[:url])
18
+ super self.class.template
19
+ puts self.result
20
+ end
21
+
22
+ class << self
23
+ def connect (url)
24
+ (host, port) = url.gsub(/^https?:\/\//, '').gsub(/\/$/, '').split(':')
25
+ etcd = Etcd.client(host: host, port: port)
26
+ begin
27
+ etcd.version
28
+ return etcd
29
+ rescue Exception => e
30
+ $stderr.puts "Couldn't connect to etcd at #{host}:#{port}"
31
+ $stderr.puts e.message
32
+ exit! 1
33
+ end
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'net/ping'
4
+
5
+ module EtcdTools
6
+ module Watchdog
7
+ class HAproxy < EtcdTools::Watchdog::Init
8
+
9
+ include EtcdTools::Watchdog::HAproxy
10
+
11
+ def run
12
+ @thread = {
13
+ etcd: thread_etcd
14
+ }
15
+ @status_etcd = false
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'net/ping'
4
+ require 'etcd-tools/watchdog/init'
5
+ require 'etcd-tools/watchdog/vip'
6
+ require 'etcd-tools/watchdog/threads/icmp'
7
+
8
+ module EtcdTools
9
+ class VipWatchdog < EtcdTools::Watchdog::Init
10
+
11
+ include EtcdTools::Watchdog::Vip
12
+
13
+ def run
14
+ if Process.euid != 0
15
+ err 'Must run under root user!'
16
+ exit! 1
17
+ end
18
+ @semaphore.merge!({ icmp: Mutex.new })
19
+ @thread = { icmp: thread_icmp, etcd: thread_etcd }
20
+ @status_etcd = false
21
+ @status_icmp = false
22
+ @thread.each_value(&:run)
23
+ # sleep 5
24
+ first_cycle = true
25
+ while !@exit do
26
+ status_etcd = status_icmp = false # FIXME: introduce CVs...
27
+ @semaphore[:icmp].synchronize { status_icmp = @status_icmp }
28
+ @semaphore[:etcd].synchronize { status_etcd = @status_etcd }
29
+ if status_etcd
30
+ if got_vip?
31
+ debug '<main> i am the leader with VIP, that is OK'
32
+ else
33
+ info '<main> i am the leader without VIP, checking whether it is free'
34
+ if status_icmp
35
+ info '<main> VIP is still up! (ICMP)'
36
+ # FIXME: notify by sensu client socket
37
+ else
38
+ info '<main> VIP is unreachable by ICMP, checking for duplicates on L2'
39
+ if vip_dup?
40
+ info '<main> VIP is still assigned! (ARP)'
41
+ # FIXME: notify by sensu client socket
42
+ else
43
+ info '<main> VIP is free, assigning'
44
+ vip_handle! status_etcd
45
+ info '<main> updating other hosts about change'
46
+ vip_update_arp!
47
+ end
48
+ end
49
+ end
50
+ else
51
+ if got_vip?
52
+ info '<main> i got VIP and should not, removing'
53
+ vip_handle! status_etcd
54
+ info '<main> updating other hosts about change'
55
+ vip_update_arp!
56
+ else
57
+ debug '<main> i am not a leader and i do not have the VIP, that is OK'
58
+ end
59
+ end
60
+ sleep @config[:parameters][:interval]
61
+ if first_cycle
62
+ @semaphore[:icmp].synchronize { status_icmp = @status_icmp }
63
+ @semaphore[:etcd].synchronize { status_etcd = @status_etcd }
64
+ info "<main> i #{status_etcd ? 'AM' : 'am NOT'} the leader"
65
+ info "<main> i #{got_vip? ? 'DO' : 'do NOT'} have the VIP"
66
+ info "<main> i #{status_icmp ? 'CAN' : 'CANNOT'} see the VIP"
67
+ end
68
+ first_cycle = false
69
+ end
70
+ info '<main> terminated!'
71
+ if got_vip?
72
+ info '<main> removing VIP'
73
+ vip_handle! false
74
+ vip_update_arp!
75
+ end
76
+ info '<main> stopping threads...'
77
+ @thread.each_value(&:join)
78
+ info '<main> exiting...'
79
+ exit 0
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,19 @@
1
+ class Hash
2
+ def deep_merge(second)
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
@@ -0,0 +1,38 @@
1
+ module EtcdTools
2
+ module Watchdog
3
+ module Config
4
+ private
5
+ def default_config
6
+ { debug: false,
7
+ parameters: { interface: 'eth0',
8
+ vip: '192.168.0.168',
9
+ mask: '255.255.255.0',
10
+ interval: 1,
11
+ etcd_endpoint: 'http://127.0.0.1:4001',
12
+ etcd_interval: 1,
13
+ etcd_timeout: 5,
14
+ icmp_count: 2,
15
+ icmp_interval: 1,
16
+ arping_count: 1,
17
+ arping_wait: 1 },
18
+ commands: { arping: `which arping`.chomp,
19
+ iproute: `which ip`.chomp,
20
+ arp: `which arp`.chomp } }
21
+ end
22
+
23
+ def config
24
+ cfg = default_config
25
+ if File.exist? '/etc/etcd-watchdog.yaml'
26
+ cfg = cfg.deep_merge YAML.load_file('/etc/etcd-watchdog.yaml')
27
+ info '<main> loaded config from /etc/etcd-watchdog.yaml'
28
+ elsif File.exist? './etcd-watchdog.yaml'
29
+ cfg = cfg.deep_merge YAML.load_file('./etcd-watchdog.yaml')
30
+ info '<main> loaded config from ./etcd-watchdog.yaml'
31
+ else
32
+ info '<main> no config file loaded, using defaults'
33
+ end
34
+ cfg
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ module EtcdTools
2
+ module Watchdog
3
+ module Etcd
4
+ # connect to ETCD
5
+ def etcd_connect!
6
+ (host, port) = @config[:parameters][:etcd_endpoint].gsub(/^https?:\/\//, '').gsub(/\/$/, '').split(':')
7
+ etcd = ::Etcd.client(host: host, port: port)
8
+ begin
9
+ versions = JSON.parse(etcd.version)
10
+ info "<etcd> conncted to ETCD at #{@config[:parameters][:etcd_endpoint]}"
11
+ info "<etcd> server version: #{versions['etcdserver']}"
12
+ info "<etcd> cluster version: #{versions['etcdcluster']}"
13
+ info "<etcd> healthy: #{etcd.healthy?}"
14
+ return etcd
15
+ rescue Exception => e
16
+ err "<etcd> couldn't connect to etcd at #{host}:#{port}"
17
+ err "<etcd> #{e.message}"
18
+ @exit = true
19
+ end
20
+ end
21
+
22
+ # is my ETCD the leader?
23
+ # <IMPLEMENTED>
24
+ def leader?(etcd)
25
+ etcd.stats(:self)['id'] == etcd.stats(:self)['leaderInfo']['leader']
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ module EtcdTools
2
+ module Watchdog
3
+ module HAproxy
4
+ # TODO
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ require 'socket'
2
+
3
+ module EtcdTools
4
+ module Watchdog
5
+ module Helpers
6
+ def hostname
7
+ @hostname ||= Socket.gethostname
8
+ end
9
+
10
+ def arping
11
+ @config[:commands][:arping]
12
+ end
13
+
14
+ def iproute
15
+ @config[:commands][:iproute]
16
+ end
17
+
18
+ def arp
19
+ @config[:commands][:arp]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,48 @@
1
+ require 'ipaddr'
2
+ require 'timeout'
3
+ require 'yaml'
4
+ require 'json'
5
+ require 'time'
6
+ require 'etcd'
7
+ require 'etcd-tools/mixins'
8
+ require 'etcd-tools/watchdog/config'
9
+ require 'etcd-tools/watchdog/logger'
10
+ require 'etcd-tools/watchdog/helpers'
11
+ require 'etcd-tools/watchdog/etcd'
12
+ require 'etcd-tools/watchdog/threads/etcd'
13
+
14
+ module EtcdTools
15
+ module Watchdog
16
+ class Init
17
+
18
+ include EtcdTools::Watchdog::Config
19
+ include EtcdTools::Watchdog::Logger
20
+ include EtcdTools::Watchdog::Helpers
21
+ include EtcdTools::Watchdog::Etcd
22
+ include EtcdTools::Watchdog::Threads
23
+
24
+ def initialize
25
+ @semaphore = {
26
+ log: Mutex.new,
27
+ etcd: Mutex.new
28
+ }
29
+ @config = { debug: false }
30
+ @config = config
31
+ @exit = false
32
+ # handle various signals
33
+ @exit_sigs = ['INT', 'TERM']
34
+ @exit_sigs.each { |sig| Signal.trap(sig) { @exit = true } }
35
+ Signal.trap('USR1') { @config[:debug] = false }
36
+ Signal.trap('USR2') { @config[:debug] = true }
37
+ Signal.trap('HUP') { @config = config }
38
+ if RUBY_VERSION >= '2.1'
39
+ Process.setproctitle('etcd-vip-watchdog')
40
+ else
41
+ $0 = 'etcd-vip-watchdog'
42
+ end
43
+ # Process.setpriority(Process::PRIO_PROCESS, 0, -20)
44
+ # Process.daemon
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,42 @@
1
+ require 'logger'
2
+
3
+ module EtcdTools
4
+ module Watchdog
5
+ module Logger
6
+ def info(message)
7
+ if @config[:debug]
8
+ @semaphore[:log].synchronize do
9
+ $stdout.puts(Time.now.to_s + ' INFO (TID:' + Thread.current.object_id.to_s + ') ' + message.to_s)
10
+ $stdout.flush
11
+ end
12
+ else
13
+ @semaphore[:log].synchronize do
14
+ $stdout.puts(Time.now.to_s + ' INFO ' + message.to_s)
15
+ $stdout.flush
16
+ end
17
+ end
18
+ end
19
+
20
+ def err(message)
21
+ if @config[:debug]
22
+ @semaphore[:log].synchronize do
23
+ $stdout.puts(Time.now.to_s + ' ERROR (TID:' + Thread.current.object_id.to_s + ') ' + message.to_s)
24
+ $stdout.flush
25
+ end
26
+ else
27
+ @semaphore[:log].synchronize do
28
+ $stdout.puts(Time.now.to_s + ' ERROR ' + message.to_s)
29
+ $stdout.flush
30
+ end
31
+ end
32
+ end
33
+
34
+ def debug(message)
35
+ @semaphore[:log].synchronize do
36
+ $stdout.puts(Time.now.to_s + ' DEBUG (TID:' + Thread.current.object_id.to_s + ') ' + message.to_s)
37
+ $stdout.flush
38
+ end if @config[:debug]
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,20 @@
1
+ module EtcdTools
2
+ module Watchdog
3
+ module Threads
4
+ def thread_etcd
5
+ Thread.new do
6
+ debug '<etcd> starting thread...'
7
+ etcd = etcd_connect!
8
+ while !@exit do
9
+ debug '<etcd> checking etcd state'
10
+ status = leader? etcd
11
+ @semaphore[:etcd].synchronize { @status_etcd = status }
12
+ debug "<etcd> i am #{status ? 'the leader' : 'not a leader' }"
13
+ sleep @config[:parameters][:etcd_interval]
14
+ end
15
+ info '<etcd> ending thread...'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module EtcdTools
2
+ module Watchdog
3
+ module Threads
4
+ def thread_icmp
5
+ Thread.new do
6
+ debug '<icmp> starting thread...'
7
+ icmp = Net::Ping::ICMP.new(@config[:parameters][:vip])
8
+ while !@exit do
9
+ debug '<icmp> checking state by ping'
10
+ status = vip_alive? icmp
11
+ @semaphore[:icmp].synchronize { @status_icmp = status }
12
+ debug "<icmp> VIP is #{status ? 'alive' : 'down' }"
13
+ sleep @config[:parameters][:icmp_interval]
14
+ end
15
+ info '<icmp> ending thread...'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,98 @@
1
+ module EtcdTools
2
+ module Watchdog
3
+ module Vip
4
+ # add or remove VIP on interface
5
+ # <IMPLEMENTED>
6
+ def vip_handle!(leader)
7
+ ip = IPAddr.new(@config[:parameters][:vip])
8
+ mask = @config[:parameters][:mask]
9
+ cmd = [ iproute,
10
+ 'address',
11
+ '',
12
+ "#{ip}/#{mask}",
13
+ 'dev',
14
+ @config[:parameters][:interface],
15
+ 'label',
16
+ @config[:parameters][:interface] + '-vip',
17
+ '>/dev/null 2>&1'
18
+ ]
19
+ case leader
20
+ when true
21
+ cmd[2] = 'add'
22
+ when false
23
+ cmd[2] = 'delete'
24
+ end
25
+ debug "CMD #{cmd.join(' ')}"
26
+ if system(cmd.join(' '))
27
+ info "IP '#{cmd[2]}' operation done"
28
+ else
29
+ err "IP '#{cmd[2]}' operation failed"
30
+ end
31
+ end
32
+
33
+ # send gratuitous ARP to the network
34
+ # <IMPLEMENTED>
35
+ def vip_update_arp!
36
+ cmd = [ arping, '-U',
37
+ '-c', @config[:parameters][:arping_count],
38
+ '-I', @config[:parameters][:interface],
39
+ @config[:parameters][:vip], '>/dev/null 2>&1' ]
40
+ debug "CMD #{cmd.join(' ')}"
41
+ if system(cmd.join(' '))
42
+ info 'gratuitous ARP packet sent'
43
+ return true
44
+ else
45
+ err 'gratuitous ARP packet failed to send'
46
+ return false
47
+ end
48
+ end
49
+
50
+ # check whether VIP is assigned to me
51
+ # <IMPLEMENTED>
52
+ def got_vip?
53
+ cmd = [ iproute,
54
+ 'address',
55
+ 'show',
56
+ 'label',
57
+ "#{@config[:parameters][:interface]}-vip",
58
+ '|',
59
+ 'grep',
60
+ '-q',
61
+ "#{@config[:parameters][:interface]}-vip"
62
+ ]
63
+ debug "CMD #{cmd.join(' ')}"
64
+ if system(cmd.join(' '))
65
+ return true
66
+ else
67
+ return false
68
+ end
69
+ end
70
+
71
+ # check reachability of VIP by ICMP echo
72
+ # <--- REWORK
73
+ def vip_alive?(icmp)
74
+ (1..@config[:parameters][:icmp_count]).each { return true if icmp.ping }
75
+ return false
76
+ end
77
+
78
+ # check whether the IP is registered anywhere
79
+ #
80
+ def vip_dup?
81
+ cmd_arp = [ arp, '-d', @config[:parameters][:vip], '>/dev/null 2>&1' ]
82
+ cmd_arping = [ arping, '-D',
83
+ '-c', @config[:parameters][:arping_count],
84
+ '-w', @config[:parameters][:arping_wait],
85
+ '-I', @config[:parameters][:interface],
86
+ @config[:parameters][:vip], '>/dev/null 2>&1' ]
87
+ debug "CMD #{cmd_arp.join(' ')}"
88
+ system(cmd_arp.join(' '))
89
+ debug "CMD #{cmd_arping.join(' ')}"
90
+ if system(cmd_arping.join(' '))
91
+ return false
92
+ else
93
+ return true
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,23 @@
1
+ module EtcdTools
2
+ module Yaml2Etcd
3
+ module Methods
4
+ def import_structure (hash, path="")
5
+ begin
6
+ hash.each do |k, v|
7
+ etcd_key = path + "/" + k.to_s
8
+ case v
9
+ when Hash
10
+ import_structure(v, etcd_key)
11
+ else
12
+ @etcd.set(etcd_key, value: v)
13
+ puts("SET: " + etcd_key + ": " + v.to_json) if @options[:verbose]
14
+ end
15
+ end
16
+ rescue Exception => e
17
+ $stderr.puts "Configuration import failed"
18
+ $stderr.puts e.message
19
+ exit! 1
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ require 'optparse'
2
+
3
+ module EtcdTools
4
+ module Yaml2Etcd
5
+ module Options
6
+ def optparse
7
+ @options = Hash.new
8
+
9
+ @options[:url] = ENV['ETCDCTL_ENDPOINT']
10
+ @options[:url] ||= "http://127.0.0.1:4001"
11
+ @options[:root_path] = "/config"
12
+
13
+
14
+ OptionParser.new do |opts|
15
+ opts.banner = "Reads YAML file and imports the data into ETCD\n\nUsage: #{$0} [OPTIONS] < config.yaml"
16
+ opts.separator ""
17
+ opts.separator "Connection options:"
18
+ opts.on("-u", "--url HOST", "URL endpoint of the ETCD service (ETCDCTL_ENDPOINT envvar also applies) [DEFAULT: http://127.0.0.1:4001]") do |param|
19
+ @options[:url] = param
20
+ end
21
+ opts.separator ""
22
+ opts.separator "Common options:"
23
+ opts.on("-r", "--root-path PATH", "root PATH of ETCD tree to inject the data [DEFAULT: /config]") do |param|
24
+ @options[:root_path] = param
25
+ end
26
+ opts.on("-v", "--verbose", "run verbosely") do |param|
27
+ @options[:verbose] = param
28
+ end
29
+ opts.on_tail("-h", "--help", "show usage") do |param|
30
+ puts opts;
31
+ exit! 0
32
+ end
33
+ end.parse!
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,44 @@
1
+ require 'yaml'
2
+ require 'etcd'
3
+ require_relative 'etcd_tools/yaml2etcd/options'
4
+ require_relative 'etcd_tools/yaml2etcd/import'
5
+
6
+ module EtcdTools
7
+ class Yaml2Etcd
8
+
9
+ include EtcdTools::Yaml2Etcd::Options
10
+ include EtcdTools::Yaml2Etcd::Import
11
+
12
+ def initialize
13
+ self.optparse
14
+ @etcd = self.class.connect(@options[:url], @options[:verbose])
15
+ @hash = self.class.read_yaml
16
+ import_structure @hash, @options[:root_path]
17
+ end
18
+
19
+ class << self
20
+ def read_yaml
21
+ begin
22
+ return YAML.load(ARGF.read)
23
+ rescue
24
+ $stderr.puts "Couldn't parse YAML"
25
+ exit! 1
26
+ end
27
+ end
28
+
29
+ def connect (url, verbose=false)
30
+ (host, port) = url.gsub(/^https?:\/\//, '').gsub(/\/$/, '').split(':')
31
+ etcd = Etcd.client(host: host, port: port)
32
+ begin
33
+ etcd.version
34
+ puts "Connected to ETCD on #{host}:#{port}" if verbose
35
+ return etcd
36
+ rescue Exception => e
37
+ $stderr.puts "Couldn't connect to etcd at #{host}:#{port}"
38
+ $stderr.puts e.message
39
+ exit! 1
40
+ end
41
+ end
42
+ end
43
+
44
+ end
data/lib/etcd_tools.rb ADDED
@@ -0,0 +1,3 @@
1
+ module EtcdTools
2
+
3
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: etcd-tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Radek 'blufor' Slavicinsky
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: etcd
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 0.3.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.3'
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.3.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: net-ping
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: '1.7'
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: 1.7.8
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ~>
48
+ - !ruby/object:Gem::Version
49
+ version: '1.7'
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: 1.7.8
53
+ description: A set of handful CLIE ETCD tools, part of PortAuthority
54
+ email: radek.slavicinsky@gmail.com
55
+ executables:
56
+ - etcd-watchdog-haproxy
57
+ - etcd-watchdog-vip
58
+ - etcd-erb
59
+ - yaml2etcd
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - bin/etcd-erb
64
+ - bin/etcd-watchdog-haproxy
65
+ - bin/etcd-watchdog-vip
66
+ - bin/yaml2etcd
67
+ - lib/etcd-tools/etcd_erb.rb
68
+ - lib/etcd-tools/etcd_erb/erb.rb
69
+ - lib/etcd-tools/etcd_erb/options.rb
70
+ - lib/etcd-tools/etcd_watchdog_haproxy.rb
71
+ - lib/etcd-tools/etcd_watchdog_vip.rb
72
+ - lib/etcd-tools/mixins.rb
73
+ - lib/etcd-tools/watchdog/config.rb
74
+ - lib/etcd-tools/watchdog/etcd.rb
75
+ - lib/etcd-tools/watchdog/haproxy.rb
76
+ - lib/etcd-tools/watchdog/helpers.rb
77
+ - lib/etcd-tools/watchdog/init.rb
78
+ - lib/etcd-tools/watchdog/logger.rb
79
+ - lib/etcd-tools/watchdog/threads/etcd.rb
80
+ - lib/etcd-tools/watchdog/threads/icmp.rb
81
+ - lib/etcd-tools/watchdog/vip.rb
82
+ - lib/etcd-tools/yaml2etcd.rb
83
+ - lib/etcd-tools/yaml2etcd/import.rb
84
+ - lib/etcd-tools/yaml2etcd/options.rb
85
+ - lib/etcd_tools.rb
86
+ homepage: http://rubygems.org/gems/etcd-tools
87
+ licenses:
88
+ - GPLv2
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '1.9'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.4.3
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: CLI ETCD tools
110
+ test_files: []