[gnome-boxes/drop-system-importer: 3/3] libvirt-machine: Allow to "Import" non-local VMs



commit 6fb713e799ce386d47d59034330ab05b6abab363
Author: Felipe Borges <felipeborges gnome org>
Date:   Wed Apr 24 18:45:05 2019 +0200

    libvirt-machine: Allow to "Import" non-local VMs
    
    These changes make it possible to "Import" a VM storage volume into
    the Boxes internal storage volumes location. We use the same
    mechanism than the "clone ()" operation, except we update the
    storage volume paths and copy/convert the disks.

 src/actions-popover.vala |  8 ++++++--
 src/libvirt-machine.vala | 33 ++++++++++++++++++++++++++++-----
 src/util-app.vala        | 24 ++++++++++++++++++++++++
 src/vm-importer.vala     |  8 +++++++-
 4 files changed, 65 insertions(+), 8 deletions(-)
---
diff --git a/src/actions-popover.vala b/src/actions-popover.vala
index 7d1e0cdd..948abc70 100644
--- a/src/actions-popover.vala
+++ b/src/actions-popover.vala
@@ -71,8 +71,12 @@ public void update_for_item (CollectionItem item) {
         }
 
         if (window.ui_state != UIState.DISPLAY) {
-            // Clone
-            section.append (_("Clone"), "box.clone");
+            var clone_or_import_label = _("Clone");
+            if (machine is LibvirtMachine && !machine.is_local)
+                clone_or_import_label = _("Import");
+
+            // Clone or Import
+            section.append (clone_or_import_label, "box.clone");
             var action = action_group.lookup_action ("clone") as GLib.SimpleAction;
             action.set_enabled (machine.can_clone);
 
diff --git a/src/libvirt-machine.vala b/src/libvirt-machine.vala
index 1c8e4830..9022b5b8 100644
--- a/src/libvirt-machine.vala
+++ b/src/libvirt-machine.vala
@@ -51,9 +51,13 @@
 
     public override bool is_local {
         get {
-            /* get_domain_disk () will return NULL for volumes that aren't managed by Boxes. */
-            if (get_domain_disk () != null)
-                return true;
+            try {
+                /* get_domain_disk () will return NULL for volumes that aren't managed by Boxes. */
+                if (get_domain_disk () != null)
+                    return true;
+            } catch (GLib.Error error) {
+                warning ("Failed to obtain domain disk: %s", error.message);
+            }
 
             return base.is_local;
         }
@@ -749,7 +753,24 @@ public override async void clone () {
             var config = new GVirConfig.Domain.from_xml (xml);
             config.set_uuid (null);
 
-            var media = new LibvirtClonedMedia (storage_volume.get_path (), config);
+            string? device_file = storage_volume.get_path ();
+            var storage_volume_path = is_local ? device_file : get_user_pkgdata (Path.build_filename 
("images", name));
+            var media = new LibvirtClonedMedia (storage_volume_path, config);
+
+            if (!is_local) {
+                var devices = config.get_devices ();
+                foreach (var device in devices) {
+                    if (!(device is GVirConfig.DomainDisk))
+                        continue;
+
+                    device_file = (device as GVirConfig.DomainDisk).get_source ();
+                    devices.remove (device);
+
+                    break;
+                }
+
+                config.set_devices (devices);
+            }
 
             // Recreate network interface so clones won't have the same mac address
             var iface= VMConfigurator.create_network_interface (config,
@@ -759,6 +780,7 @@ public override async void clone () {
 
             var vm_cloner = media.get_vm_creator ();
             var clone_machine = yield vm_cloner.create_vm (null);
+            (vm_cloner as VMImporter).import_vm (clone_machine, device_file);
             vm_cloner.launch_vm (clone_machine, this.config.access_last_time);
 
             ulong under_construct_id = 0;
@@ -771,7 +793,8 @@ public override async void clone () {
                 }
             });
         } catch (GLib.Error error) {
-            warning ("Failed to clone %s: %s", domain_config.name, error.message);
+            var action = is_local ? "clone" : "import";
+            warning ("Failed to %s %s: %s", action, domain_config.name, error.message);
             can_delete = true;
         }
     }
diff --git a/src/util-app.vala b/src/util-app.vala
index 88a9a1d3..3242de8e 100644
--- a/src/util-app.vala
+++ b/src/util-app.vala
@@ -425,6 +425,30 @@ public async bool check_storage_pool (out string diagnosis) {
         return true;
     }
 
+    public async void ensure_disk_is_readable (string disk_path) throws GLib.Error {
+        string[] argv = {};
+
+        argv += "pkexec";
+        argv += "chmod";
+        argv += "a+r";
+
+        var file = File.new_for_path (disk_path);
+        var info = yield file.query_info_async (FileAttribute.ACCESS_CAN_READ,
+                                                FileQueryInfoFlags.NONE,
+                                                Priority.DEFAULT,
+                                                null);
+        if (!info.get_attribute_boolean (FileAttribute.ACCESS_CAN_READ)) {
+            debug ("'%s' not readable, gotta make it readable..", disk_path);
+            argv += disk_path;
+        }
+
+        if (argv.length == 3)
+            return;
+
+        debug ("Making broker's disks readable..");
+        yield exec (argv, null);
+        debug ("Made all broker's disks readable.");
+    }
 
     // FIXME: Better ways to remove alpha more than welcome
     private Gdk.Pixbuf remove_alpha (Gdk.Pixbuf pixbuf) {
diff --git a/src/vm-importer.vala b/src/vm-importer.vala
index 8f1c2d57..08544f9d 100644
--- a/src/vm-importer.vala
+++ b/src/vm-importer.vala
@@ -43,10 +43,16 @@ protected virtual async void post_import_setup (LibvirtMachine machine) {
         machine.vm_creator = null;
     }
 
-    private async void import_vm (LibvirtMachine machine) {
+    public async void import_vm (LibvirtMachine machine, string? custom_source = null) {
         try {
             var destination_path = machine.storage_volume.get_path ();
 
+            if (custom_source != null) {
+                yield ensure_disk_is_readable (custom_source);
+
+                source_media.device_file = custom_source;
+            }
+
             yield source_media.copy (destination_path);
 
             // Without refreshing the pool, libvirt will not know of changes to volume we just made


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]