services: agate: Change variable names and add system test.

* doc/guix.texi (Web Services): Update documentation for agate-service-type.
* gnu/services/web.scm (agate-configuration): Rename certs, addr, lang and
central-conf variables.
* gnu/tests/web.scm (%test-agate): Add system test for agate-service-type.

Change-Id: Ie14814fca1d5158acd67899da0c3fc2c5b586c72
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
This commit is contained in:
Rodion Goritskov 2024-08-17 01:11:50 +04:00 committed by Ludovic Courtès
parent 25f22fd0e9
commit 61a7930cb0
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
3 changed files with 135 additions and 29 deletions

View file

@ -32963,16 +32963,19 @@ This is the type of the agate service, whose value should be an
(service agate-service-type (service agate-service-type
(agate-configuration (agate-configuration
(content "/srv/gemini") (content "/srv/gemini")
(certs "/srv/gemini-certs"))) (certificates "/srv/gemini-certs")))
@end lisp @end lisp
The example above represents the minimal tweaking necessary to get Agate The example above represents the minimal tweaking necessary to get Agate
up and running. Specifying the path to the certificate and key directory is up and running. Specifying the path to the certificate and key directory is
always necessary, as the Gemini protocol requires TLS by default. always necessary, as the Gemini protocol requires TLS by default.
If specified path is writable by Agate, and contains no valid key If specified @code{certificates} path is writable by Agate, and contains no
and certificate, the Agate will try to generate them on the first start. valid pre-generated key and certificate, the Agate will try to generate
If specified directory is read-only - key and certificate should be pre-generated by user. them on the first start. In this case you should pass at least one
hostname using the @code{hostnames} option.
If specified directory is read-only - key and certificate should be
pre-generated by user.
To obtain a certificate and a key in a DER format, you could, for example, To obtain a certificate and a key in a DER format, you could, for example,
use OpenSSL, running a commands similar to the following example: use OpenSSL, running a commands similar to the following example:
@ -32986,7 +32989,7 @@ openssl req -x509 -key key.der -outform DER -days 3650 -out cert.der \
Of course, you'll have to replace @i{example.com} with your own domain Of course, you'll have to replace @i{example.com} with your own domain
name, and then point the Agate configuration towards the path of the name, and then point the Agate configuration towards the path of the
directory with the generated key and certificate using the @code{certs} option. directory with the generated key and certificate using the @code{certificates} option.
@end defvar @end defvar
@ -33000,10 +33003,10 @@ The package object of the Agate server.
@item @code{content} (default: @file{"/srv/gemini"}) @item @code{content} (default: @file{"/srv/gemini"})
The directory from which Agate will serve files. The directory from which Agate will serve files.
@item @code{certs} (default: @file{"/srv/gemini-certs"}) @item @code{certificates} (default: @file{"/srv/gemini-certs"})
Root of the certificate directory. Must be filled in with a value from the user. Root of the certificate directory. Must be filled in with a value from the user.
@item @code{addr} (default: @code{'("0.0.0.0:1965" "[::]:1965")}) @item @code{addresses} (default: @code{'("[::]:1965" "0.0.0.0:1965")})
A list of the addresses to listen on. A list of the addresses to listen on.
@item @code{hostnames} (default: @code{'()}) @item @code{hostnames} (default: @code{'()})
@ -33011,7 +33014,7 @@ Virtual hosts for the Gemini server. If multiple values are
specified, corresponding directory names should be present in the @code{content} specified, corresponding directory names should be present in the @code{content}
directory. Optional. directory. Optional.
@item @code{lang} (default: @code{#f}) @item @code{languages} (default: @code{#f})
RFC 4646 language code(s) for text/gemini documents. Optional. RFC 4646 language code(s) for text/gemini documents. Optional.
@item @code{only-tls13?} (default: @code{#f}) @item @code{only-tls13?} (default: @code{#f})
@ -33021,7 +33024,7 @@ Set to @code{#t} to disable support for TLSv1.2.
Set to @code{#t} to serve secret files (files/directories starting with Set to @code{#t} to serve secret files (files/directories starting with
a dot). a dot).
@item @code{central-conf?} (default: @code{#f}) @item @code{central-configuration?} (default: @code{#f})
Set to @code{#t} to look for the .meta configuration file in the @code{content} Set to @code{#t} to look for the .meta configuration file in the @code{content}
root directory and will ignore @code{.meta} files in other directories root directory and will ignore @code{.meta} files in other directories

View file

@ -2186,20 +2186,20 @@ (define-record-type* <agate-configuration>
(default agate)) (default agate))
(content agate-configuration-content (content agate-configuration-content
(default "/srv/gemini")) (default "/srv/gemini"))
(certs agate-configuration-certs (certificates agate-configuration-certificates
(default "/srv/gemini-certs")) (default "/srv/gemini-certs"))
(addr agate-configuration-addr (addresses agate-configuration-addresses
(default '("0.0.0.0:1965" "[::]:1965"))) (default '("[::]:1965" "0.0.0.0:1965")))
(hostname agate-configuration-hostname (hostnames agate-configuration-hostnames
(default '())) (default '()))
(lang agate-configuration-lang (languages agate-configuration-languages
(default #f)) (default #f))
(only-tls13? agate-configuration-only-tls13 (only-tls13? agate-configuration-only-tls13
(default #f)) (default #f))
(serve-secret? agate-configuration-serve-secret (serve-secret? agate-configuration-serve-secret
(default #f)) (default #f))
(central-conf? agate-configuration-central-conf (central-configuration? agate-configuration-central-configuration
(default #f)) (default #f))
(ed25519? agate-configuration-ed25519 (ed25519? agate-configuration-ed25519
(default #f)) (default #f))
(skip-port-check? agate-configuration-skip-port-check (skip-port-check? agate-configuration-skip-port-check
@ -2215,9 +2215,9 @@ (define-record-type* <agate-configuration>
(define agate-shepherd-service (define agate-shepherd-service
(match-lambda (match-lambda
(($ <agate-configuration> package content certs addr (($ <agate-configuration> package content certificates addresses
hostname lang only-tls13? hostnames languages only-tls13?
serve-secret? central-conf? serve-secret? central-configuration?
ed25519? skip-port-check? ed25519? skip-port-check?
log-ip? user group log-file) log-ip? user group log-file)
(list (shepherd-service (list (shepherd-service
@ -2228,19 +2228,19 @@ (define agate-shepherd-service
#~(make-forkexec-constructor #~(make-forkexec-constructor
(list #$agate (list #$agate
"--content" #$content "--content" #$content
"--certs" #$certs "--certs" #$certificates
#$@(append-map #$@(append-map
(lambda x (append '("--addr") x)) (lambda x (append '("--addr") x))
addr) addresses)
#$@(append-map #$@(append-map
(lambda x (append '("--hostname") x)) (lambda x (append '("--hostname") x))
hostname) hostnames)
#$@(if lang #$@(if languages
(list "--lang" lang) (list "--lang" languages)
'()) '())
#$@(if serve-secret? '("--serve-secret") '()) #$@(if serve-secret? '("--serve-secret") '())
#$@(if only-tls13? '("--only-tls13") '()) #$@(if only-tls13? '("--only-tls13") '())
#$@(if central-conf? '("--central-conf") '()) #$@(if central-configuration? '("--central-conf") '())
#$@(if ed25519? '("--ed25519") '()) #$@(if ed25519? '("--ed25519") '())
#$@(if skip-port-check? '("--skip-port-check") '()) #$@(if skip-port-check? '("--skip-port-check") '())
#$@(if log-ip? '("--log-ip") '())) #$@(if log-ip? '("--log-ip") '()))

View file

@ -34,8 +34,10 @@ (define-module (gnu tests web)
#:use-module (gnu services shepherd) #:use-module (gnu services shepherd)
#:use-module (gnu services mail) #:use-module (gnu services mail)
#:use-module (gnu packages databases) #:use-module (gnu packages databases)
#:use-module (gnu packages guile-xyz)
#:use-module (gnu packages patchutils) #:use-module (gnu packages patchutils)
#:use-module (gnu packages python) #:use-module (gnu packages python)
#:use-module (gnu packages tls)
#:use-module (gnu packages web) #:use-module (gnu packages web)
#:use-module (guix packages) #:use-module (guix packages)
#:use-module (guix modules) #:use-module (guix modules)
@ -50,7 +52,8 @@ (define-module (gnu tests web)
%test-php-fpm %test-php-fpm
%test-hpcguix-web %test-hpcguix-web
%test-tailon %test-tailon
%test-patchwork)) %test-patchwork
%test-agate))
(define %index.html-contents (define %index.html-contents
;; Contents of the /index.html file. ;; Contents of the /index.html file.
@ -657,3 +660,103 @@ (define %test-patchwork
(name "patchwork") (name "patchwork")
(description "Connect to a running Patchwork service.") (description "Connect to a running Patchwork service.")
(value (run-patchwork-test patchwork)))) (value (run-patchwork-test patchwork))))
;;;
;;; Agate
;;;
(define %index.gmi-contents
;; Contents of the /index.gmi file.
"Hello, guix!")
(define %make-agate-root
;; Create our server root in /srv.
#~(begin
(mkdir "/srv")
(mkdir "/srv/gemini")
(mkdir "/srv/gemini-certs")
;; Directory should be writable for Agate user to generate certificates
(let ((user (getpw "agate")))
(chown "/srv/gemini-certs" (passwd:uid user) (passwd:gid user)))
(call-with-output-file (string-append "/srv/gemini/index.gmi")
(lambda (port)
(display #$%index.gmi-contents port)))))
(define %agate-os
(simple-operating-system
(service dhcp-client-service-type)
(simple-service 'make-agate-root activation-service-type
%make-agate-root)
(service agate-service-type
(agate-configuration
(hostnames '("localhost"))))))
(define* (run-agate-test name test-os expected-content)
(define os
(marionette-operating-system
test-os
#:imported-modules '((gnu services herd)
(guix combinators))
#:extensions (list guile-gemini guile-gnutls)))
(define forwarded-port 1965)
(define vm
(virtual-machine
(operating-system os)
(port-forwardings `((1965 . ,forwarded-port)))))
(define test
(with-imported-modules '((gnu build marionette))
#~(begin
(use-modules (srfi srfi-64)
(gnu build marionette))
(define marionette
(make-marionette (list #$vm)))
(test-runner-current (system-test-runner #$output))
(test-begin #$name)
(test-assert #$(string-append name " service running")
(marionette-eval
'(begin
(use-modules (gnu services herd))
(match (start-service '#$(string->symbol name))
(#f #f)
(('service response-parts ...)
(match (assq-ref response-parts 'running)
((#t) #t)
((pid) (number? pid))))))
marionette))
(test-assert "Agate TCP port ready, IPv4"
(wait-for-tcp-port #$forwarded-port marionette))
(test-assert "Agate TCP port ready, IPv6"
(wait-for-tcp-port #$forwarded-port marionette
#:address
'(make-socket-address
AF_INET6 (inet-pton AF_INET6 "::1") #$forwarded-port)))
(test-equal "Agate responses with the specified index.gmi"
#$expected-content
(marionette-eval '(begin
(use-modules (ice-9 iconv)
(gemini client)
(gemini request)
(gemini response))
(bytevector->string (gemini-response-body-bytes
(send-gemini-request
(build-gemini-request #:host "localhost" #:port #$forwarded-port)))
"utf8")) marionette))
(test-end))))
(gexp->derivation "agate-test" test))
(define %test-agate
(system-test
(name "agate")
(description "Connect to a running Agate service.")
(value (run-agate-test name %agate-os %index.gmi-contents))))