port-authority 0.4.8 → 0.5.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.
@@ -1,30 +0,0 @@
1
- # rubocop:disable Metrics/MethodLength
2
- require 'net/ping'
3
-
4
- module PortAuthority
5
- module Manager
6
- module Threads
7
- def thread_icmp
8
- Thread.new do
9
- Thread.current[:name] = 'icmp'
10
- begin
11
- info 'starting ICMP thread...'
12
- icmp = Net::Ping::ICMP.new(@config[:vip][:ip])
13
- until @exit
14
- debug 'checking state by ICMP echo'
15
- status = vip_alive? icmp
16
- @semaphore[:icmp].synchronize { @status_icmp = status }
17
- debug "VIP is #{status ? 'alive' : 'down'} according to ICMP"
18
- sleep @config[:icmp][:interval]
19
- end
20
- info 'ending ICMP thread...'
21
- rescue StandardError => e
22
- alert "#{e.class}: #{e.message}"
23
- alert e.backtrace
24
- @exit = true
25
- end
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,35 +0,0 @@
1
- # rubocop:disable Metrics/MethodLength
2
- module PortAuthority
3
- module Manager
4
- module Threads
5
- def thread_swarm
6
- Thread.new do
7
- Thread.current[:name] = 'swarm'
8
- info 'starting swarm thread...'
9
- begin
10
- etcd = etcd_connect!
11
- until @exit
12
- debug 'checking swarm state'
13
- status = am_i_leader? etcd
14
- @semaphore[:swarm].synchronize { @status_swarm = status }
15
- debug "i am #{status ? '' : 'NOT' } the swarm leader"
16
- sleep @config[:etcd][:interval]
17
- end
18
- info 'ending swarm thread...'
19
- rescue PortAuthority::Errors::ETCDConnectFailed => e
20
- err "#{e.class}: #{e.message}"
21
- err "connection: " + e.etcd.to_s
22
- err " #{e.backtrace.to_s}"
23
- @semaphore[:swarm].synchronize { @status_swarm = false }
24
- sleep @config[:etcd][:interval]
25
- retry unless @exit
26
- rescue StandardError => e
27
- alert e.message
28
- alert e.backtrace.to_s
29
- @exit = true
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,62 +0,0 @@
1
- require 'yaml'
2
- require 'etcd-tools'
3
-
4
- module PortAuthority
5
- module Util
6
- module Config
7
-
8
- def config
9
- cfg = default_config
10
- if File.exist? '/etc/port-authority.yaml'
11
- cfg = cfg.deep_merge YAML.load_file('/etc/port-authority.yaml')
12
- puts 'loaded config from /etc/port-authority.yaml'
13
- elsif File.exist? './port-authority.yaml'
14
- cfg = cfg.deep_merge YAML.load_file('./port-authority.yaml')
15
- puts 'loaded config from ./port-authority.yaml'
16
- else
17
- puts 'no config file loaded, using defaults'
18
- end
19
- cfg
20
- end
21
-
22
- private
23
-
24
- def default_config
25
- { debug: false,
26
- syslog: false,
27
- etcd: {
28
- endpoints: ['http://localhost:2379'],
29
- interval: 5,
30
- timeout: 5
31
- },
32
- icmp: {
33
- count: 5,
34
- interval: 2
35
- },
36
- arping: {
37
- count: 1,
38
- wait: 1
39
- },
40
- vip: {
41
- interval: 1,
42
- ip: '172.17.1.5',
43
- mask: '255.255.255.0',
44
- interface: 'eth0'
45
- },
46
- lb: {
47
- image: 'docker-registry.prz/stackdocks/haproxy:latest',
48
- name: 'lb',
49
- network: 'overlay',
50
- docker_endpoint: 'unix:///var/run/docker.sock',
51
- log_dest: '',
52
- },
53
- commands: {
54
- arping: `which arping`.chomp,
55
- arp: `which arp`.chomp,
56
- iproute: `which ip`.chomp
57
- }
58
- }
59
- end
60
- end
61
- end
62
- end
@@ -1,50 +0,0 @@
1
- require 'etcd'
2
- require 'etcd-tools/mixins'
3
-
4
- module PortAuthority
5
- module Util
6
- module Etcd
7
- # connect to ETCD
8
- def etcd_connect!
9
- endpoints = @config[:etcd][:endpoints].map { |e| e = e.gsub!(/^https?:\/\//, '').gsub(/\/$/, '').split(':'); { host: e[0], port: e[1].to_i } }
10
- debug "parsed ETCD endpoints: #{endpoints.to_s}"
11
- etcd = ::Etcd::Client.new(cluster: endpoints, read_timeout: @config[:etcd][:timeout])
12
- etcd if etcd.version
13
- rescue
14
- raise PortAuthority::Errors::ETCDConnectFailed.new(@config[:etcd][:endpoints])
15
- end
16
-
17
- def etcd_healthy?(etcd)
18
- raise PortAuthority::Errors::ETCDIsSick.new(@config[:etcd][:endpoints]) unless etcd.healthy?
19
- end
20
-
21
- def swarm_leader(etcd)
22
- etcd.get('/_pa/docker/swarm/leader').value
23
- end
24
-
25
- def am_i_leader?(etcd)
26
- Socket.ip_address_list.map(&:ip_address).member?(swarm_leader(etcd).split(':').first)
27
- end
28
-
29
- def overlay_id(etcd, name)
30
- etcd.get_hash('/_pa/docker/network/v1.0/network').each_value do |network|
31
- return network['id'] if network['name'] == name
32
- end
33
- end
34
-
35
- def list_services(etcd, network, service_name='.*')
36
- svc_filter = Regexp.new(service_name)
37
- network_id = overlay_id(etcd, network)
38
- services = Hash.new
39
- etcd.get_hash("/_pa/docker/network/v1.0/endpoint/#{network_id}").each_value do |container|
40
- next unless svc_filter.match container['name']
41
- services[container['name']] = Hash.new
42
- services[container['name']]['id'] = container['id']
43
- services[container['name']]['ip'] = container['ep_iface']['addr'].sub(/\/[0-9]+$/, '')
44
- services[container['name']]['ports'] = container['exposed_ports'].map { |port| port['Port'] }
45
- end
46
- services
47
- end
48
- end
49
- end
50
- end
@@ -1,27 +0,0 @@
1
- require 'socket'
2
-
3
- module PortAuthority
4
- module Util
5
- module Helpers
6
- def hostname
7
- @hostname ||= Socket.gethostname
8
- end
9
-
10
- def my_ip
11
- @my_ip ||= Socket.ip_address_list.detect(&:ipv4_private?).ip_address
12
- end
13
-
14
- def arping
15
- @config[:commands][:arping]
16
- end
17
-
18
- def iproute
19
- @config[:commands][:iproute]
20
- end
21
-
22
- def arp
23
- @config[:commands][:arp]
24
- end
25
- end
26
- end
27
- end
@@ -1,78 +0,0 @@
1
- require 'docker-api'
2
-
3
- module PortAuthority
4
- module Util
5
- module LoadBalancer
6
- # connect to Docker
7
- def lb_docker_setup!
8
- Docker.url = @config[:lb][:docker_endpoint]
9
- Docker.version
10
- true
11
- rescue
12
- false
13
- end
14
-
15
- def lb_update!
16
- lb_stop! if lb_up?
17
- lb_remove!
18
- lb_create!
19
- @lb_update_hook = false
20
- end
21
-
22
- def lb_remove!
23
- Docker::Container.get(@config[:lb][:name]).delete
24
- rescue Docker::Error::NotFoundError
25
- end
26
-
27
-
28
- def lb_create!
29
- lb_remove!
30
- img = Docker::Image.create('fromImage' => @config[:lb][:image])
31
-
32
- # setup port bindings hash
33
- port_bindings = Hash.new
34
- img.json['ContainerConfig']['ExposedPorts'].keys.each do |port|
35
- port_bindings[port] = [ { 'HostPort' => "#{port.split('/').first}" } ]
36
- end
37
-
38
- cont_def = {
39
- 'Image' => img.json['Id'],
40
- 'name' => @config[:lb][:name],
41
- 'Hostname' => @config[:lb][:name],
42
- 'Env' => [ "ETCDCTL_ENDPOINT=#{@config[:etcd][:endpoints].map { |e| "http://#{e}" }.join(',')}" ],
43
- 'RestartPolicy' => { 'Name' => 'never' },
44
- 'HostConfig' => {
45
- 'PortBindings' => port_bindings,
46
- 'NetworkMode' => @config[:lb][:network]
47
- }
48
- }
49
-
50
- if @config[:lb][:log_dest] != ''
51
- cont_def['HostConfig']['LogConfig'] = {
52
- 'Type' => 'gelf',
53
- 'Config' => {
54
- 'gelf-address' => @config[:lb][:log_dest],
55
- 'tag' => Socket.gethostbyname(Socket.gethostname).first + '/{{.Name}}/{{.ID}}'
56
- }
57
- }
58
- end
59
-
60
- # create container with
61
- @lb_container = Docker::Container.create(cont_def)
62
- end
63
-
64
- def lb_up?
65
- @lb_container.json['State']['Running']
66
- end
67
-
68
- def lb_start!
69
- @lb_container.start
70
- end
71
-
72
- def lb_stop!
73
- @lb_container.stop
74
- end
75
-
76
- end
77
- end
78
- end
@@ -1,57 +0,0 @@
1
- # rubocop:disable Metrics/LineLength, Metrics/AbcSize, Metrics/MethodLength
2
- require 'syslog'
3
-
4
- module PortAuthority
5
- module Util
6
- module Logger
7
- def debug(message)
8
- log :debug, message if @config[:debug]
9
- end
10
-
11
- def info(message)
12
- log :info, message
13
- end
14
-
15
- def notice(message)
16
- log :notice, message
17
- end
18
-
19
- def err(message)
20
- log :err, message
21
- end
22
-
23
- def alert(message)
24
- log :alert, message if @config[:debug]
25
- end
26
-
27
- def syslog_init(proc_name)
28
- Syslog.open(proc_name, Syslog::LOG_PID, Syslog::LOG_DAEMON)
29
- end
30
-
31
- def log(lvl, msg)
32
- if @config[:syslog]
33
- case lvl
34
- when :debug
35
- l = Syslog::LOG_DEBUG
36
- when :info
37
- l = Syslog::LOG_INFO
38
- when :notice
39
- l = Syslog::LOG_NOTICE
40
- when :err
41
- l = Syslog::LOG_ERR
42
- when :alert
43
- l = Syslog::LOG_ALERT
44
- end
45
- @semaphore[:log].synchronize do
46
- Syslog.log(l, "(%s) %s", Thread.current[:name], msg.to_s)
47
- end
48
- else
49
- @semaphore[:log].synchronize do
50
- $stdout.puts("#{Time.now.to_s} #{lvl.to_s[0].capitalize} (#{Thread.current[:name]}) #{msg.to_s}")
51
- $stdout.flush
52
- end
53
- end
54
- end
55
- end
56
- end
57
- end
@@ -1,57 +0,0 @@
1
- # rubocop:disable Metrics/LineLength, Metrics/AbcSize
2
- module PortAuthority
3
- module Util
4
- module Vip
5
- # add or remove VIP on interface
6
- # <IMPLEMENTED>
7
- def vip_handle!(leader)
8
- ip = IPAddr.new(@config[:vip][:ip])
9
- mask = @config[:vip][:mask]
10
- cmd = [iproute, 'address', '', "#{ip}/#{mask}", 'dev', @config[:vip][:interface], 'label', @config[:vip][:interface] + '-vip', '>/dev/null 2>&1']
11
- leader ? cmd[2] = 'add' : cmd[2] = 'delete'
12
- debug "#{cmd.join(' ')}"
13
- if system(cmd.join(' '))
14
- return true
15
- else
16
- return false
17
- end
18
- end
19
-
20
- # send gratuitous ARP to the network
21
- def vip_update_arp!
22
- cmd = [arping, '-U', '-q', '-c', @config[:arping][:count], '-I', @config[:vip][:interface], @config[:vip][:ip]]
23
- debug "#{cmd.join(' ')}"
24
- if system(cmd.join(' '))
25
- return true
26
- else
27
- return false
28
- end
29
- end
30
-
31
- # check whether VIP is assigned to me
32
- def got_vip?
33
- Socket.ip_address_list.map(&:ip_address).member?(@config[:vip][:ip])
34
- end
35
-
36
- # check reachability of VIP by ICMP echo
37
- def vip_alive?(icmp)
38
- (1..@config[:icmp][:count]).each { return true if icmp.ping }
39
- false
40
- end
41
-
42
- # check whether the IP is registered anywhere
43
- def vip_dup?
44
- cmd_arp = [arp, '-d', @config[:vip][:ip], '>/dev/null 2>&1']
45
- cmd_arping = [arping, '-D', '-q', '-c', @config[:arping][:count], '-w', @config[:arping][:wait], '-I', @config[:vip][:interface], @config[:vip][:ip]]
46
- debug "#{cmd_arp.join(' ')}"
47
- system(cmd_arp.join(' '))
48
- debug "#{cmd_arping.join(' ')}"
49
- if system(cmd_arping.join(' '))
50
- return false
51
- else
52
- return true
53
- end
54
- end
55
- end
56
- end
57
- end