[libvirt] [libvirt-designer 0/9] Handle more devices in GVirDesignerDomain

This series builds on the previous one (the one adding gvir_designer_domain_get_supported_devices()). It adds methods to add more devices disks/network interfaces to GVirDesignDomain. Some parts like 'Automatically add SPICE channel with SPICE graphics' may not be what we want, but I've tried to make the external API as easy as possible. Christophe

Add various devices/configuration to libvirt XML config when creating the VM. This configuration is generic enough that it should be useful on all created VMs, that's why no public API is added to set them up. However, they are split in several helpers that can easily be exported if needed. What this commit adds is: - clock - sound card - input device (a tablet which will act as a mouse) - a console (Boxes is adding one, not sure if it's required...) For maximum flexibility, we may want to make the last 2 public. I'm undecided on sound card, I don't think it's terribly interesting to configure, but I wouldn't mind exposing this publicly either. In addition to these devices, gvir_designer_domain_setup_guest() now disables power management, and sets the domain to stop on power off/crash, and to restart on reboots. --- libvirt-designer/libvirt-designer-domain.c | 95 ++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index c23101d..c0b0e19 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -314,6 +314,95 @@ end: } +static void gvir_designer_domain_add_clock(GVirDesignerDomain *design) +{ + GVirConfigDomainClock *clock; + GVirConfigDomainTimer *timer; + GVirConfigDomainClockOffset offset; + + clock = gvir_config_domain_clock_new(); + offset = GVIR_CONFIG_DOMAIN_CLOCK_UTC; + if (design->priv->os != NULL) { + const gchar *short_id; + + short_id = osinfo_product_get_short_id(OSINFO_PRODUCT(design->priv->os)); + if (g_str_has_suffix(short_id, "win")) { + offset = GVIR_CONFIG_DOMAIN_CLOCK_LOCALTIME; + } + } + gvir_config_domain_clock_set_offset(clock, offset); + + timer = GVIR_CONFIG_DOMAIN_TIMER(gvir_config_domain_timer_rtc_new()); + gvir_config_domain_timer_set_tick_policy(timer, + GVIR_CONFIG_DOMAIN_TIMER_TICK_POLICY_CATCHUP); + gvir_config_domain_clock_add_timer(clock, timer); + g_object_unref(G_OBJECT(timer)); + + timer = GVIR_CONFIG_DOMAIN_TIMER(gvir_config_domain_timer_pit_new()); + gvir_config_domain_timer_set_tick_policy(timer, + GVIR_CONFIG_DOMAIN_TIMER_TICK_POLICY_DELAY); + gvir_config_domain_clock_add_timer(clock, timer); + g_object_unref(G_OBJECT(timer)); + + gvir_config_domain_set_clock(design->priv->config, clock); + g_object_unref(G_OBJECT(clock)); +} + +static void gvir_designer_domain_add_power_management(GVirDesignerDomain *design) +{ + GVirConfigDomainPowerManagement *pm; + + pm = gvir_config_domain_power_management_new(); + gvir_config_domain_power_management_set_mem_suspend_enabled(pm, FALSE); + gvir_config_domain_power_management_set_disk_suspend_enabled(pm, FALSE); + + gvir_config_domain_set_power_management(design->priv->config, pm); + g_object_unref(G_OBJECT(pm)); +} + +static void gvir_designer_domain_set_lifecycle(GVirDesignerDomain *design) +{ + gvir_config_domain_set_lifecycle(design->priv->config, + GVIR_CONFIG_DOMAIN_LIFECYCLE_ON_POWEROFF, + GVIR_CONFIG_DOMAIN_LIFECYCLE_DESTROY); + gvir_config_domain_set_lifecycle(design->priv->config, + GVIR_CONFIG_DOMAIN_LIFECYCLE_ON_REBOOT, + GVIR_CONFIG_DOMAIN_LIFECYCLE_RESTART); + gvir_config_domain_set_lifecycle(design->priv->config, + GVIR_CONFIG_DOMAIN_LIFECYCLE_ON_CRASH, + GVIR_CONFIG_DOMAIN_LIFECYCLE_DESTROY); +} + +static void gvir_designer_domain_add_console(GVirDesignerDomain *design) +{ + GVirConfigDomainConsole *console; + GVirConfigDomainChardevSourcePty *pty; + + console = gvir_config_domain_console_new(); + pty = gvir_config_domain_chardev_source_pty_new(); + gvir_config_domain_chardev_set_source(GVIR_CONFIG_DOMAIN_CHARDEV(console), + GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE(pty)); + g_object_unref(G_OBJECT(pty)); + + gvir_config_domain_add_device(design->priv->config, + GVIR_CONFIG_DOMAIN_DEVICE(console)); + g_object_unref(G_OBJECT(console)); +} + +static void gvir_designer_domain_add_input(GVirDesignerDomain *design) +{ + GVirConfigDomainInput *input; + + input = gvir_config_domain_input_new(); + gvir_config_domain_input_set_device_type(input, + GVIR_CONFIG_DOMAIN_INPUT_DEVICE_TABLET); + + gvir_config_domain_add_device(design->priv->config, + GVIR_CONFIG_DOMAIN_DEVICE(input)); + g_object_unref(G_OBJECT(input)); +} + + static void gvir_designer_domain_init(GVirDesignerDomain *design) { GVirDesignerDomainPrivate *priv; @@ -671,6 +760,12 @@ gvir_designer_domain_setup_guest(GVirDesignerDomain *design, gvir_config_capabilities_guest_domain_get_virt_type(domain)); gvir_config_domain_set_os(priv->config, os); + gvir_designer_domain_add_clock(design); + gvir_designer_domain_add_power_management(design); + gvir_designer_domain_set_lifecycle(design); + gvir_designer_domain_add_console(design); + gvir_designer_domain_add_input(design); + ret = TRUE; cleanup: if (domain != NULL) -- 1.8.1.4

--- libvirt-designer/libvirt-designer-domain.c | 120 +++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index c0b0e19..7b1cb33 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -58,6 +58,8 @@ typedef enum { /* add new type here */ } GVirDesignerDomainNICType; +static void gvir_designer_domain_add_sound(GVirDesignerDomain *design); + static GQuark gvir_designer_domain_error_quark(void) { @@ -389,6 +391,7 @@ static void gvir_designer_domain_add_console(GVirDesignerDomain *design) g_object_unref(G_OBJECT(console)); } + static void gvir_designer_domain_add_input(GVirDesignerDomain *design) { GVirConfigDomainInput *input; @@ -765,6 +768,7 @@ gvir_designer_domain_setup_guest(GVirDesignerDomain *design, gvir_designer_domain_set_lifecycle(design); gvir_designer_domain_add_console(design); gvir_designer_domain_add_input(design); + gvir_designer_domain_add_sound(design); ret = TRUE; cleanup: @@ -933,6 +937,122 @@ cleanup: } +static OsinfoDevice * +gvir_designer_domain_get_preferred_soundcard(GVirDesignerDomain *design, + GError **error) +{ + OsinfoDevice *device = NULL; + OsinfoDeviceLink *dev_link; + + dev_link = gvir_designer_domain_get_preferred_device(design, + "audio", + error); + if (dev_link == NULL) + goto cleanup; + + device = osinfo_devicelink_get_target(dev_link); + +cleanup: + if (dev_link != NULL) + g_object_unref(dev_link); + + return device; +} + +static OsinfoDeviceList * +gvir_designer_domain_get_fallback_devices(GVirDesignerDomain *design, + const char *class, + GError **error) +{ + OsinfoDeviceList *devices = NULL; + OsinfoFilter *filter; + + filter = osinfo_filter_new(); + osinfo_filter_add_constraint(filter, OSINFO_DEVICE_PROP_CLASS, class); + devices = gvir_designer_domain_get_supported_devices(design, filter); + g_object_unref(G_OBJECT(filter)); + + if ((devices == NULL) || + (osinfo_list_get_length(OSINFO_LIST(devices)) == 0)) { + goto cleanup; + } + + return devices; + +cleanup: + if (devices != NULL) + g_object_unref(devices); + + return NULL; +} + + +static OsinfoDevice * +gvir_designer_domain_get_fallback_soundcard(GVirDesignerDomain *domain, + GError **error) +{ + OsinfoEntity *dev = NULL; + OsinfoDeviceList *devices = NULL; + + devices = gvir_designer_domain_get_fallback_devices(domain, "audio", error); + if (devices == NULL) + goto cleanup; + + dev = osinfo_list_get_nth(OSINFO_LIST(devices), 0); + g_object_ref(G_OBJECT(dev)); + +cleanup: + if (devices != NULL) + g_object_unref(G_OBJECT(devices)); + + return OSINFO_DEVICE(dev); +} + + +static GVirConfigDomainSoundModel +gvir_designer_sound_model_from_soundcard(OsinfoDevice *soundcard) +{ + const char *name; + + name = osinfo_device_get_name(soundcard); + if (g_strcmp0(name, "ac97") == 0) { + return GVIR_CONFIG_DOMAIN_SOUND_MODEL_AC97; + } else if (g_strcmp0(name, "ich6") == 0) { + return GVIR_CONFIG_DOMAIN_SOUND_MODEL_ICH6; + } else if (g_strcmp0(name, "es1370") == 0) { + return GVIR_CONFIG_DOMAIN_SOUND_MODEL_ES1370; + } else if (g_strcmp0(name, "sb16") == 0) { + return GVIR_CONFIG_DOMAIN_SOUND_MODEL_SB16; + } else { + g_warning("Unknown soundcard %s, falling back to PC speaker", name); + return GVIR_CONFIG_DOMAIN_SOUND_MODEL_PCSPK; + } +} + + +static void gvir_designer_domain_add_sound(GVirDesignerDomain *design) +{ + GVirConfigDomainSound *sound; + OsinfoDevice *soundcard; + GVirConfigDomainSoundModel model; + + soundcard = gvir_designer_domain_get_preferred_soundcard(design, NULL); + if (soundcard == NULL) + soundcard = gvir_designer_domain_get_fallback_soundcard(design, NULL); + + if (soundcard == NULL) + return; + + sound = gvir_config_domain_sound_new(); + model = gvir_designer_sound_model_from_soundcard(soundcard); + gvir_config_domain_sound_set_model(sound, model); + + gvir_config_domain_add_device(design->priv->config, + GVIR_CONFIG_DOMAIN_DEVICE(sound)); + g_object_unref(G_OBJECT(sound)); +} + + static gchar * gvir_designer_domain_next_disk_target(GVirDesignerDomain *design, GVirConfigDomainDiskBus bus) -- 1.8.1.4

On Wed, Apr 03, 2013 at 11:38:01AM +0200, Christophe Fergeau wrote:
--- libvirt-designer/libvirt-designer-domain.c | 120 +++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+)
diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index c0b0e19..7b1cb33 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -58,6 +58,8 @@ typedef enum { /* add new type here */ } GVirDesignerDomainNICType;
+static void gvir_designer_domain_add_sound(GVirDesignerDomain *design); + static GQuark gvir_designer_domain_error_quark(void) { @@ -389,6 +391,7 @@ static void gvir_designer_domain_add_console(GVirDesignerDomain *design) g_object_unref(G_OBJECT(console)); }
+ static void gvir_designer_domain_add_input(GVirDesignerDomain *design) { GVirConfigDomainInput *input; @@ -765,6 +768,7 @@ gvir_designer_domain_setup_guest(GVirDesignerDomain *design, gvir_designer_domain_set_lifecycle(design); gvir_designer_domain_add_console(design); gvir_designer_domain_add_input(design); + gvir_designer_domain_add_sound(design);
IMHO we should not be adding sound by default, since it is not the kind of device any server is going to want - it is only relevant to desktop installs. Thus it should be opt-in. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- libvirt-designer/libvirt-designer-domain.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index 7b1cb33..df8f0cb 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -1,7 +1,7 @@ /* * libvirt-designer-domain.c: libvirt domain configuration * - * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2012-2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,6 +20,7 @@ * Authors: * Daniel P. Berrange <berrange@redhat.com> * Michal Privoznik <mprivozn@redhat.com> + * Christophe Fergeau <cfergeau@redhat.com> */ #include <config.h> -- 1.8.1.4

This allows to choose between SPICE, VNC or a local display, which will go through SDL or 'desktop' depending on the hypervisor. --- configure.ac | 2 +- examples/virtxml.c | 4 ++ libvirt-designer/libvirt-designer-domain.c | 111 +++++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.h | 11 +++ libvirt-designer/libvirt-designer.sym | 2 + 5 files changed, 129 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b361f7b..ffe6760 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ AC_CANONICAL_HOST AM_SILENT_RULES([yes]) LIBOSINFO_REQUIRED=0.2.6 -LIBVIRT_GCONFIG_REQUIRED=0.0.9 +LIBVIRT_GCONFIG_REQUIRED=0.1.7 LIBVIRT_GOBJECT_REQUIRED=0.1.3 GOBJECT_INTROSPECTION_REQUIRED=0.10.8 diff --git a/examples/virtxml.c b/examples/virtxml.c index 1e9f78a..b874a90 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -568,6 +568,10 @@ main(int argc, char *argv[]) gvir_designer_domain_setup_machine(domain, &error); CHECK_ERROR; + g_object_unref(gvir_designer_domain_add_graphics(domain, + GVIR_DESIGNER_DOMAIN_GRAPHICS_SPICE, + &error)); + CHECK_ERROR; if (arch_str) { gvir_designer_domain_setup_container_full(domain, arch_str, &error); diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index df8f0cb..1222d21 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -351,6 +351,117 @@ static void gvir_designer_domain_add_clock(GVirDesignerDomain *design) g_object_unref(G_OBJECT(clock)); } + +static GVirConfigDomainGraphics * +gvir_designer_domain_create_graphics_desktop(GVirDesignerDomain *design, + GError **error) +{ + int virt_type; + + virt_type = gvir_config_domain_get_virt_type(design->priv->config); + + switch (virt_type) { + case GVIR_CONFIG_DOMAIN_VIRT_QEMU: + case GVIR_CONFIG_DOMAIN_VIRT_KQEMU: + case GVIR_CONFIG_DOMAIN_VIRT_KVM: { + GVirConfigDomainGraphicsSdl *sdl; + sdl = gvir_config_domain_graphics_sdl_new(); + return GVIR_CONFIG_DOMAIN_GRAPHICS(sdl); + } + case GVIR_CONFIG_DOMAIN_VIRT_VBOX: { + GVirConfigDomainGraphicsDesktop *desktop; + desktop = gvir_config_domain_graphics_desktop_new(); + return GVIR_CONFIG_DOMAIN_GRAPHICS(desktop); + } + default: + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "Virt type %d does not support this graphics output", + virt_type); + return NULL; + } +} + +/** + * gvir_designer_domain_add_graphics: + * @design: (transfer none): the domain designer instance + * @error: return location for a #GError, or NULL + * + * Add a new graphical framebuffer to @design. This allows + * to see what the VM displays. + * Remote display protocols will only be listening on localhost, and the + * port will be automatically allocated when the VM starts (usually + * starting at 5900). You can manipulate further the returned + * #GVirConfigDomainGraphics if you want a different behaviour. + * When setting up a SPICE display, the SPICE agent channel will be + * automatically added to the VM if it's supported and not already + * present. + * + * Returns: (transfer full): the pointer to the new graphical framebuffer + * configuration object. + */ +GVirConfigDomainGraphics * +gvir_designer_domain_add_graphics(GVirDesignerDomain *design, + GVirDesignerDomainGraphics type, + GError **error) +{ + GVirConfigDomainGraphics *graphics; + + g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL); + g_return_val_if_fail(!error_is_set(error), NULL); + + switch (type) { + case GVIR_DESIGNER_DOMAIN_GRAPHICS_DESKTOP: { + graphics = gvir_designer_domain_create_graphics_desktop(design, error); + if (graphics == NULL) + return NULL; + } + + case GVIR_DESIGNER_DOMAIN_GRAPHICS_RDP: { + GVirConfigDomainGraphicsRdp *rdp; + + rdp = gvir_config_domain_graphics_rdp_new(); + gvir_config_domain_graphics_rdp_set_autoport(rdp, TRUE); + graphics = GVIR_CONFIG_DOMAIN_GRAPHICS(rdp); + + break; + } + + case GVIR_DESIGNER_DOMAIN_GRAPHICS_SPICE: { + GVirConfigDomainGraphicsSpice *spice; + + spice = gvir_config_domain_graphics_spice_new(); + gvir_config_domain_graphics_spice_set_autoport(spice, TRUE); + /* FIXME: Should only be done for local domains */ + gvir_config_domain_graphics_spice_set_image_compression(spice, + GVIR_CONFIG_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_OFF); + graphics = GVIR_CONFIG_DOMAIN_GRAPHICS(spice); + + break; + } + + case GVIR_DESIGNER_DOMAIN_GRAPHICS_VNC: { + GVirConfigDomainGraphicsVnc *vnc; + + vnc = gvir_config_domain_graphics_vnc_new(); + gvir_config_domain_graphics_vnc_set_autoport(vnc, TRUE); + graphics = GVIR_CONFIG_DOMAIN_GRAPHICS(vnc); + + break; + } + + default: + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "Unknown graphics type: %d", type); + g_return_val_if_reached(NULL); + } + + gvir_config_domain_add_device(design->priv->config, + GVIR_CONFIG_DOMAIN_DEVICE(graphics)); + + return graphics; +} + + static void gvir_designer_domain_add_power_management(GVirDesignerDomain *design) { GVirConfigDomainPowerManagement *pm; diff --git a/libvirt-designer/libvirt-designer-domain.h b/libvirt-designer/libvirt-designer-domain.h index 83bc0e5..96e9ed6 100644 --- a/libvirt-designer/libvirt-designer-domain.h +++ b/libvirt-designer/libvirt-designer-domain.h @@ -44,6 +44,13 @@ typedef enum { GVIR_DESIGNER_DOMAIN_RESOURCES_RECOMMENDED, } GVirDesignerDomainResources; +typedef enum { + GVIR_DESIGNER_DOMAIN_GRAPHICS_DESKTOP, + GVIR_DESIGNER_DOMAIN_GRAPHICS_RDP, + GVIR_DESIGNER_DOMAIN_GRAPHICS_SPICE, + GVIR_DESIGNER_DOMAIN_GRAPHICS_VNC, +} GVirDesignerDomainGraphics; + typedef struct _GVirDesignerDomain GVirDesignerDomain; typedef struct _GVirDesignerDomainPrivate GVirDesignerDomainPrivate; typedef struct _GVirDesignerDomainClass GVirDesignerDomainClass; @@ -111,6 +118,10 @@ GVirConfigDomainInterface *gvir_designer_domain_add_interface_network(GVirDesign const char *network, GError **error); +GVirConfigDomainGraphics *gvir_designer_domain_add_graphics(GVirDesignerDomain *design, + GVirDesignerDomainGraphics type, + GError **error); + gboolean gvir_designer_domain_setup_resources(GVirDesignerDomain *design, GVirDesignerDomainResources req, GError **error); diff --git a/libvirt-designer/libvirt-designer.sym b/libvirt-designer/libvirt-designer.sym index 750ebb2..12c9912 100644 --- a/libvirt-designer/libvirt-designer.sym +++ b/libvirt-designer/libvirt-designer.sym @@ -5,6 +5,7 @@ LIBVIRT_DESIGNER_0.0.1 { gvir_designer_domain_new; gvir_designer_domain_get_type; + gvir_designer_domain_graphics_get_type; gvir_designer_domain_get_config; gvir_designer_domain_get_os; gvir_designer_domain_get_platform; @@ -15,6 +16,7 @@ LIBVIRT_DESIGNER_0.0.1 { gvir_designer_domain_add_disk_file; gvir_designer_domain_add_disk_device; + gvir_designer_domain_add_graphics; gvir_designer_domain_add_interface_network; gvir_designer_domain_setup_resources; gvir_designer_domain_resources_get_type; -- 1.8.1.4

When the user sets up the graphical framebuffer to use SPICE, we now add automatically the SPICE agent channel if it's not present already. --- libvirt-designer/libvirt-designer-domain.c | 85 ++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index 1222d21..7aed372 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -72,6 +72,7 @@ static gboolean error_is_set(GError **error) return ((error != NULL) && (*error != NULL)); } +static const char GVIR_DESIGNER_SPICE_CHANNEL_NAME[] = "com.redhat.spice.0"; static const char GVIR_DESIGNER_VIRTIO_BLOCK_DEVICE_ID[] = "http://pciids.sourceforge.net/v2.2/pci.ids/1af4/1001"; enum { @@ -317,6 +318,29 @@ end: } +static GList * +gvir_designer_domain_get_device_by_type(GVirDesignerDomain *design, GType type) +{ + GList *devices; + GList *it; + GList *matched_devices = NULL; + + devices = gvir_config_domain_get_devices(design->priv->config); + for (it = devices; it != NULL; it = it->next) { + GType device_type = G_OBJECT_TYPE(it->data); + + if (g_type_is_a(device_type, type)) { + matched_devices = g_list_prepend(matched_devices, + g_object_ref(G_OBJECT(it->data))); + } + + } + g_list_free_full(devices, g_object_unref); + + return g_list_reverse(matched_devices); +} + + static void gvir_designer_domain_add_clock(GVirDesignerDomain *design) { GVirConfigDomainClock *clock; @@ -352,6 +376,65 @@ static void gvir_designer_domain_add_clock(GVirDesignerDomain *design) } +static gboolean +gvir_designer_domain_has_spice_channel(GVirDesignerDomain *design) +{ + GList *devices; + GList *it; + gboolean has_spice = FALSE; + + devices = gvir_designer_domain_get_device_by_type(design, + GVIR_CONFIG_TYPE_DOMAIN_CHANNEL); + for (it = devices; it != NULL; it = it->next) { + GVirConfigDomainChannel *channel; + const char *target_name; + channel = GVIR_CONFIG_DOMAIN_CHANNEL(it->data); + target_name = gvir_config_domain_channel_get_target_name(channel); + if (g_strcmp0(target_name, GVIR_DESIGNER_SPICE_CHANNEL_NAME) == 0) { + /* FIXME could do more sanity checks (check if the channel + * source has the 'spicevmc' type) + */ + GVirConfigDomainChannelTargetType target_type; + target_type = gvir_config_domain_channel_get_target_type(channel); + if (target_type == GVIR_CONFIG_DOMAIN_CHANNEL_TARGET_VIRTIO) { + has_spice = TRUE; + } else { + g_critical("Inconsistent SPICE channel, target type is wrong (%d)", + target_type); + has_spice = FALSE; + } + + break; + } + } + g_list_free_full(devices, g_object_unref); + + return has_spice; +} + + +static void gvir_designer_domain_add_spice_channel(GVirDesignerDomain *design) +{ + /* FIXME: error out if there is no support for the vioserial device */ + GVirConfigDomainChannel *channel; + GVirConfigDomainChardevSourceSpiceVmc *vmc; + + channel = gvir_config_domain_channel_new(); + gvir_config_domain_channel_set_target_type(channel, + GVIR_CONFIG_DOMAIN_CHANNEL_TARGET_VIRTIO); + gvir_config_domain_channel_set_target_name(channel, + GVIR_DESIGNER_SPICE_CHANNEL_NAME); + vmc = gvir_config_domain_chardev_source_spicevmc_new(); + gvir_config_domain_chardev_set_source(GVIR_CONFIG_DOMAIN_CHARDEV(channel), + GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE(vmc)); + g_object_unref(G_OBJECT(vmc)); + + gvir_config_domain_add_device(design->priv->config, + GVIR_CONFIG_DOMAIN_DEVICE(channel)); + g_object_unref(G_OBJECT(channel)); +} + + static GVirConfigDomainGraphics * gvir_designer_domain_create_graphics_desktop(GVirDesignerDomain *design, GError **error) @@ -435,6 +518,8 @@ gvir_designer_domain_add_graphics(GVirDesignerDomain *design, gvir_config_domain_graphics_spice_set_image_compression(spice, GVIR_CONFIG_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_OFF); graphics = GVIR_CONFIG_DOMAIN_GRAPHICS(spice); + if (!gvir_designer_domain_has_spice_channel(design)) + gvir_designer_domain_add_spice_channel(design); break; } -- 1.8.1.4

This makes use of the new gvir_designer_domain_get_supported_devices() method. --- libvirt-designer/libvirt-designer-domain.c | 42 +++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index 7aed372..faf2176 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -73,6 +73,7 @@ static gboolean error_is_set(GError **error) } static const char GVIR_DESIGNER_SPICE_CHANNEL_NAME[] = "com.redhat.spice.0"; +static const char GVIR_DESIGNER_SPICE_CHANNEL_DEVICE_ID[] = "http://pciids.sourceforge.net/v2.2/pci.ids/1af4/1003"; static const char GVIR_DESIGNER_VIRTIO_BLOCK_DEVICE_ID[] = "http://pciids.sourceforge.net/v2.2/pci.ids/1af4/1001"; enum { @@ -413,12 +414,45 @@ gvir_designer_domain_has_spice_channel(GVirDesignerDomain *design) } -static void gvir_designer_domain_add_spice_channel(GVirDesignerDomain *design) +static gboolean +gvir_designer_domain_supports_spice_channel(GVirDesignerDomain *design) +{ + OsinfoDeviceList *devices; + OsinfoFilter *filter; + gboolean vioserial_found = FALSE; + + filter = osinfo_filter_new(); + osinfo_filter_add_constraint(filter, + OSINFO_ENTITY_PROP_ID, + GVIR_DESIGNER_SPICE_CHANNEL_DEVICE_ID); + devices = gvir_designer_domain_get_supported_devices(design, filter); + if (devices) { + g_warn_if_fail(osinfo_list_get_length(OSINFO_LIST(devices)) <= 1); + if (osinfo_list_get_length(OSINFO_LIST(devices)) >= 1) + vioserial_found = TRUE; + g_object_unref(G_OBJECT(devices)); + } + if (filter) + g_object_unref(G_OBJECT(filter)); + + return vioserial_found; +} + + +static gboolean gvir_designer_domain_add_spice_channel(GVirDesignerDomain *design, + GError **error) { - /* FIXME: error out if there is no support for the vioserial device */ GVirConfigDomainChannel *channel; GVirConfigDomainChardevSourceSpiceVmc *vmc; + if (!gvir_designer_domain_supports_spice_channel(design)) { + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "OS and/or hypervisor don't support virtio-serial" + " which is required by the SPICE channel"); + g_debug("SPICE channel not supported"); + return FALSE; + } + channel = gvir_config_domain_channel_new(); gvir_config_domain_channel_set_target_type(channel, GVIR_CONFIG_DOMAIN_CHANNEL_TARGET_VIRTIO); @@ -432,6 +466,8 @@ static void gvir_designer_domain_add_spice_channel(GVirDesignerDomain *design) gvir_config_domain_add_device(design->priv->config, GVIR_CONFIG_DOMAIN_DEVICE(channel)); g_object_unref(G_OBJECT(channel)); + + return TRUE; } @@ -519,7 +555,7 @@ gvir_designer_domain_add_graphics(GVirDesignerDomain *design, GVIR_CONFIG_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_OFF); graphics = GVIR_CONFIG_DOMAIN_GRAPHICS(spice); if (!gvir_designer_domain_has_spice_channel(design)) - gvir_designer_domain_add_spice_channel(design); + gvir_designer_domain_add_spice_channel(design, NULL); break; } -- 1.8.1.4

