From patchwork Mon Nov 5 09:41:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danny Milosavljevic X-Patchwork-Id: 123 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 0A74216766; Mon, 5 Nov 2018 09:42:12 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham autolearn_force=no version=3.4.0 Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) by mira.cbaines.net (Postfix) with ESMTPS id 672B71674C for ; Mon, 5 Nov 2018 09:42:11 +0000 (GMT) Received: from localhost ([::1]:34183 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gJbOc-0002yi-LO for patchwork@mira.cbaines.net; Mon, 05 Nov 2018 04:42:10 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42062) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gJbOY-0002yO-TQ for guix-patches@gnu.org; Mon, 05 Nov 2018 04:42:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gJbOU-0005dP-NY for guix-patches@gnu.org; Mon, 05 Nov 2018 04:42:06 -0500 Received: from debbugs.gnu.org ([208.118.235.43]:58587) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gJbOU-0005Vf-C9 for guix-patches@gnu.org; Mon, 05 Nov 2018 04:42:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1gJbOT-0001Q4-VV for guix-patches@gnu.org; Mon, 05 Nov 2018 04:42:01 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#33265] [WIP RFC v4] services: Add file system monitoring service. Resent-From: Danny Milosavljevic Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Mon, 05 Nov 2018 09:42:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 33265 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: To: 33265@debbugs.gnu.org Received: via spool by 33265-submit@debbugs.gnu.org id=B33265.15414108805398 (code B ref 33265); Mon, 05 Nov 2018 09:42:01 +0000 Received: (at 33265) by debbugs.gnu.org; 5 Nov 2018 09:41:20 +0000 Received: from localhost ([127.0.0.1]:34612 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1gJbNn-0001Oy-UB for submit@debbugs.gnu.org; Mon, 05 Nov 2018 04:41:20 -0500 Received: from dd26836.kasserver.com ([85.13.145.193]:49804) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1gJbNm-0001Oq-6t for 33265@debbugs.gnu.org; Mon, 05 Nov 2018 04:41:19 -0500 Received: from dayas.3.home (178.112.174.42.wireless.dyn.drei.com [178.112.174.42]) by dd26836.kasserver.com (Postfix) with ESMTPSA id E16E9336072E; Mon, 5 Nov 2018 10:41:15 +0100 (CET) From: Danny Milosavljevic Date: Mon, 5 Nov 2018 10:41:09 +0100 Message-Id: <20181105094109.21915-1-dannym@scratchpost.org> X-Mailer: git-send-email 2.19.0 In-Reply-To: <20181105035122.4359-1-dannym@scratchpost.org> References: <20181105035122.4359-1-dannym@scratchpost.org> MIME-Version: 1.0 Tags: patch X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches * gnu/services/monitoring.scm (file-system-monitoring-configuration): New variable. (file-system-monitoring-entry): New variable. (file-system-monitoring-service-type): New variable. * gnu/tests/monitoring.scm (%test-file-system-monitoring): New variable. * doc/guix.texi (File System Monitoring Service): New subsubsection. --- doc/guix.texi | 37 ++++++++++++++ gnu/services/monitoring.scm | 79 +++++++++++++++++++++++++++++- gnu/tests/monitoring.scm | 97 ++++++++++++++++++++++++++++++++++++- 3 files changed, 211 insertions(+), 2 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 3b7fa50d8..8997a0915 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -21496,6 +21496,43 @@ The following is an example @code{dicod-service} configuration. %dicod-database:gcide)))) @end example +@cindex file system monitoring +@subsubheading File System Monitoring Service + +The @code{(gnu services monitoring)} module provides a shepherd service to +monitor file system changes and call a handler procedure on changes. + +@defvr {Scheme Variable} file-system-monitoring-service-type +The service type for @command{fswatch}, which provides the file system +monitoring capability. + +@example +(service file-system-monitoring-service-type + (file-system-monitoring-configuration + (monitored-files '("/foo/bar")) + (handlers '((lambda args + (display "UH OH\n")))))) +@end example +@end defvr + +@deftp {Data Type} file-system-monitoring-configuration +The data type representing the configuration of the file-system-monitoring +service. + +@table @asis +@item @code{package} +Package containing the actual file system monitor (fswatch). + +@item @code{monitored-files} +List of files to be monitored. + +@item @code{handlers} +List of thunks which will be called once the file system monitor noticed +changes in the monitored files. + +@end table +@end deftp + @node Setuid Programs @subsection Setuid Programs diff --git a/gnu/services/monitoring.scm b/gnu/services/monitoring.scm index aa3b63a0e..a717175c0 100644 --- a/gnu/services/monitoring.scm +++ b/gnu/services/monitoring.scm @@ -26,10 +26,14 @@ #:use-module (guix gexp) #:use-module (guix records) #:use-module (ice-9 match) + #:use-module (srfi srfi-1) #:export (darkstat-configuration prometheus-node-exporter-configuration darkstat-service-type - prometheus-node-exporter-service-type)) + prometheus-node-exporter-service-type + file-system-monitoring-configuration + file-system-monitoring-entry + file-system-monitoring-service-type)) ;;; @@ -125,3 +129,76 @@ prometheus.") (list (service-extension shepherd-root-service-type (compose list prometheus-node-exporter-shepherd-service)))))) + + +;;; +;;; File System Monitoring +;;; + +(define-record-type* + file-system-monitoring-entry make-file-system-monitoring-entry + file-system-monitoring-entry? + (file-name file-system-monitoring-entry-file-name) + (handler file-system-monitoring-entry-handler)) + +(define-record-type* + file-system-monitoring-configuration + make-file-system-monitoring-configuration + file-system-monitoring-configuration? + (package file-system-monitoring-configuration-package + (default fswatch)) + (monitored-files file-system-monitoring-configuration-monitored-files + (default '()))) ; list of . + +(define file-system-monitoring-shepherd-services + (match-lambda + (($ package monitored-files) + (list (shepherd-service + (provision '(file-system-monitoring)) + (documentation "File System Monitor") + (requirement '(file-systems)) + (start #~(let ((handlers + (list #$@(map file-system-monitoring-entry-handler + monitored-files)))) + (lambda () + (sleep 1) + (for-each (lambda (handler) + (handler)) + handlers) + (fork+exec-command + `(#$(file-append package "/bin/fswatch") + "--one-event" + "-l" "1" ; latency: 1 s + ; "-d" + "--" + #$@(if monitored-files + (map file-system-monitoring-entry-file-name + monitored-files) + '("/does_not_exist"))))))) + (stop #~(make-kill-destructor)) + (respawn? #t)))))) + +(define file-system-monitoring-service-type + (service-type (name 'monitor-file-system) + (extensions + (list (service-extension shepherd-root-service-type + file-system-monitoring-shepherd-services))) + (compose concatenate) + (extend (lambda (config monitored-entries) + (let ((monitored-files + (map file-system-monitoring-entry-file-name + monitored-entries)) + (handlers + (map file-system-monitoring-entry-handler + monitored-entries))) + (match config + (($ + package initial-monitored-files) + (file-system-monitoring-configuration + (package package) + (monitored-files (append initial-monitored-files + monitored-files)))))))) + (description + "Call all @dfn{handler}s once something happens with one of +the files monitored, and on overflow. Can have false positives. Will also +call all @dfn{handlers} on startup."))) diff --git a/gnu/tests/monitoring.scm b/gnu/tests/monitoring.scm index 3320a19a7..d2b62374d 100644 --- a/gnu/tests/monitoring.scm +++ b/gnu/tests/monitoring.scm @@ -20,10 +20,12 @@ #:use-module (gnu services) #:use-module (gnu services monitoring) #:use-module (gnu services networking) + ;#:use-module (gnu system) #:use-module (gnu system vm) #:use-module (gnu tests) #:use-module (guix gexp) - #:export (%test-prometheus-node-exporter)) + #:export (%test-prometheus-node-exporter + %test-file-system-monitoring)) ;;; @@ -95,3 +97,96 @@ (description "Connect to a running prometheus-node-exporter server.") (value (run-prometheus-node-exporter-server-test name %prometheus-node-exporter-os)))) + + +;;; +;;; File System Monitoring. +;;; + +(define* (run-file-system-monitoring-test name test-os) + "Run tests in TEST-OS, which has file system monitoring running." + (define os + (marionette-operating-system + test-os + #:imported-modules '((gnu services herd)))) + + (define vm + (virtual-machine + (operating-system os) + (port-forwardings '()))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-11) + (srfi srfi-64) + (gnu build marionette) + (web client) + (web response)) + + (define marionette + (make-marionette (list #$vm))) + + (mkdir #$output) + (chdir #$output) + + (test-begin #$name) + + (test-assert "file system monitor is running" + (marionette-eval + '(begin + (use-modules (gnu services herd)) + (match (start-service 'file-system-monitoring) + (#f #f) + (('service response-parts ...) + (match (assq-ref response-parts 'running) + ((pid) (number? pid)))))) + marionette)) + + (test-assert "file system monitor notices file system change" + (marionette-eval + '(begin + ;; Not strictly necessary - but we want to test the actual + ;; fswatch invocation and not our own synthetic events, so + ;; give fswatch the chance to start up. + (sleep 2) + (mkdir-p "/tmp/glasshouse") + ;; Now we provide a file change. The monitor should [restart + ;; and thus] call all the handlers again. + (call-with-output-file "/tmp/glasshouse/notice_me" identity) + (and + (let loop ((i 0)) + (if (file-exists? "/tmp/glasshouse_noticed") + #t + (if (>= i 10) + #f + (begin + (sleep 1) + (loop (+ i 1)))))) + ; assume (file-exists? "/tmp/notice_me") + (>= (stat:mtime (stat "/tmp/glasshouse_noticed")) + (stat:mtime (stat "/tmp/glasshouse/notice_me"))))) + marionette)) + (test-end) + (exit (= (test-runner-fail-count (test-runner-current)) 0))))) + + (gexp->derivation (string-append name "-test") test)) + +(define %file-system-monitoring-os + (simple-operating-system + (service file-system-monitoring-service-type + (file-system-monitoring-configuration + (monitored-files + (list + (file-system-monitoring-entry + (file-name "/tmp/glasshouse") + (handler '(lambda _ + (call-with-output-file "/tmp/glasshouse_noticed" + identity)))))))))) + +(define %test-file-system-monitoring + (system-test + (name "file-system-monitoring") + (description "Test file system monitoring event handler.") + (value (run-file-system-monitoring-test + name %file-system-monitoring-os))))