//! //! given path=A/B/C and only A existing, create A/B and, unless //! is_file_path==1, also create A/B/C directory //! //! @param[in] path //! @param[in] is_file_path //! @param[in] user //! @param[in] group //! @param[in] mode //! //! @return 0 = path already existed, 1 = created OK, -1 = error //! int ensure_directories_exist(const char *path, int is_file_path, const char *user, const char *group, mode_t mode) { int ret = 0; int i = 0; int len = strlen(path); int try_dir = 0; char *path_copy = NULL; struct stat buf = { 0 }; if (len > 0) path_copy = strdup(path); if (path_copy == NULL) return (-1); for (i = 0; i < len; i++) { try_dir = 0; if ((path[i] == '/') && (i > 0)) { // dir path, not root path_copy[i] = '\0'; try_dir = 1; } else if ((path[i] != '/') && ((i + 1) == len)) { // last one if (!is_file_path) try_dir = 1; } if (try_dir) { if (stat(path_copy, &buf) == -1) { LOGINFO("creating path %s\n", path_copy); if (mkdir(path_copy, mode) == -1) { LOGERROR("failed to create path %s: %s\n", path_copy, strerror(errno)); EUCA_FREE(path_copy); return (-1); } ret = 1; // we created a directory if (diskutil_ch(path_copy, user, group, mode) != EUCA_OK) { LOGERROR("failed to change perms on path %s\n", path_copy); EUCA_FREE(path_copy); return (-1); } } path_copy[i] = '/'; // restore the slash } } EUCA_FREE(path_copy); return (ret); }
//! //! Handles the console output retrieval request. //! //! @param[in] nc a pointer to the NC state structure to initialize //! @param[in] pMeta a pointer to the node controller (NC) metadata structure //! @param[in] instanceId the instance identifier string (i-XXXXXXXX) //! @param[out] consoleOutput a pointer to the unallocated string that will contain the output //! //! @return EUCA_OK on success or EUCA_ERROR and EUCA_NOT_FOUND_ERROR on failure. //! static int doGetConsoleOutput(struct nc_state_t *nc, ncMetadata * pMeta, char *instanceId, char **consoleOutput) { int rc = 0; int fd = 0; int ret = EUCA_OK; int readsize = 0; char *console_output = NULL; char *console_append = NULL; char *console_main = NULL; char console_file[MAX_PATH] = ""; char userId[48] = ""; ncInstance *instance = NULL; struct stat statbuf = { 0 }; *consoleOutput = NULL; readsize = 64 * 1024; // find the instance record sem_p(inst_sem); { if ((instance = find_instance(&global_instances, instanceId)) != NULL) { snprintf(console_file, 1024, "%s/console.append.log", instance->instancePath); snprintf(userId, 48, "%s", instance->userId); } } sem_v(inst_sem); if (!instance) { logprintfl(EUCAERROR, "[%s] cannot locate instance\n", instanceId); return (EUCA_NOT_FOUND_ERROR); } // read from console.append.log if it exists into dynamically allocated 4K console_append buffer if ((rc = stat(console_file, &statbuf)) >= 0) { if (diskutil_ch(console_file, nc->admin_user_id, nc->admin_user_id, 0) != EUCA_OK) { logprintfl(EUCAERROR, "[%s] failed to change ownership of %s\n", instanceId, console_file); return (EUCA_ERROR); } if ((fd = open(console_file, O_RDONLY)) >= 0) { if ((console_append = EUCA_ZALLOC(4096, sizeof(char))) != NULL) { rc = read(fd, console_append, (4096) - 1); } close(fd); } } sem_p(inst_sem); { snprintf(console_file, MAX_PATH, "%s/console.log", instance->instancePath); } sem_v(inst_sem); // read the last 64K from console.log or the whole file, if smaller, into dynamically allocated 64K console_main buffer if ((rc = stat(console_file, &statbuf)) >= 0) { if (diskutil_ch(console_file, nc->admin_user_id, nc->admin_user_id, 0) != EUCA_OK) { logprintfl(EUCAERROR, "[%s] failed to change ownership of %s\n", instanceId, console_file); EUCA_FREE(console_append); return (EUCA_ERROR); } if ((fd = open(console_file, O_RDONLY)) >= 0) { if ((rc = lseek(fd, (off_t) (-1 * readsize), SEEK_END)) < 0) { if ((rc = lseek(fd, (off_t) 0, SEEK_SET)) < 0) { logprintfl(EUCAERROR, "[%s] cannot seek to beginning of file\n", instanceId); if (console_append) EUCA_FREE(console_append); close(fd); return (EUCA_ERROR); } } if ((console_main = EUCA_ZALLOC(readsize, sizeof(char))) != NULL) { rc = read(fd, console_main, (readsize) - 1); } close(fd); } else { logprintfl(EUCAERROR, "[%s] cannot open '%s' read-only\n", instanceId, console_file); } } else { logprintfl(EUCAERROR, "[%s] cannot stat console_output file '%s'\n", instanceId, console_file); } // concatenate console_append with console_main, base64-encode this, and put into dynamically allocated buffer consoleOutput ret = EUCA_ERROR; if ((console_output = EUCA_ZALLOC((readsize) + 4096, sizeof(char))) != NULL) { if (console_append) { strncat(console_output, console_append, 4096); } if (console_main) { strncat(console_output, console_main, readsize); } *consoleOutput = base64_enc((unsigned char *)console_output, strlen(console_output)); ret = EUCA_OK; } EUCA_FREE(console_append); EUCA_FREE(console_main); EUCA_FREE(console_output); return (ret); }
//! //! Destroy the backing store for a given instance //! //! @param[in] instance the instance identifier for which we will destroy the backing store //! @param[in] do_destroy_files set to TRUE if we need to destroy the content otherwise set to FALSE. //! //! @return EUCA_OK on success //! //! @pre The instance parameter must not be NULL and do_destroy_files must be a valid boolean. //! //! @note //! int destroy_instance_backing(ncInstance * instance, boolean do_destroy_files) { int i = 0; int ret = EUCA_OK; char path[EUCA_MAX_PATH] = ""; char work_regex[1024] = ""; // {userId}/{instanceId}/.* char scURL[512] = ""; ncVolume *volume = NULL; virtualMachine *vm = &(instance->params); virtualBootRecord *vbr = NULL; if (get_localhost_sc_url(scURL) != EUCA_OK || strlen(scURL) == 0) { LOGWARN("[%s] could not obtain SC URL (is SC enabled?)\n", instance->instanceId); scURL[0] = '\0'; } // find and detach iSCSI targets, if any for (i = 0; ((i < EUCA_MAX_VBRS) && (i < vm->virtualBootRecordLen)); i++) { vbr = &(vm->virtualBootRecord[i]); if (vbr->locationType == NC_LOCATION_SC) { if (disconnect_ebs_volume (scURL, localhost_config.use_ws_sec, localhost_config.ws_sec_policy_file, vbr->resourceLocation, vbr->preparedResourceLocation, localhost_config.ip, localhost_config.iqn) != 0) { LOGERROR("[%s] failed to disconnect volume attached to '%s'\n", instance->instanceId, vbr->backingPath); } } } // there may be iSCSI targets for volumes if instance disappeared or was migrated for (i = 0; i < EUCA_MAX_VOLUMES; ++i) { ncVolume *volume = &instance->volumes[i]; if (!is_volume_used(volume)) continue; if (disconnect_ebs_volume (scURL, localhost_config.use_ws_sec, localhost_config.ws_sec_policy_file, volume->attachmentToken, volume->connectionString, localhost_config.ip, localhost_config.iqn) != 0) { LOGERROR("[%s][%s] failed to disconnect volume\n", instance->instanceId, volume->volumeId); } } // see if instance directory is there (sometimes startup fails before it is created) set_path(path, sizeof(path), instance, NULL); if (check_path(path)) return (ret); // to ensure that we are able to delete all blobs, we chown files back to 'eucalyptus' // (e.g., libvirt on KVM on Maverick chowns them to libvirt-qemu while // VM is running and then chowns them to root after termination) { DIR *dir = NULL; if ((dir = opendir(path)) == NULL) { return (-1); } struct dirent *dir_entry; while ((dir_entry = readdir(dir)) != NULL) { char *entry_name = dir_entry->d_name; if (!strcmp(".", entry_name) || !strcmp("..", entry_name)) continue; // get the path of the directory item char entry_path[BLOBSTORE_MAX_PATH]; snprintf(entry_path, sizeof(entry_path), "%s/%s", path, entry_name); if (diskutil_ch(entry_path, EUCALYPTUS_ADMIN, NULL, BACKING_FILE_PERM)) { LOGWARN("[%s] failed to chown files before cleanup\n", instance->instanceId); } } closedir(dir); } if (do_destroy_files) { set_id2(instance, "/.*", work_regex, sizeof(work_regex)); if (blobstore_delete_regex(work_bs, work_regex) == -1) { LOGERROR("[%s] failed to remove some artifacts in %s\n", instance->instanceId, path); } for (i = 0; i < EUCA_MAX_VOLUMES; ++i) { volume = &instance->volumes[i]; snprintf(path, sizeof(path), EUCALYPTUS_VOLUME_XML_PATH_FORMAT, instance->instancePath, volume->volumeId); unlink(path); } // delete all non-blob files in the directory if (blobstore_delete_nonblobs(work_bs, instance->instancePath) < 0) { LOGWARN("[%s] failed to delete some non-blob files under %s\n", instance->instanceId, instance->instancePath); } } // Finally try to remove the directory. If either the user or our code introduced // any new files, this last step will fail. set_path(path, sizeof(path), instance, NULL); if (rmdir(path) && do_destroy_files) { LOGWARN("[%s] failed to remove backing directory %s\n", instance->instanceId, path); } return (ret); }
int destroy_instance_backing (ncInstance * instance, int do_destroy_files) { int ret = OK; int total_prereqs = 0; char path [MAX_PATH]; virtualMachine * vm = &(instance->params); // find and detach iSCSI targets, if any for (int i=0; i<EUCA_MAX_VBRS && i<vm->virtualBootRecordLen; i++) { virtualBootRecord * vbr = &(vm->virtualBootRecord[i]); if (vbr->locationType==NC_LOCATION_IQN) { if (disconnect_iscsi_target (vbr->resourceLocation)) { logprintfl(EUCAERROR, "[%s] error: failed to disconnect iSCSI target attached to %s\n", instance->instanceId, vbr->backingPath); } } } // see if instance directory is there (sometimes startup fails before it is created) set_path (path, sizeof (path), instance, NULL); if (check_path (path)) return ret; // to ensure that we are able to delete all blobs, we chown files back to 'eucalyptus' // (e.g., libvirt on KVM on Maverick chowns them to libvirt-qemu while // VM is running and then chowns them to root after termination) set_path (path, sizeof (path), instance, "*"); if (diskutil_ch (path, EUCALYPTUS_ADMIN, NULL, BACKING_FILE_PERM)) { logprintfl (EUCAWARN, "[%s] error: failed to chown files before cleanup\n", instance->instanceId); } if (do_destroy_files) { char work_regex [1024]; // {userId}/{instanceId}/.* set_id2 (instance, "/.*", work_regex, sizeof (work_regex)); if (blobstore_delete_regex (work_bs, work_regex) == -1) { logprintfl (EUCAERROR, "[%s] error: failed to remove some artifacts in %s\n", instance->instanceId, path); } // remove the known leftover files unlink (instance->xmlFilePath); unlink (instance->libvirtFilePath); unlink (instance->consoleFilePath); if (strlen (instance->floppyFilePath)) { unlink (instance->floppyFilePath); } set_path (path, sizeof (path), instance, "instance.checkpoint"); unlink (path); for (int i=0; i < EUCA_MAX_VOLUMES; ++i) { ncVolume * volume = &instance->volumes[i]; snprintf (path, sizeof (path), EUCALYPTUS_VOLUME_XML_PATH_FORMAT, instance->instancePath, volume->volumeId); unlink (path); } // bundle instance will leave additional files // let's delete every file in the directory struct dirent **files; int n = scandir(instance->instancePath, &files, 0, alphasort); char toDelete[MAX_PATH]; if (n>0){ while (n--) { struct dirent *entry = files[n]; if( entry !=NULL && strncmp(entry->d_name, ".",1)!=0 && strncmp(entry->d_name, "..", 2)!=0){ snprintf(toDelete, MAX_PATH, "%s/%s", instance->instancePath, entry->d_name); unlink(toDelete); free(entry); } } free(files); } } // Finally try to remove the directory. // If either the user or our code introduced // any new files, this last step will fail. set_path (path, sizeof (path), instance, NULL); if (rmdir (path) && do_destroy_files) { logprintfl (EUCAWARN, "[%s] warning: failed to remove backing directory %s\n", instance->instanceId, path); } return ret; }
static int doGetConsoleOutput( struct nc_state_t *nc, ncMetadata *meta, char *instanceId, char **consoleOutput) { char *console_output=NULL, *console_append=NULL, *console_main=NULL; char console_file[MAX_PATH], userId[48]; int rc, fd, ret, readsize; struct stat statbuf; ncInstance *instance=NULL; *consoleOutput = NULL; readsize = 64 * 1024; // find the instance record sem_p (inst_sem); instance = find_instance(&global_instances, instanceId); if (instance) { snprintf(console_file, 1024, "%s/console.append.log", instance->instancePath); snprintf(userId, 48, "%s", instance->userId); } sem_v (inst_sem); if (!instance) { logprintfl(EUCAERROR, "doGetConsoleOutput(): cannot locate instance with instanceId=%s\n", instanceId); return(1); } // read from console.append.log if it exists into dynamically allocated 4K console_append buffer rc = stat(console_file, &statbuf); if (rc >= 0) { if (diskutil_ch (console_file, nc->admin_user_id, nc->admin_user_id, 0) != OK) { logprintfl (EUCAERROR, "doGetConsoleOutput(): failed to change ownership of %s\n", console_file); return (1); } fd = open(console_file, O_RDONLY); if (fd >= 0) { console_append = malloc(4096); if (console_append) { bzero(console_append, 4096); rc = read(fd, console_append, (4096)-1); close(fd); } } } sem_p (inst_sem); snprintf(console_file, MAX_PATH, "%s/console.log", instance->instancePath); sem_v (inst_sem); // read the last 64K from console.log or the whole file, if smaller, into dynamically allocated 64K console_main buffer rc = stat(console_file, &statbuf); if (rc >= 0) { if (diskutil_ch (console_file, nc->admin_user_id, nc->admin_user_id, 0) != OK) { logprintfl (EUCAERROR, "doGetConsoleOutput(): failed to change ownership of %s\n", console_file); if (console_append) free(console_append); return (1); } fd = open(console_file, O_RDONLY); if (fd >= 0) { rc = lseek(fd, (off_t)(-1 * readsize), SEEK_END); if (rc < 0) { rc = lseek(fd, (off_t)0, SEEK_SET); if (rc < 0) { logprintfl(EUCAERROR, "cannot seek to beginning of file\n"); if (console_append) free(console_append); close(fd); return(1); } } console_main = malloc(readsize); if (console_main) { bzero(console_main, readsize); rc = read(fd, console_main, (readsize)-1); close(fd); } } else { logprintfl(EUCAERROR, "cannot open '%s' read-only\n", console_file); } } else { logprintfl(EUCAERROR, "cannot stat console_output file '%s'\n", console_file); } // concatenate console_append with console_main, base64-encode this, and put into dynamically allocated buffer consoleOutput ret = 1; console_output = malloc( (readsize) + 4096 ); if (console_output) { bzero(console_output, (readsize) + 4096 ); if (console_append) { strncat(console_output, console_append, 4096); } if (console_main) { strncat(console_output, console_main, readsize); } *consoleOutput = base64_enc((unsigned char *)console_output, strlen(console_output)); ret = 0; } if (console_append) free(console_append); if (console_main) free(console_main); if (console_output) free(console_output); return(ret); }