GNU bug report logs - #66160
[PATCH] gnu: Add oci-container-service-type.

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: guix-patches; Reported by: paul <goodoldpaul@HIDDEN>; Keywords: patch; Done: Ludovic Courtès <ludo@HIDDEN>; Maintainer for guix-patches is guix-patches@HIDDEN.
bug closed, send any further explanations to 66160 <at> debbugs.gnu.org and paul <goodoldpaul@HIDDEN> Request was from Ludovic Courtès <ludo@HIDDEN> to control <at> debbugs.gnu.org. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 23 Nov 2023 10:02:58 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Nov 23 05:02:58 2023
Received: from localhost ([127.0.0.1]:60662 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1r66Xy-0002gJ-2i
	for submit <at> debbugs.gnu.org; Thu, 23 Nov 2023 05:02:58 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:34630)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <ludo@HIDDEN>) id 1r66Xw-0002g2-4i
 for 66160 <at> debbugs.gnu.org; Thu, 23 Nov 2023 05:02:56 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1r66Xl-00070H-Cy; Thu, 23 Nov 2023 05:02:45 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=Pk71E+BWPx2mWZoba4C6xTQUN9QUC2i6k/yWDYl4L0E=; b=a4tgHuubbY8TAF14dle9
 my6gsZtVQP/OeYK/zh1zFgyGMrxkarDz6lgKum1rq0DfgE+TabTJEEAAk6SVQIMsP1q44nQ2XxPpa
 B1xLHwfOHnnZrOPyXyc1lFLLdRH2t2AHkcYrn3nZuzdJVivKMzP4AU3xt+tAkbP/RzKs0X2mL5H6x
 /ucmxgltZ7E4j8BPntsPOYIz9dHaaMwYpuZbevpMlMVOq6foUboaE8GXPAVqN9ZyrPghQc+gY+48D
 C1hXGTUP+HGd9xg3ySs39IB72NV6M4wEg/XhEeHEBglwhv+hIJdgwXkFrOv0Pkr1Z/XiVyCfmzrYn
 XPm3sA7nmHZ3Kg==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Giacomo Leidi <goodoldpaul@HIDDEN>
