Пример #1
0
// automatically generated. Do not modify
static void testVMs(xen_session *session) {
	printf("\nGet all the  VM Records\n");

	xen_vm_set *vm_set;
	bool d = xen_vm_get_all(session, &vm_set);
	if (d) {
		size_t i = 0;
		for (; i < vm_set->size; ++i) {
			xen_vm_record *vm_record;
			xen_vm_get_record(session, &vm_record, vm_set->contents[i]);
			char *handle = (char*) vm_record->handle;
			char *opaque = (char*) vm_set->contents[i];
			if (strcmp(handle, opaque) == 0)
				printf("identical: %s\n", opaque);
			else
				printf("record->handle[%s] v.s. set->contents[%d][%s]\n",
						opaque, i, handle);
			xen_vm_record_free(vm_record);
		}
	} else {
		print_error(session);
	}
	xen_vm_set_free(vm_set);

#if 0
	printf("== Get All VM Records ============================\n\n");

	xen_vm_xen_vm_record_map *result;
	bool ok = xen_vm_get_all_records(session, &result);
	if(!ok) {
		print_error(session);
	}
	size_t i=0;
	for(;i<result->size;++i) {
		xen_vm key = result->contents[i].key;
		struct xen_vm_record *val = result->contents[i].val;
		if(strcmp((char*)key, (char*)val->handle)==0) {

		} else {
			printf("%s v.s. %s", (char*)key, (char*)val->handle);
		}
		xen_vm_record_free(val);
		xen_vm_free(key);
	}
	free(result);
#endif

	printf("\n==============================================\n\n");
}
Пример #2
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;
}
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;
}