[libvirt] [libvirt-designer][PATCH 0/4] Yet another functional extension

This time aimed on virtxml tool to make it user friendlier a little bit. Michal Privoznik (4): Implement resources setting Cleanup double error setting and operating on empty list virtxml: Detect OS from given ISO virtxml: Detect platform from libvirt connection URI examples/virtxml.c | 200 ++++++++++++++++++++++++---- libvirt-designer/libvirt-designer-domain.c | 113 +++++++++++++++- libvirt-designer/libvirt-designer-domain.h | 8 + libvirt-designer/libvirt-designer.sym | 3 +- 4 files changed, 292 insertions(+), 32 deletions(-) -- 1.7.8.6

Users can choose between minimum and recommended values for VCPU count and amount of RAM. Moreover, recommended values should inherit defaults from the minimum. --- examples/virtxml.c | 27 +++++++- libvirt-designer/libvirt-designer-domain.c | 98 +++++++++++++++++++++++++++- libvirt-designer/libvirt-designer-domain.h | 8 ++ libvirt-designer/libvirt-designer.sym | 3 +- 4 files changed, 132 insertions(+), 4 deletions(-) diff --git a/examples/virtxml.c b/examples/virtxml.c index 87929b2..468bc2a 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -69,6 +69,8 @@ print_usage(const char *progname) " source and FORMAT is its format\n" " -i | --interface=NETWORK[,ARG=VAL] add interface with NETWORK source.\n" " Possible ARGs: mac,link={up,down}\n", + " -r | --resource={minimal|recommended} Set minimal or recommended values for\n" + " cpu count and RAM amount.\n", progname); } @@ -276,6 +278,7 @@ main(int argc, char *argv[]) char *connect_uri = NULL; GList *disk_str_list = NULL; GList *iface_str_list = NULL; + gchar *resources = NULL; int arg; struct option opt[] = { @@ -288,6 +291,7 @@ main(int argc, char *argv[]) {"architecture", required_argument, NULL, 'a'}, {"disk", required_argument, NULL, 'd'}, {"interface", required_argument, NULL, 'i'}, + {"resource", required_argument, NULL, 'r'}, {NULL, 0, NULL, 0} }; @@ -297,7 +301,7 @@ main(int argc, char *argv[]) /* Standard (non-command) options. The leading + ensures that no * argument reordering takes place, so that command options are * not confused with top-level virsh options. */ - while ((arg = getopt_long(argc, argv, "+hc:o:p:a:d:i:", opt, NULL)) != -1) { + while ((arg = getopt_long(argc, argv, "+hc:o:p:a:d:i:r:", opt, NULL)) != -1) { char *progname; switch (arg) { case 'h': @@ -347,6 +351,18 @@ main(int argc, char *argv[]) case 'i': iface_str_list = g_list_append(iface_str_list, optarg); break; + case 'r': + if (!strcmp(optarg, "minimal") || + !strcmp(optarg, "min")) { + resources = GVIR_DESIGNER_DOMAIN_RESOURCES_MINIMAL; + } else if (!strcmp(optarg, "recommended") || + !strcmp(optarg, "rec")) { + resources = GVIR_DESIGNER_DOMAIN_RESOURCES_RECOMMENDED; + } else { + print_error("Unknown resources value: '%s'", optarg); + exit(EXIT_FAILURE); + } + break; default: print_error("Something has gone tragically wrong"); case '?': @@ -389,6 +405,15 @@ main(int argc, char *argv[]) CHECK_ERROR; } + if (resources) { + gvir_designer_domain_setup_resources(domain, resources, &error); + CHECK_ERROR; + } else { + gvir_designer_domain_setup_resources(domain, + GVIR_DESIGNER_DOMAIN_RESOURCES_RECOMMENDED, + NULL); + } + g_list_foreach(disk_str_list, add_disk, domain); g_list_foreach(iface_str_list, add_iface, domain); diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index 5a10836..0411da4 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -213,9 +213,15 @@ GVirDesignerDomain *gvir_designer_domain_new(OsinfoOs *os, OsinfoPlatform *platform, GVirConfigCapabilities *caps) { + OsinfoOs *os_found = NULL; + OsinfoPlatform *platform_found = NULL; + + os_found = osinfo_db_get_os(osinfo_db, osinfo_entity_get_id(OSINFO_ENTITY(os))); + platform_found = osinfo_db_get_platform(osinfo_db, osinfo_entity_get_id(OSINFO_ENTITY(platform))); + return GVIR_DESIGNER_DOMAIN(g_object_new(GVIR_DESIGNER_TYPE_DOMAIN, - "os", os, - "platform", platform, + "os", os_found, + "platform", platform_found, "capabilities", caps, NULL)); } @@ -960,3 +966,91 @@ gvir_designer_domain_add_interface_network(GVirDesignerDomain *design, return ret; } + +static void +gvir_designer_domain_get_resources(OsinfoResourcesList *list, + const gchar *design_arch, + gint *design_n_cpus, + gint64 *design_ram) +{ + int i; + + if (!list) + return; + + for (i = 0; i < osinfo_list_get_length(OSINFO_LIST(list)); i++) { + OsinfoResources *res = OSINFO_RESOURCES(osinfo_list_get_nth(OSINFO_LIST(list), i)); + const char *arch = osinfo_resources_get_architecture(res); + gint n_cpus = -1; + gint64 ram = -1; + + if (g_str_equal(arch, "all") || + g_str_equal(arch, design_arch)) { + n_cpus = osinfo_resources_get_n_cpus(res); + ram = osinfo_resources_get_ram(res); + if (n_cpus > 0) { + *design_n_cpus = n_cpus; + } + if (ram > 0) { + /* libosinfo returns RAM in B, libvirt-gconfig takes it in KB */ + *design_ram = ram / 1024; + } + break; + } + } +} + +/** + * gvir_designer_domain_setup_resources: + * @design: (transfer none): the domain designer intance + * @req: (transfer none): requirements to set + * + * Set minimal or recommended resources on @design. + * + * Returns: (transfer none): TRUE when successfully set, FALSE otherwise. + */ +gboolean gvir_designer_domain_setup_resources(GVirDesignerDomain *design, + const gchar *req, + GError **error) +{ + g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), FALSE); + gboolean ret = FALSE; + OsinfoResourcesList *res_list_min = NULL, *res_list_rec = NULL; + GVirConfigDomainOs *os = gvir_config_domain_get_os(design->priv->config); + const gchar *design_arch = os ? gvir_config_domain_os_get_arch(os) : ""; + gint n_cpus = -1; + gint64 ram = -1; + + /* If user request recommended settings those may just override + * only a few settings when compared to minimal. So we must implement + * inheritance here. */ + res_list_min = osinfo_os_get_minimum_resources(design->priv->os); + res_list_rec = osinfo_os_get_recommended_resources(design->priv->os); + if (g_str_equal(req, GVIR_DESIGNER_DOMAIN_RESOURCES_MINIMAL)) { + gvir_designer_domain_get_resources(res_list_min, design_arch, + &n_cpus, &ram); + } else if (g_str_equal(req, GVIR_DESIGNER_DOMAIN_RESOURCES_RECOMMENDED)) { + gvir_designer_domain_get_resources(res_list_min, design_arch, + &n_cpus, &ram); + gvir_designer_domain_get_resources(res_list_rec, design_arch, + &n_cpus, &ram); + } else { + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "Unknown resources argument: '%s'", req); + goto cleanup; + } + + if ((n_cpus <= 0) && (ram <= 0)) { + g_set_error(error, GVIR_DESIGNER_DOMAIN_ERROR, 0, + "Unable to find resources in libosinfo database"); + goto cleanup; + } + + if (n_cpus > 0) + gvir_config_domain_set_vcpus(design->priv->config, n_cpus); + if (ram > 0) + gvir_config_domain_set_memory(design->priv->config, ram); + +cleanup: + return ret; +} diff --git a/libvirt-designer/libvirt-designer-domain.h b/libvirt-designer/libvirt-designer-domain.h index 5097393..28a1d06 100644 --- a/libvirt-designer/libvirt-designer-domain.h +++ b/libvirt-designer/libvirt-designer-domain.h @@ -39,6 +39,9 @@ G_BEGIN_DECLS #define GVIR_DESIGNER_IS_DOMAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GVIR_DESIGNER_TYPE_DOMAIN)) #define GVIR_DESIGNER_DOMAIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GVIR_DESIGNER_TYPE_DOMAIN, GVirDesignerDomainClass)) +#define GVIR_DESIGNER_DOMAIN_RESOURCES_MINIMAL "minimal" +#define GVIR_DESIGNER_DOMAIN_RESOURCES_RECOMMENDED "recommended" + typedef struct _GVirDesignerDomain GVirDesignerDomain; typedef struct _GVirDesignerDomainPrivate GVirDesignerDomainPrivate; typedef struct _GVirDesignerDomainClass GVirDesignerDomainClass; @@ -104,6 +107,11 @@ GVirConfigDomainDisk *gvir_designer_domain_add_disk_device(GVirDesignerDomain *d GVirConfigDomainInterface *gvir_designer_domain_add_interface_network(GVirDesignerDomain *design, const char *network, GError **error); + +gboolean gvir_designer_domain_setup_resources(GVirDesignerDomain *design, + const gchar *req, + 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 77f76b4..0dde9a6 100644 --- a/libvirt-designer/libvirt-designer.sym +++ b/libvirt-designer/libvirt-designer.sym @@ -12,7 +12,8 @@ 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_add_interface_network; + gvir_designer_domain_setup_resources; gvir_designer_domain_setup_machine; gvir_designer_domain_setup_machine_full; -- 1.7.8.6

