ziltoid 1.0.0
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.
- checksums.yaml +7 -0
- data/README.md +107 -0
- data/lib/ziltoid/command_parser.rb +53 -0
- data/lib/ziltoid/email_notifier.rb +24 -0
- data/lib/ziltoid/process.rb +106 -0
- data/lib/ziltoid/system.rb +77 -0
- data/lib/ziltoid/watcher.rb +86 -0
- data/lib/ziltoid.rb +3 -0
- data/ziltoid.gemspec +15 -0
- metadata +66 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 77f322004f95c4414b3364d2f5197ffda8b7dfd4
|
4
|
+
data.tar.gz: b47765f8f8d5484e7a70e6dd9a94e6b59242aa14
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3c21b057c2abbe9c46c2b1227bd84ab2e8eea66d8852220e5421b163e98eb97c485ce20e7f9fe812c670e3e98dac881707debb35494062206917164ef6aeedf4
|
7
|
+
data.tar.gz: 22f3f11346e327a60d813098d71e6ca254117f126390ffecb791df8c0125f8808f9f6a218b6b97aecf6a330b400efd46e22e0baa999c5a5453e4f2217167e4dd
|
data/README.md
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
# ziltoid
|
2
|
+
|
3
|
+
Cron based monitoring system.
|
4
|
+
|
5
|
+
There are many softwares that aim to watch processes, keeping them alive and clean. Some of them are well known :
|
6
|
+
- god (http://godrb.com)
|
7
|
+
- monit (http://mmonit.com/monit/)
|
8
|
+
- bluepill (https://github.com/bluepill-rb/bluepill)
|
9
|
+
- ... (https://www.ruby-toolbox.com/categories/server_monitoring)
|
10
|
+
|
11
|
+
All have good and bad sides.
|
12
|
+
One of the bad side is that each alternative is based on a deamon that compute data and then sleeps for a while. Who is monitoring this particular deamon ? What if this process suddenly stop ?
|
13
|
+
Also, you often need root right to run those tools. On some hosting environments (mainly in shared hosting), this is an issue.
|
14
|
+
|
15
|
+
Ziltoid is an attempt to solve those issues using the crontab system. It's on every system, it launches a task periodically then waits for an amount of time, it doesn't need monitoring, it can send emails to warn of a an error, and can run any script.
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
The principle of Ziltoid is to use the crontab system. You need to create a script that monitor your processes and then configure it in your crontab to run as frequently as possible (every minutes) :
|
20
|
+
|
21
|
+
* * * * * /bin/bash -l -c 'ruby /path_to_ziltoid.rb'
|
22
|
+
|
23
|
+
Ziltoid is here to help you build this script.
|
24
|
+
|
25
|
+
### Process
|
26
|
+
|
27
|
+
It encapsulates a process and everything Ziltoid might need to monitor it :
|
28
|
+
- start, stop en restart commands
|
29
|
+
- pid file path
|
30
|
+
- RAM and CPU limits
|
31
|
+
|
32
|
+
You define one like so :
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
Ziltoid::Process.new("Lighty", {
|
36
|
+
:pid_file => "/home/ror/http/tmp/lighttpd.pid",
|
37
|
+
:commands => {
|
38
|
+
:start => "/home/ror/bin/lighty start",
|
39
|
+
:stop => "/home/ror/bin/lighty stop"
|
40
|
+
},
|
41
|
+
:limit => {
|
42
|
+
:ram => 256,
|
43
|
+
:cpu => 10
|
44
|
+
}
|
45
|
+
})
|
46
|
+
```
|
47
|
+
|
48
|
+
Processes are seen as `watchables` by Ziltoid. You can build your own watchable objects and passe them to Ziltoid, as long you can call the following methods on them :
|
49
|
+
- `start`
|
50
|
+
- `stop`
|
51
|
+
- `restart`
|
52
|
+
- `watch`
|
53
|
+
|
54
|
+
### Email Notifier
|
55
|
+
|
56
|
+
This is a wrapper to email notifications. Every log message of a level higher than Logger::INFO will be sent by email.
|
57
|
+
|
58
|
+
You can configure a mail like so :
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
Ziltoid::EmailNotifier.new(
|
62
|
+
:via_options => {
|
63
|
+
:address => 'smtp.ziltoid.com',
|
64
|
+
:port => '25',
|
65
|
+
:domain => "ziltoid.com"
|
66
|
+
},
|
67
|
+
:subject => "[Balloonz] Ziltoid message",
|
68
|
+
:to => ['developers@sociabliz.com'],
|
69
|
+
:from => 'ziltoidd@ziltoid.com'
|
70
|
+
)
|
71
|
+
```
|
72
|
+
|
73
|
+
The `via_options` accept every options supported by the [pony](https://github.com/benprew/pony) library.
|
74
|
+
|
75
|
+
You can build your own notifiers (for IRC, XMPP, BaseCamp, Redmine, ....) as long as it respond to the `send` method. This method receives a `message` parameter which is the message to be sent.
|
76
|
+
|
77
|
+
### Watcher
|
78
|
+
|
79
|
+
This is the main object of Ziltoid. You can think of it as a container. With this container, you plug in a Logger, a Notifier and as many watchables as you want. Then, you run the commande of your choice.
|
80
|
+
|
81
|
+
Commands are :
|
82
|
+
- `start`: to start watchable items
|
83
|
+
- `stop`: to stop watchable items
|
84
|
+
- `restart`: to restart watchable items
|
85
|
+
- `watch`: to watch watchable items. IE start them if dead, restart them if of limits
|
86
|
+
|
87
|
+
You can see a sample Ziltoid script in the `exemple` folder.
|
88
|
+
|
89
|
+
## Drawbacks
|
90
|
+
|
91
|
+
Ziltoid is not yet complet. We are working on other watchables, like disk usage and RAM usage.
|
92
|
+
We also want to work on a grace system, where we don't count the RAM and CPU at start of process, and where we wait for a certain number of off-limit mesures to restart a process (and allow burst).
|
93
|
+
|
94
|
+
One of the bad point of the crontab system is that it doesn't run under the minute. But we think that if our system can't handle a dead process for a minute, there is an issue somewhere (in replication, sizing, ...).
|
95
|
+
|
96
|
+
## About Ziltoid
|
97
|
+
|
98
|
+
It comes from Devin Townsen famous album "Ziltoid the omniscient".
|
99
|
+
Ziltoid is omniscient, watches everything and control everything. Even processes.
|
100
|
+
|
101
|
+
Ziltoid is given to you by [The Social Client](http://www.thesocialclient.com), a digital and CRM consultant agency.
|
102
|
+
|
103
|
+
## Licencing
|
104
|
+
|
105
|
+
Ziltoid is a [Beerware](http://en.wikipedia.org/wiki/Beerware) and is licensed under the terms of the [WTFPL](http://www.wtfpl.net), see the included WTFPL-LICENSE file.
|
106
|
+
|
107
|
+
If we meet some day, and you think this stuff is worth it, you can buy us a beer in return.
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
module Ziltoid
|
5
|
+
class CommandParser
|
6
|
+
|
7
|
+
ALLOWED_COMMANDS = ["watch", "start", "stop", "restart"]
|
8
|
+
|
9
|
+
# Returns a structure describing the options.
|
10
|
+
def self.parse(args)
|
11
|
+
runnable = OpenStruct.new
|
12
|
+
|
13
|
+
helptext = <<-HELP
|
14
|
+
Available commands are :
|
15
|
+
watch : watches all processes
|
16
|
+
start : starts all processes
|
17
|
+
stop : stops all processes
|
18
|
+
restart : restarts all processes
|
19
|
+
HELP
|
20
|
+
|
21
|
+
opt_parser = OptionParser.new do |opts|
|
22
|
+
# Printing generic help at the top of commands summary
|
23
|
+
opts.banner = "Usage: ziltoid.rb [options]"
|
24
|
+
opts.separator ""
|
25
|
+
opts.separator helptext
|
26
|
+
opts.separator ""
|
27
|
+
opts.separator "Common options :"
|
28
|
+
|
29
|
+
# No argument, shows at tail. This will print a commands summary.
|
30
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
31
|
+
puts opts
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Retrieves all arguments except option-like ones (e.g. '-h' or '-v')
|
37
|
+
opt_parser.parse!(args)
|
38
|
+
# Fetches the first argument as the intended command
|
39
|
+
command = args.shift
|
40
|
+
|
41
|
+
# Making sure the command is valid, otherwise print commands summary
|
42
|
+
if command && ALLOWED_COMMANDS.include?(command)
|
43
|
+
runnable.command = command
|
44
|
+
else
|
45
|
+
puts opt_parser.help
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
|
49
|
+
runnable
|
50
|
+
end # parse()
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'pony'
|
2
|
+
|
3
|
+
module Ziltoid
|
4
|
+
class EmailNotifier
|
5
|
+
attr_accessor :via_options, :from, :to, :subject
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
self.via_options = options[:via_options]
|
9
|
+
self.to = options[:to]
|
10
|
+
self.from = options[:from]
|
11
|
+
self.subject = options[:subject]
|
12
|
+
end
|
13
|
+
|
14
|
+
def send(message)
|
15
|
+
Pony.mail(
|
16
|
+
:to => self.to,
|
17
|
+
:via => :smtp,
|
18
|
+
:via_options => self.via_options,
|
19
|
+
:from => self.from,
|
20
|
+
:subject => self.subject, :body => message
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Ziltoid
|
2
|
+
class Process
|
3
|
+
attr_accessor :name, :ram_limit, :cpu_limit, :start_command, :stop_command, :restart_command, :pid_file
|
4
|
+
|
5
|
+
WAIT_TIME_BEFORE_CHECK = 1.0
|
6
|
+
|
7
|
+
def initialize(name, options = {})
|
8
|
+
self.name = name
|
9
|
+
self.ram_limit = options[:limit] ? options[:limit][:ram] : nil
|
10
|
+
self.cpu_limit = options[:limit] ? options[:limit][:cpu] : nil
|
11
|
+
self.pid_file = options[:pid_file] || "~/.ziltoid/#{name}.pid"
|
12
|
+
|
13
|
+
if options[:commands]
|
14
|
+
self.start_command = options[:commands][:start] || nil
|
15
|
+
self.stop_command = options[:commands][:stop] || nil
|
16
|
+
self.restart_command = options[:commands][:restart] || nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def pid
|
21
|
+
if self.pid_file && File.exist?(self.pid_file)
|
22
|
+
str = File.read(pid_file)
|
23
|
+
str.to_i if str.size > 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def alive?
|
28
|
+
Ziltoid::System.pid_alive?(self.pid)
|
29
|
+
end
|
30
|
+
|
31
|
+
def dead?
|
32
|
+
!alive?
|
33
|
+
end
|
34
|
+
|
35
|
+
def remove_pid_file
|
36
|
+
if self.pid_file && File.exist?(self.pid_file)
|
37
|
+
File.delete(self.pid_file)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def above_cpu_limit?(include_children = true)
|
42
|
+
Ziltoid::System.cpu_usage(self.pid, include_children) > self.cpu_limit.to_f
|
43
|
+
end
|
44
|
+
|
45
|
+
def above_ram_limit?(include_children = true)
|
46
|
+
Ziltoid::System.ram_usage(self.pid, include_children) > self.ram_limit.to_i * 1024
|
47
|
+
end
|
48
|
+
|
49
|
+
def watch!
|
50
|
+
Watcher.log("Ziltoid is watching process #{self.name}")
|
51
|
+
if !alive?
|
52
|
+
Watcher.log("Process #{self.name} is dead", Logger::WARN)
|
53
|
+
return start!
|
54
|
+
end
|
55
|
+
if above_cpu_limit?
|
56
|
+
Watcher.log("Process #{self.name} is above CPU limit (#{self.cpu_limit.to_f})", Logger::WARN)
|
57
|
+
return restart!
|
58
|
+
end
|
59
|
+
if above_ram_limit?
|
60
|
+
Watcher.log("Process #{self.name} is above RAM limit (#{self.ram_limit.to_f})", Logger::WARN)
|
61
|
+
return restart!
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def start!
|
66
|
+
return if Ziltoid::System.pid_alive?(self.pid)
|
67
|
+
Watcher.log("Ziltoid is starting process #{self.name}", Logger::WARN)
|
68
|
+
remove_pid_file
|
69
|
+
%x(#{self.start_command})
|
70
|
+
end
|
71
|
+
|
72
|
+
def stop!
|
73
|
+
Watcher.log("Ziltoid is stoping process #{self.name}", Logger::WARN)
|
74
|
+
memoized_pid = self.pid
|
75
|
+
|
76
|
+
if dead?
|
77
|
+
remove_pid_file
|
78
|
+
else
|
79
|
+
|
80
|
+
thread = Thread.new do
|
81
|
+
%x(#{self.stop_command})
|
82
|
+
sleep(WAIT_TIME_BEFORE_CHECK)
|
83
|
+
if alive?
|
84
|
+
%x(kill #{memoized_pid})
|
85
|
+
sleep(WAIT_TIME_BEFORE_CHECK)
|
86
|
+
if alive?
|
87
|
+
%x(kill -9 #{memoized_pid})
|
88
|
+
sleep(WAIT_TIME_BEFORE_CHECK)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
remove_pid_file if dead?
|
92
|
+
end.join
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def restart!
|
98
|
+
Watcher.log("Ziltoid is restarting process #{self.name}", Logger::WARN)
|
99
|
+
alive = self.alive?
|
100
|
+
return %x(#{self.restart_command}) if alive && self.restart_command
|
101
|
+
stop! if alive
|
102
|
+
return start!
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Ziltoid
|
2
|
+
|
3
|
+
module System
|
4
|
+
|
5
|
+
# The position of each field in ps output
|
6
|
+
PS_FIELDS = [:pid, :ppid, :cpu, :ram]
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def pid_alive?(pid)
|
11
|
+
return false if pid.nil?
|
12
|
+
begin
|
13
|
+
::Process.kill(0, pid)
|
14
|
+
true
|
15
|
+
rescue Errno::EPERM # no permission, but it is definitely alive
|
16
|
+
true
|
17
|
+
rescue Errno::ESRCH
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def ps_aux
|
23
|
+
# BSD style ps invocation
|
24
|
+
processes = `ps axo pid,ppid,pcpu,rss`.split("\n")
|
25
|
+
|
26
|
+
processes.inject({}) do |result, process|
|
27
|
+
info = process.split(/\s+/)
|
28
|
+
info.delete_if { |p_info| p_info.strip.empty? }
|
29
|
+
info.map! { |p_info| p_info.gsub(",", ".") }
|
30
|
+
|
31
|
+
info = PS_FIELDS.each_with_index.inject({}) do |info_hash, (field, field_index)|
|
32
|
+
info_hash[field] = info[field_index]
|
33
|
+
info_hash
|
34
|
+
end
|
35
|
+
|
36
|
+
pid = info[:pid].strip.to_i
|
37
|
+
result[pid] = info
|
38
|
+
result
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def cpu_usage(pid, include_children = true)
|
43
|
+
ps = ps_aux
|
44
|
+
return unless ps[pid]
|
45
|
+
cpu_used = ps[pid][:cpu].to_f
|
46
|
+
|
47
|
+
get_children(pid).each do |child_pid|
|
48
|
+
cpu_used += ps[child_pid][:cpu].to_f if ps[child_pid]
|
49
|
+
end if include_children
|
50
|
+
|
51
|
+
cpu_used
|
52
|
+
end
|
53
|
+
|
54
|
+
def ram_usage(pid, include_children = true)
|
55
|
+
ps = ps_aux
|
56
|
+
return unless ps[pid]
|
57
|
+
mem_used = ps[pid][:ram].to_i
|
58
|
+
|
59
|
+
get_children(pid).each do |child_pid|
|
60
|
+
mem_used += ps[child_pid][:ram].to_i if ps[child_pid]
|
61
|
+
end if include_children
|
62
|
+
|
63
|
+
mem_used
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_children(parent_pid)
|
67
|
+
child_pids = []
|
68
|
+
ps_aux.each_pair do |_pid, info|
|
69
|
+
child_pids << info[:pid].to_i if info[:ppid].to_i == parent_pid.to_i
|
70
|
+
end
|
71
|
+
grand_children = child_pids.map { |pid| get_children(pid) }.flatten
|
72
|
+
child_pids.concat grand_children
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
module Ziltoid
|
4
|
+
class Watcher
|
5
|
+
attr_accessor :watchlist
|
6
|
+
|
7
|
+
def logger
|
8
|
+
Ziltoid::Watcher.logger
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.logger
|
12
|
+
@@logger
|
13
|
+
end
|
14
|
+
|
15
|
+
def notifiers
|
16
|
+
Ziltoid::Watcher.notifiers
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.notifiers
|
20
|
+
@@notifiers ||= []
|
21
|
+
return @@notifiers
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.log(message, level = Logger::INFO)
|
25
|
+
@@logger ||= Logger.new($stdout)
|
26
|
+
@@logger.add(level, message)
|
27
|
+
if level > Logger::INFO
|
28
|
+
self.notifiers.each do |n|
|
29
|
+
n.send(message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(options = {})
|
35
|
+
self.watchlist ||= {}
|
36
|
+
@@logger = options[:logger] || Logger.new($stdout)
|
37
|
+
@@logger.progname = options[:progname] || "Ziltoid"
|
38
|
+
@@logger.level = options[:log_level] || Logger::INFO
|
39
|
+
@@notifiers = options[:notifiers] if options[:notifiers]
|
40
|
+
end
|
41
|
+
|
42
|
+
def add(watchable)
|
43
|
+
self.watchlist[watchable.name] = watchable
|
44
|
+
end
|
45
|
+
|
46
|
+
def run!(command = :watch)
|
47
|
+
watchlist.values.each do |watchable|
|
48
|
+
watchable.send("#{command}!".to_sym)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def watch!
|
53
|
+
Watcher.log("Ziltoid is now on duty : watching all watchables !")
|
54
|
+
run!(:watch)
|
55
|
+
end
|
56
|
+
|
57
|
+
def start!
|
58
|
+
Watcher.log("Ziltoid is now on duty : all watchables starting !")
|
59
|
+
run!(:start)
|
60
|
+
end
|
61
|
+
|
62
|
+
def stop!
|
63
|
+
Watcher.log("Ziltoid is now on duty : all watchables stoping !")
|
64
|
+
run!(:stop)
|
65
|
+
end
|
66
|
+
|
67
|
+
def restart!
|
68
|
+
Watcher.log("Ziltoid is now on duty : all watchables restarting !")
|
69
|
+
run!(:restart)
|
70
|
+
end
|
71
|
+
|
72
|
+
def run(command = :watch)
|
73
|
+
case command
|
74
|
+
when :watch
|
75
|
+
watch!
|
76
|
+
when :start
|
77
|
+
start!
|
78
|
+
when :stop
|
79
|
+
stop!
|
80
|
+
when :restart
|
81
|
+
restart!
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
data/lib/ziltoid.rb
ADDED
data/ziltoid.gemspec
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'ziltoid'
|
3
|
+
s.version = '1.0.0'
|
4
|
+
s.date = '2014-12-22'
|
5
|
+
s.summary = "Ziltoid, crontab based monitoring system"
|
6
|
+
s.description = "Ziltoid, crontab based monitoring system"
|
7
|
+
s.authors = ["Stéphane Akkaoui", "Vincent Gabou"]
|
8
|
+
s.email = 'developers@sociabliz.com'
|
9
|
+
s.files = %w(README.md ziltoid.gemspec) + Dir['lib/**/*.rb']
|
10
|
+
s.add_dependency 'pony'
|
11
|
+
|
12
|
+
s.homepage =
|
13
|
+
'http://github.com/meuble/ziltoid'
|
14
|
+
s.license = 'WTFPL'
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ziltoid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stéphane Akkaoui
|
8
|
+
- Vincent Gabou
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-12-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: pony
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
description: Ziltoid, crontab based monitoring system
|
29
|
+
email: developers@sociabliz.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- README.md
|
35
|
+
- lib/ziltoid.rb
|
36
|
+
- lib/ziltoid/command_parser.rb
|
37
|
+
- lib/ziltoid/email_notifier.rb
|
38
|
+
- lib/ziltoid/process.rb
|
39
|
+
- lib/ziltoid/system.rb
|
40
|
+
- lib/ziltoid/watcher.rb
|
41
|
+
- ziltoid.gemspec
|
42
|
+
homepage: http://github.com/meuble/ziltoid
|
43
|
+
licenses:
|
44
|
+
- WTFPL
|
45
|
+
metadata: {}
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 2.4.2
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: Ziltoid, crontab based monitoring system
|
66
|
+
test_files: []
|