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 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