Ejemplo n.º 1
0
/* creates network intereface for VM */
int
createVifNetwork (virConnectPtr conn, xen_vm vm, char *device,
                  char *bridge, char *mac)
{
    xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session;
    xen_vm xvm = NULL;
    char *uuid = NULL;
    xen_vm_get_uuid(session, &uuid, vm);
    if (uuid) {
        if (!xen_vm_get_by_uuid(session, &xvm, uuid))
            return -1;
        VIR_FREE(uuid);
    }
    xen_vm_record_opt *vm_opt = xen_vm_record_opt_alloc();
    vm_opt->is_record = 0;
    vm_opt->u.handle = xvm;
    xen_network_set *net_set = NULL;
    xen_network_record *net_rec = NULL;
    int cnt = 0;
    if (xen_network_get_all(session, &net_set)) {
        for(cnt = 0; cnt < net_set->size; cnt++) {
            if (xen_network_get_record(session, &net_rec, net_set->contents[cnt])) {
                if (STREQ(net_rec->bridge, bridge)) {
                    break;
                } else {
                    xen_network_record_free(net_rec);
                }
            }
        }
    }
    if (cnt < net_set->size && net_rec) {
        xen_network network = NULL;
        xen_network_get_by_uuid(session, &network, net_rec->uuid);
        xen_network_record_opt *network_opt = xen_network_record_opt_alloc();
        network_opt->is_record = 0;
        network_opt->u.handle = network;
        xen_vif_record *vif_record = xen_vif_record_alloc();
        vif_record->mac = mac;
        vif_record->vm = vm_opt;
        vif_record->network = network_opt;
        xen_vif vif = NULL;

        vif_record->other_config = xen_string_string_map_alloc(0);
        vif_record->runtime_properties = xen_string_string_map_alloc(0);
        vif_record->qos_algorithm_params = xen_string_string_map_alloc(0);
        vif_record->device = strdup(device);
        xen_vif_create(session, &vif, vif_record);
        if (!vif) {
            xen_vif_free(vif);
            xen_vif_record_free(vif_record);
            xen_network_record_free(net_rec);
            xen_network_set_free(net_set);
            return 0;
        }
        xen_vif_record_free(vif_record);
        xen_network_record_free(net_rec);
    }
    if (net_set != NULL) xen_network_set_free(net_set);
    return -1;
}
Ejemplo n.º 2
0
/* Create a VM record from the XML description */
int
createVMRecordFromXml(virConnectPtr conn, virDomainDefPtr def,
                      xen_vm_record **record, xen_vm *vm)
{
    char uuidStr[VIR_UUID_STRING_BUFLEN];
    xen_string_string_map *strings = NULL;
    int device_number = 0;
    size_t i;

    *record = xen_vm_record_alloc();
    if (VIR_STRDUP((*record)->name_label, def->name) < 0)
        goto error;
    if (def->uuid) {
        virUUIDFormat(def->uuid, uuidStr);
        if (VIR_STRDUP((*record)->uuid, uuidStr) < 0)
            goto error;
    }
    if (STREQ(def->os.type, "hvm")) {
        char *boot_order = NULL;
        if (VIR_STRDUP((*record)->hvm_boot_policy, "BIOS order") < 0)
            goto error;
        if (def->os.nBootDevs != 0)
            boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]);
        if (boot_order != NULL) {
            xen_string_string_map *hvm_boot_params = NULL;
            allocStringMap(&hvm_boot_params, (char *)"order", boot_order);
            (*record)->hvm_boot_params = hvm_boot_params;
            VIR_FREE(boot_order);
        }
    } else if (STREQ(def->os.type, "xen")) {
        if (VIR_STRDUP((*record)->pv_bootloader, "pygrub") < 0)
            goto error;
        if (def->os.kernel) {
            if (VIR_STRDUP((*record)->pv_kernel, def->os.kernel) < 0)
                goto error;
        }
        if (def->os.initrd) {
            if (VIR_STRDUP((*record)->pv_ramdisk, def->os.initrd) < 0)
                goto error;
        }
        if (def->os.cmdline) {
            if (VIR_STRDUP((*record)->pv_args, def->os.cmdline) < 0)
                goto error;
        }
        (*record)->hvm_boot_params = xen_string_string_map_alloc(0);
    }
    if (def->os.bootloaderArgs)
        if (VIR_STRDUP((*record)->pv_bootloader_args, def->os.bootloaderArgs) < 0)
            goto error;

    if (def->mem.cur_balloon)
        (*record)->memory_static_max = (int64_t) (def->mem.cur_balloon * 1024);
    if (def->mem.max_balloon)
        (*record)->memory_dynamic_max = (int64_t) (def->mem.max_balloon * 1024);
    else
        (*record)->memory_dynamic_max = (*record)->memory_static_max;

    if (def->maxvcpus) {
        (*record)->vcpus_max = (int64_t) def->maxvcpus;
        (*record)->vcpus_at_startup = (int64_t) def->vcpus;
    }
    if (def->onPoweroff)
        (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff);
    if (def->onReboot)
        (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot);
    if (def->onCrash)
        (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash);

    if (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_DOMAIN_FEATURE_STATE_ON)
        allocStringMap(&strings, (char *)"acpi", (char *)"true");
    if (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_DOMAIN_FEATURE_STATE_ON)
        allocStringMap(&strings, (char *)"apic", (char *)"true");
    if (def->features[VIR_DOMAIN_FEATURE_PAE] == VIR_DOMAIN_FEATURE_STATE_ON)
        allocStringMap(&strings, (char *)"pae", (char *)"true");
    if (def->features[VIR_DOMAIN_FEATURE_HAP] == VIR_DOMAIN_FEATURE_STATE_ON)
        allocStringMap(&strings, (char *)"hap", (char *)"true");
    if (def->features[VIR_DOMAIN_FEATURE_VIRIDIAN] == VIR_DOMAIN_FEATURE_STATE_ON)
        allocStringMap(&strings, (char *)"viridian", (char *)"true");
    if (strings != NULL)
        (*record)->platform = strings;

    (*record)->vcpus_params = xen_string_string_map_alloc(0);
    (*record)->other_config = xen_string_string_map_alloc(0);
    (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0);
    (*record)->xenstore_data = xen_string_string_map_alloc(0);
    (*record)->hvm_shadow_multiplier = 1.000;
    if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session,
                        vm, *record)) {
        xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL);
        return -1;
    }

    for (i = 0; i < def->nnets; i++) {
        if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
            def->nets[i]->data.bridge.brname) {
            char *mac;

            if (VIR_ALLOC_N(mac, VIR_MAC_STRING_BUFLEN) < 0)
                goto error;
            virMacAddrFormat(&def->nets[i]->mac, mac);

            if (createVifNetwork(conn, *vm, device_number,
                                 def->nets[i]->data.bridge.brname,
                                 mac) < 0) {
                VIR_FREE(mac);
                virReportOOMError();
                goto error;
            }
            device_number++;
        }
    }
    return 0;

  error:
    xen_vm_record_free(*record);
    return -1;
}
Ejemplo n.º 3
0
/* Create a VM record from the XML description */
int
createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def,
                       xen_vm_record **record, xen_vm *vm)
{
    char uuidStr[VIR_UUID_STRING_BUFLEN];
    *record = xen_vm_record_alloc();
    if (!((*record)->name_label = strdup(def->name)))
        goto error_cleanup;
    if (def->uuid) {
        virUUIDFormat(def->uuid, uuidStr);
        if (!((*record)->uuid = strdup(uuidStr)))
            goto error_cleanup;
    }
    if (STREQ(def->os.type, "hvm")) {
        char *boot_order = NULL;
        if (!((*record)->hvm_boot_policy = strdup("BIOS order")))
            goto error_cleanup;
        if (def->os.nBootDevs != 0)
            boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]);
        if (boot_order != NULL) {
            xen_string_string_map *hvm_boot_params = NULL;
            allocStringMap(&hvm_boot_params, (char *)"order", boot_order);
            (*record)->hvm_boot_params = hvm_boot_params;
            VIR_FREE(boot_order);
        }
    } else if (STREQ(def->os.type, "xen")) {
        if (!((*record)->pv_bootloader = strdup("pygrub")))
            goto error_cleanup;
        if (def->os.kernel) {
            if (!((*record)->pv_kernel = strdup(def->os.kernel)))
                goto error_cleanup;
        }
        if (def->os.initrd) {
            if (!((*record)->pv_ramdisk = strdup(def->os.initrd)))
                goto error_cleanup;
        }
        if (def->os.cmdline) {
            if (!((*record)->pv_args = strdup(def->os.cmdline)))
                goto error_cleanup;
        }
        (*record)->hvm_boot_params = xen_string_string_map_alloc(0);
    }
    if (def->os.bootloaderArgs)
        if (!((*record)->pv_bootloader_args = strdup(def->os.bootloaderArgs)))
            goto error_cleanup;

    if (def->memory)
        (*record)->memory_static_max = (int64_t) (def->memory * 1024);
    if (def->maxmem)
        (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024);
    else
        (*record)->memory_dynamic_max = (*record)->memory_static_max;

    if (def->vcpus) {
        (*record)->vcpus_max = (int64_t) def->vcpus;
        (*record)->vcpus_at_startup = (int64_t) def->vcpus;
    }
    if (def->onPoweroff)
        (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff);
    if (def->onReboot)
        (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot);
    if (def->onCrash)
        (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash);

    xen_string_string_map *strings = NULL;
    if (def->features) {
        if (def->features & (1 << VIR_DOMAIN_FEATURE_ACPI))
            allocStringMap(&strings, (char *)"acpi", (char *)"true");
        if (def->features & (1 << VIR_DOMAIN_FEATURE_APIC))
            allocStringMap(&strings, (char *)"apic", (char *)"true");
        if (def->features & (1 << VIR_DOMAIN_FEATURE_PAE))
            allocStringMap(&strings, (char *)"pae", (char *)"true");
    }
    if (strings != NULL)
        (*record)->platform = strings;

    (*record)->vcpus_params = xen_string_string_map_alloc(0);
    (*record)->other_config = xen_string_string_map_alloc(0);
    (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0);
    (*record)->xenstore_data = xen_string_string_map_alloc(0);
    (*record)->hvm_shadow_multiplier = 1.000;
    if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session,
                        vm, *record)) {
        xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL);
        return -1;
    }

    int device_number = 0;
    char *bridge = NULL, *mac = NULL;
    int i;
    for (i = 0; i < def->nnets; i++) {
        if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
            if (def->nets[i]->data.bridge.brname)
                if (!(bridge = strdup(def->nets[i]->data.bridge.brname)))
                    goto error_cleanup;
            if (def->nets[i]->mac) {
                char macStr[VIR_MAC_STRING_BUFLEN];
                virFormatMacAddr(def->nets[i]->mac, macStr);
                if (!(mac = strdup(macStr))) {
                    VIR_FREE(bridge);
                    goto error_cleanup;
                }
            }
            if (mac != NULL && bridge != NULL) {
                char device[NETWORK_DEVID_SIZE] = "\0";
                sprintf(device, "%d", device_number);
                createVifNetwork(conn, *vm, device, bridge, mac);
                VIR_FREE(bridge);
                device_number++;
            }
            VIR_FREE(bridge);
        }
    }
    return 0;

  error_cleanup:
    virReportOOMError();
    xen_vm_record_free(*record);
    return -1;
}
Ejemplo n.º 4
0
/**
 * 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;
}
/*
 * Async job worker that gets called on a separate thread (see Xen_Job.c)
*/
static void migrate_task(void *async_job)
{
    /* Perform the migration */
    Xen_job *job = (Xen_job *)async_job;
    xen_utils_session *session = job->session;
    int state = JobState_Exception;
    CMPIrc statusrc = CMPI_RC_ERR_FAILED;
    char *job_status_description = "ERROR: Migrate VM failed with unknown error";
    char *xen_error = NULL;
    migrate_job_context *job_context = (migrate_job_context *)job->job_context;
    bool kvpNeedsReenabling=false;
    bool error=false;
    char *uuid=NULL;
    xen_string_string_map *other_config=NULL;

    _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_INFO, ("Migration job started"));

    state = JobState_Running;
    job_change_state(job, session, state, 0, 0, STATE_MIGRATE_STARTED);
    sleep(1);

    if(!error && !xen_vm_get_uuid(session->xen, &uuid, job_context->vm)) {
        _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_ERROR, ("Could not get the UUID of the vm."));
        error=true;
    }

    if(!error && !xen_vm_get_other_config(session->xen, &other_config, job_context->vm)) {
        _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_ERROR, ("Could not get other_config of the VM"));
        error=true;
    }

    if(!error && xen_utils_get_from_string_string_map(other_config, "kvp_enabled")) {
        _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_INFO, ("KVP is enabled, disabling it to allow migration"));
        kvpNeedsReenabling=true;
        if(xen_utils_preparemigration_kvp_channel(session, uuid) != Xen_KVP_RC_OK) {
            error=true;
            _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_ERROR, ("Could not prepare KVP for migration"));
        }
    }

    if(!error) {
        _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_INFO, ("Doing the migration"));
        xen_string_string_map *options = xen_string_string_map_alloc(0);
        if(!xen_vm_pool_migrate(session->xen, job_context->vm, job_context->host, options)) {
            _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_ERROR, ("Could not do the migration"));
            error=true;
        }
        xen_string_string_map_free(options);
    }

    if(!error) {
        state = JobState_Completed;
        statusrc = CMPI_RC_OK;
        job_status_description = "Completed Successfully";
    }
    else {
        state = JobState_Exception;
        statusrc = CMPI_RC_ERR_FAILED;
        xen_error = xen_utils_get_xen_error(session->xen);
        job_status_description = xen_error;
    }

    // The reenabling of KVM is always done,  it is not depending on whether the migration was succesfull / an error occured
    if(kvpNeedsReenabling) {
        _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_INFO, ("Reenabling KVP"));
        if (xen_utils_finishmigration_kvp_channel(session, uuid) != Xen_KVP_RC_OK) {
            _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_ERROR, ("Could not reenable KVP"));
			state = JobState_Exception;
			statusrc = CMPI_RC_ERR_FAILED;
			job_status_description = "Error: Could not re-enable KVP channel";
        }
    }

    _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_INFO, ("Migration job status %d (%s)", statusrc, job_status_description));
    job_change_state(job, session, state, 100, statusrc, job_status_description);

    if(job_context->vm) 
        xen_vm_free(job_context->vm);
    if(job_context->host)
        xen_host_free(job_context->host);
    free(job_context);
    if(xen_error)
        free(xen_error);
    if(uuid)
        free(uuid);
    if(other_config)
        free(other_config);
}
Ejemplo n.º 6
0
static CMPIrc host_set_properties(
    provider_resource *resource, 
    CMPIInstance *inst
    )
{
    local_host_resource *ctx = (local_host_resource *)resource->ctx;

    /* Key properties to be filled in */
    CMSetProperty(inst, "Name",(CMPIValue *)ctx->host_rec->uuid, CMPI_chars);
    CMSetProperty(inst, "CreationClassName",(CMPIValue *)"Xen_HostComputerSystem", CMPI_chars);

    xen_host_metrics metrics = NULL;
    xen_host_get_metrics(resource->session->xen, &metrics, ctx->host);
    xen_host_metrics_record *metrics_rec = NULL;
    if (metrics) {
        xen_host_metrics_get_record(resource->session->xen, &metrics_rec, metrics);
        xen_host_metrics_free(metrics);
    }

    /* Populate the instance's properties with the backend data */
    _set_allowed_operations(resource->broker, ctx->host_rec, inst, "AvailableRequestedStates");

    /* Check other-config (as a cache) */
    char *CN = NULL;
    CN = xen_utils_get_from_string_string_map(ctx->host_rec->other_config, "host_cn");
    /* Did not find the CN in the cache, call out to plugin */
    if (CN) {
        _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_DEBUG,("CN back from other_config = %s for host %s", CN, ctx->host));
        CMSetProperty(inst, "CN", (CMPIValue *)CN, CMPI_chars);
    } else {
        /* Get CN name by calling a plugin on the Host */
        //char *CN = NULL;
        xen_string_string_map *args = xen_string_string_map_alloc(0);
        xen_host_call_plugin(resource->session->xen, &CN, ctx->host, "xscim", "read_host_cn", args);
        xen_string_string_map_free(args);
        _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_DEBUG,("CN name back from plugin = %s for host %s", CN, ctx->host));
        /* Update the other_config cache */
        xen_host_add_to_other_config(resource->session->xen, ctx->host, "host_cn", CN);
        CMSetProperty(inst, "CN", (CMPIValue *)CN, CMPI_chars);
	// Only need to free CN here because we have made the plugin call.
	// If we've taken the value from the cache it will be free'd when
	// ctx->host_rec is free'd.
        if (CN)
          free(CN);
    } 

    CMSetProperty(inst, "Caption",(CMPIValue *)"XenServer Host", CMPI_chars);
    DMTF_Dedicated dedicated = DMTF_Dedicated_Other;
    CMPIArray *arr = CMNewArray(resource->broker, 1, CMPI_uint16, NULL);
    CMSetArrayElementAt(arr, 0, (CMPIValue *)&dedicated, CMPI_uint16);
    CMSetProperty(inst, "Dedicated",(CMPIValue *)&arr, CMPI_uint16A);
    CMSetProperty(inst, "Description",(CMPIValue *)ctx->host_rec->name_description, CMPI_chars);
    CMSetProperty(inst, "ElementName",(CMPIValue *)ctx->host_rec->name_label, CMPI_chars);
    DMTF_EnabledDefault eDefault = DMTF_EnabledDefault_Enabled;
    CMSetProperty(inst, "EnabledDefault",(CMPIValue *)&eDefault, CMPI_uint16);
    DMTF_EnabledState eState = DMTF_EnabledState_Enabled;
    if (!ctx->host_rec->enabled)
        eState = DMTF_EnabledState_Enabled_but_Offline;
    CMSetProperty(inst, "EnabledState",(CMPIValue *)&eState, CMPI_uint16);
    DMTF_HealthState hState = DMTF_HealthState_OK;
    CMSetProperty(inst, "HealthState",(CMPIValue *)&hState, CMPI_uint16);
    //CMPIDateTime *date_time = xen_utils_time_t_to_CMPIDateTime(resource->broker, <time_value>);
    //CMSetProperty(inst, "InstallDate",(CMPIValue *)&date_time, CMPI_dateTime);
    CMSetProperty(inst, "NameFormat",(CMPIValue *)DMTF_NameFormat_Other, CMPI_chars);
    DMTF_OperationalStatus opStatus = DMTF_OperationalStatus_OK;
    if (!ctx->host_rec->enabled)
        opStatus = DMTF_OperationalStatus_Stopped;
    CMPIArray *opStatusArr = CMNewArray(resource->broker, 1, CMPI_uint16, NULL);
    CMSetArrayElementAt(opStatusArr, 0, (CMPIValue *)&opStatus, CMPI_uint16);
    CMSetProperty(inst, "OperationalStatus",(CMPIValue *)&opStatusArr, CMPI_uint16A);
    //CMPIArray *arr = CMNewArray(resource->broker, 1, CMPI_chars, NULL);
    //CMSetArrayElementAt(arr, 0, (CMPIValue *)<value>, CMPI_chars);
    //CMSetProperty(inst, "OtherDedicatedDescriptions",(CMPIValue *)&arr, CMPI_charsA);
    //CMSetProperty(inst, "OtherEnabledState",(CMPIValue *)<value>, CMPI_chars);
    arr = xen_utils_convert_string_string_map_to_CMPIArray(resource->broker, ctx->host_rec->other_config);
    if(arr)
        CMSetProperty(inst, "OtherConfig",(CMPIValue *)&arr, CMPI_stringA);
    CMPIArray *otheridinfo = CMNewArray(resource->broker, 4, CMPI_chars, NULL);
    char* brand = xen_utils_get_from_string_string_map(ctx->host_rec->software_version, "product_brand");
    char* version = xen_utils_get_from_string_string_map(ctx->host_rec->software_version, "product_version");
    char* build = xen_utils_get_from_string_string_map(ctx->host_rec->software_version, "build_number");
    CMSetArrayElementAt(otheridinfo, 0, (CMPIValue *)ctx->host_rec->address, CMPI_chars);
    CMSetArrayElementAt(otheridinfo, 1, (CMPIValue *)brand, CMPI_chars);
    CMSetArrayElementAt(otheridinfo, 2, (CMPIValue *)version, CMPI_chars);
    CMSetArrayElementAt(otheridinfo, 3, (CMPIValue *)build, CMPI_chars);
    CMSetProperty(inst, "OtherIdentifyingInfo",(CMPIValue *)&otheridinfo, CMPI_charsA);
    CMPIArray *iddesc = CMNewArray(resource->broker, 4, CMPI_chars, NULL);
    CMSetArrayElementAt(iddesc, 0, (CMPIValue *)"IPv4Address", CMPI_chars);
    CMSetArrayElementAt(iddesc, 1, (CMPIValue *)"ProductBrand", CMPI_chars);
    CMSetArrayElementAt(iddesc, 2, (CMPIValue *)"ProductVersion", CMPI_chars);
    CMSetArrayElementAt(iddesc, 3, (CMPIValue *)"BuildNumber", CMPI_chars);
    CMSetProperty(inst, "IdentifyingDescriptions",(CMPIValue *)&iddesc, CMPI_charsA);

    //CMPIArray *arr = CMNewArray(resource->broker, 1, CMPI_uint16, NULL);
    //CMSetArrayElementAt(arr, 0, (CMPIValue *)&<value>, CMPI_uint16);
    //CMSetProperty(inst, "PowerManagementCapabilities",(CMPIValue *)&arr, CMPI_uint16A);
    char *owner = xen_utils_get_from_string_string_map(ctx->host_rec->other_config, "owner");
    char *ownercontact = xen_utils_get_from_string_string_map(ctx->host_rec->other_config, "ownercontact");
    if (owner)
        CMSetProperty(inst, "PrimaryOwnerName",(CMPIValue *)owner, CMPI_chars);
    if (ownercontact)
        CMSetProperty(inst, "PrimaryOwnerContact",(CMPIValue *)ownercontact, CMPI_chars);
    DMTF_RequestedState rState = DMTF_RequestedState_Enabled;

    CMSetProperty(inst, "RequestedState",(CMPIValue *)&rState, CMPI_uint16);
    //CMSetProperty(inst, "ResetCapability",(CMPIValue *)&<value>, CMPI_uint16);
    char *serverrole = xen_utils_get_from_string_string_map(ctx->host_rec->other_config, "role");
    if (serverrole) {
        CMPIArray *rolesarr = CMNewArray(resource->broker, 1, CMPI_chars, NULL);
        CMSetArrayElementAt(rolesarr, 0, (CMPIValue *)serverrole, CMPI_chars);
        CMSetProperty(inst, "Roles",(CMPIValue *)&rolesarr, CMPI_charsA);
    }

    if (ctx->host_rec->other_config) {
        char *val = xen_utils_get_from_string_string_map(ctx->host_rec->other_config, "boot_time");
        if (val) {
            time_t time = atol(val);
            CMPIDateTime *start_time = xen_utils_time_t_to_CMPIDateTime(resource->broker, time);
            if (start_time) CMSetProperty(inst, "StartTime",(CMPIValue *)&start_time, CMPI_dateTime);
        }
    }
    CMSetProperty(inst, "Status",(CMPIValue *)DMTF_Status_OK, CMPI_chars);
    //CMPIArray *arr = CMNewArray(resource->broker, 1, CMPI_chars, NULL);
    //CMSetArrayElementAt(arr, 0, (CMPIValue *)<value>, CMPI_chars);
    //CMSetProperty(inst, "StatusDescriptions",(CMPIValue *)&arr, CMPI_charsA);
    if (metrics_rec && (metrics_rec->last_updated != 0)) {
        CMPIDateTime *install_time = xen_utils_time_t_to_CMPIDateTime(resource->broker, metrics_rec->last_updated);
        CMSetProperty(inst, "TimeOfLastStateChange",(CMPIValue *)&install_time, CMPI_dateTime);
    }

    /* properties to indicate hosts's time zone. We compute local time zone on this 
    host and assume all hosts are in the same zone since xapi doest report the time zone at this time */
    time_t now = time(NULL);
    struct tm tmnow;
    localtime_r(&now, &tmnow);
    CMSetProperty(inst, "TimeOffset", (CMPIValue *)&tmnow.tm_gmtoff, CMPI_sint32);

    if (metrics_rec)
        xen_host_metrics_record_free(metrics_rec);
    return CMPI_RC_OK;
}
Ejemplo n.º 7
0
/******************************************************************************
* disk_rasd_to_vbd
*
* This function attempts to parse a Xen_Disk CIM instance and populate a new
* VBD record. It also gets the record to the VDI that the VBD attaches to (could
* be a newly created VDI, if requested) and a handle to an existing SR as
* pointed to by the PoolID field in the CIM instance
*
* Returns 1 on Success and 0 on failure.
*******************************************************************************/
int disk_rasd_to_vbd(
    const CMPIBroker *broker,
    xen_utils_session* session,
    CMPIInstance *disk_rasd,
    xen_vbd_record **vbd_rec,
    xen_vdi_record **vdi_rec,
    xen_sr  *sr,
    CMPIStatus *status)
{
    CMPIData propertyvalue;
    char *error_msg = "ERROR: Unknown error";
    char *sr_label = NULL, *vdi_name_label = NULL, *vdi_name_desc = NULL;
    char *vbd_device = NULL, *vbd_uuid = NULL, *vdi_uuid = NULL;
    enum xen_vbd_type vbd_type = XEN_VBD_TYPE_DISK; /* default with Disk (as opposed to CDRom) */
    enum xen_vdi_type vdi_type = XEN_VDI_TYPE_USER;
    bool vbd_readonly = false, vbd_bootable = false;/* defaults for Disk type */
    int vbd_mode= XEN_VBD_MODE_RW;                  /* defaults for Disk type */
    int64_t disk_size = -1;                         /* for CDRoms - this is the size expected */
    char buf[MAX_INSTANCEID_LEN];

    *vbd_rec  = NULL;
    *vdi_rec  = NULL;

    /* only resource types of 15,16 and 19 are currently supported */
    int rc = CMPI_RC_ERR_INVALID_PARAMETER;
    propertyvalue = CMGetProperty(disk_rasd, "ResourceType", status);
    if ((status->rc != CMPI_RC_OK) || CMIsNullValue(propertyvalue)) {
        error_msg = "ERROR: Xen_DiskSettingData has no ResourceType";
        goto Error;
    }
    int res_type = propertyvalue.value.uint16;
    if ((res_type == DMTF_ResourceType_CD_Drive) || (res_type == DMTF_ResourceType_DVD_drive)) {
        vbd_mode = XEN_VBD_MODE_RO;
        vbd_type = XEN_VBD_TYPE_CD;
    }
    else if ((res_type == DMTF_ResourceType_Storage_Extent) || (res_type == DMTF_ResourceType_Disk_Drive))
        vbd_type = XEN_VBD_TYPE_DISK;
    else {
        error_msg = "ERROR: Xen_DiskSettingData has unsupported ResourceType";
        goto Error;
    }

    /* Get the instance ID which has the device's UUID in it, if its available
      This will be usd during deletes and not used during create*/
    propertyvalue = CMGetProperty(disk_rasd, "InstanceID", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue)) {
        _CMPIStrncpyDeviceNameFromID(buf, CMGetCharPtr(propertyvalue.value.string),
            sizeof(buf)/sizeof(buf[0]));
        vbd_uuid = strdup(buf);
    }

    /* The HostResource property is used to identify the VDI, if available */
    propertyvalue = CMGetProperty(disk_rasd, "HostResource", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue)) {
        /* HostResource is always in WBEM URI format and it points to a 
          Xen_DiskImage object reference. Convert it to CMPIObjectPath */
        CMPIData data = CMGetArrayElementAt(propertyvalue.value.array, 0, NULL);
        CMPIObjectPath *obj_path = xen_utils_WBEM_URI_to_CMPIObjectPath(
                                       broker, 
                                       CMGetCharPtr(data.value.string));
        if (obj_path) {
            /* this should be a Xen_DiskImage object reference */
            /* Get the DeviceID key */
            propertyvalue = CMGetKey(obj_path, "DeviceID", status);
            if ((status->rc == CMPI_RC_OK) && 
                !CMIsNullValue(propertyvalue) && 
                propertyvalue.type == CMPI_string) {
                memset(buf, 0, sizeof(buf));
                _CMPIStrncpyDeviceNameFromID(buf, CMGetCharPtr(propertyvalue.value.string),
                                             sizeof(buf)/sizeof(buf[0]));
                vdi_uuid = strdup(buf);
            }
        }
    }
    if (!vdi_uuid) {
        /* second chance, Try the HostExtentName */
        propertyvalue = CMGetProperty(disk_rasd, "HostExtentName", status);
        if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue))
            vdi_uuid = strdup(CMGetCharPtr(propertyvalue.value.string));
    }
    /* Device is specified as the address on the host bus */
    propertyvalue = CMGetProperty(disk_rasd, "AddressOnParent", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue))
        vbd_device = strdup(CMGetCharPtr(propertyvalue.value.string));

    propertyvalue = CMGetProperty(disk_rasd, "Bootable", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue))
        vbd_bootable = propertyvalue.value.boolean;

    propertyvalue = CMGetProperty(disk_rasd, "Access", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue)) {
        if (propertyvalue.value.uint16 == Access_Readable)
            vbd_mode = XEN_VBD_MODE_RO;
    }

    /*
    * The Pool ID property is used to identify the Xen SR
    * This could be NULL if VDIs are reused or if
    * the VBD has to be created on the default SR.
    */
    propertyvalue = CMGetProperty(disk_rasd, "PoolID", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue)) {
        char *poolid = CMGetCharPtr(propertyvalue.value.string);
        if (poolid && (*poolid != '\0'))
            sr_label = strdup(poolid);
    }

    propertyvalue = CMGetProperty(disk_rasd, "ElementName", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue))
        vdi_name_label = strdup(CMGetCharPtr(propertyvalue.value.string));

    propertyvalue = CMGetProperty(disk_rasd, "Description", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue))
        vdi_name_desc = strdup(CMGetCharPtr(propertyvalue.value.string));

    /* Get the disk size from the CIM instance -
    * If this is a new disk, this property is required
    * If we are instantiating a CDRom VDI, this is not required */
    int64_t multiplier = 1; /* default to bytes */
    propertyvalue = CMGetProperty(disk_rasd, "AllocationUnits", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue)) {
        char *units = CMGetCharPtr(propertyvalue.value.string);
        if ((multiplier = xen_utils_get_alloc_units(units)) == 0) {
            error_msg = "ERROR: Xen_DiskSettingData has unsupported AllocationUnits";
            goto Error;
        }
    }

    /* Limit and VirtualQuantity properties mean the same when we create the VBD */
    propertyvalue = CMGetProperty(disk_rasd, "VirtualQuantity", status);
    if ((status->rc == CMPI_RC_OK) && !CMIsNullValue(propertyvalue))
        disk_size = (propertyvalue.value.uint64) * multiplier;

    if (vbd_type == XEN_VBD_TYPE_CD)
        vdi_type = XEN_VDI_TYPE_USER;

    /* We have enough information... create the Xen device records so we can */
    /* create new devices or identify existing ones */
    /* Create the VDI device record */
    rc = CMPI_RC_ERR_FAILED;
    *vdi_rec = xen_vdi_record_alloc();
    if (*vdi_rec == NULL) {
        error_msg = "ERROR: Unable to malloc memory";
        goto Error;
    }

    (*vdi_rec)->virtual_size  = disk_size;
