Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package virt-scenario for openSUSE:Factory checked in at 2023-06-07 23:07:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/virt-scenario (Old) and /work/SRC/openSUSE:Factory/.virt-scenario.new.15902 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "virt-scenario" Wed Jun 7 23:07:59 2023 rev:15 rq:1091283 version:2.0.8 Changes: -------- --- /work/SRC/openSUSE:Factory/virt-scenario/virt-scenario.changes 2023-06-06 19:58:03.499113220 +0200 +++ /work/SRC/openSUSE:Factory/.virt-scenario.new.15902/virt-scenario.changes 2023-06-07 23:08:38.659769216 +0200 @@ -1,0 +2,11 @@ +Wed Jun 7 14:45:00 UTC 2023 - Antoine Ginies <agin...@suse.com> + +- version 2.0.8: + * disk image encryption is now supported + * if image encryption is enabled the default mode will be + preparing Guest and Host as the secret uuid is needed + * overwrite mode delete previous domain on the hypervisor + to avoid any previous Guest XML definition + * clean up some code + +------------------------------------------------------------------- Old: ---- virt-scenario-2.0.7.tar.gz New: ---- virt-scenario-2.0.8.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ virt-scenario.spec ++++++ --- /var/tmp/diff_new_pack.ZGuYLs/_old 2023-06-07 23:08:39.207772398 +0200 +++ /var/tmp/diff_new_pack.ZGuYLs/_new 2023-06-07 23:08:39.211772421 +0200 @@ -20,7 +20,7 @@ %define pythons python3 Name: virt-scenario -Version: 2.0.7 +Version: 2.0.8 Release: 0 Summary: Tool to create XML guest configuration and prepare the host for a scenario License: GPL-3.0-or-later ++++++ virt-scenario-2.0.7.tar.gz -> virt-scenario-2.0.8.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/ChangeLog new/virt-scenario-2.0.8/ChangeLog --- old/virt-scenario-2.0.7/ChangeLog 2023-06-06 18:33:29.000000000 +0200 +++ new/virt-scenario-2.0.8/ChangeLog 2023-06-07 16:50:28.000000000 +0200 @@ -1,3 +1,73 @@ +2023-06-07 aginies + + add more info in overwrite mode + + +2023-06-07 aginies + + use uuid instead of susbsystem + + +2023-06-07 aginies + + overwrite delete prevoious domain on the hypervisor + + +2023-06-07 aginies + + add domain_list and remove_domain + + +2023-06-07 aginies + + add more info about overwrite + + +2023-06-07 aginies + + sync doc + + +2023-06-07 aginies + + various fixes to get encryption ok + + +2023-06-07 aginies + + disable encryption option for now + + +2023-06-07 aginies + + prepare 2.0.8 + + +2023-06-07 aginies + + various fixes for encryption support + + +2023-06-07 aginies + + add encryption to XML if needed + + +2023-06-07 aginies + + move get_qemu_img_uuid to util + + +2023-06-07 aginies + + add add_encryption support + + +2023-06-07 aginies + + add get_qemu_img_uuid + + 2023-06-06 aginies remove machine name in changelog diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/PKG-INFO new/virt-scenario-2.0.8/PKG-INFO --- old/virt-scenario-2.0.7/PKG-INFO 2023-06-06 18:33:29.000000000 +0200 +++ new/virt-scenario-2.0.8/PKG-INFO 2023-06-07 16:50:28.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: virt-scenario -Version: 2.0.7 +Version: 2.0.8 Summary: Virt-scenario Home-page: https://github.com/aginies/virt-scenario Author: Antoine Ginies @@ -21,6 +21,7 @@ IE: setting up a secure VM is not so easy from scratch, this tool will prepare the host, the XML guest config with secure parameter, and will deal with all the certificate, attestation and launch measurement. In only 2 commands you can start a secure VM on an AMD SEV system! + It also simplify the usage of disk Image encryption. Customization to match a specific scenario is not graved in stone. The idea is to prepare a configuration which should improved the usage compared to a basic setting. @@ -336,6 +337,7 @@ * Access host OS filesystem * AMD SEV * select right firmware for VM guest + * Disk Encryption ## Stuff currently immutable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/README.md new/virt-scenario-2.0.8/README.md --- old/virt-scenario-2.0.7/README.md 2023-06-06 13:53:27.000000000 +0200 +++ new/virt-scenario-2.0.8/README.md 2023-06-07 15:01:49.000000000 +0200 @@ -13,6 +13,7 @@ IE: setting up a secure VM is not so easy from scratch, this tool will prepare the host, the XML guest config with secure parameter, and will deal with all the certificate, attestation and launch measurement. In only 2 commands you can start a secure VM on an AMD SEV system! +It also simplify the usage of disk Image encryption. Customization to match a specific scenario is not graved in stone. The idea is to prepare a configuration which should improved the usage compared to a basic setting. @@ -328,6 +329,7 @@ * Access host OS filesystem * AMD SEV * select right firmware for VM guest +* Disk Encryption ## Stuff currently immutable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/man/virt-scenario.1 new/virt-scenario-2.0.8/man/virt-scenario.1 --- old/virt-scenario-2.0.7/man/virt-scenario.1 2023-06-06 18:26:25.000000000 +0200 +++ new/virt-scenario-2.0.8/man/virt-scenario.1 2023-06-07 15:01:58.000000000 +0200 @@ -34,6 +34,7 @@ prepare the host, the XML guest config with secure parameter, and will deal with all the certificate, attestation and launch measurement. In only 2 commands you can start a secure VM on an AMD SEV system! +It also simplify the usage of disk Image encryption. .PP Customization to match a specific scenario is not graved in stone. The idea is to prepare a configuration which should improved the usage @@ -451,6 +452,8 @@ AMD SEV .IP \[bu] 2 select right firmware for VM guest +.IP \[bu] 2 +Disk Encryption .SS Stuff currently immutable .PP This is currently not changeable using the template, this needs to be diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/setup.py new/virt-scenario-2.0.8/setup.py --- old/virt-scenario-2.0.7/setup.py 2023-06-06 18:33:04.000000000 +0200 +++ new/virt-scenario-2.0.8/setup.py 2023-06-07 10:52:15.000000000 +0200 @@ -163,7 +163,7 @@ setuptools.setup( name="virt-scenario", - version="2.0.7", + version="2.0.8", author="Antoine Ginies", author_email="agin...@suse.com", description="Virt-scenario", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/src/virt_scenario.egg-info/PKG-INFO new/virt-scenario-2.0.8/src/virt_scenario.egg-info/PKG-INFO --- old/virt-scenario-2.0.7/src/virt_scenario.egg-info/PKG-INFO 2023-06-06 18:33:29.000000000 +0200 +++ new/virt-scenario-2.0.8/src/virt_scenario.egg-info/PKG-INFO 2023-06-07 16:50:28.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: virt-scenario -Version: 2.0.7 +Version: 2.0.8 Summary: Virt-scenario Home-page: https://github.com/aginies/virt-scenario Author: Antoine Ginies @@ -21,6 +21,7 @@ IE: setting up a secure VM is not so easy from scratch, this tool will prepare the host, the XML guest config with secure parameter, and will deal with all the certificate, attestation and launch measurement. In only 2 commands you can start a secure VM on an AMD SEV system! + It also simplify the usage of disk Image encryption. Customization to match a specific scenario is not graved in stone. The idea is to prepare a configuration which should improved the usage compared to a basic setting. @@ -336,6 +337,7 @@ * Access host OS filesystem * AMD SEV * select right firmware for VM guest + * Disk Encryption ## Stuff currently immutable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/src/virtscenario/__init__.py new/virt-scenario-2.0.8/src/virtscenario/__init__.py --- old/virt-scenario-2.0.7/src/virtscenario/__init__.py 2023-06-06 17:45:01.000000000 +0200 +++ new/virt-scenario-2.0.8/src/virtscenario/__init__.py 2023-06-07 10:52:41.000000000 +0200 @@ -29,5 +29,5 @@ import builtins builtins.__dict__["_"] = str -__version__ = "2.0.7" +__version__ = "2.0.8" print(" Version: "+__version__) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/src/virtscenario/cmd.py new/virt-scenario-2.0.8/src/virtscenario/cmd.py --- old/virt-scenario-2.0.7/src/virtscenario/cmd.py 2023-06-06 13:53:27.000000000 +0200 +++ new/virt-scenario-2.0.8/src/virtscenario/cmd.py 2023-06-07 16:30:45.000000000 +0200 @@ -343,6 +343,9 @@ - guest: only XML guest configuration - host: only host configuration - both should be done (default) + + Note: in case of disk image encryption, "both" mode will be forced + as this is mandatory to create the VM image to retrieve the uuid """ mode = args if mode not in self.conf.all_modes: @@ -382,7 +385,8 @@ def do_overwrite(self, args): """ - Overwrite mode allow you to overwrite previous config (XML and config store) + Overwrite mode allow you to overwrite previous config (XML and config store), + This will also undefine any previous VM with the same name on current Hypervisor """ overwrite = args if overwrite not in self.conf.on_off_options: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/src/virtscenario/configuration.py new/virt-scenario-2.0.8/src/virtscenario/configuration.py --- old/virt-scenario-2.0.7/src/virtscenario/configuration.py 2023-06-06 13:53:27.000000000 +0200 +++ new/virt-scenario-2.0.8/src/virtscenario/configuration.py 2023-06-07 16:49:50.000000000 +0200 @@ -460,6 +460,8 @@ encryption = self.conf.dataprompt.get('encryption') if encryption != None: self.STORAGE_DATA.update({'encryption': encryption}) + # fore both mode in case of encryption on as we need uuid from VM image + self.conf.mode = "both" disk_cache = self.conf.dataprompt.get('disk_cache') if disk_cache != None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/src/virtscenario/hypervisors.py new/virt-scenario-2.0.8/src/virtscenario/hypervisors.py --- old/virt-scenario-2.0.7/src/virtscenario/hypervisors.py 2023-06-06 13:53:27.000000000 +0200 +++ new/virt-scenario-2.0.8/src/virtscenario/hypervisors.py 2023-06-07 16:31:56.000000000 +0200 @@ -22,7 +22,7 @@ import yaml import libvirt -import virtscenario.util as util +import virtscenario.util class HyperVisor: """ @@ -51,7 +51,7 @@ try: self.conn = libvirt.open(self.url) ver = self.conn.getVersion() - util.print_ok('Connected to libvirtd socket; Version: '+str(ver)) + virtscenario.util.print_ok('Connected to libvirtd socket; Version: '+str(ver)) return self.is_connected() except libvirt.libvirtError as verror: print(repr(verror), file=sys.stderr) @@ -60,6 +60,45 @@ def domain_capabilities(self): return self.conn.getDomainCapabilities() + def secret_list(self): + """ + return list of secret key + """ + return self.conn.listSecrets() + + def domain_list(self): + """ + return all domains available on the hypervisor + """ + all = [] + active_domain_ids = self.conn.listDomainsID() + active_domains = [self.conn.lookupByID(domain_id) for domain_id in active_domain_ids] + inactive_domain_ids = self.conn.listDefinedDomains() + inactive_domains = [self.conn.lookupByName(domain_name) for domain_name in inactive_domain_ids] + for domain in active_domains: + all.append(domain.name()) + for domain in inactive_domains: + all.append(domain.name()) + return all + + def remove_domain(self, domain): + """ + remove a domain by name + """ + all_domains = self.domain_list() + if domain in all_domains: + if domain.state()[0] == libvirt.VIR_DOMAIN_RUNNING: + virtscenario.util.print_warning(f"Domain {domain_name} is running! I will not undefine it.") + else: + domain = self.conn.lookupByName(domain) + domain.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_NVRAM) + + def secret_lookup_by_uuid(self, secret_name): + """ + look by uuid + """ + return self.conn.secretLookupByUUIDString(secret_name) + def network_list(self): """ Return a list of all network available on the hypervisor @@ -111,7 +150,7 @@ try: data = yaml.safe_load(stream) except yaml.YAMLError: - util.print_error("Failed to load Hypervisor list") + virtscenario.util.print_error("Failed to load Hypervisor list") old_list = HV_LIST.copy() HV_LIST.clear() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/src/virtscenario/scenario.py new/virt-scenario-2.0.8/src/virtscenario/scenario.py --- old/virt-scenario-2.0.7/src/virtscenario/scenario.py 2023-06-06 16:07:55.000000000 +0200 +++ new/virt-scenario-2.0.8/src/virtscenario/scenario.py 2023-06-07 16:24:24.000000000 +0200 @@ -172,6 +172,11 @@ # transparent hugepages doesnt need any XML config self.hugepages = "" + if self.conf.overwrite == "on": + # remove previous domain in the hypervisor + hypervisor.remove_domain(self.callsign) + + if (self.conf.mode != "guest" or self.conf.mode == "both") and util.check_iam_root() is True: util.print_title("Host Section") # Create the Virtual Disk image @@ -325,6 +330,10 @@ # transparent hugepages doesnt need any XML config self.hugepages = "" + if self.conf.overwrite == "on": + # remove previous domain in the hypervisor + hypervisor.remove_domain(self.callsign) + if (self.conf.mode != "guest" or self.conf.mode == "both") and util.check_iam_root() is True: util.print_title("Host Section") # Create the Virtual Disk image @@ -482,7 +491,6 @@ self.custom = ["loader", "vnet"] self.loader = firmware - # Check user setting configuration.Configuration.check_user_settings(self, securevm) @@ -553,6 +561,10 @@ # END of the config host.host_end() + if self.conf.overwrite == "on": + # remove previous domain in the hypervisor + hypervisor.remove_domain(self.callsign) + if self.conf.mode != "host" or self.conf.mode == "both": util.final_step_guest(cfg_store, self, verbose) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/src/virtscenario/util.py new/virt-scenario-2.0.8/src/virtscenario/util.py --- old/virt-scenario-2.0.7/src/virtscenario/util.py 2023-06-06 18:14:14.000000000 +0200 +++ new/virt-scenario-2.0.8/src/virtscenario/util.py 2023-06-07 16:35:03.000000000 +0200 @@ -18,12 +18,15 @@ """ import subprocess +import uuid import os import getpass import shutil import yaml +import json import virtscenario.qemulist as qemulist import virtscenario.xmlutil as xmlutil +import virtscenario.hypervisors as hv def system_command(cmd): """ @@ -32,7 +35,8 @@ proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc.wait() out, errs = proc.communicate(timeout=5) - out = str(out, 'UTF-8') + #out = str(out, 'UTF-8') + out = out.decode('utf-8') return out, errs def run_command_with_except(cmd): @@ -42,7 +46,7 @@ stderr = result.stderr return stdout, stderr except subprocess.CalledProcessError as e: - print(f"Command '{cmd}' failed with exit code {e.returncode}:") + print(f"Command:\n'{cmd}'\n failed with exit code {e.returncode}:") print(e.stderr) def cmd_exists(cmd): @@ -201,6 +205,7 @@ cmd = "virt-xml-validate "+xmlfile out, errs = system_command(cmd) if errs: + print(cmd) print(errs) print(out) @@ -283,6 +288,10 @@ validate the XML file """ filename = cfg_store.get_domain_config_filename() + directory = os.path.dirname(filename) + if not os.path.isdir(directory): + os.makedirs(directory) + print_title("Guest Section") create_xml_config(filename, data) if verbose is True: @@ -301,7 +310,7 @@ files_list.append(files) return files_list -def create_xml_config(filename, data): +def create_xml_config(filename, data, disk=""): """ draft xml create step create the xml file @@ -340,6 +349,12 @@ if "vnet" in data.custom: xmlutil.change_network_source(filename, data.vnet) ### if "XXXX" in data.custom: + # encryption needs uuid from VM image + if data.STORAGE_DATA['encryption'] == "on": + disk_file = data.STORAGE_DATA['path']+"/"+data.STORAGE_DATA['storage_name']+"."+data.STORAGE_DATA['format'] + disk_uuid = generate_secret_uuid(disk_file, data.STORAGE_DATA['password']) + # update disk with encryption data + xmlutil.add_encryption(filename, disk_uuid) def create_from_template(finalfile, xml_all): """ @@ -349,3 +364,48 @@ print(finalfile) with open(finalfile, 'w') as file_h: file_h.write(xml_all) + +def generate_secret_uuid(image, password): + """ + uuid + virsh secret-define --xml "<secret ephemeral='no' private='yes'><uuid>your_secret_uuid</uuid><usage type='volume'><volume>/path/to/encrypted_disk.qcow2</volume></usage></secret>" + virsh secret-set-value --secret your_secret_uuid --base64 "$(echo -n 'your_passphrase' | base64)" + """ + check_secret_uuid(image) + secret_uuid = str(uuid.uuid4()) + tmp_file = "/tmp/secret.xml" + file = open(tmp_file, "w") + file.write("<secret ephemeral='no' private='yes'>\n <uuid>"+secret_uuid+"</uuid>\n <usage type='volume'>\n <volume>"+str(image)+"</volume>\n </usage>\n</secret>") + file.close() + cmd_define_secret = "virsh secret-define --file "+tmp_file + cmd_password = "virsh secret-set-value --secret "+secret_uuid+" $(echo -n '"+password+"' | base64)" + run_command_with_except(cmd_define_secret) + run_command_with_except(cmd_password) + os.remove(tmp_file) + return secret_uuid + +def check_secret_uuid(image): + hypervisor = hv.select_hypervisor() + if not hypervisor.is_connected(): + print_error("No connection to LibVirt") + return + + secrets = hypervisor.secret_list() + # Check if the image path exists in the secrets + for secret_name in secrets: + secret = hypervisor.secret_lookup_by_uuid(secret_name) + xml_desc = secret.XMLDesc(0) + if image in xml_desc: + print(f"Secret with image path {image} already exists. Undefining it") + cmd_rm_uuid = "virsh secret-undefine "+secret_name + print(cmd_rm_uuid) + run_command_with_except(cmd_rm_uuid) + +def get_qemu_img_uuid(image): + """ + retrieve the uuid from the image + """ + command = ["qemu-img", "info", "--output=json", image] + output = subprocess.check_output(command).decode("utf-8") + img_info = json.loads(output) + return img_info['format-specific']['data']['encrypt']['uuid'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/src/virtscenario/xmlutil.py new/virt-scenario-2.0.8/src/virtscenario/xmlutil.py --- old/virt-scenario-2.0.7/src/virtscenario/xmlutil.py 2023-06-06 13:53:27.000000000 +0200 +++ new/virt-scenario-2.0.8/src/virtscenario/xmlutil.py 2023-06-07 13:44:58.000000000 +0200 @@ -59,6 +59,29 @@ # Write the modified XML tree back to the file ET.ElementTree(root).write(file) +def add_encryption(file, uuid): + """ + add encryption data to disk + """ + tree = ET.parse(file) + root = tree.getroot() + disk_elem = root.find('./devices/disk') + + if disk_elem is not None: + source_elem = disk_elem.find("source") + if source_elem is not None: + source_elem.tail = "\n " + encryption_elem = ET.SubElement(source_elem, 'encryption') + encryption_elem.set('format', 'luks') + encryption_elem.tail = "\n " + secret_elem = ET.SubElement(encryption_elem, 'secret') + secret_elem.set('type', 'passphrase') + secret_elem.set('uuid', uuid) + #element_string = ET.tostring(disk_elem, encoding='unicode') + #print(element_string) + + tree.write(file, encoding='UTF-8', xml_declaration=True) + def add_attestation(file_path: str, dh_cert_path: str, session_path: str) -> None: """ add attestation element in the Tree @@ -91,7 +114,6 @@ # Parse the XML file tree = ET.parse(file_path) root = tree.getroot() - # Find the interface # Find the 'interface' element within the 'devices' element interface_elem = root.find("./devices/interface") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/virt-scenario-2.0.7/src/vsmygtk/main.py new/virt-scenario-2.0.8/src/vsmygtk/main.py --- old/virt-scenario-2.0.7/src/vsmygtk/main.py 2023-06-06 13:53:27.000000000 +0200 +++ new/virt-scenario-2.0.8/src/vsmygtk/main.py 2023-06-07 16:31:27.000000000 +0200 @@ -638,7 +638,7 @@ gtk.margin_bottom_right(switch_overwrite) switch_overwrite.set_halign(Gtk.Align.START) switch_overwrite.connect("notify::active", self.on_switch_overwrite_activated) - switch_overwrite.set_tooltip_text("This will overwrite any previous VM configuration!") + switch_overwrite.set_tooltip_text("This will overwrite any previous VM configuration!\nThis will also undefine any previous VM with the same name on current Hypervisor") switch_overwrite.set_active(False) grid_scena.attach(label_overwrite, 0, 3, 1, 1) grid_scena.attach(switch_overwrite, 1, 3, 1, 1)