aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Wilken2023-04-20 23:12:01 +0200
committerTimo Wilken2023-04-21 14:32:02 +0200
commit79ea4090f9b5591e1e93c0bc5a5250ce4b390981 (patch)
treea0a8bca56baa09fab5e420fd385ce75c5f731528
parent5c1c824fb6fc7881e2cf9bedcce7ff24550f8210 (diff)
Add initial restic-server code
-rw-r--r--tw/packages/restic.scm80
-rw-r--r--tw/services/restic.scm84
2 files changed, 164 insertions, 0 deletions
diff --git a/tw/packages/restic.scm b/tw/packages/restic.scm
new file mode 100644
index 00000000..9c1a5865
--- /dev/null
+++ b/tw/packages/restic.scm
@@ -0,0 +1,80 @@
+(define-module (tw packages restic)
+ #:use-module (gnu packages golang)
+ #:use-module (gnu packages syncthing) ;some Go libraries
+ #:use-module (guix build utils)
+ #:use-module (guix build-system copy)
+ #:use-module (guix build-system go)
+ #:use-module (guix git-download)
+ #:use-module (guix packages)
+ #:use-module ((guix licenses)
+ #:prefix license:))
+
+(define-public go-github-com-coreos-go-systemd-activation
+ (package
+ (name "go-github-com-coreos-go-systemd-activation")
+ (version "0.0.0-20191104093116-d3cd4ed1dbcf")
+ (source (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/coreos/go-systemd")
+ (commit (go-version->git-ref version))))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32
+ "193mgqn7n4gbb8jb5kyn6ml4lbvh4xs55qpjnisaz7j945ik3kd8"))))
+ (build-system go-build-system)
+ (arguments
+ '(#:import-path "github.com/coreos/go-systemd/activation"
+ #:unpack-path "github.com/coreos/go-systemd"))
+ (home-page "https://github.com/coreos/go-systemd")
+ (synopsis "Go bindings to systemd socket activation")
+ (description "Go bindings to systemd socket activation; for writing and
+using socket activation from Go.")
+ (license license:asl2.0)))
+
+(define-public restic-rest-server
+ (package
+ (name "restic-rest-server")
+ (version "0.11.0")
+ (source (origin
+ (method git-fetch)
+ (uri (git-reference
+ (url "https://github.com/restic/rest-server")
+ (commit (string-append "v" version))))
+ (file-name (git-file-name name version))
+ (sha256
+ (base32
+ "1nvmxc9x0mlks6yfn66fmwn50k5q83ip4g9vvb0kndzd7hwcyacy"))))
+ (build-system go-build-system)
+ (arguments
+ '(#:import-path "github.com/restic/rest-server/cmd/rest-server"
+ #:unpack-path "github.com/restic/rest-server"
+ #:install-source? #f ;all we need is the binary
+ #:phases (modify-phases %standard-phases
+ (replace 'check
+ (lambda* (#:key tests? #:allow-other-keys . args)
+ (when tests?
+ ;; Unit tests seems to break with Guix' non-standard TMPDIR.
+ (setenv "TMPDIR" "/tmp")
+ (apply (assoc-ref %standard-phases
+ 'check) args))))
+ (add-after 'install 'rename-binary
+ (lambda* (#:key outputs #:allow-other-keys)
+ (with-directory-excursion (assoc-ref outputs "out")
+ ;; "rest-server" is a bit too generic.
+ (rename-file "bin/rest-server"
+ "bin/restic-rest-server")))))))
+ (propagated-inputs (list go-golang-org-x-crypto
+ go-github-com-spf13-cobra
+ go-github-com-prometheus-client-golang
+ go-github-com-miolini-datacounter
+ go-github-com-minio-sha256-simd
+ go-github-com-gorilla-handlers
+ go-github-com-coreos-go-systemd-activation))
+ (home-page "https://github.com/restic/rest-server")
+ (synopsis "Restic REST server")
+ (description
+ "The Restic REST server is a high performance HTTP server that implements
+restic's REST backend API. It provides a secure and efficient way to backup
+data remotely, using the restic backup client and a @code{rest:} URL.")
+ (license license:bsd-2)))
diff --git a/tw/services/restic.scm b/tw/services/restic.scm
new file mode 100644
index 00000000..637c7104
--- /dev/null
+++ b/tw/services/restic.scm
@@ -0,0 +1,84 @@
+(define-module (tw services restic)
+ #:use-module (gnu)
+ #:use-module ((gnu packages admin)
+ #:select (shadow))
+ #:use-module (gnu services)
+ #:use-module (gnu services configuration)
+ #:use-module (gnu services shepherd)
+ #:use-module (guix gexp)
+ #:use-module (guix packages)
+ #:use-module (tw packages restic)
+ #:export (restic-server-service-type
+ restic-server-configuration))
+
+(define-maybe/no-serialization integer)
+(define-maybe/no-serialization string)
+
+;; TODO: implement --tls, --tls-cert and --tls-key, maybe using certbot-service-type?
+(define-configuration/no-serialization restic-server-configuration
+ (repository-path (string "/var/lib/restic") "The directory containing
+restic's repositories and @code{.htpasswd} file, unless otherwise configured
+using @code{htpasswd-file}.")
+ (restic-server (package restic-rest-server) "The restic REST server package to use.")
+ (bind-address (string ":8000") "The listen address (including port) to bind to.")
+ (htpasswd-file (maybe-string #f) "Location of @code{.htpasswd} file
+(default: @code{REPOSITORY-PATH/.htpasswd}).")
+ (auth? (boolean #t) "Whether to authenticate users at all (using .htpasswd).")
+ (verify-upload? (boolean #t) "Whether to verify the integrity of uploaded
+data. @emph{Do not disable} unless the restic server is to be run on a very
+low-power device.")
+ (append-only? (boolean #f) "Whether to run the restic server in append-only mode.")
+ (max-repository-size (maybe-integer %unset-value) "Maximum repository size
+in bytes, if any.")
+ (private-repos-only? (boolean #f) "Whether to let users only access their
+private restic repos.")
+ (prometheus? (boolean #f) "Whether to serve Prometheus metrics.")
+ (prometheus-auth? (boolean #t) "Whether to require authentication as the
+@code{metrics} user to access the Prometheus /metrics endpoint."))
+
+(define (restic-server-arguments config)
+ "Turn CONFIG into a list of arguments to the restic-rest-server executable."
+ `("--path" ,(restic-server-configuration-repository-path config)
+ "--log" "/var/log/restic-server.log"
+ "--listen" ,(restic-server-configuration-bind-address config)
+ ,@(if (restic-server-configuration-append-only? config) '("--append-only") '())
+ ,@(let ((max-size (restic-server-configuration-max-repository-size config)))
+ (if (integer? max-size) `("--max-size" ,max-size) '()))
+ ,@(if (restic-server-configuration-private-repos-only? config) '("--private-repos") '())
+ ,@(if (restic-server-configuration-prometheus? config) '("--prometheus") '())
+ ,@(if (restic-server-configuration-prometheus-auth? config) '() '("--prometheus-no-auth"))))
+
+(define (restic-server-service config)
+ "Create a `shepherd-service' for the restic REST server from CONFIG."
+ (list (shepherd-service
+ (provision '(restic-server))
+ (requirement '(networking))
+ (documentation "Run the Restic REST server to serve backup repositories via HTTP.")
+ (start #~(make-forkexec-constructor
+ (list #$(file-append (restic-server-configuration-restic-server config)
+ "/bin/restic-rest-server")
+ #$@(restic-server-arguments config))
+ #:user "restic" #:group "restic"))
+ (stop #~(make-kill-destructor)))))
+
+(define (restic-server-accounts config)
+ "Create user accounts and groups for the restic REST server defined in CONFIG."
+ (list (user-account
+ (name "restic")
+ (group "restic")
+ (comment "Restic server user")
+ (system? #t)
+ (home-directory (restic-server-configuration-repository-path config))
+ (shell (file-append shadow "/sbin/nologin")))
+ (user-group
+ (name "restic")
+ (system? #t))))
+
+(define restic-server-service-type
+ (service-type
+ (name 'restic-server)
+ (extensions
+ (list (service-extension shepherd-root-service-type restic-server-service)
+ (service-extension account-service-type restic-server-accounts)))
+ (description
+ "Restic REST server, running as a service user instead of root.")))