[elbe-devel] [PATCH] initvmaction: Add clone action

Olivier Dion dion at linutronix.de
Wed May 20 04:26:40 CEST 2020


The command allows to clone an existing initvm and register it to new
libvirt domain.  The usage is 'elbe initvm [options] clone
<initvm-dir>.  As a result, a new initvm is created backend by the
existing one.

The command start by checking that the root initvm directory has the
libvirt.xml and buildenv.img.

Then, the libvirt.xml is copied from the root to the new initvm.  It's
then sed to change to hardcoded path and uuid.

Then, the buildenv.img is created using qemu-img in COW semantic,
resulting in a much smaller image for the cloned initvm.

Finally, the new initvm is register to libvirt using the default
domain name ELB_INITVM_DOMAIN.

Signed-off-by: Olivier Dion <dion at linutronix.de>
---
 elbepack/initvmaction.py | 72 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/elbepack/initvmaction.py b/elbepack/initvmaction.py
index f8572402..4cabfd3d 100644
--- a/elbepack/initvmaction.py
+++ b/elbepack/initvmaction.py
@@ -14,6 +14,8 @@ import sys
 import time
 import os
 import datetime
+import shutil
+import uuid
 
 import libvirt
 
@@ -643,3 +645,73 @@ class SubmitAction(InitVMAction):
             submit_and_dl_result(xmlfile, cdrom, opt)
 
 InitVMAction.register(SubmitAction)
+
+class CloneAction(InitVMAction):
+
+    tag = 'clone'
+
+    def __init__(self, node):
+        InitVMAction.__init__(self, node, initvmNeeded=False)
+
+    def no_overwrite(self, path):
+        if os.path.exists(path):
+            print("%s already exists! I'm not overwriting it!" % path)
+            sys.exit(20)
+
+    def execute(self, initvm_dir, _opt, args):
+
+        if len(args) != 1:
+            print("usage: elbe initvm [options] clone <initvm>")
+            sys.exit(20)
+
+        root = args[0]
+
+        src_xml = os.path.join(root, "libvirt.xml")
+        src_img = os.path.join(root, "buildenv.img")
+
+        for f in (src_xml, src_img):
+            if not os.path.exists(f):
+                print("Missing %s in initvm %s" % (os.path.basename(f), root))
+                sys.exit(20)
+
+        # TODO:py3 - Use exist_ok=True instead of catching exception
+        try:
+            os.makedirs(initvm_dir)
+        except FileExistsError:
+            pass
+
+        dst_xml = os.path.join(initvm_dir, "libvirt.xml")
+        dst_img = os.path.join(initvm_dir, "buildenv.img")
+
+        # Copy libvirt.xml
+        self.no_overwrite(dst_xml)
+        shutil.copyfile(src_xml, dst_xml)
+
+        # Apply sed to libvirt.xml
+        exprs = ["s|%s|%s|g" % (src_img, dst_img),
+                 "s|<uuid>.*</uuid>|<uuid>%s</uuid>|" % uuid.uuid4(),
+                 "s|<name>.*</name>|<name>%s</name>|" % cfg["initvm_domain"]]
+        args = []
+        for e in exprs:
+            args.append("-e")
+            args.append("'%s'" % e)
+
+        system("sed -i %s %s" % (" ".join(args), dst_xml))
+
+        # Copy QEMU image
+        self.no_overwrite(dst_img)
+        system('qemu-img create -f qcow2 -F qcow2 -b "%s" "%s"' %
+               (src_img, dst_img))
+
+        # Register new initvm to libvirt
+        with open(dst_xml) as f:
+            xml = f.read()
+            try:
+                self.conn.defineXML(xml)
+            except libvirt.libvirtError:
+                print('Registering initvm in libvirt failed', file=sys.stderr)
+                print('Try `virsh --connect qemu:///system undefine %s` to delete existing initvm' % cfg['initvm_domain'],
+                      file=sys.stderr)
+                sys.exit(20)
+
+InitVMAction.register(CloneAction)
-- 
2.26.2




More information about the elbe-devel mailing list