apocalypse-client 0.0.2 → 0.0.3
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.
- data/.gitignore +1 -0
- data/README.md +3 -15
- data/bin/apocalypse-client +6 -7
- data/lib/apocalypse-client.rb +43 -15
- data/lib/apocalypse-client/install.rb +151 -0
- data/lib/apocalypse-client/response.rb +40 -0
- data/lib/apocalypse-client/version.rb +1 -1
- data/spec/client_spec.rb +7 -0
- data/spec/spec_helper.rb +1 -1
- metadata +7 -7
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -17,25 +17,13 @@ Next install the ruby gem.
|
|
17
17
|
|
18
18
|
sudo gem install apocalypse-client
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
* * * * * root PATH=$PATH:/sbin:/usr/sbin /usr/bin/env apocalypse-client report --server SERVER --port PORT --hostid HOSTID > /dev/null
|
24
|
-
|
20
|
+
once installed run the install|now command
|
21
|
+
apocalypse-client now
|
22
|
+
|
25
23
|
This will send metrics data every minute to your Apocalypse server. If
|
26
24
|
you require different intervals, refer to `man 5 crontab` for details on
|
27
25
|
how to schedule reporting.
|
28
26
|
|
29
|
-
You need to replace the placeholders with actual data:
|
30
|
-
|
31
|
-
* `SERVER` - The ip or hostname for your Apocalypse server. E.g.
|
32
|
-
apocalyse.example.org
|
33
|
-
* `PORT` - The port number the Apocalypse server is listening on.
|
34
|
-
Default: 80
|
35
|
-
* `HOSTID` - An ID identifying this server. You are free to choose
|
36
|
-
whatever you want. But be careful not to chose a duplicate hostid,
|
37
|
-
because it will mess up you statistics.
|
38
|
-
|
39
27
|
If an error occurs cron will try to notify you by email. This depends on
|
40
28
|
how your systems cron is configured.
|
41
29
|
|
data/bin/apocalypse-client
CHANGED
@@ -6,7 +6,7 @@ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
|
6
6
|
require "apocalypse-client"
|
7
7
|
require 'trollop'
|
8
8
|
|
9
|
-
SUB_COMMANDS = %w(report install
|
9
|
+
SUB_COMMANDS = %w(report check install now update)
|
10
10
|
|
11
11
|
global_opts = Trollop::options do
|
12
12
|
banner "Apocalypse Reporter"
|
@@ -17,14 +17,13 @@ cmd = ARGV.shift
|
|
17
17
|
cmd_opts = case cmd
|
18
18
|
when "report"
|
19
19
|
Trollop::options do
|
20
|
-
|
21
|
-
opt :port, "Port the Apocalypse Server is listening on. Default: 80", :type => :string, :default => '80', :short => "-p"
|
22
|
-
opt :hostid, "Identifier for this server", :type => :string, :short => "-i"
|
20
|
+
# Nothing here
|
23
21
|
end
|
22
|
+
when "update"
|
23
|
+
Trollop::options {}
|
24
24
|
when "install"
|
25
|
-
|
26
|
-
|
27
|
-
end
|
25
|
+
when "now"
|
26
|
+
Trollop::options {}
|
28
27
|
when "check"
|
29
28
|
Trollop::options do
|
30
29
|
# TODO
|
data/lib/apocalypse-client.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
+
require "yaml"
|
1
2
|
require 'rubygems'
|
2
3
|
require 'net/http'
|
3
4
|
require 'json'
|
5
|
+
require 'apocalypse-client/version'
|
6
|
+
require 'apocalypse-client/response'
|
7
|
+
require 'apocalypse-client/install'
|
4
8
|
|
5
9
|
class Hash
|
6
10
|
#
|
@@ -14,15 +18,26 @@ end
|
|
14
18
|
|
15
19
|
module Apocalypse
|
16
20
|
class Client
|
17
|
-
|
21
|
+
def self.host_file; "#{File.dirname(__FILE__)}/../host.yml"; end
|
22
|
+
def self.cron_job_file; "/etc/cron.d/apocalyse"; end
|
23
|
+
def self.rvm?; !`which rvm`.chomp.empty? end
|
24
|
+
|
25
|
+
def self.cron_job_command
|
26
|
+
return rvm? \
|
27
|
+
? " * * * * * root PATH=$PATH:/sbin:/usr/sbin rvm use $RUBY_VERSION ; /usr/local/bin/rvm exec apocalypse-client report > /dev/null" \
|
28
|
+
: "* * * * * root PATH=$PATH:/sbin:/usr/sbin /usr/bin/env apocalypse-client report > /dev/null"
|
29
|
+
end
|
18
30
|
|
19
31
|
# Report metrics
|
20
32
|
def report(options)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
33
|
+
request = Net::HTTP::Post.new("/api/metrics/#{properties[:hostname]}", initheader = {'Content-Type' =>'application/json'})
|
34
|
+
request.body = gather_metrics.to_json
|
35
|
+
Net::HTTP.start(properties[:server_address], properties[:port]) do |http|
|
36
|
+
request.basic_auth(properties[:username], properties[:password])
|
37
|
+
response = http.request(request)
|
38
|
+
|
39
|
+
Apocalyse::Client::Response.parse!(response)
|
40
|
+
end
|
26
41
|
end
|
27
42
|
|
28
43
|
# Check if all local deps are available
|
@@ -41,16 +56,18 @@ module Apocalypse
|
|
41
56
|
end
|
42
57
|
end
|
43
58
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
Simply create the file `/etc/cron.d/apocalypse` and put the following line in it:
|
59
|
+
def update(options)
|
60
|
+
installation = Apocalyse::Client::Install.new
|
61
|
+
installation.update!
|
62
|
+
end
|
49
63
|
|
50
|
-
|
64
|
+
def now(options)
|
65
|
+
install(options)
|
66
|
+
end
|
51
67
|
|
52
|
-
|
53
|
-
|
68
|
+
def install(options)
|
69
|
+
installation = Apocalyse::Client::Install.new
|
70
|
+
installation.install!
|
54
71
|
end
|
55
72
|
|
56
73
|
# Gather metrics
|
@@ -63,10 +80,15 @@ Make sure to replace the server and hostid placeholders with something more usef
|
|
63
80
|
'memory' => memory_metrics,
|
64
81
|
'swap' => swap_metrics,
|
65
82
|
'blockdevices' => blockdevice_metrics,
|
66
|
-
'network' => network_metrics
|
83
|
+
'network' => network_metrics,
|
84
|
+
'client' => client_information
|
67
85
|
}
|
68
86
|
end
|
69
87
|
|
88
|
+
def client_information
|
89
|
+
{ 'version' => Apocalypse::Client::VERSION }
|
90
|
+
end
|
91
|
+
|
70
92
|
# Returns the number of CPU Cores for this system
|
71
93
|
def cpu_cores
|
72
94
|
`cat /proc/cpuinfo | grep bogomips | wc -l`.strip
|
@@ -129,5 +151,11 @@ Make sure to replace the server and hostid placeholders with something more usef
|
|
129
151
|
}}
|
130
152
|
end
|
131
153
|
end
|
154
|
+
|
155
|
+
private
|
156
|
+
def properties
|
157
|
+
throw Exception.new("Host file not found. Please run `apocalyse-client now`") unless File.exists?(self.class.host_file)
|
158
|
+
@properties ||= ::YAML.load(File.open(self.class.host_file))
|
159
|
+
end
|
132
160
|
end
|
133
161
|
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module Apocalyse
|
2
|
+
module Client
|
3
|
+
class Install
|
4
|
+
def install!
|
5
|
+
check_file_access # Start of by checking if we can write the Cron job
|
6
|
+
read_values # Now ask the user for the configuration input
|
7
|
+
validate # Make sure the input is correct
|
8
|
+
check_server # Check if the provided server is accessible
|
9
|
+
write_host_file # Write the configuration file for this host
|
10
|
+
install_cron_job # Finally install the Cronjob
|
11
|
+
|
12
|
+
puts "All done.."
|
13
|
+
rescue Exception => e
|
14
|
+
puts e.message
|
15
|
+
end
|
16
|
+
|
17
|
+
def update!
|
18
|
+
puts "Updating..."
|
19
|
+
# Nothing here as nothing needs to be updated yet.
|
20
|
+
end
|
21
|
+
|
22
|
+
def self_update!
|
23
|
+
update_gem # gem update apocalypse-client
|
24
|
+
update_command # Do a update command
|
25
|
+
|
26
|
+
rescue Exception => e
|
27
|
+
puts e.message
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
# Read the configuration for this server provided by the user
|
32
|
+
def read_values
|
33
|
+
# Read the Apocalypse Server information
|
34
|
+
url = read_user_input("Enter The full address of the Apocalypse server: ").downcase
|
35
|
+
@port = read_user_input("Enter The port number of the Apocalypse server {{default}}: ", "80")
|
36
|
+
|
37
|
+
# Cleanup the user input for the server input
|
38
|
+
url = url.gsub(/http:\/\/(.+?$)/, "\\1") if url =~ /^http:\/\//i
|
39
|
+
@address = url.gsub(/\/$/, "")
|
40
|
+
|
41
|
+
# HTTP auth variables
|
42
|
+
@username = read_user_input("Enter your username {{default}}: " , `whoami`)
|
43
|
+
@password = read_user_input("Enter your password: " , "", false)
|
44
|
+
|
45
|
+
# This servers hostname
|
46
|
+
@hostname = read_user_input("Enter The full hostname(FQDN) {{default}}: " , `hostname`).downcase
|
47
|
+
end
|
48
|
+
|
49
|
+
# Ask the user if the input is valid
|
50
|
+
# If so write the host file and continue installing
|
51
|
+
def validate
|
52
|
+
2.times { puts }
|
53
|
+
puts <<-EOF
|
54
|
+
You have entered the following information
|
55
|
+
Apocalypse server : #{@address}
|
56
|
+
Apocalypse server port : #{@port}
|
57
|
+
Apocalypse username : #{@username}
|
58
|
+
Apocalypse password : #{'*' *@password.length}
|
59
|
+
This Server' hostname : #{@hostname}
|
60
|
+
EOF
|
61
|
+
|
62
|
+
print "Is this correct? [no]: "
|
63
|
+
raise Exception.new("Aborted by user.") unless gets =~ /^y(?:es|)$/
|
64
|
+
puts
|
65
|
+
end
|
66
|
+
|
67
|
+
# Check if the server address is correct
|
68
|
+
def check_server
|
69
|
+
raise Exception.new("Could not reach Apocalypse server please check the address and port and try again.") unless server_reachable?
|
70
|
+
end
|
71
|
+
|
72
|
+
# Write the user provided information to a YAML file
|
73
|
+
def write_host_file
|
74
|
+
puts "Writing Apocalypse host file..."
|
75
|
+
host_config = {
|
76
|
+
:hostname => @hostname,
|
77
|
+
:server_address => @address,
|
78
|
+
:port => @port,
|
79
|
+
:username => @username,
|
80
|
+
:password => @password
|
81
|
+
}
|
82
|
+
file = File.open(::Apocalypse::Client.host_file, "w") do |f|
|
83
|
+
f.write host_config.to_yaml
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def check_file_access
|
88
|
+
writeable = `if [ \`touch #{::Apocalypse::Client.cron_job_file} 2> /dev/null; echo "$?"\` -eq 0 ]; then
|
89
|
+
echo "true"
|
90
|
+
else
|
91
|
+
echo "false"
|
92
|
+
fi`
|
93
|
+
unless writeable.chomp.eql? "true"
|
94
|
+
raise Exception.new("You don't have permission to write #{::Apocalypse::Client.cron_job_file}. Either run the script as root or make #{::Apocalypse::Client.cron_job_file} writeable for this user.")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def install_cron_job
|
99
|
+
`echo "#{::Apocalypse::Client.cron_job_command}" > #{::Apocalypse::Client.cron_job_file}`
|
100
|
+
end
|
101
|
+
|
102
|
+
def update_gem
|
103
|
+
if ::Apocalypse::Client.rvm?
|
104
|
+
puts "Updating gem using RVM.."
|
105
|
+
`PATH=$PATH:/sbin:/usr/sbin rvm use $RUBY_VERSION; /usr/local/bin/rvm gem update apocalypse-client > /dev/null`
|
106
|
+
else
|
107
|
+
puts "Updating system gem.."
|
108
|
+
`PATH=$PATH:/sbin:/usr/sbin; sudo gem update apocalypse-client > /dev/null`
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def update_command
|
113
|
+
if ::Apocalypse::Client.rvm?
|
114
|
+
`PATH=$PATH:/sbin:/usr/sbin rvm use $RUBY_VERSION; apocalypse-client update > /dev/null`
|
115
|
+
else
|
116
|
+
`PATH=$PATH:/sbin:/usr/sbin /usr/bin/env apocalypse-client update > /dev/null`
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
# Read the user input from the console and return either the default value or the user input
|
122
|
+
def read_user_input(message, default = "", show_input = true)
|
123
|
+
print interpolate_message(message, default)
|
124
|
+
show_input ? gets : silent_command { gets }
|
125
|
+
($_.chomp.empty?) ? default.chomp : $_.chomp
|
126
|
+
end
|
127
|
+
|
128
|
+
# Interpolate the message with the given string replacing: {{var}} with: (var: #{str})
|
129
|
+
def interpolate_message(message, str)
|
130
|
+
message.gsub(/\{\{(.+?)\}\}/, (str.empty?) ? "" : "(\\1: #{str.chomp})")
|
131
|
+
end
|
132
|
+
|
133
|
+
# Execute the command in the given block without returning writing anything to stdout
|
134
|
+
def silent_command(&cmd)
|
135
|
+
system "stty -echo"
|
136
|
+
yield
|
137
|
+
system "stty echo"
|
138
|
+
puts
|
139
|
+
end
|
140
|
+
|
141
|
+
# Check if the server is reachable before continuing with the installation
|
142
|
+
def server_reachable?
|
143
|
+
puts "Checking #{@address}:#{@port}"
|
144
|
+
res = Net::HTTP.start(@address, @port) {|http| http.get('/') }
|
145
|
+
return res.code == "200"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Apocalyse
|
2
|
+
module Client
|
3
|
+
class Response
|
4
|
+
RESULT_OK = 0
|
5
|
+
RESULT_CLIENT_OUTDATED = 1001
|
6
|
+
|
7
|
+
def self.parse!(response)
|
8
|
+
return if response.code.to_i == 401
|
9
|
+
|
10
|
+
if response.code.to_i == 200
|
11
|
+
response_obj = JSON.parse(response.body)
|
12
|
+
unless response_obj["code"] == RESULT_OK
|
13
|
+
perform!(response_obj["code"])
|
14
|
+
end
|
15
|
+
else
|
16
|
+
resolve_invalid_response
|
17
|
+
end
|
18
|
+
|
19
|
+
rescue => e
|
20
|
+
resolve_invalid_response
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.perform!(result_code)
|
24
|
+
case result_code
|
25
|
+
when RESULT_CLIENT_OUTDATED
|
26
|
+
puts "Received update result code"
|
27
|
+
::Apocalyse::Client::Install.new.self_update!
|
28
|
+
|
29
|
+
else
|
30
|
+
resolve_invalid_response
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.resolve_invalid_response
|
35
|
+
puts "Invalid response, let's try to update."
|
36
|
+
::Apocalyse::Client::Install.new.self_update!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/client_spec.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
|
3
4
|
describe Apocalypse::Client do
|
4
5
|
before(:each) do
|
5
6
|
@reporter = Apocalypse::Client.new
|
@@ -122,4 +123,10 @@ EOF
|
|
122
123
|
sda2["mount"].should eql("/")
|
123
124
|
end
|
124
125
|
end
|
126
|
+
|
127
|
+
describe "Client information" do
|
128
|
+
it "should return the current version of this client." do
|
129
|
+
@reporter.client_information.should eql({ 'version' => Apocalypse::Client::VERSION })
|
130
|
+
end
|
131
|
+
end
|
125
132
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apocalypse-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 3
|
10
|
+
version: 0.0.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ariejan de Vroom
|
@@ -15,8 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
19
|
-
default_executable:
|
18
|
+
date: 2011-10-04 00:00:00 Z
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: json
|
@@ -84,10 +83,11 @@ files:
|
|
84
83
|
- apocalypse-client.gemspec
|
85
84
|
- bin/apocalypse-client
|
86
85
|
- lib/apocalypse-client.rb
|
86
|
+
- lib/apocalypse-client/install.rb
|
87
|
+
- lib/apocalypse-client/response.rb
|
87
88
|
- lib/apocalypse-client/version.rb
|
88
89
|
- spec/client_spec.rb
|
89
90
|
- spec/spec_helper.rb
|
90
|
-
has_rdoc: true
|
91
91
|
homepage: ""
|
92
92
|
licenses: []
|
93
93
|
|
@@ -117,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
117
|
requirements: []
|
118
118
|
|
119
119
|
rubyforge_project: apocalypse-client
|
120
|
-
rubygems_version: 1.5
|
120
|
+
rubygems_version: 1.8.5
|
121
121
|
signing_key:
|
122
122
|
specification_version: 3
|
123
123
|
summary: Watch out for the apocalypse
|