#if OSS_XENAPI
    (*vdi_rec)->other_config  = xen_string_string_map_alloc(0);
    vdi_location = "";
    (*vdi_rec)->other_config->contents[0].key= strdup("location");
    (*vdi_rec)->other_config->contents[0].val = strdup(vdi_location);
    (*vdi_rec)->other_config->size = 1;
#else
    (*vdi_rec)->other_config  = xen_string_string_map_alloc(0);
    (*vdi_rec)->other_config->size = 0;
#endif
    (*vdi_rec)->type          = vdi_type;
    (*vdi_rec)->read_only     = vbd_readonly;
    (*vdi_rec)->name_label    = vdi_name_label;
    (*vdi_rec)->name_description = vdi_name_desc;

#if XENAPI_VERSION > 400
    (*vdi_rec)->managed = true;
#endif

    /* If VDI has already been created, use it */
    if (vdi_uuid) {
        _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_INFO, ("VDI specified in the RASD: -%s-", vdi_uuid));
        (*vdi_rec)->uuid = vdi_uuid;
    }

    /* create the VBD record */
    *vbd_rec = xen_vbd_record_alloc();
    if (*vbd_rec == NULL) {
        error_msg = "ERROR: Unable to malloc memory";
        goto Error;
    }

    if (vbd_uuid)
        (*vbd_rec)->uuid = vbd_uuid;

