Add lxd service

  • Open
  • quality assurance status badge
Details
3 participants
  • Ludovic Courtès
  • Vagrant Cascadian
  • Andrew Whatson
Owner
unassigned
Submitted by
Andrew Whatson
Severity
normal
A
A
Andrew Whatson wrote on 20 Aug 2021 14:43
[PATCH 0/6] Add lxd package and service.
(address . guix-patches@gnu.org)
CAPE069d6GfVhv_DDZSa3TzaEBturRG99SsT=9WCuLLYvpugTkA@mail.gmail.com
Andrew Whatson (6):
gnu: libraft: Update to 0.11.2.
gnu: libdqlite: Update to 1.9.0.
gnu: lxc: Update to 4.0.10.
gnu: lxcfs: Update to 4.0.9.
gnu: Add lxd.
services: Add lxd-service-type.

gnu/packages/cluster.scm | 12 +--
gnu/packages/virtualization.scm | 121 ++++++++++++++++++++++++++++++--
gnu/services/virtualization.scm | 66 +++++++++++++++++
gnu/system/file-systems.scm | 11 ++
4 files changed, 201 insertions(+), 9 deletions(-)
A
A
Andrew Whatson wrote on 20 Aug 2021 14:45
[PATCH 1/6] gnu: libraft: Update to 0.11.2.
(address . 50133@debbugs.gnu.org)(name . Andrew Whatson)(address . whatson@gmail.com)
20210820124524.117090-1-whatson@gmail.com
* gnu/packages/cluster.scm (libraft): Update to 0.11.2.
[inputs]: Add lz4.
---
gnu/packages/cluster.scm | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

