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.
- checksums.yaml +4 -4
- data/bin/pa-lbaas-agent +3 -0
- data/bin/pa-service-list +2 -2
- data/lib/port-authority.rb +0 -8
- data/lib/port-authority/agent.rb +164 -0
- data/lib/port-authority/agents/lbaas.rb +134 -0
- data/lib/port-authority/config.rb +49 -0
- data/lib/port-authority/etcd.rb +47 -0
- data/lib/port-authority/logger.rb +56 -0
- data/lib/port-authority/mechanism/floating_ip.rb +51 -0
- data/lib/port-authority/mechanism/load_balancer.rb +89 -0
- data/lib/port-authority/tool.rb +9 -0
- data/lib/port-authority/{services.rb → tools/service_list.rb} +12 -16
- metadata +16 -18
- data/bin/pa-manager +0 -3
- data/lib/port-authority/manager.rb +0 -153
- data/lib/port-authority/manager/init.rb +0 -49
- data/lib/port-authority/manager/threads/icmp.rb +0 -30
- data/lib/port-authority/manager/threads/swarm.rb +0 -35
- data/lib/port-authority/util/config.rb +0 -62
- data/lib/port-authority/util/etcd.rb +0 -50
- data/lib/port-authority/util/helpers.rb +0 -27
- data/lib/port-authority/util/loadbalancer.rb +0 -78
- data/lib/port-authority/util/logger.rb +0 -57
- data/lib/port-authority/util/vip.rb +0 -57
@@ -0,0 +1,51 @@
|
|
1
|
+
# rubocop:disable Metrics/LineLength, Metrics/AbcSize
|
2
|
+
require 'net/ping'
|
3
|
+
|
4
|
+
module PortAuthority
|
5
|
+
module Mechanism
|
6
|
+
module FloatingIP
|
7
|
+
|
8
|
+
extend self
|
9
|
+
|
10
|
+
attr_accessor :_icmp
|
11
|
+
|
12
|
+
def init!
|
13
|
+
@_icmp = Net::Ping::ICMP.new(Config.lbaas[:floating_ip])
|
14
|
+
end
|
15
|
+
|
16
|
+
# add or remove VIP on interface
|
17
|
+
def handle!(leader)
|
18
|
+
return true if shellcmd Config.commands[:iproute], 'address', leader ? 'add' : 'delete', "#{Config.lbaas[:floating_ip]}/32", 'dev', Config.lbaas[:interface], '>/dev/null 2>&1'
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
# send gratuitous ARP to the network
|
23
|
+
def arp_update!
|
24
|
+
return true if shellcmd Config.commands[:arping], '-U', '-q', '-c', Config.lbaas[:arping_count], '-I', Config.lbaas[:interface], Config.lbaas[:floating_ip]
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
# check whether VIP is assigned to me
|
29
|
+
def up?
|
30
|
+
Socket.ip_address_list.map(&:ip_address).member?(Config.lbaas[:floating_ip])
|
31
|
+
end
|
32
|
+
|
33
|
+
# check reachability of VIP by ICMP echo
|
34
|
+
def reachable?
|
35
|
+
(1..Config.lbaas[:icmp_count]).each { return true if @_icmp.ping }
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def arp_del!
|
40
|
+
return true if shellcmd Config.commands[:arp], '-d', Config.lbaas[:floating_ip], '>/dev/null 2>&1'
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
# check whether the IP is registered anywhere
|
45
|
+
def duplicate?
|
46
|
+
return true if shellcmd Config.commands[:arping], '-D', '-q', '-c', Config.lbaas[:arping_count], '-w', Config.lbaas[:arping_wait], '-I', Config.lbaas[:interface], Config.lbaas[:floating_ip]
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'docker-api'
|
2
|
+
|
3
|
+
module PortAuthority
|
4
|
+
module Mechanism
|
5
|
+
module LoadBalancer
|
6
|
+
|
7
|
+
extend self
|
8
|
+
|
9
|
+
attr_reader :_container, :_container_def, :_image
|
10
|
+
|
11
|
+
def init!
|
12
|
+
Docker.url = Config.lbaas[:docker_endpoint]
|
13
|
+
Docker.options = { connect_timeout: Config.lbaas[:docker_timeout] || 10 }
|
14
|
+
end
|
15
|
+
|
16
|
+
def container
|
17
|
+
@_container ||= Docker::Container.get(Config.lbaas[:name]) rescue nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def image
|
21
|
+
@_image ||= Docker::Image.create('fromImage' => Config.lbaas[:image])
|
22
|
+
end
|
23
|
+
|
24
|
+
def pull!
|
25
|
+
@_image = Docker::Image.create('fromImage' => Config.lbaas[:image])
|
26
|
+
end
|
27
|
+
|
28
|
+
def create!
|
29
|
+
port_bindings = Hash.new
|
30
|
+
self.image.json['ContainerConfig']['ExposedPorts'].keys.each do |port|
|
31
|
+
port_bindings[port] = [ { 'HostPort' => "#{port.split('/').first}" } ]
|
32
|
+
end
|
33
|
+
@_container_def = {
|
34
|
+
'Image' => self.image.json['Id'],
|
35
|
+
'name' => Config.lbaas[:name],
|
36
|
+
'Hostname' => Config.lbaas[:name],
|
37
|
+
'Env' => [ "ETCDCTL_ENDPOINT=#{Config.etcd[:endpoints].map { |e| "http://#{e}" }.join(',')}" ],
|
38
|
+
'RestartPolicy' => { 'Name' => 'never' },
|
39
|
+
'HostConfig' => {
|
40
|
+
'PortBindings' => port_bindings,
|
41
|
+
'NetworkMode' => Config.lbaas[:network]
|
42
|
+
}
|
43
|
+
}
|
44
|
+
if Config.lbaas[:log_dest] != ''
|
45
|
+
@_container_def['HostConfig']['LogConfig'] = {
|
46
|
+
'Type' => 'gelf',
|
47
|
+
'Config' => {
|
48
|
+
'gelf-address' => Config.lbaas[:log_dest],
|
49
|
+
'tag' => Socket.gethostbyname(Socket.gethostname).first + '/{{.Name}}/{{.ID}}'
|
50
|
+
}
|
51
|
+
}
|
52
|
+
end
|
53
|
+
@_container = Docker::Container.create(@_container_def)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def update!
|
58
|
+
begin
|
59
|
+
self.stop! && start = true if self.up?
|
60
|
+
self.remove!
|
61
|
+
self.pull!
|
62
|
+
self.create!
|
63
|
+
self.start! if start == true
|
64
|
+
rescue StandardError => e
|
65
|
+
Logger.error "UNCAUGHT EXCEPTION IN THREAD #{Thread.current[:name]}"
|
66
|
+
Logger.error [' ', e.class, e.message].join(' ')
|
67
|
+
Logger.error ' ' + e.backtrace.to_s
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def remove!
|
72
|
+
self.container.delete
|
73
|
+
end
|
74
|
+
|
75
|
+
def up?
|
76
|
+
self.container.json['State']['Running']
|
77
|
+
end
|
78
|
+
|
79
|
+
def start!
|
80
|
+
self.container.start
|
81
|
+
end
|
82
|
+
|
83
|
+
def stop!
|
84
|
+
self.container.stop
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -2,14 +2,13 @@ require 'optparse'
|
|
2
2
|
require 'json'
|
3
3
|
require 'yaml'
|
4
4
|
require 'etcd-tools'
|
5
|
-
require 'etcd-tools/
|
6
|
-
require 'port-authority/
|
5
|
+
# require 'etcd-tools/mixins'
|
6
|
+
require 'port-authority/etcd'
|
7
|
+
require 'port-authority/tool'
|
7
8
|
|
8
9
|
module PortAuthority
|
9
|
-
module
|
10
|
-
class
|
11
|
-
include PortAuthority::Util::Etcd
|
12
|
-
include EtcdTools::Etcd
|
10
|
+
module Tools
|
11
|
+
class ServiceList < PortAuthority::Tool
|
13
12
|
|
14
13
|
attr_reader :etcd
|
15
14
|
|
@@ -61,18 +60,15 @@ module PortAuthority
|
|
61
60
|
end.parse!
|
62
61
|
end
|
63
62
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
unless @network
|
68
|
-
$stderr.puts "Missing NETWORK_NAME!"
|
63
|
+
def run
|
64
|
+
unless @ARGS[0]
|
65
|
+
$stderr.puts 'Missing NETWORK_NAME!'
|
69
66
|
exit 1
|
70
67
|
end
|
71
|
-
@etcd = etcd_connect @options[:url]
|
72
|
-
end
|
73
68
|
|
74
|
-
|
75
|
-
|
69
|
+
@etcd = PortAuthority::Etcd.shell_cluster_connect(@options[:url])
|
70
|
+
|
71
|
+
services = @etcd.swarm_list_services(@ARGS[0], @options[:service_filter])
|
76
72
|
|
77
73
|
if @options[:output_yaml]
|
78
74
|
puts services.to_yaml
|
@@ -80,7 +76,7 @@ module PortAuthority
|
|
80
76
|
puts services.to_json
|
81
77
|
else
|
82
78
|
if @options[:ip_only]
|
83
|
-
services.each { |
|
79
|
+
services.each { |_, params| puts params['ip'] }
|
84
80
|
elsif @options[:ports]
|
85
81
|
services.each do |name, params|
|
86
82
|
params['ports'].each do |port|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: port-authority
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.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-
|
11
|
+
date: 2016-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: etcd
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
version: '0.4'
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 0.4.
|
42
|
+
version: 0.4.4
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -49,7 +49,7 @@ dependencies:
|
|
49
49
|
version: '0.4'
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 0.4.
|
52
|
+
version: 0.4.4
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: net-ping
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,25 +93,23 @@ dependencies:
|
|
93
93
|
description: CLI Tools for PortAuthority
|
94
94
|
email: radek.slavicinsky@gmail.com
|
95
95
|
executables:
|
96
|
+
- pa-lbaas-agent
|
96
97
|
- pa-service-list
|
97
|
-
- pa-manager
|
98
98
|
extensions: []
|
99
99
|
extra_rdoc_files: []
|
100
100
|
files:
|
101
|
-
- bin/pa-
|
101
|
+
- bin/pa-lbaas-agent
|
102
102
|
- bin/pa-service-list
|
103
103
|
- lib/port-authority.rb
|
104
|
-
- lib/port-authority/
|
105
|
-
- lib/port-authority/
|
106
|
-
- lib/port-authority/
|
107
|
-
- lib/port-authority/
|
108
|
-
- lib/port-authority/
|
109
|
-
- lib/port-authority/
|
110
|
-
- lib/port-authority/
|
111
|
-
- lib/port-authority/
|
112
|
-
- lib/port-authority/
|
113
|
-
- lib/port-authority/util/logger.rb
|
114
|
-
- lib/port-authority/util/vip.rb
|
104
|
+
- lib/port-authority/agent.rb
|
105
|
+
- lib/port-authority/agents/lbaas.rb
|
106
|
+
- lib/port-authority/config.rb
|
107
|
+
- lib/port-authority/etcd.rb
|
108
|
+
- lib/port-authority/logger.rb
|
109
|
+
- lib/port-authority/mechanism/floating_ip.rb
|
110
|
+
- lib/port-authority/mechanism/load_balancer.rb
|
111
|
+
- lib/port-authority/tool.rb
|
112
|
+
- lib/port-authority/tools/service_list.rb
|
115
113
|
homepage: https://github.com/prozeta/port-authority
|
116
114
|
licenses:
|
117
115
|
- GPLv2
|
@@ -132,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
130
|
version: '0'
|
133
131
|
requirements: []
|
134
132
|
rubyforge_project:
|
135
|
-
rubygems_version: 2.4.
|
133
|
+
rubygems_version: 2.4.8
|
136
134
|
signing_key:
|
137
135
|
specification_version: 4
|
138
136
|
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,49 +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
|
-
@semaphore = { log: Mutex.new }
|
17
|
-
@config = config
|
18
|
-
@exit = false
|
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') do
|
27
|
-
if @config[:debug]
|
28
|
-
@config[:debug] = false
|
29
|
-
else
|
30
|
-
@config[:debug] = true
|
31
|
-
end
|
32
|
-
end
|
33
|
-
Signal.trap('HUP') { @config = config }
|
34
|
-
end
|
35
|
-
|
36
|
-
def setup(proc_name, nice = -20)
|
37
|
-
debug 'setting process name'
|
38
|
-
if RUBY_VERSION >= '2.1'
|
39
|
-
Process.setproctitle(proc_name)
|
40
|
-
else
|
41
|
-
$0 = proc_name
|
42
|
-
end
|
43
|
-
debug 'setting process title'
|
44
|
-
Process.setpriority(Process::PRIO_PROCESS, 0, nice)
|
45
|
-
# FIXME: Process.daemon ...
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|