diff --git a/doc/guix.texi b/doc/guix.texi index f0a59a6b4b..c10fc649d1 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -12120,6 +12120,32 @@ Additional command line options to pass to @code{memcached}. @end table @end deftp +@defvr {Scheme Variable} mongodb-service-type +This is the service type for @uref{https://www.mongodb.com/, MongoDB}. +The value for the service type is a @code{mongodb-configuration} object. +@end defvr + +@example +(service mongodb-service-type) +@end example + +@deftp {Data Type} mongodb-configuration +Data type representing the configuration of mongodb. + +@table @asis +@item @code{mongodb} (default: @code{mongodb}) +The MongoDB package to use. + +@item @code{config-file} (default: @code{%default-mongodb-configuration-file}) +The configuration file for MongoDB. + +@item @code{data-directory} (default: @code{"/var/lib/mongodb"}) +This value is used to create the directory, so that it exists and is +owned by the mongodb user. It should match the data-directory which +MongoDB is configured to use through the configuration file. +@end table +@end deftp + @defvr {Scheme Variable} redis-service-type This is the service type for the @uref{https://redis.io/, Redis} key/value store, whose value is a @code{redis-configuration} object. diff --git a/gnu/services/databases.scm b/gnu/services/databases.scm index de1f6b8411..6a01cb1ce6 100644 --- a/gnu/services/databases.scm +++ b/gnu/services/databases.scm @@ -44,6 +44,14 @@ memcached-configuration-udp-port memcached-configuration-additional-options + + mongodb-configuration + mongodb-configuration? + mongodb-configuration-mongodb + mongodb-configuration-config-file + mongodb-configuration-data-directory + mongodb-service-type + mysql-service mysql-service-type mysql-configuration @@ -262,6 +270,87 @@ and stores the database cluster in @var{data-directory}." (const %memcached-accounts)))) (default-value (memcached-configuration)))) + +;;; +;;; MongoDB +;;; + +(define %default-mongodb-configuration-file + (plain-file + "mongodb.yaml" + "# GNU Guix: MongoDB default configuration file +processManagement: + pidFilePath: /var/run/mongodb/pid +storage: + dbPath: /var/lib/mongodb +")) + + +(define-record-type* + mongodb-configuration make-mongodb-configuration + mongodb-configuration? + (mongodb mongodb-configuration-mongodb + (default mongodb)) + (config-file mongodb-configuration-config-file + (default %default-mongodb-configuration-file)) + (data-directory mongodb-configuration-data-directory + (default "/var/lib/mongodb"))) + +(define %mongodb-accounts + (list (user-group (name "mongodb") (system? #t)) + (user-account + (name "mongodb") + (group "mongodb") + (system? #t) + (comment "Mongodb server user") + (home-directory "/var/lib/mongodb") + (shell (file-append shadow "/sbin/nologin"))))) + +(define mongodb-activation + (match-lambda + (($ mongodb config-file data-directory) + #~(begin + (use-modules (guix build utils)) + (let ((user (getpwnam "mongodb"))) + (for-each + (lambda (directory) + (mkdir-p directory) + (chown directory + (passwd:uid user) (passwd:gid user))) + '("/var/run/mongodb" #$data-directory))))))) + +(define mongodb-shepherd-service + (match-lambda + (($ mongodb config-file data-directory) + (shepherd-service + (provision '(mongodb)) + (documentation "Run the Mongodb daemon.") + (requirement '(user-processes loopback)) + (start #~(make-forkexec-constructor + `(,(string-append #$mongodb "/bin/mongod") + "--config" + ,#$config-file) + #:user "mongodb" + #:group "mongodb" + #:pid-file "/var/run/mongodb/pid" + #:log-file "/var/log/mongodb.log")) + (stop #~(make-kill-destructor)))))) + +(define mongodb-service-type + (service-type + (name 'mongodb) + (description "Run the MongoDB document database server.") + (extensions + (list (service-extension shepherd-root-service-type + (compose list + mongodb-shepherd-service)) + (service-extension activation-service-type + mongodb-activation) + (service-extension account-service-type + (const %mongodb-accounts)))) + (default-value + (mongodb-configuration)))) + ;;; ;;; MySQL. diff --git a/gnu/tests/databases.scm b/gnu/tests/databases.scm index 9d9a753747..9e335b27c6 100644 --- a/gnu/tests/databases.scm +++ b/gnu/tests/databases.scm @@ -25,9 +25,11 @@ #:use-module (gnu services) #:use-module (gnu services databases) #:use-module (gnu services networking) + #:use-module (gnu packages databases) #:use-module (guix gexp) #:use-module (guix store) - #:export (%test-memcached)) + #:export (%test-memcached + %test-mongodb)) (define %memcached-os (simple-operating-system @@ -121,3 +123,85 @@ (name "memcached") (description "Connect to a running MEMCACHED server.") (value (run-memcached-test)))) + +(define %mongodb-os + (operating-system + (inherit + (simple-operating-system + (dhcp-client-service) + (service mongodb-service-type))) + (packages (cons* mongodb + %base-packages)))) + +(define* (run-mongodb-test #:optional (port 27017)) + "Run tests in %MONGODB-OS, forwarding PORT." + (define os + (marionette-operating-system + %mongodb-os + #:imported-modules '((gnu services herd) + (guix combinators)))) + + (define vm + (virtual-machine + (operating-system os) + (memory-size 1024) + (disk-image-size (* 1024 (expt 2 20))) + (port-forwardings `((27017 . ,port))))) + + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (srfi srfi-11) (srfi srfi-64) + (gnu build marionette) + (ice-9 popen) + (ice-9 rdelim)) + + (define marionette + (make-marionette (list #$vm))) + + (mkdir #$output) + (chdir #$output) + + (test-begin "mongodb") + + (test-assert "service running" + (marionette-eval + '(begin + (use-modules (gnu services herd)) + (match (start-service 'mongodb) + (#f #f) + (('service response-parts ...) + (match (assq-ref response-parts 'running) + ((pid) (number? pid)))))) + marionette)) + + (test-eq "test insert" + 0 + (system* (string-append #$mongodb "/bin/mongo") + "test" + "--eval" + "db.testCollection.insert({data: 'test-data'})")) + + (test-equal "test find" + "test-data" + (let* ((port (open-pipe* + OPEN_READ + (string-append #$mongodb "/bin/mongo") + "test" + "--quiet" + "--eval" + "db.testCollection.findOne().data")) + (output (read-line port)) + (status (close-pipe port))) + output)) + + (test-end) + (exit (= (test-runner-fail-count (test-runner-current)) 0))))) + + (gexp->derivation "mongodb-test" test)) + +(define %test-mongodb + (system-test + (name "mongodb") + (description "Connect to a running MONGODB server.") + (value (run-mongodb-test))))