watchmonkey_cli 1.9.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 623f20ce059d5f6b5b7a9681f22cf5ce6f165e13481b6707289be5d1a8fa2859
4
- data.tar.gz: b4b3ab70d5aa2fb649cdbbaa0e2c99d2da446bfae49ef332bf2d65b3d551b391
3
+ metadata.gz: 5d2615fa891c7ccb38541934fa918c33fa37a93cc3d3c52ece8db41a100e1d0b
4
+ data.tar.gz: 98f2a66da3fdc810c9b7fc1396ba12a605f3cd12d939585e9c9ed03d9f252fbf
5
5
  SHA512:
6
- metadata.gz: 3b82d300ad1617ded3156dc8fa1e82f27a435f9965134236d2b21fef7d8a2df2019e7e7786650ae3bc4c925d9cc9e27e9054b015ed3f514b0d88185c5f47d93b
7
- data.tar.gz: 65a2ec5bad871ca993cebdee262461f11f175117377ecdad0261bda5fb780f6c5a6962d7447fb0c108541880377d8b8c4880d444b540886ad567051dcc703781
6
+ metadata.gz: 23307a955c34627a32e0023df5dc40874eda5d72e80f152e2a57bcf12be767b34db53fc565ffbc8329060cbfe8e72871956123bf553f0ff409ed4468528bca0f
7
+ data.tar.gz: c671b5bac01cf8c423eef81ada024cd35a1c82f426c9fa80cee4cb90047aa242c579a39248ef349d2cc69d7be281037caac74afa410d59af633029f5b5860b52
data/Gemfile CHANGED
@@ -2,3 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in dle.gemspec
4
4
  gemspec
5
+
6
+ # optional dependencies
7
+ gem 'telegram-bot-ruby'
data/README.md CHANGED
@@ -4,10 +4,11 @@ Watchmonkey is a very simple tool to monitor resources with Ruby without the nee
4
4
 
5
5
  Before looking any further you might want to know:
6
6
 
