[libvirt] [libvirt-designer][PATCH v2 0/4] Basic disk & interface support

with small example called virtxml. The first patch has been ACKed. I am sending it for completeness sake. diff to v1: -Martin's and Chritophe's review notes worked in. Michal Privoznik (4): Load osinfo DB on init domain: Introduce disk support examples: Create an example of usage program domain: Introduce interface support .gitignore | 1 + Makefile.am | 2 +- configure.ac | 12 +- examples/Makefile.am | 21 ++ examples/virtxml.c | 395 ++++++++++++++++++++++++++ libvirt-designer/Makefile.am | 1 + libvirt-designer/libvirt-designer-domain.c | 347 ++++++++++++++++++++++- libvirt-designer/libvirt-designer-domain.h | 12 +- libvirt-designer/libvirt-designer-internal.h | 30 ++ libvirt-designer/libvirt-designer-main.c | 17 +- libvirt-designer/libvirt-designer.sym | 4 + 11 files changed, 837 insertions(+), 5 deletions(-) create mode 100644 examples/Makefile.am create mode 100644 examples/virtxml.c create mode 100644 libvirt-designer/libvirt-designer-internal.h -- 1.7.8.6

as we need this DB later to find an OS or hypervisor and supported devices. --- libvirt-designer/Makefile.am | 1 + libvirt-designer/libvirt-designer-domain.c | 5 +++- libvirt-designer/libvirt-designer-internal.h | 30 ++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-main.c | 17 +++++++++++++- 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 libvirt-designer/libvirt-designer-internal.h diff --git a/libvirt-designer/Makefile.am b/libvirt-designer/Makefile.am index cf40419..8f10c41 100644 --- a/libvirt-designer/Makefile.am +++ b/libvirt-designer/Makefile.am @@ -20,6 +20,7 @@ DESIGNER_GENERATED_FILES = \ DESIGNER_HEADER_FILES = \ libvirt-designer.h \ + libvirt-designer-internal.h \ libvirt-designer-main.h \ libvirt-designer-domain.h \ $(NULL) diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index 9b4a7ed..a8cabde 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -17,13 +17,16 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Author: Daniel P. Berrange <berrange@redhat.com> + * Authors: + * Daniel P. Berrange <berrange@redhat.com> + * Michal Privoznik <mprivozn@redhat.com> */ #include <config.h> #include <sys/utsname.h> #include "libvirt-designer/libvirt-designer.h" +#include "libvirt-designer/libvirt-designer-internal.h" #define GVIR_DESIGNER_DOMAIN_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_DESIGNER_TYPE_DOMAIN, GVirDesignerDomainPrivate)) diff --git a/libvirt-designer/libvirt-designer-internal.h b/libvirt-designer/libvirt-designer-internal.h new file mode 100644 index 0000000..bbef922 --- /dev/null +++ b/libvirt-designer/libvirt-designer-internal.h @@ -0,0 +1,30 @@ +/* + * libvirt-designer-internal.h: internal definitions just + * used by code from the library + * + * Copyright (C) 2012 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Michal Privoznik <mprivozn@redhat.com> + */ + +#ifndef __LIBVIRT_DESIGNER_INTERNAL_H__ +#define __LIBVIRT_DESIGNER_INTERNAL_H__ + +extern OsinfoLoader *osinfo_loader; +extern OsinfoDb *osinfo_db; + +#endif /* __LIBVIRT_DESIGNER_INTERNAL_H__ */ diff --git a/libvirt-designer/libvirt-designer-main.c b/libvirt-designer/libvirt-designer-main.c index 60bf8f5..f2381a6 100644 --- a/libvirt-designer/libvirt-designer-main.c +++ b/libvirt-designer/libvirt-designer-main.c @@ -17,7 +17,9 @@ * License along with this library; If not, see * <http://www.gnu.org/licenses/>. * - * Author: Daniel P. Berrange <berrange@redhat.com> + * Authors: + * Daniel P. Berrange <berrange@redhat.com> + * Michal Privoznik <mprivozn@redhat.com> */ #include <config.h> @@ -28,6 +30,9 @@ #include <libvirt-designer/libvirt-designer.h> #include <libvirt-gconfig/libvirt-gconfig.h> +OsinfoLoader *osinfo_loader = NULL; +OsinfoDb *osinfo_db = NULL; + /** * gvir_designer_init: * @argc: (inout): pointer to application's argc @@ -80,5 +85,15 @@ gboolean gvir_designer_init_check(int *argc, gvir_log_handler, NULL); #endif + /* Init libosinfo and load databases from default paths */ + /* XXX maybe we want to let users tell a different path via + * env variable or argv */ + osinfo_loader = osinfo_loader_new(); + osinfo_loader_process_default_path(osinfo_loader, err); + if (err) + return FALSE; + + osinfo_db = osinfo_loader_get_db(osinfo_loader); + return TRUE; } -- 1.7.8.6

