cloud66_agent 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/cloud66_agent.gemspec +1 -1
- data/lib/cloud66_agent/commands/configure.rb +46 -40
- data/lib/cloud66_agent/commands/vitals.rb +2 -2
- data/lib/cloud66_agent/utils/config.rb +121 -111
- data/lib/cloud66_agent/utils/server.rb +74 -74
- data/lib/cloud66_agent/utils/version.rb +1 -1
- data/lib/cloud66_agent/utils/vital_signs.rb +111 -85
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c38dc8b98765dbcd9303528cc6ff8c57013613c1908b259e73c0b17d5f1327c7
|
4
|
+
data.tar.gz: 930f568ce197cf07f061f026af19231b6050486769450f617049449451b44e50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00c8fa84e68deea570a160aa7aa9eca9286312c35dad0b44e7700a7cb793f753a03f99f1a311be63aa666b918c1c9a1c42f7fc2d174386f9a6482f399cdd47fa
|
7
|
+
data.tar.gz: affeb9cb1ef085b1db0f8ff18e366b4e7e7af408c6fed305eb637587a46b315a22a9d7b9353288ed6fd741fda2331b16bb2eb7db7f00fb783339772f606c5854
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.4.
|
1
|
+
ruby-2.4.5
|
data/cloud66_agent.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |gem|
|
|
7
7
|
gem.name = "cloud66_agent"
|
8
8
|
gem.version = Cloud66::Utils::Version.current
|
9
9
|
gem.platform = Gem::Platform::RUBY
|
10
|
-
gem.date = '
|
10
|
+
gem.date = '2019-03-27'
|
11
11
|
gem.authors = ["Cloud 66"]
|
12
12
|
gem.email = ['hello@cloud66.com']
|
13
13
|
gem.licenses = ['MIT']
|
@@ -3,48 +3,54 @@ require 'cloud66_agent/utils/version'
|
|
3
3
|
require 'cloud66_agent/utils/server'
|
4
4
|
|
5
5
|
module Cloud66
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
module Commands
|
7
|
+
class Configure
|
8
|
+
def self.perform(server_uid, cloud)
|
9
|
+
begin
|
10
|
+
if cloud.nil? || cloud.empty?
|
11
|
+
# try figure it out
|
12
|
+
$config.is_aws = Utils::VitalSigns.is_aws?
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
if $config.is_aws
|
15
|
+
$config.is_gc = false
|
16
|
+
else
|
17
|
+
# try figure it out
|
18
|
+
$config.is_gc = Utils::VitalSigns.is_gc?
|
19
|
+
end
|
20
|
+
else
|
21
|
+
# use the passed in value
|
22
|
+
$config.is_aws = (cloud == 'aws')
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
# use the passed in value
|
25
|
+
$config.is_gc = (cloud == 'googlecloud')
|
26
|
+
end
|
27
|
+
data = {
|
28
|
+
:timezone => Time.new.zone,
|
29
|
+
:server_uid => server_uid,
|
30
|
+
:version => Utils::Version.current,
|
31
|
+
:system => Utils::VitalSigns.system_info}
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
$config.disabled = false
|
41
|
-
$config.save
|
42
|
-
exit 0
|
43
|
-
rescue => exc
|
44
|
-
$logger.error "Command \"configure\" failed: #{exc.message}"
|
45
|
-
exit -1
|
46
|
-
end
|
33
|
+
address_info = Utils::VitalSigns.address_info
|
34
|
+
data = data.merge(address_info)
|
35
|
+
rescue => exc
|
36
|
+
data = {error: exc.message}
|
37
|
+
end
|
38
|
+
result = Utils::Server.send_configure data
|
39
|
+
$config.agent_uid = result['agent_uid']
|
47
40
|
|
48
|
-
|
49
|
-
|
41
|
+
disk_warning_percent = result['disk_warning_percent']
|
42
|
+
$config.disk_warning_percent = disk_warning_percent.to_i unless disk_warning_percent.nil?
|
43
|
+
disk_critical_percent = result['disk_critical_percent']
|
44
|
+
$config.disk_critical_percent = disk_critical_percent.to_i unless disk_critical_percent.nil?
|
45
|
+
|
46
|
+
$config.disabled = false
|
47
|
+
$config.save
|
48
|
+
exit 0
|
49
|
+
rescue => exc
|
50
|
+
$logger.error "Command \"configure\" failed: #{exc.message}"
|
51
|
+
exit -1
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
50
56
|
end
|
@@ -6,11 +6,11 @@ module Cloud66
|
|
6
6
|
class Vitals
|
7
7
|
def self.perform
|
8
8
|
begin
|
9
|
-
data = Utils::VitalSigns.
|
9
|
+
data = Utils::VitalSigns.vitals_alerts
|
10
10
|
rescue => exc
|
11
11
|
data = { error: exc.message }
|
12
12
|
end
|
13
|
-
Utils::Server.send_vitals data
|
13
|
+
Utils::Server.send_vitals(data) if !data.nil? && !data.empty?
|
14
14
|
exit 0
|
15
15
|
rescue => exc
|
16
16
|
$logger.error "Command \"vitals\" failed: #{exc.message}"
|
@@ -1,115 +1,125 @@
|
|
1
1
|
require 'cloud66_agent/utils/vital_signs'
|
2
2
|
|
3
3
|
module Cloud66
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
4
|
+
module Utils
|
5
|
+
class Config
|
6
|
+
|
7
|
+
# default conf dir
|
8
|
+
CONFIG_PATH = "/etc/cloud66/cloud66_agent.yml"
|
9
|
+
|
10
|
+
attr_accessor :api_url,
|
11
|
+
:api_key,
|
12
|
+
:secret_key,
|
13
|
+
:agent_uid,
|
14
|
+
:disabled,
|
15
|
+
:is_aws,
|
16
|
+
:is_gc,
|
17
|
+
:log,
|
18
|
+
:log_level,
|
19
|
+
:disk_warning_percent,
|
20
|
+
:disk_critical_percent
|
21
|
+
|
22
|
+
# load up the config at startup
|
23
|
+
def initialize
|
24
|
+
load if File.exists?(CONFIG_PATH)
|
25
|
+
|
26
|
+
# set defaults
|
27
|
+
@log = @log.nil? ? "/var/log/cloud66_agent.log" : @log == "STDOUT" ? STDOUT : @log
|
28
|
+
@log_level ||= 2
|
29
|
+
@api_url ||= 'https://api.cloud66.com'
|
30
|
+
@disabled ||= false
|
31
|
+
@is_aws ||= false
|
32
|
+
@is_gc ||= false
|
33
|
+
|
34
|
+
# defaults
|
35
|
+
@disk_warning_percent = 80
|
36
|
+
@disk_critical_percent = 90
|
37
|
+
end
|
38
|
+
|
39
|
+
def is_agent_configured?
|
40
|
+
return !@agent_uid.nil? && !@agent_uid.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
def save
|
44
|
+
Dir.mkdir(CONFIG_PATH) if !FileTest::directory?(File.dirname(CONFIG_PATH))
|
45
|
+
|
46
|
+
File.open(CONFIG_PATH, 'w+') do |out|
|
47
|
+
data = {
|
48
|
+
'api_url' => @api_url,
|
49
|
+
'api_key' => @api_key,
|
50
|
+
'secret_key' => @secret_key,
|
51
|
+
'agent_uid' => @agent_uid,
|
52
|
+
'disabled' => @disabled,
|
53
|
+
'is_aws' => @is_aws,
|
54
|
+
'is_gc' => @is_gc,
|
55
|
+
'log' => @log == STDOUT ? "STDOUT" : @log,
|
56
|
+
'log_level' => @log_level,
|
57
|
+
'disk_warning_percent' => @disk_warning_percent,
|
58
|
+
'disk_critical_percent' => @disk_critical_percent,
|
59
|
+
}
|
60
|
+
out.puts to_cust_yaml(data)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def delete
|
65
|
+
File.delete(CONFIG_PATH) if File.exists?(CONFIG_PATH)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def load
|
71
|
+
raise "config not found" unless File.exists?(CONFIG_PATH)
|
72
|
+
config = from_cust_yaml(IO.read(CONFIG_PATH))
|
73
|
+
@api_url = config['api_url']
|
74
|
+
@api_key = config['api_key']
|
75
|
+
@secret_key = config['secret_key']
|
76
|
+
@agent_uid = config['agent_uid']
|
77
|
+
@disabled = config['disabled']
|
78
|
+
@is_aws = config['is_aws']
|
79
|
+
@is_gc = config['is_gc']
|
80
|
+
@log = config['log']
|
81
|
+
@log_level = config['log_level']
|
82
|
+
@disk_warning_percent = config['disk_warning_percent'].to_i if config['disk_warning_percent']
|
83
|
+
@disk_critical_percent = config['disk_critical_percent'].to_i if config['disk_critical_percent']
|
84
|
+
rescue
|
85
|
+
# we can't load the file
|
86
|
+
end
|
87
|
+
|
88
|
+
# temporary measure to handle psych dependency errors
|
89
|
+
def to_cust_yaml(hash)
|
90
|
+
yaml_output = ''
|
91
|
+
hash.each do |key, value|
|
92
|
+
if !!value == value || value.is_a?(Integer)
|
93
|
+
yaml_output += "#{key}: #{value.to_s}\n"
|
94
|
+
else
|
95
|
+
yaml_output += "#{key}: \"#{value.to_s}\"\n"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
return yaml_output
|
99
|
+
end
|
100
|
+
|
101
|
+
# temporary measure to handle psych dependency errors
|
102
|
+
def from_cust_yaml(yaml)
|
103
|
+
hash = {}
|
104
|
+
yaml.lines.each do |line|
|
105
|
+
next if line.nil? || !line.include?(':')
|
106
|
+
key = line.split(':', 2)[0].strip
|
107
|
+
value = line.split(':', 2)[1].strip
|
108
|
+
next if value.empty?
|
109
|
+
|
110
|
+
if value =~ /^(true|false)$/
|
111
|
+
value = true if value == 'true'
|
112
|
+
value = false if value == 'false'
|
113
|
+
elsif value =~ /^[0-9]+$/
|
114
|
+
value = value.to_i
|
115
|
+
elsif value =~ /^".*"$/
|
116
|
+
value = value.gsub(/^"/, '').gsub(/"$/, '')
|
117
|
+
end
|
118
|
+
hash[key] = value
|
119
|
+
end
|
120
|
+
return hash
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
115
125
|
end
|
@@ -2,92 +2,92 @@ require 'httparty'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
module Cloud66
|
5
|
-
|
5
|
+
module Utils
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
class Server
|
8
|
+
include HTTParty
|
9
|
+
# set the default request timeout to 45 seconds
|
10
|
+
# this sets the open_timeout and the read_timeout
|
11
|
+
default_timeout 45
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
def self.send_configure(data)
|
14
|
+
process(do_request(:post, '/server/configure.json', build_content(data)))
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
def self.send_pulse
|
18
|
+
process(do_request(:get, "/server/#{$config.agent_uid}/pulse.json", build_content))
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def self.send_address(data)
|
22
|
+
process(do_request(:post, "/server/#{$config.agent_uid}/address.json", build_content(data)))
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def self.send_vitals(data)
|
26
|
+
process(do_request(:post, "/server/#{$config.agent_uid}/vitals_alerts.json", build_content(data)))
|
27
|
+
end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
def self.send_job_start(job_uid)
|
30
|
+
process(do_request(:get, "/job/#{job_uid}/start.json", build_content))
|
31
|
+
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
def self.send_job_end(job_uid, data)
|
34
|
+
process(do_request(:post, "/job/#{job_uid}/end.json", build_content(data)))
|
35
|
+
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
def self.send_fail2ban(data)
|
38
|
+
process(do_request(:post, "/server/#{$config.agent_uid}/fail2ban.json", build_content(data)))
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
def self.send_message(data)
|
42
|
+
#puts data
|
43
|
+
process(do_request(:post, "/server/#{$config.agent_uid}/message.json", build_content(data)))
|
44
|
+
end
|
45
45
|
|
46
|
-
|
46
|
+
private
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
48
|
+
def self.process(response)
|
49
|
+
$logger.debug "Received response!"
|
50
|
+
if response.code != 200
|
51
|
+
$logger.debug "Response code: #{response.code}"
|
52
|
+
$logger.debug "Response body: #{response.body}"
|
53
|
+
raise response.body
|
54
|
+
else
|
55
|
+
parsed_response = response.parsed_response
|
56
|
+
unless parsed_response['ok']
|
57
|
+
if parsed_response['shut_down']
|
58
|
+
$config.disabled = true
|
59
|
+
$config.save
|
60
|
+
exit 86
|
61
|
+
elsif parsed_response.has_key?('error')
|
62
|
+
raise parsed_response['error']
|
63
|
+
else
|
64
|
+
raise "unidentified error"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
$logger.debug "Parsed response: #{parsed_response}"
|
68
|
+
parsed_response['data']
|
69
|
+
end
|
70
|
+
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
72
|
+
def self.do_request(verb, url, content)
|
73
|
+
$logger.debug "Sending (#{verb}) request..."
|
74
|
+
$logger.debug "Request url: #{url}"
|
75
|
+
$logger.debug "Request content: #{content}"
|
76
|
+
base_uri $config.api_url
|
77
|
+
self.send verb, url, content
|
78
|
+
end
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
80
|
+
def self.build_content(data = nil)
|
81
|
+
time = Time.now.utc.to_i
|
82
|
+
hash = Digest::SHA1.hexdigest("#{$config.api_key}#{$config.secret_key}#{time}").downcase
|
83
|
+
if data.nil?
|
84
|
+
content = {:headers => {'api-key' => $config.api_key, 'hash' => hash, 'time' => time.to_s}}
|
85
|
+
else
|
86
|
+
content = {:headers => {'api-key' => $config.api_key, 'hash' => hash, 'time' => time.to_s, 'Content-Type' => 'application/json'}, :body => {data: data}.to_json}
|
87
|
+
end
|
88
|
+
content
|
89
|
+
end
|
90
90
|
|
91
|
-
|
92
|
-
|
91
|
+
end
|
92
|
+
end
|
93
93
|
end
|
@@ -1,97 +1,123 @@
|
|
1
1
|
module Cloud66
|
2
|
-
|
3
|
-
|
2
|
+
module Utils
|
3
|
+
class VitalSigns
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
IP_BLOCK_REGEX = /\d{,2}|1\d{2}|2[0-4]\d|25[0-5]/
|
6
|
+
IP_REGEX = /\A#{IP_BLOCK_REGEX}\.#{IP_BLOCK_REGEX}\.#{IP_BLOCK_REGEX}\.#{IP_BLOCK_REGEX}\z/
|
7
7
|
|
8
|
-
def self.system_info
|
9
|
-
# system info
|
10
|
-
return parse_data(`facter`)
|
11
|
-
end
|
12
8
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
reported_ip = `/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
|
18
|
-
result[:ext_ipv4] = reported_ip if reported_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
19
|
-
reported_ip = `/usr/bin/curl -s http://169.254.169.254/latest/meta-data/local-ipv4`
|
20
|
-
result[:int_ipv4] = reported_ip if reported_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
21
|
-
# GC special case
|
22
|
-
elsif $config.is_gc
|
23
|
-
external_ip = `/usr/bin/curl -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip`
|
24
|
-
result[:ext_ipv4] = external_ip if external_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
25
|
-
internal_ip = `/usr/bin/curl -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/network-interfaces/0/ip`
|
26
|
-
result[:int_ipv4] = internal_ip if internal_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
27
|
-
else
|
28
|
-
interfaces_raw = `facter interfaces`.strip
|
29
|
-
interfaces = interfaces_raw.split(',').select { |interface| interface !~ /^lo/ }
|
30
|
-
# don't have any ip address info
|
31
|
-
unless interfaces.empty?
|
32
|
-
# return all interface information
|
33
|
-
facter_command = "facter #{interfaces.map { |interface| "ipaddress_#{interface} ipaddress6_#{interface}" }.join(' ')}"
|
34
|
-
raw_data = `#{facter_command}`.strip
|
35
|
-
result = parse_data(raw_data) rescue {}
|
36
|
-
end
|
37
|
-
end
|
38
|
-
normalised_hash = {}
|
39
|
-
result.each do |key, value|
|
40
|
-
if value =~ IP_REGEX && value != '127.0.0.1' && value != '127.0.1.1'
|
41
|
-
normalised_hash[key] = value
|
42
|
-
end
|
43
|
-
end
|
44
|
-
return normalised_hash
|
45
|
-
end
|
9
|
+
def self.system_info
|
10
|
+
# system info
|
11
|
+
return parse_data(`facter`)
|
12
|
+
end
|
46
13
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
14
|
+
def self.vitals_alerts
|
15
|
+
vitals_alerts = {}
|
16
|
+
space_alerts = calculate_space_alerts($config.disk_warning_percent, $config.disk_critical_percent)
|
17
|
+
vitals_alerts[:disk] = space_alerts if space_alerts.present?
|
18
|
+
return vitals_alerts
|
19
|
+
end
|
51
20
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
21
|
+
def self.address_info
|
22
|
+
result = {}
|
23
|
+
# AWS special case
|
24
|
+
if $config.is_aws
|
25
|
+
reported_ip = `/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
|
26
|
+
result[:ext_ipv4] = reported_ip if reported_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
27
|
+
reported_ip = `/usr/bin/curl -s http://169.254.169.254/latest/meta-data/local-ipv4`
|
28
|
+
result[:int_ipv4] = reported_ip if reported_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
29
|
+
# GC special case
|
30
|
+
elsif $config.is_gc
|
31
|
+
external_ip = `/usr/bin/curl -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip`
|
32
|
+
result[:ext_ipv4] = external_ip if external_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
33
|
+
internal_ip = `/usr/bin/curl -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/network-interfaces/0/ip`
|
34
|
+
result[:int_ipv4] = internal_ip if internal_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
35
|
+
else
|
36
|
+
interfaces_raw = `facter interfaces`.strip
|
37
|
+
interfaces = interfaces_raw.split(',').select {|interface| interface !~ /^lo/}
|
38
|
+
# don't have any ip address info
|
39
|
+
unless interfaces.empty?
|
40
|
+
# return all interface information
|
41
|
+
facter_command = "facter #{interfaces.map {|interface| "ipaddress_#{interface} ipaddress6_#{interface}"}.join(' ')}"
|
42
|
+
raw_data = `#{facter_command}`.strip
|
43
|
+
result = parse_data(raw_data) rescue {}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
normalised_hash = {}
|
47
|
+
result.each do |key, value|
|
48
|
+
if value =~ IP_REGEX && value != '127.0.0.1' && value != '127.0.1.1'
|
49
|
+
normalised_hash[key] = value
|
50
|
+
end
|
51
|
+
end
|
52
|
+
return normalised_hash
|
53
|
+
end
|
56
54
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
55
|
+
def self.is_aws?
|
56
|
+
# 6 seconds to find out if this is a AWS image or not!
|
57
|
+
instance = `/usr/bin/curl --connect-timeout 6 -s http://169.254.169.254/latest/meta-data/instance-id` rescue nil
|
58
|
+
return false if instance.nil? || instance.empty?
|
62
59
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
return false unless external_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
60
|
+
# now check the external ip to make sure we're not just being routed
|
61
|
+
reported_ip = `/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4` rescue nil
|
62
|
+
return false if reported_ip.nil? || reported_ip.empty?
|
63
|
+
return false unless reported_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
68
64
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
65
|
+
# it is aws
|
66
|
+
return true
|
67
|
+
rescue => exc
|
68
|
+
return false
|
69
|
+
end
|
74
70
|
|
75
|
-
|
71
|
+
def self.is_gc?
|
72
|
+
# 6 seconds to find out if this is a AWS image or not!
|
73
|
+
external_ip = `/usr/bin/curl --connect-timeout 6 -s -H "Metadata-Flavor: Google" http://metadata/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip` rescue nil
|
74
|
+
return false if external_ip.nil? || external_ip.empty?
|
75
|
+
return false unless external_ip =~ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
77
|
+
# it is google cloud
|
78
|
+
return true
|
79
|
+
rescue => exc
|
80
|
+
return false
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.calculate_space_alerts(warning_threshold, critical_threshold)
|
84
|
+
space_alerts = []
|
85
|
+
return space_alerts if warning_threshold == 0 || critical_threshold == 0
|
86
|
+
# get the df output (linux only)
|
87
|
+
df_output = `sudo df -h | grep -v /var/lib/docker | grep -v /var/lib/kubelet | grep -v Use% | awk '{print $1"|"$6"|"$5}'`
|
88
|
+
df_output.lines.each do |df_line|
|
89
|
+
parts = df_line.split('|')
|
90
|
+
next unless parts.size == 3
|
91
|
+
filesystem = parts[0].strip
|
92
|
+
mounted = parts[1].strip
|
93
|
+
percentage = parts[2].strip.gsub(/%/, '').to_i
|
94
|
+
if percentage >= critical_threshold
|
95
|
+
space_alerts << {level: :critical, filesystem: filesystem, mounted: mounted, percentage: percentage}
|
96
|
+
elsif percentage > warning_threshold
|
97
|
+
space_alerts << {level: :warning, filesystem: filesystem, mounted: mounted, percentage: percentage}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
return space_alerts
|
101
|
+
end
|
102
|
+
|
103
|
+
# parse the data, not using YAML due to YAML parsing issues and JSON output not always working
|
104
|
+
def self.parse_data(data)
|
105
|
+
hash = {}
|
106
|
+
data.lines.each do |line|
|
107
|
+
split = line.split('=>')
|
108
|
+
if split.size == 2
|
109
|
+
key = split[0].strip rescue ''
|
110
|
+
value = split[1].strip rescue ''
|
111
|
+
if !value.nil? && value != 'nil'
|
112
|
+
# exclude empty or long results (like ssh keys)
|
113
|
+
if !value.empty? && value.size < 100
|
114
|
+
hash[key] = value
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
return hash
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
97
123
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloud66_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cloud 66
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mime-types
|
@@ -160,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
160
|
version: '0'
|
161
161
|
requirements: []
|
162
162
|
rubyforge_project:
|
163
|
-
rubygems_version: 2.
|
163
|
+
rubygems_version: 2.7.9
|
164
164
|
signing_key:
|
165
165
|
specification_version: 4
|
166
166
|
summary: Cloud 66 server component
|