port-authority 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- metadata +22 -35
- data/bin/pa-manager +0 -3
- data/lib/port-authority/manager/app.rb +0 -153
- data/lib/port-authority/manager/init.rb +0 -43
- data/lib/port-authority/manager/threads/icmp.rb +0 -30
- data/lib/port-authority/manager/threads/swarm.rb +0 -42
- data/lib/port-authority/util/config.rb +0 -61
- data/lib/port-authority/util/etcd.rb +0 -33
- data/lib/port-authority/util/helpers.rb +0 -27
- data/lib/port-authority/util/loadbalancer.rb +0 -66
- data/lib/port-authority/util/logger.rb +0 -57
- data/lib/port-authority/util/vip.rb +0 -57
- data/lib/port-authority.rb +0 -28
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YWMwYTk0NjYzYjI2OTAyYTc0OWQwOGJhZWY5MjE5M2U4MWZhMDMzMg==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e29bbb93c31d6ecff7d9931333bda2b6d5b70f04
|
4
|
+
data.tar.gz: e964daf7b9d98e1f93efe3737e96e09c1a9f33f6
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
NjRjYzNmZDU5ZWFlZDNlMTczY2I1YmFjMWI5MDdiZDhmNDVkNTc1NGRjY2M5
|
11
|
-
YzIyY2JjZmJiM2I5N2U5ODBjNDBkZmM1MmZjZDk0MjgwYjlhYWI=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NTY4MWVkODk1NzE5ZjU3ZTNlYTYwNzA0MjkxZDg3MDkxNjhjN2Y0YWQ4MGY3
|
14
|
-
MzNiNDM2ZWM0MjFjN2FhMmNmYTJhODkxMGFmMmE5ZmZjMzVkOTk0MDFiNDNh
|
15
|
-
ZGFlYzA3MGQ4MjMwOWUwNDYxNmZiOGQyZDEwMDk3NGQwMTI5OTg=
|
6
|
+
metadata.gz: 22a89d416d76f7797f51ee1425ca00cd11df6bbc0062940db3cf891d36b08b19019b31580fb01b6abee0bbfc9c26e3d86f3ad005708965904d351f49e634e69f
|
7
|
+
data.tar.gz: 450d1ca0945399efed8020a21f027c7334854689d986e5804fec9807efc4688aed154b5dfa7db59a2a232ea3f5ecdcfe7c94577375676d630579765eb5c875aa
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: port-authority
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Radek 'blufor' Slavicinsky
|
@@ -14,101 +14,88 @@ dependencies:
|
|
14
14
|
name: etcd
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0.3'
|
20
|
-
- -
|
20
|
+
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: 0.3.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - ~>
|
27
|
+
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0.3'
|
30
|
-
- -
|
30
|
+
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 0.3.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: etcd-tools
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- - ~>
|
37
|
+
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '0.4'
|
40
|
-
- -
|
40
|
+
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
42
|
version: 0.4.0
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
|
-
- - ~>
|
47
|
+
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: '0.4'
|
50
|
-
- -
|
50
|
+
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: 0.4.0
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: net-ping
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
|
-
- - ~>
|
57
|
+
- - "~>"
|
58
58
|
- !ruby/object:Gem::Version
|
59
59
|
version: '1.7'
|
60
|
-
- -
|
60
|
+
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: 1.7.8
|
63
63
|
type: :runtime
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- - ~>
|
67
|
+
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '1.7'
|
70
|
-
- -
|
70
|
+
- - ">="
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: 1.7.8
|
73
73
|
- !ruby/object:Gem::Dependency
|
74
74
|
name: docker-api
|
75
75
|
requirement: !ruby/object:Gem::Requirement
|
76
76
|
requirements:
|
77
|
-
- - ~>
|
77
|
+
- - "~>"
|
78
78
|
- !ruby/object:Gem::Version
|
79
79
|
version: '1.0'
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 1.25.0
|
83
83
|
type: :runtime
|
84
84
|
prerelease: false
|
85
85
|
version_requirements: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - ~>
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '1.0'
|
90
|
-
- -
|
90
|
+
- - ">="
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: 1.25.0
|
93
93
|
description: CLI Tools for PortAuthority
|
94
94
|
email: radek.slavicinsky@gmail.com
|
95
|
-
executables:
|
96
|
-
- pa-manager
|
95
|
+
executables: []
|
97
96
|
extensions: []
|
98
97
|
extra_rdoc_files: []
|
99
|
-
files:
|
100
|
-
- bin/pa-manager
|
101
|
-
- lib/port-authority.rb
|
102
|
-
- lib/port-authority/manager/app.rb
|
103
|
-
- lib/port-authority/manager/init.rb
|
104
|
-
- lib/port-authority/manager/threads/icmp.rb
|
105
|
-
- lib/port-authority/manager/threads/swarm.rb
|
106
|
-
- lib/port-authority/util/config.rb
|
107
|
-
- lib/port-authority/util/etcd.rb
|
108
|
-
- lib/port-authority/util/helpers.rb
|
109
|
-
- lib/port-authority/util/loadbalancer.rb
|
110
|
-
- lib/port-authority/util/logger.rb
|
111
|
-
- lib/port-authority/util/vip.rb
|
98
|
+
files: []
|
112
99
|
homepage: https://github.com/prozeta/port-authority
|
113
100
|
licenses:
|
114
101
|
- GPLv2
|
@@ -119,17 +106,17 @@ require_paths:
|
|
119
106
|
- lib
|
120
107
|
required_ruby_version: !ruby/object:Gem::Requirement
|
121
108
|
requirements:
|
122
|
-
- -
|
109
|
+
- - ">="
|
123
110
|
- !ruby/object:Gem::Version
|
124
111
|
version: 1.9.3
|
125
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
113
|
requirements:
|
127
|
-
- -
|
114
|
+
- - ">="
|
128
115
|
- !ruby/object:Gem::Version
|
129
116
|
version: '0'
|
130
117
|
requirements: []
|
131
118
|
rubyforge_project:
|
132
|
-
rubygems_version: 2.4.
|
119
|
+
rubygems_version: 2.4.6
|
133
120
|
signing_key:
|
134
121
|
specification_version: 4
|
135
122
|
summary: Port Authority
|
data/bin/pa-manager
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
# rubocop:disable MethodLength, CyclomaticComplexity, Metrics/BlockNesting, Metrics/LineLength, Metrics/AbcSize, Metrics/PerceivedComplexity
|
2
|
-
require 'ipaddr'
|
3
|
-
require 'port-authority'
|
4
|
-
require 'port-authority/util/vip'
|
5
|
-
require 'port-authority/util/etcd'
|
6
|
-
require 'port-authority/util/loadbalancer'
|
7
|
-
require 'port-authority/manager/init'
|
8
|
-
require 'port-authority/manager/threads/icmp'
|
9
|
-
require 'port-authority/manager/threads/swarm'
|
10
|
-
|
11
|
-
module PortAuthority
|
12
|
-
module Manager
|
13
|
-
##
|
14
|
-
# Port Authority Manager - manages floating VIP and lb placement
|
15
|
-
#
|
16
|
-
class App < PortAuthority::Manager::Init
|
17
|
-
include PortAuthority::Util::Etcd
|
18
|
-
include PortAuthority::Util::Vip
|
19
|
-
include PortAuthority::Util::LoadBalancer
|
20
|
-
include PortAuthority::Manager::Threads
|
21
|
-
|
22
|
-
def run
|
23
|
-
# exit if not root
|
24
|
-
if Process.euid != 0
|
25
|
-
alert 'must run under root user!'
|
26
|
-
exit! 1
|
27
|
-
end
|
28
|
-
|
29
|
-
Signal.trap('USR1') { @lb_update_hook = true }
|
30
|
-
|
31
|
-
# prepare semaphores
|
32
|
-
@semaphore.merge!(swarm: Mutex.new, icmp: Mutex.new)
|
33
|
-
|
34
|
-
# prepare threads
|
35
|
-
@thread = {icmp: thread_icmp,swarm: thread_swarm}
|
36
|
-
|
37
|
-
# prepare status vars
|
38
|
-
@status_swarm = false
|
39
|
-
@status_icmp = false
|
40
|
-
|
41
|
-
# start threads
|
42
|
-
@thread.each_value(&:run)
|
43
|
-
|
44
|
-
# setup docker client
|
45
|
-
lb_docker_setup! || @exit = true
|
46
|
-
|
47
|
-
# prepare container with load-balancer
|
48
|
-
lb_create!
|
49
|
-
|
50
|
-
# wait for threads to make sure they gather something
|
51
|
-
debug 'waiting for threads to gather something...'
|
52
|
-
sleep @config[:vip][:interval]
|
53
|
-
first_cycle = true
|
54
|
-
status_time = Time.now.to_i - 60
|
55
|
-
|
56
|
-
# main loop
|
57
|
-
until @exit
|
58
|
-
# initialize local state vars on first iteration
|
59
|
-
status_swarm = status_icmp = false if first_cycle
|
60
|
-
|
61
|
-
if @lb_update_hook
|
62
|
-
notice 'updating LB image'
|
63
|
-
lb_update!
|
64
|
-
end
|
65
|
-
|
66
|
-
# iteration interval
|
67
|
-
sleep @config[:vip][:interval]
|
68
|
-
|
69
|
-
# sync state to local variables
|
70
|
-
@semaphore[:icmp].synchronize { status_icmp = @status_icmp }
|
71
|
-
@semaphore[:swarm].synchronize { status_swarm = @status_swarm }
|
72
|
-
|
73
|
-
# the logic (should be self-explanatory ;))
|
74
|
-
if status_swarm
|
75
|
-
debug 'i am the leader'
|
76
|
-
if got_vip?
|
77
|
-
debug 'got VIP, that is OK'
|
78
|
-
else
|
79
|
-
info 'no VIP here, checking whether it is free'
|
80
|
-
if status_icmp
|
81
|
-
info 'VIP is still up! (ICMP)'
|
82
|
-
# FIXME: notify by sensu client socket
|
83
|
-
else
|
84
|
-
# FIXME: proper arping handling
|
85
|
-
# info 'VIP is unreachable by ICMP, checking for duplicates on L2'
|
86
|
-
# if vip_dup?
|
87
|
-
# info 'VIP is still assigned! (ARP)'
|
88
|
-
# # FIXME: notify by sensu client socket
|
89
|
-
# else
|
90
|
-
# info 'VIP is free :) assigning'
|
91
|
-
# vip_handle! status_swarm
|
92
|
-
# info 'updating other hosts about change'
|
93
|
-
# vip_update_arp!
|
94
|
-
# end
|
95
|
-
notice 'VIP is free :) assigning'
|
96
|
-
vip_handle! status_swarm
|
97
|
-
notice 'updating other hosts about change'
|
98
|
-
vip_update_arp!
|
99
|
-
end
|
100
|
-
end
|
101
|
-
if lb_up?
|
102
|
-
debug 'load-balancer is up, that is OK'
|
103
|
-
else
|
104
|
-
notice 'load-balancer is down, starting'
|
105
|
-
lb_start!
|
106
|
-
end
|
107
|
-
else
|
108
|
-
debug 'i am not the leader'
|
109
|
-
if got_vip?
|
110
|
-
notice 'i got VIP and should not, removing'
|
111
|
-
vip_handle! status_swarm
|
112
|
-
notice 'updating other hosts about change'
|
113
|
-
vip_update_arp!
|
114
|
-
else
|
115
|
-
debug 'no VIP here, that is OK'
|
116
|
-
end
|
117
|
-
if lb_up?
|
118
|
-
notice 'load-balancer is up, stopping'
|
119
|
-
lb_stop!
|
120
|
-
else
|
121
|
-
debug 'load-balancer is down, that is OK'
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
if status_time + 60 <= Time.now.to_i
|
126
|
-
info "STATUS_REPORT { leader: '#{status_swarm ? 'yes' : 'no'}', vip: '#{got_vip? ? 'yes' : 'no'}/#{status_icmp ? 'up' : 'down'}', lb: '#{lb_up? ? 'yes' : 'no'}' }"
|
127
|
-
status_time = Time.now.to_i
|
128
|
-
end
|
129
|
-
|
130
|
-
end
|
131
|
-
|
132
|
-
# this is triggerred on exit
|
133
|
-
@thread.each_value(&:join)
|
134
|
-
|
135
|
-
# remove VIP on shutdown
|
136
|
-
if got_vip?
|
137
|
-
notice 'removing VIP'
|
138
|
-
vip_handle! false
|
139
|
-
vip_update_arp!
|
140
|
-
end
|
141
|
-
|
142
|
-
# stop LB on shutdown
|
143
|
-
if lb_up?
|
144
|
-
notice 'stopping load-balancer'
|
145
|
-
lb_stop!
|
146
|
-
end
|
147
|
-
|
148
|
-
info 'exiting...'
|
149
|
-
exit 0
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'timeout'
|
2
|
-
require 'json'
|
3
|
-
require 'etcd-tools'
|
4
|
-
require 'port-authority/util/config'
|
5
|
-
require 'port-authority/util/logger'
|
6
|
-
require 'port-authority/util/helpers'
|
7
|
-
|
8
|
-
module PortAuthority
|
9
|
-
module Manager
|
10
|
-
class Init
|
11
|
-
include PortAuthority::Util::Config
|
12
|
-
include PortAuthority::Util::Logger
|
13
|
-
include PortAuthority::Util::Helpers
|
14
|
-
|
15
|
-
def initialize(proc_name='dummy')
|
16
|
-
@config = config
|
17
|
-
@exit = false
|
18
|
-
@semaphore = { log: Mutex.new }
|
19
|
-
Thread.current[:name] = 'main'
|
20
|
-
syslog_init proc_name if @config[:syslog]
|
21
|
-
setup proc_name
|
22
|
-
info 'starting main thread'
|
23
|
-
debug 'setting signal handling'
|
24
|
-
@exit_sigs = %w(INT TERM)
|
25
|
-
@exit_sigs.each { |sig| Signal.trap(sig) { @exit = true } }
|
26
|
-
Signal.trap('USR2') { @config[:debug] = !@config[:debug] }
|
27
|
-
Signal.trap('HUP') { @config = config }
|
28
|
-
end
|
29
|
-
|
30
|
-
def setup(proc_name, nice = -20)
|
31
|
-
debug 'setting process name'
|
32
|
-
if RUBY_VERSION >= '2.1'
|
33
|
-
Process.setproctitle(proc_name)
|
34
|
-
else
|
35
|
-
$0 = proc_name
|
36
|
-
end
|
37
|
-
debug 'setting process title'
|
38
|
-
Process.setpriority(Process::PRIO_PROCESS, 0, nice)
|
39
|
-
# FIXME: Process.daemon ...
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -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,42 +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 ETCD state'
|
13
|
-
etcd_healthy? etcd
|
14
|
-
debug 'checking swarm state'
|
15
|
-
status = am_i_leader? etcd
|
16
|
-
@semaphore[:swarm].synchronize { @status_swarm = status }
|
17
|
-
debug "i am #{status ? 'the leader' : 'not the leader' }"
|
18
|
-
sleep @config[:etcd][:interval]
|
19
|
-
end
|
20
|
-
info 'ending swarm thread...'
|
21
|
-
rescue PortAuthority::Errors::ETCDIsSick => e
|
22
|
-
notice "#{e.class}: #{e.message}"
|
23
|
-
notice "connection: " + e.etcd.to_s
|
24
|
-
@semaphore[:swarm].synchronize { @status_swarm = false }
|
25
|
-
sleep @config[:etcd][:interval]
|
26
|
-
retry unless @exit
|
27
|
-
rescue PortAuthority::Errors::ETCDConnectFailed => e
|
28
|
-
err "#{e.class}: #{e.message}"
|
29
|
-
err "connection: " + e.etcd.to_s
|
30
|
-
@semaphore[:swarm].synchronize { @status_swarm = false }
|
31
|
-
sleep @config[:etcd][:interval]
|
32
|
-
retry unless @exit
|
33
|
-
rescue StandardError => e
|
34
|
-
alert e.message
|
35
|
-
alert e.backtrace.to_s
|
36
|
-
@exit = true
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,61 +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
|
-
},
|
52
|
-
commands: {
|
53
|
-
arping: `which arping`.chomp,
|
54
|
-
arp: `which arp`.chomp,
|
55
|
-
iproute: `which ip`.chomp
|
56
|
-
}
|
57
|
-
}
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,33 +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
|
-
rescue StandardError => e
|
28
|
-
false
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
33
|
-
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,66 +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
|
-
# create container with
|
39
|
-
@lb_container = Docker::Container.create(
|
40
|
-
'Image' => img.json['Id'],
|
41
|
-
'name' => @config[:lb][:name],
|
42
|
-
'Hostname' => @config[:lb][:name],
|
43
|
-
'Env' => [ "ETCDCTL_ENDPOINT=#{@config[:etcd][:endpoints].join(',')}" ],
|
44
|
-
'RestartPolicy' => { 'Name' => 'never' },
|
45
|
-
'HostConfig' => {
|
46
|
-
'PortBindings' => port_bindings,
|
47
|
-
'NetworkMode' => @config[:lb][:network]
|
48
|
-
}
|
49
|
-
)
|
50
|
-
end
|
51
|
-
|
52
|
-
def lb_up?
|
53
|
-
@lb_container.json['State']['Running']
|
54
|
-
end
|
55
|
-
|
56
|
-
def lb_start!
|
57
|
-
@lb_container.start
|
58
|
-
end
|
59
|
-
|
60
|
-
def lb_stop!
|
61
|
-
@lb_container.stop
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
end
|
66
|
-
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
|
data/lib/port-authority.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
module PortAuthority
|
2
|
-
module Manager
|
3
|
-
end
|
4
|
-
|
5
|
-
module Util
|
6
|
-
end
|
7
|
-
|
8
|
-
module Errors
|
9
|
-
|
10
|
-
class ETCDConnectFailed < StandardError
|
11
|
-
attr_reader :etcd, :message
|
12
|
-
def initialize(etcd, message = "Can't connect to ETCD")
|
13
|
-
@message = message
|
14
|
-
@etcd = etcd
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class ETCDIsSick < StandardError
|
19
|
-
attr_reader :etcd, :message
|
20
|
-
def initialize(etcd, message = 'ETCD is not healthy')
|
21
|
-
@message = message
|
22
|
-
@etcd = etcd
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|