/** * Creation of a new VM by cloning from an existing template (looked up by name) */ static xen_vm create_new_vm(xen_session *session, char* template_name, char* sr_name, bool PV) { /* * Lookup template by name */ xen_vm_set *vms; if (!xen_vm_get_by_name_label(session, &vms, template_name) || vms->size < 1) { fprintf(stderr, "VM lookup failed.\n"); print_error(session); return NULL; } /* * Create VM by cloning from template */ xen_vm vm; char *name_before = "NewVM <&>"; //using xml sensitive characters int name_length = 9; xen_vm_clone(session, &vm, vms->contents[0], name_before); char *name_after; xen_vm_get_name_label(session, &name_after, vm); int result = strncmp(name_before, name_after, name_length); if (result != 0){ fprintf(stderr, "Error: The VM name failed to be encoded/decoded correctly\n"); fprintf(stderr, "Before:%s\nAfter:%s\n", name_before, name_after); return NULL; } xen_vm_set_free(vms); if (!session->ok) { fprintf(stderr, "VM clone failed.\n"); print_error(session); return NULL; } if (PV) { xen_string_string_map *other_config; if (!xen_vm_get_other_config(session, &other_config, vm)) { fprintf(stderr, "VM get other_config failed.\n"); print_error(session); return NULL; } char *disks = NULL; for (size_t i=0; i < other_config->size; i++) { printf("%s -> %s.\n", other_config->contents[i].key, other_config->contents[i].val); if (strcmp(other_config->contents[i].key, "disks") == 0) { disks = other_config->contents[i].val; break; } } if (disks == NULL) { fprintf(stderr, "Did not find provision XML in other_config.\n"); xen_string_string_map_free(other_config); return NULL; } xen_sr_set *srs; if (!xen_sr_get_by_name_label(session, &srs, sr_name) || srs->size < 1) { fprintf(stderr, "SR lookup failed.\n"); print_error(session); xen_vm_free(vm); return NULL; } xen_sr sr = srs->contents[0]; char *sr_uuid; if(!xen_sr_get_uuid(session, &sr_uuid, sr)){ //TODO free...? return NULL; } char *new_str; if(asprintf(&new_str, "sr=\"%s\"", sr_uuid) < 0) { return NULL; } char *new_disks = replace_str(disks, "sr=\"\"", new_str); free(new_str); xen_string_string_map_free(other_config); if (new_disks == NULL) { fprintf(stderr, "Error replacing SR in provision XML.\n"); return NULL; } fprintf(stdout, "New provisions XML: %s\n", new_disks); if (!xen_vm_remove_from_other_config(session, vm, "disks")) { fprintf(stderr, "Error removing old value from other_config.\n"); print_error(session); free(new_disks); return NULL; } if (!xen_vm_add_to_other_config(session, vm, "disks", new_disks)) { fprintf(stderr, "Error adding new value to other_config.\n"); print_error(session); free(new_disks); return NULL; } free(new_disks); } xen_vm_set_name_description(session, vm, "An example VM created via C bindings"); if (!session->ok) { fprintf(stderr, "Failed to set VM description.\n"); print_error(session); return NULL; } xen_vm_provision(session, vm); if (!session->ok) { fprintf(stderr, "Failed to provision VM.\n"); print_error(session); return NULL; } if (PV) return vm; /* * Create a new disk for the new VM. */ printf("Creating new (blank) disk image in 'Shared SR'\n"); xen_sr_set *srs; if (!xen_sr_get_by_name_label(session, &srs, sr_name) || srs->size < 1) { fprintf(stderr, "SR lookup failed.\n"); print_error(session); xen_vm_free(vm); return NULL; } xen_sr_record_opt sr_record = { .u.handle = srs->contents[0] }; xen_string_string_map* other_config = xen_string_string_map_alloc(0); xen_vdi_record vdi0_record = { .name_label = "MyRootFS", .name_description = "MyRootFS description", .sr = &sr_record, .virtual_size = (1024 * 1024 * 1024), /* 1 GiB in bytes */ .type = XEN_VDI_TYPE_SYSTEM, .sharable = false, .read_only = false, .other_config = other_config }; xen_vdi vdi0; if (!xen_vdi_create(session, &vdi0, &vdi0_record)) { fprintf(stderr, "VDI creation failed.\n"); print_error(session); xen_sr_set_free(srs); xen_vm_free(vm); return NULL; } xen_vm_record_opt vm_record_opt = { .u.handle = vm }; xen_vdi_record_opt vdi0_record_opt = { .u.handle = vdi0 }; xen_string_string_map* qos_algorithm_params = xen_string_string_map_alloc(0); xen_string_string_map* vbd_other_config = xen_string_string_map_alloc(0); enum xen_vbd_type vbd_type_disk = xen_vbd_type_from_string(session, "Disk"); printf("Attaching disk image to newly created VM\n"); xen_vbd_record vbd0_record = { .vm = &vm_record_opt, .vdi = &vdi0_record_opt, .userdevice = "xvda", .type = vbd_type_disk, .mode = XEN_VBD_MODE_RW, .bootable = 1, .qos_algorithm_params = qos_algorithm_params, .other_config = vbd_other_config }; xen_vbd vbd0; if (!xen_vbd_create(session, &vbd0, &vbd0_record)) { fprintf(stderr, "VBD creation failed.\n"); print_error(session); xen_vdi_free(vdi0); xen_sr_set_free(srs); xen_vm_free(vm); return NULL; } char *vm_uuid; char *vdi0_uuid; char *vbd0_uuid; xen_vm_get_uuid(session, &vm_uuid, vm); xen_vdi_get_uuid(session, &vdi0_uuid, vdi0); xen_vbd_get_uuid(session, &vbd0_uuid, vbd0); if (!session->ok) { fprintf(stderr, "get_uuid call failed.\n"); print_error(session); xen_uuid_free(vm_uuid); xen_uuid_free(vdi0_uuid); xen_uuid_free(vbd0_uuid); xen_vbd_free(vbd0); xen_vdi_free(vdi0); xen_sr_set_free(srs); xen_vm_free(vm); return NULL; } fprintf(stderr, "Created a new VM, with UUID %s, VDI UUID %s, VBD " "UUID %s.\n", vm_uuid, vdi0_uuid, vbd0_uuid); xen_uuid_free(vm_uuid); xen_uuid_free(vdi0_uuid); xen_uuid_free(vbd0_uuid); xen_vbd_free(vbd0); xen_vdi_free(vdi0); xen_sr_set_free(srs); return vm; } /** * Print the power state for the given VM. */ static void print_vm_power_state(xen_session *session, xen_vm vm) { char *vm_uuid; enum xen_vm_power_state power_state; if (!xen_vm_get_uuid(session, &vm_uuid, vm)) { print_error(session); return; } if (!xen_vm_get_power_state(session, &power_state, vm)) { xen_uuid_free(vm_uuid); print_error(session); return; } printf("VM %s power state is %s.\n", vm_uuid, xen_vm_power_state_to_string(power_state)); xen_uuid_free(vm_uuid); } /* * Replace all occurrences of orig in str with rep * * @returns newly malloc'd string - you must free it */ static char *replace_str(char *str, char *orig, char *rep) { int occurrences = 0; int i = 0, k = 0; char *p = str; while ((p = strstr(p, orig)) != NULL) { ++occurrences; p += strlen(orig); } char *buffer = malloc(strlen(str) + 1 - (occurrences * (strlen(orig) - strlen(rep)))); if(buffer == NULL) return NULL; p = str; while ((p = strstr(p, orig)) != NULL) { int j = p - str - k; strncpy(buffer + i, str + k, j); i += j; strcpy(buffer + i, rep); i += strlen(rep); p += strlen(orig); k += j + strlen(orig); } strncpy(buffer + i, str + k, strlen(str + k)); buffer[i + strlen(str + k)] = '\0'; return buffer; }
/* * Callback received when the hotplug scripts have placed the physical-device * node. Read it and the mode node, and create a vbd. If the frontend is * ready, connect. */ static void backend_changed(struct xenbus_watch *watch, const char **vec, unsigned int len) { int err; unsigned major; unsigned minor; struct backend_info *be = container_of(watch, struct backend_info, backend_watch); struct xenbus_device *dev = be->dev; int cdrom = 0; unsigned long handle; char *device_type; DPRINTK(""); err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%x:%x", &major, &minor); if (XENBUS_EXIST_ERR(err)) { /* * Since this watch will fire once immediately after it is * registered, we expect this. Ignore it, and wait for the * hotplug scripts. */ return; } if (err != 2) { xenbus_dev_fatal(dev, err, "reading physical-device"); return; } if (be->major | be->minor) { if (be->major != major || be->minor != minor) pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n", be->major, be->minor, major, minor); return; } be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL); if (IS_ERR(be->mode)) { err = PTR_ERR(be->mode); be->mode = NULL; xenbus_dev_fatal(dev, err, "reading mode"); return; } device_type = xenbus_read(XBT_NIL, dev->otherend, "device-type", NULL); if (!IS_ERR(device_type)) { cdrom = strcmp(device_type, "cdrom") == 0; kfree(device_type); } /* Front end dir is a number, which is used as the handle. */ err = strict_strtoul(strrchr(dev->otherend, '/') + 1, 0, &handle); if (err) return; be->major = major; be->minor = minor; err = xen_vbd_create(be->blkif, handle, major, minor, !strchr(be->mode, 'w'), cdrom); if (err) xenbus_dev_fatal(dev, err, "creating vbd structure"); else { err = xenvbd_sysfs_addif(dev); if (err) { xen_vbd_free(&be->blkif->vbd); xenbus_dev_fatal(dev, err, "creating sysfs entries"); } } if (err) { kfree(be->mode); be->mode = NULL; be->major = 0; be->minor = 0; } else { /* We're potentially connected now */ xen_update_blkif_status(be->blkif); } }