and virtio disks can be advertised as PCI bus devices. --- libvirt-designer/libvirt-designer-domain.c | 15 ++++++++++++--- 1 files changed, 12 insertions(+), 3 deletions(-) diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c index 0411da4..4046d8c 100644 --- a/libvirt-designer/libvirt-designer-domain.c +++ b/libvirt-designer/libvirt-designer-domain.c @@ -688,6 +688,9 @@ gvir_designer_domain_get_supported_disk_bus_types(GVirDesignerDomain *design) 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); @@ -699,6 +702,7 @@ gvir_designer_domain_get_supported_disk_bus_types(GVirDesignerDomain *design) ret = g_hash_table_get_keys(bus_hash); ret = g_list_copy(ret); +cleanup: g_hash_table_destroy(bus_hash); return ret; } @@ -811,18 +815,23 @@ gvir_designer_domain_add_disk_full(GVirDesignerDomain *design, goto error; item = g_list_first(bus_str_list); - bus_str_list = item->data; + 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"); - gvir_config_domain_disk_set_driver_type(disk, format); + 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")) { + } 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; -- 1.7.8.6

In some cases telling OS version is redundant as ISO image with specified OS is passed some arguments later as disk. Don't require --os then. --- examples/virtxml.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 71 insertions(+), 5 deletions(-) diff --git a/examples/virtxml.c b/examples/virtxml.c index 468bc2a..131c462 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -253,6 +253,67 @@ add_iface(gpointer data, } } +static OsinfoOs * +guess_os_from_disk(GList *disk_str_list) +{ + OsinfoOs *ret = NULL; + GList *tmp = g_list_first(disk_str_list); + OsinfoLoader *loader = osinfo_loader_new(); + GError *error = NULL; + OsinfoDb *db; + + osinfo_loader_process_default_path(loader, &error); + if (error) { + print_error("Error loading libosinfo data: %s", error->message); + goto cleanup; + } + + db = osinfo_loader_get_db(loader); + + while (tmp) { + char *path = (char *) tmp->data; + char *sep = strchr(path, ','); + OsinfoMedia *media = NULL; + OsinfoMedia *matched_media = NULL; + + if (sep) { + path = g_strndup(path, sep-path); + } + + media = osinfo_media_create_from_location(path, NULL, &error); + if (error) { + /* don't report error but silently continue to next disk */ + print_error("%s", error->message); + g_error_free(error); + error = NULL; + tmp = g_list_next(tmp); + continue; + } + + ret = osinfo_db_guess_os_from_media(db, media, &matched_media); + + if (sep) + g_free(path); + + if (ret) { + g_object_ref(ret); + break; + } + + tmp = g_list_next(tmp); + } + +cleanup: + g_clear_object(&loader); + return ret; +} + +static OsinfoPlatform * +guess_platform_from_connect(virConnectPtr conn) +{ + return NULL; +} + #define CHECK_ERROR \ if (error) { \ print_error("%s", error->message); \ @@ -371,10 +432,6 @@ main(int argc, char *argv[]) } } - if (!os_str) { - print_error("Operating system was not specified"); - exit(EXIT_FAILURE); - } if (!platform_str) { print_error("Platform was not specified"); exit(EXIT_FAILURE); @@ -391,10 +448,19 @@ main(int argc, char *argv[]) goto cleanup; } - os = osinfo_os_new(os_str); platform = osinfo_platform_new(platform_str); caps = gvir_config_capabilities_new_from_xml(caps_str, NULL); + if (os_str) { + os = osinfo_os_new(os_str); + } else { + os = guess_os_from_disk(disk_str_list); + if (!os) { + print_error("Operating system was not specified and could not be guessed"); + exit(EXIT_FAILURE); + } + } + domain = gvir_designer_domain_new(os, platform, caps); gvir_designer_domain_setup_machine(domain, &error); -- 1.7.8.6

