//! //! Main entry point of the application //! //! @param[in] argc the number of parameter passed on the command line //! @param[in] argv the list of arguments //! //! @return EUCA_OK on success or EUCA_ERROR on failure. //! int main(int argc, char **argv) { //char *sc_url_prefix = "sc://"; //char *sc_ur1 = "http://192.168.1.1:8773/services/Storage"; //char *sc_ur1_slash = "http://192.168.1.1:8773/services/Storage/"; //char *sc_hostname_url = "http://testhost.com:8773/services/Storage"; //char *sc_hostname_ur1_slash = "http://testhost.com:8773/services/Storage/"; char *serialized1 = "sc://vol-123ABCD,10aavaeosvas-sd-adsf-asdfa-vasdva"; char *serialized2 = "sc://vol-123ABCD,10aavaeosvas-sd-adsf-asdfa-vasdva"; ebs_volume_data test_struct1 = { "testtoken123", "vol-AB123DD" }; ebs_volume_data test_struct2 = { "1aoivlna-adflnew-aavaa0an12zc", "vol-123ABCD" }; char *output = NULL; ebs_volume_data *ebs_out = NULL; int result; printf("Testing serialization\n"); result = serialize_volume(&test_struct1, &output); printf("Got serialized output: %s\n", output); EUCA_FREE(output); result = serialize_volume(&test_struct2, &output); printf("Got serialized output: %s\n", output); EUCA_FREE(output); printf("Testing de-serialization\n"); result = deserialize_volume(serialized1, &ebs_out); printf("Input %s\n\tGot de-serialized: %s %s\n", serialized1, ebs_out->volumeId, ebs_out->token); EUCA_FREE(ebs_out); result = deserialize_volume(serialized2, &ebs_out); printf("Input %s\n\tGot de-serialized: %s %s\n", serialized2, ebs_out->volumeId, ebs_out->token); EUCA_FREE(ebs_out); //int replace_sc_url(const char * volume_string, const char * scUrl, char * restrict dest_string) /*printf("Testing url replacement\n"); char url_out1[512]; result = replace_sc_url(serialized1, "http://localhost.com:8773/services/Storage", url_out1); printf("Result string %s\n", url_out1); char url_out2[512]; result = replace_sc_url(serialized2, "http://192.168.1.1:8773/services/Storage/", url_out2); printf("Result string %s\n", url_out2); char url_out3[512]; result = replace_sc_url(serialized3, "http://localhost.com:8773/services/Storage", url_out3); printf("Result string %s\n", url_out3); */ return (0); }
//! //! Detach a local device that is iSCSI and disconnect the session. //! //! @param[in] sc_url - The URL to reach the cluster's SC at. //! @param[in] use_ws_sec - boolean to determine use of WS-SEC. //! @param[in] ws_sec_policy_file - Policy file path for WS-SEC //! @param[in] attachment_token - The volume/token string received in the request that will be used //! @param[in] connect_string - The connect string used for attachment, to be re-used on disconnect //! @param[in] local_ip - The local host's external IP //! @param[in] local_iqn - The local host's IQN //! //! @return //! //! @pre //! //! @post //! //! @note should only be invoked after detachment from the guest //! int disconnect_ebs_volume(char *sc_url, int use_ws_sec, char *ws_sec_policy_file, char *attachment_token, char *connect_string, char *local_ip, char *local_iqn) { int ret = EUCA_ERROR; int norescan = 0; //send a 0 to indicate no rescan requested ebs_volume_data *vol_data = NULL; if (attachment_token == NULL || connect_string == NULL || local_ip == NULL || local_iqn == NULL) { LOGERROR("Cannont disconnect ebs volume. Got NULL input parameters.\n"); return EUCA_ERROR; } LOGTRACE("Disconnecting an EBS volume\n"); if (deserialize_volume(attachment_token, &vol_data) != EUCA_OK) { LOGERROR("Could not deserialize attachment token string %s\n", attachment_token); return EUCA_ERROR; } LOGTRACE("Requesting volume lock\n"); sem_p(vol_sem); { LOGTRACE("Got volume lock\n"); ret = cleanup_volume_attachment(sc_url, use_ws_sec, ws_sec_policy_file, vol_data, connect_string, local_ip, local_iqn, norescan); LOGTRACE("cleanup_volume_attachment returned: %d\n", ret); LOGTRACE("Releasing volume lock\n"); } sem_v(vol_sem); LOGTRACE("Released volume lock\n"); EUCA_FREE(vol_data); return ret; }
//! //! Implement the backing store for a given instance //! //! @param[in] instance pointer to the instance //! @param[in] is_migration_dest //! //! @return EUCA_OK on success or EUCA_ERROR on failure //! //! @pre The instance parameter must not be NULL. //! //! @post //! int create_instance_backing(ncInstance * instance, boolean is_migration_dest) { int rc = 0; int ret = EUCA_ERROR; virtualMachine *vm = &(instance->params); artifact *sentinel = NULL; char work_prefix[1024] = { 0 }; // {userId}/{instanceId} char base_path[EUCA_MAX_PATH]; char user_dir_path[EUCA_MAX_PATH]; // set various instance-directory-relative paths in the instance struct set_instance_paths(instance); set_path(base_path, sizeof(base_path), NULL, NULL); snprintf(user_dir_path, sizeof(user_dir_path), "%s/%s", base_path, instance->userId); // create backing directory if ((check_path(user_dir_path) == 1) && (mkdir(user_dir_path, INSTANCE_DIRECTORY_PERM) == -1)) { LOGERROR("[%s] could not create backing directory %s\n", instance->instanceId, user_dir_path); goto out; } if (mkdir(instance->instancePath, INSTANCE_DIRECTORY_PERM) == -1) { LOGERROR("[%s] could not create backing directory %s\n", instance->instanceId, instance->instancePath); goto out; } if (strstr(instance->platform, "windows")) { // generate the floppy file for windows instances if (makeWindowsFloppy(nc_state.home, instance->instancePath, instance->keyName, instance->instanceId)) { LOGERROR("[%s] could not create windows bootup script floppy\n", instance->instanceId); goto out; } else { set_path(instance->floppyFilePath, sizeof(instance->floppyFilePath), instance, "floppy"); instance->hasFloppy = TRUE; } } else if (instance->credential && strlen(instance->credential)) { LOGDEBUG("[%s] creating floppy for instance credential\n", instance->instanceId); if (make_credential_floppy(nc_state.home, instance->instancePath, instance->credential)) { LOGERROR("[%s] could not create credential floppy\n", instance->instanceId); goto out; } else { set_path(instance->floppyFilePath, sizeof(instance->floppyFilePath), instance, "floppy"); instance->hasFloppy = TRUE; } } else if(instance->hasFloppy && is_migration_dest) { LOGDEBUG("[%s] creating blank instance credential floppy\n", instance->instanceId); char dest_path[1024] = ""; int fd = 0; snprintf(dest_path, 1024, "%s/floppy", instance->instancePath); if ((fd = open(dest_path, O_CREAT | O_TRUNC | O_RDWR, 0700)) < 0) { LOGERROR("[%s] failed to create fake floppy\n", instance->instanceId); goto out; } else { lseek(fd, 1024*2048-1, SEEK_SET); write(fd, "\n", 1); } close(fd); } else { instance->hasFloppy = FALSE; } set_id(instance, NULL, work_prefix, sizeof(work_prefix)); // compute tree of dependencies sentinel = vbr_alloc_tree(vm, // the struct containing the VBR TRUE, // make working copy of runtime-modifiable files is_migration_dest, // tree of an instance on the migration destination (instance->do_inject_key) ? (instance->keyName) : (NULL), // the SSH key &(instance->bail_flag), // flag indicating that provisioning should bail instance->instanceId); // ID is for logging if (sentinel == NULL) { LOGERROR("[%s] failed to prepare extended backing for instance\n", instance->instanceId); goto out; } sem_p(disk_sem); { // download/create/combine the dependencies rc = art_implement_tree(sentinel, work_bs, cache_bs, work_prefix, INSTANCE_PREP_TIMEOUT_USEC); } sem_v(disk_sem); if (rc != EUCA_OK) { LOGERROR("[%s] failed to implement backing for instance\n", instance->instanceId); goto out; } // copy EBS entries from VBR[] to volumes[] for (int i = 0; ((i < EUCA_MAX_VBRS) && (i < instance->params.virtualBootRecordLen)); i++) { virtualBootRecord *vbr = &(instance->params.virtualBootRecord[i]); if (vbr->locationType == NC_LOCATION_SC) { char *volumeId = vbr->id; // id is 'emi-XXXX', replace it with 'vol-XXXX' ebs_volume_data *vol_data = NULL; if (deserialize_volume(vbr->resourceLocation, &vol_data) == 0) { volumeId = vol_data->volumeId; } if (save_volume(instance, volumeId, vbr->resourceLocation, // attachmentToken vbr->preparedResourceLocation, // connect_string vbr->guestDeviceName, VOL_STATE_ATTACHED, vbr->backingPath) == NULL) { // the XML LOGERROR("[%s] failed to add record for volume %s\n", instance->instanceId, volumeId); } EUCA_FREE(vol_data); } } if (save_instance_struct(instance)) // update instance checkpoint now that the struct got updated goto out; ret = EUCA_OK; out: if (sentinel) art_free(sentinel); return (ret); }
//! //! Connects an EBS volume to the local host as an ISCSI block device. The resulting device is placed in *result_device //! //! @param[in] sc_url - The URL to reach the cluster's SC at. //! @param[in] attachment_token - The attachment token/volume string received in the attach request (or vbr) //! @param[in] use_ws_sec - Boolean to use WS-SEC on SC call. //! @param[in] ws_sec_policy_file - Policy file for WS-SEC on SC call. //! @param[in] local_ip - External IP of the local host. Will be used to send to SC for authorization //! @param[in] local_iqn - IQN of local host for sending to SC for authorization. //! @param[out] result_device - The block device that is the EBS volume connected to local host, will be populated on success. //! @param[out] vol_data - The populated ebs_volume_data struct that hold volume info (id, connect string, token, etc) //! //! @return EUCA_OK on success, EUCA_ERROR on failure. //! //! @pre //! //! @post //! //! @note //! int connect_ebs_volume(char *sc_url, char *attachment_token, int use_ws_sec, char *ws_sec_policy_file, char *local_ip, char *local_iqn, char **result_device, ebs_volume_data ** vol_data) { int ret = EUCA_OK; char *reencrypted_token = NULL; char *connect_string = NULL; char *dev = NULL; int do_rescan = 1; if (sc_url == NULL || strlen(sc_url) == 0 || attachment_token == NULL || local_ip == NULL || local_iqn == NULL) { LOGERROR("Cannont connect ebs volume. Got NULL input parameters.\n"); return EUCA_ERROR; } if (deserialize_volume(attachment_token, vol_data) != EUCA_OK || *vol_data == NULL) { LOGERROR("Failed parsing volume string %s\n", attachment_token); ret = EUCA_ERROR; return ret; } if (strlen((*vol_data)->volumeId) == 0 || (*vol_data)->token == NULL || strlen((*vol_data)->token) == 0) { LOGERROR("After deserializing volume string, still found null or empty volumeId or token"); ret = EUCA_ERROR; return ret; } LOGTRACE("Parsed volume info: volumeId=%s, encrypted token=%s\n", (*vol_data)->volumeId, (*vol_data)->token); if (re_encrypt_token((*vol_data)->token, &reencrypted_token) != EUCA_OK || reencrypted_token == NULL || strlen(reencrypted_token) <= 0) { LOGERROR("Failed on re-encryption of token for call to SC\n"); if (reencrypted_token != NULL) { EUCA_FREE(reencrypted_token); } return EUCA_ERROR; } LOGTRACE("Requesting volume lock\n"); sem_p(vol_sem); //Acquire the lock, after this, failure requires 'goto release' for release of lock LOGTRACE("Got volume lock\n"); LOGTRACE("Calling ExportVolume on SC at %s\n", sc_url); threadCorrelationId* corr_id = get_corrid(); if (scClientCall(corr_id!=NULL ? corr_id->correlation_id: NULL, NULL, use_ws_sec, ws_sec_policy_file, request_timeout_sec, sc_url, "ExportVolume", (*vol_data)->volumeId, reencrypted_token, local_ip, local_iqn, &connect_string) != EUCA_OK) { LOGERROR("Failed to get connection information for volume %s from storage controller at: %s\n", (*vol_data)->volumeId, sc_url); ret = EUCA_ERROR; goto release; } else { if (euca_strncpy((*vol_data)->connect_string, connect_string, EBS_CONNECT_STRING_MAX_LENGTH) == NULL) { LOGERROR("Failed to copy connect string from SC response: %s\n", connect_string); ret = EUCA_ERROR; goto release; } } //copy the connection info from the SC return to the resourceLocation. dev = connect_iscsi_target((*vol_data)->connect_string); if (!dev || !strstr(dev, "/dev")) { LOGERROR("Failed to connect to iSCSI target: %s\n", (*vol_data)->connect_string); //disconnect the volume if (cleanup_volume_attachment(sc_url, use_ws_sec, ws_sec_policy_file, (*vol_data), (*vol_data)->connect_string, local_ip, local_iqn, do_rescan) != EUCA_OK) { LOGTRACE("cleanup_volume_attachment returned failure on cleanup from connection failure\n"); } ret = EUCA_ERROR; goto release; } *result_device = dev; release: LOGTRACE("Releasing volume lock\n"); sem_v(vol_sem); LOGTRACE("Released volume lock\n"); if (reencrypted_token != NULL) { EUCA_FREE(reencrypted_token); } if (ret != EUCA_OK && (*vol_data) != NULL) { //Free the vol data struct too EUCA_FREE(*vol_data); } return ret; }