Subject: Re: [bug#66160] [PATCH v2] gnu: Add oci-container-service-type.
In-Reply-To: <913b66b3e32e37af82fb49b9744ecfb24114bad2.1698181140.git.goodoldpaul@HIDDEN>
 (Giacomo Leidi's message of "Tue, 24 Oct 2023 22:59:00 +0200")
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <913b66b3e32e37af82fb49b9744ecfb24114bad2.1698181140.git.goodoldpaul@HIDDEN>
Date: Thu, 23 Nov 2023 11:02:42 +0100
Message-ID: <8734wwg531.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hi,

Giacomo Leidi <goodoldpaul@HIDDEN> skribis:

> * gnu/services/docker.scm (oci-container-configuration): New variable;
> (oci-container-shepherd-service): new variable;
> (oci-container-service-type): new variable.
> * doc/guix.texi: Document it.

Finally applied, thanks!

As discussed earlier, please follow up with a patch adding a system test
so that the service doesn=E2=80=99t bitrot.

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 24 Oct 2023 21:00:05 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Oct 24 17:00:05 2023
Received: from localhost ([127.0.0.1]:56785 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qvOVQ-0007Cb-AV
	for submit <at> debbugs.gnu.org; Tue, 24 Oct 2023 17:00:05 -0400
Received: from confino.investici.org ([2a11:7980:1::2:0]:52337)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qvOVK-0007BX-CT
 for 66160 <at> debbugs.gnu.org; Tue, 24 Oct 2023 17:00:02 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4SFPZ44323z113g;
 Tue, 24 Oct 2023 20:59:24 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1698181164;
 bh=Z1hNdnLGhgg5L544YW3vX9o1DdfYFuizritZAsIm6Pw=;
 h=From:To:Cc:Subject:Date:From;
 b=VbcpRXijSJphs3+Rm6Y4Bu0bbz8D7Sb5kwBGeiFFCfWqA1xZqPsbpxX4CkMRSoNDV
 JuGx2qgla3fkXwWWY7TManD5YYs7ssTTrf50KblaAZVdw2tpzP1JZ4EPlo2KAh65Fp
 WMS88I7KO+UZhfhtePglB4U1hGe6wFh2X09kYgaY=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4SFPZ43QLhz113S; Tue, 24 Oct 2023 20:59:24 +0000 (UTC)
From: Giacomo Leidi <goodoldpaul@HIDDEN>
To: 66160 <at> debbugs.gnu.org
Subject: [PATCH v2] gnu: Add oci-container-service-type.
Date: Tue, 24 Oct 2023 22:59:00 +0200
Message-ID: <913b66b3e32e37af82fb49b9744ecfb24114bad2.1698181140.git.goodoldpaul@HIDDEN>
X-Mailer: git-send-email 2.41.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 66160
Cc: Giacomo Leidi <goodoldpaul@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

* gnu/services/docker.scm (oci-container-configuration): New variable;
(oci-container-shepherd-service): new variable;
(oci-container-service-type): new variable.
* doc/guix.texi: Document it.
---
 doc/guix.texi           | 131 ++++++++++++++++++++
 gnu/services/docker.scm | 260 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 390 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index b90078be06..f6363a16a3 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -39518,6 +39518,137 @@ Miscellaneous Services
 @command{singularity run} and similar commands.
 @end defvar
 
+@cindex OCI-backed, Shepherd services
+@subsubheading OCI backed services
+
+Should you wish to manage your Docker containers with the same consistent
+interface you use for your other Shepherd services,
+@var{oci-container-service-type} is the tool to use: given an
+@acronym{Open Container Initiative, OCI} container image, it will run it in a
+Shepherd service.  One example where this is useful: it lets you run services
+that are available as Docker/OCI images but not yet packaged for Guix.
+
+@defvar oci-container-service-type
+
+This is a thin wrapper around Docker's CLI that executes OCI images backed
+processes as Shepherd Services.
+
+@lisp
+(service oci-container-service-type
+         (list
+          (oci-container-configuration
+           (image "prom/prometheus")
+           (network "host")
+           (ports
+             '(("9000" . "9000")
+               ("9090" . "9090"))))
+          (oci-container-configuration
+           (image "grafana/grafana:10.0.1")
+           (network "host")
+           (ports
+             '(("3000" . "3000")))
+           (volumes
+             '("/var/lib/grafana:/var/lib/grafana")))))
+@end lisp
+
+In this example two different Shepherd services are going be added to the
+system.  Each @code{oci-container-configuration} record translates to a
+@code{docker run} invocation and its fields directly map to options.  You can
+refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run,upstream},
+documentation for the semantics of each value.  If the images are not found they
+will be
+@url{https://docs.docker.com/engine/reference/commandline/pull/,pulled}.  The
+spawned services are going to be attached to the host network and are supposed
+to behave like other processes.
+
+@end defvar
+
+@c %start of fragment
+
+@deftp {Data Type} oci-container-configuration
+Available @code{oci-container-configuration} fields are:
+
+@table @asis
+@item @code{user} (default: @code{"oci-container"}) (type: string)
+The user under whose authority docker commands will be run.
+
+@item @code{group} (default: @code{"docker"}) (type: string)
+The group under whose authority docker commands will be run.
+
+@item @code{command} (default: @code{()}) (type: list-of-strings)
+Overwrite the default command (@code{CMD}) of the image.
+
+@item @code{entrypoint} (default: @code{""}) (type: string)
+Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.
+
+@item @code{environment} (default: @code{()}) (type: list)
+Set environment variables. This can be a list of pairs or strings, even mixed:
+
+@lisp
+(list '("LANGUAGE" . "eo:ca:eu")
+      "JAVA_HOME=/opt/java")
+@end lisp
+
+String are passed directly to the Docker CLI. You can refer to the
+@uref{https://docs.docker.com/engine/reference/commandline/run/#env,upstream}
+documentation for semantics.
+
+@item @code{image} (type: string)
+The image used to build the container.  Images are resolved by the
+Docker Engine, and follow the usual format
+@code{myregistry.local:5000/testing/test-image:tag}.
+
+@item @code{provision} (default: @code{""}) (type: string)
+Set the name of the provisioned Shepherd service.
+
+@item @code{network} (default: @code{""}) (type: string)
+Set a Docker network for the spawned container.
+
+@item @code{ports} (default: @code{()}) (type: list)
+Set the port or port ranges to expose from the spawned container.  This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("8080" . "80")
+      "10443:443")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@uref{https://docs.docker.com/engine/reference/commandline/run/#publish,upstream}
+documentation for semantics.
+
+@item @code{volumes} (default: @code{()}) (type: list)
+Set volume mappings for the spawned container.  This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("/root/data/grafana" . "/var/lib/grafana")
+      "/gnu/store:/gnu/store")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@uref{https://docs.docker.com/engine/reference/commandline/run/#volume,upstream}
+documentation for semantics.
+
+@item @code{container-user} (default: @code{""}) (type: string)
+Set the current user inside the spawned container.  You can refer to the
+@url{https://docs.docker.com/engine/reference/run/#user,upstream}
+documentation for semantics.
+
+@item @code{workdir} (default: @code{""}) (type: string)
+Set the current working for the spawned Shepherd service.
+You can refer to the
+@url{https://docs.docker.com/engine/reference/run/#workdir,upstream}
+documentation for semantics.
+
+@end table
+
+@end deftp
+
+
+@c %end of fragment
+
 @cindex Audit
 @subsubheading Auditd Service
 
diff --git a/gnu/services/docker.scm b/gnu/services/docker.scm
index c2023d618c..ebea0a473a 100644
--- a/gnu/services/docker.scm
+++ b/gnu/services/docker.scm
@@ -5,6 +5,7 @@
 ;;; Copyright © 2020 Efraim Flashner <efraim@HIDDEN>
 ;;; Copyright © 2020 Jesse Dowell <jessedowell@HIDDEN>
 ;;; Copyright © 2021 Brice Waegeneire <brice@HIDDEN>
+;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -29,15 +30,36 @@ (define-module (gnu services docker)
   #:use-module (gnu services shepherd)
   #:use-module (gnu system setuid)
   #:use-module (gnu system shadow)
+  #:use-module (gnu packages admin)               ;shadow
   #:use-module (gnu packages docker)
   #:use-module (gnu packages linux)               ;singularity
   #:use-module (guix records)
+  #:use-module (guix diagnostics)
   #:use-module (guix gexp)
+  #:use-module (guix i18n)
   #:use-module (guix packages)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
 
   #:export (docker-configuration
             docker-service-type
-            singularity-service-type))
+            singularity-service-type
+            oci-container-configuration
+            oci-container-configuration?
+            oci-container-configuration-fields
+            oci-container-configuration-user
+            oci-container-configuration-group
+            oci-container-configuration-command
+            oci-container-configuration-entrypoint
+            oci-container-configuration-environment
+            oci-container-configuration-image
+            oci-container-configuration-provision
+            oci-container-configuration-network
+            oci-container-configuration-ports
+            oci-container-configuration-volumes
+            oci-container-service-type
+            oci-container-shepherd-service))
 
 (define-configuration docker-configuration
   (docker
@@ -216,3 +238,239 @@ (define singularity-service-type
                        (service-extension activation-service-type
                                           (const %singularity-activation))))
                 (default-value singularity)))
+
+
+;;;
+;;; OCI container.
+;;;
+
+(define (oci-sanitize-pair pair delimiter)
+  (define (valid? member)
+    (or (string? member)
+        (gexp? member)
+        (file-like? member)))
+  (match pair
+    (((? valid? key) . (? valid? value))
+     #~(string-append #$key #$delimiter #$value))
+    (_
+     (raise
+      (formatted-message
+       (G_ "pair members must contain only strings, gexps or file-like objects
+but ~a was found")
+       pair)))))
+
+(define (oci-sanitize-mixed-list name value delimiter)
+  (map
+   (lambda (el)
+     (cond ((string? el) el)
+           ((pair? el) (oci-sanitize-pair el delimiter))
+           (else
+            (raise
+             (formatted-message
+              (G_ "~a members must be either a string or a pair but ~a was
+found!")
+              name el)))))
+   value))
+
+(define (oci-sanitize-environment value)
+  ;; Expected spec format:
+  ;; '(("HOME" . "/home/nobody") "JAVA_HOME=/java")
+  (oci-sanitize-mixed-list "environment" value "="))
+
+(define (oci-sanitize-ports value)
+  ;; Expected spec format:
+  ;; '(("8088" . "80") "2022:22")
+  (oci-sanitize-mixed-list "ports" value ":"))
+
+(define (oci-sanitize-volumes value)
+  ;; Expected spec format:
+  ;; '(("/mnt/dir" . "/dir") "/run/current-system/profile:/java")
+  (oci-sanitize-mixed-list "volumes" value ":"))
+
+(define-maybe/no-serialization string)
+
+(define-configuration/no-serialization oci-container-configuration
+  (user
+   (string "oci-container")
+   "The user under whose authority docker commands will be run.")
+  (group
+   (string "docker")
+   "The group under whose authority docker commands will be run.")
+  (command
+   (list-of-strings '())
+   "Overwrite the default command (@code{CMD}) of the image.")
+  (entrypoint
+   (maybe-string)
+   "Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.")
+  (environment
+   (list '())
+   "Set environment variables.  This can be a list of pairs or strings, even
+mixed:
+
+@lisp
+(list '(\"LANGUAGE\" . \"eo:ca:eu\")
+      \"JAVA_HOME=/opt/java\")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#env,upstream}
+documentation for semantics."
+   (sanitizer oci-sanitize-environment))
+  (image
+   (string)
+   "The image used to build the container.  Images are resolved by the Docker
+Engine, and follow the usual format
+@code{myregistry.local:5000/testing/test-image:tag}.")
+  (provision
+   (maybe-string)
+   "Set the name of the provisioned Shepherd service.")
+  (network
+   (maybe-string)
+   "Set a Docker network for the spawned container.")
+  (ports
+   (list '())
+   "Set the port or port ranges to expose from the spawned container.  This can
+be a list of pairs or strings, even mixed:
+
+@lisp
+(list '(\"8080\" . \"80\")
+      \"10443:443\")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#publish,upstream}
+documentation for semantics."
+   (sanitizer oci-sanitize-ports))
+  (volumes
+   (list '())
+   "Set volume mappings for the spawned container.  This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '(\"/root/data/grafana\" . \"/var/lib/grafana\")
+      \"/gnu/store:/gnu/store\")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#volume,upstream}
+documentation for semantics."
+   (sanitizer oci-sanitize-volumes))
+  (container-user
+   (maybe-string)
+   "Set the current user inside the spawned container.  You can refer to the
+@url{https://docs.docker.com/engine/reference/run/#user,upstream}
+documentation for semantics.")
+  (workdir
+   (maybe-string)
+   "Set the current working for the spawned Shepherd service.
+You can refer to the
+@url{https://docs.docker.com/engine/reference/run/#workdir,upstream}
+documentation for semantics."))
+
+(define oci-container-configuration->options
+  (lambda (config)
+    (let ((entrypoint
+           (oci-container-configuration-entrypoint config))
+          (network
+           (oci-container-configuration-network config))
+          (user
+           (oci-container-configuration-user config))
+          (workdir
+           (oci-container-configuration-workdir config)))
+      (apply append
+             (filter (compose not unspecified?)
+                     `(,(if (maybe-value-set? entrypoint)
+                            `("--entrypoint" ,entrypoint)
+                            '())
+                       ,(append-map
+                         (lambda (spec)
+                           (list "--env" spec))
+                         (oci-container-configuration-environment config))
+                       ,(if (maybe-value-set? network)
+                            `("--network" ,network)
+                            '())
+                       ,(if (maybe-value-set? user)
+                            `("--user" ,user)
+                            '())
+                       ,(if (maybe-value-set? workdir)
+                            `("--workdir" ,workdir)
+                            '())
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-p" spec))
+                         (oci-container-configuration-ports config))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-v" spec))
+                         (oci-container-configuration-volumes config))))))))
+
+(define (oci-container-shepherd-service config)
+  (define (guess-name name image)
+    (if (maybe-value-set? name)
+        name
+        (string-append "docker-"
+                       (basename (car (string-split image #\:))))))
+
+  (let* ((docker-command (file-append docker-cli "/bin/docker"))
+         (user (oci-container-configuration-user config))
+         (group (oci-container-configuration-group config))
+         (command (oci-container-configuration-command config))
+         (provision (oci-container-configuration-provision config))
+         (image (oci-container-configuration-image config))
+         (options (oci-container-configuration->options config))
+         (name (guess-name provision image)))
+
+    (shepherd-service (provision `(,(string->symbol name)))
+                      (requirement '(dockerd user-processes))
+                      (respawn? #f)
+                      (documentation
+                       (string-append
+                        "Docker backed Shepherd service for image: " image))
+                      (start
+                       #~(make-forkexec-constructor
+                          ;; docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
+                          (list #$docker-command "run" "--rm"
+                                "--name" #$name
+                                #$@options #$image #$@command)
+                          #:user #$user
+                          #:group #$group))
+                      (stop
+                       #~(lambda _
+                           (invoke #$docker-command "rm" "-f" #$name)))
+                      (actions
+                       (list
+                        (shepherd-action
+                         (name 'pull)
+                         (documentation
+                          (format #f "Pull ~a's image (~a)."
+                                  name image))
+                         (procedure
+                          #~(lambda _
+                              (invoke #$docker-command "pull" #$image)))))))))
+
+(define %oci-container-accounts
+  (list (user-account
+         (name "oci-container")
+         (comment "OCI services account")
+         (group "docker")
+         (system? #t)
+         (home-directory "/var/empty")
+         (shell (file-append shadow "/sbin/nologin")))))
+
+(define (configs->shepherd-services configs)
+  (map oci-container-shepherd-service configs))
+
+(define oci-container-service-type
+  (service-type (name 'oci-container)
+                (extensions (list (service-extension profile-service-type
+                                                     (lambda _ (list docker-cli)))
+                                  (service-extension account-service-type
+                                                     (const %oci-container-accounts))
+                                  (service-extension shepherd-root-service-type
+                                                     configs->shepherd-services)))
+                (default-value '())
+                (extend append)
+                (compose concatenate)
+                (description
+                 "This service allows the management of Docker and OCI
+containers as Shepherd services.")))

base-commit: 7e4324575c80cbe3c18c26b0507776b16ba3989e
-- 
2.41.0





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 24 Oct 2023 20:23:16 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Oct 24 16:23:16 2023
Received: from localhost ([127.0.0.1]:56770 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qvNvo-00065i-GD
	for submit <at> debbugs.gnu.org; Tue, 24 Oct 2023 16:23:16 -0400
Received: from confino.investici.org ([2a11:7980:1::2:0]:22863)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qvNvl-00065X-EM
 for 66160 <at> debbugs.gnu.org; Tue, 24 Oct 2023 16:23:15 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4SFNlh5jntz114N;
 Tue, 24 Oct 2023 20:22:40 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1698178960;
 bh=5G02OQWAZyR9wCuzyhRv+nviJxNBodlMQelGr6qJPIM=;
 h=Date:Subject:To:Cc:References:From:In-Reply-To:From;
 b=PGKDq3iIlurFiFrBq1aqWBIXKNQkkGmO2nhoOGCcCgwCQhU92pzxsZr3Xloyv9dEu
 4E6uz5yg0DgmPYJsT+ZGgx8AO6PzhfAM8gJmWW9pS/Ij+cLq6CO1oSU5v0BjB5JxB7
 gsqq04dhdCSkUOw0bQ1nTSKUcnGJAbCL1ufdRPRs=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4SFNlh4XQrz114M; Tue, 24 Oct 2023 20:22:40 +0000 (UTC)
Message-ID: <35d25d08-3794-adc5-3208-6cee10c48fd6@HIDDEN>
Date: Tue, 24 Oct 2023 22:22:40 +0200
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.15.0
Subject: Re: [bug#66160] [PATCH] gnu: Add oci-container-service-type.
To: =?UTF-8?Q?Ludovic_Court=c3=a8s?= <ludo@HIDDEN>
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <8b8a0eed3b02cfd2edb94859da83032c96ee5616.1696619356.git.goodoldpaul@HIDDEN>
 <875y39fao8.fsf@HIDDEN> <604138b9-a567-68eb-82fe-d205390636e7@HIDDEN>
 <874jimz7y5.fsf@HIDDEN> <16c3e931-09d2-9e85-97f1-c7f78d5ff2ec@HIDDEN>
 <874jig81uw.fsf@HIDDEN>
Content-Language: en-US
From: paul <goodoldpaul@HIDDEN>
In-Reply-To: <874jig81uw.fsf@HIDDEN>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.5 (-)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.5 (--)

Hi Ludo’ ,

thank you for your explanation.

On 10/24/23 17:41, Ludovic Courtès wrote:
> If you take the route of one ‘oci-container-service-type’ per
> daemon/server that you want to run,
what you mention below is already implemented in my latest patch [0]:
> then <oci-container-configuration>
> should probably have a ‘user’ field to specify under which user to run
> the container.
this is oci-container-configuration-user
> <oci-container-configuration> would need
> a ‘provision’ field to specify the Shepherd service name (the
> “provisions”).
this is oci-container-configuration-name. I now realize that "name" it's 
not the best field name, so I'm sending a patch with this renamed to 
oci-container-configuration-provision .
>   Likewise, perhaps a field to specify the data directory
> is needed.
I don't think oci-container-configuration should concern about a data 
directory since oci containers themselves only have a volume concept 
which is covered. what you brought into my mind is that docker supports 
-w/--workdir so I implemented it and added it to the patch I'm about to 
send.
> Does that make sense?

Yes, thank you :) My doubts come from shepherd-root-service-type 
accepting a list of services. What would be the reason to break 
consistency with it? I think we would add the friction of having to write


(service nextcloud-cron-oci-service-type)

(service nextcloud-oci-service-type)


instead of simply


(service nextcloud-cron-oci-service-type)


One way out of this if you think is a good solution could be having an 
oci-containers-service-type that's supposed to be only extended whose 
value would be a list of <oci-container-configuration> and an 
oci-single-service-type that could not be extended whose value would be 
a single <oci-container-configuration> . The oci-single-service-type 
would simply extend the oci-containers-service-type and maintenance 
would be free.

What do you think?


Thank you for your help,

giacomo


[0]: https://issues.guix.gnu.org/66160#10-lineno69





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 24 Oct 2023 15:41:53 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Oct 24 11:41:53 2023
Received: from localhost ([127.0.0.1]:56345 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qvJXU-00042W-Vy
	for submit <at> debbugs.gnu.org; Tue, 24 Oct 2023 11:41:53 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:46280)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <ludo@HIDDEN>) id 1qvJXT-00042F-3G
 for 66160 <at> debbugs.gnu.org; Tue, 24 Oct 2023 11:41:51 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1qvJWs-0007ev-JZ; Tue, 24 Oct 2023 11:41:14 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=sJu/r/+tK33PNUeMh8mHz7sVqJqMuiaOu1P0NUAJbtQ=; b=Oh/FGKE0qMQDZUyk3Q8O
 zQ5Q7fThkjKwGTc4d/1kpUjVcCpaO1UeEMVup/MhdOdsrqL4oy/WN+Yhq0hgGKZXhc+MvSXgxsdFA
 gu3+YoOID+ej2t3YoykC86rPfigtrbxBQFWIvRew1bl7auaZnsQVOULqgm+IpkodyK2Fko7Mok7WI
 0LoyH42W/YFw+6a4cK2XGLNoGa8QtHhZ0DPL8zFDtwtfN7lJWMaFRjcffwZpwfSsY2gLtKTR2Z3eS
 QnJpw8VITCCJqR2N3DiIDnH1e8QBade+7qGyXhCRmLoIcvbJOLKUthbZ9b76pTJh6+PoPZIn6oz/h
 U0cyPvn4BKQSIg==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: paul <goodoldpaul@HIDDEN>
Subject: Re: [bug#66160] [PATCH] gnu: Add oci-container-service-type.
In-Reply-To: <16c3e931-09d2-9e85-97f1-c7f78d5ff2ec@HIDDEN> (paul's
 message of "Thu, 19 Oct 2023 23:16:35 +0200")
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <8b8a0eed3b02cfd2edb94859da83032c96ee5616.1696619356.git.goodoldpaul@HIDDEN>
 <875y39fao8.fsf@HIDDEN>
 <604138b9-a567-68eb-82fe-d205390636e7@HIDDEN>
 <874jimz7y5.fsf@HIDDEN>
 <16c3e931-09d2-9e85-97f1-c7f78d5ff2ec@HIDDEN>
Date: Tue, 24 Oct 2023 17:41:11 +0200
Message-ID: <874jig81uw.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hi,

paul <goodoldpaul@HIDDEN> skribis:


[...]

>> In that case, maybe create an =E2=80=9Coci-service=E2=80=9D account part=
 of the =E2=80=9Cdocker=E2=80=9D
>> group, and run =E2=80=98docker run=E2=80=99 as that user instead of runn=
ing it as root?
>> Would that be OK or am I overlooking something?
> I already added such user in the latest version of my patch. I
> probably made a mess with patch subjects.

Oh, my bad; perfect then.

>> What I=E2=80=99m suggesting above is that one would build a list of
>> =E2=80=98oci-container-service-type=E2=80=99 instances, like:
>>
>>    (list (service oci-container-service-type
>>                   (oci-container-configuration =E2=80=A6))
>>          (service oci-container-service-type
>>                   (oci-container-configuration =E2=80=A6))
>>          =E2=80=A6)
>>
>> Each instance above would correspond to exactly one program in a Docker
>> image.
>>
>> I feel it=E2=80=99s slightly more natural than having a service type that
>> implements support for multiple OCI services at once.
> I agree it's more natural but (list service-a service-b ...) it's the
> same interface exposed by the shepherd-root-service-type, I believe
> for the same reasons I need the oci-nextcloud-service-type to
> instantiate 3 shepherd services but only create a single account,
> activate a single data dir under /var/lib, something like this:
>
> (defineoci-nextcloud-service-type
> (service-type(name'nextcloud)
> (extensions(list(service-extensionoci-container-service-type
> (lambda (config) (make-nextcloud-container config)
> (make-nextcloud-cron-container config)))

[...]

> The only way where oci-container-service-type could support this use
> case by accepting a single configuration is I guess if multiple
> (service-extension oci-container-service-type ...) where allowed, am I
> understanding correctly? Is it legal in Guix to write somthing like:
>
> (extensions(list(service-extensionoci-container-service-type
> make-nextcloud-container)
> (service-extensionoci-container-service-typemake-nextcloud-cron-container)
> (service-extensionaccount-service-type
> (const%nextcloud-accounts))
> (service-extensionactivation-service-type
> %nextcloud-activation)))

If you take the route of one =E2=80=98oci-container-service-type=E2=80=99 p=
er
daemon/server that you want to run, then <oci-container-configuration>
should probably have a =E2=80=98user=E2=80=99 field to specify under which =
user to run
the container.  =E2=80=98oci-container-service-type=E2=80=99 would create e=
xactly one
Shepherd service so, likewise, <oci-container-configuration> would need
a =E2=80=98provision=E2=80=99 field to specify the Shepherd service name (t=
he
=E2=80=9Cprovisions=E2=80=9D).  Likewise, perhaps a field to specify the da=
ta directory
is needed.

Does that make sense?

Thanks,
Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 19 Oct 2023 21:17:07 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Oct 19 17:17:07 2023
Received: from localhost ([127.0.0.1]:38004 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qtaOA-0004lm-HG
	for submit <at> debbugs.gnu.org; Thu, 19 Oct 2023 17:17:07 -0400
Received: from confino.investici.org ([93.190.126.19]:48477)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qtaO8-0004lc-5C
 for 66160 <at> debbugs.gnu.org; Thu, 19 Oct 2023 17:17:05 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4SBLBC5Fdvz11BK;
 Thu, 19 Oct 2023 21:16:35 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1697750195;
 bh=vrmWaRgOmsTDoSOszmUFJ8u5YvPxY6rpl1geArVHKCA=;
 h=Date:Subject:To:Cc:References:From:In-Reply-To:From;
 b=gu6AowT5zQqI6LFRjDLLaou7Ce3wD7iqbbkbvpcd9P6pCcVbByXTIPWoyox8Vv7WW
 ieDGiGHKk5smkCtXAVTniN1xy3mfkj+g0OVgk77kAkp5cJQZ7aPMl91PcfkgnJO7MG
 4ATVyQwz2cY4PII4+qfucFGSNnKnxisdcEwo3huY=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4SBLBC43JTz119C; Thu, 19 Oct 2023 21:16:35 +0000 (UTC)
Content-Type: multipart/alternative;
 boundary="------------45oI4y2ozTIpuFiaFffYQiww"
Message-ID: <16c3e931-09d2-9e85-97f1-c7f78d5ff2ec@HIDDEN>
Date: Thu, 19 Oct 2023 23:16:35 +0200
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.15.0
Subject: Re: [bug#66160] [PATCH] gnu: Add oci-container-service-type.
To: =?UTF-8?Q?Ludovic_Court=c3=a8s?= <ludo@HIDDEN>
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <8b8a0eed3b02cfd2edb94859da83032c96ee5616.1696619356.git.goodoldpaul@HIDDEN>
 <875y39fao8.fsf@HIDDEN> <604138b9-a567-68eb-82fe-d205390636e7@HIDDEN>
 <874jimz7y5.fsf@HIDDEN>
Content-Language: en-US
From: paul <goodoldpaul@HIDDEN>
In-Reply-To: <874jimz7y5.fsf@HIDDEN>
X-Spam-Score: -1.5 (-)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.5 (--)

This is a multi-part message in MIME format.
--------------45oI4y2ozTIpuFiaFffYQiww
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit

Hello Ludo’ ,

On 10/19/23 22:13, Ludovic Courtès wrote:
> Hello,
>
> paul<goodoldpaul@HIDDEN>  skribis:
>
>
> [...]
>
>>> Does ‘docker run’ necessarily need to run as root, or are there cases
>>> where one might want to run it as non-root?  (I expect the latter.)
>> yes you are right, it's only required to be in the docker group or in
>> general have enough permission to operate on the docker daemon
>> socket. I added a new service extension setting up an oci-container
>> user, that it's just in the docker group and can not login, that runs
>> oci backed services. it is also overridable by the user
> In that case, maybe create an “oci-service” account part of the “docker”
> group, and run ‘docker run’ as that user instead of running it as root?
> Would that be OK or am I overlooking something?
I already added such user in the latest version of my patch. I probably 
made a mess with patch subjects.
> What I’m suggesting above is that one would build a list of
> ‘oci-container-service-type’ instances, like:
>
>    (list (service oci-container-service-type
>                   (oci-container-configuration …))
>          (service oci-container-service-type
>                   (oci-container-configuration …))
>          …)
>
> Each instance above would correspond to exactly one program in a Docker
> image.
>
> I feel it’s slightly more natural than having a service type that
> implements support for multiple OCI services at once.
I agree it's more natural but (list service-a service-b ...) it's the 
same interface exposed by the shepherd-root-service-type, I believe for 
the same reasons I need the oci-nextcloud-service-type to instantiate 3 
shepherd services but only create a single account, activate a single 
data dir under /var/lib, something like this:

(defineoci-nextcloud-service-type
(service-type(name'nextcloud)
(extensions(list(service-extensionoci-container-service-type
(lambda (config) (make-nextcloud-container config) 
(make-nextcloud-cron-container config)))
(service-extensionaccount-service-type
(const%nextcloud-accounts))
(service-extensionactivation-service-type
%nextcloud-activation)))
(default-value(nextcloud-configuration))
(description
"This service provides the Nextcloud service as an OCI-backed container.")))

The only way where oci-container-service-type could support this use 
case by accepting a single configuration is I guess if multiple 
(service-extension oci-container-service-type ...) where allowed, am I 
understanding correctly? Is it legal in Guix to write somthing like:

(extensions(list(service-extensionoci-container-service-type
make-nextcloud-container) 
(service-extensionoci-container-service-typemake-nextcloud-cron-container) 
(service-extensionaccount-service-type
(const%nextcloud-accounts))
(service-extensionactivation-service-type
%nextcloud-activation)))

> Check out under gnu/tests/*.scm, in particular (gnu tests docker).

Thank you for the pointer, I'll look into those.

giacomo

--------------45oI4y2ozTIpuFiaFffYQiww
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 8bit

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Hello Ludo’ ,<br>
    </p>
    <div class="moz-cite-prefix">On 10/19/23 22:13, Ludovic Courtès
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:874jimz7y5.fsf@HIDDEN">
      <pre class="moz-quote-pre" wrap="">Hello,

paul <a class="moz-txt-link-rfc2396E" href="mailto:goodoldpaul@HIDDEN">&lt;goodoldpaul@HIDDEN&gt;</a> skribis:


[...]

</pre>
      <blockquote type="cite">
        <blockquote type="cite">
          <pre class="moz-quote-pre" wrap="">Does ‘docker run’ necessarily need to run as root, or are there cases
where one might want to run it as non-root?  (I expect the latter.)
</pre>
        </blockquote>
        <pre class="moz-quote-pre" wrap="">
yes you are right, it's only required to be in the docker group or in
general have enough permission to operate on the docker daemon
socket. I added a new service extension setting up an oci-container
user, that it's just in the docker group and can not login, that runs
oci backed services. it is also overridable by the user
</pre>
      </blockquote>
      <pre class="moz-quote-pre" wrap="">
In that case, maybe create an “oci-service” account part of the “docker”
group, and run ‘docker run’ as that user instead of running it as root?
Would that be OK or am I overlooking something?
</pre>
    </blockquote>
    I already added such user in the latest version of my patch. I
    probably made a mess with patch subjects.
    <blockquote type="cite" cite="mid:874jimz7y5.fsf@HIDDEN">
      <pre class="moz-quote-pre" wrap="">What I’m suggesting above is that one would build a list of
‘oci-container-service-type’ instances, like:

  (list (service oci-container-service-type
                 (oci-container-configuration …))
        (service oci-container-service-type
                 (oci-container-configuration …))
        …)

Each instance above would correspond to exactly one program in a Docker
image.

I feel it’s slightly more natural than having a service type that
implements support for multiple OCI services at once.</pre>
    </blockquote>
    I agree it's more natural but (list service-a service-b ...) it's
    the same interface exposed by the shepherd-root-service-type, I
    believe for the same reasons I need the oci-nextcloud-service-type
    to instantiate 3 shepherd services but only create a single account,
    activate a single data dir under /var/lib, something like this:<br>
    <br>
    <pre><span id="LC193" data-testid="content" class="line" lang="scheme"><span class="">(</span><span class="hljs-built_in">define</span><span class=""> </span><span class="">oci-nextcloud-service-type</span><span class=""></span></span>
<span id="LC194" data-testid="content" class="line" lang="scheme"><span class="">  </span><span class="">(</span><span class="hljs-name">service-type</span><span class=""> </span><span class="">(</span><span class="hljs-name">name</span><span class=""> </span><span class="hljs-symbol">'nextcloud</span><span class="">)</span><span class=""></span></span>
<span id="LC195" data-testid="content" class="line" lang="scheme"><span class="">                </span><span class="">(</span><span class="hljs-name">extensions</span><span class=""> </span><span class="">(</span><span class="hljs-built_in">list</span><span class=""> </span><span class="">(</span><span class="hljs-name">service-extension</span><span class=""> </span><span class="">oci-container-service-type</span><span class=""></span></span>
<span id="LC196" data-testid="content" class="line" lang="scheme"><span class="">                                                     (lambda (config)
                                                       (make-nextcloud-container config)
                                                       (make-nextcloud-cron-container config))</span><span class=""></span><span class="">)</span><span class=""></span></span>
<span id="LC197" data-testid="content" class="line" lang="scheme"><span class="">                                  </span><span class="">(</span><span class="hljs-name">service-extension</span><span class=""> </span><span class="">account-service-type</span><span class=""></span></span>
<span id="LC198" data-testid="content" class="line" lang="scheme"><span class="">                                                     </span><span class="">(</span><span class="hljs-name">const</span><span class=""> </span><span class="">%nextcloud-accounts</span><span class="">)</span><span class="">)</span><span class=""></span></span>
<span id="LC199" data-testid="content" class="line" lang="scheme"><span class="">                                  </span><span class="">(</span><span class="hljs-name">service-extension</span><span class=""> </span><span class="">activation-service-type</span><span class=""></span></span>
<span id="LC200" data-testid="content" class="line" lang="scheme"><span class="">                                                     </span><span class="">%nextcloud-activation</span><span class="">)</span><span class="">)</span><span class="">)</span><span class=""></span></span>
<span id="LC201" data-testid="content" class="line" lang="scheme"><span class="">                </span><span class="">(</span><span class="hljs-name">default-value</span><span class=""> </span><span class="">(nextcloud</span><span class="hljs-name">-configuration</span><span class="">)</span><span class="">)</span><span class=""></span></span>
<span id="LC202" data-testid="content" class="line" lang="scheme"><span class="">                </span><span class="">(</span><span class="hljs-name">description</span><span class=""></span></span>
<span id="LC203" data-testid="content" class="line" lang="scheme"><span class="">                 </span><span class="hljs-string">"This service provides the Nextcloud service as an OCI-backed container."</span><span class="">)</span><span class="">)</span><span class="">)</span></span>
</pre>
    <p>The only way where oci-container-service-type could support this
      use case by accepting a single configuration is I guess if
      multiple (service-extension oci-container-service-type ...) where
      allowed, am I understanding correctly? Is it legal in Guix to
      write somthing like:</p>
    <pre><span id="LC195" data-testid="content" class="line" lang="scheme"><span class=""></span><span class="">(</span><span class="hljs-name">extensions</span><span class=""> </span><span class="">(</span><span class="hljs-built_in">list</span><span class=""> </span><span class="">(</span><span class="hljs-name">service-extension</span><span class=""> </span><span class="">oci-container-service-type</span><span class=""></span></span>
<span id="LC196" data-testid="content" class="line" lang="scheme"><span class="">                                     make-nextcloud-container)
                  </span></span><span id="LC196" data-testid="content" class="line" lang="scheme"><span class=""><span id="LC195" data-testid="content" class="line" lang="scheme"><span class="">(</span><span class="hljs-name">service-extension</span><span class=""> </span><span class="">oci-container-service-type</span><span class=""></span></span>
<span id="LC196" data-testid="content" class="line" lang="scheme"><span class="">                                     make-nextcloud-cron-container)</span></span>
                  </span></span><span id="LC197" data-testid="content" class="line" lang="scheme"><span class=""></span><span class="">(</span><span class="hljs-name">service-extension</span><span class=""> </span><span class="">account-service-type</span><span class=""></span></span>
<span id="LC198" data-testid="content" class="line" lang="scheme"><span class="">                                     </span><span class="">(</span><span class="hljs-name">const</span><span class=""> </span><span class="">%nextcloud-accounts</span><span class="">)</span><span class="">)</span><span class=""></span></span>
<span id="LC199" data-testid="content" class="line" lang="scheme"><span class="">                  </span><span class="">(</span><span class="hljs-name">service-extension</span><span class=""> </span><span class="">activation-service-type</span><span class=""></span></span>
<span id="LC200" data-testid="content" class="line" lang="scheme"><span class="">                                     </span><span class="">%nextcloud-activation</span><span class="">)</span><span class="">)</span><span class="">)</span><span class=""></span></span>

</pre>
    <blockquote type="cite" cite="mid:874jimz7y5.fsf@HIDDEN">
      <pre class="moz-quote-pre" wrap="">Check out under gnu/tests/*.scm, in particular (gnu tests docker).
</pre>
    </blockquote>
    <p>Thank you for the pointer, I'll look into those.</p>
    <p>giacomo<br>
    </p>
  </body>
</html>

--------------45oI4y2ozTIpuFiaFffYQiww--




Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 19 Oct 2023 20:14:33 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Oct 19 16:14:33 2023
Received: from localhost ([127.0.0.1]:37910 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qtZPd-00067t-2U
	for submit <at> debbugs.gnu.org; Thu, 19 Oct 2023 16:14:33 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:40950)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <ludo@HIDDEN>) id 1qtZPa-00067c-3E
 for 66160 <at> debbugs.gnu.org; Thu, 19 Oct 2023 16:14:31 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1qtZP3-00063w-NW; Thu, 19 Oct 2023 16:13:57 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=65+oMwCm5msCzVqmiZQkV1VW+HFQ0L2a0yYHreMm3+E=; b=naLBsSMWL4x/RuiWcBFL
 l0+5SqGw8a07UQOhYSs91H2iAPSA/mi2llcecBSASxGL4c2Cx88/Ic6NNgdlDLv4AlvmZxtS3K8M8
 ma+SEmrKUJVth/sUV7Gs5yXPeR3ANz7TWTU5PjXJUkmpjRth6kQSqf8s088jIi+Zf/ftHi9LdSMKZ
 O6VwatHZbcn4OTcmtWEdixS/VPaXYbTszMT36AibLCly+gXuDornv4D4okVBIrNvfvFGdbkCl67Sq
 OHTKiztkmeR/1xptR+B1CtH81rEV0/SecAHaJ9rCNWEd35JLOYlXMmNpJ/IM/3FYyfUy9xBZfEQWF
 GqqolKxsoGTpPg==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: paul <goodoldpaul@HIDDEN>
Subject: Re: [bug#66160] [PATCH] gnu: Add oci-container-service-type.
In-Reply-To: <604138b9-a567-68eb-82fe-d205390636e7@HIDDEN> (paul's
 message of "Sat, 14 Oct 2023 23:29:59 +0200")
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <8b8a0eed3b02cfd2edb94859da83032c96ee5616.1696619356.git.goodoldpaul@HIDDEN>
 <875y39fao8.fsf@HIDDEN>
 <604138b9-a567-68eb-82fe-d205390636e7@HIDDEN>
Date: Thu, 19 Oct 2023 22:13:54 +0200
Message-ID: <874jimz7y5.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hello,

paul <goodoldpaul@HIDDEN> skribis:


[...]

>> Does =E2=80=98docker run=E2=80=99 necessarily need to run as root, or ar=
e there cases
>> where one might want to run it as non-root?  (I expect the latter.)
>
> yes you are right, it's only required to be in the docker group or in
> general have enough permission to operate on the docker daemon
> socket. I added a new service extension setting up an oci-container
> user, that it's just in the docker group and can not login, that runs
> oci backed services. it is also overridable by the user

In that case, maybe create an =E2=80=9Coci-service=E2=80=9D account part of=
 the =E2=80=9Cdocker=E2=80=9D
group, and run =E2=80=98docker run=E2=80=99 as that user instead of running=
 it as root?
Would that be OK or am I overlooking something?

>>> +(define oci-container-service-type
>>> +  (service-type (name 'oci-container)
>>> +                (extensions (list (service-extension profile-service-t=
ype
>>> +                                                     (lambda _ (list d=
ocker-cli)))
>>> +                                  (service-extension shepherd-root-ser=
vice-type
>>> +                                                     configs->shepherd=
-services)))
>>> +                (default-value '())
>> I wonder if it should take a list of configs and be extensible, or
>> simply take a single config.  Users would write:
>>
>>    (service oci-container-service-type
>>             (oci-container-configuration =E2=80=A6))
>>
>> WDYT?

[...]

> Right now we can already do:
>
> (service oci-container-service-type
>            (list
>              (oci-container-configuration =E2=80=A6)))
>
> and i updated the documentation accordingly. do you have any
> suggestion for changing the api of oci-container-configuration to
> support having different shepherd oci backed services behind a guix
> system service? This way we could remove the (list) call.

What I=E2=80=99m suggesting above is that one would build a list of
=E2=80=98oci-container-service-type=E2=80=99 instances, like:

  (list (service oci-container-service-type
                 (oci-container-configuration =E2=80=A6))
        (service oci-container-service-type
                 (oci-container-configuration =E2=80=A6))
        =E2=80=A6)

Each instance above would correspond to exactly one program in a Docker
image.

I feel it=E2=80=99s slightly more natural than having a service type that
implements support for multiple OCI services at once.

> I actually looked around but didn't find them, but it was a long time
> ago and I certainly didn't look very well. I'm definitely up for
> testing this (maybe it's possible to use swineherd? could we use it
> for automating integration tests?), could you point me to something
> similar i can look to as an example?

Check out under gnu/tests/*.scm, in particular (gnu tests docker).

HTH!

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 14 Oct 2023 21:49:11 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Oct 14 17:49:11 2023
Received: from localhost ([127.0.0.1]:50764 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qrmVS-0006SJ-7r
	for submit <at> debbugs.gnu.org; Sat, 14 Oct 2023 17:49:11 -0400
Received: from confino.investici.org ([93.190.126.19]:46049)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qrmVO-0006Rx-Rj
 for 66160 <at> debbugs.gnu.org; Sat, 14 Oct 2023 17:49:08 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4S7H7Y3jqLz112T;
 Sat, 14 Oct 2023 21:48:41 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1697320121;
 bh=MbUCsVOspa/cqr8U6LZqsWF6Mm7O3F6b5C294RWArpE=;
 h=From:To:Cc:Subject:Date:From;
 b=gQpUjmBOXDe0P/Yd+5zRThzGVytHkr1IhV8fP0/Oswa+rIUPAnBD89G+TVcSx5xaC
 Xk4KJv9+Fw4f5scMK6LOqxLeNS0JzurpFGDS7W1La/n4tsYlZQ7FOWyfDUyIAFjCuN
 vqzlHXPUavNrF72WYxY0EQbvokEIeWgxuiWEDqaM=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4S7H7Y36qtz1111; Sat, 14 Oct 2023 21:48:41 +0000 (UTC)
From: Giacomo Leidi <goodoldpaul@HIDDEN>
To: 66160 <at> debbugs.gnu.org@HIDDEN
Subject: [PATCH] gnu: Add oci-container-service-type.
Date: Sat, 14 Oct 2023 23:47:56 +0200
Message-ID: <f3d8c164b63af53128074d7dcbf91e8a7a73180c.1697320076.git.goodoldpaul@HIDDEN>
X-Mailer: git-send-email 2.41.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 66160
Cc: Giacomo Leidi <goodoldpaul@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

* gnu/services/docker.scm (oci-container-configuration): New variable;
(oci-container-shepherd-service): new variable;
(oci-container-service-type): new variable.
* doc/guix.texi: Document it.
---
 doc/guix.texi           | 120 ++++++++++++++++++++
 gnu/services/docker.scm | 237 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 356 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 083504dcb8..6de46a1ebe 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -39534,6 +39534,126 @@ Miscellaneous Services
 @command{singularity run} and similar commands.
 @end defvar
 
+@cindex OCI-backed, Shepherd services
+@subsubheading OCI backed services
+
+Should you wish to manage your Docker containers with the same consistent
+interface you use for your other Shepherd services,
+@var{oci-container-service-type} is the tool to use: given an
+@acronym{Open Container Initiative, OCI} container image, it will run it in a
+Shepherd service.  One example where this is useful: it lets you run services
+that are available as Docker/OCI images but not yet packaged for Guix.
+
+@defvar oci-container-service-type
+
+This is a thin wrapper around Docker's CLI that executes OCI images backed
+processes as Shepherd Services.
+
+@lisp
+(service oci-container-service-type
+         (list
+          (oci-container-configuration
+           (image "prom/prometheus")
+           (network "host")
+           (ports
+             '(("9000" . "9000")
+               ("9090" . "9090"))))
+          (oci-container-configuration
+           (image "grafana/grafana:10.0.1")
+           (network "host")
+           (ports
+             '(("3000" . "3000")))
+           (volumes
+             '("/var/lib/grafana:/var/lib/grafana")))))
+@end lisp
+
+In this example two different Shepherd services are going be added to the
+system.  Each @code{oci-container-configuration} record translates to a
+@code{docker run} invocation and its fields directly map to options.  You can
+refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run,upstream},
+documentation for the semantics of each value.  If the images are not found they
+will be
+@url{https://docs.docker.com/engine/reference/commandline/pull/,pulled}.  The
+spawned services are going to be attached to the host network and are supposed
+to behave like other processes.
+
+@end defvar
+
+@c %start of fragment
+
+@deftp {Data Type} oci-container-configuration
+Available @code{oci-container-configuration} fields are:
+
+@table @asis
+@item @code{user} (default: @code{"oci-container"}) (type: string)
+The user under whose authority docker commands will be run.
+
+@item @code{group} (default: @code{"docker"}) (type: string)
+The group under whose authority docker commands will be run.
+
+@item @code{command} (default: @code{()}) (type: list-of-strings)
+Overwrite the default command (@code{CMD}) of the image.
+
+@item @code{entrypoint} (default: @code{""}) (type: string)
+Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.
+
+@item @code{environment} (default: @code{()}) (type: list)
+Set environment variables. This can be a list of pairs or strings, even mixed:
+
+@lisp
+(list '("LANGUAGE" . "eo:ca:eu")
+      "JAVA_HOME=/opt/java")
+@end lisp
+
+String are passed directly to the Docker CLI. You can refer to the
+@uref{https://docs.docker.com/engine/reference/commandline/run/#env,upstream}
+documentation for semantics.
+
+@item @code{image} (type: string)
+The image used to build the container.  Images are resolved by the
+Docker Engine, and follow the usual format
+@code{myregistry.local:5000/testing/test-image:tag}.
+
+@item @code{name} (default: @code{""}) (type: string)
+Set a name for the spawned container.
+
+@item @code{network} (default: @code{""}) (type: string)
+Set a Docker network for the spawned container.
+
+@item @code{ports} (default: @code{()}) (type: list)
+Set the port or port ranges to expose from the spawned container.  This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("8080" . "80")
+      "10443:443")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@uref{https://docs.docker.com/engine/reference/commandline/run/#publish,upstream}
+documentation for semantics.
+
+@item @code{volumes} (default: @code{()}) (type: list)
+Set volume mappings for the spawned container.  This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("/root/data/grafana" . "/var/lib/grafana")
+      "/gnu/store:/gnu/store")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@uref{https://docs.docker.com/engine/reference/commandline/run/#volume,upstream}
+documentation for semantics.
+
+@end table
+
+@end deftp
+
+
+@c %end of fragment
+
 @cindex Audit
 @subsubheading Auditd Service
 
diff --git a/gnu/services/docker.scm b/gnu/services/docker.scm
index c2023d618c..2d709bf2ce 100644
--- a/gnu/services/docker.scm
+++ b/gnu/services/docker.scm
@@ -5,6 +5,7 @@
 ;;; Copyright © 2020 Efraim Flashner <efraim@HIDDEN>
 ;;; Copyright © 2020 Jesse Dowell <jessedowell@HIDDEN>
 ;;; Copyright © 2021 Brice Waegeneire <brice@HIDDEN>
+;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -29,15 +30,34 @@ (define-module (gnu services docker)
   #:use-module (gnu services shepherd)
   #:use-module (gnu system setuid)
   #:use-module (gnu system shadow)
+  #:use-module (gnu packages admin)               ;shadow
   #:use-module (gnu packages docker)
   #:use-module (gnu packages linux)               ;singularity
   #:use-module (guix records)
+  #:use-module (guix diagnostics)
   #:use-module (guix gexp)
+  #:use-module (guix i18n)
   #:use-module (guix packages)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
 
   #:export (docker-configuration
             docker-service-type
-            singularity-service-type))
+            singularity-service-type
+            oci-container-configuration
+            oci-container-configuration?
+            oci-container-configuration-fields
+            oci-container-configuration-command
+            oci-container-configuration-entrypoint
+            oci-container-configuration-environment
+            oci-container-configuration-image
+            oci-container-configuration-name
+            oci-container-configuration-network
+            oci-container-configuration-ports
+            oci-container-configuration-volumes
+            oci-container-service-type
+            oci-container-shepherd-service))
 
 (define-configuration docker-configuration
   (docker
@@ -216,3 +236,218 @@ (define singularity-service-type
                        (service-extension activation-service-type
                                           (const %singularity-activation))))
                 (default-value singularity)))
+
+
+;;;
+;;; OCI container.
+;;;
+
+(define (oci-sanitize-pair pair delimiter)
+  (define (valid? member)
+    (or (string? member)
+        (gexp? member)
+        (file-like? member)))
+  (match pair
+    (((? valid? key) . (? valid? value))
+     #~(string-append #$key #$delimiter #$value))
+    (_
+     (raise
+      (formatted-message
+       (G_ "pair members must contain only strings, gexps or file-like objects
+but ~a was found")
+       pair)))))
+
+(define (oci-sanitize-mixed-list name value delimiter)
+  (map
+   (lambda (el)
+     (cond ((string? el) el)
+           ((pair? el) (oci-sanitize-pair el delimiter))
+           (else
+            (raise
+             (formatted-message
+              (G_ "~a members must be either a string or a pair but ~a was
+found!")
+              name el)))))
+   value))
+
+(define (oci-sanitize-environment value)
+  ;; Expected spec format:
+  ;; '(("HOME" . "/home/nobody") "JAVA_HOME=/java")
+  (oci-sanitize-mixed-list "environment" value "="))
+
+(define (oci-sanitize-ports value)
+  ;; Expected spec format:
+  ;; '(("8088" . "80") "2022:22")
+  (oci-sanitize-mixed-list "ports" value ":"))
+
+(define (oci-sanitize-volumes value)
+  ;; Expected spec format:
+  ;; '(("/mnt/dir" . "/dir") "/run/current-system/profile:/java")
+  (oci-sanitize-mixed-list "volumes" value ":"))
+
+(define-maybe/no-serialization string)
+
+(define-configuration/no-serialization oci-container-configuration
+  (user
+   (string "oci-container")
+   "The user under whose authority docker commands will be run.")
+  (group
+   (string "docker")
+   "The group under whose authority docker commands will be run.")
+  (command
+   (list-of-strings '())
+   "Overwrite the default command (@code{CMD}) of the image.")
+  (entrypoint
+   (maybe-string)
+   "Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.")
+  (environment
+   (list '())
+   "Set environment variables.  This can be a list of pairs or strings, even
+mixed:
+
+@lisp
+(list '(\"LANGUAGE\" . \"eo:ca:eu\")
+      \"JAVA_HOME=/opt/java\")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#env,upstream}
+documentation for semantics."
+   (sanitizer oci-sanitize-environment))
+  (image
+   (string)
+   "The image used to build the container.  Images are resolved by the Docker
+Engine, and follow the usual format
+@code{myregistry.local:5000/testing/test-image:tag}.")
+  (name
+   (maybe-string)
+   "Set a name for the spawned container.")
+  (network
+   (maybe-string)
+   "Set a Docker network for the spawned container.")
+  (ports
+   (list '())
+   "Set the port or port ranges to expose from the spawned container.  This can
+be a list of pairs or strings, even mixed:
+
+@lisp
+(list '(\"8080\" . \"80\")
+      \"10443:443\")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#publish,upstream}
+documentation for semantics."
+   (sanitizer oci-sanitize-ports))
+  (volumes
+   (list '())
+   "Set volume mappings for the spawned container.  This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '(\"/root/data/grafana\" . \"/var/lib/grafana\")
+      \"/gnu/store:/gnu/store\")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#volume,upstream}
+documentation for semantics."
+   (sanitizer oci-sanitize-volumes)))
+
+(define oci-container-configuration->options
+  (lambda (config)
+    (let ((entrypoint
+           (oci-container-configuration-entrypoint config))
+          (network
+           (oci-container-configuration-network config)))
+      (apply append
+             (filter (compose not unspecified?)
+                     `(,(if (maybe-value-set? entrypoint)
+                            `("--entrypoint" ,entrypoint)
+                            '())
+                       ,(append-map
+                         (lambda (spec)
+                           (list "--env" spec))
+                         (oci-container-configuration-environment config))
+                       ,(if (maybe-value-set? network)
+                            `("--network" ,network)
+                            '())
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-p" spec))
+                         (oci-container-configuration-ports config))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-v" spec))
+                         (oci-container-configuration-volumes config))))))))
+
+(define (oci-container-shepherd-service config)
+  (define (guess-name name image)
+    (if (maybe-value-set? name)
+        name
+        (string-append "docker-"
+                       (basename (car (string-split image #\:))))))
+
+  (let* ((docker-command (file-append docker-cli "/bin/docker"))
+         (user (oci-container-configuration-user config))
+         (group (oci-container-configuration-group config))
+         (command (oci-container-configuration-command config))
+         (config-name (oci-container-configuration-name config))
+         (image (oci-container-configuration-image config))
+         (options (oci-container-configuration->options config))
+         (name (guess-name config-name image)))
+
+    (shepherd-service (provision `(,(string->symbol name)))
+                      (requirement '(dockerd user-processes))
+                      (respawn? #f)
+                      (documentation
+                       (string-append
+                        "Docker backed Shepherd service for image: " image))
+                      (start
+                       #~(make-forkexec-constructor
+                          ;; docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
+                          (list #$docker-command "run" "--rm"
+                                "--name" #$name
+                                #$@options #$image #$@command)
+                          #:user #$user
+                          #:group #$group))
+                      (stop
+                       #~(lambda _
+                           (invoke #$docker-command "rm" "-f" #$name)))
+                      (actions
+                       (list
+                        (shepherd-action
+                         (name 'pull)
+                         (documentation
+                          (format #f "Pull ~a's image (~a)."
+                                  name image))
+                         (procedure
+                          #~(lambda _
+                              (invoke #$docker-command "pull" #$image)))))))))
+
+(define %oci-container-accounts
+  (list (user-account
+         (name "oci-container")
+         (comment "OCI services account")
+         (group "docker")
+         (system? #t)
+         (home-directory "/var/empty")
+         (shell (file-append shadow "/sbin/nologin")))))
+
+(define (configs->shepherd-services configs)
+  (map oci-container-shepherd-service configs))
+
+(define oci-container-service-type
+  (service-type (name 'oci-container)
+                (extensions (list (service-extension profile-service-type
+                                                     (lambda _ (list docker-cli)))
+                                  (service-extension account-service-type
+                                                     (const %oci-container-accounts))
+                                  (service-extension shepherd-root-service-type
+                                                     configs->shepherd-services)))
+                (default-value '())
+                (extend append)
+                (compose concatenate)
+                (description
+                 "This service allows the management of Docker and OCI
+containers as Shepherd services.")))

base-commit: 8aad7210ea06992ee3f36ca7f57678240949e063
-- 
2.41.0





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 14 Oct 2023 21:37:18 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Oct 14 17:37:18 2023
Received: from localhost ([127.0.0.1]:50760 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qrmJx-0005vK-AB
	for submit <at> debbugs.gnu.org; Sat, 14 Oct 2023 17:37:18 -0400
Received: from confino.investici.org ([93.190.126.19]:23381)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qrmJu-0005vB-Ie
 for 66160 <at> debbugs.gnu.org; Sat, 14 Oct 2023 17:37:16 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4S7Gss1R6xz112P;
 Sat, 14 Oct 2023 21:36:49 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1697319409;
 bh=SNhrLOp4rcsZ23W9XxBGRJjHILYPtJxp0yxV4pSQVsg=;
 h=From:To:Cc:Subject:Date:From;
 b=PFuhxJrgdygRmhHkynjHq/Hfmuh50gJ0ImcNgSph03Ge2IT4Kf02KoavC5Y6YolpO
 JhlFxfdjyuOlZKWTWg1AqqYXZP1G0b0U/KTbbFc0Nu5NlqQX5Z6MHUkLSdsOplt+GM
 uTmH0Kn2pNotZc7r5K12ppNI+cib2uOH9NdHHimk=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4S7Gss0q91z10yD; Sat, 14 Oct 2023 21:36:48 +0000 (UTC)
From: Giacomo Leidi <goodoldpaul@HIDDEN>
To: 66160 <at> debbugs.gnu.org@HIDDEN
Subject: [PATCH] gnu: Add oci-container-service-type.
Date: Sat, 14 Oct 2023 23:36:12 +0200
Message-ID: <c37c207d617d927f1978deccb70a8f8809a82de6.1697319372.git.goodoldpaul@HIDDEN>
X-Mailer: git-send-email 2.41.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 66160
Cc: Giacomo Leidi <goodoldpaul@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

* gnu/services/docker.scm (oci-container-configuration): New variable;
(oci-container-shepherd-service): new variable;
(oci-container-service-type): new variable.
* doc/guix.texi: Document it.
---
 doc/guix.texi           | 123 +++++++++++++++++++++
 gnu/services/docker.scm | 237 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 359 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 083504dcb8..54d5074bd7 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -39534,6 +39534,129 @@ Miscellaneous Services
 @command{singularity run} and similar commands.
 @end defvar
 
+@cindex OCI-backed, Shepherd services
+@subsubheading OCI backed services
+
+Should you wish to manage your Docker containers with the same consistent
+interface you use for your other Shepherd services,
+@var{oci-container-service-type} is the tool to use: given an
+@acronym{Open Container Initiative, OCI} container image, it will run it in a
+Shepherd service.  One example where this is useful: it lets you run services
+that are available as Docker/OCI images but not yet packaged for Guix.
+
+@defvar oci-container-service-type
+
+This is a thin wrapper around Docker's CLI that executes OCI images backed
+processes as Shepherd Services.
+
+@lisp
+(service oci-container-service-type
+         (list
+          (oci-container-configuration
+           (image "prom/prometheus")
+           (network "host")
+           (ports
+             '(("9000" . "9000")
+               ("9090" . "9090"))))))
+
+(service oci-container-service-type
+         (list
+          (oci-container-configuration
+           (image "grafana/grafana:10.0.1")
+           (network "host")
+           (ports
+             '(("3000" . "3000")))
+           (volumes
+             '("/var/lib/grafana:/var/lib/grafana"))))))
+@end lisp
+
+In this example two different Shepherd services are going be added to the
+system.  Each @code{oci-container-configuration} record translates to a
+@code{docker run} invocation and its fields directly map to options.  You can
+refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run,upstream},
+documentation for the semantics of each value.  If the images are not found they
+will be
+@url{https://docs.docker.com/engine/reference/commandline/pull/,pulled}.  The
+spawned services are going to be attached to the host network and are supposed
+to behave like other processes.
+
+@end defvar
+
+@c %start of fragment
+
+@deftp {Data Type} oci-container-configuration
+Available @code{oci-container-configuration} fields are:
+
+@table @asis
+@item @code{user} (default: @code{"oci-container"}) (type: string)
+The user under whose authority docker commands will be run.
+
+@item @code{group} (default: @code{"docker"}) (type: string)
+The group under whose authority docker commands will be run.
+
+@item @code{command} (default: @code{()}) (type: list-of-strings)
+Overwrite the default command (@code{CMD}) of the image.
+
+@item @code{entrypoint} (default: @code{""}) (type: string)
+Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.
+
+@item @code{environment} (default: @code{()}) (type: list)
+Set environment variables. This can be a list of pairs or strings, even mixed:
+
+@lisp
+(list '("LANGUAGE" . "eo:ca:eu")
+      "JAVA_HOME=/opt/java")
+@end lisp
+
+String are passed directly to the Docker CLI. You can refer to the
+@uref{https://docs.docker.com/engine/reference/commandline/run/#env,upstream}
+documentation for semantics.
+
+@item @code{image} (type: string)
+The image used to build the container.  Images are resolved by the
+Docker Engine, and follow the usual format
+@code{myregistry.local:5000/testing/test-image:tag}.
+
+@item @code{name} (default: @code{""}) (type: string)
+Set a name for the spawned container.
+
+@item @code{network} (default: @code{""}) (type: string)
+Set a Docker network for the spawned container.
+
+@item @code{ports} (default: @code{()}) (type: list)
+Set the port or port ranges to expose from the spawned container.  This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("8080" . "80")
+      "10443:443")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@uref{https://docs.docker.com/engine/reference/commandline/run/#publish,upstream}
+documentation for semantics.
+
+@item @code{volumes} (default: @code{()}) (type: list)
+Set volume mappings for the spawned container.  This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("/root/data/grafana" . "/var/lib/grafana")
+      "/gnu/store:/gnu/store")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@uref{https://docs.docker.com/engine/reference/commandline/run/#volume,upstream}
+documentation for semantics.
+
+@end table
+
+@end deftp
+
+
+@c %end of fragment
+
 @cindex Audit
 @subsubheading Auditd Service
 
diff --git a/gnu/services/docker.scm b/gnu/services/docker.scm
index c2023d618c..2d709bf2ce 100644
--- a/gnu/services/docker.scm
+++ b/gnu/services/docker.scm
@@ -5,6 +5,7 @@
 ;;; Copyright © 2020 Efraim Flashner <efraim@HIDDEN>
 ;;; Copyright © 2020 Jesse Dowell <jessedowell@HIDDEN>
 ;;; Copyright © 2021 Brice Waegeneire <brice@HIDDEN>
+;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -29,15 +30,34 @@ (define-module (gnu services docker)
   #:use-module (gnu services shepherd)
   #:use-module (gnu system setuid)
   #:use-module (gnu system shadow)
+  #:use-module (gnu packages admin)               ;shadow
   #:use-module (gnu packages docker)
   #:use-module (gnu packages linux)               ;singularity
   #:use-module (guix records)
+  #:use-module (guix diagnostics)
   #:use-module (guix gexp)
+  #:use-module (guix i18n)
   #:use-module (guix packages)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
 
   #:export (docker-configuration
             docker-service-type
-            singularity-service-type))
+            singularity-service-type
+            oci-container-configuration
+            oci-container-configuration?
+            oci-container-configuration-fields
+            oci-container-configuration-command
+            oci-container-configuration-entrypoint
+            oci-container-configuration-environment
+            oci-container-configuration-image
+            oci-container-configuration-name
+            oci-container-configuration-network
+            oci-container-configuration-ports
+            oci-container-configuration-volumes
+            oci-container-service-type
+            oci-container-shepherd-service))
 
 (define-configuration docker-configuration
   (docker
@@ -216,3 +236,218 @@ (define singularity-service-type
                        (service-extension activation-service-type
                                           (const %singularity-activation))))
                 (default-value singularity)))
+
+
+;;;
+;;; OCI container.
+;;;
+
+(define (oci-sanitize-pair pair delimiter)
+  (define (valid? member)
+    (or (string? member)
+        (gexp? member)
+        (file-like? member)))
+  (match pair
+    (((? valid? key) . (? valid? value))
+     #~(string-append #$key #$delimiter #$value))
+    (_
+     (raise
+      (formatted-message
+       (G_ "pair members must contain only strings, gexps or file-like objects
+but ~a was found")
+       pair)))))
+
+(define (oci-sanitize-mixed-list name value delimiter)
+  (map
+   (lambda (el)
+     (cond ((string? el) el)
+           ((pair? el) (oci-sanitize-pair el delimiter))
+           (else
+            (raise
+             (formatted-message
+              (G_ "~a members must be either a string or a pair but ~a was
+found!")
+              name el)))))
+   value))
+
+(define (oci-sanitize-environment value)
+  ;; Expected spec format:
+  ;; '(("HOME" . "/home/nobody") "JAVA_HOME=/java")
+  (oci-sanitize-mixed-list "environment" value "="))
+
+(define (oci-sanitize-ports value)
+  ;; Expected spec format:
+  ;; '(("8088" . "80") "2022:22")
+  (oci-sanitize-mixed-list "ports" value ":"))
+
+(define (oci-sanitize-volumes value)
+  ;; Expected spec format:
+  ;; '(("/mnt/dir" . "/dir") "/run/current-system/profile:/java")
+  (oci-sanitize-mixed-list "volumes" value ":"))
+
+(define-maybe/no-serialization string)
+
+(define-configuration/no-serialization oci-container-configuration
+  (user
+   (string "oci-container")
+   "The user under whose authority docker commands will be run.")
+  (group
+   (string "docker")
+   "The group under whose authority docker commands will be run.")
+  (command
+   (list-of-strings '())
+   "Overwrite the default command (@code{CMD}) of the image.")
+  (entrypoint
+   (maybe-string)
+   "Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.")
+  (environment
+   (list '())
+   "Set environment variables.  This can be a list of pairs or strings, even
+mixed:
+
+@lisp
+(list '(\"LANGUAGE\" . \"eo:ca:eu\")
+      \"JAVA_HOME=/opt/java\")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#env,upstream}
+documentation for semantics."
+   (sanitizer oci-sanitize-environment))
+  (image
+   (string)
+   "The image used to build the container.  Images are resolved by the Docker
+Engine, and follow the usual format
+@code{myregistry.local:5000/testing/test-image:tag}.")
+  (name
+   (maybe-string)
+   "Set a name for the spawned container.")
+  (network
+   (maybe-string)
+   "Set a Docker network for the spawned container.")
+  (ports
+   (list '())
+   "Set the port or port ranges to expose from the spawned container.  This can
+be a list of pairs or strings, even mixed:
+
+@lisp
+(list '(\"8080\" . \"80\")
+      \"10443:443\")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#publish,upstream}
+documentation for semantics."
+   (sanitizer oci-sanitize-ports))
+  (volumes
+   (list '())
+   "Set volume mappings for the spawned container.  This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '(\"/root/data/grafana\" . \"/var/lib/grafana\")
+      \"/gnu/store:/gnu/store\")
+@end lisp
+
+String are passed directly to the Docker CLI.  You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#volume,upstream}
+documentation for semantics."
+   (sanitizer oci-sanitize-volumes)))
+
+(define oci-container-configuration->options
+  (lambda (config)
+    (let ((entrypoint
+           (oci-container-configuration-entrypoint config))
+          (network
+           (oci-container-configuration-network config)))
+      (apply append
+             (filter (compose not unspecified?)
+                     `(,(if (maybe-value-set? entrypoint)
+                            `("--entrypoint" ,entrypoint)
+                            '())
+                       ,(append-map
+                         (lambda (spec)
+                           (list "--env" spec))
+                         (oci-container-configuration-environment config))
+                       ,(if (maybe-value-set? network)
+                            `("--network" ,network)
+                            '())
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-p" spec))
+                         (oci-container-configuration-ports config))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-v" spec))
+                         (oci-container-configuration-volumes config))))))))
+
+(define (oci-container-shepherd-service config)
+  (define (guess-name name image)
+    (if (maybe-value-set? name)
+        name
+        (string-append "docker-"
+                       (basename (car (string-split image #\:))))))
+
+  (let* ((docker-command (file-append docker-cli "/bin/docker"))
+         (user (oci-container-configuration-user config))
+         (group (oci-container-configuration-group config))
+         (command (oci-container-configuration-command config))
+         (config-name (oci-container-configuration-name config))
+         (image (oci-container-configuration-image config))
+         (options (oci-container-configuration->options config))
+         (name (guess-name config-name image)))
+
+    (shepherd-service (provision `(,(string->symbol name)))
+                      (requirement '(dockerd user-processes))
+                      (respawn? #f)
+                      (documentation
+                       (string-append
+                        "Docker backed Shepherd service for image: " image))
+                      (start
+                       #~(make-forkexec-constructor
+                          ;; docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
+                          (list #$docker-command "run" "--rm"
+                                "--name" #$name
+                                #$@options #$image #$@command)
+                          #:user #$user
+                          #:group #$group))
+                      (stop
+                       #~(lambda _
+                           (invoke #$docker-command "rm" "-f" #$name)))
+                      (actions
+                       (list
+                        (shepherd-action
+                         (name 'pull)
+                         (documentation
+                          (format #f "Pull ~a's image (~a)."
+                                  name image))
+                         (procedure
+                          #~(lambda _
+                              (invoke #$docker-command "pull" #$image)))))))))
+
+(define %oci-container-accounts
+  (list (user-account
+         (name "oci-container")
+         (comment "OCI services account")
+         (group "docker")
+         (system? #t)
+         (home-directory "/var/empty")
+         (shell (file-append shadow "/sbin/nologin")))))
+
+(define (configs->shepherd-services configs)
+  (map oci-container-shepherd-service configs))
+
+(define oci-container-service-type
+  (service-type (name 'oci-container)
+                (extensions (list (service-extension profile-service-type
+                                                     (lambda _ (list docker-cli)))
+                                  (service-extension account-service-type
+                                                     (const %oci-container-accounts))
+                                  (service-extension shepherd-root-service-type
+                                                     configs->shepherd-services)))
+                (default-value '())
+                (extend append)
+                (compose concatenate)
+                (description
+                 "This service allows the management of Docker and OCI
+containers as Shepherd services.")))

base-commit: 8aad7210ea06992ee3f36ca7f57678240949e063
-- 
2.41.0





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 14 Oct 2023 21:30:31 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Oct 14 17:30:31 2023
Received: from localhost ([127.0.0.1]:50752 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qrmDO-0005jP-SX
	for submit <at> debbugs.gnu.org; Sat, 14 Oct 2023 17:30:31 -0400
Received: from confino.investici.org ([2a11:7980:1::2:0]:22799)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qrmDK-0005j4-QA
 for 66160 <at> debbugs.gnu.org; Sat, 14 Oct 2023 17:30:28 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4S7Gk005pHz112P;
 Sat, 14 Oct 2023 21:30:00 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1697319000;
 bh=DzK9usJyXiyn+szmKqVwzCIOHWTwdV49vy1xpQSwHps=;
 h=Date:Subject:To:Cc:References:From:In-Reply-To:From;
 b=Hfluur7ny2+YgOh9WqtShoLvoNuQ91G4QcqQVGrK7k4mx80dqw06zgHFAGmPEEjdF
 nrBTZ7PsraXiL5UnA9fIoeyRpD7+XdbI6DfldCIGc6G9GQRJhSbfMHajGADuZjHDid
 fBDm/SZDbiyWic2n/8Kr0/U+ErmTS/WfiH1COfTM=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4S7Gjz6hxTz10yP; Sat, 14 Oct 2023 21:29:59 +0000 (UTC)
Message-ID: <604138b9-a567-68eb-82fe-d205390636e7@HIDDEN>
Date: Sat, 14 Oct 2023 23:29:59 +0200
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.15.0
Subject: Re: [bug#66160] [PATCH] gnu: Add oci-container-service-type.
To: =?UTF-8?Q?Ludovic_Court=c3=a8s?= <ludo@HIDDEN>
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <8b8a0eed3b02cfd2edb94859da83032c96ee5616.1696619356.git.goodoldpaul@HIDDEN>
 <875y39fao8.fsf@HIDDEN>
Content-Language: en-US
From: paul <goodoldpaul@HIDDEN>
In-Reply-To: <875y39fao8.fsf@HIDDEN>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.5 (-)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.5 (--)

Hi Ludo’ ,


> We’re almost there!  There’s a couple of things I overlooked before (my
> apologies), so here we go:
Thank you for your help and the time you spent reviewing this!
>> +@table @asis
>> +@item @code{command} (default: @code{()}) (type: list-of-strings)
>> +Overwrite the default command (@code{CMD}) of the image.
>> +
>> +@item @code{entrypoint} (default: @code{""}) (type: string)
>> +Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.
> Apparently this doesn’t match the docstring that’s in
> ‘define-configuration’.
>
> Could you make sure the docstring is the canonical source?  Then you can
> use ‘generate-documentation’ to generate the bit that you’ll paste in
> guix.texi (info "(guix) Complex Configurations").
I should have aligned the code and documentation.
>
>> +  (entrypoint
>> +   (string "")
>> +   "Overwrite the default ENTRYPOINT of the image.")
>> +  (environment
>> +   (list '())
>> +   "Set environment variables."
>> +   (sanitizer oci-sanitize-environment))
>> +  (image
>> +   (string)
>> +   "The image used to build the container.")
>> +  (name
>> +   (string "")
>> +   "Set a name for the spawned container.")
> Please use ‘maybe-string’ in cases where it’s either the Docker default
> (default ENTRYPOINT, default CMD, etc.) or some user-provided value.
> I find it clearer or at least more conventional than using the empty
> string to denote default values.
I don't know why I didn't do it in the first place, thank you. fixed
>> +                       #~(make-forkexec-constructor
>> +                          ;; docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
>> +                          (list #$docker-command
>> +                                "run"
>> +                                "--rm"
>> +                                "--name" #$name
>> +                                #$@(oci-container-configuration->options config)
>> +                                #$(oci-container-configuration-image config)
>> +                                #$@(oci-container-configuration-command config))
>> +                          #:user "root"
>> +                          #:group "root"))
> Does ‘docker run’ necessarily need to run as root, or are there cases
> where one might want to run it as non-root?  (I expect the latter.)

yes you are right, it's only required to be in the docker group or in 
general have enough permission to operate on the docker daemon socket. I 
added a new service extension setting up an oci-container user, that 
it's just in the docker group and can not login, that runs oci backed 
services. it is also overridable by the user


>
>> +(define oci-container-service-type
>> +  (service-type (name 'oci-container)
>> +                (extensions (list (service-extension profile-service-type
>> +                                                     (lambda _ (list docker-cli)))
>> +                                  (service-extension shepherd-root-service-type
>> +                                                     configs->shepherd-services)))
>> +                (default-value '())
> I wonder if it should take a list of configs and be extensible, or
> simply take a single config.  Users would write:
>
>    (service oci-container-service-type
>             (oci-container-configuration …))
>
> WDYT?

I get that it's not super consistent with other services but for example 
Nextcloud in some case require 3 containers: nextcloud itself, redis and 
a cron container. in this case i suppose one would define an 
oci-nextcloud-service-type which maybe extends an 
oci-redis-service-type. in this case the oci-nextcloud-service-type 
would define the 2 shepherd services for nextcloud and the cron process 
and the oci-redis-service-type would define one redis service.

Right now we can already do:

(service oci-container-service-type
            (list
              (oci-container-configuration …)))

and i updated the documentation accordingly. do you have any suggestion 
for changing the api of oci-container-configuration to support having 
different shepherd oci backed services behind a guix system service? 
This way we could remove the (list) call.

>
> Last thing: there’s no system test (something we normally require), but
> since I forgot about it before and I’m already asking for more than I
> should :-) I propose to leave it for later.

I actually looked around but didn't find them, but it was a long time 
ago and I certainly didn't look very well. I'm definitely up for testing 
this (maybe it's possible to use swineherd? could we use it for 
automating integration tests?), could you point me to something similar 
i can look to as an example?


Thank you for your time and effort, i'm sending an updated patch


giacomo





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 14 Oct 2023 16:10:08 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Oct 14 12:10:08 2023
Received: from localhost ([127.0.0.1]:50253 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qrhDK-0000h8-Om
	for submit <at> debbugs.gnu.org; Sat, 14 Oct 2023 12:10:08 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:45012)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <ludo@HIDDEN>) id 1qrhDF-0000gV-52
 for 66160 <at> debbugs.gnu.org; Sat, 14 Oct 2023 12:10:04 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1qrhCk-0002UC-Uf; Sat, 14 Oct 2023 12:09:30 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=wnc7uu8UnVRFPlIQ7c2L45tG7WFf+T/o5ei81XdMLKE=; b=MT9416+I9+xfX+y3KIDI
 hJ4q+4Utbp6vuserLqCBqaL5yOuZ2G7ZeTiX3L24vSEHH5TqD/41qLXg+lFcYEtWAGE2i25kuOzF9
 uSsFQVtN8rFRNtCcKt7HGHja3SVbH2moX/Ds9qOJtZzpRIAncBjy/cyOMCautbzIUWSYrtMmFGTdh
 Z99hHIUOS6ZWla2QdwtnAuGjgXQo5v8Q29JsWq89yVpuBQyEa1uG0r/NB8bFtUu8HizS7azvNtRcz
 wMR2JPigrx1+eL+L7X+BTRptricTRzpjhfxT+m0Hv9Vh5PAy+dXYN/pK9AqsBlbPT/zjey0cYaRQh
 zciuXxY5AFvnnw==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Giacomo Leidi <goodoldpaul@HIDDEN>
Subject: Re: [bug#66160] [PATCH] gnu: Add oci-container-service-type.
In-Reply-To: <8b8a0eed3b02cfd2edb94859da83032c96ee5616.1696619356.git.goodoldpaul@HIDDEN>
 (Giacomo Leidi's message of "Fri, 6 Oct 2023 21:09:16 +0200")
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <8b8a0eed3b02cfd2edb94859da83032c96ee5616.1696619356.git.goodoldpaul@HIDDEN>
Date: Sat, 14 Oct 2023 18:09:27 +0200
Message-ID: <875y39fao8.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hi Giacomo,

Giacomo Leidi <goodoldpaul@HIDDEN> skribis:

> * gnu/services/docker.scm (oci-container-configuration): New variable;
> (oci-container-shepherd-service): new variable;
> (oci-container-service-type): new variable.
> * doc/guix.texi: Document it.

We=E2=80=99re almost there!  There=E2=80=99s a couple of things I overlooke=
d before (my
apologies), so here we go:

> +@table @asis
> +@item @code{command} (default: @code{()}) (type: list-of-strings)
> +Overwrite the default command (@code{CMD}) of the image.
> +
> +@item @code{entrypoint} (default: @code{""}) (type: string)
> +Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.

Apparently this doesn=E2=80=99t match the docstring that=E2=80=99s in
=E2=80=98define-configuration=E2=80=99.

Could you make sure the docstring is the canonical source?  Then you can
use =E2=80=98generate-documentation=E2=80=99 to generate the bit that you=
=E2=80=99ll paste in
guix.texi (info "(guix) Complex Configurations").

> +  (entrypoint
> +   (string "")
> +   "Overwrite the default ENTRYPOINT of the image.")
> +  (environment
> +   (list '())
> +   "Set environment variables."
> +   (sanitizer oci-sanitize-environment))
> +  (image
> +   (string)
> +   "The image used to build the container.")
> +  (name
> +   (string "")
> +   "Set a name for the spawned container.")

Please use =E2=80=98maybe-string=E2=80=99 in cases where it=E2=80=99s eithe=
r the Docker default
(default ENTRYPOINT, default CMD, etc.) or some user-provided value.
I find it clearer or at least more conventional than using the empty
string to denote default values.

> +(define oci-container-configuration->options
> +  (lambda (config)
> +    (let ((entrypoint
> +           (oci-container-configuration-entrypoint config))
> +          (network
> +           (oci-container-configuration-network config)))
> +      (apply append
> +             (filter (compose not unspecified?)
> +                     `(,(when (not (string-null? entrypoint))
> +                          (list "--entrypoint" entrypoint))
> +                       ,(append-map
> +                         (lambda (spec)
> +                           (list "--env" spec))
> +                         (oci-container-configuration-environment config=
))
> +                       ,(when (not (string-null? network))
> +                          (list "--network" network))

This would thus become:

   `(,@(if entrypoint
           `("--entrypoint" ,entrypoint)
           '())
     =E2=80=A6)

> +                       #~(make-forkexec-constructor
> +                          ;; docker run [OPTIONS] IMAGE [COMMAND] [ARG..=
.]
> +                          (list #$docker-command
> +                                "run"
> +                                "--rm"
> +                                "--name" #$name
> +                                #$@(oci-container-configuration->options=
 config)
> +                                #$(oci-container-configuration-image con=
fig)
> +                                #$@(oci-container-configuration-command =
config))
> +                          #:user "root"
> +                          #:group "root"))

Does =E2=80=98docker run=E2=80=99 necessarily need to run as root, or are t=
here cases
where one might want to run it as non-root?  (I expect the latter.)

> +(define oci-container-service-type
> +  (service-type (name 'oci-container)
> +                (extensions (list (service-extension profile-service-type
> +                                                     (lambda _ (list doc=
ker-cli)))
> +                                  (service-extension shepherd-root-servi=
ce-type
> +                                                     configs->shepherd-s=
ervices)))
> +                (default-value '())

I wonder if it should take a list of configs and be extensible, or
simply take a single config.  Users would write:

  (service oci-container-service-type
           (oci-container-configuration =E2=80=A6))

WDYT?

Last thing: there=E2=80=99s no system test (something we normally require),=
 but
since I forgot about it before and I=E2=80=99m already asking for more than=
 I
should :-) I propose to leave it for later.


Thanks!

Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 13 Oct 2023 22:59:04 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Oct 13 18:59:04 2023
Received: from localhost ([127.0.0.1]:47539 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qrR7X-0001lQ-7L
	for submit <at> debbugs.gnu.org; Fri, 13 Oct 2023 18:59:04 -0400
Received: from confino.investici.org ([2a11:7980:1::2:0]:28471)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qrR7T-0001l0-Vy
 for 66160 <at> debbugs.gnu.org; Fri, 13 Oct 2023 18:59:01 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4S6hkh0yDGz11CJ;
 Fri, 13 Oct 2023 22:58:36 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1697237916;
 bh=Yes1joIH2CN5st1Q0iB2zujZRE8Fr+s/1c+6BNEUOHU=;
 h=From:To:Cc:Subject:Date:From;
 b=SZLFcjRnlhPAvuEDYFPThPoyjBMcpU+wv+grs5U+tTk81F/R6uVwwjPezLiIP4jB7
 2BdUY4EFPMdDr6KiI3R3dYOCKyi3KnVEvxpbFhVsXVFNdBY5xW1/MtJ5MwCxr99hrL
 9nrwG3x2+v+WaALGajgD9a1eZWHoVh2VcnYkKno0=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4S6hkh0NzPz11Bk; Fri, 13 Oct 2023 22:58:36 +0000 (UTC)
From: Giacomo Leidi <goodoldpaul@HIDDEN>
To: 66160 <at> debbugs.gnu.org
Subject: [PATCH] gnu: Add oci-container-service-type.
Date: Sat, 14 Oct 2023 00:57:33 +0200
Message-ID: <7bac25b131f2d7a00e694879c1aa7dde5279e6cf.1697237853.git.goodoldpaul@HIDDEN>
X-Mailer: git-send-email 2.41.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 66160
Cc: Giacomo Leidi <goodoldpaul@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

* gnu/services/docker.scm (oci-container-configuration): New variable;
(oci-container-shepherd-service): new variable;
(oci-container-service-type): new variable.
* doc/guix.texi: Document it.
---
 doc/guix.texi           | 108 +++++++++++++++++++++++
 gnu/services/docker.scm | 185 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 292 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 083504dcb8..97c3515652 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -39534,6 +39534,114 @@ Miscellaneous Services
 @command{singularity run} and similar commands.
 @end defvar
 
+@cindex OCI-backed, Shepherd services
+@subsubheading OCI backed services
+
+Should you wish to manage your Docker containers with the same consistent
+interface you use for your other Shepherd services,
+@var{oci-container-service-type} is the tool to use: given an
+@acronym{Open Container Initiative, OCI} container image, it will run it in a
+Shepherd service.  One example where this is useful: it lets you run services
+that are available as Docker/OCI images but not yet packaged for Guix.
+
+@defvar oci-container-service-type
+
+This is a thin wrapper around Docker's CLI that executes OCI images backed
+processes as Shepherd Services.
+
+@lisp
+(simple-service 'oci-grafana-service
+                oci-container-service-type
+                (list
+                 (oci-container-configuration
+                  (image "prom/prometheus")
+                  (network "host")
+                  (ports
+                    '(("9000" . "9000")
+                      ("9090" . "9090"))))))
+                 (oci-container-configuration
+                  (image "grafana/grafana:10.0.1")
+                  (network "host")
+                  (ports
+                    '(("3000" . "3000")))
+                  (volumes
+                    '("/var/lib/grafana:/var/lib/grafana"))))))
+@end lisp
+
+In this example two different Shepherd services are going be added to the
+system.  Each @code{oci-container-configuration} record translates to a
+@code{docker run} invocation and its fields directly map to options.  You can
+refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run,upstream},
+documentation for the semantics of each value.  If the images are not found they
+will be
+@url{https://docs.docker.com/engine/reference/commandline/pull/,pulled}.  The
+spawned services are going to be attached to the host network and are supposed
+to behave like other processes.
+
+@end defvar
+
+@deftp {Data Type} oci-container-configuration
+Available @code{oci-container-configuration} fields are:
+
+@table @asis
+@item @code{command} (default: @code{()}) (type: list-of-strings)
+Overwrite the default command (@code{CMD}) of the image.
+
+@item @code{entrypoint} (default: @code{""}) (type: string)
+Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.
+
+@item @code{environment} (default: @code{()}) (type: list)
+Set environment variables. This can be a list of pairs or strings, even mixed:
+
+@lisp
+(list '("LANGUAGE" . "eo:ca:eu")
+      "JAVA_HOME=/opt/java")
+@end lisp
+
+String are passed directly to the Docker CLI. You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#env,upstream}
+documentation for semantics.
+
+@item @code{image} (type: string)
+The image used to build the container. Images are resolved by the Docker Engine,
+and follow the usual format @code{myregistry.local:5000/testing/test-image:tag}.
+
+@item @code{name} (default: @code{""}) (type: string)
+Set a name for the spawned container.
+
+@item @code{network} (default: @code{""}) (type: string)
+Set a Docker network for the spawned container.
+
+@item @code{ports} (default: @code{()}) (type: list)
+Set the port or port ranges to expose from the spawned container. This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("8080" . "80")
+      "10443:443")
+@end lisp
+
+String are passed directly to the Docker CLI. You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#publish,upstream}
+documentation for semantics.
+
+@item @code{volumes} (default: @code{()}) (type: list)
+Set volume mappings for the spawned container. This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("/root/data/grafana" . "/var/lib/grafana")
+      "/gnu/store:/gnu/store")
+@end lisp
+
+String are passed directly to the Docker CLI. You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#volume,upstream}
+documentation for semantics.
+
+@end table
+@end deftp
+
 @cindex Audit
 @subsubheading Auditd Service
 
diff --git a/gnu/services/docker.scm b/gnu/services/docker.scm
index c2023d618c..be954f7a27 100644
--- a/gnu/services/docker.scm
+++ b/gnu/services/docker.scm
@@ -5,6 +5,7 @@
 ;;; Copyright © 2020 Efraim Flashner <efraim@HIDDEN>
 ;;; Copyright © 2020 Jesse Dowell <jessedowell@HIDDEN>
 ;;; Copyright © 2021 Brice Waegeneire <brice@HIDDEN>
+;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -32,12 +33,30 @@ (define-module (gnu services docker)
   #:use-module (gnu packages docker)
   #:use-module (gnu packages linux)               ;singularity
   #:use-module (guix records)
+  #:use-module (guix diagnostics)
   #:use-module (guix gexp)
+  #:use-module (guix i18n)
   #:use-module (guix packages)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
 
   #:export (docker-configuration
             docker-service-type
-            singularity-service-type))
+            singularity-service-type
+            oci-container-configuration
+            oci-container-configuration?
+            oci-container-configuration-fields
+            oci-container-configuration-command
+            oci-container-configuration-entrypoint
+            oci-container-configuration-environment
+            oci-container-configuration-image
+            oci-container-configuration-name
+            oci-container-configuration-network
+            oci-container-configuration-ports
+            oci-container-configuration-volumes
+            oci-container-service-type
+            oci-container-shepherd-service))
 
 (define-configuration docker-configuration
   (docker
@@ -216,3 +235,167 @@ (define singularity-service-type
                        (service-extension activation-service-type
                                           (const %singularity-activation))))
                 (default-value singularity)))
+
+
+;;;
+;;; OCI container.
+;;;
+
+(define (oci-sanitize-pair pair delimiter)
+  (define (valid? member)
+    (or (string? member)
+        (gexp? member)
+        (file-like? member)))
+  (match pair
+    (((? valid? key) . (? valid? value))
+     #~(string-append #$key #$delimiter #$value))
+    (_
+     (raise
+      (formatted-message
+       (G_ "pair members must contain only strings, gexps or file-like objects
+but ~a was found")
+       pair)))))
+
+(define (oci-sanitize-mixed-list name value delimiter)
+  (map
+   (lambda (el)
+     (cond ((string? el) el)
+           ((pair? el) (oci-sanitize-pair el delimiter))
+           (else
+            (raise
+             (formatted-message
+              (G_ "~a members must be either a string or a pair but ~a was
+found!")
+              name el)))))
+   value))
+
+(define (oci-sanitize-environment value)
+  ;; Expected spec format:
+  ;; '(("HOME" . "/home/nobody") "JAVA_HOME=/java")
+  (oci-sanitize-mixed-list "environment" value "="))
+
+(define (oci-sanitize-ports value)
+  ;; Expected spec format:
+  ;; '(("8088" . "80") "2022:22")
+  (oci-sanitize-mixed-list "ports" value ":"))
+
+(define (oci-sanitize-volumes value)
+  ;; Expected spec format:
+  ;; '(("/mnt/dir" . "/dir") "/run/current-system/profile:/java")
+  (oci-sanitize-mixed-list "volumes" value ":"))
+
+(define-configuration/no-serialization oci-container-configuration
+  (command
+   (list-of-strings '())
+   "Overwrite the default CMD of the image.")
+  (entrypoint
+   (string "")
+   "Overwrite the default ENTRYPOINT of the image.")
+  (environment
+   (list '())
+   "Set environment variables."
+   (sanitizer oci-sanitize-environment))
+  (image
+   (string)
+   "The image used to build the container.")
+  (name
+   (string "")
+   "Set a name for the spawned container.")
+  (network
+   (string "")
+   "Set a Docker network for the spawned container.")
+  (ports
+   (list '())
+   "Set the port or port ranges to expose from the spawned container."
+   (sanitizer oci-sanitize-ports))
+  (volumes
+   (list '())
+   "Set volume mappings for the spawned container."
+   (sanitizer oci-sanitize-volumes)))
+
+(define oci-container-configuration->options
+  (lambda (config)
+    (let ((entrypoint
+           (oci-container-configuration-entrypoint config))
+          (network
+           (oci-container-configuration-network config)))
+      (apply append
+             (filter (compose not unspecified?)
+                     `(,(when (not (string-null? entrypoint))
+                          (list "--entrypoint" entrypoint))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "--env" spec))
+                         (oci-container-configuration-environment config))
+                       ,(when (not (string-null? network))
+                          (list "--network" network))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-p" spec))
+                         (oci-container-configuration-ports config))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-v" spec))
+                         (oci-container-configuration-volumes config))))))))
+
+(define (oci-container-shepherd-service config)
+  (define (guess-name name image)
+    (if (not (string-null? name))
+        name
+        (string-append "docker-"
+                       (basename (car (string-split image #\:))))))
+
+  (let* ((docker-command (file-append docker-cli "/bin/docker"))
+         (command (oci-container-configuration-command config))
+         (config-name (oci-container-configuration-name config))
+         (image (oci-container-configuration-image config))
+         (options (oci-container-configuration->options config))
+         (name (guess-name config-name image)))
+
+    (shepherd-service (provision `(,(string->symbol name)))
+                      (requirement '(dockerd user-processes))
+                      (respawn? #f)
+                      (documentation
+                       (string-append
+                        "Docker backed Shepherd service for image: " image))
+                      (start
+                       #~(make-forkexec-constructor
+                          ;; docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
+                          (list #$docker-command
+                                "run"
+                                "--rm"
+                                "--name" #$name
+                                #$@options
+                                #$image
+                                #$@command)
+                          #:user "root"
+                          #:group "root"))
+                      (stop
+                       #~(lambda _
+                           (invoke #$docker-command "stop" #$name)))
+                      (actions
+                       (list
+                        (shepherd-action
+                         (name 'pull)
+                         (documentation
+                          (format #f "Pull ~a's image (~a)."
+                                  name image))
+                         (procedure
+                          #~(lambda _
+                              (invoke #$docker-command "pull" #$image)))))))))
+
+(define (configs->shepherd-services configs)
+  (map oci-container-shepherd-service configs))
+
+(define oci-container-service-type
+  (service-type (name 'oci-container)
+                (extensions (list (service-extension profile-service-type
+                                                     (lambda _ (list docker-cli)))
+                                  (service-extension shepherd-root-service-type
+                                                     configs->shepherd-services)))
+                (default-value '())
+                (extend append)
+                (compose concatenate)
+                (description
+                 "This service allows the management of Docker and OCI
+containers as Shepherd services.")))

base-commit: 8aad7210ea06992ee3f36ca7f57678240949e063
-- 
2.41.0





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 13 Oct 2023 22:53:35 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Oct 13 18:53:34 2023
Received: from localhost ([127.0.0.1]:47529 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qrR2E-0001cV-In
	for submit <at> debbugs.gnu.org; Fri, 13 Oct 2023 18:53:34 -0400
Received: from confino.investici.org ([2a11:7980:1::2:0]:58875)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qrR2A-0001cF-8n
 for 66160 <at> debbugs.gnu.org; Fri, 13 Oct 2023 18:53:33 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4S6hcH39NMz11CJ;
 Fri, 13 Oct 2023 22:53:03 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1697237583;
 bh=vM6vahwe4QM4bOPJAgZRNmyn+wuiSkz0/P0QNKmPRGk=;
 h=Date:Subject:From:To:Cc:References:In-Reply-To:From;
 b=SshPIgz274PGXh9TbLlhh4L1u5O+6OjcgnK/FXlGtfh6ZYowQCovQRkXWos2fgZv+
 bUYuPqUhfNdaaNE3KZa9itaYINQ8xQ24wEwgHVCXqPw8ggWhvyZbu5u3aut5al+oVM
 iKHgET55xcoqlkAMRQ5bJJqvBD5zbQJmZn4gzShQ=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4S6hcH2cv0z11Bk; Fri, 13 Oct 2023 22:53:03 +0000 (UTC)
Message-ID: <ea07b976-c0f9-4572-cd7d-f906add4bf4c@HIDDEN>
Date: Sat, 14 Oct 2023 00:53:02 +0200
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.15.0
Subject: Re: bug#66160: [PATCH] gnu: Add oci-container-service-type.
From: paul <goodoldpaul@HIDDEN>
To: =?UTF-8?Q?Ludovic_Court=c3=a8s?= <ludo@HIDDEN>
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <3b982aed1fa51f7b9e4bd87294b006f1977d26aa.1695414861.git.goodoldpaul@HIDDEN>
 <87v8bl3zvg.fsf_-_@HIDDEN>
 <a190efeb-6cff-6d61-3086-45cfb053ad88@HIDDEN>
Content-Language: en-US
In-Reply-To: <a190efeb-6cff-6d61-3086-45cfb053ad88@HIDDEN>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
X-Spam-Score: -1.5 (-)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.5 (--)

Hi,

I'm sending a patch rebased on current master. I also added a 'pull' 
action to allow running docker pull for the image of an oci container.


Thank you for your time,


giacomo





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 6 Oct 2023 20:51:31 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Oct 06 16:51:31 2023
Received: from localhost ([127.0.0.1]:52776 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qornG-0000C5-4X
	for submit <at> debbugs.gnu.org; Fri, 06 Oct 2023 16:51:30 -0400
Received: from confino.investici.org ([2a11:7980:1::2:0]:63975)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qornC-0000Bj-El
 for 66160 <at> debbugs.gnu.org; Fri, 06 Oct 2023 16:51:29 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4S2LDl6vZfz114q;
 Fri,  6 Oct 2023 20:51:03 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1696625463;
 bh=TaNzuhHAyAUHrJDCslXcdEyeFhVBLdTVur0MrxBwLpI=;
 h=From:To:Cc:Subject:Date:From;
 b=OIHEMQ2fKJ2muCzfYzy6zG04PM4RJgw1+AMmwIUTfmFAB08Hj1YdQixV/5Gqj5Mtk
 FzvGbXnoJK54QDOcE0nz/V8CpcjCXsEovRLy6/+bgqvTdbT/mljoqwR9EX1X40xJYl
 P5evpaJBUBEtcDqU5PdyouPlwv3zRD0hTglKj4vw=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4S2LDl6MBQz114W; Fri,  6 Oct 2023 20:51:03 +0000 (UTC)
From: Giacomo Leidi <goodoldpaul@HIDDEN>
To: 66160 <at> debbugs.gnu.org
Subject: [PATCH] gnu: Add oci-container-service-type.
Date: Fri,  6 Oct 2023 21:09:16 +0200
Message-ID: <8b8a0eed3b02cfd2edb94859da83032c96ee5616.1696619356.git.goodoldpaul@HIDDEN>
X-Mailer: git-send-email 2.41.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 66160
Cc: Giacomo Leidi <goodoldpaul@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

* gnu/services/docker.scm (oci-container-configuration): New variable;
(oci-container-shepherd-service): new variable;
(oci-container-service-type): new variable.
* doc/guix.texi: Document it.
---
 doc/guix.texi           | 108 ++++++++++++++++++++++++++
 gnu/services/docker.scm | 167 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 274 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 617b8463e3..5c3908f758 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -39349,6 +39349,114 @@ Miscellaneous Services
 @command{singularity run} and similar commands.
 @end defvar
 
+@cindex OCI-backed, Shepherd services
+@subsubheading OCI backed services
+
+Should you wish to manage your Docker containers with the same consistent
+interface you use for your other Shepherd services,
+@var{oci-container-service-type} is the tool to use: given an
+@acronym{Open Container Initiative, OCI} container image, it will run it in a
+Shepherd service.  One example where this is useful: it lets you run services
+that are available as Docker/OCI images but not yet packaged for Guix.
+
+@defvar oci-container-service-type
+
+This is a thin wrapper around Docker's CLI that executes OCI images backed
+processes as Shepherd Services.
+
+@lisp
+(simple-service 'oci-grafana-service
+                oci-container-service-type
+                (list
+                 (oci-container-configuration
+                  (image "prom/prometheus")
+                  (network "host")
+                  (ports
+                    '(("9000" . "9000")
+                      ("9090" . "9090"))))))
+                 (oci-container-configuration
+                  (image "grafana/grafana:10.0.1")
+                  (network "host")
+                  (ports
+                    '(("3000" . "3000")))
+                  (volumes
+                    '("/var/lib/grafana:/var/lib/grafana"))))))
+@end lisp
+
+In this example two different Shepherd services are going be added to the
+system.  Each @code{oci-container-configuration} record translates to a
+@code{docker run} invocation and its fields directly map to options.  You can
+refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run,upstream},
+documentation for the semantics of each value.  If the images are not found they
+will be
+@url{https://docs.docker.com/engine/reference/commandline/pull/,pulled}.  The
+spawned services are going to be attached to the host network and are supposed
+to behave like other processes.
+
+@end defvar
+
+@deftp {Data Type} oci-container-configuration
+Available @code{oci-container-configuration} fields are:
+
+@table @asis
+@item @code{command} (default: @code{()}) (type: list-of-strings)
+Overwrite the default command (@code{CMD}) of the image.
+
+@item @code{entrypoint} (default: @code{""}) (type: string)
+Overwrite the default entrypoint (@code{ENTRYPOINT}) of the image.
+
+@item @code{environment} (default: @code{()}) (type: list)
+Set environment variables. This can be a list of pairs or strings, even mixed:
+
+@lisp
+(list '("LANGUAGE" . "eo:ca:eu")
+      "JAVA_HOME=/opt/java")
+@end lisp
+
+String are passed directly to the Docker CLI. You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#env,upstream}
+documentation for semantics.
+
+@item @code{image} (type: string)
+The image used to build the container. Images are resolved by the Docker Engine,
+and follow the usual format @code{myregistry.local:5000/testing/test-image:tag}.
+
+@item @code{name} (default: @code{""}) (type: string)
+Set a name for the spawned container.
+
+@item @code{network} (default: @code{""}) (type: string)
+Set a Docker network for the spawned container.
+
+@item @code{ports} (default: @code{()}) (type: list)
+Set the port or port ranges to expose from the spawned container. This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("8080" . "80")
+      "10443:443")
+@end lisp
+
+String are passed directly to the Docker CLI. You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#publish,upstream}
+documentation for semantics.
+
+@item @code{volumes} (default: @code{()}) (type: list)
+Set volume mappings for the spawned container. This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("/root/data/grafana" . "/var/lib/grafana")
+      "/gnu/store:/gnu/store")
+@end lisp
+
+String are passed directly to the Docker CLI. You can refer to the
+@url{https://docs.docker.com/engine/reference/commandline/run/#volume,upstream}
+documentation for semantics.
+
+@end table
+@end deftp
+
 @cindex Audit
 @subsubheading Auditd Service
 
diff --git a/gnu/services/docker.scm b/gnu/services/docker.scm
index c2023d618c..af87001143 100644
--- a/gnu/services/docker.scm
+++ b/gnu/services/docker.scm
@@ -5,6 +5,7 @@
 ;;; Copyright © 2020 Efraim Flashner <efraim@HIDDEN>
 ;;; Copyright © 2020 Jesse Dowell <jessedowell@HIDDEN>
 ;;; Copyright © 2021 Brice Waegeneire <brice@HIDDEN>
+;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -32,12 +33,30 @@ (define-module (gnu services docker)
   #:use-module (gnu packages docker)
   #:use-module (gnu packages linux)               ;singularity
   #:use-module (guix records)
+  #:use-module (guix diagnostics)
   #:use-module (guix gexp)
+  #:use-module (guix i18n)
   #:use-module (guix packages)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
+  #:use-module (ice-9 match)
 
   #:export (docker-configuration
             docker-service-type
-            singularity-service-type))
+            singularity-service-type
+            oci-container-configuration
+            oci-container-configuration?
+            oci-container-configuration-fields
+            oci-container-configuration-command
+            oci-container-configuration-entrypoint
+            oci-container-configuration-environment
+            oci-container-configuration-image
+            oci-container-configuration-name
+            oci-container-configuration-network
+            oci-container-configuration-ports
+            oci-container-configuration-volumes
+            oci-container-service-type
+            oci-container-shepherd-service))
 
 (define-configuration docker-configuration
   (docker
@@ -216,3 +235,149 @@ (define singularity-service-type
                        (service-extension activation-service-type
                                           (const %singularity-activation))))
                 (default-value singularity)))
+
+
+;;;
+;;; OCI container.
+;;;
+
+(define (oci-sanitize-pair pair delimiter)
+  (match pair
+    (((? string? key) . (? string? value))
+     (string-append key delimiter value))
+    (_
+     (raise
+      (formatted-message
+       (G_ "pair members must contain only strings but ~a was found")
+       pair)))))
+
+(define (oci-sanitize-mixed-list name value delimiter)
+  (map
+   (lambda (el)
+     (cond ((string? el) el)
+           ((pair? el) (oci-sanitize-pair el delimiter))
+           (else
+            (raise
+             (formatted-message
+              (G_ "~a members must be either a string or a pair but ~a was found!")
+              name el)))))
+   value))
+
+(define (oci-sanitize-environment value)
+  ;; Expected spec format:
+  ;; '(("HOME" . "/home/nobody") "JAVA_HOME=/java")
+  (oci-sanitize-mixed-list "environment" value "="))
+
+(define (oci-sanitize-ports value)
+  ;; Expected spec format:
+  ;; '(("8088" . "80") "2022:22")
+  (oci-sanitize-mixed-list "ports" value ":"))
+
+(define (oci-sanitize-volumes value)
+  ;; Expected spec format:
+  ;; '(("/mnt/dir" . "/dir") "/run/current-system/profile:/java")
+  (oci-sanitize-mixed-list "volumes" value ":"))
+
+(define-configuration/no-serialization oci-container-configuration
+  (command
+   (list-of-strings '())
+   "Overwrite the default CMD of the image.")
+  (entrypoint
+   (string "")
+   "Overwrite the default ENTRYPOINT of the image.")
+  (environment
+   (list '())
+   "Set environment variables."
+   (sanitizer oci-sanitize-environment))
+  (image
+   (string)
+   "The image used to build the container.")
+  (name
+   (string "")
+   "Set a name for the spawned container.")
+  (network
+   (string "")
+   "Set a Docker network for the spawned container.")
+  (ports
+   (list '())
+   "Set the port or port ranges to expose from the spawned container."
+   (sanitizer oci-sanitize-ports))
+  (volumes
+   (list '())
+   "Set volume mappings for the spawned container."
+   (sanitizer oci-sanitize-volumes)))
+
+(define oci-container-configuration->options
+  (lambda (config)
+    (let ((entrypoint
+           (oci-container-configuration-entrypoint config))
+          (network
+           (oci-container-configuration-network config)))
+      (apply append
+             (filter (compose not unspecified?)
+                     `(,(when (not (string-null? entrypoint))
+                          (list "--entrypoint" entrypoint))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "--env" spec))
+                         (oci-container-configuration-environment config))
+                       ,(when (not (string-null? network))
+                          (list "--network" network))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-p" spec))
+                         (oci-container-configuration-ports config))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-v" spec))
+                         (oci-container-configuration-volumes config))))))))
+
+(define (oci-container-shepherd-service config)
+  (define (guess-name name image)
+    (if (not (string-null? name))
+        name
+        (string-append "docker-"
+                       (basename (car (string-split image #\:))))))
+
+  (let* ((docker-command (file-append docker-cli "/bin/docker"))
+         (config-name (oci-container-configuration-name config))
+         (image (oci-container-configuration-image config))
+         (name (guess-name config-name image)))
+
+    (shepherd-service (provision `(,(string->symbol name)))
+                      (requirement '(dockerd user-processes))
+                      (respawn? #f)
+                      (documentation
+                       (string-append
+                        "Docker backed Shepherd service for image: " image))
+                      (start
+                       #~(make-forkexec-constructor
+                          ;; docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
+                          (list #$docker-command
+                                "run"
+                                "--rm"
+                                "--name" #$name
+                                #$@(oci-container-configuration->options config)
+                                #$(oci-container-configuration-image config)
+                                #$@(oci-container-configuration-command config))
+                          #:user "root"
+                          #:group "root"))
+                      (stop
+                       #~(lambda _
+                           (invoke #$docker-command "stop" #$name))))))
+
+(define (configs->shepherd-services configs)
+  (map oci-container-shepherd-service configs))
+
+(define oci-container-service-type
+  (service-type (name 'oci-container)
+                (extensions (list (service-extension profile-service-type
+                                                     (lambda _ (list docker-cli)))
+                                  (service-extension shepherd-root-service-type
+                                                     configs->shepherd-services)))
+                (default-value '())
+                (extend append)
+                (compose concatenate)
+                (description
+                 "This service allows the management of Docker and OCI
+containers as Shepherd services.")))

base-commit: f45c0c82289d409b4fac00464ea8b323839ba53f
-- 
2.41.0





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 5 Oct 2023 17:31:05 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Oct 05 13:31:05 2023
Received: from localhost ([127.0.0.1]:48457 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qoSBl-0006yy-7l
	for submit <at> debbugs.gnu.org; Thu, 05 Oct 2023 13:31:05 -0400
Received: from confino.investici.org ([93.190.126.19]:22703)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qoSBi-0006yY-9S
 for 66160 <at> debbugs.gnu.org; Thu, 05 Oct 2023 13:31:03 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4S1dr23KNZz10yw;
 Thu,  5 Oct 2023 17:30:42 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1696527042;
 bh=tkOptpR82Ch5o5bVHYBwasRcWpD7na/eJ8c8fYvTjV4=;
 h=Date:Subject:To:Cc:References:From:In-Reply-To:From;
 b=qeFnfTuU6nEYdMts/vdwnWuc0YQV+XiejZNohKTwuVeiRDU2QEdWLjUvLw9JGTtRM
 zwl+Um/9FFN8B9T0q0/+anN/75vlowWcVSssArXUfQ6wzZzCaFwUcinZ2LocAtGWct
 5JRw93OAW3FxylL8EyHgpBm/jyoXa/D5cf2yRoHY=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4S1dr22tz0z10wv; Thu,  5 Oct 2023 17:30:42 +0000 (UTC)
Message-ID: <a190efeb-6cff-6d61-3086-45cfb053ad88@HIDDEN>
Date: Thu, 5 Oct 2023 19:30:41 +0200
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.15.0
Subject: Re: bug#66160: [PATCH] gnu: Add oci-container-service-type.
To: =?UTF-8?Q?Ludovic_Court=c3=a8s?= <ludo@HIDDEN>
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <3b982aed1fa51f7b9e4bd87294b006f1977d26aa.1695414861.git.goodoldpaul@HIDDEN>
 <87v8bl3zvg.fsf_-_@HIDDEN>
Content-Language: en-US
From: paul <goodoldpaul@HIDDEN>
In-Reply-To: <87v8bl3zvg.fsf_-_@HIDDEN>
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
X-Spam-Score: -1.5 (-)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -2.5 (--)

Hi,

On 10/5/23 16:30, Ludovic Courtès wrote:
> Hi,
>
> Giacomo Leidi <goodoldpaul@HIDDEN> skribis:
>
>> * gnu/services/docker.scm (oci-container-configuration): New variable;
>> (oci-container-shepherd-service): new variable;
>> (oci-container-service-type): new variable.
>> * doc/guix.texi: Document it.
> Neat!
>
>> +@cindex OCI-backed, Shepherd services
>> +@subsubheading OCI backed services
>> +
>> +Should you wish to manage your Docker containers with the same consistent
>> +interface you use for your other Shepherd services,
>> +@var{oci-container-service-type} is the tool to use.
> Perhaps expound a bit, like:
>
>    … is the tool to use: given an @acronym{Open Container Initiative,
>    OCI} container image, it will run it in a Shepherd service.  One
>    example where this is useful: it lets you run services that are
>    available as Docker/OCI images but not yet packaged for Guix.
nice thank you, fixed.
>
>> +@defvar oci-container-service-type
>> +
>> +This is a thin wrapper around Docker's CLI that wraps OCI images backed
>> +processes as Shepherd Services.
>> +
>> +@lisp
>> +(simple-service 'oci-grafana-service
>> +                (list
>> +                 (oci-container-configuration
> The second argument to ‘simple-service’ is missing.
Good catch, fixed.
>
>> +                  (image "prom/prometheus")
>> +                  (network "host")
>> +                  (ports
>> +                    '(("9000" . "9000")
>> +                      ("9090" . "9090"))))))
>> +                 (oci-container-configuration
>> +                  (image "grafana/grafana:10.0.1")
>> +                  (network "host")
>> +                  (volumes
>> +                    '("/var/lib/grafana:/var/lib/grafana"))))))
>> +@end lisp
> Please explain the example in one or two sentences.
>
> Personally, I’d like to know how the image names are resolved; would be
> nice to mention it in the doc.
[ ... ]
>
>> +@table @asis
>> +@item @code{command} (default: @code{()}) (type: list-of-strings)
>> +Overwrite the default CMD of the image.
> “… the default command (@code{CMD}) of the image.”
[ ... ]
>
>> +@item @code{entrypoint} (default: @code{""}) (type: string)
>> +Overwrite the default ENTRYPOINT of the image.
> Likewise.
Fixed, thank you.
>
>> +@item @code{environment} (default: @code{()}) (type: list)
>> +Set environment variables. This can be a list of pairs or strings, even mixed:
>> +
>> +@lisp
>> +(list '("LANGUAGE" . "eo:ca:eu")
>> +      "JAVA_HOME=/opt/java")
> I would choose one or the other, but not both.
I would like to allow some kind of escape (the same way the nice Guix 
configuration records provide an extra-content field which is literally 
appended to the config) in case there's some something I didn't foresee 
with this implementation. It may be paranoia, I don't have a strong 
opinion. are you strongly against supporting the two formats?
>
>> +@item @code{ports} (default: @code{()}) (type: list)
>> +Set the port or port ranges to expose from the spawned container. This can be a
>> +list of pairs or strings, even mixed:
>> +
>> +@lisp
>> +(list '("8080" . "80")
>> +      "10443:443")
> Likewise.
>
>> +(define (oci-sanitize-pair pair delimiter)
>> +  (cond ((file-like? (car pair))
>> +         (file-append (car pair) delimiter (cdr pair)))
> Please use ‘match’ instead of car/cdr (info "(guix) Data Types and
> Pattern Matching").
Thank you, fixed.
>
>> +         (error
>> +          (format #f "pair members must only contain gexps, file-like objects and strings but ~a was found" (car pair))))))
> Should be (raise (formatted-message (G_ …))).  That way we get i18n
> support and the message is presented like other error messages.

[ ... ]
>
>> +            (error
>> +             (format #f "~a members must be either a string or a pair but ~a was found!" name el)))))
> Ditto.

[ ... ]
>
>> +    (shepherd-service (provision `(,(string->symbol name)))
>> +                      (requirement '(dockerd))
> Actually: (requirement '(dockerd user-processes)).

[ ... ]
>
>> +                (description
>> +                 "This service provides allows the management of Docker
>> +containers as Shepherd services.")))
> “Docker and OCI containers”
Fixed.
> Could you send an updated patch?

I should have addressed all of your comments besides the one on the 
key-value format. I'm sending an updated patch.


Thank you for your time and effort,


giacomo





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 5 Oct 2023 14:31:32 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Oct 05 10:31:32 2023
Received: from localhost ([127.0.0.1]:48062 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qoPNz-0008OV-Hd
	for submit <at> debbugs.gnu.org; Thu, 05 Oct 2023 10:31:31 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:35912)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <ludo@HIDDEN>) id 1qoPNw-0008OD-8W
 for 66160 <at> debbugs.gnu.org; Thu, 05 Oct 2023 10:31:30 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <ludo@HIDDEN>)
 id 1qoPNW-0005K6-W3; Thu, 05 Oct 2023 10:31:03 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-Version:Date:References:In-Reply-To:Subject:To:
 From; bh=dewsmrblf++qAB/1KmJYtAeQq+SbUBPXC6fscAyK7u0=; b=mN+tfK5LZludW+gLANIC
 tN34IW6Azd2jnmz0NiargaFZuC0Xpdow8kBuMIt9reCe9TOWzXWd10nifgLVIl9oIC4/EQvUTytZk
 PeptzGt2RKs1DPtD8grElIES5lV8RT9JKDfyWH/fRUR8tXW03+Ryg9rSxJA2wGm61qC6YDnH+Tt6y
 YdPLgM1yBnui9C1cmOBZ0nZpphI+Wd9JOndANdjTXHksCELryZ1EYloF534W/kMt/ue38sw+Jor7Z
 ZK9FDSN0M0f/YwPnnKnVd4jlZ8NMr2t4Mh93WeKJ8BK64UBHyxCdEG6gheAA+dvVJajXNHMuEyqCY
 kiYEjbzoBl0gjA==;
From: =?utf-8?Q?Ludovic_Court=C3=A8s?= <ludo@HIDDEN>
To: Giacomo Leidi <goodoldpaul@HIDDEN>
Subject: Re: bug#66160: [PATCH] gnu: Add oci-container-service-type.
In-Reply-To: <3b982aed1fa51f7b9e4bd87294b006f1977d26aa.1695414861.git.goodoldpaul@HIDDEN>
 (Giacomo Leidi's message of "Fri, 22 Sep 2023 22:34:21 +0200")
References: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
 <3b982aed1fa51f7b9e4bd87294b006f1977d26aa.1695414861.git.goodoldpaul@HIDDEN>
Date: Thu, 05 Oct 2023 16:30:59 +0200
Message-ID: <87v8bl3zvg.fsf_-_@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 66160
Cc: 66160 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Hi,

Giacomo Leidi <goodoldpaul@HIDDEN> skribis:

> * gnu/services/docker.scm (oci-container-configuration): New variable;
> (oci-container-shepherd-service): new variable;
> (oci-container-service-type): new variable.
> * doc/guix.texi: Document it.

Neat!

> +@cindex OCI-backed, Shepherd services
> +@subsubheading OCI backed services
> +
> +Should you wish to manage your Docker containers with the same consistent
> +interface you use for your other Shepherd services,
> +@var{oci-container-service-type} is the tool to use.

Perhaps expound a bit, like:

  =E2=80=A6 is the tool to use: given an @acronym{Open Container Initiative,
  OCI} container image, it will run it in a Shepherd service.  One
  example where this is useful: it lets you run services that are
  available as Docker/OCI images but not yet packaged for Guix.

> +@defvar oci-container-service-type
> +
> +This is a thin wrapper around Docker's CLI that wraps OCI images backed
> +processes as Shepherd Services.
> +
> +@lisp
> +(simple-service 'oci-grafana-service
> +                (list
> +                 (oci-container-configuration

The second argument to =E2=80=98simple-service=E2=80=99 is missing.

> +                  (image "prom/prometheus")
> +                  (network "host")
> +                  (ports
> +                    '(("9000" . "9000")
> +                      ("9090" . "9090"))))))
> +                 (oci-container-configuration
> +                  (image "grafana/grafana:10.0.1")
> +                  (network "host")
> +                  (volumes
> +                    '("/var/lib/grafana:/var/lib/grafana"))))))
> +@end lisp

Please explain the example in one or two sentences.

Personally, I=E2=80=99d like to know how the image names are resolved; woul=
d be
nice to mention it in the doc.

> +@table @asis
> +@item @code{command} (default: @code{()}) (type: list-of-strings)
> +Overwrite the default CMD of the image.

=E2=80=9C=E2=80=A6 the default command (@code{CMD}) of the image.=E2=80=9D

> +@item @code{entrypoint} (default: @code{""}) (type: string)
> +Overwrite the default ENTRYPOINT of the image.

Likewise.

> +@item @code{environment} (default: @code{()}) (type: list)
> +Set environment variables. This can be a list of pairs or strings, even =
mixed:
> +
> +@lisp
> +(list '("LANGUAGE" . "eo:ca:eu")
> +      "JAVA_HOME=3D/opt/java")

I would choose one or the other, but not both.

> +@item @code{ports} (default: @code{()}) (type: list)
> +Set the port or port ranges to expose from the spawned container. This c=
an be a
> +list of pairs or strings, even mixed:
> +
> +@lisp
> +(list '("8080" . "80")
> +      "10443:443")

Likewise.

> +(define (oci-sanitize-pair pair delimiter)
> +  (cond ((file-like? (car pair))
> +         (file-append (car pair) delimiter (cdr pair)))

Please use =E2=80=98match=E2=80=99 instead of car/cdr (info "(guix) Data Ty=
pes and
Pattern Matching").

> +         (error
> +          (format #f "pair members must only contain gexps, file-like ob=
jects and strings but ~a was found" (car pair))))))

Should be (raise (formatted-message (G_ =E2=80=A6))).  That way we get i18n
support and the message is presented like other error messages.

> +            (error
> +             (format #f "~a members must be either a string or a pair bu=
t ~a was found!" name el)))))

Ditto.

> +    (shepherd-service (provision `(,(string->symbol name)))
> +                      (requirement '(dockerd))

Actually: (requirement '(dockerd user-processes)).

> +                (description
> +                 "This service provides allows the management of Docker
> +containers as Shepherd services.")))

=E2=80=9CDocker and OCI containers=E2=80=9D

Could you send an updated patch?

Thanks,
Ludo=E2=80=99.




Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at 66160 <at> debbugs.gnu.org:


Received: (at 66160) by debbugs.gnu.org; 22 Sep 2023 20:34:58 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Sep 22 16:34:58 2023
Received: from localhost ([127.0.0.1]:37337 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qjmra-0003l0-4N
	for submit <at> debbugs.gnu.org; Fri, 22 Sep 2023 16:34:58 -0400
Received: from confino.investici.org ([2a11:7980:1::2:0]:49101)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qjmrY-0003km-80
 for 66160 <at> debbugs.gnu.org; Fri, 22 Sep 2023 16:34:57 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4RskXL4fZFz1156;
 Fri, 22 Sep 2023 20:34:42 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1695414882;
 bh=iNxdaarAFZ1CX0zSLFf6y9lgrZmbI9qrkto+84vyJ2Q=;
 h=From:To:Cc:Subject:Date:From;
 b=YulRJSMEhI4x7ZxjW3e5XTpybIBZAztmS2FxFDqOPnzKuEoK1bcjHpM49cg2hwI0m
 dUU0Ygye10qVPo3DK3XsyBFuFBW8Jg6I09sCxu/y+QieSLnqqKnmRE9TwUEbNQ8pfl
 bMbu4Qp5FI+Sq9hfy94f7myE40D8sCBe25IehlS8=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4RskXL2vtKz114y; Fri, 22 Sep 2023 20:34:42 +0000 (UTC)
From: Giacomo Leidi <goodoldpaul@HIDDEN>
To: 66160 <at> debbugs.gnu.org
Subject: [PATCH] gnu: Add oci-container-service-type.
Date: Fri, 22 Sep 2023 22:34:21 +0200
Message-ID: <3b982aed1fa51f7b9e4bd87294b006f1977d26aa.1695414861.git.goodoldpaul@HIDDEN>
X-Mailer: git-send-email 2.41.0
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: 66160
Cc: Giacomo Leidi <goodoldpaul@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

* gnu/services/docker.scm (oci-container-configuration): New variable;
(oci-container-shepherd-service): new variable;
(oci-container-service-type): new variable.
* doc/guix.texi: Document it.
---
 doc/guix.texi           |  78 +++++++++++++++++++
 gnu/services/docker.scm | 163 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 240 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 617b8463e3..988ab64773 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -39349,6 +39349,84 @@ Miscellaneous Services
 @command{singularity run} and similar commands.
 @end defvar
 
+@cindex OCI-backed, Shepherd services
+@subsubheading OCI backed services
+
+Should you wish to manage your Docker containers with the same consistent
+interface you use for your other Shepherd services,
+@var{oci-container-service-type} is the tool to use.
+
+@defvar oci-container-service-type
+
+This is a thin wrapper around Docker's CLI that wraps OCI images backed
+processes as Shepherd Services.
+
+@lisp
+(simple-service 'oci-grafana-service
+                (list
+                 (oci-container-configuration
+                  (image "prom/prometheus")
+                  (network "host")
+                  (ports
+                    '(("9000" . "9000")
+                      ("9090" . "9090"))))))
+                 (oci-container-configuration
+                  (image "grafana/grafana:10.0.1")
+                  (network "host")
+                  (volumes
+                    '("/var/lib/grafana:/var/lib/grafana"))))))
+@end lisp
+
+@end defvar
+
+@deftp {Data Type} oci-container-configuration
+Available @code{oci-container-configuration} fields are:
+
+@table @asis
+@item @code{command} (default: @code{()}) (type: list-of-strings)
+Overwrite the default CMD of the image.
+
+@item @code{entrypoint} (default: @code{""}) (type: string)
+Overwrite the default ENTRYPOINT of the image.
+
+@item @code{environment} (default: @code{()}) (type: list)
+Set environment variables. This can be a list of pairs or strings, even mixed:
+
+@lisp
+(list '("LANGUAGE" . "eo:ca:eu")
+      "JAVA_HOME=/opt/java")
+@end lisp
+
+@item @code{image} (type: string)
+The image used to build the container.
+
+@item @code{name} (default: @code{""}) (type: string)
+Set a name for the spawned container.
+
+@item @code{network} (default: @code{""}) (type: string)
+Set a Docker network for the spawned container.
+
+@item @code{ports} (default: @code{()}) (type: list)
+Set the port or port ranges to expose from the spawned container. This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("8080" . "80")
+      "10443:443")
+@end lisp
+
+@item @code{volumes} (default: @code{()}) (type: list)
+Set volume mappings for the spawned container. This can be a
+list of pairs or strings, even mixed:
+
+@lisp
+(list '("/root/data/grafana" . "/var/lib/grafana")
+      "/gnu/store:/gnu/store")
+@end lisp
+
+@end table
+@end deftp
+
 @cindex Audit
 @subsubheading Auditd Service
 
diff --git a/gnu/services/docker.scm b/gnu/services/docker.scm
index c2023d618c..8a4fa2107e 100644
--- a/gnu/services/docker.scm
+++ b/gnu/services/docker.scm
@@ -5,6 +5,7 @@
 ;;; Copyright © 2020 Efraim Flashner <efraim@HIDDEN>
 ;;; Copyright © 2020 Jesse Dowell <jessedowell@HIDDEN>
 ;;; Copyright © 2021 Brice Waegeneire <brice@HIDDEN>
+;;; Copyright © 2023 Giacomo Leidi <goodoldpaul@HIDDEN>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -34,10 +35,25 @@ (define-module (gnu services docker)
   #:use-module (guix records)
   #:use-module (guix gexp)
   #:use-module (guix packages)
+  #:use-module (srfi srfi-1)
+  #:use-module (ice-9 format)
 
   #:export (docker-configuration
             docker-service-type
-            singularity-service-type))
+            singularity-service-type
+            oci-container-configuration
+            oci-container-configuration?
+            oci-container-configuration-fields
+            oci-container-configuration-command
+            oci-container-configuration-entrypoint
+            oci-container-configuration-environment
+            oci-container-configuration-image
+            oci-container-configuration-name
+            oci-container-configuration-network
+            oci-container-configuration-ports
+            oci-container-configuration-volumes
+            oci-container-service-type
+            oci-container-shepherd-service))
 
 (define-configuration docker-configuration
   (docker
@@ -216,3 +232,148 @@ (define singularity-service-type
                        (service-extension activation-service-type
                                           (const %singularity-activation))))
                 (default-value singularity)))
+
+
+;;;
+;;; OCI container.
+;;;
+
+(define (oci-sanitize-pair pair delimiter)
+  (cond ((file-like? (car pair))
+         (file-append (car pair) delimiter (cdr pair)))
+        ((gexp? (car pair))
+         (file-append (car pair) delimiter (cdr pair)))
+        ((string? (car pair))
+         (string-append (car pair) delimiter (cdr pair)))
+        (else
+         (error
+          (format #f "pair members must only contain gexps, file-like objects and strings but ~a was found" (car pair))))))
+
+(define (oci-sanitize-mixed-list name value delimiter)
+  (map
+   (lambda (el)
+     (cond ((string? el) el)
+           ((pair? el) (oci-sanitize-pair el delimiter))
+           (else
+            (error
+             (format #f "~a members must be either a string or a pair but ~a was found!" name el)))))
+   value))
+
+(define (oci-sanitize-environment value)
+  ;; Expected spec format:
+  ;; '(("HOME" . "/home/nobody") "JAVA_HOME=/java")
+  (oci-sanitize-mixed-list "environment" value "="))
+
+(define (oci-sanitize-ports value)
+  ;; Expected spec format:
+  ;; '(("8088" . "80") "2022:22")
+  (oci-sanitize-mixed-list "ports" value ":"))
+
+(define (oci-sanitize-volumes value)
+  ;; Expected spec format:
+  ;; '(("/mnt/dir" . "/dir") "/run/current-system/profile:/java")
+  (oci-sanitize-mixed-list "volumes" value ":"))
+
+(define-configuration/no-serialization oci-container-configuration
+  (command
+   (list-of-strings '())
+   "Overwrite the default CMD of the image.")
+  (entrypoint
+   (string "")
+   "Overwrite the default ENTRYPOINT of the image.")
+  (environment
+   (list '())
+   "Set environment variables."
+   (sanitizer oci-sanitize-environment))
+  (image
+   (string)
+   "The image used to build the container.")
+  (name
+   (string "")
+   "Set a name for the spawned container.")
+  (network
+   (string "")
+   "Set a Docker network for the spawned container.")
+  (ports
+   (list '())
+   "Set the port or port ranges to expose from the spawned container."
+   (sanitizer oci-sanitize-ports))
+  (volumes
+   (list '())
+   "Set volume mappings for the spawned container."
+   (sanitizer oci-sanitize-volumes)))
+
+(define oci-container-configuration->options
+  (lambda (config)
+    (let ((entrypoint
+           (oci-container-configuration-entrypoint config))
+          (network
+           (oci-container-configuration-network config)))
+      (apply append
+             (filter (compose not unspecified?)
+                     `(,(when (not (string-null? entrypoint))
+                          (list "--entrypoint" entrypoint))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "--env" spec))
+                         (oci-container-configuration-environment config))
+                       ,(when (not (string-null? network))
+                          (list "--network" network))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-p" spec))
+                         (oci-container-configuration-ports config))
+                       ,(append-map
+                         (lambda (spec)
+                           (list "-v" spec))
+                         (oci-container-configuration-volumes config))))))))
+
+(define (oci-container-shepherd-service config)
+  (define (guess-name name image)
+    (if (not (string-null? name))
+        name
+        (string-append "docker-"
+                       (basename (car (string-split image #\:))))))
+
+  (let* ((docker-command (file-append docker-cli "/bin/docker"))
+         (config-name (oci-container-configuration-name config))
+         (image (oci-container-configuration-image config))
+         (name (guess-name config-name image)))
+
+    (shepherd-service (provision `(,(string->symbol name)))
+                      (requirement '(dockerd))
+                      (respawn? #f)
+                      (documentation
+                       (string-append
+                        "Docker backed Shepherd service for image: " image))
+                      (start
+                       #~(make-forkexec-constructor
+                          ;; docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
+                          (list #$docker-command
+                                "run"
+                                "--rm"
+                                "--name" #$name
+                                #$@(oci-container-configuration->options config)
+                                #$(oci-container-configuration-image config)
+                                #$@(oci-container-configuration-command config))
+                          #:user "root"
+                          #:group "root"))
+                      (stop
+                       #~(lambda _
+                           (invoke #$docker-command "stop" #$name))))))
+
+(define (configs->shepherd-services configs)
+  (map oci-container-shepherd-service configs))
+
+(define oci-container-service-type
+  (service-type (name 'oci-container)
+                (extensions (list (service-extension profile-service-type
+                                                     (lambda _ (list docker-cli)))
+                                  (service-extension shepherd-root-service-type
+                                                     configs->shepherd-services)))
+                (default-value '())
+                (extend append)
+                (compose concatenate)
+                (description
+                 "This service provides allows the management of Docker
+containers as Shepherd services.")))

base-commit: f45c0c82289d409b4fac00464ea8b323839ba53f
-- 
2.41.0





Information forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 22 Sep 2023 20:33:11 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Sep 22 16:33:11 2023
Received: from localhost ([127.0.0.1]:37332 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1qjmpq-0003iH-KD
	for submit <at> debbugs.gnu.org; Fri, 22 Sep 2023 16:33:10 -0400
Received: from lists.gnu.org ([2001:470:142::17]:41876)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <goodoldpaul@HIDDEN>) id 1qjmpm-0003hl-DG
 for submit <at> debbugs.gnu.org; Fri, 22 Sep 2023 16:33:09 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <goodoldpaul@HIDDEN>)
 id 1qjmpW-0000BS-6x
 for guix-patches@HIDDEN; Fri, 22 Sep 2023 16:32:50 -0400
Received: from confino.investici.org ([93.190.126.19])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <goodoldpaul@HIDDEN>)
 id 1qjmpT-0000hq-KY
 for guix-patches@HIDDEN; Fri, 22 Sep 2023 16:32:49 -0400
Received: from mx1.investici.org (unknown [127.0.0.1])
 by confino.investici.org (Postfix) with ESMTP id 4RskV42RnLz114x
 for <guix-patches@HIDDEN>; Fri, 22 Sep 2023 20:32:44 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=autistici.org;
 s=stigmate; t=1695414764;
 bh=bIfV90To134UdrsaFGyp2qAvqI+9FJQYSz1Oi298+dg=;
 h=Date:To:From:Subject:From;
 b=b1Vm30b4fwv1xmPtvZsicTDYTMqAD8mTif1PPOHo3gJpqeCW1GaCiQ+kksvDgpKHG
 NJRpKuoszxFs07706evrAXvNrGG/NopU27vWXkUtxcONdu5/caN+uufVoCtwU/4Bo0
 PU9lvrKxT1ZtFJXFioRgJBQ3tY8fUyxqPjYAkgxw=
Received: from [93.190.126.19] (mx1.investici.org [93.190.126.19])
 (Authenticated sender: goodoldpaul@HIDDEN) by localhost (Postfix) with
 ESMTPSA id 4RskV41vTkz114v
 for <guix-patches@HIDDEN>; Fri, 22 Sep 2023 20:32:44 +0000 (UTC)
Message-ID: <650a02e2-9425-a7fd-2014-7cf6e17ee65b@HIDDEN>
Date: Fri, 22 Sep 2023 22:32:43 +0200
MIME-Version: 1.0
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
 Thunderbird/102.15.0
To: guix-patches@HIDDEN
Content-Language: en-US
From: paul <goodoldpaul@HIDDEN>
Subject: [PATCH] gnu: Add oci-container-service-type.
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Received-SPF: pass client-ip=93.190.126.19;
 envelope-from=goodoldpaul@HIDDEN; helo=confino.investici.org
X-Spam_score_int: -20
X-Spam_score: -2.1
X-Spam_bar: --
X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_PASS=-0.001,
 SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 0.9 (/)
X-Debbugs-Envelope-To: submit
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.1 (/)

Dear Guixers,

following up on 
https://lists.gnu.org/archive/html/guix-devel/2023-09/msg00468.html , 
I'm sending the implementation for the oci-backed shepherd services.

Thank you for your time,

giacomo





Acknowledgement sent to paul <goodoldpaul@HIDDEN>:
New bug report received and forwarded. Copy sent to guix-patches@HIDDEN. Full text available.
Report forwarded to guix-patches@HIDDEN:
bug#66160; Package guix-patches. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Thu, 23 Nov 2023 10:15:01 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.