Toggle diff (42 lines)
diff --git a/gnu/packages/cluster.scm b/gnu/packages/cluster.scm
index e643cc58f9..5464c6dd4d 100644
--- a/gnu/packages/cluster.scm
+++ b/gnu/packages/cluster.scm
@@ -28,6 +28,7 @@
#:use-module (guix packages)
#:use-module (gnu packages autotools)
#:use-module (gnu packages check)
+ #:use-module (gnu packages compression)
#:use-module (gnu packages flex)
#:use-module (gnu packages gettext)
#:use-module (gnu packages libevent)
@@ -188,7 +189,7 @@ independently or together to provide resilient infrastructures.")
(define-public libraft
(package
(name "libraft")
- (version "0.10.1")
+ (version "0.11.2")
(home-page "https://github.com/canonical/raft")
(source (origin
(method git-fetch)
@@ -197,7 +198,7 @@ independently or together to provide resilient infrastructures.")
(file-name (git-file-name name version))
(sha256
(base32
- "18idj53vnl5fx1ja1zlp8kiwmdxgwjxsi88rdql0pbh0484b92a3"))))
+ "050dwy34jh8dihfwfm0r1by2i3sy9crapipp9idw32idm79y4izb"))))
(arguments '(#:configure-flags '("--enable-uv")
#:phases
(modify-phases %standard-phases
@@ -207,7 +208,8 @@ independently or together to provide resilient infrastructures.")
((".*test_uv_append.c.*") ""))
#t)))))
(inputs
- `(("libuv" ,libuv)))
+ `(("libuv" ,libuv)
+ ("lz4" ,lz4)))
(native-inputs
`(("autoconf" ,autoconf)
("automake" ,automake)
--
2.32.0
A
A
Andrew Whatson wrote on 20 Aug 2021 14:45
[PATCH 2/6] gnu: libdqlite: Update to 1.9.0.
(address . 50133@debbugs.gnu.org)(name . Andrew Whatson)(address . whatson@gmail.com)
20210820124524.117090-2-whatson@gmail.com
* gnu/packages/cluster.scm (libdqlite): Update to 1.9.0.
---
gnu/packages/cluster.scm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

Toggle diff (24 lines)
diff --git a/gnu/packages/cluster.scm b/gnu/packages/cluster.scm
index 5464c6dd4d..2de5f6fe36 100644
--- a/gnu/packages/cluster.scm
+++ b/gnu/packages/cluster.scm
@@ -228,7 +228,7 @@ snapshots).")
(define-public libdqlite
(package
(name "libdqlite")
- (version "1.7.0")
+ (version "1.9.0")
(home-page "https://github.com/canonical/dqlite")
(source (origin
(method git-fetch)
@@ -237,7 +237,7 @@ snapshots).")
(file-name (git-file-name name version))
(sha256
(base32
- "15cg8yl3n7lcg0qyg0byciz8v6y200ghmzzkwpdzggy3m6c168wl"))))
+ "0zalsvr0vy7632nhm96a29lrfy18iqsmbxpyz2lvq80mrjlbrzsn"))))
(arguments
'(#:phases
(modify-phases %standard-phases
--
2.32.0
A
A
Andrew Whatson wrote on 20 Aug 2021 14:45
[PATCH 3/6] gnu: lxc: Update to 4.0.10.
(address . 50133@debbugs.gnu.org)(name . Andrew Whatson)(address . whatson@gmail.com)
20210820124524.117090-3-whatson@gmail.com
* gnu/packages/virtualization.scm (lxc): Update to 4.0.10.
---
gnu/packages/virtualization.scm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

Toggle diff (24 lines)
diff --git a/gnu/packages/virtualization.scm b/gnu/packages/virtualization.scm
index 1bbcb46b99..0919ef7785 100644
--- a/gnu/packages/virtualization.scm
+++ b/gnu/packages/virtualization.scm
@@ -997,7 +997,7 @@ all common programming languages. Vala bindings are also provided.")
(define-public lxc
(package
(name "lxc")
- (version "4.0.6")
+ (version "4.0.10")
(source (origin
(method url-fetch)
(uri (string-append
@@ -1005,7 +1005,7 @@ all common programming languages. Vala bindings are also provided.")
version ".tar.gz"))
(sha256
(base32
- "0qz4l7mlhq7hx53q606qgvkyzyr01glsw290v8ppzvxn1fydlrci"))))
+ "1sgsic9dzj3wv2k5bx2vhcgappivhp1glkqfc2yrgr6jas052351"))))
(build-system gnu-build-system)
(native-inputs
`(("pkg-config" ,pkg-config)))
--
2.32.0
A
A
Andrew Whatson wrote on 20 Aug 2021 14:45
[PATCH 4/6] gnu: lxcfs: Update to 4.0.9.
(address . 50133@debbugs.gnu.org)(name . Andrew Whatson)(address . whatson@gmail.com)
20210820124524.117090-4-whatson@gmail.com
* gnu/packages/virtualization.scm (lxcfs): Update to 4.0.9.
---
gnu/packages/virtualization.scm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

Toggle diff (24 lines)
diff --git a/gnu/packages/virtualization.scm b/gnu/packages/virtualization.scm
index 0919ef7785..07ad1cb101 100644
--- a/gnu/packages/virtualization.scm
+++ b/gnu/packages/virtualization.scm
@@ -1044,7 +1044,7 @@ manage system or application containers.")
(define-public lxcfs
(package
(name "lxcfs")
- (version "4.0.8")
+ (version "4.0.9")
(home-page "https://github.com/lxc/lxcfs")
(source (origin
(method git-fetch)
@@ -1053,7 +1053,7 @@ manage system or application containers.")
(file-name (git-file-name name version))
(sha256
(base32
- "1f74wy88si2ia035pcvciq5821kc8jcb75w1f8vhbp0cd29rqdpi"))))
+ "0zx58lair8hwi4bxm5h7i8n1j5fcdgw5cr6f4wk9qhks0sr5dip5"))))
(arguments
'(#:configure-flags '("--localstatedir=/var")))
(native-inputs
--
2.32.0
A
A
Andrew Whatson wrote on 20 Aug 2021 14:45
[PATCH 5/6] gnu: Add lxd.
(address . 50133@debbugs.gnu.org)(name . Andrew Whatson)(address . whatson@gmail.com)
20210820124524.117090-5-whatson@gmail.com
* gnu/packages/virtualization.scm (lxd): New variable.
---
gnu/packages/virtualization.scm | 113 ++++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)

