apocalypse-client 0.0.2

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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour -f progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in apocalypse-reporter.gemspec
4
+ gemspec
@@ -0,0 +1,82 @@
1
+ # Apocalypse Client
2
+
3
+ Apocalypse Client is a ruby gem that can be installed on a remote
4
+ server.
5
+
6
+ ## Installation
7
+
8
+ Apocalypse Client currently focusses on Debian/Ubuntu systems only.
9
+
10
+ There is only one dependency to the operating system, namely the
11
+ `sysstat` package. This package is used to gather information about disk
12
+ utilisation and performance.
13
+
14
+ sudo apt-get install sysstat
15
+
16
+ Next install the ruby gem.
17
+
18
+ sudo gem install apocalypse-client
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
+
25
+ This will send metrics data every minute to your Apocalypse server. If
26
+ you require different intervals, refer to `man 5 crontab` for details on
27
+ how to schedule reporting.
28
+
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
+ If an error occurs cron will try to notify you by email. This depends on
40
+ how your systems cron is configured.
41
+
42
+ ## Choosing a proper hostid
43
+
44
+ Choosing a proper hostid is important, because it can be arbitrarily
45
+ chosen. There are several options:
46
+
47
+ * Use the format `appname-role-number`. E.g. `ariejannet-db-01` or
48
+ `reddis-memcached-42`.
49
+ * IP Address of the server, this guarantees some level of uniqueness
50
+
51
+ Note: at this time, there is not convention for picking hostids.
52
+ However, the first method is likely to become the convention and will
53
+ allow logical grouping of servers by role and application.
54
+
55
+ ## Authors
56
+
57
+ * Ariejan de Vroom <ariejan@ariejan.net>
58
+ * Kabisa ICT - http://kabisa.nl
59
+
60
+ ## License
61
+
62
+ Copyright (c) 2011 Ariejan de Vroom
63
+
64
+ Permission is hereby granted, free of charge, to any person obtaining
65
+ a copy of this software and associated documentation files (the
66
+ "Software"), to deal in the Software without restriction, including
67
+ without limitation the rights to use, copy, modify, merge, publish,
68
+ distribute, sublicense, and/or sell copies of the Software, and to
69
+ permit persons to whom the Software is furnished to do so, subject to
70
+ the following conditions:
71
+
72
+ The above copyright notice and this permission notice shall be
73
+ included in all copies or substantial portions of the Software.
74
+
75
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
76
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
77
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
78
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
79
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
80
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
81
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
82
+
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ task :default => :spec
4
+
5
+ desc "Run all specs"
6
+ task "spec" do
7
+ exec "bundle exec rspec spec"
8
+ end
9
+
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "apocalypse-client/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "apocalypse-client"
7
+ s.version = Apocalypse::Client::VERSION
8
+ s.authors = ["Ariejan de Vroom"]
9
+ s.email = ["ariejan@ariejan.net"]
10
+ s.homepage = ""
11
+ s.summary = %q{Watch out for the apocalypse}
12
+ s.description = %q{Server monitoring made easy}
13
+
14
+ s.rubyforge_project = "apocalypse-client"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency("json", ["~> 1.5.3"])
22
+ s.add_dependency("trollop", ["~> 1.16.2"])
23
+
24
+ s.add_development_dependency("rspec", ["~> 2.6.0"])
25
+ end
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require "apocalypse-client"
7
+ require 'trollop'
8
+
9
+ SUB_COMMANDS = %w(report install check)
10
+
11
+ global_opts = Trollop::options do
12
+ banner "Apocalypse Reporter"
13
+ stop_on SUB_COMMANDS
14
+ end
15
+
16
+ cmd = ARGV.shift
17
+ cmd_opts = case cmd
18
+ when "report"
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"
23
+ end
24
+ when "install"
25
+ Trollop::options do
26
+ # TODO
27
+ end
28
+ when "check"
29
+ Trollop::options do
30
+ # TODO
31
+ end
32
+ else
33
+ Trollop::die "unknown command #{cmd.inspect}"
34
+ end
35
+
36
+ reporter = Apocalypse::Client.new
37
+ reporter.send(cmd, cmd_opts)
@@ -0,0 +1,133 @@
1
+ require 'rubygems'
2
+ require 'net/http'
3
+ require 'json'
4
+
5
+ class Hash
6
+ #
7
+ # Create a hash from an array of keys and corresponding values.
8
+ def self.zip(keys, values, default=nil, &block)
9
+ hsh = block_given? ? Hash.new(&block) : Hash.new(default)
10
+ keys.zip(values) { |k,v| hsh[k]=v }
11
+ hsh
12
+ end
13
+ end
14
+
15
+ module Apocalypse
16
+ class Client
17
+ ## Commands
18
+
19
+ # Report metrics
20
+ 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}"
26
+ end
27
+
28
+ # Check if all local deps are available
29
+ def check(options)
30
+ errors = []
31
+ [
32
+ ["/usr/bin/iostat", "sysstat"]
33
+ ].each do |filename, package|
34
+ errors << "Cannot find `#{filename}`. Please run `apt-get install #{package}` to resolve this." if !File.exists?(filename)
35
+ end
36
+
37
+ if errors.empty?
38
+ puts "Everything seems to be in place. You're good to go."
39
+ else
40
+ errors.each { |error| puts errors }
41
+ end
42
+ end
43
+
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:
49
+
50
+ * * * * * root PATH=$PATH:/sbin:/usr/sbin /usr/bin/env apocalypse-reporter report --server APOCALYPSE_SERVER --hostid SERVER_ID > /dev/null
51
+
52
+ Make sure to replace the server and hostid placeholders with something more useful.
53
+ EOF
54
+ end
55
+
56
+ # Gather metrics
57
+ def gather_metrics
58
+ {
59
+ 'cpu' => {
60
+ 'cores' => cpu_cores.strip,
61
+ 'loadavg' => cpu_loadavg
62
+ },
63
+ 'memory' => memory_metrics,
64
+ 'swap' => swap_metrics,
65
+ 'blockdevices' => blockdevice_metrics,
66
+ 'network' => network_metrics
67
+ }
68
+ end
69
+
70
+ # Returns the number of CPU Cores for this system
71
+ def cpu_cores
72
+ `cat /proc/cpuinfo | grep bogomips | wc -l`.strip
73
+ end
74
+
75
+ # Gather load average data
76
+ def cpu_loadavg
77
+ `cat /proc/loadavg`.split
78
+ end
79
+
80
+ def blockdevice_metrics
81
+ columns = ["tps", "rps", "wps", "size", "used", "available", "usage", "mount"]
82
+
83
+ io_data = `/usr/bin/env iostat -dk | tail -n+4`.split("\n").map { |line| line.split[0...-2] }
84
+ usage_data = `df -l --block-size=M | grep -i ^/dev/[sh]`.split("\n").map { |line| line.split }
85
+
86
+ io_data.collect do |device_data|
87
+ device_name = device_data.shift
88
+ device_usage = usage_data.select { |x| x[0].include? device_name }.flatten
89
+
90
+ unless device_usage.empty?
91
+ device_data += device_usage[1..-1]
92
+ end
93
+
94
+ { device_name => Hash.zip(columns, device_data) }
95
+ end
96
+ end
97
+
98
+ def memory_metrics
99
+ {
100
+ 'free' => `cat /proc/meminfo | grep MemFree | awk '{print $2}'`.strip,
101
+ 'total' => `cat /proc/meminfo | grep MemTotal | awk '{print $2}'`.strip
102
+ }
103
+ end
104
+
105
+ def swap_metrics
106
+ {
107
+ 'free' => `cat /proc/meminfo | grep SwapFree | awk '{print $2}'`.strip,
108
+ 'total' => `cat /proc/meminfo | grep SwapTotal | awk '{print $2}'`.strip
109
+ }
110
+ end
111
+
112
+ def network_metrics
113
+ devices = `/usr/bin/env ifconfig | egrep 'Link encap' | grep -v 'lo' | awk '{print $1}'`.split
114
+
115
+ devices.collect do |device_name|
116
+ { device_name => {
117
+ 'hwaddr' => `/usr/bin/env ifconfig #{device_name} | egrep -o 'HWaddr \([0-9a-fA-F]\{2\}\:*\){6}' | awk '{print $2}'`.strip,
118
+ 'mtu' => `/usr/bin/env ifconfig #{device_name} | egrep -o MTU\:[0-9]+ | tr -s ':' ' ' | awk '{print $2}'`.strip,
119
+ 'metric' => `/usr/bin/env ifconfig #{device_name} | egrep -o Metric\:[0-9]+ | tr -s ':' ' ' | awk '{print $2}'`.strip,
120
+ 'encapsulation' => `/usr/bin/env ifconfig #{device_name} | egrep -o 'Link encap\:[a-zA-Z]+' | cut -d":" -f2`.strip,
121
+ 'rxbytes' => `/usr/bin/env ifconfig #{device_name} | grep bytes | awk '/RX/ {print $2}' | tr -s ':' ' ' | awk '{print $2}'`.strip,
122
+ 'txbytes' => `/usr/bin/env ifconfig #{device_name} | grep bytes | awk '/TX/ {print $6}' | tr -s ':' ' ' | awk '{print $2}'`.strip,
123
+ 'ipv4address' => `/usr/bin/env ifconfig #{device_name} | egrep -o 'inet addr\:[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | tr -s ':' ' ' | awk '{print $3}'`.strip,
124
+ 'broadcast' => `/usr/bin/env ifconfig #{device_name} | egrep -o Bcast\:[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\} | tr -s ':' ' ' | awk '{print $2}'`.strip,
125
+ 'netmask' => `/usr/bin/env ifconfig #{device_name} | egrep -o Mask\:[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\} | tr -s ':' ' ' | awk '{print $2}'`.strip,
126
+ 'gateway' => `netstat -rn | grep ^0.0.0.0 | grep UG | grep #{device_name} | awk '{print $2}' | head -n1`.strip,
127
+ 'ipv6addr' => `/usr/bin/env ifconfig #{device_name} | egrep -o 'inet6 addr\:\ \([a-fA-F0-9]\{1,4}\:\{1,2\}[a-fA-F0-9]\{1,4}\:\{1,2\}\)+[A-Fa-f0-9\/^\ ]+' | awk '{print $3}'`.strip,
128
+ 'ipv6scope' => `/usr/bin/env ifconfig #{device_name} | egrep -o Scope\:[a-zA-Z]+ | cut -d":" -f2`.strip
129
+ }}
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,5 @@
1
+ module Apocalypse
2
+ class Client
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+
3
+ describe Apocalypse::Client do
4
+ before(:each) do
5
+ @reporter = Apocalypse::Client.new
6
+ end
7
+
8
+ describe "cpu cores" do
9
+ it "should return the correct number of cores" do
10
+ @reporter.should_receive(:`).with("cat /proc/cpuinfo | grep bogomips | wc -l").and_return("4")
11
+ @reporter.cpu_cores.should eql("4")
12
+ end
13
+ end
14
+
15
+ describe "cpu loadavg" do
16
+ it "should return the correct loadavg values" do
17
+ @reporter.should_receive(:`).with("cat /proc/loadavg").and_return("0.89 0.92 1.12 1/124 28786")
18
+ @reporter.cpu_loadavg.should eql(["0.89", "0.92", "1.12", "1/124", "28786"])
19
+ end
20
+ end
21
+
22
+ describe "memory" do
23
+ it "should gather free and used memory" do
24
+ @reporter.should_receive(:`).with("cat /proc/meminfo | grep MemFree | awk '{print $2}'").and_return("998452")
25
+ @reporter.should_receive(:`).with("cat /proc/meminfo | grep MemTotal | awk '{print $2}'").and_return("7864548")
26
+
27
+ memory_metrics = @reporter.memory_metrics
28
+ memory_metrics["free"].should eql("998452")
29
+ memory_metrics["total"].should eql("7864548")
30
+ end
31
+ end
32
+
33
+ describe "swap" do
34
+ it "should gather free and used swap" do
35
+ @reporter.should_receive(:`).with("cat /proc/meminfo | grep SwapFree | awk '{print $2}'").and_return("934452")
36
+ @reporter.should_receive(:`).with("cat /proc/meminfo | grep SwapTotal | awk '{print $2}'").and_return("15728632")
37
+
38
+ swap_metrics = @reporter.swap_metrics
39
+ swap_metrics["free"].should eql("934452")
40
+ swap_metrics["total"].should eql("15728632")
41
+ end
42
+ end
43
+
44
+ describe "networking" do
45
+ it "should get network metrics" do
46
+ {
47
+ "/usr/bin/env ifconfig | egrep 'Link encap' | grep -v 'lo' | awk '{print $1}'" => "eth0",
48
+ "/usr/bin/env ifconfig eth0 | egrep -o 'HWaddr \([0-9a-fA-F]\{2\}\:*\){6}' | awk '{print $2}'" => "bc:de:12:ba:38:b3",
49
+ "/usr/bin/env ifconfig eth0 | egrep -o MTU\:[0-9]+ | tr -s ':' ' ' | awk '{print $2}'" => "1500",
50
+ "/usr/bin/env ifconfig eth0 | egrep -o Metric\:[0-9]+ | tr -s ':' ' ' | awk '{print $2}'" => "1",
51
+ "/usr/bin/env ifconfig eth0 | egrep -o 'Link encap\:[a-zA-Z]+' | cut -d\":\" -f2" => "Ethernet",
52
+ "/usr/bin/env ifconfig eth0 | grep bytes | awk '/RX/ {print $2}' | tr -s ':' ' ' | awk '{print $2}'" => "384735745",
53
+ "/usr/bin/env ifconfig eth0 | grep bytes | awk '/TX/ {print $6}' | tr -s ':' ' ' | awk '{print $2}'" => "3575372573",
54
+ "/usr/bin/env ifconfig eth0 | egrep -o 'inet addr\:[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | tr -s ':' ' ' | awk '{print $3}'" => "10.187.234.18",
55
+ "/usr/bin/env ifconfig eth0 | egrep -o Bcast\:[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\} | tr -s ':' ' ' | awk '{print $2}'" => "10.187.234.254",
56
+ "/usr/bin/env ifconfig eth0 | egrep -o Mask\:[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\} | tr -s ':' ' ' | awk '{print $2}'" => "255.0.0.0",
57
+ "netstat -rn | grep ^0.0.0.0 | grep UG | grep eth0 | awk '{print $2}' | head -n1" => "10.187.234.1",
58
+ "/usr/bin/env ifconfig eth0 | egrep -o 'inet6 addr\:\ \([a-fA-F0-9]\{1,4}\:\{1,2\}[a-fA-F0-9]\{1,4}\:\{1,2\}\)+[A-Fa-f0-9\/^\ ]+' | awk '{print $3}'" => "fe80::1031:3cff:fe00:bde1/64",
59
+ "/usr/bin/env ifconfig eth0 | egrep -o Scope\:[a-zA-Z]+ | cut -d\":\" -f2" => "Link"
60
+ }.each do |command, result|
61
+ @reporter.should_receive(:`).with(command).and_return(result)
62
+ end
63
+
64
+ network_metrics = @reporter.network_metrics.first["eth0"]
65
+
66
+ network_metrics["hwaddr"].should eql("bc:de:12:ba:38:b3")
67
+ network_metrics["mtu"].should eql("1500")
68
+ network_metrics["metric"].should eql("1")
69
+ network_metrics["encapsulation"].should eql("Ethernet")
70
+ network_metrics["rxbytes"].should eql("384735745")
71
+ network_metrics["txbytes"].should eql("3575372573")
72
+ network_metrics["ipv4address"].should eql("10.187.234.18")
73
+ network_metrics["broadcast"].should eql("10.187.234.254")
74
+ network_metrics["netmask"].should eql("255.0.0.0")
75
+ network_metrics["gateway"].should eql("10.187.234.1")
76
+ network_metrics["ipv6addr"].should eql("fe80::1031:3cff:fe00:bde1/64")
77
+ network_metrics["ipv6scope"].should eql("Link")
78
+ end
79
+ end
80
+
81
+ describe "block devices" do
82
+ it "should gather the correct block device info" do
83
+ iostat = <<-EOF
84
+ sda1 0.21 1.95 2.35 157872 189884
85
+ sda2 5.74 18.53 22.08 1496597 1783516
86
+
87
+ EOF
88
+
89
+ df = <<-EOF
90
+ /dev/sda2 29529M 7506M 20524M 27% /
91
+ EOF
92
+
93
+ @reporter.should_receive(:`).with("/usr/bin/env iostat -dk | tail -n+4").and_return(iostat)
94
+ @reporter.should_receive(:`).with("df -l --block-size=M | grep -i ^/dev/[sh]").and_return(df)
95
+
96
+ result = @reporter.blockdevice_metrics
97
+
98
+ result.size.should eql(2)
99
+
100
+ # sda1
101
+ sda1 = result.select{ |a| a.keys.include?("sda1") }.first["sda1"]
102
+
103
+ sda1["tps"].should eql("0.21")
104
+ sda1["rps"].should eql("1.95")
105
+ sda1["wps"].should eql("2.35")
106
+ sda1["size"].should be_nil
107
+ sda1["usage"].should be_nil
108
+ sda1["used"].should be_nil
109
+ sda1["available"].should be_nil
110
+ sda1["mount"].should be_nil
111
+
112
+ # sda2
113
+ sda2 = result.select{ |a| a.keys.include?("sda2") }.first["sda2"]
114
+
115
+ sda2["tps"].should eql("5.74")
116
+ sda2["rps"].should eql("18.53")
117
+ sda2["wps"].should eql("22.08")
118
+ sda2["size"].should eql("29529M")
119
+ sda2["usage"].should eql("27%")
120
+ sda2["used"].should eql("7506M")
121
+ sda2["available"].should eql("20524M")
122
+ sda2["mount"].should eql("/")
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,4 @@
1
+ require 'apocalypse-client'
2
+
3
+ require 'rspec'
4
+ require 'json'
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apocalypse-client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Ariejan de Vroom
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-06 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: json
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 5
30
+ segments:
31
+ - 1
32
+ - 5
33
+ - 3
34
+ version: 1.5.3
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: trollop
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 83
46
+ segments:
47
+ - 1
48
+ - 16
49
+ - 2
50
+ version: 1.16.2
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rspec
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 23
62
+ segments:
63
+ - 2
64
+ - 6
65
+ - 0
66
+ version: 2.6.0
67
+ type: :development
68
+ version_requirements: *id003
69
+ description: Server monitoring made easy
70
+ email:
71
+ - ariejan@ariejan.net
72
+ executables:
73
+ - apocalypse-client
74
+ extensions: []
75
+
76
+ extra_rdoc_files: []
77
+
78
+ files:
79
+ - .gitignore
80
+ - .rspec
81
+ - Gemfile
82
+ - README.md
83
+ - Rakefile
84
+ - apocalypse-client.gemspec
85
+ - bin/apocalypse-client
86
+ - lib/apocalypse-client.rb
87
+ - lib/apocalypse-client/version.rb
88
+ - spec/client_spec.rb
89
+ - spec/spec_helper.rb
90
+ has_rdoc: true
91
+ homepage: ""
92
+ licenses: []
93
+
94
+ post_install_message:
95
+ rdoc_options: []
96
+
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 3
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ requirements: []
118
+
119
+ rubyforge_project: apocalypse-client
120
+ rubygems_version: 1.5.0
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: Watch out for the apocalypse
124
+ test_files:
125
+ - spec/client_spec.rb
126
+ - spec/spec_helper.rb