Hey, I should have looked more in depth at these commits earlier, sorry for the late feedback ;) On Mon, Sep 10, 2012 at 03:58:25PM +0200, Michal Privoznik wrote:
diff --git a/libvirt-designer/libvirt-designer-internal.h b/libvirt-designer/libvirt-designer-internal.h new file mode 100644 index 0000000..bbef922 --- /dev/null +++ b/libvirt-designer/libvirt-designer-internal.h @@ -0,0 +1,30 @@ +/* + * libvirt-designer-internal.h: internal definitions just + * used by code from the library + * + * Copyright (C) 2012 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Michal Privoznik <mprivozn@redhat.com> + */ + +#ifndef __LIBVIRT_DESIGNER_INTERNAL_H__ +#define __LIBVIRT_DESIGNER_INTERNAL_H__ + +extern OsinfoLoader *osinfo_loader; +extern OsinfoDb *osinfo_db; + +#endif /* __LIBVIRT_DESIGNER_INTERNAL_H__ */ diff --git a/libvirt-designer/libvirt-designer-main.c b/libvirt-designer/libvirt-designer-main.c index 60bf8f5..f2381a6 100644 --- a/libvirt-designer/libvirt-designer-main.c +++ b/libvirt-designer/libvirt-designer-main.c @@ -17,7 +17,9 @@ * License along with this library; If not, see * <http://www.gnu.org/licenses/>. * - * Author: Daniel P. Berrange <berrange@redhat.com> + * Authors: + * Daniel P. Berrange <berrange@redhat.com> + * Michal Privoznik <mprivozn@redhat.com> */
#include <config.h> @@ -28,6 +30,9 @@ #include <libvirt-designer/libvirt-designer.h> #include <libvirt-gconfig/libvirt-gconfig.h>
+OsinfoLoader *osinfo_loader = NULL; +OsinfoDb *osinfo_db = NULL; + /** * gvir_designer_init: * @argc: (inout): pointer to application's argc @@ -80,5 +85,15 @@ gboolean gvir_designer_init_check(int *argc, gvir_log_handler, NULL); #endif
+ /* Init libosinfo and load databases from default paths */ + /* XXX maybe we want to let users tell a different path via + * env variable or argv */
osinfo_loader_process_default_path() looks into $XDG_CONFIG_DIR/libosinfo/db so end users can override it, but users of the library may indeed also want to be able to override it.
+ osinfo_loader = osinfo_loader_new(); + osinfo_loader_process_default_path(osinfo_loader, err); + if (err) + return FALSE;
I'm not sure we want to error out there, see http://git.fedorahosted.org/cgit/libosinfo.git/commit/?id=dbde512c3a64640d61... for my reasoning (and you can try a "mkdir -p ~/.config/libosinfo/db && echo '<bad' >~/.config/libosinfo/db/broken.xml" to get into a 'bad' situation). Christophe

On 12.09.2012 11:19, Christophe Fergeau wrote:
Hey,
I should have looked more in depth at these commits earlier, sorry for the late feedback ;)
Better late than never :)
On Mon, Sep 10, 2012 at 03:58:25PM +0200, Michal Privoznik wrote:
diff --git a/libvirt-designer/libvirt-designer-internal.h b/libvirt-designer/libvirt-designer-internal.h new file mode 100644 index 0000000..bbef922 --- /dev/null +++ b/libvirt-designer/libvirt-designer-internal.h @@ -0,0 +1,30 @@ +/* + * libvirt-designer-internal.h: internal definitions just + * used by code from the library + * + * Copyright (C) 2012 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Michal Privoznik <mprivozn@redhat.com> + */ + +#ifndef __LIBVIRT_DESIGNER_INTERNAL_H__ +#define __LIBVIRT_DESIGNER_INTERNAL_H__ + +extern OsinfoLoader *osinfo_loader; +extern OsinfoDb *osinfo_db; + +#endif /* __LIBVIRT_DESIGNER_INTERNAL_H__ */ diff --git a/libvirt-designer/libvirt-designer-main.c b/libvirt-designer/libvirt-designer-main.c index 60bf8f5..f2381a6 100644 --- a/libvirt-designer/libvirt-designer-main.c +++ b/libvirt-designer/libvirt-designer-main.c @@ -17,7 +17,9 @@ * License along with this library; If not, see * <http://www.gnu.org/licenses/>. * - * Author: Daniel P. Berrange <berrange@redhat.com> + * Authors: + * Daniel P. Berrange <berrange@redhat.com> + * Michal Privoznik <mprivozn@redhat.com> */
#include <config.h> @@ -28,6 +30,9 @@ #include <libvirt-designer/libvirt-designer.h> #include <libvirt-gconfig/libvirt-gconfig.h>
+OsinfoLoader *osinfo_loader = NULL; +OsinfoDb *osinfo_db = NULL; + /** * gvir_designer_init: * @argc: (inout): pointer to application's argc @@ -80,5 +85,15 @@ gboolean gvir_designer_init_check(int *argc, gvir_log_handler, NULL); #endif
+ /* Init libosinfo and load databases from default paths */ + /* XXX maybe we want to let users tell a different path via + * env variable or argv */
osinfo_loader_process_default_path() looks into $XDG_CONFIG_DIR/libosinfo/db so end users can override it, but users of the library may indeed also want to be able to override it.
Yeah; for now I just call process_default_path() however in future users may with to process just a specific file, path, whatever. Don't know if it is something that should be passed through argv[] or an API. I guess we will decide if such moment come.
+ osinfo_loader = osinfo_loader_new(); + osinfo_loader_process_default_path(osinfo_loader, err); + if (err) + return FALSE;
I'm not sure we want to error out there, see http://git.fedorahosted.org/cgit/libosinfo.git/commit/?id=dbde512c3a64640d61... for my reasoning (and you can try a "mkdir -p ~/.config/libosinfo/db && echo '<bad' >~/.config/libosinfo/db/broken.xml" to get into a 'bad' situation).
IIUC, malformed XML doesn't affect loading of other well-formed XMLs, right? If this is the case, then yes - we should not report error. However, if malformed XML results in empty libosinfo DB, then we must report error here as non-empty DB is crucial for libvirt-designer. Michal
Christophe

On Wed, Sep 12, 2012 at 11:48:31AM +0200, Michal Privoznik wrote:
+ osinfo_loader = osinfo_loader_new(); + osinfo_loader_process_default_path(osinfo_loader, err); + if (err) + return FALSE;
I'm not sure we want to error out there, see http://git.fedorahosted.org/cgit/libosinfo.git/commit/?id=dbde512c3a64640d61... for my reasoning (and you can try a "mkdir -p ~/.config/libosinfo/db && echo '<bad' >~/.config/libosinfo/db/broken.xml" to get into a 'bad' situation).
IIUC, malformed XML doesn't affect loading of other well-formed XMLs, right? If this is the case, then yes - we should not report error. However, if malformed XML results in empty libosinfo DB, then we must report error here as non-empty DB is crucial for libvirt-designer.
Malformed XML will not prevent other database files from being loaded, but libosinfo still reports an error in this case. However, osinfo-detect will still be working as expected, you can test it with the example I provided. Maybe it should be up to libosinfo not to error out on invalid XML files, but to have additional API for users who want to be informed about anything going wrong in the loading process. Christophe

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

On 09/10/2012 03:58 PM, Michal Privoznik wrote:
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)); + }
Here you can use Java-style list iteration as well (the one you use in virtxml.c). [...] otherwise looks good, so (as I said earlier) FWIW ACK from me. Martin

On Mon, Sep 10, 2012 at 03:58:26PM +0200, Michal Privoznik wrote:
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 +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");
Opps, don't want to hardcode use of qemu here - need to make this conditional based on the <domain type='...'/> value.
+ 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; +} +/**
Minor note - my preference is to leave 2 blank lines between functions.
+ * 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; +}
I know you've pushed this series already, so fine to just post followup fixes as needed or push directly. 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 :|

On Mon, Sep 10, 2012 at 03:58:26PM +0200, Michal Privoznik wrote:
+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);
NULL is a valid list (empty list), so g_list_copy(NULL); is fine.
+ +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");
g_set_error_literal would be slightly better here.
+ 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)
I haven't looked at the callers, but in public APIs, passing a NULL GError** is acceptable, so this test would be better as 'if (error != NULL && *error != NULL)' (I always wonder why glib does not provide g_error_is_set).
+ 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;
Looks like 'error' will be leaked in we go to error. Christophe

--- .gitignore | 1 + Makefile.am | 2 +- configure.ac | 12 ++- examples/Makefile.am | 21 ++++ examples/virtxml.c | 317 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 351 insertions(+), 2 deletions(-) create mode 100644 examples/Makefile.am create mode 100644 examples/virtxml.c diff --git a/.gitignore b/.gitignore index b7ba45a..d570af8 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ Makefile.in /config.log /config.status /configure +/examples/virtxml /libtool /libvirt-designer-1.0.pc /libvirt-designer.spec diff --git a/Makefile.am b/Makefile.am index b0f68c0..ab06626 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS = libvirt-designer +SUBDIRS = libvirt-designer examples ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 795990f..bdee845 100644 --- a/configure.ac +++ b/configure.ac @@ -13,6 +13,7 @@ AM_SILENT_RULES([yes]) LIBOSINFO_REQUIRED=0.0.5 LIBVIRT_GCONFIG_REQUIRED=0.0.9 GOBJECT_INTROSPECTION_REQUIRED=0.10.8 +LIBVIRT_REQUIRED=0.9.0 LIBVIRT_DESIGNER_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` LIBVIRT_DESIGNER_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'` @@ -30,6 +31,12 @@ AC_SUBST([LIBVIRT_DESIGNER_VERSION_NUMBER]) AC_PROG_CC AM_PROG_CC_C_O +AC_CHECK_FUNCS([strchr]) +AC_CHECK_FUNCS([strrchr]) +AC_CHECK_FUNCS([uname]) +AC_PROG_CXX +AC_PROG_RANLIB +AC_TYPE_SIZE_T AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL @@ -40,6 +47,7 @@ LIBVIRT_DESIGNER_COMPILE_WARNINGS PKG_CHECK_MODULES(LIBOSINFO, libosinfo-1.0 >= $LIBOSINFO_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GCONFIG, libvirt-gconfig-1.0 >= $LIBVIRT_GCONFIG_REQUIRED) +PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED) LIBVIRT_DESIGNER_GETTEXT LIBVIRT_DESIGNER_GTK_MISC @@ -51,7 +59,8 @@ LIBVIRT_DESIGNER_INTROSPECTION AC_OUTPUT(Makefile libvirt-designer/Makefile libvirt-designer.spec - libvirt-designer-1.0.pc) + libvirt-designer-1.0.pc + examples/Makefile) AC_MSG_NOTICE([]) AC_MSG_NOTICE([Configuration summary]) @@ -62,4 +71,5 @@ AC_MSG_NOTICE([ Libraries:]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([ LIBOSINFO: $LIBOSINFO_CFLAGS $LIBOSINFO_LIBS]) AC_MSG_NOTICE([ LIBVIRT_GCONFIG: $LIBVIRT_GCONFIG_CFLAGS $LIBVIRT_GCONFIG_LIBS]) +AC_MSG_NOTICE([ LIBVIRT: $LIBVIRT_CFLAGS $LIBVIRT_LIBS]) AC_MSG_NOTICE([]) diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..afbb3ce --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,21 @@ +INCLUDES = \ + -I$(top_builddir)/libvirt-designer \ + -I$(top_srcdir) + +virtxml_LDADD = \ + $(top_builddir)/libvirt-designer/libvirt-designer-1.0.la + +virtxml_CFLAGS = \ + $(COVERAGE_CFLAGS) \ + $(LIBOSINFO_CFLAGS) \ + $(LIBVIRT_GCONFIG_CFLAGS) \ + $(WARN_CFLAGS2) \ + $(LIBVIRT_CFLAGS) \ + $(NULL) + +virtxml_LDFLAGS = \ + $(LIBOSINFO_LIBS) \ + $(LIBVIRT_GCONFIG_LIBS) \ + $(LIBVIRT_LIBS) + +bin_PROGRAMS = virtxml diff --git a/examples/virtxml.c b/examples/virtxml.c new file mode 100644 index 0000000..20e3f3c --- /dev/null +++ b/examples/virtxml.c @@ -0,0 +1,317 @@ +/* + * virtxml.c: produce an domain XML + * + * Copyright (C) 2012 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Michal Privoznik <mprivozn@redhat.com> + */ + +#include <config.h> +#include <libvirt-designer/libvirt-designer.h> +#include <libvirt/libvirt.h> +#include <libvirt/virterror.h> + +#include <stdio.h> +#include <getopt.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +GList *disk_str_list = NULL; + +#define print_error(...) \ + print_error_impl(__FUNCTION__, __LINE__, __VA_ARGS__) + +static void +print_error_impl(const char *funcname, + size_t linenr, + const char *fmt, ...) +{ + va_list args; + + fprintf(stderr, "Error in %s:%zu ", funcname, linenr); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr,"\n"); +} + +static OsinfoDb * +get_default_osinfo_db(void) +{ + GError *err = NULL; + OsinfoLoader *loader = NULL; + OsinfoDb *ret = NULL; + + loader = osinfo_loader_new(); + osinfo_loader_process_default_path(loader, &err); + if (err) { + print_error("Unable to load default libosinfo DB: %s", err->message); + goto cleanup; + } + + ret = osinfo_loader_get_db(loader); + g_object_ref(ret); + +cleanup: + g_object_unref(loader); + return ret; +} + +static gint +entity_compare(gconstpointer a, gconstpointer b) +{ + const gchar *id_a = osinfo_entity_get_param_value(OSINFO_ENTITY(a), + OSINFO_ENTITY_PROP_ID); + const gchar *id_b = osinfo_entity_get_param_value(OSINFO_ENTITY(b), + OSINFO_ENTITY_PROP_ID); + return g_strcmp0(id_a, id_b); +} + +static gboolean +print_oses(const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + OsinfoDb *db = get_default_osinfo_db(); + OsinfoOsList *list; + GList *oses = NULL; + GList *os_iter; + int ret = EXIT_FAILURE; + + if (!db) + goto cleanup; + + printf(" Operating System ID\n" + "-----------------------\n"); + + list = osinfo_db_get_os_list(db); + if (!list) + goto cleanup; + oses = osinfo_list_get_elements(OSINFO_LIST(list)); + oses = g_list_sort(oses, entity_compare); + for (os_iter = oses; os_iter; os_iter = os_iter->next) { + OsinfoOs *os = OSINFO_OS(os_iter->data); + const char *id = osinfo_entity_get_param_value(OSINFO_ENTITY(os), + OSINFO_ENTITY_PROP_ID); + + printf("%s\n", id); + } + + ret = EXIT_SUCCESS; + +cleanup: + if (list) + g_object_unref(list); + if (db) + g_object_unref(db); + + exit(ret); + return TRUE; +} + +static gboolean +print_platforms(const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + OsinfoDb *db = get_default_osinfo_db(); + OsinfoPlatformList *list; + GList *platforms = NULL; + GList *platform_iter; + int ret = EXIT_FAILURE; + + if (!db) + goto cleanup; + + printf(" Platform ID\n" + "---------------\n"); + + list = osinfo_db_get_platform_list(db); + if (!list) + goto cleanup; + platforms = osinfo_list_get_elements(OSINFO_LIST(list)); + platforms = g_list_sort(platforms, entity_compare); + for (platform_iter = platforms; platform_iter; platform_iter = platform_iter->next) { + OsinfoPlatform *platform = OSINFO_PLATFORM(platform_iter->data); + const char *id = osinfo_entity_get_param_value(OSINFO_ENTITY(platform), + OSINFO_ENTITY_PROP_ID); + + printf("%s\n", id); + } + + ret = EXIT_SUCCESS; + +cleanup: + if (list) + g_object_unref(list); + if (db) + g_object_unref(db); + + exit(ret); + return TRUE; +} + +static void +add_disk(gpointer data, + gpointer user_data) +{ + GVirDesignerDomain *domain = (GVirDesignerDomain *) user_data; + char *path = (char *) data; + char *format = NULL; + struct stat buf; + GError *error = NULL; + + format = strchr(path, ','); + if (format) { + *format = '\0'; + format++; + } + + if (!path || !strlen(path)) { + print_error("No path provided"); + exit(EXIT_FAILURE); + } + + if (!stat(path, &buf) && + !S_ISREG(buf.st_mode)) { + gvir_designer_domain_add_disk_device(domain, path, &error); + } else { + gvir_designer_domain_add_disk_file(domain, path, format, &error); + } + + if (error) { + print_error("%s", error->message); + exit(EXIT_FAILURE); + } +} + +static gboolean +add_disk_str(const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + disk_str_list = g_list_append(disk_str_list, g_strdup(value)); + return TRUE; +} + +#define CHECK_ERROR \ + if (error) { \ + print_error("%s", error->message); \ + goto cleanup; \ + } + +int +main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + GError *error = NULL; + OsinfoOs *os = NULL; + OsinfoPlatform *platform = NULL; + GVirConfigCapabilities *caps = NULL; + GVirConfigDomain *config = NULL; + GVirDesignerDomain *domain = NULL; + virConnectPtr conn = NULL; + char *caps_str = NULL; + gchar *xml = NULL; + static char *os_str = NULL; + static char *platform_str = NULL; + static char *arch_str = NULL; + static char *connect_uri = NULL; + GOptionContext *context; + + static GOptionEntry entries[] = + { + {"connect", 'c', 0, G_OPTION_ARG_STRING, &connect_uri, + "libvirt connection URI used for querying capabilities", "URI"}, + {"list-os", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, print_oses, + "list IDs of known OSes", NULL}, + {"list-platform", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, print_platforms, + "list IDs of known hypervisors", NULL}, + {"os", 'o', 0, G_OPTION_ARG_STRING, &os_str, + "set domain OS", "OS"}, + {"platform", 'p', 0, G_OPTION_ARG_STRING, &platform_str, + "set hypervisor under which domain will be running", "PLATFORM"}, + {"architecture", 'a', 0, G_OPTION_ARG_STRING, &arch_str, + "set domain architecture", "ARCH"}, + {"disk", 'd', 0, G_OPTION_ARG_CALLBACK, add_disk_str, + "add disk to domain with PATH being source and FORMAT its format", "PATH[,FORMAT]"}, + {NULL} + }; + + if (!gvir_designer_init_check(&argc, &argv, NULL)) + return EXIT_FAILURE; + + context = g_option_context_new ("- test tree model performance"); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + g_print ("option parsing failed: %s\n", error->message); + return EXIT_FAILURE; + } + if (!os_str) { + print_error("Operating system was not specified"); + return EXIT_FAILURE; + } + if (!platform_str) { + print_error("Platform was not specified"); + return EXIT_FAILURE; + } + + conn = virConnectOpenAuth(connect_uri, virConnectAuthPtrDefault, VIR_CONNECT_RO); + if (!conn) { + print_error("Unable to connect to libvirt"); + return EXIT_FAILURE; + } + + if ((caps_str = virConnectGetCapabilities(conn)) == NULL) { + print_error("failed to get capabilities"); + goto cleanup; + } + + os = osinfo_os_new(os_str); + platform = osinfo_platform_new(platform_str); + caps = gvir_config_capabilities_new_from_xml(caps_str, NULL); + + domain = gvir_designer_domain_new(os, platform, caps); + + gvir_designer_domain_setup_machine(domain, &error); + CHECK_ERROR; + + if (arch_str) { + gvir_designer_domain_setup_container_full(domain, arch_str, &error); + CHECK_ERROR; + } + + g_list_foreach(disk_str_list, add_disk, domain); + + config = gvir_designer_domain_get_config(domain); + xml = gvir_config_object_to_xml(GVIR_CONFIG_OBJECT(config)); + + g_printf("%s\n", xml); + + ret = EXIT_SUCCESS; + +cleanup: + virConnectClose(conn); + return ret; +} -- 1.7.8.6

