machines.lisp 3.77 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
;;; -*- Mode: Lisp ; Base: 10 ; Syntax: ANSI-Common-Lisp -*-
;;;;; Machines and executing on them...


(in-package :philip-jose)

(defparameter *hostname* nil)
(def*fun gethostname ()
  (or *hostname* (setf *hostname* (sb-unix:unix-gethostname))))

;;(defparameter *domainname* nil)
;;(defun getdomainname ()
;;  (or *domainname* (setf *domainname* (sb-unix:unix-getdomainname))))

(defparameter *localhost-names* nil)
(def*fun get-localhost-names ()
  (or *localhost-names* (setf *localhost-names* (compute-localhost-names))))
(defun compute-localhost-names ()
  (list nil
        "localhost"
        (gethostname)))
;;;  (concatenate 'string (gethostname) "." (getdomainname))))

(defun machine-localhost-p (m)
  ;;--- the most correct way would be to resolve and then compare to 127.0.0.1/8 and other local addresses from ifconfig output...
  (member m (get-localhost-names) :test #'equal))



(def*fun spawn-process-on (machine &rest process-spec)
  (if (machine-localhost-p machine)
    (apply #'spawn-process process-spec)
    (apply #'spawn-remote-process machine process-spec)))

;;;---*** make less SBCL-dependent?
#-sbcl (error "Philip-Jose requires SBCL at this point")
(def*fun spawn-process (program &rest args)
  (sb-ext:run-program (->string program) (mapcar #'->string args)
                      :wait nil :pty nil :input nil :output nil :error nil))

(defun ->string (x)
  (typecase x
    (string x)
    (symbol (string-downcase (symbol-name x)))
    (t (format nil "~A" x))))

(def*fun spawn-remote-process (machine program &rest args)
  (spawn-process *ssh-path*
                 machine (command-line-from-strings
                          (mapcar #'->string (cons program args)))))

(defun kill-machine-process (machine pid)
  (spawn-process-on machine "/bin/kill" -9 pid))

(defun pts-old-p (p)
  (let ((mtime (nth-value 11 (et:stat (namestring p)))))
    (< mtime (- (et:gettimeofday) 3600))))

(defun all-pts-old-p ()
  (every #'pts-old-p
         (directory (make-pathname :directory "/dev/pts/" :name :wild))))

(defun low-loadavg-p ()
  (< (nth-value 2 (read-loadavg)) .38))

(cffi:defcfun getloadavg :int (loadavg :pointer) (nelem :int))

(defun read-loadavg ()
  (values-list
   (cffi:with-foreign-object (loadavg :double 3)
     (getloadavg loadavg 3)
     (loop for i below 3 collect
           (cffi:mem-aref loadavg :double i)))))

(defun get-id ()
  (or *id*
      (setf *id* (list (gethostname) (iolib-posix:getpid) (get-real-time)))))

(defun validate-and-start-client (server port)
  (let* ((all-pts-old-p (all-pts-old-p))
         (low-loadavg-p (low-loadavg-p))
         (valid (and all-pts-old-p low-loadavg-p)))
    (simple-client `(:register-client ,(get-id) :valid t ;;,valid
                     ;; :explanation (:all-pts-old-p ,all-pts-old-p :low-loadavg-p ,low-loadavg-p)
                     )
                   server port)
    (if t ;valid
        (worker-loop :server server :port port)
        (logger "~&Client not taking part in the farm: ~S"
                (list :all-pts-old-p all-pts-old-p :low-loadavg-p low-loadavg-p)))))

(def*fun simple-client (message target port)
  (let* ((address (ensure-address target))
         (socket (make-tcp-connection address port)))
    (unwind-protect
         (progn
           (safe-write message :stream socket)
           (princ +crlf+ socket)
           (finish-output socket)
           ;;(shutdown socket :write)
           (read socket))
      (close socket))))

(defun spawn-client (machine &optional (server (gethostname)) (port *port*))
  (logger "~&Spawning client on ~S" machine)
  (spawn-process-on machine *farmer-path* "client" server port))

(def*fun start-clients ()
  (spawn-all-clients)
  nil)

(def*fun spawn-all-clients ()
  (dolist (machine (process-registry-log))
    (loop repeat *workers-per-machine* do
      (spawn-client machine))))