#if XENAPI_VERSION > 400
    if (vbd_device)
        (*vbd_rec)->userdevice = vbd_device;
    (*vbd_rec)->other_config = xen_string_string_map_alloc(0);
#endif
    (*vbd_rec)->bootable = vbd_bootable;
    (*vbd_rec)->mode = vbd_mode;
    (*vbd_rec)->type = vbd_type;
    (*vbd_rec)->qos_algorithm_params = xen_string_string_map_alloc(0);

    if (vbd_type == XEN_VBD_TYPE_CD)
        (*vdi_rec)->sharable = true;
    else
        (*vdi_rec)->sharable = false;

    /* Identify the Storage Repository where this VDI will be created (if its being created) */
    if (sr_label) {
        if (!_get_sr(broker, session, sr_label, true, sr, status)) {
            _SBLIM_TRACE(_SBLIM_TRACE_LEVEL_ERROR,
                ("--- getting SR for %s failed", sr_label));
            goto Error;
        }
        free(sr_label);
    }
    return 1;

    Error:
    if (sr_label)
        free(sr_label);
    if (vdi_name_label) {
        free(vdi_name_label);
        if (*vdi_rec)
            (*vdi_rec)->name_label = NULL;
    }
    if(vdi_name_desc) {
        free(vdi_name_desc);
    }
    if(vbd_device) {
        free(vbd_device);
    }
    if(vbd_uuid) {
        free(vbd_uuid);
    }

    /* frees fields as well */
    if (*vbd_rec) {
        xen_vbd_record_free(*vbd_rec);
        *vbd_rec = NULL;
    }
    if (*vdi_rec) {
        xen_vdi_record_free(*vdi_rec);
        *vdi_rec = NULL;
    }
    xen_utils_set_status(broker, status, rc, error_msg, session->xen);
    return 0;
}
int main(int argc, char **argv)
{

    if (argc != 6)
    {
        usage();
    }

    url = argv[1];
    char *username = argv[2];
    char *password = argv[3];
    
    source_url = argv[4];
    target_url = argv[5];

    xmlInitParser();
    xmlKeepBlanksDefault(0);
    xen_init();
    curl_global_init(CURL_GLOBAL_ALL);

#define CLEANUP                                 \
    do {                                        \
        xen_session_logout(session);            \
        curl_global_cleanup();                  \
        xen_fini();                             \
        xmlCleanupParser();                     \
    } while(0)                                  \

    
    xen_session *session =
        xen_session_login_with_password(call_func, NULL, username, password,
                                        xen_api_latest_version);

    printf("\n\nQuerying host...\n");
    xen_host host;
    if (!xen_session_get_this_host(session, &host, session))
    {
        print_error(session);
        CLEANUP;
        return 1;
    }
    
    /* Read in the source host and target host using their name labels
     */
    xen_host_set *source_hosts;
    
    int rc = 0;
 
    rc = get_host_names(session, &source_hosts, source_url );
    if (rc !=0 )
    {
        fprintf(stderr, "source host lookup failed.\n");
	print_error(session);
        return 1;
    }
    
    
    xen_host_set *target_hosts;
    rc = 0;
    rc = get_host_names(session, &target_hosts, target_url );
    if (rc !=0 )
    {
        fprintf(stderr, "target host lookup failed.\n");
	print_error(session);
        return 1;
    }
    
            
    struct xen_vm_set *all_vms_in_pool;
    xen_vm_get_all(session, &all_vms_in_pool);
    
    
    bool *vm_to_be_migrated = calloc(all_vms_in_pool->size, sizeof(bool));
    int num_vms_to_migrate = 0;
    enum xen_task_status_type task_status;
   
    xen_vm_record* result;
    
    for (size_t i = 0; i < all_vms_in_pool->size; i++ )
    {
        xen_vm a_vm = all_vms_in_pool->contents[i];
        xen_vm_get_record(session, &result, a_vm);
        
        /*
         * we can only migrate VMs that are
         * -not templates 
         * -not control domains
         * -and are running 
         * 
         * resident_on is used to identify the eligible VMs on the user
         * requested source_host 
         */
        
        if ( !result->is_a_template 
              && !result->is_control_domain
              && (result->power_state ==  XEN_VM_POWER_STATE_RUNNING)
              && (strcmp(result->resident_on->u.handle, 
                         (char*)source_hosts->contents[0]) == 0) )
        {
            // flag this VM as one suitable to migrate
            vm_to_be_migrated[i] = true;
            num_vms_to_migrate++; 
        }
        else 
        {
            vm_to_be_migrated[i] = false;
        }
    }
   
    
    if (!session->ok)
    {
        /* Error has been logged, just clean up. */
        xen_host_set_free(source_hosts);
        xen_host_set_free(target_hosts);
        xen_vm_set_free(all_vms_in_pool);       
        xen_vm_record_free(result);
        free(vm_to_be_migrated);
        CLEANUP;
        return 1;
    }

    xen_task* task_list = calloc(num_vms_to_migrate, sizeof(xen_task));
    xen_string_string_map* options = xen_string_string_map_alloc(0);    
    xen_string_set *error_msgs = NULL;
    
    int idx = 0;
    for (size_t i = 0; i < all_vms_in_pool->size; i++ )
    {
     
        if (vm_to_be_migrated[i] == true)
        {
            xen_vm_pool_migrate_async(session, &task_list[idx], all_vms_in_pool->contents[i], 
                                        target_hosts->contents[0], options );
            
            idx++;
            printf(" Migrating VM %zd \n", i);
        }
    
    }
    
    // time out after certain number of iterations
    int max_iter = 50; 
    int iter = 0;
    int pause_interval_secs = 4;
    int tasks_running = 0;
    int tasks_completed = 0;
    xen_task a_task;
    bool tasks_still_pending = true;

    /* Poll how many of the migration tasks have completed. 
     * 
     * The task querying below isn't is intended to provide a sample of useful 
     * syntax. In practice a user would probably consider using functions such 
     * as xen_task_cancel or indeed the asynchronous equivalent 
     * xen_task_cancel_async.
     * These functions and other task handling ones are defined in xen_task.c
     */
    
    while ( iter < max_iter && tasks_still_pending )
    {
        tasks_running = 0;
        tasks_completed = 0;
        for (int j = 0; j < num_vms_to_migrate; j++)
        {
            a_task = task_list[j];
           
            xen_task_get_status(session, &task_status, a_task);
            
            if (task_status == XEN_TASK_STATUS_TYPE_PENDING)
            {
                tasks_running++;
            }
            else
            {
                /* See the xen_task_status_type enum definitions
                 * defined in xen_task_status_type.h a task can have
                 * failed, or be cancelled or in the process of being cancelled
                 * amongst others.
                 * The definition of tasks_completed in this context is tasks
                 * not pending.
                 */
                           
                if (task_status == XEN_TASK_STATUS_TYPE_FAILURE)
                {
                    if (xen_task_get_error_info(session, &error_msgs, task_list[j] ))
                    {
                        /* VMs may need to meet certain criteria for migration to be 
                         * possible between hosts; such as shared storage between
                         * hosts. It is advisable to check the criteria needed for 
                         * migration on the particular version of XenServer. 
                         * The error messages output below should give information
                         * that allows the identification of an unsupported
                         * operation
                         */
                        printf("-------------------------------------\n");
                        printf("Failed while trying to migrate VM: \n");
                        for(size_t k=0; k<error_msgs->size; k++)
                        {
                            printf("error_msg %zu : %s \n",  k, error_msgs->contents[k]); 
                        }
                    }
                }
                
                tasks_completed++;
            }

        }

        if (tasks_running == 0) 
        {
            tasks_still_pending = false; // stop the iteration early
            printf("All tasks completed \n");
        }
        printf("*********************************************\n");
        printf("VM migration progress, poll number %d \n", iter);
        printf("----------------------------------------\n");
        printf(" Tasks pending : %d \n", tasks_running);
        printf("       ended   : %d \n", tasks_completed);
        printf("*********************************************\n");    
        
        iter++;
        sleep(pause_interval_secs); 
        
    }
    

    xen_string_set_free(error_msgs);
    xen_string_string_map_free(options);
    xen_host_set_free(source_hosts);
    xen_host_set_free(target_hosts);
    free(task_list);
    free(vm_to_be_migrated);
    xen_vm_set_free(all_vms_in_pool);
    
    CLEANUP;
}