kldockeragent 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Rakefile +0 -0
- data/VERSION +1 -0
- data/bin/kldockeragent +41 -0
- data/kldockeragent.gemspec +14 -0
- data/lib/kldockeragent/agent.rb +151 -0
- data/lib/kldockeragent/api.rb +51 -0
- data/lib/kldockeragent/commands.rb +34 -0
- data/lib/kldockeragent/helper.rb +154 -0
- data/lib/kldockeragent/net.rb +23 -0
- data/lib/kldockeragent/notifier.rb +106 -0
- data/lib/kldockeragent/server.rb +43 -0
- data/lib/kldockeragent.rb +17 -0
- metadata +57 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8c505ae9e35342dd34f178dec5018675e204693b
|
4
|
+
data.tar.gz: 3853d4786fe5aadf6f631cd5cc461b7c8c5a27ee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2854427e5768d19dfc27896c8dea49745f81420479cc0ac7cb18003f1a831b2a63d9cb6fd2180df41fc0450274aeb6d441db43503512bb92b469af519f83e411
|
7
|
+
data.tar.gz: 652d7b08dbe57af4e2f0e272937eed0b29a9c6a80eb07669359a6082ed8b844fbaf70c1f481ce2f5cd45d73290cf9f77bf6fb137dcc82201113fad79bcf5421e
|
data/.gitignore
ADDED
data/Rakefile
ADDED
File without changes
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.5.0
|
data/bin/kldockeragent
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/kldockeragent'
|
4
|
+
|
5
|
+
def version?
|
6
|
+
File.read(File.dirname(__FILE__) + '/../VERSION').strip
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Trollop::options do
|
10
|
+
version "kldockeragent #{version?} (c) 2016 Kytoonlabs"
|
11
|
+
banner <<-EOS
|
12
|
+
Agent for KL Docker Agent configuration management tool.
|
13
|
+
Usage:
|
14
|
+
kldockeragent [options]
|
15
|
+
|
16
|
+
where [options] are:
|
17
|
+
EOS
|
18
|
+
opt :start, "Start the agent. If --daemon option is set true, then the agent will start as a daemon.", :short => '-s'
|
19
|
+
opt :stop, "Stop the daemon agent.", :short => '-t'
|
20
|
+
opt :restart, "Restart the daemon agent.", :short => '-r'
|
21
|
+
opt :status, "Print the status of the daemon agent.", :short => '-a'
|
22
|
+
end
|
23
|
+
|
24
|
+
if opts[:start]
|
25
|
+
if not KL::Agent.pid.nil?
|
26
|
+
puts "Agent is already running with PID #{KL::Agent.pid}"
|
27
|
+
else
|
28
|
+
opts[:daemon] = true
|
29
|
+
KL::Agent.start(opts)
|
30
|
+
end
|
31
|
+
elsif opts[:stop]
|
32
|
+
KL::Agent.stop(opts)
|
33
|
+
elsif opts[:restart]
|
34
|
+
KL.logger.info '[main] Restart Agent command detected.'
|
35
|
+
opts[:daemon] = true
|
36
|
+
KL::Agent.stop if KL::Agent.pid.to_i > 0
|
37
|
+
KL::Agent.start(opts)
|
38
|
+
elsif opts[:status]
|
39
|
+
KL::Agent.status
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'kldockeragent'
|
3
|
+
s.version = File.read(File.dirname(__FILE__) + '/VERSION').strip
|
4
|
+
s.date = File.mtime(File.dirname(__FILE__) + '/VERSION').strftime("%Y-%m-%d")
|
5
|
+
s.summary = "KL DockerAgent"
|
6
|
+
s.description = "Agent with REST Api to send information about docker containers"
|
7
|
+
s.authors = ["Kytoonlabs"]
|
8
|
+
s.email = 'admin@kytoonlabs.com'
|
9
|
+
s.homepage = 'https://kytoonlabs.com/tools/docker-agent'
|
10
|
+
s.license = 'MIT'
|
11
|
+
s.require_paths = ['lib']
|
12
|
+
s.executables << 'kldockeragent'
|
13
|
+
s.files = `git ls-files`.split("\n").select { |n| !(n =~ /^(modules|test)\/.*/) }
|
14
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'thread'
|
3
|
+
require 'uri'
|
4
|
+
require 'net/http'
|
5
|
+
require 'logger'
|
6
|
+
require 'json'
|
7
|
+
require 'digest/md5'
|
8
|
+
require 'shellwords'
|
9
|
+
require 'trollop'
|
10
|
+
require 'socket'
|
11
|
+
|
12
|
+
module KL
|
13
|
+
module Agent
|
14
|
+
|
15
|
+
PIDFile = "#{KL.home}/kldockeragent.pid"
|
16
|
+
|
17
|
+
@@notifier_engine = KL::Notifier.new
|
18
|
+
@@web_server = KL::Server.new
|
19
|
+
|
20
|
+
@@global_app_uuid = KL.getApplicationId
|
21
|
+
|
22
|
+
# Start the agent.
|
23
|
+
#
|
24
|
+
# options:
|
25
|
+
# :daemon => true if running as a daemon, false if as a console application
|
26
|
+
# :port => port of web server will listen to
|
27
|
+
# :ssl => set true to enable HTTPS
|
28
|
+
# :certfile => certificate file path for HTTPS
|
29
|
+
# :keyfile => key file path for HTTPS
|
30
|
+
#
|
31
|
+
def self.start(opts={})
|
32
|
+
KL.logger.info "[main] Starting agent: #{KL::Agent.getUUID}"
|
33
|
+
puts "Starting agent..."
|
34
|
+
|
35
|
+
@@config = opts
|
36
|
+
|
37
|
+
Process.daemon if opts[:daemon] and not opts[:mock]
|
38
|
+
begin
|
39
|
+
if not is_windows
|
40
|
+
# trap signal
|
41
|
+
['INT', 'KILL', 'HUP'].each do |signal|
|
42
|
+
trap(signal) {
|
43
|
+
KL.logger.info "[main] Shutting down services..."
|
44
|
+
web_server.stop
|
45
|
+
notifier_engine.stop
|
46
|
+
loop do
|
47
|
+
break if notifier_engine.status == :stopped
|
48
|
+
sleep 1
|
49
|
+
end
|
50
|
+
|
51
|
+
self.close
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
File.open(PIDFile, 'w', 0644) { |f| f.write($$.to_s) }
|
57
|
+
|
58
|
+
notifier_engine.start
|
59
|
+
web_server.start
|
60
|
+
|
61
|
+
@@main_enabled = true
|
62
|
+
while @@main_enabled; end
|
63
|
+
|
64
|
+
rescue Exception => e
|
65
|
+
KL.logger.error "Starting the agent [Failed] #{e}\n#{e.backtrace.join("\n")}"
|
66
|
+
raise e
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Stop the agent's daemon.
|
71
|
+
#
|
72
|
+
def self.stop(opts={})
|
73
|
+
begin
|
74
|
+
pid = File.read(PIDFile).to_i
|
75
|
+
puts "Stopping agent with PID #{pid}..."
|
76
|
+
Process.kill 'HUP', pid
|
77
|
+
|
78
|
+
if not opts[:mock]
|
79
|
+
begin
|
80
|
+
sleep (KL::Notifier::SleepTime + 0.5)
|
81
|
+
|
82
|
+
Process.kill 0, pid
|
83
|
+
KL.logger.info "[main] Agent is still running."
|
84
|
+
puts "Agent is still running."
|
85
|
+
|
86
|
+
KL.logger.info "[main] Killing agent."
|
87
|
+
puts "Killing agent."
|
88
|
+
Process.kill 9, pid
|
89
|
+
rescue
|
90
|
+
KL.logger.info "[main] Agent has stopped."
|
91
|
+
puts "Agent has stopped."
|
92
|
+
File.delete(PIDFile) if File.exist?(PIDFile)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
rescue
|
97
|
+
puts "Agent is not running."
|
98
|
+
File.delete(PIDFile) if File.exist?(PIDFile)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.pid
|
103
|
+
begin
|
104
|
+
pid = File.read(PIDFile).to_i
|
105
|
+
return pid if Process.kill 0, pid
|
106
|
+
rescue
|
107
|
+
end
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
|
111
|
+
# Return agent's PID if it is running, otherwise nil.
|
112
|
+
#
|
113
|
+
def self.status
|
114
|
+
if pid.nil?
|
115
|
+
puts "Agent is not running."
|
116
|
+
else
|
117
|
+
puts "Agent is running with PID #{pid}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.is_windows
|
122
|
+
(RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.is_linux
|
126
|
+
(RbConfig::CONFIG['host_os'] =~ /linux/)
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.notifier_engine
|
130
|
+
@@notifier_engine
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.web_server
|
134
|
+
@@web_server
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.close
|
138
|
+
KL.logger.info "[main] Stopping agent..."
|
139
|
+
@@main_enabled = false
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.getUUID
|
143
|
+
@@global_app_uuid
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.getVersion
|
147
|
+
File.read(File.dirname(__FILE__) + '/../../VERSION').strip
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'webrick'
|
3
|
+
require 'webrick/https'
|
4
|
+
require 'webrick/ssl'
|
5
|
+
require 'openssl'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
class KL::Api < Sinatra::Base
|
9
|
+
|
10
|
+
before do
|
11
|
+
halt 503 if !KL.server_registered
|
12
|
+
pass if ['ping'].include? request.path_info.split('/')[1]
|
13
|
+
if env['HTTP_AUTHORIZATION'] && env['HTTP_AUTHORIZATION'].split(':').length == 2
|
14
|
+
auth_header = env['HTTP_AUTHORIZATION'].split(':')
|
15
|
+
else
|
16
|
+
halt 401
|
17
|
+
end
|
18
|
+
public_key = auth_header[0]
|
19
|
+
signature = auth_header[1]
|
20
|
+
|
21
|
+
registry = KL.getRegistryData
|
22
|
+
|
23
|
+
halt 403 if public_key != registry['server']
|
24
|
+
|
25
|
+
data = request.path
|
26
|
+
data = "#{data}?#{request.query_string}" if request.query_string != ""
|
27
|
+
|
28
|
+
if ['POST', 'PUT', 'PATCH'].include? request.request_method
|
29
|
+
request.body.rewind
|
30
|
+
data += request.body.read
|
31
|
+
end
|
32
|
+
|
33
|
+
computed_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), registry['agent'], data)
|
34
|
+
if computed_signature == signature
|
35
|
+
KL.logger.info "[api] #{request.request_method} #{request.path}"
|
36
|
+
pass
|
37
|
+
else
|
38
|
+
halt 403
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
get '/ping' do
|
43
|
+
KL.logger.info "[api] Pong! to #{request.ip}"
|
44
|
+
'Pong: ' + `date`
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/api/v1/applications' do
|
48
|
+
KL.publish_json(KL.Request_getDockerListAllApplications)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module KL
|
2
|
+
def KL.Command_registerNewAgent
|
3
|
+
KL.logger.info '[command] Registering new agent...'
|
4
|
+
agent = KL::Agent.getUUID
|
5
|
+
data = KL.prepare_agent_register_data(agent)
|
6
|
+
uri = "#{KL.config['notifier']['server']}/api/1.0/nodes/register"
|
7
|
+
res = KL.net_post_json(uri, data.to_json)
|
8
|
+
|
9
|
+
if res.is_a?(Net::HTTPSuccess)
|
10
|
+
response = JSON.parse(res.body)
|
11
|
+
registry = {
|
12
|
+
agent: agent,
|
13
|
+
server: response['code']
|
14
|
+
}
|
15
|
+
KL.create_registry_file(registry)
|
16
|
+
KL.logger.info '[command] Agent registration has been completed correctly'
|
17
|
+
else
|
18
|
+
KL.logger.info '[command] An error has occurred trying to register agent.'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def KL.Command_notifyStatus
|
23
|
+
KL.logger.info '[command] Sending instance update...'
|
24
|
+
data = KL.prepare_agent_data
|
25
|
+
uri = "#{KL.config['notifier']['server']}/api/1.0/nodes/data"
|
26
|
+
headers_auth = KL.getAuthorizationHeaders('/api/1.0/nodes/data', data.to_json)
|
27
|
+
res = KL.net_post_json(uri, data.to_json, headers_auth)
|
28
|
+
if res.is_a?(Net::HTTPSuccess)
|
29
|
+
KL.logger.info '[command] Agent notification successfully executed.'
|
30
|
+
else
|
31
|
+
KL.logger.info '[command] An error has occurred trying to notify update.'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
require 'webrick/https'
|
3
|
+
require 'usagewatch'
|
4
|
+
|
5
|
+
module KL
|
6
|
+
def KL.create_default_config(file, logger)
|
7
|
+
File.open(file, File::RDWR|File::CREAT, 0644) { |f|
|
8
|
+
f.flock(File::LOCK_EX)
|
9
|
+
value = '{"api":{"port":3344,"ssl":false},"notifier":{"server":"https://hub.kytoonlabs.com:4444","rate":120}}'
|
10
|
+
f.rewind
|
11
|
+
f.write(value.to_s)
|
12
|
+
f.flush
|
13
|
+
f.truncate(f.pos)
|
14
|
+
}
|
15
|
+
logger.info "[config] Default config file has been created at {#{file}}" if logger
|
16
|
+
end
|
17
|
+
|
18
|
+
def KL.logger
|
19
|
+
home = KL.home
|
20
|
+
Dir.mkdir(home, 0700) if not File.exist?(home)
|
21
|
+
logFile = "#{home}/kldockeragent.log"
|
22
|
+
log = WEBrick::Log.new(logFile, WEBrick::BasicLog::INFO ||
|
23
|
+
WEBrick::BasicLog::ERROR ||
|
24
|
+
WEBrick::BasicLog::FATAL ||
|
25
|
+
WEBrick::BasicLog::WARN)
|
26
|
+
log
|
27
|
+
end
|
28
|
+
|
29
|
+
def KL.home
|
30
|
+
home = ((Process.euid == 0 and File.directory?('/var')) ? '/var/kldockerpagent' : File.expand_path(Dir.home + '/.kldockeragent'))
|
31
|
+
home
|
32
|
+
end
|
33
|
+
|
34
|
+
def KL.config
|
35
|
+
configFile = "#{KL.home}/kldockeragent.json"
|
36
|
+
KL.create_default_config(configFile, KL.logger) if !File.exist?(configFile)
|
37
|
+
config_json = File.read(configFile)
|
38
|
+
config_data = JSON.parse(config_json)
|
39
|
+
config_data
|
40
|
+
end
|
41
|
+
|
42
|
+
def KL.server_registered
|
43
|
+
registryFile = "#{KL.home}/kldockeragent.registry"
|
44
|
+
reg = File.exist?(registryFile)
|
45
|
+
reg
|
46
|
+
end
|
47
|
+
|
48
|
+
def KL.publish_json(json_object, st = 200)
|
49
|
+
status st
|
50
|
+
content_type :json
|
51
|
+
json_object.to_json
|
52
|
+
end
|
53
|
+
def KL.prepare_agent_register_data(hash)
|
54
|
+
data = {
|
55
|
+
private_hash: hash,
|
56
|
+
hostname: `hostname`.gsub("\n",""),
|
57
|
+
system_info: `uname -a`.gsub("\n",""),
|
58
|
+
docker_version: `docker --version`.gsub("\n","").gsub("Docker version ",""),
|
59
|
+
agent_version: KL::Agent.getVersion,
|
60
|
+
ip_address: IPSocket.getaddress(Socket.gethostname)
|
61
|
+
}
|
62
|
+
data
|
63
|
+
end
|
64
|
+
|
65
|
+
def KL.create_registry_file(data)
|
66
|
+
file = "#{KL.home}/kldockeragent.registry"
|
67
|
+
File.open(file, File::RDWR|File::CREAT, 0644) { |f|
|
68
|
+
f.flock(File::LOCK_EX)
|
69
|
+
f.rewind
|
70
|
+
f.write(data.to_json.to_s)
|
71
|
+
f.flush
|
72
|
+
f.truncate(f.pos)
|
73
|
+
}
|
74
|
+
logger.info "[config] Registry config file has been created at {#{file}}" if logger
|
75
|
+
end
|
76
|
+
|
77
|
+
def KL.getRegistryData
|
78
|
+
json_reg = JSON.parse(File.open("#{KL.home}/kldockeragent.registry").read)
|
79
|
+
json_reg
|
80
|
+
end
|
81
|
+
|
82
|
+
def KL.getApplicationId
|
83
|
+
if (KL.server_registered)
|
84
|
+
registry = KL.getRegistryData
|
85
|
+
id = registry['agent']
|
86
|
+
else
|
87
|
+
id = SecureRandom.uuid
|
88
|
+
end
|
89
|
+
id
|
90
|
+
end
|
91
|
+
|
92
|
+
def KL.getAuthorizationHeaders(url, json_data)
|
93
|
+
headers = {}
|
94
|
+
if (KL.server_registered)
|
95
|
+
registry = KL.getRegistryData
|
96
|
+
hash_data = KL.generateHash(url, json_data, registry['agent'])
|
97
|
+
auth_code = "#{registry['server']}:#{hash_data}"
|
98
|
+
headers = {}
|
99
|
+
headers['Authorization'] = auth_code
|
100
|
+
end
|
101
|
+
headers
|
102
|
+
end
|
103
|
+
|
104
|
+
def KL.generateHash(url, json_data, private_key)
|
105
|
+
data = "#{url}#{json_data}"
|
106
|
+
hash_data = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), private_key, data)
|
107
|
+
hash_data
|
108
|
+
end
|
109
|
+
|
110
|
+
def KL.prepare_agent_data
|
111
|
+
data = {
|
112
|
+
system_info: KL.Request_getSystemInfo,
|
113
|
+
docker_info: KL.Request_getDockerListAllApplications,
|
114
|
+
agent_version: KL::Agent.getVersion
|
115
|
+
}
|
116
|
+
data
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
def KL.Request_getDockerListAllApplications
|
121
|
+
filter = '_klac'
|
122
|
+
apps = Array.new
|
123
|
+
query = `docker ps --filter="name=#{filter}" --format="{{.ID}}::{{.Names}}::{{.Status}}::{{.Image}}"`
|
124
|
+
query.gsub!(/\r\n?/, "\n")
|
125
|
+
query.each_line do |line|
|
126
|
+
data = line.split('::')
|
127
|
+
apps.push({
|
128
|
+
'id' => data[0],
|
129
|
+
'name' => data[1].gsub(filter,""),
|
130
|
+
'status'=>data[2],
|
131
|
+
'image'=>data[3].gsub("\n","")
|
132
|
+
})
|
133
|
+
end
|
134
|
+
return apps
|
135
|
+
end
|
136
|
+
|
137
|
+
def KL.Request_getSystemInfo
|
138
|
+
usw = Usagewatch
|
139
|
+
info = {}
|
140
|
+
if KL::Agent.is_linux
|
141
|
+
info['os'] = 'linux'
|
142
|
+
info['diskused'] = usw.uw_diskused
|
143
|
+
info['diskused_perc'] = usw.uw_diskused_perc
|
144
|
+
info['cpuused'] = usw.uw_cpuused
|
145
|
+
info['memused'] = usw.uw_memused
|
146
|
+
info['cputop'] = usw.uw_cputop
|
147
|
+
info['memtop'] = usw.uw_memtop
|
148
|
+
else
|
149
|
+
info['os'] = 'not linux'
|
150
|
+
end
|
151
|
+
info
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module KL
|
4
|
+
def KL.net_post_json(url, data, headers = [])
|
5
|
+
KL.logger.info "[net] Posting JSON to #{url} => #{data}"
|
6
|
+
|
7
|
+
uri = URI(url)
|
8
|
+
|
9
|
+
req = Net::HTTP::Post.new(uri)
|
10
|
+
req.content_type = 'application/json'
|
11
|
+
req.body = data
|
12
|
+
req['X-Kytoonlabs-Docker-Agent'] = KL::Agent.getUUID[0..13].gsub(/\s\w+\s*$/, '')
|
13
|
+
headers.each do |key, value|
|
14
|
+
req[key] = value
|
15
|
+
end
|
16
|
+
|
17
|
+
Net::HTTP.start(uri.hostname, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
18
|
+
@res = http.request req
|
19
|
+
end
|
20
|
+
KL.logger.info "[net] Response Code: #{@res.code}, Response Body: #{@res.body}"
|
21
|
+
@res
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
class KL::Notifier
|
4
|
+
|
5
|
+
SleepTime = 10
|
6
|
+
|
7
|
+
NotifierLockFile = "#{KL.home}/notifier.lock.#{Time.now.to_i}"
|
8
|
+
|
9
|
+
attr_reader :enabled, :status, :mode
|
10
|
+
|
11
|
+
def initialize(p={})
|
12
|
+
@lock = Mutex.new
|
13
|
+
@enabled = false
|
14
|
+
@status = :stopped
|
15
|
+
@index = 0
|
16
|
+
config = KL.config
|
17
|
+
@rate = config['notifier']['rate']
|
18
|
+
end
|
19
|
+
|
20
|
+
def stop
|
21
|
+
@enabled = false
|
22
|
+
end
|
23
|
+
|
24
|
+
def start
|
25
|
+
@enabled = true
|
26
|
+
@lock.synchronize {
|
27
|
+
return if @status == :running
|
28
|
+
@status = :running
|
29
|
+
}
|
30
|
+
Thread.new {
|
31
|
+
begin
|
32
|
+
register_notifier_thread(:reset)
|
33
|
+
|
34
|
+
system("rm -f #{KL.home}/operator.*.lock")
|
35
|
+
system("rm -f #{KL.home}/notifier.lock.*")
|
36
|
+
|
37
|
+
KL.logger.info "[notifier] Notifier engine is running"
|
38
|
+
|
39
|
+
self.run_notifier
|
40
|
+
|
41
|
+
File.delete(NotifierLockFile) if File.exist?(NotifierLockFile)
|
42
|
+
KL.logger.info "[notifier] Notifier engine has stopped."
|
43
|
+
|
44
|
+
rescue Exception => exp
|
45
|
+
KL.logger.error "Cannot start notifier engine => #{exp}\n#{exp.backtrace.join("\n")}"
|
46
|
+
end
|
47
|
+
@status = :stopped
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def run_notifier
|
52
|
+
KL.logger.info "[notifier] Executing notifier engine every #{@rate} seconds"
|
53
|
+
while @enabled
|
54
|
+
begin
|
55
|
+
wait_for_notifier?
|
56
|
+
|
57
|
+
notify_data
|
58
|
+
|
59
|
+
sleep SleepTime
|
60
|
+
|
61
|
+
rescue Exception => e
|
62
|
+
KL.logger.error "Error on executing notifier \n#{e}\n#{e.backtrace.join("\n")}"
|
63
|
+
sleep SleepTime
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def register_notifier_thread(mode=nil)
|
69
|
+
File.open(NotifierLockFile, File::RDWR|File::CREAT, 0644) { |f|
|
70
|
+
f.flock(File::LOCK_EX)
|
71
|
+
value = (mode == :reset ? 0 : (f.read.to_i + 1))
|
72
|
+
f.rewind
|
73
|
+
f.write(value.to_s)
|
74
|
+
f.flush
|
75
|
+
f.truncate(f.pos)
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def wait_for_notifier?
|
80
|
+
total_notifier = 1
|
81
|
+
loop do
|
82
|
+
total_notifier = (File.exist?(NotifierLockFile) ? File.read(NotifierLockFile).to_i : 0)
|
83
|
+
return if total_notifier <= 0 or not @enabled
|
84
|
+
sleep 1
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def notify_data
|
89
|
+
KL.logger.info "[heartbeat]"
|
90
|
+
if KL.server_registered
|
91
|
+
if (@index <= (@rate/SleepTime))
|
92
|
+
@index = @index + 1
|
93
|
+
else
|
94
|
+
@index = 0
|
95
|
+
KL.logger.info "[notifier] Executing notifier..."
|
96
|
+
KL.Command_notifyStatus
|
97
|
+
KL.logger.info "[notifier] Notifier executed."
|
98
|
+
end
|
99
|
+
else
|
100
|
+
KL.logger.info "[notifier] Executing notifier..."
|
101
|
+
KL.Command_registerNewAgent
|
102
|
+
KL.logger.info "[notifier] Notifier executed."
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
require 'webrick/https'
|
3
|
+
require 'openssl'
|
4
|
+
require 'rack/ssl'
|
5
|
+
|
6
|
+
class KL::Server
|
7
|
+
def initialize
|
8
|
+
@config = KL.config
|
9
|
+
if @config['api']['ssl']
|
10
|
+
options = {
|
11
|
+
:Port => @config['api']['port'],
|
12
|
+
:SSLEnable => true,
|
13
|
+
:SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
|
14
|
+
:SSLCertificate => OpenSSL::X509::Certificate.new(File.open(@config['api']['cert']['crt']).read),
|
15
|
+
:SSLPrivateKey => OpenSSL::PKey::RSA.new(File.open(@config['api']['cert']['key']).read),
|
16
|
+
:SSLCertName => [[ "CN", WEBrick::Utils::getservername ]]
|
17
|
+
}
|
18
|
+
else
|
19
|
+
options = {
|
20
|
+
:Port => @config['api']['port'],
|
21
|
+
:SSLEnable => false
|
22
|
+
}
|
23
|
+
end
|
24
|
+
@webrick_options = options
|
25
|
+
@server = ::Rack::Handler::WEBrick
|
26
|
+
end
|
27
|
+
def start
|
28
|
+
KL.logger.info '[server] Starting web server...'
|
29
|
+
Thread.new {
|
30
|
+
@server.run KL::Api, @webrick_options
|
31
|
+
}
|
32
|
+
if (@config['api']['ssl'])
|
33
|
+
msg = "[server] Web server listening on #{@config['api']['port']} with SSL"
|
34
|
+
else
|
35
|
+
msg = "[server] Web server listening on #{@config['api']['port']}"
|
36
|
+
end
|
37
|
+
KL.logger.info msg
|
38
|
+
end
|
39
|
+
def stop
|
40
|
+
@server.shutdown
|
41
|
+
KL.logger.info '[server] Web server has stopped.'
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# external dependencies
|
2
|
+
require 'rubygems'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module KL
|
6
|
+
end
|
7
|
+
|
8
|
+
# internal dependencies
|
9
|
+
libdir = File.expand_path(File.dirname(__FILE__))
|
10
|
+
|
11
|
+
require libdir + '/kldockeragent/net.rb'
|
12
|
+
require libdir + '/kldockeragent/commands.rb'
|
13
|
+
require libdir + '/kldockeragent/helper.rb'
|
14
|
+
require libdir + '/kldockeragent/api.rb'
|
15
|
+
require libdir + '/kldockeragent/server.rb'
|
16
|
+
require libdir + '/kldockeragent/notifier.rb'
|
17
|
+
require libdir + '/kldockeragent/agent.rb'
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kldockeragent
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kytoonlabs
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-11 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Agent with REST Api to send information about docker containers
|
14
|
+
email: admin@kytoonlabs.com
|
15
|
+
executables:
|
16
|
+
- kldockeragent
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".gitignore"
|
21
|
+
- Rakefile
|
22
|
+
- VERSION
|
23
|
+
- bin/kldockeragent
|
24
|
+
- kldockeragent.gemspec
|
25
|
+
- lib/kldockeragent.rb
|
26
|
+
- lib/kldockeragent/agent.rb
|
27
|
+
- lib/kldockeragent/api.rb
|
28
|
+
- lib/kldockeragent/commands.rb
|
29
|
+
- lib/kldockeragent/helper.rb
|
30
|
+
- lib/kldockeragent/net.rb
|
31
|
+
- lib/kldockeragent/notifier.rb
|
32
|
+
- lib/kldockeragent/server.rb
|
33
|
+
homepage: https://kytoonlabs.com/tools/docker-agent
|
34
|
+
licenses:
|
35
|
+
- MIT
|
36
|
+
metadata: {}
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
requirements: []
|
52
|
+
rubyforge_project:
|
53
|
+
rubygems_version: 2.0.14.1
|
54
|
+
signing_key:
|
55
|
+
specification_version: 4
|
56
|
+
summary: KL DockerAgent
|
57
|
+
test_files: []
|