[gnome-boxes/wip/system-libvirt-import2: 11/13] Allow user to import system libvirt VMs



commit 8019d86a54af7afcba6097834ca14b1479cfdfa1
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date:   Fri Nov 15 17:07:31 2013 +0000

    Allow user to import system libvirt VMs
    
    On launch of Boxes, if there is no boxes defined and there is VMs
    available on system libvirt, allow user to import those VMs to session
    libvirt (and therefore Boxes).
    
    We gotta elevate privileges to change permissions on disks/images as by
    default they are not even readable to anyone but root/qemu. This
    unfortunately means launching of undesirable polkit dialog.

 src/Makefile.am                  |    1 +
 src/app.vala                     |    2 +
 src/libvirt-system-importer.vala |  142 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 145 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 78d712a..cbfec97 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -114,6 +114,7 @@ gnome_boxes_SOURCES =                               \
        vm-configurator.vala                    \
        vm-creator.vala                         \
        vm-importer.vala                        \
+       libvirt-system-importer.vala            \
        libvirt-system-vm-importer.vala         \
        vnc-display.vala                        \
        wizard-source.vala                      \
diff --git a/src/app.vala b/src/app.vala
index 59d93c8..3826dd2 100644
--- a/src/app.vala
+++ b/src/app.vala
@@ -82,6 +82,7 @@ private class Boxes.App: Boxes.UI {
     public Properties properties;
     public DisplayPage display_page;
     public EmptyBoxes empty_boxes;
+    public LibvirtSystemImporter system_importer;
     public string? uri { get; set; }
     public Collection collection;
     public CollectionFilter filter;
@@ -572,6 +573,7 @@ private class Boxes.App: Boxes.UI {
         wizard = new Wizard ();
         properties = new Properties ();
         empty_boxes = new EmptyBoxes ();
+        system_importer = new LibvirtSystemImporter ();
 
         var vbox_actor = new Clutter.Actor ();
         vbox_actor.name = "top-vbox";
diff --git a/src/libvirt-system-importer.vala b/src/libvirt-system-importer.vala
new file mode 100644
index 0000000..8c1327a
--- /dev/null
+++ b/src/libvirt-system-importer.vala
@@ -0,0 +1,142 @@
+// This file is part of GNOME Boxes. License: LGPLv2+
+using GVir;
+
+errordomain Boxes.LibvirtSystemImporterError {
+    NO_SUITABLE_DISK
+}
+
+private class Boxes.LibvirtSystemImporter: GLib.Object {
+    private GVir.Connection connection;
+    private GLib.List<GVir.Domain> domains;
+
+    public LibvirtSystemImporter () {
+        App.app.call_when_ready (() => {
+            if (App.app.collection.items.length == 0)
+                prepare_import.begin ();
+        });
+    }
+
+    private async void prepare_import () {
+        connection = new GVir.Connection ("qemu+unix:///system");
+
+        try {
+            yield connection.open_read_only_async (null);
+            debug ("Connected to system libvirt, now fetching domains..");
+            yield connection.fetch_domains_async (null);
+        } catch (GLib.Error error) {
+            warning ("Failed to connect to system libvirt: %s", error.message);
+
+            return;
+        }
+
+        domains = connection.get_domains ();
+        debug ("Fetched %u domains from system libvirt.", domains.length ());
+        var num_domains = domains.length ();
+        if (num_domains == 0)
+            return;
+
+        string msg;
+        if (num_domains == 1)
+            msg = _("Do you want to import '%s' from system broker?").printf (domains.data.get_name ());
+        else
+            // Translators: %u here is number of boxes availble for import
+            msg = ngettext ("Do you want to import %u box from system broker?",
+                            "Do you want to import %u boxes from system broker?",
+                            num_domains).printf (num_domains);
+        Notificationbar.OKFunc launch_import = () => {
+            import.begin ();
+        };
+
+        App.app.notificationbar.display_for_action (msg, _("Yes"), (owned) launch_import);
+    }
+
+    private async void import () {
+        GVirConfig.Domain[] configs = {};
+        string[] disk_paths = {};
+
+        foreach (var domain in domains) {
+            GVirConfig.Domain config;
+            string disk_path;
+
+            try {
+                get_domain_info (domain, out config, out disk_path);
+                configs += config;
+                disk_paths += disk_path;
+            } catch (GLib.Error error) {
+                warning ("%s", error.message);
+            }
+        }
+
+        try {
+            yield ensure_disks_readable (disk_paths);
+        } catch (GLib.Error error) {
+            warning ("Failed to make all libvirt system disks readable: %s", error.message);
+
+            return;
+        }
+
+        for (var i = 0; i < configs.length; i++)
+            import_domain.begin (configs[i], disk_paths[i], null, (obj, result) => {
+                try {
+                    import_domain.end (result);
+                } catch (GLib.Error error) {
+                    warning ("Failed to import '%s': %s", configs[i].name, error.message);
+                }
+            });
+    }
+
+    private void get_domain_info (Domain domain, out GVirConfig.Domain config, out string disk_path) throws 
GLib.Error {
+        debug ("Fetching config for '%s' from system libvirt.", domain.get_name ());
+        config = domain.get_config (DomainXMLFlags.INACTIVE);
+        debug ("Finding a suitable disk to import for '%s' from system libvirt.", domain.get_name ());
+        disk_path = get_disk_path (config);
+    }
+
+    private async void import_domain (GVirConfig.Domain config,
+                                      string            disk_path,
+                                      Cancellable?      cancellable = null) throws GLib.Error {
+        debug ("Importing '%s' from system libvirt..", config.name);
+
+        var media = new LibvirtSystemMedia (disk_path, config);
+        var vm_importer = media.get_vm_creator ();
+        var machine = yield vm_importer.create_vm (cancellable);
+        vm_importer.launch_vm (machine);
+    }
+
+    private string get_disk_path (GVirConfig.Domain config) throws 
LibvirtSystemImporterError.NO_SUITABLE_DISK {
+        string disk_path = null;
+
+        var devices = config.get_devices ();
+        foreach (var device in devices) {
+            if (!(device is GVirConfig.DomainDisk))
+                continue;
+
+            var disk = device as GVirConfig.DomainDisk;
+            if (disk.get_guest_device_type () == GVirConfig.DomainDiskGuestDeviceType.DISK) {
+                disk_path = disk.get_source ();
+
+                break;
+            }
+        }
+
+        if (disk_path == null)
+            throw new LibvirtSystemImporterError.NO_SUITABLE_DISK
+                                    (_("Failed to find suitable disk to import for box '%s'"), config.name);
+
+        return disk_path;
+    }
+
+    private async void ensure_disks_readable (string[] disk_paths) throws GLib.Error {
+        string[] argv = {};
+
+        argv += "pkexec";
+        argv += "chmod";
+        argv += "a+r";
+        foreach (var disk_path in disk_paths)
+            argv += disk_path;
+
+        debug ("Making all libvirt system disks readable..");
+        yield exec (argv, null);
+        debug ("Made all libvirt system disks readable.");
+    }
+}


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