This will add an USB redirection channel to the VM. This can be called multiple times to redirect several USB devices at once. This will also adds the needed controllers if they are not already present in the VM. The current code has 2 shortcomings: - USB redirection is only supported with SPICE, but this is not checked for - the USB controller added to the VM are hardcoded, no check if they are supported by the OS, hypervisor, ... --- examples/virtxml.c | 5 ++ libvirt-designer/libvirt-designer-domain.c | 117 +++++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.h | 1 + libvirt-designer/libvirt-designer.sym | 2 + 4 files changed, 125 insertions(+) diff --git a/examples/virtxml.c b/examples/virtxml.c index b874a90..c9dc36d 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -497,6 +497,7 @@ main(int argc, char *argv[]) static char *resources_str = NULL; GVirDesignerDomainResources resources; GOptionContext *context = NULL; + unsigned int i; static GOptionEntry entries[] = { @@ -572,6 +573,10 @@ main(int argc, char *argv[]) GVIR_DESIGNER_DOMAIN_GRAPHICS_SPICE, &error)); CHECK_ERROR; + for (i = 0; i < 4; i++) { + g_object_unref(gvir_designer_domain_add_usb_redir(domain, &error)); + CHECK_ERROR; + } if (arch_str) { gvir_designer_domain_setup_container_full(domain, arch_str, &error); diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index faf2176..50d09c5 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -583,6 +583,123 @@ gvir_designer_domain_add_graphics(GVirDesignerDomain *design, } +static gboolean +gvir_designer_domain_supports_usb(GVirDesignerDomain *design) +{ + GList *devices; + devices = gvir_designer_domain_get_device_by_type(design, + GVIR_CONFIG_TYPE_DOMAIN_CONTROLLER_USB); + g_list_free_full(devices, g_object_unref); + + return (devices != NULL); +} + + +static GVirConfigDomainControllerUsb * +gvir_designer_domain_create_usb_controller(GVirDesignerDomain *design, + GVirConfigDomainControllerUsbModel model, + guint indx, + GVirConfigDomainControllerUsb *master, + guint start_port) +{ + GVirConfigDomainControllerUsb *controller; + + controller = gvir_config_domain_controller_usb_new(); + gvir_config_domain_controller_usb_set_model(controller, model); + gvir_config_domain_controller_set_index(GVIR_CONFIG_DOMAIN_CONTROLLER(controller), indx); + if (master) + gvir_config_domain_controller_usb_set_master(controller, master, start_port); + + gvir_config_domain_add_device(design->priv->config, + GVIR_CONFIG_DOMAIN_DEVICE(controller)); + + return controller; +} + + +static void +gvir_designer_domain_add_usb_controllers(GVirDesignerDomain *design) +{ + GVirConfigDomainControllerUsb *master; + GVirConfigDomainControllerUsb *controller; + + g_debug("Adding USB controllers"); + + master = gvir_designer_domain_create_usb_controller(design, + GVIR_CONFIG_DOMAIN_CONTROLLER_USB_MODEL_ICH9_EHCI1, + 0, + NULL, + 0); + controller = gvir_designer_domain_create_usb_controller(design, + GVIR_CONFIG_DOMAIN_CONTROLLER_USB_MODEL_ICH9_UHCI1, + 0, + master, + 0); + g_object_unref(G_OBJECT(controller)); + controller = gvir_designer_domain_create_usb_controller(design, + GVIR_CONFIG_DOMAIN_CONTROLLER_USB_MODEL_ICH9_UHCI2, + 0, + master, + 2); + g_object_unref(G_OBJECT(controller)); + controller = gvir_designer_domain_create_usb_controller(design, + GVIR_CONFIG_DOMAIN_CONTROLLER_USB_MODEL_ICH9_UHCI3, + 0, + master, + 4); + g_object_unref(G_OBJECT(controller)); + g_object_unref(G_OBJECT(master)); +} + + +/** + * gvir_designer_domain_add_usb_redir: + * @design: (transfer none): the domain designer instance + * @error: return location for a #GError, or NULL + * + * Add a new usb redirection channel into @design. This allows to redirect + * an USB device from the SPICE client to the guest. One USB device + * can be redirected per redirection channel, this function can + * be called multiple times if you need to redirect multiple devices + * simultaneously. An USB2 EHCI controller and USB1 UHCI controllers + * will be automatically added to @design if @design does not have + * USB controllers yet. + * + * Returns: (transfer full): the pointer to the new USB redir channel + */ +GVirConfigDomainRedirdev * +gvir_designer_domain_add_usb_redir(GVirDesignerDomain *design, GError **error) +{ + /* FIXME: check if OS/hypervisor support USB + * check if SPICE is being used + */ + GVirConfigDomainRedirdev *redirdev; + GVirConfigDomainChardevSourceSpiceVmc *vmc; + + g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL); + g_return_val_if_fail(!error_is_set(error), NULL); + + redirdev = gvir_config_domain_redirdev_new(); + gvir_config_domain_redirdev_set_bus(redirdev, + GVIR_CONFIG_DOMAIN_REDIRDEV_BUS_USB); + vmc = gvir_config_domain_chardev_source_spicevmc_new(); + gvir_config_domain_chardev_set_source(GVIR_CONFIG_DOMAIN_CHARDEV(redirdev), + GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE(vmc)); + g_object_unref(G_OBJECT(vmc)); + + gvir_config_domain_add_device(design->priv->config, + GVIR_CONFIG_DOMAIN_DEVICE(redirdev)); + + if (!gvir_designer_domain_supports_usb(design)) { + gvir_designer_domain_add_usb_controllers(design); + } else { + g_debug("USB controllers are already present"); + } + + return redirdev; +} + + static void gvir_designer_domain_add_power_management(GVirDesignerDomain *design) { GVirConfigDomainPowerManagement *pm; diff --git a/libvirt-designer/libvirt-designer-domain.h b/libvirt-designer/libvirt-designer-domain.h index 96e9ed6..1c130c6 100644 --- a/libvirt-designer/libvirt-designer-domain.h +++ b/libvirt-designer/libvirt-designer-domain.h @@ -121,6 +121,7 @@ GVirConfigDomainInterface *gvir_designer_domain_add_interface_network(GVirDesign GVirConfigDomainGraphics *gvir_designer_domain_add_graphics(GVirDesignerDomain *design, GVirDesignerDomainGraphics type, GError **error); +GVirConfigDomainRedirdev *gvir_designer_domain_add_usb_redir(GVirDesignerDomain *design, GError **error); gboolean gvir_designer_domain_setup_resources(GVirDesignerDomain *design, GVirDesignerDomainResources req, diff --git a/libvirt-designer/libvirt-designer.sym b/libvirt-designer/libvirt-designer.sym index 12c9912..eec33b1 100644 --- a/libvirt-designer/libvirt-designer.sym +++ b/libvirt-designer/libvirt-designer.sym @@ -18,6 +18,8 @@ LIBVIRT_DESIGNER_0.0.1 { gvir_designer_domain_add_disk_device; gvir_designer_domain_add_graphics; gvir_designer_domain_add_interface_network; + gvir_designer_domain_add_usb_redir; + gvir_designer_domain_setup_resources; gvir_designer_domain_resources_get_type; -- 1.8.1.4

This setups smartcard redirection to the guest. I'm not yet fully sure what users could want to tweak there (there are various ways of setting up the smartcard redirection), so this code may need to be made more flexible. The current code is also not checking whether the hypervisor supports this kind of redirection or not. --- examples/virtxml.c | 2 ++ libvirt-designer/libvirt-designer-domain.c | 36 ++++++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.h | 1 + libvirt-designer/libvirt-designer.sym | 1 + 4 files changed, 40 insertions(+) diff --git a/examples/virtxml.c b/examples/virtxml.c index c9dc36d..b56ce0d 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -577,6 +577,8 @@ main(int argc, char *argv[]) g_object_unref(gvir_designer_domain_add_usb_redir(domain, &error)); CHECK_ERROR; } + g_object_unref(gvir_designer_domain_add_smartcard(domain, &error)); + CHECK_ERROR; if (arch_str) { gvir_designer_domain_setup_container_full(domain, arch_str, &error); diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index 50d09c5..601cde5 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -700,6 +700,42 @@ gvir_designer_domain_add_usb_redir(GVirDesignerDomain *design, GError **error) } +/** + * gvir_designer_domain_add_smartcard: + * @design: (transfer none): the domain designer instance + * @error: return location for a #GError, or NULL + * + * Add a new virtual smartcard reader to @design. This will allow to + * share a smartcard reader between the guest and the host. + * + * Returns: (transfer full): the pointer to the new smartcard device + */ +GVirConfigDomainSmartcard * +gvir_designer_domain_add_smartcard(GVirDesignerDomain *design, GError **error) +{ + /* FIXME: check if OS/hypervisor support smartcard, might need + * libosinfo improvements + */ + GVirConfigDomainSmartcardPassthrough *smartcard; + GVirConfigDomainChardevSourceSpiceVmc *vmc; + GVirConfigDomainChardevSource *source; + + g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL); + g_return_val_if_fail(!error_is_set(error), NULL); + + smartcard = gvir_config_domain_smartcard_passthrough_new(); + vmc = gvir_config_domain_chardev_source_spicevmc_new(); + source = GVIR_CONFIG_DOMAIN_CHARDEV_SOURCE(vmc); + gvir_config_domain_smartcard_passthrough_set_source(smartcard, source); + g_object_unref(G_OBJECT(vmc)); + + gvir_config_domain_add_device(design->priv->config, + GVIR_CONFIG_DOMAIN_DEVICE(smartcard)); + + return GVIR_CONFIG_DOMAIN_SMARTCARD(smartcard); +} + + static void gvir_designer_domain_add_power_management(GVirDesignerDomain *design) { GVirConfigDomainPowerManagement *pm; diff --git a/libvirt-designer/libvirt-designer-domain.h b/libvirt-designer/libvirt-designer-domain.h index 1c130c6..1102232 100644 --- a/libvirt-designer/libvirt-designer-domain.h +++ b/libvirt-designer/libvirt-designer-domain.h @@ -121,6 +121,7 @@ GVirConfigDomainInterface *gvir_designer_domain_add_interface_network(GVirDesign GVirConfigDomainGraphics *gvir_designer_domain_add_graphics(GVirDesignerDomain *design, GVirDesignerDomainGraphics type, GError **error); +GVirConfigDomainSmartcard *gvir_designer_domain_add_smartcard(GVirDesignerDomain *design, GError **error); GVirConfigDomainRedirdev *gvir_designer_domain_add_usb_redir(GVirDesignerDomain *design, GError **error); gboolean gvir_designer_domain_setup_resources(GVirDesignerDomain *design, diff --git a/libvirt-designer/libvirt-designer.sym b/libvirt-designer/libvirt-designer.sym index eec33b1..3441bec 100644 --- a/libvirt-designer/libvirt-designer.sym +++ b/libvirt-designer/libvirt-designer.sym @@ -18,6 +18,7 @@ LIBVIRT_DESIGNER_0.0.1 { gvir_designer_domain_add_disk_device; gvir_designer_domain_add_graphics; gvir_designer_domain_add_interface_network; + gvir_designer_domain_add_smartcard; gvir_designer_domain_add_usb_redir; gvir_designer_domain_setup_resources; -- 1.8.1.4

This takes into account the devices specified by the deployment, if this fails, consider the intersection of devices supported by the OS and by the platform, and if this still fails, falls back to a hardcoded hypervisor type -> video model mapping. --- examples/virtxml.c | 2 + libvirt-designer/libvirt-designer-domain.c | 172 ++++++++++++++++++++++++++++- libvirt-designer/libvirt-designer-domain.h | 2 + libvirt-designer/libvirt-designer.sym | 1 + 4 files changed, 176 insertions(+), 1 deletion(-) diff --git a/examples/virtxml.c b/examples/virtxml.c index b56ce0d..a7a1a0f 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -579,6 +579,8 @@ main(int argc, char *argv[]) } g_object_unref(gvir_designer_domain_add_smartcard(domain, &error)); CHECK_ERROR; + g_object_unref(gvir_designer_domain_add_video(domain, &error)); + CHECK_ERROR; if (arch_str) { gvir_designer_domain_setup_container_full(domain, arch_str, &error); diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index 601cde5..9fef041 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -1156,7 +1156,6 @@ gvir_designer_domain_setup_guest(GVirDesignerDomain *design, gvir_designer_domain_add_input(design); gvir_designer_domain_add_sound(design); - ret = TRUE; cleanup: if (domain != NULL) g_object_unref(domain); @@ -1772,6 +1771,177 @@ gvir_designer_domain_add_interface_network(GVirDesignerDomain *design, return ret; } +static GVirConfigDomainVideoModel +gvir_designer_domain_video_model_str_to_enum(const char *model_str, + GError **error) +{ + GVirConfigDomainVideoModel model; + + if (g_str_equal(model_str, "vga")) { + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_VGA; + } else if (g_str_equal(model_str, "cirrus")) { + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_CIRRUS; + } else if (g_str_equal(model_str, "vmvga")) { + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_VMVGA; + } else if (g_str_equal(model_str, "xen")) { + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_XEN; + } else if (g_str_equal(model_str, "vbox")) { + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_VBOX; + } else if (g_str_equal(model_str, "qxl")) { + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_QXL; + } else { + g_debug("unsupported video model type '%s'", model_str); + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "unsupported video model type '%s'", model_str); + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_VGA; + } + + return model; +} + +/* FIXME: belongs in platform descriptions, maybe useful as a last resort */ +static GVirConfigDomainVideoModel +gvir_designer_domain_video_model_from_virt_type(GVirDesignerDomain *design) +{ + GVirConfigDomainVirtType virt_type; + GVirConfigDomainVideoModel model; + + virt_type = gvir_config_domain_get_virt_type(design->priv->config); + switch (virt_type) { + case GVIR_CONFIG_DOMAIN_VIRT_QEMU: + case GVIR_CONFIG_DOMAIN_VIRT_KQEMU: + case GVIR_CONFIG_DOMAIN_VIRT_KVM: + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_QXL; + break; + case GVIR_CONFIG_DOMAIN_VIRT_XEN: + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_XEN; + break; + case GVIR_CONFIG_DOMAIN_VIRT_VMWARE: + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_VMVGA; + break; + case GVIR_CONFIG_DOMAIN_VIRT_VBOX: + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_VBOX; + break; + case GVIR_CONFIG_DOMAIN_VIRT_LXC: + case GVIR_CONFIG_DOMAIN_VIRT_UML: + case GVIR_CONFIG_DOMAIN_VIRT_OPENVZ: + case GVIR_CONFIG_DOMAIN_VIRT_VSERVER: + case GVIR_CONFIG_DOMAIN_VIRT_LDOM: + case GVIR_CONFIG_DOMAIN_VIRT_TEST: + case GVIR_CONFIG_DOMAIN_VIRT_HYPERV: + case GVIR_CONFIG_DOMAIN_VIRT_ONE: + case GVIR_CONFIG_DOMAIN_VIRT_PHYP: + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_VGA; + break; + default: + g_warn_if_reached(); + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_VGA; + break; + } + + return model; +} + +static const gchar * +gvir_designer_domain_get_preferred_video_model(GVirDesignerDomain *design, + GError **error) +{ + const gchar *ret = NULL; + OsinfoDeviceLink *dev_link = NULL; + OsinfoDevice *dev; + + dev_link = gvir_designer_domain_get_preferred_device(design, "video", error); + if (!dev_link) + goto cleanup; + + dev = osinfo_devicelink_get_target(dev_link); + if (dev) + ret = osinfo_device_get_name(dev); + +cleanup: + if (dev_link) + g_object_unref(dev_link); + return ret; +} + +static GVirConfigDomainVideoModel +gvir_designer_domain_get_fallback_video_model(GVirDesignerDomain *design) +{ + OsinfoDeviceList *supported_devices = NULL; + OsinfoFilter *filter = NULL; + OsinfoDevice *device = NULL; + const char *model_str; + GVirConfigDomainVideoModel model; + GError *error = NULL; + + model = GVIR_CONFIG_DOMAIN_VIDEO_MODEL_VGA; + + filter = osinfo_filter_new(); + osinfo_filter_add_constraint(filter, OSINFO_DEVICE_PROP_CLASS, "video"); + supported_devices = gvir_designer_domain_get_supported_devices(design, filter); + if ((supported_devices == NULL) || osinfo_list_get_length(OSINFO_LIST(supported_devices)) == 0) + goto fallback; + + device = OSINFO_DEVICE(osinfo_list_get_nth(OSINFO_LIST(supported_devices), 0)); + model_str = osinfo_device_get_name(device); + model = gvir_designer_domain_video_model_str_to_enum(model_str, + &error); + if (error != NULL) { + g_clear_error(&error); + goto fallback; + } + goto end; + +fallback: + model = gvir_designer_domain_video_model_from_virt_type(design); + +end: + if (filter != NULL) + g_object_unref(G_OBJECT(filter)); + if (supported_devices != NULL) + g_object_unref(G_OBJECT(supported_devices)); + + return model; +} + +/** + * gvir_designer_domain_add_video: + * @design: (transfer none): the domain designer instance + * @error: return location for a #GError, or NULL + * + * Add a new video device into @design. + * + * Returns: (transfer full): the pointer to the new video device. + */ +GVirConfigDomainVideo * +gvir_designer_domain_add_video(GVirDesignerDomain *design, GError **error) +{ + GVirConfigDomainVideo *video; + const gchar *model_str = NULL; + GVirConfigDomainVideoModel model; + + g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL); + g_return_val_if_fail(!error_is_set(error), NULL); + + model_str = gvir_designer_domain_get_preferred_video_model(design, NULL); + if (model_str != NULL) { + model = gvir_designer_domain_video_model_str_to_enum(model_str, error); + if (error_is_set(error)) { + g_clear_error(error); + model = gvir_designer_domain_get_fallback_video_model(design); + } + } else { + model = gvir_designer_domain_get_fallback_video_model(design); + } + + video = gvir_config_domain_video_new(); + gvir_config_domain_video_set_model(video, model); + gvir_config_domain_add_device(design->priv->config, + GVIR_CONFIG_DOMAIN_DEVICE(video)); + + return video; +} + static void gvir_designer_domain_get_resources(OsinfoResourcesList *res_list, diff --git a/libvirt-designer/libvirt-designer-domain.h b/libvirt-designer/libvirt-designer-domain.h index 1102232..e3afbe1 100644 --- a/libvirt-designer/libvirt-designer-domain.h +++ b/libvirt-designer/libvirt-designer-domain.h @@ -123,6 +123,8 @@ GVirConfigDomainGraphics *gvir_designer_domain_add_graphics(GVirDesignerDomain * GError **error); GVirConfigDomainSmartcard *gvir_designer_domain_add_smartcard(GVirDesignerDomain *design, GError **error); GVirConfigDomainRedirdev *gvir_designer_domain_add_usb_redir(GVirDesignerDomain *design, GError **error); +GVirConfigDomainVideo *gvir_designer_domain_add_video(GVirDesignerDomain *design, + GError **error); gboolean gvir_designer_domain_setup_resources(GVirDesignerDomain *design, GVirDesignerDomainResources req, diff --git a/libvirt-designer/libvirt-designer.sym b/libvirt-designer/libvirt-designer.sym index 3441bec..afacab7 100644 --- a/libvirt-designer/libvirt-designer.sym +++ b/libvirt-designer/libvirt-designer.sym @@ -20,6 +20,7 @@ LIBVIRT_DESIGNER_0.0.1 { gvir_designer_domain_add_interface_network; gvir_designer_domain_add_smartcard; gvir_designer_domain_add_usb_redir; + gvir_designer_domain_add_video; gvir_designer_domain_setup_resources; gvir_designer_domain_resources_get_type; -- 1.8.1.4

Apart from danpb's comment in patch #3 which I've fixed locally, any more feedback/review on this series? Christophe On Wed, Apr 03, 2013 at 11:37:59AM +0200, Christophe Fergeau wrote:
This series builds on the previous one (the one adding gvir_designer_domain_get_supported_devices()). It adds methods to add more devices disks/network interfaces to GVirDesignDomain. Some parts like 'Automatically add SPICE channel with SPICE graphics' may not be what we want, but I've tried to make the external API as easy as possible.
Christophe
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On Thu, Apr 18, 2013 at 04:17:17PM +0200, Michal Privoznik wrote:
On 17.04.2013 10:37, Christophe Fergeau wrote:
Apart from danpb's comment in patch #3 which I've fixed locally, any more feedback/review on this series?
Christophe
Same applies here. I am unable to apply the patchset cleanly. Could you repost please?
v2 posted, goes on top of the v2 of the other patch series (the 'improve disk bus type handling' one). Christophe
participants (3)
-
Christophe Fergeau
-
Daniel P. Berrange
-
Michal Privoznik