as in nearly all cases users will install the guest on current libvirt we've just obtained capabilities from. --- examples/virtxml.c | 119 ++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 88 insertions(+), 31 deletions(-) diff --git a/examples/virtxml.c b/examples/virtxml.c index 131c462..3e00e09 100644 --- a/examples/virtxml.c +++ b/examples/virtxml.c @@ -37,6 +37,9 @@ #define print_error(...) \ print_error_impl(__FUNCTION__, __LINE__, __VA_ARGS__) +OsinfoLoader *loader = NULL; +OsinfoDb *db = NULL; + static void print_error_impl(const char *funcname, size_t linenr, @@ -74,12 +77,11 @@ print_usage(const char *progname) progname); } -static OsinfoDb * -get_default_osinfo_db(void) +static gboolean +load_osinfo(void) { GError *err = NULL; - OsinfoLoader *loader = NULL; - OsinfoDb *ret = NULL; + gboolean ret = FALSE; loader = osinfo_loader_new(); osinfo_loader_process_default_path(loader, &err); @@ -88,8 +90,9 @@ get_default_osinfo_db(void) goto cleanup; } - ret = osinfo_loader_get_db(loader); - g_object_ref(ret); + db = osinfo_loader_get_db(loader); + g_object_ref(db); + ret = TRUE; cleanup: g_object_unref(loader); @@ -99,11 +102,10 @@ cleanup: static int print_oses(void) { - OsinfoDb *db = get_default_osinfo_db(); OsinfoOsList *list; int i; - if (!db) + if (!db && !load_osinfo()) return EXIT_FAILURE; list = osinfo_db_get_os_list(db); @@ -121,19 +123,16 @@ print_oses(void) } g_object_unref(list); - g_object_unref(db); - return EXIT_SUCCESS; } static int print_platforms(void) { - OsinfoDb *db = get_default_osinfo_db(); OsinfoPlatformList *list; int i; - if (!db) + if (!db && !load_osinfo()) return EXIT_FAILURE; list = osinfo_db_get_platform_list(db); @@ -152,8 +151,6 @@ print_platforms(void) } g_object_unref(list); - g_object_unref(db); - return EXIT_SUCCESS; } @@ -258,17 +255,10 @@ guess_os_from_disk(GList *disk_str_list) { OsinfoOs *ret = NULL; GList *tmp = g_list_first(disk_str_list); - OsinfoLoader *loader = osinfo_loader_new(); GError *error = NULL; - OsinfoDb *db; - osinfo_loader_process_default_path(loader, &error); - if (error) { - print_error("Error loading libosinfo data: %s", error->message); - goto cleanup; - } - - db = osinfo_loader_get_db(loader); + if (!db && !load_osinfo()) + exit(EXIT_FAILURE); while (tmp) { char *path = (char *) tmp->data; @@ -304,14 +294,75 @@ guess_os_from_disk(GList *disk_str_list) } cleanup: - g_clear_object(&loader); + return ret; +} + +static OsinfoPlatform * +find_platform_by_short_id(const char *short_id) +{ + OsinfoPlatform *ret = NULL; + OsinfoPlatformList *list = NULL; + int i; + + if (!db && !load_osinfo()) + return NULL; + + list = osinfo_db_get_platform_list(db); + + for (i = 0; i < osinfo_list_get_length(OSINFO_LIST(list)); i++) { + OsinfoPlatform *ent = OSINFO_PLATFORM(osinfo_list_get_nth(OSINFO_LIST(list), i)); + const char *id = osinfo_entity_get_param_value(OSINFO_ENTITY(ent), + OSINFO_PRODUCT_PROP_SHORT_ID); + + if (id && + !strcmp(id, short_id)) { + ret = ent; + g_object_ref(ret); + break; + } + } + + g_object_unref(list); return ret; } static OsinfoPlatform * guess_platform_from_connect(virConnectPtr conn) { - return NULL; + OsinfoPlatform *ret = NULL; + const char *hv_type = virConnectGetType(conn); + unsigned long ver, major, minor, release; + int tmp; + char *short_id = NULL, *type = NULL; + + tmp = virConnectGetVersion(conn, &ver); + if (!hv_type || tmp < 0) { + print_error("Unable to get hypervisor and its version"); + exit(EXIT_FAILURE); + } + + /* do some mappings: + * QEMU -> kvm + * Xen -> xen + */ + type = g_ascii_strdown(hv_type, -1); + if (!strcmp(type, "qemu")) { + g_free(type); + type = g_strdup("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(type); + return ret; } #define CHECK_ERROR \ @@ -432,11 +483,6 @@ main(int argc, char *argv[]) } } - if (!platform_str) { - print_error("Platform was not specified"); - exit(EXIT_FAILURE); - } - conn = virConnectOpenAuth(connect_uri, virConnectAuthPtrDefault, VIR_CONNECT_RO); if (!conn) { print_error("Unable to connect to libvirt"); @@ -448,7 +494,6 @@ main(int argc, char *argv[]) goto cleanup; } - platform = osinfo_platform_new(platform_str); caps = gvir_config_capabilities_new_from_xml(caps_str, NULL); if (os_str) { @@ -461,6 +506,18 @@ main(int argc, char *argv[]) } } + if (platform_str) { + platform = osinfo_platform_new(platform_str); + } else { + platform = guess_platform_from_connect(conn); + + if (!platform) { + print_error("Platform was not specified and could not be guessed"); + exit(EXIT_FAILURE); + } + } + + domain = gvir_designer_domain_new(os, platform, caps); gvir_designer_domain_setup_machine(domain, &error); -- 1.7.8.6
participants (1)
-
Michal Privoznik