apocalypse-client 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ host.yml
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
- Now you can create the file `/etc/cron.d/apocalypse` with the following
21
- content:
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
 
@@ -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 check)
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
- opt :server, "Hostname of the Apocalypse Server", :type => :string, :short => "-s"
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
- Trollop::options do
26
- # TODO
27
- end
25
+ when "now"
26
+ Trollop::options {}
28
27
  when "check"
29
28
  Trollop::options do
30
29
  # TODO
@@ -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
- ## Commands
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
- puts options.inspect
22
- request = Net::HTTP::Post.new("/api/metrics/#{options[:hostid]}", initheader = {'Content-Type' =>'application/json'})
23
- request.body = gather_metrics.to_json
24
- response = Net::HTTP.new(options[:server], options[:port]).start {|http| http.request(request) }
25
- puts "Response #{response.code} #{response.message}: #{response.body}"
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 install(options)
45
- puts <<-EOF
46
- Sorry, no automated installation yet. Installation is, however, quite easy.
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
- * * * * * root PATH=$PATH:/sbin:/usr/sbin /usr/bin/env apocalypse-reporter report --server APOCALYPSE_SERVER --hostid SERVER_ID > /dev/null
64
+ def now(options)
65
+ install(options)
66
+ end
51
67
 
52
- Make sure to replace the server and hostid placeholders with something more useful.
53
- EOF
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
@@ -1,5 +1,5 @@
1
1
  module Apocalypse
2
2
  class Client
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  end
5
5
  end
@@ -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
@@ -1,4 +1,4 @@
1
1
  require 'apocalypse-client'
2
-
2
+ require 'apocalypse-client/version'
3
3
  require 'rspec'
4
4
  require 'json'
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: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
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-07-06 00:00:00 +02:00
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.0
120
+ rubygems_version: 1.8.5
121
121
  signing_key:
122
122
  specification_version: 3
123
123
  summary: Watch out for the apocalypse