Let users add either files or devices as disks to domains. --- libvirt-designer/libvirt-designer-domain.c | 259 ++++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.h | 7 + libvirt-designer/libvirt-designer.sym | 3 + 3 files changed, 269 insertions(+), 0 deletions(-) diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index a8cabde..8e649d7 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -37,6 +37,12 @@ struct _GVirDesignerDomainPrivate GVirConfigCapabilities *caps; OsinfoOs *os; OsinfoPlatform *platform; + + OsinfoDeployment *deployment; + /* next disk targets */ + unsigned int ide; + unsigned int virtio; + unsigned int sata; }; G_DEFINE_TYPE(GVirDesignerDomain, gvir_designer_domain, G_TYPE_OBJECT); @@ -134,6 +140,8 @@ static void gvir_designer_domain_finalize(GObject *object) g_object_unref(priv->os); g_object_unref(priv->platform); g_object_unref(priv->caps); + if (priv->deployment) + g_object_unref(priv->deployment); G_OBJECT_CLASS(gvir_designer_domain_parent_class)->finalize(object); } @@ -663,3 +671,254 @@ cleanup: g_object_unref(guest); return ret; } + +static GList * +gvir_designer_domain_get_supported_disk_bus_types(GVirDesignerDomain *design) +{ + GVirDesignerDomainPrivate *priv = design->priv; + OsinfoDeviceList *dev_list; + GHashTable *bus_hash = g_hash_table_new(g_str_hash, g_str_equal); + GList *ret = NULL; + int i; + + dev_list = osinfo_os_get_devices_by_property(priv->os, "class", "block", TRUE); + if (!dev_list) + goto cleanup; + + for (i = 0; i < osinfo_list_get_length(OSINFO_LIST(dev_list)); i++) { + OsinfoDevice *dev = OSINFO_DEVICE(osinfo_list_get_nth(OSINFO_LIST(dev_list), i)); + const gchar *bus = osinfo_device_get_bus_type(dev); + + if (bus) + g_hash_table_add(bus_hash, g_strdup(bus)); + } + + ret = g_hash_table_get_keys(bus_hash); + if (ret) + ret = g_list_copy(ret); + +cleanup: + g_hash_table_destroy(bus_hash); + return ret; +} + +static OsinfoDeviceLink * +gvir_designer_domain_get_preferred_device(GVirDesignerDomain *design, + const char *class, + GError **error) +{ + GVirDesignerDomainPrivate *priv = design->priv; + OsinfoFilter *filter = osinfo_filter_new(); + OsinfoDeviceLinkFilter *filter_link = NULL; + OsinfoDeployment *deployment = priv->deployment; + OsinfoDeviceLink *dev_link = NULL; + + if (!deployment) { + priv->deployment = deployment = osinfo_db_find_deployment(osinfo_db, + priv->os, + priv->platform); + if (!deployment) { + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "Unable to find any deployment in libosinfo database"); + goto cleanup; + } + } + + osinfo_filter_add_constraint(filter, "class", class); + filter_link = osinfo_devicelinkfilter_new(filter); + dev_link = osinfo_deployment_get_preferred_device_link(deployment, OSINFO_FILTER(filter_link)); + +cleanup: + if (filter_link) + g_object_unref(filter_link); + if (filter) + g_object_unref(filter); + return dev_link; +} + +static const gchar * +gvir_designer_domain_get_preferred_disk_bus_type(GVirDesignerDomain *design, + GError **error) +{ + OsinfoDevice *dev; + OsinfoDeviceLink *dev_link = gvir_designer_domain_get_preferred_device(design, + "block", + error); + const gchar *ret = NULL; + + if (!dev_link) + return NULL; + + dev = osinfo_devicelink_get_target(dev_link); + if (dev) + ret = osinfo_device_get_bus_type(dev); + + return ret; +} + +static gchar * +gvir_designer_domain_next_disk_target(GVirDesignerDomain *design, + GVirConfigDomainDiskBus bus) +{ + gchar *ret = NULL; + GVirDesignerDomainPrivate *priv = design->priv; + + switch (bus) { + case GVIR_CONFIG_DOMAIN_DISK_BUS_IDE: + ret = g_strdup_printf("hd%c", 'a' + priv->ide++); + break; + case GVIR_CONFIG_DOMAIN_DISK_BUS_VIRTIO: + ret = g_strdup_printf("vd%c", 'a' + priv->virtio++); + break; + case GVIR_CONFIG_DOMAIN_DISK_BUS_SATA: + ret = g_strdup_printf("sd%c", 'a' + priv->sata++); + break; + case GVIR_CONFIG_DOMAIN_DISK_BUS_FDC: + case GVIR_CONFIG_DOMAIN_DISK_BUS_SCSI: + case GVIR_CONFIG_DOMAIN_DISK_BUS_XEN: + case GVIR_CONFIG_DOMAIN_DISK_BUS_USB: + case GVIR_CONFIG_DOMAIN_DISK_BUS_UML: + default: + /* not supported yet */ + /* XXX should we fallback to ide/virtio? */ + break; + } + + return ret; +} + +static GVirConfigDomainDisk * +gvir_designer_domain_add_disk_full(GVirDesignerDomain *design, + GVirConfigDomainDiskType type, + const char *path, + const char *format, + gchar *target, + GError **error) +{ + GVirDesignerDomainPrivate *priv = design->priv; + GVirConfigDomainDisk *disk = NULL; + GVirConfigDomainDiskBus bus; + gchar *target_gen = NULL; + const gchar *bus_str = NULL; + GList *bus_str_list = NULL, *item = NULL; + + /* Guess preferred disk bus */ + bus_str = gvir_designer_domain_get_preferred_disk_bus_type(design, error); + if (!bus_str) { + /* And fallback if fails */ + bus_str_list = gvir_designer_domain_get_supported_disk_bus_types(design); + if (!bus_str_list) { + if (!*error) + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "Unable to find any disk bus type"); + goto error; + } + + item = g_list_first(bus_str_list); + bus_str = item->data; + if (!bus_str) + goto error; + } + + g_clear_error(error); + + disk = gvir_config_domain_disk_new(); + gvir_config_domain_disk_set_type(disk, type); + gvir_config_domain_disk_set_source(disk, path); + gvir_config_domain_disk_set_driver_name(disk, "qemu"); + if (format) + gvir_config_domain_disk_set_driver_type(disk, format); + if (g_str_equal(bus_str, "ide")) { + bus = GVIR_CONFIG_DOMAIN_DISK_BUS_IDE; + } else if (g_str_equal(bus_str, "virtio") || + g_str_equal(bus_str, "pci")) { + bus = GVIR_CONFIG_DOMAIN_DISK_BUS_VIRTIO; + } else if (g_str_equal(bus_str, "sata")) { + bus = GVIR_CONFIG_DOMAIN_DISK_BUS_SATA; + } else { + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "unsupported disk bus type '%s'", bus_str); + goto error; + } + + gvir_config_domain_disk_set_target_bus(disk, bus); + + if (!target) { + target = target_gen = gvir_designer_domain_next_disk_target(design, bus); + if (!target_gen) { + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "unable to generate target name for bus '%s'", bus_str); + goto error; + } + } + gvir_config_domain_disk_set_target_dev(disk, target); + + g_list_free(bus_str_list); + g_free(target_gen); + + gvir_config_domain_add_device(priv->config, GVIR_CONFIG_DOMAIN_DEVICE(disk)); + + return disk; + +error: + g_free(target_gen); + g_list_free(bus_str_list); + if (disk) + g_object_unref(disk); + return NULL; +} +/** + * gvir_designer_domain_add_disk_file: + * @design: (transfer none): the domain designer instance + * @filepath: (transfer none): the path to a file + * @format: (transfer none): disk format + * + * Add a new disk to the domain. + * + * Returns: (transfer none): the pointer to new disk. + * If something fails NULL is returned and @error is set. + */ +GVirConfigDomainDisk *gvir_designer_domain_add_disk_file(GVirDesignerDomain *design, + const char *filepath, + const char *format, + GError **error) +{ + g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL); + + GVirConfigDomainDisk *ret = NULL; + + ret = gvir_designer_domain_add_disk_full(design, + GVIR_CONFIG_DOMAIN_DISK_FILE, + filepath, + format, + NULL, + error); + return ret; +} + +/** + * gvir_designer_domain_add_disk_device: + * @design: (transfer none): the domain designer instance + * @devpath: (transfer none): path to the device + * + * Add given device as a new disk to the domain designer instance. + * + * Returns: (transfer none): the pointer to the new disk. + * If something fails NULL is returned and @error is set. + */ +GVirConfigDomainDisk *gvir_designer_domain_add_disk_device(GVirDesignerDomain *design, + const char *devpath, + GError **error) +{ + g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL); + + GVirConfigDomainDisk *ret = NULL; + + ret = gvir_designer_domain_add_disk_full(design, + GVIR_CONFIG_DOMAIN_DISK_BLOCK, + devpath, + "raw", + NULL, + error); + return ret; +} diff --git a/libvirt-designer/libvirt-designer-domain.h b/libvirt-designer/libvirt-designer-domain.h index 23b5750..06a5749 100644 --- a/libvirt-designer/libvirt-designer-domain.h +++ b/libvirt-designer/libvirt-designer-domain.h @@ -93,6 +93,13 @@ gboolean gvir_designer_domain_setup_container_full(GVirDesignerDomain *design, const char *arch, GError **error); +GVirConfigDomainDisk *gvir_designer_domain_add_disk_file(GVirDesignerDomain *design, + const char *filepath, + const char *format, + GError **error); +GVirConfigDomainDisk *gvir_designer_domain_add_disk_device(GVirDesignerDomain *design, + const char *devpath, + GError **error); G_END_DECLS diff --git a/libvirt-designer/libvirt-designer.sym b/libvirt-designer/libvirt-designer.sym index 2a56a92..e67323a 100644 --- a/libvirt-designer/libvirt-designer.sym +++ b/libvirt-designer/libvirt-designer.sym @@ -10,6 +10,9 @@ LIBVIRT_DESIGNER_0.0.1 { gvir_designer_domain_get_platform; gvir_designer_domain_get_capabilities; + gvir_designer_domain_add_disk_file; + gvir_designer_domain_add_disk_device; + gvir_designer_domain_setup_machine; gvir_designer_domain_setup_machine_full; gvir_designer_domain_setup_container; -- 1.7.8.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list