Toggle diff (147 lines)
diff --git a/gnu/packages/virtualization.scm b/gnu/packages/virtualization.scm
index 07ad1cb101..da130d1e9d 100644
--- a/gnu/packages/virtualization.scm
+++ b/gnu/packages/virtualization.scm
@@ -20,6 +20,7 @@
;;; Copyright © 2021 Leo Famulari <leo@famulari.name>
;;; Copyright © 2021 Pierre Langlois <pierre.langlois@gmx.com>
;;; Copyright © 2021 Dion Mendel <guix@dm9.info>
+;;; Copyright © 2021 Andrew Whatson <whatson@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -49,6 +50,7 @@
#:use-module (gnu packages bison)
#:use-module (gnu packages build-tools)
#:use-module (gnu packages check)
+ #:use-module (gnu packages cluster)
#:use-module (gnu packages cmake)
#:use-module (gnu packages compression)
#:use-module (gnu packages cross-base)
@@ -102,6 +104,7 @@
#:use-module (gnu packages python-xyz)
#:use-module (gnu packages pulseaudio)
#:use-module (gnu packages readline)
+ #:use-module (gnu packages rsync)
#:use-module (gnu packages selinux)
#:use-module (gnu packages sdl)
#:use-module (gnu packages sphinx)
@@ -1070,6 +1073,116 @@ of making Linux containers feel more like a virtual machine.
It started as a side project of LXC but can be used by any run-time.")
(license license:lgpl2.1+)))
+(define-public lxd
+ (package
+ (name "lxd")
+ (version "4.17")
+ (source (origin
+ (method url-fetch)
+ (uri (string-append
+ "https://github.com/lxc/lxd/releases/download/"
+ "lxd-" version "/lxd-" version ".tar.gz"))
+ (sha256
+ (base32
+ "1kzmgyg5kw3zw9qa6jabld6rmb53b6yy69h7y9znsdlf74jllljl"))))
+ (build-system go-build-system)
+ (arguments
+ `(#:import-path "github.com/lxc/lxd"
+ #:tests? #f ;; tests fail due to missing /var, cgroups, etc.
+ #:modules ((guix build go-build-system)
+ (guix build union)
+ (guix build utils)
+ (srfi srfi-1))
+ #:phases
+ (modify-phases %standard-phases
+ (add-after 'unpack 'unpack-dist
+ (lambda* (#:key import-path #:allow-other-keys)
+ (with-directory-excursion (string-append "src/" import-path)
+ ;; remove the link back to the top level
+ (delete-file (string-append "_dist/src/" import-path))
+ ;; move all the deps into the src directory
+ (copy-recursively "_dist/src" "../../.."))
+ #t))
+ (replace 'build
+ (lambda* (#:key import-path #:allow-other-keys)
+ (with-directory-excursion (string-append "src/" import-path)
+ (invoke "make" "build" "CC=gcc" "TAG_SQLITE3=libsqlite3")
+ #t)))
+ (replace 'check
+ (lambda* (#:key tests? import-path #:allow-other-keys)
+ (when tests?
+ (with-directory-excursion (string-append "src/" import-path)
+ (invoke "make" "check" "CC=gcc" "TAG_SQLITE3=libsqlite3")))
+ #t))
+ (replace 'install
+ (lambda* (#:key inputs outputs import-path #:allow-other-keys)
+ (let* ((out (assoc-ref outputs "out"))
+ (bin-dir
+ (string-append out "/bin/"))
+ (doc-dir
+ (string-append out "/share/doc/lxd-" ,version))
+ (completions-dir
+ (string-append out "/share/bash-completion/completions")))
+ (with-directory-excursion (string-append "src/" import-path)
+ ;; wrap lxd with runtime dependencies
+ (wrap-program (string-append bin-dir "lxd")
+ `("PATH" ":" prefix
+ ,(fold (lambda (input paths)
+ (let* ((in (assoc-ref inputs input))
+ (bin (string-append in "/bin"))
+ (sbin (string-append in "/sbin")))
+ (append (filter file-exists?
+ (list bin sbin)) paths)))
+ '()
+ '("bash" "acl" "rsync" "tar" "xz" "btrfs-progs"
+ "gzip" "dnsmasq" "squashfs-tools" "iproute2"
+ "criu" "iptables"))))
+ ;; remove unwanted binaries
+ (for-each (lambda (prog)
+ (delete-file (string-append bin-dir prog)))
+ '("deps" "macaroon-identity" "generate"))
+ ;; install documentation
+ (for-each (lambda (file)
+ (install-file file doc-dir))
+ (find-files "doc"))
+ ;; install bash completion
+ (rename-file "scripts/bash/lxd-client" "scripts/bash/lxd")
+ (install-file "scripts/bash/lxd" completions-dir)))
+ #t)))))
+ (native-inputs
+ `(;; test dependencies:
+ ;; ("go-github-com-rogpeppe-godeps" ,go-github-com-rogpeppe-godeps)
+ ;; ("go-github-com-tsenart-deadcode" ,go-github-com-tsenart-deadcode)
+ ;; ("go-golang-org-x-lint" ,go-golang-org-x-lint)
+ ("pkg-config" ,pkg-config)))
+ (inputs
+ `(("acl" ,acl)
+ ("eudev" ,eudev)
+ ("libdqlite" ,libdqlite)
+ ("libraft" ,libraft)
+ ("libcap" ,libcap)
+ ("lxc" ,lxc)
+ ;; runtime dependencies:
+ ("bash" ,bash-minimal)
+ ("rsync" ,rsync)
+ ("tar" ,tar)
+ ("xz" ,xz)
+ ("btrfs-progs" ,btrfs-progs)
+ ("gzip" ,gzip)
+ ("dnsmasq" ,dnsmasq)
+ ("squashfs-tools" ,squashfs-tools)
+ ("iproute2" ,iproute)
+ ("criu" ,criu)
+ ("iptables" ,iptables)))
+ (synopsis "Daemon based on liblxc offering a REST API to manage containers")
+ (home-page "https://linuxcontainers.org/lxd/")
+ (description "LXD is a next generation system container manager. It
+offers a user experience similar to virtual machines but using Linux
+containers instead. It's image based with pre-made images available for a
+wide number of Linux distributions and is built around a very powerful, yet
+pretty simple, REST API.")
+ (license license:asl2.0)))
+
(define-public libvirt
(package
(name "libvirt")
--
2.32.0
A
A
Andrew Whatson wrote on 20 Aug 2021 14:45
[PATCH 6/6] services: Add lxd-service-type.
(address . 50133@debbugs.gnu.org)(name . Andrew Whatson)(address . whatson@gmail.com)
20210820124524.117090-6-whatson@gmail.com
* gnu/services/virtualization.scm (lxd-configuration): New type.
(%lxd-accounts, lxd-service-type): New variables.
(%lxd-activation, lxd-shepherd-service): New procedures.
* gnu/system/file-systems.scm (%elogind-file-systems): Add
"/sys/fs/cgroup/systemd" file-system.
---
gnu/services/virtualization.scm | 66 +++++++++++++++++++++++++++++++++
gnu/system/file-systems.scm | 11 ++++++
2 files changed, 77 insertions(+)

Toggle diff (108 lines)
diff --git a/gnu/services/virtualization.scm b/gnu/services/virtualization.scm
index c8adcd06d0..34ddc94423 100644
--- a/gnu/services/virtualization.scm
+++ b/gnu/services/virtualization.scm
@@ -75,6 +75,9 @@
virtlog-configuration
virtlog-service-type
+ lxd-configuration
+ lxd-service-type
+
%qemu-platforms
lookup-qemu-platforms
qemu-platform?
@@ -548,6 +551,69 @@ potential infinite waits blocking libvirt."))
`((libvirt-configuration ,libvirt-configuration-fields))
'libvirt-configuration))
+
+;;;
+;;; LXD linux container daemon.
+;;;
+
+(define-configuration lxd-configuration
+ (lxd
+ (package lxd)
+ "LXD package.")
+ (debug?
+ (boolean #f)
+ "Enable or disable debug messages.")
+ (verbose?
+ (boolean #f)
+ "Enable or disable information messages."))
+
+(define %lxd-accounts
+ (list (user-group (name "lxd") (system? #t))))
+
+(define (%lxd-activation config)
+ #~(begin
+ (use-modules (guix build utils))
+ (mkdir-p "/var/log/lxd")))
+
+(define (lxd-shepherd-service config)
+ (let* ((lxd (lxd-configuration-lxd config))
+ (debug? (lxd-configuration-debug? config))
+ (verbose? (lxd-configuration-verbose? config)))
+ (list
+ (shepherd-service
+ (documentation "LXD daemon.")
+ (provision '(lxd))
+ (requirement '(dbus-system
+ elogind
+ file-system-/sys/fs/cgroup/blkio
+ file-system-/sys/fs/cgroup/cpu
+ file-system-/sys/fs/cgroup/cpuset
+ file-system-/sys/fs/cgroup/devices
+ file-system-/sys/fs/cgroup/memory
+ file-system-/sys/fs/cgroup/pids
+ file-system-/sys/fs/cgroup/systemd
+ networking
+ udev))
+ (start #~(make-forkexec-constructor
+ (list (string-append #$lxd "/bin/lxd")
+ "--group=lxd"
+ "--logfile=/var/log/lxd/lxd.log"
+ #$@(if debug? '("--debug") '())
+ #$@(if verbose? '("--verbose") '()))))
+ (stop #~(make-kill-destructor))))))
+
+(define lxd-service-type
+ (service-type
+ (name 'lxd)
+ (extensions
+ (list (service-extension activation-service-type
+ %lxd-activation)
+ (service-extension shepherd-root-service-type
+ lxd-shepherd-service)
+ (service-extension account-service-type
+ (const %lxd-accounts))))
+ (default-value (lxd-configuration))))
+
;;;
;;; Transparent QEMU emulation via binfmt_misc.
diff --git a/gnu/system/file-systems.scm b/gnu/system/file-systems.scm
index b9eda80958..7c3777298b 100644
--- a/gnu/system/file-systems.scm
+++ b/gnu/system/file-systems.scm
@@ -499,6 +499,17 @@ TARGET in the other system."
(check? #f)
(options "none,name=elogind")
(create-mount-point? #t)
+ (dependencies (list (car %control-groups))))
+ ;; The systemd cgroup needs to exist to run systemd inside linux
+ ;; containers (eg. via LXD). This is *not* required for elogind, but
+ ;; keeping it with the other systemd hacks seemed sensible, for now.
+ (file-system
+ (device "cgroup")
+ (mount-point "/sys/fs/cgroup/systemd")
+ (type "cgroup")
+ (check? #f)
+ (options "none,name=systemd")
+ (create-mount-point? #t)
(dependencies (list (car %control-groups)))))
%control-groups))
--
2.32.0
L
L
Ludovic Courtès wrote on 28 Sep 2021 15:42
Re: bug#50133: [PATCH 0/6] Add lxd package and service.
(name . Andrew Whatson)(address . whatson@gmail.com)(address . 50133@debbugs.gnu.org)
87ee98akb7.fsf_-_@gnu.org
Hi Andrew,

The whole series LGTM and I’ve already applied patch 1–5.

Some comments below about the service:

Andrew Whatson <whatson@gmail.com> skribis:

Toggle quote (6 lines)
> * gnu/services/virtualization.scm (lxd-configuration): New type.
> (%lxd-accounts, lxd-service-type): New variables.
> (%lxd-activation, lxd-shepherd-service): New procedures.
> * gnu/system/file-systems.scm (%elogind-file-systems): Add
> "/sys/fs/cgroup/systemd" file-system.

[...]

Toggle quote (12 lines)
> +(define lxd-service-type
> + (service-type
> + (name 'lxd)
> + (extensions
> + (list (service-extension activation-service-type
> + %lxd-activation)
> + (service-extension shepherd-root-service-type
> + lxd-shepherd-service)
> + (service-extension account-service-type
> + (const %lxd-accounts))))
> + (default-value (lxd-configuration))))

Please add a ‘description’ field.

Toggle quote (21 lines)
> index b9eda80958..7c3777298b 100644
> --- a/gnu/system/file-systems.scm
> +++ b/gnu/system/file-systems.scm
> @@ -499,6 +499,17 @@ TARGET in the other system."
> (check? #f)
> (options "none,name=elogind")
> (create-mount-point? #t)
> + (dependencies (list (car %control-groups))))
> + ;; The systemd cgroup needs to exist to run systemd inside linux
> + ;; containers (eg. via LXD). This is *not* required for elogind, but
> + ;; keeping it with the other systemd hacks seemed sensible, for now.
> + (file-system
> + (device "cgroup")
> + (mount-point "/sys/fs/cgroup/systemd")
> + (type "cgroup")
> + (check? #f)
> + (options "none,name=systemd")
> + (create-mount-point? #t)
> (dependencies (list (car %control-groups)))))
> %control-groups))

Instead of adding it here, how about extending
‘file-system-service-type’ instead, similar to what
‘qemu-binfmt-service-type’ does? That way, the extra requirement would
be limited to LXD.

Two other things, could you add:

1. documentation in the manual under “Virtualization Services”, with a
commented config example?

2. (ideally) a system test to ensure that the basics of the service
are working?

TIA!

Ludo’.
V
V
Vagrant Cascadian wrote on 2 Sep 2023 08:01
Re: [bug#50133] [PATCH 0/6] Add lxd package and service.
87cyz1nmfq.fsf@wireframe
retitle 50133 Add lxd service
thanks

On 2021-09-28, Ludovic Courtès wrote:
Toggle quote (2 lines)
> The whole series LGTM and I’ve already applied patch 1–5.

Retitling as the only outstanding issue is the lxd service.


Toggle quote (61 lines)
> Some comments below about the service:
>
> Andrew Whatson <whatson@gmail.com> skribis:
>
>> * gnu/services/virtualization.scm (lxd-configuration): New type.
>> (%lxd-accounts, lxd-service-type): New variables.
>> (%lxd-activation, lxd-shepherd-service): New procedures.
>> * gnu/system/file-systems.scm (%elogind-file-systems): Add
>> "/sys/fs/cgroup/systemd" file-system.
>
> [...]
>
>> +(define lxd-service-type
>> + (service-type
>> + (name 'lxd)
>> + (extensions
>> + (list (service-extension activation-service-type
>> + %lxd-activation)
>> + (service-extension shepherd-root-service-type
>> + lxd-shepherd-service)
>> + (service-extension account-service-type
>> + (const %lxd-accounts))))
>> + (default-value (lxd-configuration))))
>
> Please add a ‘description’ field.
>
>> index b9eda80958..7c3777298b 100644
>> --- a/gnu/system/file-systems.scm
>> +++ b/gnu/system/file-systems.scm
>> @@ -499,6 +499,17 @@ TARGET in the other system."
>> (check? #f)
>> (options "none,name=elogind")
>> (create-mount-point? #t)
>> + (dependencies (list (car %control-groups))))
>> + ;; The systemd cgroup needs to exist to run systemd inside linux
>> + ;; containers (eg. via LXD). This is *not* required for elogind, but
>> + ;; keeping it with the other systemd hacks seemed sensible, for now.
>> + (file-system
>> + (device "cgroup")
>> + (mount-point "/sys/fs/cgroup/systemd")
>> + (type "cgroup")
>> + (check? #f)
>> + (options "none,name=systemd")
>> + (create-mount-point? #t)
>> (dependencies (list (car %control-groups)))))
>> %control-groups))
>
> Instead of adding it here, how about extending
> ‘file-system-service-type’ instead, similar to what
> ‘qemu-binfmt-service-type’ does? That way, the extra requirement would
> be limited to LXD.
>
> Two other things, could you add:
>
> 1. documentation in the manual under “Virtualization Services”, with a
> commented config example?
>
> 2. (ideally) a system test to ensure that the basics of the service
> are working?


live well,
vagrant
-----BEGIN PGP SIGNATURE-----

iHUEARYKAB0WIQRlgHNhO/zFx+LkXUXcUY/If5cWqgUCZPLPqQAKCRDcUY/If5cW
qrD8APwNEcCl5h5xqSMZMMppDGzGXdB8GyTnngeeaJSaSx4SzAD/QQjvJGTXJtRI
ZPovlsPzqLZfNCopCH3vkZEJ5tv3DQk=
=LZAr
-----END PGP SIGNATURE-----

?
Your comment

Commenting via the web interface is currently disabled.

To comment on this conversation send an email to 50133@debbugs.gnu.org

To respond to this issue using the mumi CLI, first switch to it
mumi current 50133
Then, you may apply the latest patchset in this issue (with sign off)
mumi am -- -s
Or, compose a reply to this issue
mumi compose
Or, send patches to this issue
mumi send-email *.patch