//!
//! 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);
}
Exemple #2
0
//!
//! 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);
}
Exemple #4
0
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);
}