7
- * There is no escalation or notification system but you may add it yourself
8
- * I created this for being used with [Platypus](http://sveinbjorn.org/platypus) hence the [Platypus Hook](https://github.com/2called-chaos/watchmonkey_cli/blob/master/lib/watchmonkey_cli/hooks/platypus.rb)
7
+ * There is no escalation or notification system (except experimental telegram bot) but you may add it yourself
8
+ * I originally created this for being used with [Platypus](http://sveinbjorn.org/platypus) hence the [Platypus Hook](https://github.com/2called-chaos/watchmonkey_cli/blob/master/lib/watchmonkey_cli/hooks/platypus.rb)
9
9
  * This is how the text output looks like: [Screenshot](http://imgur.com/8yLYnKb)
10
10
  * This is how the Platypus support looks like: [ProgressBar](http://imgur.com/Vd8ZD7A) [HTML/WebView](http://imgur.com/5FwmWFZ)
11
+ * This is how Telegram Bot looks for now: [Telegram Screenshot](http://imgur.com/HBONi51)
11
12
 
12
13
  ---
13
14
 
@@ -43,6 +44,8 @@ To get a list of available options invoke Watchmonkey with the `--help` or `-h`
43
44
  --generate-config [myconfig] Generates a example config in ~/.watchmonkey
44
45
  -l, --log [file] Log to file, defaults to ~/.watchmonkey/logs/watchmonkey.log
45
46
  -t, --threads [NUM] Amount of threads to be used for checking (default: 10)
47
+ -e, --except tag1,tag2 Don't run tasks tagged with given tags
48
+ -o, --only tag1,tag2 Only run tasks tagged with given tags
46
49
  -s, --silent Only print errors and infos
47
50
  -q, --quiet Only print errors
48
51
 
@@ -81,6 +84,15 @@ If you want to monitor something that is not covered by the buildin handlers you
81
84
  By default Watchmonkey will run all tests once and then exit. This addon will enable Watchmonkey to run in a loop and run tests on a periodic interval.
82
85
  Since this seems like a core feature it might get included directly into Watchmonkey but for now take a look at the [application configuration file](https://github.com/2called-chaos/watchmonkey_cli/blob/master/doc/config_example.rb) and [ReQueue source code](https://github.com/2called-chaos/watchmonkey_cli/blob/master/lib/watchmonkey_cli/hooks/requeue.rb) for integration examples.
83
86
 
87
+ ### Telegram Bot
88
+ Notify via Telegram. Experimental. Refer to [application configuration file](https://github.com/2called-chaos/watchmonkey_cli/blob/master/doc/config_example.rb) and [TelegramBot source code](https://github.com/2called-chaos/watchmonkey_cli/blob/master/lib/watchmonkey_cli/hooks/telegram_bot.rb) for further information.
89
+
90
+ * works with ReQueue (wouldn't make much sense otherwise huh?)
91
+ * optional per-user message throttling via checker uniqid (checker name + host + arguments)
92
+ * optional per-user only/except filters based on tags
93
+ * planned: robust telegram connection failure handling
94
+ * planned: per-user regex exclusion filters
95
+
84
96
  ### Platypus support
85
97
  [Platypus](http://sveinbjorn.org/platypus) is a MacOS software to create dead simple GUI wrappers for scripts. There is buildin support for the interface types ProgressBar and WebView. For integration examples take a look at the [application configuration file](https://github.com/2called-chaos/watchmonkey_cli/blob/master/doc/config_example.rb) and [Platypus hook source code](https://github.com/2called-chaos/watchmonkey_cli/blob/master/lib/watchmonkey_cli/hooks/platypus.rb).
86
98
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.9.0
1
+ 1.12.0
@@ -12,9 +12,18 @@ module MyWatchmonkeyCheckers
12
12
  # e.g. my_checker "http://google.com", some_option: true
13
13
  self.checker_name = "my_checker"
14
14
 
15
+ # Maximum amount of time this task may run before it gets killed.
16
+ # Set to 0/false to have no time limit whatsoever.
17
+ # Set to proc to evaluate at runtime
18
+ # Defaults to app.opts[:maxrt] if nil/unset
19
+ #self.maxrt = false
20
+ #self.maxrt = 5.minutes
21
+ #self.maxrt = ->(app, checker, args){ app.opts[:maxrt] && app.opts[:maxrt] * 2 }
22
+
15
23
  # Called by configuration defining a check with all the arguments.
16
24
  # e.g. my_checker "http://google.com", some_option: true
17
25
  # Should invoke `app.enqueue` which will by default call `#check!` method with given arguments.
26
+ # Must have options as last argument!
18
27
  def enqueue host, opts = {}
19
28
  opts = { some_option: false }.merge(opts)
20
29
 
@@ -28,6 +37,7 @@ module MyWatchmonkeyCheckers
28
37
  end
29
38
 
30
39
  # First argument is the result object, all other arguments came from `app.enqueue` call.
40
+ # Must have options as last argument!
31
41
  def check! result, host, opts = {}
32
42
  # Do your checks and modify the result object.
33
43
  # Debug messages will not show if -s/--silent or -q/--quiet argument is passed.
@@ -43,3 +43,59 @@ if @argv.delete("--platypus")
43
43
 
44
44
  @opts[:colorize] = false # doesn't render in platypus
45
45
  end
46
+
47
+
48
+
49
+ # Integrate Telegram notifications
50
+ # For options refer to the source code:
51
+ # https://github.com/2called-chaos/watchmonkey_cli/blob/master/lib/watchmonkey_cli/hooks/telegram_bot.rb
52
+ if @argv.delete("--telegram")
53
+ require "watchmonkey_cli/hooks/telegram_bot"
54
+ WatchmonkeyCli::TelegramBot.hook!(self, {
55
+ # to create a bot refer to https://core.telegram.org/bots#6-botfather
56
+ api_key: "123456789:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
57
+
58
+ # poll timeout, the longer this is (in seconds) the longer it will take to gracefully shut down
59
+ timeout: 5,
60
+
61
+ # optionally log incoming messages
62
+ #logger: Logger.new(STDOUT),
63
+
64
+ # purge old throttle data, default: 30.days
65
+ #throttle_retention: 30.days,
66
+
67
+ # retry sending messages that failed, default: false
68
+ # Not recommended since on connection failure a HUGE amount of messages will accumulate
69
+ # and spam you (and reach rate limits) upon connection restore.
70
+ #retry_on_egress_failure: false,
71
+
72
+ # configure your notification targets, if not listed you can't interact with the bot
73
+ notify: [
74
+ [
75
+ # your telegram ID, if you try talking to the bot it will tell you your ID
76
+ 987654321,
77
+
78
+ # flags
79
+ # - :all -- same as :debug, :info, :error (not recommended)
80
+ # - :debug -- send all debug messages (not recommended)
81
+ # - :info -- send all info messages (not recommended)
82
+ # - :error -- send all error messages (RECOMMENDED)
83
+ # - :admin_flag -- allows access to some commands (/wm_shutdown /stats)
84
+ [:error, :admin_flag],
85
+
86
+ # options (all optional, you can comment them out but leave the {})
87
+ {
88
+ # throttle: seconds(int) -- throttle messages by checker uniqid for this long (0/false = no throttle, default)
89
+ throttle: 15*60,
90
+
91
+ # only: Array(string, symbol) -- only notify when tagged with given tags
92
+ only: %w[production critical],
93
+
94
+ # except: Array(string, symbol) -- don't notify when tagged with given tags (runs after only-check)
95
+ except: %w[database],
96
+ }
97
+ ],
98
+ [123456789, [:error], { throttle: 30.minutes }]
99
+ ],
100
+ })
101
+ end
@@ -59,9 +59,11 @@ module WatchmonkeyCli
59
59
  end
60
60
  end
61
61
 
62
- def initialize app, file
62
+ def initialize app, file = nil, tags = []
63
63
  @app = app
64
64
  @file = file
65
+ @tags = tags
66
+ return unless file
65
67
  begin
66
68
  eval File.read(file, encoding: "utf-8"), binding, file
67
69
  rescue
@@ -74,9 +76,42 @@ module WatchmonkeyCli
74
76
  @app.fetch_connection(:ssh, name, opts, &b)
75
77
  end
76
78
 
79
+ def tag_all! *tags
80
+ @tags = tags.map(&:to_sym)
81
+ end
82
+
77
83
  def method_missing meth, *args, &block
78
84
  if c = @app.checkers[meth.to_s]
79
- c.enqueue(*args)
85
+ opts = args.extract_options!
86
+ only = @app.opts[:tag_only]
87
+ except = @app.opts[:tag_except]
88
+
89
+ # build tags
90
+ tags = (@tags + (opts[:tags] || []).map(&:to_sym))
91
+ if @app.opts[:autotag]
92
+ tags << :"WMC-#{c.class.checker_name}" # checker name
93
+ if args[0].is_a?(Symbol)
94
+ tags << :"WMS-#{args[0]}" # ssh/local connection
95
+ elsif args[0].is_a?(String) && args[0].match(/\Ahttp(s)?:\/\//i)
96
+ uri = URI.parse(args[0]) rescue false
97
+ tags << :"WMH-#{uri.hostname.gsub(".", "_")}" if uri # hostname from URL
98
+ end
99
+ end
100
+ tags = tags.uniq
101
+ @app.tag_list.merge(tags)
102
+
103
+ if only.any?
104
+ if tags.any?{|t| only.include?(t) }
105
+ if tags.any?{|t| except.include?(t) }
106
+ return @app.debug "Skipping #{meth} with #{args} and #{opts} due to tag_except filter..."
107
+ end
108
+ else
109
+ return @app.debug "Skipping #{meth} with #{args} and #{opts} due to tag_only filter..."
110
+ end
111
+ elsif tags.any?{|t| except.include?(t) }
112
+ return @app.debug "Skipping #{meth} with #{args} and #{opts} due to tag_except filter..."
113
+ end
114
+ c.enqueue(*args, opts.merge(tags: tags))
80
115
  else
81
116
  super
82
117
  end
@@ -1,5 +1,26 @@
1
1
  # This is a Ruby file!
2
2
 
3
+ # =========================================
4
+ # = Step 0: Tag all checkers in this file =
5
+ # =========================================
6
+
7
+ # All checkers you define after this will get these
8
+ # base tags (you can pass additional ones).
9
+ # Do note that you can call this method multiple
10
+ # times and it will replace your base tags for
11
+ # all checkers to follow, base tags will be cleared
12
+ # upon reaching the end of the file.
13
+
14
+ tag_all! :production, :critical
15
+
16
+ # You can use additional tags on any checker by passing
17
+ # a `tags` option consisting of an Array of strings or symbols.
18
+ # e.g.:
19
+ # some_checker :some_target, tags: %w[critical foo bar]
20
+
21
+
22
+
23
+
3
24
  # =================================
4
25
  # = Step 1: Setup SSH connections =
5
26
  # =================================
@@ -36,7 +57,7 @@ ssh_connection :my_server, host: "wheel@example.com", port: 23 # additional opti
36
57
  #
37
58
  # timeout Maximum time to wait for request (default: 20 seconds)
38
59
  # verify If enabled the peer will be verified (default: true)
39
- # threshold Minimum certificate lifetime before showing warnings (default: 1.month)
60
+ # threshold Minimum certificate lifetime before showing warnings (default: 28.days)
40
61
  #
41
62
  ssl_expiration "https://example.com", threshold: 3.months
42
63
 
@@ -1,6 +1,12 @@
1
1
  module WatchmonkeyCli
2
2
  class Application
3
3
  module Core
4
+ def filtered_threads
5
+ Thread.list.reject do |thr|
6
+ thr.backtrace[0]["gems/concurrent-ruby"] rescue false
7
+ end
8
+ end
9
+
4
10
  # ===================
5
11
  # = Signal trapping =
6
12
  # ===================
@@ -37,10 +43,31 @@ module WatchmonkeyCli
37
43
  end
38
44
  end
39
45
 
40
- def fire which, *args
46
+ def fire which, *args, &block
41
47
  return if @disable_event_firing
42
- sync { debug "[Event] Firing #{which} (#{@hooks[which].try(:length) || 0} handlers) #{args.map(&:class)}", 99 }
43
- @hooks[which] && @hooks[which].each{|h| h.call(*args) }
48
+ sync { debug "[Event] Firing #{which} (#{@hooks[which].try(:length) || 0} handlers) #{args.map(&:class)}#{" HAS_BLOCK" if block}", 99 }
49
+ if block && (!@hooks[which] || @hooks[which].empty?)
50
+ block.call
51
+ else
52
+ if @hooks[which] && @hooks[which].any?
53
+ if block
54
+ catch :abort do
55
+ _fire_around(@hooks[which], args, 0, &block)
56
+ end
57
+ else
58
+ @hooks[which].all?{|h| h.call(*args) }
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def _fire_around hooks, args, index = 0, &block
65
+ return block.call unless hook = hooks[index]
66
+ skip = catch(:skip) {
67
+ hook.call(*args) { _fire_around(hooks, args, index + 1, &block) }
68
+ nil
69
+ }
70
+ _fire_around(hooks, args, index + 1, &block) if skip
44
71
  end
45
72
 
46
73
 
@@ -81,7 +108,12 @@ module WatchmonkeyCli
81
108
 
82
109
  def close_connections!
83
110
  @connections.each do |type, clist|
84
- clist.each{|id, con| con.close! }
111
+ clist.each do |id, con|
112
+ if con.established?
113
+ debug "[SHUTDOWN] closing #{type} connection #{id} #{con}"
114
+ con.close!
115
+ end
116
+ end
85
117
  end
86
118
  end
87
119
 
@@ -97,8 +129,26 @@ module WatchmonkeyCli
97
129
  @queue << [checker, a, ->(*a) {
98
130
  begin
99
131
  result = Checker::Result.new(checker, *a)
132
+
133
+ # assign tags
134
+ taskopts = a.extract_options!
135
+ result.tags = taskopts[:tags] || []
136
+ a << taskopts
137
+
100
138
  checker.debug(result.str_running)
101
- checker.safe(result.str_safe) { cb.call(result, *a) }
139
+ checker.rsafe(result) {
140
+ timeout = checker.class.maxrt.nil? ? @opts[:maxrt] : checker.class.maxrt
141
+ timeout = timeout.call(self, checker, a) if timeout.respond_to?(:call)
142
+ begin
143
+ if timeout && timeout > 0
144
+ Timeout::timeout(timeout) { cb.call(result, *a) }
145
+ else
146
+ cb.call(result, *a)
147
+ end
148
+ rescue Timeout::Error => ex
149
+ result.error! "TIMEOUT: did not finish within #{timeout} seconds, task killed!"
150
+ end
151
+ }
102
152
  fire(:result_dump, result, a, checker)
103
153
  result.dump!
104
154
  ensure
@@ -3,7 +3,11 @@ module WatchmonkeyCli
3
3
  module Dispatch
4
4
  def dispatch action = (@opts[:dispatch] || :help)
5
5
  if respond_to?("dispatch_#{action}")
6
- send("dispatch_#{action}")
6
+ fire(:dispatch_before, action)
7
+ fire(:dispatch_around, action) do
8
+ send("dispatch_#{action}")
9
+ end
10
+ fire(:dispatch_after, action)
7
11
  else
8
12
  abort("unknown action #{action}", 1)
9
13
  end
@@ -41,7 +45,7 @@ module WatchmonkeyCli
41
45
  ensure
42
46
  @running = false
43
47
  stop_checkers!
44
- close_connections!
48
+ Timeout::timeout(@opts[:conclosewait]) { close_connections! } rescue false
45
49
  release_signals
46
50
  end
47
51
 
@@ -13,6 +13,10 @@ module WatchmonkeyCli
13
13
  sync { @opts[:stdout].send(:warn, *a) }
14
14
  end
15
15
 
16
+ def info msg
17
+ puts c("[INFO] #{msg}", :blue)
18
+ end
19
+
16
20
  def debug msg, lvl = 1
17
21
  puts c("[DEBUG] #{msg}", :black) if @opts[:debug] && @opts[:debug] >= lvl
18
22
  end
@@ -1,6 +1,6 @@
1
1
  module WatchmonkeyCli
2
2
  class Application
3
- attr_reader :opts, :checkers, :connections, :threads, :queue, :hooks, :processed
3
+ attr_reader :opts, :checkers, :connections, :threads, :queue, :hooks, :processed, :tag_list
4
4
  include Helper
5
5
  include OutputHelper
6
6
  include Colorize
@@ -21,9 +21,22 @@ module WatchmonkeyCli
21
21
  app.haltpoint
22
22
  rescue Interrupt
23
23
  app.abort("Interrupted", 1)
24
+ rescue SystemExit
25
+ # silence
24
26
  ensure
27
+ $wm_runtime_exiting = true
25
28
  app.fire(:wm_shutdown)
26
- app.debug "#{Thread.list.length} threads remain..."
29
+ if app.filtered_threads.length > 1
30
+ app.error "[WARN] #{app.filtered_threads.length} threads remain (should be 1)..."
31
+ app.filtered_threads.each do |thr|
32
+ app.debug "[THR] #{Thread.main == thr ? "MAIN" : "THREAD"}\t#{thr.alive? ? "ALIVE" : "DEAD"}\t#{thr.inspect}", 10
33
+ thr.backtrace.each do |l|
34
+ app.debug "[THR]\t#{l}", 20
35
+ end
36
+ end
37
+ else
38
+ app.debug "1 thread remains..."
39
+ end
27
40
  end
28
41
  end
29
42
  end
@@ -36,6 +49,7 @@ module WatchmonkeyCli
36
49
  @monitor = Monitor.new
37
50
  @threads = []
38
51
  @queue = Queue.new
52
+ @tag_list = Set.new
39
53
  @processed = 0
40
54
  @running = false
41
55
  @opts = {
@@ -45,11 +59,16 @@ module WatchmonkeyCli
45
59
  colorize: true, # -m flag
46
60
  debug: false, # -d flag
47
61
  threads: 10, # -t flag
62
+ maxrt: 120.seconds, # max runtime of a single task after which it will be terminated (may break SSH connection), 0/false to not limit runtime
63
+ conclosewait: 10, # max seconds to wait for connections to be closed (may never if they got killed by maxrt)
48
64
  loop_forever: false, # (internal) loop forever (app mode)
49
65
  loop_wait_empty: 1, # (internal) time to wait in thread if queue is empty
66
+ autotag: true, # (internal) if true checkers will get auto tags for checker name and hostname/connection
50
67
  silent: false, # -s flag
51
68
  quiet: false, # -q flag
52
69
  stdout: STDOUT, # (internal) STDOUT redirect
70
+ tag_only: [], # -o flag
71
+ tag_except: [], # -e flag
53
72
  }
54
73
  init_params
55
74
  yield(self)
@@ -63,6 +82,8 @@ module WatchmonkeyCli
63
82
  opts.on("--generate-config [myconfig]", "Generates a example config in ~/.watchmonkey") {|s| @opts[:dispatch] = :generate_config; @opts[:config_name] = s }
64
83
  opts.on("-l", "--log [file]", "Log to file, defaults to ~/.watchmonkey/logs/watchmonkey.log") {|s| @opts[:logfile] = s || logger_filename }
65
84
  opts.on("-t", "--threads [NUM]", Integer, "Amount of threads to be used for checking (default: 10)") {|s| @opts[:threads] = s }
85
+ opts.on("-e", "--except tag1,tag2", Array, "Don't run tasks tagged with given tags") {|s| @opts[:tag_except] = s.map(&:to_sym) }
86
+ opts.on("-o", "--only tag1,tag2", Array, "Only run tasks tagged with given tags") {|s| @opts[:tag_only] = s.map(&:to_sym) }
66
87
  opts.on("-s", "--silent", "Only print errors and infos") { @opts[:silent] = true }
67
88
  opts.on("-q", "--quiet", "Only print errors") { @opts[:quiet] = true }
68
89
 
@@ -74,10 +95,15 @@ module WatchmonkeyCli
74
95
  opts.on("-z", "Do not check for updates on GitHub (with -v/--version)") { @opts[:check_for_updates] = false }
75
96
  opts.on("--dump-core", "for developers") { @opts[:dump] = true }
76
97
  end
98
+ fire(:optparse_init, @optparse)
77
99
  end
78
100
 
79
101
  def parse_params
80
- @optparse.parse!(@argv)
102
+ fire(:optparse_parse_before, @optparse)
103
+ fire(:optparse_parse_around, @optparse) do
104
+ @optparse.parse!(@argv)
105
+ end
106
+ fire(:optparse_parse_after, @optparse)
81
107
  rescue OptionParser::ParseError => e
82
108
  abort(e.message)
83
109
  dispatch(:help)
@@ -17,6 +17,14 @@ module WatchmonkeyCli
17
17
  @checker_name = name
18
18
  end
19
19
 
20
+ def self.maxrt
21
+ @maxrt
22
+ end
23
+
24
+ def self.maxrt= seconds
25
+ @maxrt = seconds
26
+ end
27
+
20
28
  module AppHelper
21
29
  def init_checkers!
22
30
  @checkers = {}
@@ -44,16 +52,24 @@ module WatchmonkeyCli
44
52
 
45
53
  class Result
46
54
  attr_reader :checker, :type, :args
47
- attr_accessor :result, :command, :data
55
+ attr_accessor :result, :command, :data, :tags
48
56
 
49
57
  def initialize checker, *args
50
58
  @checker = checker
51
59
  @args = args
52
60
  @mutex = Monitor.new
53
61
  @type = :info
62
+ @tags = []
54
63
  @spool = { error: [], info: [], debug: []}
55
64
  end
56
65
 
66
+ def uniqid additional = []
67
+ ([
68
+ self.class.name,
69
+ @args.map(&:to_s).to_s,
70
+ ] + additional).join("/")
71
+ end
72
+
57
73
  def sync &block
58
74
  @mutex.synchronize(&block)
59
75
  end
@@ -147,6 +163,10 @@ module WatchmonkeyCli
147
163
  end
148
164
  end
149
165
 
166
+ def blank_config tags = []
167
+ Application::Configuration.new(app, nil, tags)
168
+ end
169
+
150
170
  # def to_s
151
171
  # string = "#<#{self.class.name}:#{self.object_id} "
152
172
  # fields = self.class.inspector_fields.map{|field| "#{field}: #{self.send(field)}"}
@@ -168,8 +188,10 @@ module WatchmonkeyCli
168
188
  error "#{descriptor}retry #{tries} reason is `#{e.class}: #{e.message}'"
169
189
  e.backtrace.each{|l| debug "\t\t#{l}" }
170
190
  end
171
- sleep 1
172
- retry
191
+ unless $wm_runtime_exiting
192
+ sleep 1
193
+ retry
194
+ end
173
195
  end
174
196
  error "#{descriptor}retries exceeded"
175
197
  end
@@ -187,10 +209,12 @@ module WatchmonkeyCli
187
209
  e.backtrace.each{|l| resultobj.debug "\t\t#{l}" }
188
210
  resultobj.dump!
189
211
  end
190
- sleep 1
191
- retry
212
+ unless $wm_runtime_exiting
213
+ sleep 1
214
+ retry
215
+ end
192
216
  end
193
- resultobj.error! "#{descriptor}retries exceeded"
217
+ resultobj.error! "retries exceeded"
194
218
  resultobj.dump!
195
219
  end
196
220
  end
@@ -0,0 +1,29 @@
1
+ module WatchmonkeyCli
2
+ module Checkers
3
+ class DevPry < Checker
4
+ self.checker_name = "dev_pry"
5
+ self.maxrt = false
6
+
7
+ def enqueue host, opts = {}
8
+ host = app.fetch_connection(:loopback, :local) if !host || host == :local
9
+ host = app.fetch_connection(:ssh, host) if host.is_a?(Symbol)
10
+ app.enqueue(self, host, opts)
11
+ end
12
+
13
+ def check! result, host, opts = {}
14
+ if app.opts[:threads] > 1
15
+ result.error! "pry only works properly within the main thread, run watchmonkey with `-t0`"
16
+ return
17
+ end
18
+
19
+ begin
20
+ require "pry"
21
+ binding.pry
22
+ 1+1 # pry may bug out otherwise if it's last statement
23
+ rescue LoadError => ex
24
+ result.error! "pry is required (gem install pry)! #{ex.class}: #{ex.message}"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -4,7 +4,7 @@ module WatchmonkeyCli
4
4
  self.checker_name = "ftp_availability"
5
5
 
6
6
  def enqueue host, opts = {}
7
- opts = { threshold: 1.months }.merge(opts)
7
+ opts = {}.merge(opts)
8
8
  app.enqueue(self, host, opts)
9
9
  end
10
10
 
@@ -4,7 +4,7 @@ module WatchmonkeyCli
4
4
  self.checker_name = "ssl_expiration"
5
5
 
6
6
  def enqueue page, opts = {}
7
- opts = { threshold: 1.months, verify: true, timeout: 20 }.merge(opts)
7
+ opts = { threshold: 28.days, verify: true, timeout: 20 }.merge(opts)
8
8
  app.enqueue(self, page, opts)
9
9
  end
10
10
 
@@ -35,7 +35,9 @@ module WatchmonkeyCli
35
35
  # sec.check!(result, host, opts[which])
36
36
  # end
37
37
  # app.enqueue_sub(self, which, host, opts[which]) if opts[which]
38
- spawn_sub(which, host, opts[which].is_a?(Hash) ? opts[which] : {}) unless opts[which] == false
38
+ #spawn_sub(which, host, (opts[which].is_a?(Hash) ? opts[which] : {}).merge(tags: result.tags)) unless opts[which] == false
39
+ stags = (opts[:tags] || []).reject{|t| t.to_s.start_with?("WMC-") }
40
+ blank_config(stags).send(which, host, (opts[which].is_a?(Hash) ? opts[which] : {})) unless opts[which] == false
39
41
  end
40
42
  end
41
43
  end
@@ -9,7 +9,8 @@ module WatchmonkeyCli
9
9
  # if available enable ssl_expiration support
10
10
  if page.start_with?("https://") && opts[:ssl_expiration] != false && !app.running?
11
11
  sopts = { timeout: opts[:timeout] }.merge(opts[:ssl_expiration].is_a?(Hash) ? opts[:ssl_expiration] : {})
12
- spawn_sub("ssl_expiration", page, sopts)
12
+ stags = (opts[:tags] || []).reject{|t| t.to_s.start_with?("WMC-") }
13
+ blank_config(stags).ssl_expiration(page, sopts)
13
14
  end
14
15
  end
15
16
 
@@ -71,7 +71,7 @@ module WatchmonkeyCli
71
71
  <dt>Items in Queue</dt><dd class="qlength">#{@queue.length}</dd>
72
72
  <dt>Items in ReQ</dt><dd class="rqlength">#{@requeue.length}</dd>
73
73
  <dt>Workers</dt><dd class="workers">#{@threads.select{|t| t[:working] }.length}/#{@threads.length} working (#{@threads.select(&:alive?).length} alive)</dd>
74
- <dt>Threads</dt><dd class="tlength">#{Thread.list.length}</dd>
74
+ <dt>Threads</dt><dd class="tlength">#{filtered_threads.length}</dd>
75
75
  <dt>Processed entries</dt><dd class="processed">#{@processed}</dd>
76
76
  <dt>Watching since</dt><dd>#{@boot}</dd>
77
77
  <dt>Last draw</dt><dd class="lastdraw">#{Time.current}</dd>
@@ -93,7 +93,7 @@ module WatchmonkeyCli
93
93
  $("dd.qlength").html("#{@queue.length}");
94
94
  $("dd.rqlength").html("#{@requeue.length}");
95
95
  $("dd.workers").html("#{@threads.select{|t| t[:working] }.length}/#{@threads.length} working#{ti}");
96
- $("dd.tlength").html("#{Thread.list.length}");
96
+ $("dd.tlength").html("#{filtered_threads.length}");
97
97
  $("dd.processed").html("#{@processed}");
98
98
  $("dd.lastdraw").html("#{Time.current}");
99
99
  $("pre.lasterrors").html("#{escape_javascript @platypus_status_cache[:errors].map{|t,e| "#{t}: #{e}" }.join("\n")}");
@@ -37,11 +37,12 @@ module WatchmonkeyCli
37
37
  puts " Queue: #{@queue.length}"
38
38
  puts " Requeue: #{@requeue.length}"
39
39
  puts " Workers: #{@threads.select{|t| t[:working] }.length}/#{@threads.length} working (#{@threads.select(&:alive?).length} alive)"
40
- puts " Threads: #{Thread.list.length}"
40
+ puts " Threads: #{filtered_threads.length}"
41
41
  # puts " #{@threads.select(&:alive?).length} alive"
42
42
  # puts " #{@threads.select{|t| t.status == "run" }.length} running"
43
43
  # puts " #{@threads.select{|t| t.status == "sleep" }.length} sleeping"
44
44
  puts " Processed: #{@processed}"
45
+ puts " Promises: #{@telegram_bot_egress_promises.length}" if @telegram_bot_egress_promises
45
46
  puts "========== //STATUS =========="
46
47
  end
47
48
  end
@@ -101,6 +102,16 @@ module WatchmonkeyCli
101
102
  }]
102
103
  end
103
104
  end
105
+
106
+ def requeue_runall
107
+ return if $wm_runtime_exiting
108
+ sync do
109
+ debug "Running all queued tasks immediately!"
110
+ @requeue.each_with_index do |(run_at, callback), index|
111
+ @requeue[index][0] = Time.now
112
+ end
113
+ end
114
+ end
104
115
  end
105
116
  end
106
117
  end