etcd-tools 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []