summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Fergeau <cfergeau@redhat.com>2013-03-19 23:11:47 +0100
committerChristophe Fergeau <cfergeau@redhat.com>2013-04-01 21:15:25 +0200
commitc579f979e2921bf24ecaef4c2ef108fc6c56ea08 (patch)
tree5b990d65ddea61c87e7b98c18da53b8cf0482c43
parent8a9c4128bec29757c44c4c8d7ef29b19b024476e (diff)
virtxml: Add GVirDesigner structure
Experiments to see if I can get a high-level API to generate VMs...
-rw-r--r--examples/Makefile.am5
-rw-r--r--examples/virtoptions.c818
-rw-r--r--examples/virtoptions.h66
-rw-r--r--examples/virtxml.c582
4 files changed, 904 insertions, 567 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am
index ae2667e..71f029e 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -18,6 +18,11 @@ virtxml_LDFLAGS = \
$(LIBVIRT_GCONFIG_LIBS) \
$(LIBVIRT_GOBJECT_LIBS)
+virtxml_SOURCES = \
+ virtoptions.c \
+ virtoptions.h \
+ virtxml.c
+
POD2MAN = pod2man -c "Virtualization Support" -r "$(PACKAGE)-$(VERSION)"
%.1: %.c Makefile
diff --git a/examples/virtoptions.c b/examples/virtoptions.c
new file mode 100644
index 0000000..9f57945
--- /dev/null
+++ b/examples/virtoptions.c
@@ -0,0 +1,818 @@
+/*
+ * virtoptions.c: generate a GvirDesignerDomain from cmdline options
+ *
+ * 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: Christophe Fergeau <cfergeau@redhat.com>
+ * Author: Michal Privoznik <mprivozn@redhat.com>
+ */
+
+/* FIXME: GVirDesigner is not useful and should be killed in a refactoring,
+ * it exists because of the way the code evolved from the monolithic
+ * virtxml.c code
+ */
+#include <config.h>
+
+#include <libvirt-gobject/libvirt-gobject.h>
+
+#include <string.h>
+#include <sys/stat.h>
+
+#include "virtoptions.h"
+
+OsinfoDb *db = NULL;
+
+typedef struct _GVirDesigner GVirDesigner;
+
+static gboolean print_oses(const gchar *option_name, const gchar *value,
+ gpointer data, GError **error);
+static gboolean print_platforms(const gchar *option_name, const gchar *value,
+ gpointer data, GError **error);
+static void add_disk(gpointer data, gpointer user_data);
+static gboolean add_disk_str(const gchar *option_name, const gchar *value,
+ gpointer data, GError **error);
+static void add_iface(gpointer data, gpointer user_data);
+static gboolean add_iface_str(const gchar *option_name, const gchar *value,
+ gpointer data, GError **error);
+static OsinfoOs *find_os(const gchar *os_str);
+static OsinfoOs *find_os_by_short_id(const char *short_id);
+static OsinfoOs *guess_os_from_disk(GList *disk_list);
+static OsinfoPlatform *find_platform(const char *platform_str);
+static OsinfoPlatform *guess_platform_from_connect(GVirConnection *conn);
+static OsinfoPlatform *find_platform_by_short_id(const char *short_id);
+static gboolean gvir_designer_guess_os (GVirDesigner *designer,
+ GVirDesignerOptions *options);
+static gboolean gvir_designer_guess_platform (GVirDesigner *designer,
+ GVirDesignerOptions *options);
+static gboolean gvir_designer_guess_resources (GVirDesigner *designer,
+ GVirDesignerOptions *options);
+static gboolean gvir_designer_create_domain (GVirDesigner *designer,
+ GVirDesignerOptions *options,
+ GError **error);
+
+
+#define SET_OPTION_STR(field_name) \
+ static gboolean set_##field_name##_str(const gchar *option_name, \
+ const gchar *value, \
+ gpointer data, \
+ GError **error) \
+ { \
+ GVirDesignerOptions *options = (GVirDesignerOptions *)data; \
+\
+ g_free(options->field_name); \
+ options->field_name = g_strdup (value); \
+\
+ return TRUE; \
+ }
+
+
+struct _GVirDesigner {
+ GVirConnection *conn;
+ GVirConfigCapabilities *caps;
+ OsinfoOs *os;
+ OsinfoPlatform *platform;
+ GVirDesignerDomain *domain;
+};
+
+
+static void gvir_designer_free (GVirDesigner *designer)
+{
+ g_return_if_fail (designer != NULL);
+
+ if (designer->conn != NULL)
+ g_object_unref (G_OBJECT(designer->conn));
+ if (designer->caps != NULL)
+ g_object_unref (G_OBJECT(designer->caps));
+ if (designer->os != NULL)
+ g_object_unref (G_OBJECT(designer->os));
+ if (designer->platform != NULL)
+ g_object_unref (G_OBJECT(designer->platform));
+ if (designer->domain != NULL)
+ g_object_unref (G_OBJECT(designer->domain));
+
+ g_free (designer);
+}
+
+
+static GVirDesigner *gvir_designer_new (void)
+{
+ return g_new0 (GVirDesigner, 1);
+}
+
+static GVirDesigner *gvir_designer_new_for_uri (const char *connect_uri, GError **error)
+{
+ GError *local_error = NULL;
+ GVirDesigner *designer;
+ GVirConnection *conn;
+ GVirConfigCapabilities *caps;
+
+ g_return_val_if_fail (connect_uri != NULL, NULL);
+ conn = gvir_connection_new(connect_uri);
+ gvir_connection_open(conn, NULL, &local_error);
+ if (local_error != NULL) {
+ g_propagate_error (error, local_error);
+ return NULL;
+ }
+
+ caps = gvir_connection_get_capabilities(conn, &local_error);
+ if (local_error != NULL) {
+ g_object_unref (G_OBJECT (conn));
+ g_propagate_error (error, local_error);
+ return NULL;
+ }
+
+ designer = gvir_designer_new ();
+ designer->conn = conn;
+ designer->caps = caps;
+
+ return designer;
+}
+
+struct _GVirDesignerOptions {
+ char *arch;
+ char *connect_uri;
+ char *os;
+ char *platform;
+ char *resources;
+
+ GList *disks;
+ GList *net_interfaces;
+};
+
+SET_OPTION_STR(arch)
+SET_OPTION_STR(connect_uri)
+SET_OPTION_STR(os)
+SET_OPTION_STR(platform)
+SET_OPTION_STR(resources)
+
+
+GVirDesignerOptions *gvir_designer_options_new (void)
+{
+ return g_new0 (GVirDesignerOptions, 1);
+}
+
+void gvir_designer_options_free (GVirDesignerOptions *options)
+{
+ g_return_if_fail (options != NULL);
+
+ g_free (options->arch);
+ g_free (options->connect_uri);
+ g_free (options->os);
+ g_free (options->platform);
+ g_free (options->resources);
+ g_list_free_full (options->disks, g_free);
+ g_list_free_full (options->net_interfaces, g_free);
+ g_free (options);
+}
+
+GVirDesignerDomain *gvir_designer_domain_new_from_options (GVirDesignerOptions *options, GError **err)
+{
+ GVirDesigner *designer;
+ GVirDesignerDomain *domain;
+ GError *error = NULL;
+
+ g_return_val_if_fail (options != NULL, NULL);
+
+ designer = gvir_designer_new_for_uri (options->connect_uri, &error);
+ CHECK_ERROR;
+ if (designer == NULL) {
+ print_error("Could not create connection to libvirt daemon");
+ goto cleanup;
+ }
+
+ if (!gvir_designer_guess_os (designer, options)) {
+ print_error("Operating system could not be found or guessed");
+ goto cleanup;
+ }
+
+ if (!gvir_designer_guess_platform (designer, options)) {
+ print_error("Platform was not specified or could not be guessed");
+ goto cleanup;
+ }
+
+ gvir_designer_create_domain (designer, options, &error);
+ CHECK_ERROR;
+
+ if (!gvir_designer_guess_resources (designer, options)) {
+ print_error("Resources could not be set or guessed");
+ goto cleanup;
+ }
+
+ domain = g_object_ref (G_OBJECT (designer->domain));
+ gvir_designer_free (designer);
+
+ return domain;
+
+cleanup:
+ if (designer != NULL)
+ gvir_designer_free (designer);
+
+ if (error != NULL)
+ g_propagate_error (err, error);
+
+ return NULL;
+}
+
+
+GOptionGroup *gvir_designer_options_get_option_group (GVirDesignerOptions *options)
+{
+ GOptionGroup *option_group;
+
+ static GOptionEntry entries[] =
+ {
+ {"connect", 'c', 0, G_OPTION_ARG_CALLBACK, set_connect_uri_str,
+ "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_CALLBACK, set_os_str,
+ "set domain OS", "OS"},
+ {"platform", 'p', 0, G_OPTION_ARG_CALLBACK, set_platform_str,
+ "set hypervisor under which domain will be running", "PLATFORM"},
+ {"architecture", 'a', 0, G_OPTION_ARG_CALLBACK, set_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]"},
+ {"interface", 'i', 0, G_OPTION_ARG_CALLBACK, add_iface_str,
+ "add interface with NETWORK source. Possible ARGs: mac, link={up,down}", "NETWORK[,ARG=VAL]"},
+ {"resources", 'r', 0, G_OPTION_ARG_CALLBACK, set_resources_str,
+ "Set minimal or recommended values for cpu count and RAM amount", "{minimal|recommended}"},
+ {NULL}
+ };
+
+ option_group = g_option_group_new (NULL, NULL, NULL,
+ options, NULL);
+ g_option_group_add_entries (option_group, entries);
+ g_option_group_set_translation_domain (option_group, GETTEXT_PACKAGE);
+
+ return option_group;
+}
+
+static gboolean gvir_designer_guess_os (GVirDesigner *designer,
+ GVirDesignerOptions *options)
+{
+ OsinfoOs *os;
+
+ g_return_val_if_fail (designer != NULL, FALSE);
+
+ if (options->os) {
+ os = find_os(options->os);
+ if (!os)
+ os = find_os_by_short_id(options->os);
+ } else {
+ os = guess_os_from_disk(options->disks);
+ }
+
+ if (designer->os != NULL)
+ g_object_unref (designer->os);
+ designer->os = os;
+
+ return (os != NULL);
+}
+
+static gboolean gvir_designer_guess_platform (GVirDesigner *designer,
+ GVirDesignerOptions *options)
+{
+ OsinfoPlatform *platform;
+
+ g_return_val_if_fail (designer != NULL, FALSE);
+
+ if (options->platform) {
+ platform = find_platform(options->platform);
+ if (!platform)
+ platform = find_platform_by_short_id(options->platform);
+ } else {
+ platform = guess_platform_from_connect(designer->conn);
+ }
+
+ if (designer->platform != NULL)
+ g_object_unref (designer->platform);
+ designer->platform = platform;
+
+ return (platform != NULL);
+}
+
+static gboolean gvir_designer_guess_resources (GVirDesigner *designer,
+ GVirDesignerOptions *options)
+{
+ GVirDesignerDomainResources resources;
+ GError *error = NULL;
+
+ g_return_val_if_fail (designer != NULL, FALSE);
+
+ if (options->resources) {
+ if (g_str_equal(options->resources, "minimal") ||
+ g_str_equal(options->resources, "min"))
+ resources = GVIR_DESIGNER_DOMAIN_RESOURCES_MINIMAL;
+ else if (g_str_equal(options->resources, "recommended") ||
+ g_str_equal(options->resources, "rec"))
+ resources = GVIR_DESIGNER_DOMAIN_RESOURCES_RECOMMENDED;
+ else {
+ print_error("Unknown value '%s' for resources", options->resources);
+ return FALSE;
+ }
+ gvir_designer_domain_setup_resources (designer->domain, resources, &error);
+ if (error != NULL) {
+ g_clear_error (&error);
+ return FALSE;
+ }
+ } else {
+ gvir_designer_domain_setup_resources(designer->domain,
+ GVIR_DESIGNER_DOMAIN_RESOURCES_RECOMMENDED,
+ &error);
+ }
+
+ return TRUE;
+}
+
+
+static gboolean gvir_designer_create_domain (GVirDesigner *designer,
+ GVirDesignerOptions *options,
+ GError **error)
+{
+ GVirDesignerDomain *domain;
+ unsigned int i;
+ GError *local_error = NULL;
+
+ domain = gvir_designer_domain_new(db,
+ designer->os,
+ designer->platform,
+ designer->caps);
+ gvir_designer_domain_setup_machine(domain, &local_error);
+ if (local_error != NULL) {
+ g_object_unref (G_OBJECT(domain));
+ g_propagate_error(error, local_error);
+ return FALSE;
+ }
+ g_object_unref(gvir_designer_domain_add_graphics(domain,
+ GVIR_DESIGNER_DOMAIN_GRAPHICS_SPICE,
+ &local_error));
+ if (local_error != NULL)
+ goto error;
+ for (i = 0; i < 4; i++) {
+ g_object_unref(gvir_designer_domain_add_usb_redir(domain, &local_error));
+ if (local_error != NULL)
+ goto error;
+ }
+ g_object_unref(gvir_designer_domain_add_smartcard(domain, &local_error));
+ if (local_error != NULL)
+ goto error;
+ g_object_unref(gvir_designer_domain_add_video(domain, &local_error));
+ if (local_error != NULL)
+ goto error;
+
+ if (options->arch) {
+ gvir_designer_domain_setup_container_full(domain, options->arch, &local_error);
+ g_object_unref (G_OBJECT(domain));
+ g_propagate_error(error, local_error);
+ return FALSE;
+ }
+
+ g_list_foreach(options->disks, add_disk, domain);
+ g_list_foreach(options->net_interfaces, add_iface, domain);
+
+ designer->domain = domain;
+
+ return TRUE;
+
+error:
+ g_object_unref (G_OBJECT(domain));
+ g_propagate_error(error, local_error);
+ return FALSE;
+}
+
+
+static gboolean
+load_osinfo(void)
+{
+ GError *err = NULL;
+ gboolean ret = FALSE;
+ OsinfoLoader *loader = 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);
+ g_clear_error(&err);
+ }
+
+ db = osinfo_loader_get_db(loader);
+ g_object_ref(db);
+ ret = TRUE;
+
+ 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)
+{
+ OsinfoOsList *list = NULL;
+ GList *oses = NULL;
+ GList *os_iter;
+ int ret = EXIT_FAILURE;
+
+ if (!db && !load_osinfo())
+ 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);
+ g_list_free(oses);
+
+ exit(ret);
+ return TRUE;
+}
+
+static gboolean
+print_platforms(const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ OsinfoPlatformList *list = NULL;
+ GList *platforms = NULL;
+ GList *platform_iter;
+ int ret = EXIT_FAILURE;
+
+ if (!db && !load_osinfo())
+ 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);
+ g_list_free(platforms);
+
+ exit(ret);
+ return TRUE;
+}
+
+static void
+add_disk(gpointer data,
+ gpointer user_data)
+{
+ GVirDesignerDomain *domain = (GVirDesignerDomain *) user_data;
+ GVirConfigDomainDisk *disk;
+ 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)) {
+ disk = gvir_designer_domain_add_disk_device(domain, path, &error);
+ } else {
+ disk = gvir_designer_domain_add_disk_file(domain, path, format, &error);
+ }
+ if (disk)
+ g_object_unref(G_OBJECT(disk));
+
+ 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)
+{
+ GVirDesignerOptions *options = (GVirDesignerOptions *)data;
+
+ options->disks = g_list_append(options->disks, g_strdup(value));
+
+ 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 (g_str_equal(key, "mac")) {
+ gvir_config_domain_interface_set_mac(iface, val);
+ } else if (g_str_equal(key, "link")) {
+ if (g_str_equal(val, "up")) {
+ link = GVIR_CONFIG_DOMAIN_INTERFACE_LINK_STATE_UP;
+ } else if (g_str_equal(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)
+{
+ GVirDesignerOptions *options = (GVirDesignerOptions *)data;
+
+ options->net_interfaces = g_list_append(options->net_interfaces,
+ g_strdup(value));
+
+ return TRUE;
+}
+
+static OsinfoEntity *
+find_entity_by_short_id(OsinfoList *ent_list,
+ const char *short_id)
+{
+ OsinfoEntity *ret = NULL;
+ GList *list, *list_iterator;
+
+ list = osinfo_list_get_elements(ent_list);
+ for (list_iterator = list; list_iterator; list_iterator = list_iterator->next) {
+ const char *id = osinfo_entity_get_param_value(list_iterator->data,
+ OSINFO_PRODUCT_PROP_SHORT_ID);
+
+ if (!g_strcmp0(id, short_id)) {
+ ret = list_iterator->data;
+ g_object_ref(ret);
+ break;
+ }
+ }
+
+ g_list_free(list);
+ return ret;
+}
+
+static OsinfoOs *
+find_os(const gchar *os_str)
+{
+ OsinfoOs *ret = NULL;
+
+ if (!db && !load_osinfo())
+ return NULL;
+
+ ret = osinfo_db_get_os(db, os_str);
+
+ return ret;
+}
+
+static OsinfoOs *
+find_os_by_short_id(const char *short_id)
+{
+ OsinfoOs *ret = NULL;
+ OsinfoOsList *oses = NULL;
+ OsinfoEntity *found = NULL;
+
+ if (!db && !load_osinfo())
+ return NULL;
+
+ oses = osinfo_db_get_os_list(db);
+
+ if (!oses)
+ goto cleanup;
+
+ found = find_entity_by_short_id(OSINFO_LIST(oses), short_id);
+
+ if (!found)
+ goto cleanup;
+ ret = OSINFO_OS(found);
+
+cleanup:
+ if (oses)
+ g_object_unref(oses);
+ return ret;
+}
+
+static OsinfoOs *
+guess_os_from_disk(GList *disk_list)
+{
+ OsinfoOs *ret = NULL;
+ GList *list_it = NULL;
+
+ if (!db && !load_osinfo())
+ return NULL;
+
+ for (list_it = disk_list; list_it; list_it = list_it->next) {
+ char *path = (char *) list_it->data;
+ char *sep = strchr(path, ',');
+ OsinfoMedia *media = NULL;
+
+ if (sep)
+ path = g_strndup(path, sep-path);
+
+ media = osinfo_media_create_from_location(path, NULL, NULL);
+
+ if (sep)
+ g_free(path);
+
+ if (!media)
+ continue;
+
+ if (osinfo_db_identify_media(db, media)) {
+ g_object_get(G_OBJECT(media), "os", &ret, NULL);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static OsinfoPlatform *
+find_platform(const char *platform_str)
+{
+ OsinfoPlatform *ret = NULL;
+
+ if (!db && !load_osinfo())
+ return NULL;
+
+ ret = osinfo_db_get_platform(db, platform_str);
+
+ return ret;
+}
+
+static OsinfoPlatform *
+find_platform_by_short_id(const char *short_id)
+{
+ OsinfoPlatform *ret = NULL;
+ OsinfoPlatformList *platforms = NULL;
+ OsinfoEntity *found = NULL;
+
+ if (!db && !load_osinfo())
+ goto cleanup;
+
+ platforms = osinfo_db_get_platform_list(db);
+
+ if (!platforms)
+ goto cleanup;
+
+ found = find_entity_by_short_id(OSINFO_LIST(platforms), short_id);
+
+ if (!found)
+ goto cleanup;
+
+ ret = OSINFO_PLATFORM(found);
+
+cleanup:
+ if (platforms)
+ g_object_unref(platforms);
+ return ret;
+}
+
+static OsinfoPlatform *
+guess_platform_from_connect(GVirConnection *conn)
+{
+ OsinfoPlatform *ret = NULL;
+ gchar *hv_type = NULL;
+ gulong ver, major, minor, release;
+ char *short_id = NULL, *type = NULL;
+
+ hv_type = gvir_connection_get_hypervisor_name(conn, NULL);
+ ver = gvir_connection_get_version(conn, NULL);
+
+ if (!hv_type || !ver) {
+ print_error("Unable to get hypervisor and its version");
+ exit(EXIT_FAILURE);
+ }
+
+ /* do some mappings:
+ * QEMU -> qemu-kvm
+ * Xen -> xen
+ */
+ type = g_ascii_strdown(hv_type, -1);
+ if (g_str_equal(type, "qemu") && ver <= 1002000) {
+ g_free(type);
+ type = g_strdup("qemu-kvm");
+ }
+
+ major = ver / 1000000;
+ ver %= 1000000;
+ minor = ver / 1000;
+ release = ver % 1000 ;
+
+ short_id = g_strdup_printf("%s-%lu.%lu.%lu", type, major, minor, release);
+
+ ret = find_platform_by_short_id(short_id);
+
+ g_free(short_id);
+ g_free(hv_type);
+ g_free(type);
+ return ret;
+}
diff --git a/examples/virtoptions.h b/examples/virtoptions.h
new file mode 100644
index 0000000..f14b04f
--- /dev/null
+++ b/examples/virtoptions.h
@@ -0,0 +1,66 @@
+/*
+ * 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: Christophe Fergeau <cfergeau@redhat.com>
+ */
+
+
+#ifndef __VIRT_OPTIONS_H__
+#define __VIRT_OPTIONS_H__
+
+#include <libvirt-designer/libvirt-designer.h>
+
+typedef struct _GVirDesignerOptions GVirDesignerOptions;
+
+GVirDesignerDomain *gvir_designer_domain_new_from_options (GVirDesignerOptions *options, GError **err);
+GVirDesignerOptions *gvir_designer_options_new (void);
+void gvir_designer_options_free (GVirDesignerOptions *options);
+GOptionGroup *gvir_designer_options_get_option_group (GVirDesignerOptions *options);
+
+
+#define print_error(...) \
+ print_error_impl(__FUNCTION__, __LINE__, __VA_ARGS__)
+
+#define CHECK_ERROR \
+ if (error) { \
+ print_error("%s", error->message); \
+ goto cleanup; \
+ }
+
+static void print_error_impl(const char *funcname,
+ size_t linenr,
+ const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+
+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");
+}
+
+
+#endif /* __VIRT_OPTIONS_H__ */
diff --git a/examples/virtxml.c b/examples/virtxml.c
index a7a1a0f..ab29ce2 100644
--- a/examples/virtxml.c
+++ b/examples/virtxml.c
@@ -27,589 +27,43 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include <string.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <unistd.h>
#include <glib/gprintf.h>
-GList *disk_str_list = NULL;
-GList *iface_str_list = NULL;
-OsinfoDb *db = 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, ...) __attribute__ ((format (printf, 3, 4)));
-
-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 gboolean
-load_osinfo(void)
-{
- GError *err = NULL;
- gboolean ret = FALSE;
- OsinfoLoader *loader = 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);
- g_clear_error(&err);
- }
-
- db = osinfo_loader_get_db(loader);
- g_object_ref(db);
- ret = TRUE;
-
- 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)
-{
- OsinfoOsList *list = NULL;
- GList *oses = NULL;
- GList *os_iter;
- int ret = EXIT_FAILURE;
-
- if (!db && !load_osinfo())
- 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);
- g_list_free(oses);
-
- exit(ret);
- return TRUE;
-}
-
-static gboolean
-print_platforms(const gchar *option_name,
- const gchar *value,
- gpointer data,
- GError **error)
-{
- OsinfoPlatformList *list = NULL;
- GList *platforms = NULL;
- GList *platform_iter;
- int ret = EXIT_FAILURE;
-
- if (!db && !load_osinfo())
- 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);
- g_list_free(platforms);
-
- exit(ret);
- return TRUE;
-}
-
-static void
-add_disk(gpointer data,
- gpointer user_data)
-{
- GVirDesignerDomain *domain = (GVirDesignerDomain *) user_data;
- GVirConfigDomainDisk *disk;
- 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)) {
- disk = gvir_designer_domain_add_disk_device(domain, path, &error);
- } else {
- disk = gvir_designer_domain_add_disk_file(domain, path, format, &error);
- }
- if (disk)
- g_object_unref(G_OBJECT(disk));
-
- 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;
-}
-
-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 (g_str_equal(key, "mac")) {
- gvir_config_domain_interface_set_mac(iface, val);
- } else if (g_str_equal(key, "link")) {
- if (g_str_equal(val, "up")) {
- link = GVIR_CONFIG_DOMAIN_INTERFACE_LINK_STATE_UP;
- } else if (g_str_equal(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;
-}
-
-static OsinfoEntity *
-find_entity_by_short_id(OsinfoList *ent_list,
- const char *short_id)
-{
- OsinfoEntity *ret = NULL;
- GList *list, *list_iterator;
-
- list = osinfo_list_get_elements(ent_list);
- for (list_iterator = list; list_iterator; list_iterator = list_iterator->next) {
- const char *id = osinfo_entity_get_param_value(list_iterator->data,
- OSINFO_PRODUCT_PROP_SHORT_ID);
-
- if (!g_strcmp0(id, short_id)) {
- ret = list_iterator->data;
- g_object_ref(ret);
- break;
- }
- }
- g_list_free(list);
-
- return ret;
-}
-
-static OsinfoOs *
-find_os(const gchar *os_str)
-{
- OsinfoOs *ret = NULL;
-
- if (!db && !load_osinfo())
- return NULL;
-
- ret = osinfo_db_get_os(db, os_str);
-
- return ret;
-}
-
-static OsinfoOs *
-find_os_by_short_id(const char *short_id)
-{
- OsinfoOs *ret = NULL;
- OsinfoOsList *oses = NULL;
- OsinfoEntity *found = NULL;
-
- if (!db && !load_osinfo())
- return NULL;
-
- oses = osinfo_db_get_os_list(db);
-
- if (!oses)
- goto cleanup;
-
- found = find_entity_by_short_id(OSINFO_LIST(oses), short_id);
-
- if (!found)
- goto cleanup;
- ret = OSINFO_OS(found);
-
-cleanup:
- if (oses)
- g_object_unref(oses);
- return ret;
-}
-
-static OsinfoOs *
-guess_os_from_disk(GList *disk_list)
-{
- OsinfoOs *ret = NULL;
- GList *list_it = NULL;
-
- if (!db && !load_osinfo())
- return NULL;
-
- for (list_it = disk_list; list_it; list_it = list_it->next) {
- char *path = (char *) list_it->data;
- char *sep = strchr(path, ',');
- OsinfoMedia *media = NULL;
-
- if (sep)
- path = g_strndup(path, sep-path);
-
- media = osinfo_media_create_from_location(path, NULL, NULL);
-
- if (sep)
- g_free(path);
-
- if (!media)
- continue;
-
- if (osinfo_db_identify_media(db, media)) {
- g_object_get(G_OBJECT(media), "os", &ret, NULL);
- break;
- }
- }
-
- return ret;
-}
-
-static OsinfoPlatform *
-find_platform(const char *platform_str)
-{
- OsinfoPlatform *ret = NULL;
-
- if (!db && !load_osinfo())
- return NULL;
-
- ret = osinfo_db_get_platform(db, platform_str);
-
- return ret;
-}
-
-static OsinfoPlatform *
-find_platform_by_short_id(const char *short_id)
-{
- OsinfoPlatform *ret = NULL;
- OsinfoPlatformList *platforms = NULL;
- OsinfoEntity *found = NULL;
-
- if (!db && !load_osinfo())
- goto cleanup;
-
- platforms = osinfo_db_get_platform_list(db);
-
- if (!platforms)
- goto cleanup;
-
- found = find_entity_by_short_id(OSINFO_LIST(platforms), short_id);
-
- if (!found)
- goto cleanup;
-
- ret = OSINFO_PLATFORM(found);
-
-cleanup:
- if (platforms)
- g_object_unref(platforms);
- return ret;
-}
-
-static OsinfoPlatform *
-guess_platform_from_connect(GVirConnection *conn)
-{
- OsinfoPlatform *ret = NULL;
- gchar *hv_type = NULL;
- gulong ver, major, minor, release;
- char *short_id = NULL, *type = NULL;
-
- hv_type = gvir_connection_get_hypervisor_name(conn, NULL);
- ver = gvir_connection_get_version(conn, NULL);
-
- if (!hv_type || !ver) {
- print_error("Unable to get hypervisor and its version");
- exit(EXIT_FAILURE);
- }
-
- /* do some mappings:
- * QEMU -> qemu-kvm
- * Xen -> xen
- */
- type = g_ascii_strdown(hv_type, -1);
- if (g_str_equal(type, "qemu") && ver <= 1002000) {
- g_free(type);
- type = g_strdup("qemu-kvm");
- }
-
- major = ver / 1000000;
- ver %= 1000000;
- minor = ver / 1000;
- release = ver % 1000 ;
-
- short_id = g_strdup_printf("%s-%lu.%lu.%lu", type, major, minor, release);
-
- ret = find_platform_by_short_id(short_id);
-
- g_free(short_id);
- g_free(hv_type);
- g_free(type);
- return ret;
-}
-
-#define CHECK_ERROR \
- if (error) { \
- print_error("%s", error->message); \
- goto cleanup; \
- }
+#include "virtoptions.h"
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;
- GVirConnection *conn = NULL;
gchar *xml = NULL;
- static char *os_str = NULL;
- static char *platform_str = NULL;
- static char *arch_str = NULL;
- static char *connect_uri = NULL;
- static char *resources_str = NULL;
- GVirDesignerDomainResources resources;
GOptionContext *context = NULL;
- unsigned int i;
-
- 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]"},
- {"interface", 'i', 0, G_OPTION_ARG_CALLBACK, add_iface_str,
- "add interface with NETWORK source. Possible ARGs: mac, link={up,down}", "NETWORK[,ARG=VAL]"},
- {"resources", 'r', 0, G_OPTION_ARG_STRING, &resources_str,
- "Set minimal or recommended values for cpu count and RAM amount", "{minimal|recommended}"},
- {NULL}
- };
+ GOptionGroup *group;
+ GVirDesignerOptions *options = NULL;
+ GVirDesignerDomain *domain = NULL;
if (!gvir_designer_init_check(&argc, &argv, NULL))
- return EXIT_FAILURE;
+ goto cleanup;
- context = g_option_context_new ("- test tree model performance");
- g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+ options = gvir_designer_options_new();
+ group = gvir_designer_options_get_option_group(options);
+ context = g_option_context_new("- test tree model performance");
+ g_option_context_set_main_group(context, group);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_print ("option parsing failed: %s\n", error->message);
- return EXIT_FAILURE;
- }
-
- conn = gvir_connection_new(connect_uri);
- gvir_connection_open(conn, NULL, &error);
- CHECK_ERROR;
-
- caps = gvir_connection_get_capabilities(conn, &error);
- CHECK_ERROR;
-
- if (os_str) {
- os = find_os(os_str);
- if (!os)
- os = find_os_by_short_id(os_str);
- } else {
- os = guess_os_from_disk(disk_str_list);
- }
-
- if (!os) {
- print_error("Operating system could not be find or guessed");
- goto cleanup;
- }
-
- if (platform_str) {
- platform = find_platform(platform_str);
- if (!platform)
- platform = find_platform_by_short_id(platform_str);
- } else {
- platform = guess_platform_from_connect(conn);
- }
-
- if (!platform) {
- print_error("Platform was not specified or could not be guessed");
goto cleanup;
}
- domain = gvir_designer_domain_new(db, os, platform, caps);
-
- 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;
- for (i = 0; i < 4; i++) {
- 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;
- g_object_unref(gvir_designer_domain_add_video(domain, &error));
+ domain = gvir_designer_domain_new_from_options(options, &error);
CHECK_ERROR;
-
- if (arch_str) {
- gvir_designer_domain_setup_container_full(domain, arch_str, &error);
- CHECK_ERROR;
- }
-
- if (resources_str) {
- if (g_str_equal(resources_str, "minimal") ||
- g_str_equal(resources_str, "min"))
- resources = GVIR_DESIGNER_DOMAIN_RESOURCES_MINIMAL;
- else if (g_str_equal(resources_str, "recommended") ||
- g_str_equal(resources_str, "rec"))
- resources = GVIR_DESIGNER_DOMAIN_RESOURCES_RECOMMENDED;
- else {
- print_error("Unknown value '%s' for resources", resources_str);
- goto cleanup;
- }
- gvir_designer_domain_setup_resources(domain, resources, &error);
- CHECK_ERROR;
- } else {
- gvir_designer_domain_setup_resources(domain,
- GVIR_DESIGNER_DOMAIN_RESOURCES_RECOMMENDED,
- NULL);
+ if (domain == NULL) {
+ print_error ("Failed to create domain from commandline options");
+ goto cleanup;
}
- 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));
@@ -621,16 +75,10 @@ main(int argc, char *argv[])
cleanup:
if (context)
g_option_context_free(context);
- if (os)
- g_object_unref(G_OBJECT(os));
- if (platform)
- g_object_unref(G_OBJECT(platform));
- if (caps)
- g_object_unref(G_OBJECT(caps));
+ if (options)
+ gvir_designer_options_free(options);
if (domain)
g_object_unref(G_OBJECT(domain));
- if (conn)
- gvir_connection_close(conn);
return ret;
}