init - reed-alert - Lightweight agentless alerting system for server
HTML git clone git://bitreich.org/reed-alert/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/reed-alert/
DIR Log
DIR Files
DIR Refs
DIR Tags
DIR README
DIR LICENSE
---
DIR commit 9410e05e37aefd2e1880178e655a8bd64173c645
HTML Author: solene rapenne <solene@dataswamp.org>
Date: Fri, 7 Oct 2016 12:25:49 +0200
init
Diffstat:
A example.lisp | 50 +++++++++++++++++++++++++++++++
A functions.lisp | 49 +++++++++++++++++++++++++++++++
A probes.lisp | 92 +++++++++++++++++++++++++++++++
3 files changed, 191 insertions(+), 0 deletions(-)
---
DIR diff --git a/example.lisp b/example.lisp
@@ -0,0 +1,50 @@
+(defvar *alerts*
+ (list
+ '(dont-use-it ("REMINDER" function params date hostname description level os newline _ space result))
+ '(void nil)
+ '(mail nil)
+ '(sms ("echo -n '" date _ function " CRITICAL " hostname "' | curl http://somewebservice"))
+ '(mail ("echo -n '" date _ hostname " had problem on " function newline params _ " values " result newline
+ description "' | mail -s '[Error] " function " - " hostname "' foo@bar.com"))
+ '(with-plus ("echo -n '" + date + _ + hostname + " had problem on " + function + newline + params + newline
+ + description + "' | mail -s '[Error] " + function + " - " + hostname + "' foo@bar.com"))))
+
+(load "functions.lisp")
+
+;; check if used percent :path partition is more than :limit
+(=> mail disk-usage (:path "/" :limit 90))
+(=> mail disk-usage (:path "/usr" :limit 85))
+(=> mail disk-usage (:path "/tmp" :limit 1)) ;; failure
+
+;; check if :path file exists
+(=> mail file-exists (:path "/bsd.rd" :desc "OpenBSD kernel /bsd.rd"))
+(=> void file-exists (:path "/non-existant-file")) ;; failure file not found
+
+;; check if :path file exists and has been updated since :limit minutes
+(=> void file-updated (:path "/var/log/messages" :limit 400))
+(=> mail file-updated (:path "/bsd.rd" :limit 1 :desc "OpenBSD kernel")) ;; failure
+
+;; check if :path pid file process is running
+(=> mail pid-running (:path "/var/run/xdm.pid" :desc "XDM pid"))
+(=> mail pid-running (:path "/home/user/test.pid")) ;; failure
+
+;; check if number of processes on the system is more than :limit
+(=> mail number-of-processes (:limit 200))
+(=> mail number-of-processes (:limit 1)) ;; failure
+
+;; check if load average on (1/5/15) minutes is more than :limit
+(=> mail load-average-1 (:limit 4))
+(=> mail load-average-5 (:limit 2))
+(=> mail load-average-15 (:limit 1))
+(=> mail load-average-1 (:limit 0.2)) ;; should trigger error
+
+;; check if :host host is reachable
+(=> mail ping (:host "8.8.8.8" :desc "Google DNS"))
+(=> void ping (:host "2.3.4.256" :desc "Not valid ipv4 address")) ;; fail error
+(=> void ping (:host "127.40.30.21" :desc "Certainly not used address")) ;; fail time out
+
+;; check if :command command return 0 (success) or something else (error)
+(=> void command (:command "echo hello")) ;; success
+(=> void command (:command "ls /non-existent-file")) ;; fail
+
+(quit)
DIR diff --git a/functions.lisp b/functions.lisp
@@ -0,0 +1,49 @@
+(load "probes.lisp")
+
+(defun color(num1 num2)
+ (format nil "~a[~a;~am" #\Escape num1 num2))
+
+(defparameter *red* (color 1 31))
+(defparameter *white* (color 0 70))
+(defparameter *green* (color 1 32))
+(defparameter *yellow* (color 0 33))
+
+(defun trigger-alert(level function params result)
+ (format nil "~{~a~}"
+ (mapcar #'(lambda(x)
+ (if (symbolp x)
+ (case x
+ (+ "")
+ (result result)
+ (hostname (machine-instance))
+ (date (multiple-value-bind
+ (second minute hour day month year)
+ (get-decoded-time)
+ (format nil "~a/~a/~a ~a:~a:~a" year month day hour minute second)))
+ (os (software-type))
+ (function function)
+ (space " ")
+ (_ " ")
+ (params params)
+ (desc (getf params :desc ""))
+ (newline #\Newline)
+ (level level))
+ x))
+ (cadr (assoc level *alerts*)))))
+
+(defmacro stop-if-error(&body body)
+ `(progn
+ (and ,@body)))
+
+(defmacro =>(level fonction params)
+ `(progn
+ (format t "[~a~a ~20A~a] ~35A" *yellow* ',level ',fonction *white* (getf ',params :desc ',params))
+ (let ((result (funcall ',fonction ',params)))
+ (if (not (listp result))
+ (progn
+ (format t " => ~asuccess~a~%" *green* *white*)
+ t)
+ (progn
+ (format t " => ~aerror~a~%" *red* *white*)
+ (uiop:run-program (trigger-alert ',level ',fonction ',params (cadr result)) :output t)
+ nil)))))
DIR diff --git a/probes.lisp b/probes.lisp
@@ -0,0 +1,92 @@
+(defmacro create-probe(name &body code)
+ `(progn (defun ,name(params) ,@code)))
+
+(defun command-return-code(command)
+ (let ((code (nth-value 2 (uiop:run-program command :ignore-error-status t))))
+ (if (= 0 code)
+ t
+ (list nil (format nil "return code = ~a" code)))))
+
+(create-probe
+ file-exists
+ (let ((result (probe-file (getf params :path))))
+ (if result
+ t
+ (list nil "file not found"))))
+
+(create-probe
+ file-updated
+ (if (probe-file (getf params :path))
+ (with-open-file (file (getf params :path))
+ (let* ((write-date (file-write-date file))
+ (now (get-universal-time))
+ (result (floor (- now write-date) 60)))
+ (if (> (getf params :limit) result)
+ t
+ (list nil result))))
+ (list nil "file not found")))
+
+(create-probe
+ pid-running
+ (if (probe-file (getf params :path))
+ (let ((pid-number (with-open-file (stream (getf params :path)) (read-line stream))))
+ (command-return-code (list "ps" "-p" pid-number)))
+ (list nil "file not found")))
+
+(create-probe
+ disk-usage
+ (let* ((output (uiop:run-program (list "df" (getf params :path)) :output :lines)) (line (second output)))
+ (let ((percent-character-pos (position #\% line)))
+ (let ((used-disk
+ (parse-integer
+ (subseq line
+ (position #\Space line :end percent-character-pos :from-end t)
+ percent-character-pos))))
+ (if (< used-disk (getf params :limit))
+ t
+ (list nil "used-disk"))))))
+
+(defun system-load(time)
+ (read-from-string
+ (let ((command (concatenate 'string
+ "uptime | awk '{ print $"
+ (princ-to-string time)
+ " }'")))
+ (uiop:run-program command :output :string))))
+
+(create-probe
+ load-average-1
+ (let ((load (system-load 10)))
+ (if (< load (getf params :limit))
+ t
+ (list nil load))))
+
+(create-probe
+ load-average-5
+ (let ((load (system-load 11)))
+ (if (< load (getf params :limit))
+ t
+ (list nil load))))
+
+(create-probe
+ load-average-15
+ (let ((load (system-load 12)))
+ (if (< load (getf params :limit))
+ t
+ (list nil load))))
+
+(create-probe
+ command
+ (command-return-code (getf params :command)))
+
+(create-probe
+ ping
+ (command-return-code (list "ping" "-c2" (getf params :host))))
+
+(create-probe
+ number-of-processes
+ (let* ((output (uiop:run-program (list "ps" "aux") :output :lines))
+ (result (length output)))
+ (if (> (getf params :limit) result)
+ t
+ (list nil result))))