services: radicale: Use define-configuration.
* doc/guix.texi (radicale-configuration): Update documentation to reflect new configuration, add new symbols. * gnu/services/mail.scm (%default-radicale-config-file): Delete. (radicale-auth-configuration, radicale-auth-configuration?) (radicale-encoding-configuration, radicale-encoding-configuration?) (radicale-logging-configuration, radicale-logging-configuration?) (radicale-rights-configuration, radicale-rights-configuration?) (radicale-server-configuration, radicale-server-configuration?) (radicale-storage-configuration, radicale-storage-configuration?): New configuration types and corresponding predicates. (radicale-configuration, radicale-configuration?): Use define-configuration. (radicale-activation, radicale-shepherd-service): Update to new configuration format. (radicale-activation): Use user-defined values for service files. (radicale-service-type): Capitalize "Radicale" in description. Change-Id: Ic88b8ff2750e3d658f6c7cee02d33417aa8ee6d2 Signed-off-by: Liliana Marie Prikler <liliana.prikler@gmail.com>master
parent
617f1e5320
commit
b49e556b9e
188
doc/guix.texi
188
doc/guix.texi
|
@ -28248,23 +28248,195 @@ Mailutils Manual}, for details.
|
||||||
@cindex CardDAV
|
@cindex CardDAV
|
||||||
|
|
||||||
@defvar radicale-service-type
|
@defvar radicale-service-type
|
||||||
This is the type of the @uref{https://radicale.org, Radicale} CalDAV/CardDAV
|
This is the type of the @uref{https://radicale.org, Radicale}
|
||||||
server whose value should be a @code{radicale-configuration}.
|
CalDAV/CardDAV server whose value should be a
|
||||||
|
@code{radicale-configuration}. The default configuration matches the
|
||||||
|
@uref{https://radicale.org/v3.html#configuration, upstream
|
||||||
|
documentation}.
|
||||||
@end defvar
|
@end defvar
|
||||||
|
|
||||||
@deftp {Data Type} radicale-configuration
|
@deftp {Data Type} radicale-configuration
|
||||||
Data type representing the configuration of @command{radicale}.
|
Data type representing the configuration of @command{radicale}.
|
||||||
|
Available @code{radicale-configuration} fields are:
|
||||||
|
|
||||||
@table @asis
|
@table @asis
|
||||||
@item @code{package} (default: @code{radicale})
|
@item @code{package} (default: @code{radicale}) (type: package)
|
||||||
The package that provides @command{radicale}.
|
Package that provides @command{radicale}.
|
||||||
|
|
||||||
@item @code{config-file} (default: @code{%default-radicale-config-file})
|
@item @code{auth} (default: @code{'()}) (type: radicale-auth-configuration)
|
||||||
File-like object of the configuration file to use, by default it will listen
|
Configuration for auth-related variables.
|
||||||
on TCP port 5232 of @code{localhost} and use the @code{htpasswd} file at
|
|
||||||
@file{/var/lib/radicale/users} with no (@code{plain}) encryption.
|
@deftp {Data Type} radicale-auth-configuration
|
||||||
|
Data type representing the @code{auth} section of a @command{radicale}
|
||||||
|
configuration file. Available @code{radicale-auth-configuration} fields
|
||||||
|
are:
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item @code{type} (default: @code{'none}) (type: symbol)
|
||||||
|
The method to verify usernames and passwords. Options are @code{none},
|
||||||
|
@code{htpasswd}, @code{remote-user}, and @code{http-x-remote-user}.
|
||||||
|
This value is tied to @code{htpasswd-filename} and
|
||||||
|
@code{htpasswd-encryption}.
|
||||||
|
|
||||||
|
@item @code{htpasswd-filename} (default: @code{"/etc/radicale/users"}) (type: file-name)
|
||||||
|
Path to the htpasswd file. Use htpasswd or similar to generate this
|
||||||
|
file.
|
||||||
|
|
||||||
|
@item @code{htpasswd-encryption} (default: @code{'md5}) (type: symbol)
|
||||||
|
Encryption method used in the htpasswd file. Options are @code{plain},
|
||||||
|
@code{bcrypt}, and @code{md5}.
|
||||||
|
|
||||||
|
@item @code{delay} (default: @code{1}) (type: non-negative-integer)
|
||||||
|
Average delay after failed login attempts in seconds.
|
||||||
|
|
||||||
|
@item @code{realm} (default: @code{"Radicale - Password Required"}) (type: string)
|
||||||
|
Message displayed in the client when a password is needed.
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
@item @code{encoding} (default: @code{'()}) (type: radicale-encoding-configuration)
|
||||||
|
Configuration for encoding-related variables.
|
||||||
|
|
||||||
|
@deftp {Data Type} radicale-encoding-configuration
|
||||||
|
Data type representing the @code{encoding} section of a
|
||||||
|
@command{radicale} configuration file. Available
|
||||||
|
@code{radicale-encoding-configuration} fields are:
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item @code{request} (default: @code{'utf-8}) (type: symbol)
|
||||||
|
Encoding for responding requests.
|
||||||
|
|
||||||
|
@item @code{stock} (default: @code{'utf-8}) (type: symbol)
|
||||||
|
Encoding for storing local collections.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
@item @code{headers-file} (default: none) (type: file-like)
|
||||||
|
Custom HTTP headers.
|
||||||
|
|
||||||
|
@item @code{logging} (default: @code{'()}) (type: radicale-logging-configuration)
|
||||||
|
Configuration for logging-related variables.
|
||||||
|
|
||||||
|
@deftp {Data Type} radicale-logging-configuration
|
||||||
|
Data type representing the @code{logging} section of a
|
||||||
|
@command{radicale} configuration file. Available
|
||||||
|
@code{radicale-logging-configuration} fields are:
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item @code{level} (default: @code{'warning}) (type: symbol)
|
||||||
|
Set the logging level. One of @code{debug}, @code{info},
|
||||||
|
@code{warning}, @code{error}, or @code{critical}.
|
||||||
|
|
||||||
|
@item @code{mask-passwords?} (default: @code{#t}) (type: boolean)
|
||||||
|
Whether to include passwords in logs.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
@item @code{rights} (default: @code{'()}) (type: radicale-rights-configuration)
|
||||||
|
Configuration for rights-related variables. This should be a
|
||||||
|
@code{radicale-rights-configuration}.
|
||||||
|
|
||||||
|
@deftp {Data Type} radicale-rights-configuration
|
||||||
|
Data type representing the @code{rights} section of a @command{radicale}
|
||||||
|
configuration file. Available @code{radicale-rights-configuration}
|
||||||
|
fields are:
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item @code{type} (default: @code{'owner-only}) (type: symbol)
|
||||||
|
Backend used to check collection access rights. The recommended backend
|
||||||
|
is @code{owner-only}. If access to calendars and address books outside
|
||||||
|
the home directory of users is granted, clients won't detect these
|
||||||
|
collections and will not show them to the user. Choosing any other
|
||||||
|
method is only useful if you access calendars and address books directly
|
||||||
|
via URL. Options are @code{authenticate}, @code{owner-only},
|
||||||
|
@code{owner-write}, and @code{from-file}.
|
||||||
|
|
||||||
|
@item @code{file} (default: @code{""}) (type: file-name)
|
||||||
|
File for the rights backend @code{from-file}.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
@item @code{server} (default: @code{'()}) (type: radicale-server-configuration)
|
||||||
|
Configuration for server-related variables. Ignored if WSGI is used.
|
||||||
|
|
||||||
|
@deftp {Data Type} radicale-server-configuration
|
||||||
|
Data type representing the @code{server} section of a @command{radicale}
|
||||||
|
configuration file. Available @code{radicale-server-configuration}
|
||||||
|
fields are:
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item @code{hosts} (default: @code{(list "localhost:5232")}) (type: list-of-ip-addresses)
|
||||||
|
List of IP addresses that the server will bind to.
|
||||||
|
|
||||||
|
@item @code{max-connections} (default: @code{8}) (type: non-negative-integer)
|
||||||
|
Maximum number of parallel connections. Set to 0 to disable the limit.
|
||||||
|
|
||||||
|
@item @code{max-content-length} (default: @code{100000000}) (type: non-negative-integer)
|
||||||
|
Maximum size of the request body in bytes.
|
||||||
|
|
||||||
|
@item @code{timeout} (default: @code{30}) (type: non-negative-integer)
|
||||||
|
Socket timeout in seconds.
|
||||||
|
|
||||||
|
@item @code{ssl?} (default: @code{#f}) (type: boolean)
|
||||||
|
Whether to enable transport layer encryption.
|
||||||
|
|
||||||
|
@item @code{certificate} (default: @code{"/etc/ssl/radicale.cert.pem"}) (type: file-name)
|
||||||
|
Path of the SSL certificate.
|
||||||
|
|
||||||
|
@item @code{key} (default: @code{"/etc/ssl/radicale.key.pem"}) (type: file-name)
|
||||||
|
Path to the private key for SSL. Only effective if @code{ssl?} is
|
||||||
|
@code{#t}.
|
||||||
|
|
||||||
|
@item @code{certificate-authority} (default: @code{""}) (type: file-name)
|
||||||
|
Path to CA certificate for validating client certificates. This can be
|
||||||
|
used to secure TCP traffic between Radicale and a reverse proxy. If you
|
||||||
|
want to authenticate users with client-side certificates, you also have
|
||||||
|
to write an authentication plugin that extracts the username from the
|
||||||
|
certificate.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
@item @code{storage} (default: @code{'()}) (type: radicale-storage-configuration)
|
||||||
|
Configuration for storage-related variables.
|
||||||
|
|
||||||
|
@deftp {Data Type} radicale-storage-configuration
|
||||||
|
Data type representing the @code{storage} section of a
|
||||||
|
@command{radicale} configuration file. Available
|
||||||
|
@code{radicale-storage-configuration} fields are:
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item @code{type} (default: @code{'multifilesystem}) (type: symbol)
|
||||||
|
Backend used to store data. Options are @code{multifilesystem} and
|
||||||
|
@code{multifilesystem-nolock}.
|
||||||
|
|
||||||
|
@item @code{filesystem-folder} (default: @code{"/var/lib/radicale/collections"}) (type: file-name)
|
||||||
|
Folder for storing local collections. Created if not present.
|
||||||
|
|
||||||
|
@item @code{max-sync-token-age} (default: @code{2592000}) (type: non-negative-integer)
|
||||||
|
Delete sync-tokens that are older than the specified time in seconds.
|
||||||
|
|
||||||
|
@item @code{hook} (default: @code{""}) (type: string)
|
||||||
|
Command run after changes to storage.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@end deftp
|
||||||
|
|
||||||
|
@item @code{web-interface?} (default: @code{#t}) (type: boolean)
|
||||||
|
Whether to use Radicale's built-in web interface.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
@end deftp
|
@end deftp
|
||||||
|
|
||||||
@subsubheading Rspamd Service
|
@subsubheading Rspamd Service
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
;;; Copyright © 2020 Jonathan Brielmaier <jonathan.brielmaier@web.de>
|
;;; Copyright © 2020 Jonathan Brielmaier <jonathan.brielmaier@web.de>
|
||||||
;;; Copyright © 2023 Thomas Ieong <th.ieong@free.fr>
|
;;; Copyright © 2023 Thomas Ieong <th.ieong@free.fr>
|
||||||
;;; Copyright © 2023 Saku Laesvuori <saku@laesvuori.fi>
|
;;; Copyright © 2023 Saku Laesvuori <saku@laesvuori.fi>
|
||||||
|
;;; Copyright © 2024 Juliana Sims <juli@incana.org>
|
||||||
;;;
|
;;;
|
||||||
;;; This file is part of GNU Guix.
|
;;; This file is part of GNU Guix.
|
||||||
;;;
|
;;;
|
||||||
|
@ -38,10 +39,12 @@
|
||||||
#:use-module (gnu packages dav)
|
#:use-module (gnu packages dav)
|
||||||
#:use-module (gnu packages tls)
|
#:use-module (gnu packages tls)
|
||||||
#:use-module (guix deprecation)
|
#:use-module (guix deprecation)
|
||||||
|
#:use-module ((guix diagnostics) #:select (source-properties->location))
|
||||||
#:use-module (guix modules)
|
#:use-module (guix modules)
|
||||||
#:use-module (guix records)
|
#:use-module (guix records)
|
||||||
#:use-module (guix packages)
|
#:use-module (guix packages)
|
||||||
#:use-module (guix gexp)
|
#:use-module (guix gexp)
|
||||||
|
#:use-module (ice-9 curried-definitions)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (ice-9 format)
|
#:use-module (ice-9 format)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
|
@ -79,10 +82,21 @@
|
||||||
imap4d-service-type
|
imap4d-service-type
|
||||||
%default-imap4d-config-file
|
%default-imap4d-config-file
|
||||||
|
|
||||||
|
radicale-auth-configuration
|
||||||
|
radicale-auth-configuration?
|
||||||
|
radicale-encoding-configuration
|
||||||
|
radicale-encoding-configuration?
|
||||||
|
radicale-logging-configuration
|
||||||
|
radicale-logging-configuration?
|
||||||
|
radicale-rights-configuration
|
||||||
|
radicale-rights-configuration?
|
||||||
|
radicale-server-configuration
|
||||||
|
radicale-server-configuration?
|
||||||
|
radicale-storage-configuration
|
||||||
|
radicale-storage-configuration?
|
||||||
radicale-configuration
|
radicale-configuration
|
||||||
radicale-configuration?
|
radicale-configuration?
|
||||||
radicale-service-type
|
radicale-service-type
|
||||||
%default-radicale-config-file
|
|
||||||
|
|
||||||
rspamd-configuration
|
rspamd-configuration
|
||||||
rspamd-service-type
|
rspamd-service-type
|
||||||
|
@ -1929,23 +1943,258 @@ exim_group = exim
|
||||||
;;; Radicale.
|
;;; Radicale.
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
(define-record-type* <radicale-configuration>
|
;; Maybe types
|
||||||
radicale-configuration make-radicale-configuration
|
|
||||||
radicale-configuration?
|
|
||||||
(package radicale-configuration-package
|
|
||||||
(default radicale))
|
|
||||||
(config-file radicale-configuration-config-file
|
|
||||||
(default %default-radicale-config-file)))
|
|
||||||
|
|
||||||
(define %default-radicale-config-file
|
(define (comma-separated-ip-list? lst)
|
||||||
(plain-file "radicale.conf" "
|
(every (lambda (s)
|
||||||
[auth]
|
(or (string-prefix? "localhost" s)
|
||||||
type = htpasswd
|
((@@ (gnu services vpn) ipv4-address?) s)
|
||||||
htpasswd_filename = /var/lib/radicale/users
|
((@@ (gnu services vpn) ipv6-address?) s)))
|
||||||
htpasswd_encryption = plain
|
lst))
|
||||||
|
|
||||||
[server]
|
(define-maybe boolean (prefix radicale-))
|
||||||
hosts = localhost:5232"))
|
(define-maybe comma-separated-ip-list (prefix radicale-))
|
||||||
|
(define-maybe file-name (prefix radicale-))
|
||||||
|
(define-maybe non-negative-integer (prefix radicale-))
|
||||||
|
(define-maybe string (prefix radicale-))
|
||||||
|
(define-maybe symbol (prefix radicale-))
|
||||||
|
|
||||||
|
;; Serializers and sanitizers
|
||||||
|
|
||||||
|
(define (radicale-serialize-field field-name value)
|
||||||
|
;; XXX We quote the un-gexp form here because otherwise symbol-literals are
|
||||||
|
;; treated as variables. We can get away with this because all of our other
|
||||||
|
;; field value types are primitives by the time they get here so are printed
|
||||||
|
;; the same whether or not they are quoted.
|
||||||
|
#~(format #f "~a = ~a\n" #$(uglify-field-name field-name) '#$value))
|
||||||
|
|
||||||
|
(define (radicale-serialize-boolean field-name value?)
|
||||||
|
(radicale-serialize-field field-name (if value? "True" "False")))
|
||||||
|
|
||||||
|
(define (radicale-serialize-comma-separated-ip-list field-name value)
|
||||||
|
(radicale-serialize-field field-name (string-join value ", ")))
|
||||||
|
|
||||||
|
(define radicale-serialize-file-name radicale-serialize-field)
|
||||||
|
|
||||||
|
(define radicale-serialize-non-negative-integer radicale-serialize-field)
|
||||||
|
|
||||||
|
(define radicale-serialize-string radicale-serialize-field)
|
||||||
|
|
||||||
|
(define radicale-serialize-symbol radicale-serialize-field)
|
||||||
|
|
||||||
|
(define ((sanitize-delimited-symbols syms location field) value)
|
||||||
|
(cond
|
||||||
|
((not (maybe-value-set? value))
|
||||||
|
value)
|
||||||
|
((member value syms)
|
||||||
|
(string->symbol (uglify-field-name value)))
|
||||||
|
(else
|
||||||
|
(configuration-field-error (source-properties->location location)
|
||||||
|
field
|
||||||
|
value))))
|
||||||
|
|
||||||
|
;; Section configuration types
|
||||||
|
|
||||||
|
(define-configuration radicale-auth-configuration
|
||||||
|
(type
|
||||||
|
maybe-symbol
|
||||||
|
"The method to verify usernames and passwords. Options are @code{none},
|
||||||
|
@code{htpasswd}, @code{remote-user}, and @code{http-x-remote-user}.
|
||||||
|
|
||||||
|
This value is tied to @code{htpasswd-filename} and @code{htpasswd-encryption}."
|
||||||
|
(sanitizer
|
||||||
|
(sanitize-delimited-symbols '(none htpasswd remote-user http-x-remote-user)
|
||||||
|
(current-source-location)
|
||||||
|
'type)))
|
||||||
|
(htpasswd-filename
|
||||||
|
maybe-file-name
|
||||||
|
"Path to the htpasswd file. Use htpasswd or similar to generate this file.")
|
||||||
|
(htpasswd-encryption
|
||||||
|
maybe-symbol
|
||||||
|
"Encryption method used in the htpasswd file. Options are @code{plain},
|
||||||
|
@code{bcrypt}, and @code{md5}."
|
||||||
|
(sanitizer
|
||||||
|
(sanitize-delimited-symbols '(plain bcrypt md5)
|
||||||
|
(current-source-location)
|
||||||
|
'htpasswd-encryption)))
|
||||||
|
(delay
|
||||||
|
maybe-non-negative-integer
|
||||||
|
"Average delay after failed login attempts in seconds.")
|
||||||
|
(realm
|
||||||
|
maybe-string
|
||||||
|
"Message displayed in the client when a password is needed.")
|
||||||
|
(prefix radicale-))
|
||||||
|
|
||||||
|
(define-configuration radicale-encoding-configuration
|
||||||
|
(request
|
||||||
|
maybe-symbol
|
||||||
|
"Encoding for responding requests.")
|
||||||
|
(stock
|
||||||
|
maybe-symbol
|
||||||
|
"Encoding for storing local collections.")
|
||||||
|
(prefix radicale-))
|
||||||
|
|
||||||
|
(define-configuration radicale-logging-configuration
|
||||||
|
(level
|
||||||
|
maybe-symbol
|
||||||
|
"Set the logging level. One of @code{debug}, @code{info}, @code{warning},
|
||||||
|
@code{error}, or @code{critical}."
|
||||||
|
(sanitizer (sanitize-delimited-symbols '(debug info warning error critical)
|
||||||
|
(current-source-location)
|
||||||
|
'level)))
|
||||||
|
(mask-passwords?
|
||||||
|
maybe-boolean
|
||||||
|
"Whether to include passwords in logs.")
|
||||||
|
(prefix radicale-))
|
||||||
|
|
||||||
|
(define-configuration radicale-rights-configuration
|
||||||
|
(type
|
||||||
|
maybe-symbol
|
||||||
|
"Backend used to check collection access rights. The recommended backend is
|
||||||
|
@code{owner-only}. If access to calendars and address books outside the home
|
||||||
|
directory of users is granted, clients won't detect these collections and will
|
||||||
|
not show them to the user. Choosing any other method is only useful if you
|
||||||
|
access calendars and address books directly via URL. Options are
|
||||||
|
@code{authenticate}, @code{owner-only}, @code{owner-write}, and
|
||||||
|
@code{from-file}."
|
||||||
|
(sanitizer
|
||||||
|
(sanitize-delimited-symbols '(authenticate owner-only owner-write from-file)
|
||||||
|
(current-source-location)
|
||||||
|
'type)))
|
||||||
|
(file
|
||||||
|
maybe-file-name
|
||||||
|
"File for the rights backend @code{from-file}.")
|
||||||
|
(prefix radicale-))
|
||||||
|
|
||||||
|
(define-configuration radicale-server-configuration
|
||||||
|
(hosts
|
||||||
|
maybe-comma-separated-ip-list
|
||||||
|
"List of IP addresses that the server will bind to.")
|
||||||
|
(max-connections
|
||||||
|
maybe-non-negative-integer
|
||||||
|
"Maximum number of parallel connections. Set to 0 to disable the limit.")
|
||||||
|
(max-content-length
|
||||||
|
maybe-non-negative-integer
|
||||||
|
"Maximum size of the request body in byetes.")
|
||||||
|
(timeout
|
||||||
|
maybe-non-negative-integer
|
||||||
|
"Socket timeout in seconds.")
|
||||||
|
(ssl?
|
||||||
|
maybe-boolean
|
||||||
|
"Whether to enable transport layer encryption.")
|
||||||
|
(certificate
|
||||||
|
maybe-file-name
|
||||||
|
"Path of the SSL certificate.")
|
||||||
|
(key
|
||||||
|
maybe-file-name
|
||||||
|
"Path to the private key for SSL. Only effective if @code{ssl?} is
|
||||||
|
@code{#t}.")
|
||||||
|
(certificate-authority
|
||||||
|
maybe-file-name
|
||||||
|
"Path to CA certificate for validating client certificates. This can be used
|
||||||
|
to secure TCP traffic between Radicale and a reverse proxy. If you want to
|
||||||
|
authenticate users with client-side certificates, you also have to write an
|
||||||
|
authentication plugin that extracts the username from the certificate.")
|
||||||
|
(prefix radicale-))
|
||||||
|
|
||||||
|
(define-configuration radicale-storage-configuration
|
||||||
|
(type
|
||||||
|
maybe-symbol
|
||||||
|
"Backend used to store data. Options are @code{multifilesystem} and
|
||||||
|
@code{multifilesystem-nolock}."
|
||||||
|
(sanitizer
|
||||||
|
(sanitize-delimited-symbols '(multifilesystem multifilesystem-nolock)
|
||||||
|
(current-source-location)
|
||||||
|
'type)))
|
||||||
|
(filesystem-folder
|
||||||
|
maybe-file-name
|
||||||
|
"Folder for storing local collections. Created if not present.")
|
||||||
|
(max-sync-token-age
|
||||||
|
maybe-non-negative-integer
|
||||||
|
"Delete sync-tokens that are older than the specified time in seconds.")
|
||||||
|
(hook
|
||||||
|
maybe-string
|
||||||
|
"Command run after changes to storage.")
|
||||||
|
(prefix radicale-))
|
||||||
|
|
||||||
|
;; Helpers for using section configurations in the main configuration
|
||||||
|
|
||||||
|
;; XXX These indirections are necessary to avoid creating semantic ambiguity
|
||||||
|
(define auth-config? radicale-auth-configuration?)
|
||||||
|
(define encoding-config? radicale-encoding-configuration?)
|
||||||
|
(define headers-file? file-like?)
|
||||||
|
(define logging-config? radicale-logging-configuration?)
|
||||||
|
(define rights-config? radicale-rights-configuration?)
|
||||||
|
(define server-config? radicale-server-configuration?)
|
||||||
|
(define storage-config? radicale-storage-configuration?)
|
||||||
|
|
||||||
|
(define-maybe auth-config)
|
||||||
|
(define-maybe encoding-config)
|
||||||
|
(define-maybe headers-file)
|
||||||
|
(define-maybe logging-config)
|
||||||
|
(define-maybe rights-config)
|
||||||
|
(define-maybe server-config)
|
||||||
|
(define-maybe storage-config)
|
||||||
|
|
||||||
|
(define ((serialize-radicale-section fields) name cfg)
|
||||||
|
#~(format #f "[~a]\n~a\n" '#$name #$(serialize-configuration cfg fields)))
|
||||||
|
|
||||||
|
(define serialize-auth-config
|
||||||
|
(serialize-radicale-section radicale-auth-configuration-fields))
|
||||||
|
(define serialize-encoding-config
|
||||||
|
(serialize-radicale-section radicale-encoding-configuration-fields))
|
||||||
|
(define serialize-logging-config
|
||||||
|
(serialize-radicale-section radicale-logging-configuration-fields))
|
||||||
|
(define serialize-rights-config
|
||||||
|
(serialize-radicale-section radicale-rights-configuration-fields))
|
||||||
|
(define serialize-server-config
|
||||||
|
(serialize-radicale-section radicale-server-configuration-fields))
|
||||||
|
(define serialize-storage-config
|
||||||
|
(serialize-radicale-section radicale-storage-configuration-fields))
|
||||||
|
|
||||||
|
(define (serialize-radicale-configuration cfg)
|
||||||
|
(mixed-text-file
|
||||||
|
"radicale.conf"
|
||||||
|
(serialize-configuration cfg radicale-configuration-fields)))
|
||||||
|
|
||||||
|
(define-configuration radicale-configuration
|
||||||
|
;; Only fields whose default value does not match upstream are not maybe-types
|
||||||
|
(package
|
||||||
|
(file-like radicale)
|
||||||
|
"Package that provides @command{radicale}.")
|
||||||
|
(auth
|
||||||
|
maybe-auth-config
|
||||||
|
"Configuration for auth-related variables.")
|
||||||
|
(encoding
|
||||||
|
maybe-encoding-config
|
||||||
|
"Configuration for encoding-related variables.")
|
||||||
|
(headers-file
|
||||||
|
maybe-headers-file
|
||||||
|
"Custom HTTP headers."
|
||||||
|
(serializer
|
||||||
|
(lambda (field-name value)
|
||||||
|
#~(begin
|
||||||
|
(use-modules (ice-9 rdelim))
|
||||||
|
(format #f "[headers]\n~a\n\n"
|
||||||
|
(with-input-from-file #$value read-string))))))
|
||||||
|
(logging
|
||||||
|
maybe-logging-config
|
||||||
|
"Configuration for logging-related variables.")
|
||||||
|
(rights
|
||||||
|
maybe-rights-config
|
||||||
|
"Configuration for rights-related variables.")
|
||||||
|
(server
|
||||||
|
maybe-server-config
|
||||||
|
"Configuration for server-related variables. Ignored if WSGI is used.")
|
||||||
|
(storage
|
||||||
|
maybe-storage-config
|
||||||
|
"Configuration for storage-related variables.")
|
||||||
|
(web-interface?
|
||||||
|
maybe-boolean
|
||||||
|
"Whether to use Radicale's built-in web interface."
|
||||||
|
(serializer
|
||||||
|
(lambda (_ use?)
|
||||||
|
#~(format #f "[web]\ntype = ~a\n\n" #$(if use? "internal" "none"))))))
|
||||||
|
|
||||||
(define %radicale-accounts
|
(define %radicale-accounts
|
||||||
(list (user-group
|
(list (user-group
|
||||||
|
@ -1959,43 +2208,88 @@ hosts = localhost:5232"))
|
||||||
(home-directory "/var/empty")
|
(home-directory "/var/empty")
|
||||||
(shell (file-append shadow "/sbin/nologin")))))
|
(shell (file-append shadow "/sbin/nologin")))))
|
||||||
|
|
||||||
(define radicale-shepherd-service
|
(define (radicale-shepherd-service cfg)
|
||||||
(match-lambda
|
|
||||||
(($ <radicale-configuration> package config-file)
|
|
||||||
(list (shepherd-service
|
(list (shepherd-service
|
||||||
(provision '(radicale))
|
(provision '(radicale))
|
||||||
(documentation "Run the radicale daemon.")
|
(documentation "Run the radicale daemon.")
|
||||||
(requirement '(networking))
|
(requirement '(networking))
|
||||||
(start #~(make-forkexec-constructor
|
(start #~(make-forkexec-constructor
|
||||||
(list #$(file-append package "/bin/radicale")
|
(list #$(file-append (radicale-configuration-package cfg)
|
||||||
"-C" #$config-file)
|
"/bin/radicale")
|
||||||
|
"-C" #$(serialize-radicale-configuration cfg))
|
||||||
#:user "radicale"
|
#:user "radicale"
|
||||||
#:group "radicale"))
|
#:group "radicale"))
|
||||||
(stop #~(make-kill-destructor)))))))
|
(stop #~(make-kill-destructor)))))
|
||||||
|
|
||||||
(define radicale-activation
|
(define radicale-activation
|
||||||
(match-lambda
|
(match-lambda
|
||||||
(($ <radicale-configuration> package config-file)
|
(($ <radicale-configuration> _ auth-config _ _ _ _ _ storage-config _)
|
||||||
|
;; Get values for the collections directory
|
||||||
|
;; See https://radicale.org/v3.html#running-as-a-service
|
||||||
|
(define filesystem-folder-val
|
||||||
|
(if (maybe-value-set? storage-config)
|
||||||
|
(radicale-storage-configuration-filesystem-folder storage-config)
|
||||||
|
storage-config))
|
||||||
|
(define collections-dir
|
||||||
|
(if (maybe-value-set? filesystem-folder-val)
|
||||||
|
filesystem-folder-val
|
||||||
|
"/var/lib/radicale/collections"))
|
||||||
|
(define collections-parent-dir (dirname collections-dir))
|
||||||
|
;; Get values for the password file directory
|
||||||
|
(define auth-value-set? (maybe-value-set? auth-config))
|
||||||
|
;; If auth's type is 'none or unset, that means there is no authentication
|
||||||
|
;; and we don't need to setup files for it
|
||||||
|
(define auth?
|
||||||
|
(and auth-value-set?
|
||||||
|
(not (eq? (radicale-auth-configuration-type auth-config) 'none))))
|
||||||
|
(define password-file-val
|
||||||
|
(if auth-value-set?
|
||||||
|
(radicale-auth-configuration-htpasswd-filename auth-config)
|
||||||
|
auth-config))
|
||||||
|
(define password-file-dir
|
||||||
|
(if (maybe-value-set? password-file-val)
|
||||||
|
(dirname password-file-val)
|
||||||
|
"/etc/radicale"))
|
||||||
(with-imported-modules '((guix build utils))
|
(with-imported-modules '((guix build utils))
|
||||||
#~(begin
|
#~(begin
|
||||||
(use-modules (guix build utils))
|
(use-modules (guix build utils))
|
||||||
(let ((uid (passwd:uid (getpw "radicale")))
|
(let ((user (getpwnam "radicale")))
|
||||||
(gid (group:gid (getgr "radicale"))))
|
;; Collections directory perms
|
||||||
(mkdir-p "/var/lib/radicale/collections")
|
(mkdir-p/perms #$collections-dir user #o700)
|
||||||
(chown "/var/lib/radicale" uid gid)
|
;; Password file perms
|
||||||
(chown "/var/lib/radicale/collections" uid gid)
|
(when #$auth?
|
||||||
(chmod "/var/lib/radicale" #o700)))))))
|
;; In theory, the password file and thus this directory should already
|
||||||
|
;; exist because the user has to make them by hand
|
||||||
|
(mkdir-p/perms #$password-file-dir user #o700))))))))
|
||||||
|
|
||||||
(define radicale-service-type
|
(define radicale-service-type
|
||||||
(service-type
|
(service-type
|
||||||
(name 'radicale)
|
(name 'radicale)
|
||||||
(description "Run radicale, a small CalDAV and CardDAV server.")
|
(description "Run Radicale, a small CalDAV and CardDAV server.")
|
||||||
(extensions
|
(extensions
|
||||||
(list (service-extension shepherd-root-service-type radicale-shepherd-service)
|
(list (service-extension shepherd-root-service-type radicale-shepherd-service)
|
||||||
(service-extension account-service-type (const %radicale-accounts))
|
(service-extension account-service-type (const %radicale-accounts))
|
||||||
(service-extension activation-service-type radicale-activation)))
|
(service-extension activation-service-type radicale-activation)))
|
||||||
(default-value (radicale-configuration))))
|
(default-value (radicale-configuration))))
|
||||||
|
|
||||||
|
(define (generate-radicale-documentation)
|
||||||
|
(generate-documentation
|
||||||
|
`((radicale-configuration
|
||||||
|
,radicale-configuration-fields
|
||||||
|
(auth radicale-auth-configuration)
|
||||||
|
(encoding radicale-encoding-configuration)
|
||||||
|
(logging radicale-logging-configuration)
|
||||||
|
(rights radicale-rights-configuration)
|
||||||
|
(server radicale-server-configuration)
|
||||||
|
(storage radicale-storage-configuration))
|
||||||
|
(radicale-auth-configuration ,radicale-auth-configuration-fields)
|
||||||
|
(radicale-encoding-configuration ,radicale-encoding-configuration-fields)
|
||||||
|
(radicale-logging-configuration ,radicale-logging-configuration-fields)
|
||||||
|
(radicale-rights-configuration ,radicale-rights-configuration-fields)
|
||||||
|
(radicale-server-configuration ,radicale-server-configuration-fields)
|
||||||
|
(radicale-storage-configuration ,radicale-storage-configuration-fields))
|
||||||
|
'radicale-configuration))
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
;;; Rspamd.
|
;;; Rspamd.
|
||||||
;;;
|
;;;
|
||||||
|
|
Reference in New Issue