On 09/10/2012 03:58 PM, Michal Privoznik wrote:
--- .gitignore | 1 + Makefile.am | 2 +- configure.ac | 12 ++- examples/Makefile.am | 21 ++++ examples/virtxml.c | 317 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 351 insertions(+), 2 deletions(-) create mode 100644 examples/Makefile.am create mode 100644 examples/virtxml.c
[...]
diff --git a/configure.ac b/configure.ac index 795990f..bdee845 100644 --- a/configure.ac +++ b/configure.ac @@ -13,6 +13,7 @@ AM_SILENT_RULES([yes]) LIBOSINFO_REQUIRED=0.0.5 LIBVIRT_GCONFIG_REQUIRED=0.0.9 GOBJECT_INTROSPECTION_REQUIRED=0.10.8 +LIBVIRT_REQUIRED=0.9.0
LIBVIRT_DESIGNER_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` LIBVIRT_DESIGNER_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'` @@ -30,6 +31,12 @@ AC_SUBST([LIBVIRT_DESIGNER_VERSION_NUMBER])
AC_PROG_CC AM_PROG_CC_C_O +AC_CHECK_FUNCS([strchr]) +AC_CHECK_FUNCS([strrchr]) +AC_CHECK_FUNCS([uname]) +AC_PROG_CXX +AC_PROG_RANLIB
I get a warning that this is obsoleted by LT_INIT.
+AC_TYPE_SIZE_T
AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL @@ -40,6 +47,7 @@ LIBVIRT_DESIGNER_COMPILE_WARNINGS
PKG_CHECK_MODULES(LIBOSINFO, libosinfo-1.0 >= $LIBOSINFO_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GCONFIG, libvirt-gconfig-1.0 >= $LIBVIRT_GCONFIG_REQUIRED) +PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED)
LIBVIRT_DESIGNER_GETTEXT LIBVIRT_DESIGNER_GTK_MISC @@ -51,7 +59,8 @@ LIBVIRT_DESIGNER_INTROSPECTION AC_OUTPUT(Makefile libvirt-designer/Makefile libvirt-designer.spec - libvirt-designer-1.0.pc) + libvirt-designer-1.0.pc + examples/Makefile)
AC_MSG_NOTICE([]) AC_MSG_NOTICE([Configuration summary]) @@ -62,4 +71,5 @@ AC_MSG_NOTICE([ Libraries:]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([ LIBOSINFO: $LIBOSINFO_CFLAGS $LIBOSINFO_LIBS]) AC_MSG_NOTICE([ LIBVIRT_GCONFIG: $LIBVIRT_GCONFIG_CFLAGS $LIBVIRT_GCONFIG_LIBS]) +AC_MSG_NOTICE([ LIBVIRT: $LIBVIRT_CFLAGS $LIBVIRT_LIBS]) AC_MSG_NOTICE([]) diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..afbb3ce --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,21 @@ +INCLUDES = \ + -I$(top_builddir)/libvirt-designer \ + -I$(top_srcdir) + +virtxml_LDADD = \ + $(top_builddir)/libvirt-designer/libvirt-designer-1.0.la + +virtxml_CFLAGS = \ + $(COVERAGE_CFLAGS) \ + $(LIBOSINFO_CFLAGS) \ + $(LIBVIRT_GCONFIG_CFLAGS) \ + $(WARN_CFLAGS2) \
There should be $(WARN_CFLAGS) here I bet (copy/paste error).
+ $(LIBVIRT_CFLAGS) \ + $(NULL) + +virtxml_LDFLAGS = \ + $(LIBOSINFO_LIBS) \ + $(LIBVIRT_GCONFIG_LIBS) \ + $(LIBVIRT_LIBS) + +bin_PROGRAMS = virtxml diff --git a/examples/virtxml.c b/examples/virtxml.c new file mode 100644 index 0000000..20e3f3c --- /dev/null +++ b/examples/virtxml.c @@ -0,0 +1,317 @@ +/* + * virtxml.c: produce an domain XML + * + * Copyright (C) 2012 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Michal Privoznik <mprivozn@redhat.com> + */ + +#include <config.h> +#include <libvirt-designer/libvirt-designer.h> +#include <libvirt/libvirt.h> +#include <libvirt/virterror.h> + +#include <stdio.h> +#include <getopt.h>
Unused, can be removed. [...] ACK from me as I don't think it needs that much of a attention when these are the (almost) first patches there. That reminds me, Add yourself to the AUTHORS with this series ;) Martin

On Mon, Sep 10, 2012 at 03:58:27PM +0200, Michal Privoznik wrote:
diff --git a/configure.ac b/configure.ac index 795990f..bdee845 100644 --- a/configure.ac +++ b/configure.ac @@ -13,6 +13,7 @@ AM_SILENT_RULES([yes]) LIBOSINFO_REQUIRED=0.0.5 LIBVIRT_GCONFIG_REQUIRED=0.0.9 GOBJECT_INTROSPECTION_REQUIRED=0.10.8 +LIBVIRT_REQUIRED=0.9.0
LIBVIRT_DESIGNER_MAJOR_VERSION=`echo $VERSION | awk -F. '{print $1}'` LIBVIRT_DESIGNER_MINOR_VERSION=`echo $VERSION | awk -F. '{print $2}'` @@ -30,6 +31,12 @@ AC_SUBST([LIBVIRT_DESIGNER_VERSION_NUMBER])
AC_PROG_CC AM_PROG_CC_C_O +AC_CHECK_FUNCS([strchr]) +AC_CHECK_FUNCS([strrchr]) +AC_CHECK_FUNCS([uname]) +AC_PROG_CXX +AC_PROG_RANLIB +AC_TYPE_SIZE_T
AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL @@ -40,6 +47,7 @@ LIBVIRT_DESIGNER_COMPILE_WARNINGS
PKG_CHECK_MODULES(LIBOSINFO, libosinfo-1.0 >= $LIBOSINFO_REQUIRED) PKG_CHECK_MODULES(LIBVIRT_GCONFIG, libvirt-gconfig-1.0 >= $LIBVIRT_GCONFIG_REQUIRED) +PKG_CHECK_MODULES(LIBVIRT, libvirt >= $LIBVIRT_REQUIRED)
LIBVIRT_DESIGNER_GETTEXT LIBVIRT_DESIGNER_GTK_MISC @@ -51,7 +59,8 @@ LIBVIRT_DESIGNER_INTROSPECTION AC_OUTPUT(Makefile libvirt-designer/Makefile libvirt-designer.spec - libvirt-designer-1.0.pc) + libvirt-designer-1.0.pc + examples/Makefile)
AC_MSG_NOTICE([]) AC_MSG_NOTICE([Configuration summary]) @@ -62,4 +71,5 @@ AC_MSG_NOTICE([ Libraries:]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([ LIBOSINFO: $LIBOSINFO_CFLAGS $LIBOSINFO_LIBS]) AC_MSG_NOTICE([ LIBVIRT_GCONFIG: $LIBVIRT_GCONFIG_CFLAGS $LIBVIRT_GCONFIG_LIBS]) +AC_MSG_NOTICE([ LIBVIRT: $LIBVIRT_CFLAGS $LIBVIRT_LIBS]) AC_MSG_NOTICE([])
As an enhancement it'd be nice to add a '--enable/disable-examples' argument so that we keep the ability to build this without needing libvirt available. Indeed if we make it optional, there's no reason not to use libvirt-gobject for the example programs - only the library needs to avoid a libvirt/libvirt-gobject dependency. 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 :|

Let users add NICs to domains. --- examples/virtxml.c | 78 ++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.c | 83 ++++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.h | 3 + libvirt-designer/libvirt-designer.sym | 1 + 4 files changed, 165 insertions(+), 0 deletions(-) diff --git a/examples/virtxml.c b/examples/virtxml.c index 20e3f3c..df83f57 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -35,6 +35,7 @@ #include <unistd.h> GList *disk_str_list = NULL; +GList *iface_str_list = NULL; #define print_error(...) \ print_error_impl(__FUNCTION__, __LINE__, __VA_ARGS__) @@ -215,6 +216,79 @@ add_disk_str(const gchar *option_name, return TRUE; } +static void +add_iface(gpointer data, + gpointer user_data) +{ + GVirDesignerDomain *domain = (GVirDesignerDomain *) user_data; + char *network = (char *) data; + char *param = NULL; + GVirConfigDomainInterface *iface = NULL; + GError *error = NULL; + + param = strchr(network, ','); + if (param) { + *param = '\0'; + param++; + } + + iface = gvir_designer_domain_add_interface_network(domain, network, &error); + if (error) { + print_error("%s", error->message); + exit(EXIT_FAILURE); + } + + while (param && *param) { + char *key = param; + char *val; + GVirConfigDomainInterfaceLinkState link; + + /* move to next token */ + param = strchr(param, ','); + if (param) { + *param = '\0'; + param++; + } + + /* parse token */ + val = strchr(key, '='); + if (!val) { + print_error("Invalid format: %s", key); + exit(EXIT_FAILURE); + } + + *val = '\0'; + val++; + + if (!strcmp(key, "mac")) { + gvir_config_domain_interface_set_mac(iface, val); + } else if (!strcmp(key, "link")) { + if (!strcmp(val, "up")) { + link = GVIR_CONFIG_DOMAIN_INTERFACE_LINK_STATE_UP; + } else if (!strcmp(val, "down")) { + link = GVIR_CONFIG_DOMAIN_INTERFACE_LINK_STATE_DOWN; + } else { + print_error("Unknown value: %s", val); + exit(EXIT_FAILURE); + } + gvir_config_domain_interface_set_link_state(iface, link); + } else { + print_error("Unknown key: %s", key); + exit(EXIT_FAILURE); + } + } +} + +static gboolean +add_iface_str(const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + iface_str_list = g_list_append(iface_str_list, g_strdup(value)); + return TRUE; +} + #define CHECK_ERROR \ if (error) { \ print_error("%s", error->message); \ @@ -256,6 +330,8 @@ main(int argc, char *argv[]) "set domain architecture", "ARCH"}, {"disk", 'd', 0, G_OPTION_ARG_CALLBACK, add_disk_str, "add disk to domain with PATH being source and FORMAT its format", "PATH[,FORMAT]"}, + {"interface", 'i', 0, G_OPTION_ARG_CALLBACK, add_iface_str, + "add interface with NETWORK source. Possible ARGs: mac, link={up,down}", "NETWORK[,ARG=VAL]"}, {NULL} }; @@ -304,6 +380,8 @@ main(int argc, char *argv[]) g_list_foreach(disk_str_list, add_disk, domain); + g_list_foreach(iface_str_list, add_iface, domain); + config = gvir_designer_domain_get_config(domain); xml = gvir_config_object_to_xml(GVIR_CONFIG_OBJECT(config)); diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index 8e649d7..4af432b 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -49,6 +49,11 @@ G_DEFINE_TYPE(GVirDesignerDomain, gvir_designer_domain, G_TYPE_OBJECT); #define GVIR_DESIGNER_DOMAIN_ERROR gvir_designer_domain_error_quark() +typedef enum { + GVIR_DESIGNER_DOMAIN_NIC_TYPE_NETWORK, + /* add new type here */ +} GVirDesignerDomainNICType; + static GQuark gvir_designer_domain_error_quark(void) { @@ -922,3 +927,81 @@ GVirConfigDomainDisk *gvir_designer_domain_add_disk_device(GVirDesignerDomain *d error); return ret; } + +static const gchar * +gvir_designer_domain_get_preferred_nic_model(GVirDesignerDomain *design, + GError **error) +{ + const gchar *ret = NULL; + OsinfoDeviceLink *dev_link = NULL; + + dev_link = gvir_designer_domain_get_preferred_device(design, "network", error); + if (!dev_link) + goto cleanup; + + ret = osinfo_devicelink_get_driver(dev_link); + +cleanup: + if (dev_link) + g_object_unref(dev_link); + return ret; +} + +static GVirConfigDomainInterface * +gvir_designer_domain_add_interface_full(GVirDesignerDomain *design, + GVirDesignerDomainNICType type, + const char *network, + GError **error) +{ + GVirConfigDomainInterface *ret; + const gchar *model = NULL; + + model = gvir_designer_domain_get_preferred_nic_model(design, error); + + switch (type) { + case GVIR_DESIGNER_DOMAIN_NIC_TYPE_NETWORK: + ret = GVIR_CONFIG_DOMAIN_INTERFACE(gvir_config_domain_interface_network_new()); + gvir_config_domain_interface_network_set_source(GVIR_CONFIG_DOMAIN_INTERFACE_NETWORK(ret), + network); + break; + default: + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "Unsupported interface type '%d'", type); + goto cleanup; + } + + if (model) + gvir_config_domain_interface_set_model(ret, model); + + gvir_config_domain_add_device(design->priv->config, GVIR_CONFIG_DOMAIN_DEVICE(ret)); + +cleanup: + return ret; +} + +/** + * gvir_designer_domain_add_interface_network: + * @design: (transfer none): the domain designer instance + * @network: (transfer none): network name + * + * Add new network interface card into @design. The interface is + * of 'network' type with @network used as the source network. + * + * Returns: (transfer none): the pointer to the new interface. + */ +GVirConfigDomainInterface * +gvir_designer_domain_add_interface_network(GVirDesignerDomain *design, + const char *network, + GError **error) +{ + g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL); + + GVirConfigDomainInterface *ret = NULL; + + ret = gvir_designer_domain_add_interface_full(design, + GVIR_DESIGNER_DOMAIN_NIC_TYPE_NETWORK, + network, + error); + + return ret; +} diff --git a/libvirt-designer/libvirt-designer-domain.h b/libvirt-designer/libvirt-designer-domain.h index 06a5749..5097393 100644 --- a/libvirt-designer/libvirt-designer-domain.h +++ b/libvirt-designer/libvirt-designer-domain.h @@ -101,6 +101,9 @@ GVirConfigDomainDisk *gvir_designer_domain_add_disk_device(GVirDesignerDomain *d const char *devpath, GError **error); +GVirConfigDomainInterface *gvir_designer_domain_add_interface_network(GVirDesignerDomain *design, + const char *network, + GError **error); G_END_DECLS #endif /* __LIBVIRT_DESIGNER_DOMAIN_H__ */ diff --git a/libvirt-designer/libvirt-designer.sym b/libvirt-designer/libvirt-designer.sym index e67323a..317a07b 100644 --- a/libvirt-designer/libvirt-designer.sym +++ b/libvirt-designer/libvirt-designer.sym @@ -12,6 +12,7 @@ LIBVIRT_DESIGNER_0.0.1 { gvir_designer_domain_add_disk_file; gvir_designer_domain_add_disk_device; + gvir_designer_domain_add_interface_network; gvir_designer_domain_setup_machine; gvir_designer_domain_setup_machine_full; -- 1.7.8.6

On 09/10/2012 03:58 PM, Michal Privoznik wrote:
Let users add NICs to domains. --- examples/virtxml.c | 78 ++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.c | 83 ++++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.h | 3 + libvirt-designer/libvirt-designer.sym | 1 + 4 files changed, 165 insertions(+), 0 deletions(-)
diff --git a/examples/virtxml.c b/examples/virtxml.c index 20e3f3c..df83f57 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -35,6 +35,7 @@ #include <unistd.h>
GList *disk_str_list = NULL; +GList *iface_str_list = NULL;
#define print_error(...) \ print_error_impl(__FUNCTION__, __LINE__, __VA_ARGS__) @@ -215,6 +216,79 @@ add_disk_str(const gchar *option_name, return TRUE; }
+static void +add_iface(gpointer data, + gpointer user_data) +{ + GVirDesignerDomain *domain = (GVirDesignerDomain *) user_data; + char *network = (char *) data; + char *param = NULL; + GVirConfigDomainInterface *iface = NULL; + GError *error = NULL; + + param = strchr(network, ','); + if (param) { + *param = '\0'; + param++; + } + + iface = gvir_designer_domain_add_interface_network(domain, network, &error); + if (error) { + print_error("%s", error->message); + exit(EXIT_FAILURE); + } + + while (param && *param) { + char *key = param; + char *val; + GVirConfigDomainInterfaceLinkState link; + + /* move to next token */ + param = strchr(param, ','); + if (param) { + *param = '\0'; + param++; + } + + /* parse token */ + val = strchr(key, '='); + if (!val) { + print_error("Invalid format: %s", key); + exit(EXIT_FAILURE); + } + + *val = '\0'; + val++; + + if (!strcmp(key, "mac")) { + gvir_config_domain_interface_set_mac(iface, val); + } else if (!strcmp(key, "link")) { + if (!strcmp(val, "up")) { + link = GVIR_CONFIG_DOMAIN_INTERFACE_LINK_STATE_UP; + } else if (!strcmp(val, "down")) {
Change those 4 !strcmp to g_str_equal. [...] ACK with that fixed. Martin

On 10.09.2012 19:03, Martin Kletzander wrote:
On 09/10/2012 03:58 PM, Michal Privoznik wrote:
Let users add NICs to domains. --- examples/virtxml.c | 78 ++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.c | 83 ++++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.h | 3 + libvirt-designer/libvirt-designer.sym | 1 + 4 files changed, 165 insertions(+), 0 deletions(-)
diff --git a/examples/virtxml.c b/examples/virtxml.c index 20e3f3c..df83f57 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -35,6 +35,7 @@ #include <unistd.h>
GList *disk_str_list = NULL; +GList *iface_str_list = NULL;
#define print_error(...) \ print_error_impl(__FUNCTION__, __LINE__, __VA_ARGS__) @@ -215,6 +216,79 @@ add_disk_str(const gchar *option_name, return TRUE; }
+static void +add_iface(gpointer data, + gpointer user_data) +{ + GVirDesignerDomain *domain = (GVirDesignerDomain *) user_data; + char *network = (char *) data; + char *param = NULL; + GVirConfigDomainInterface *iface = NULL; + GError *error = NULL; + + param = strchr(network, ','); + if (param) { + *param = '\0'; + param++; + } + + iface = gvir_designer_domain_add_interface_network(domain, network, &error); + if (error) { + print_error("%s", error->message); + exit(EXIT_FAILURE); + } + + while (param && *param) { + char *key = param; + char *val; + GVirConfigDomainInterfaceLinkState link; + + /* move to next token */ + param = strchr(param, ','); + if (param) { + *param = '\0'; + param++; + } + + /* parse token */ + val = strchr(key, '='); + if (!val) { + print_error("Invalid format: %s", key); + exit(EXIT_FAILURE); + } + + *val = '\0'; + val++; + + if (!strcmp(key, "mac")) { + gvir_config_domain_interface_set_mac(iface, val); + } else if (!strcmp(key, "link")) { + if (!strcmp(val, "up")) { + link = GVIR_CONFIG_DOMAIN_INTERFACE_LINK_STATE_UP; + } else if (!strcmp(val, "down")) {
Change those 4 !strcmp to g_str_equal.
[...]
ACK with that fixed.
Martin
Thanks for review. I've fixed all the nits and pushed whole set. Michal

On Mon, Sep 10, 2012 at 03:58:28PM +0200, Michal Privoznik wrote:
Let users add NICs to domains. --- examples/virtxml.c | 78 ++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.c | 83 ++++++++++++++++++++++++++++ libvirt-designer/libvirt-designer-domain.h | 3 + libvirt-designer/libvirt-designer.sym | 1 + 4 files changed, 165 insertions(+), 0 deletions(-)
diff --git a/examples/virtxml.c b/examples/virtxml.c index 20e3f3c..df83f57 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -35,6 +35,7 @@ #include <unistd.h>
GList *disk_str_list = NULL; +GList *iface_str_list = NULL;
#define print_error(...) \ print_error_impl(__FUNCTION__, __LINE__, __VA_ARGS__) @@ -215,6 +216,79 @@ add_disk_str(const gchar *option_name, return TRUE; }
+static void +add_iface(gpointer data, + gpointer user_data) +{ + GVirDesignerDomain *domain = (GVirDesignerDomain *) user_data; + char *network = (char *) data; + char *param = NULL; + GVirConfigDomainInterface *iface = NULL; + GError *error = NULL; + + param = strchr(network, ','); + if (param) { + *param = '\0'; + param++; + }
glib provides a g_strsplit (and plenty of useful functions in http://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html )
+ + iface = gvir_designer_domain_add_interface_network(domain, network, &error); + if (error) { + print_error("%s", error->message); + exit(EXIT_FAILURE);
An alternative here can be g_error
+ } + + while (param && *param) { + char *key = param; + char *val; + GVirConfigDomainInterfaceLinkState link; + + /* move to next token */ + param = strchr(param, ','); + if (param) { + *param = '\0'; + param++; + } + + /* parse token */ + val = strchr(key, '='); + if (!val) { + print_error("Invalid format: %s", key); + exit(EXIT_FAILURE); + } + + *val = '\0'; + val++; + + if (!strcmp(key, "mac")) { + gvir_config_domain_interface_set_mac(iface, val); + } else if (!strcmp(key, "link")) { + if (!strcmp(val, "up")) { + link = GVIR_CONFIG_DOMAIN_INTERFACE_LINK_STATE_UP; + } else if (!strcmp(val, "down")) { + link = GVIR_CONFIG_DOMAIN_INTERFACE_LINK_STATE_DOWN; + } else { + print_error("Unknown value: %s", val); + exit(EXIT_FAILURE); + }
If you find yourself doing similar parsing in several places, a function similar to gvir_config_genum_get_value can be really useful ( http://libvirt.org/git/?p=libvirt-glib.git;a=blob;f=libvirt-gconfig/libvirt-... ) Christophe
participants (4)
-
Christophe Fergeau
-
Daniel P. Berrange
-
Martin Kletzander
-
Michal Privoznik