Ejemplo n.º 1
0
//!
//! 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}

    // set various instance-directory-relative paths in the instance struct
    set_instance_paths(instance);

    // ensure instance directory exists
    if (ensure_directories_exist(instance->instancePath, 0, NULL, "root", BACKING_DIRECTORY_PERM) == -1)
        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");
        }
    } else if (strlen(instance->instancePk) > 0) {  // TODO: credential floppy is limited to Linux instances ATM
        LOGDEBUG("[%s] creating floppy for instance credential\n", instance->instanceId);
        if (make_credential_floppy(nc_state.home, instance)) {
            LOGERROR("[%s] could not create credential floppy\n", instance->instanceId);
            goto out;
        } else {
            set_path(instance->floppyFilePath, sizeof(instance->floppyFilePath), instance, "floppy");
        }
    }

    set_id(instance, NULL, work_prefix, sizeof(work_prefix));

    // if this looks like a partition m1.small image, make it a bootable disk
    virtualMachine *vm2 = NULL;
    LOGDEBUG("vm->virtualBootRecordLen=%d\n", vm->virtualBootRecordLen);
    if (vm->virtualBootRecordLen == 5) {    // TODO: make this check more robust

        // as an experiment, construct a new VBR, without swap and ephemeral
        virtualMachine vm_copy;
        vm2 = &vm_copy;
        memcpy(vm2, vm, sizeof(virtualMachine));
        bzero(vm2->virtualBootRecord, EUCA_MAX_VBRS * sizeof(virtualBootRecord));
        vm2->virtualBootRecordLen = 0;

        virtualBootRecord *emi_vbr = NULL;
        for (int i = 0; i < EUCA_MAX_VBRS && i < vm->virtualBootRecordLen; i++) {
            virtualBootRecord *vbr = &(vm->virtualBootRecord[i]);
            if (vbr->type != NC_RESOURCE_KERNEL && vbr->type != NC_RESOURCE_RAMDISK && vbr->type != NC_RESOURCE_IMAGE)
                continue;
            if (vbr->type == NC_RESOURCE_IMAGE)
                emi_vbr = vbr;
            memcpy(vm2->virtualBootRecord + (vm2->virtualBootRecordLen++), vbr, sizeof(virtualBootRecord));
        }

        if (emi_vbr == NULL) {
            LOGERROR("[%s] failed to find EMI among VBR entries\n", instance->instanceId);
            goto out;
        }

        if (vbr_add_ascii("boot:none:104857600:ext3:sda2:none", vm2) != EUCA_OK) {
            LOGERROR("[%s] could not add a boot partition VBR entry\n", instance->instanceId);
            goto out;
        }
        if (vbr_parse(vm2, NULL) != EUCA_OK) {
            LOGERROR("[%s] could not parse the boot partition VBR entry\n", instance->instanceId);
            goto out;
        }
        // compute tree of dependencies
        sentinel = vbr_alloc_tree(vm2, // the struct containing the VBR
                                  TRUE, // we always make the disk bootable, for consistency
                                  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->instanceId);    // ID is for logging
        if (sentinel == NULL) {
            LOGERROR("[%s] failed to prepare backing for instance\n", instance->instanceId);
            goto out;
        }

        LOGDEBUG("disk size prior to tree implementation is = %lld\n", sentinel->deps[0]->size_bytes);
        long long right_disk_size = sentinel->deps[0]->size_bytes;

        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;
        }

        LOGDEBUG("[%s] created the initial bootable disk\n", instance->instanceId);

        /* option A starts */
        assert(emi_vbr);
        assert(sentinel->deps[0]);
        strcpy(emi_vbr->guestDeviceName, "sda");    // switch 'sda1' to 'sda' now that we've built the disk
        //emi_vbr->sizeBytes = sentinel->deps[0]->size_bytes; // update the size to match the disk
        emi_vbr->sizeBytes = right_disk_size;   // this is bad...
        LOGDEBUG("at boot disk creation time emi_vbr->sizeBytes = %lld\n", emi_vbr->sizeBytes);
        euca_strncpy(emi_vbr->id, sentinel->deps[0]->id, SMALL_CHAR_BUFFER_SIZE);   // change to the ID of the disk
        if (vbr_parse(vm, NULL) != EUCA_OK) {
            LOGERROR("[%s] could not parse the boot partition VBR entry\n", instance->instanceId);
            goto out;
        }
        emi_vbr->locationType = NC_LOCATION_NONE;   // i.e., it should already exist

        art_free(sentinel);
        /* option A end */

        /* option B starts *
           memcpy(vm, vm2, sizeof(virtualMachine));
           if (save_instance_struct(instance)) // update instance checkpoint now that the struct got updated
           goto out;
           ret = EUCA_OK;
           goto out;
           * option B ends */
    }
    // compute tree of dependencies
    sentinel = vbr_alloc_tree(vm,      // the struct containing the VBR
                              FALSE,   // if image had to be made bootable, that was done above
                              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->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;
    }

    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);
}
Ejemplo n.º 2
0
//!
//!
//!
//! @param[in] req
//!
//! @return EUCA_OK on success or EUCA_ERROR on failure
//!
int prepare_validate(imager_request * req)
{
    int i = 0;
    int num_sda_parts = 0;
    imager_param *p = NULL;
    prepare_params *state = NULL;

    print_req(req);

    if ((state = EUCA_ZALLOC(1, sizeof(prepare_params))) == NULL)
        err("out of memory");

    // set defaults
    state->bootable = FALSE;
    state->cache = TRUE;
    state->work = FALSE;
    state->action = ACTION_DOWNLOAD | ACTION_CONVERT;

    // record in 'state' all specified parameters
    for (p = req->params; p != NULL && p->key != NULL; p++) {
        if (strcmp(p->key, _CACHE) == 0) {
            state->cache = parse_boolean(p->val);
        } else if (strcmp(p->key, _BOOT) == 0) {
            state->bootable = parse_boolean(p->val);
        } else if (strcmp(p->key, _ID) == 0) {
            state->id = p->val;
        } else if (strcmp(p->key, _KEY) == 0) {
            state->sshkey = parse_loginpassword(p->val);
        } else if (strcmp(p->key, _OUT) == 0) {
            state->out = p->val;
        } else if (strcmp(p->key, _WORK) == 0) {
            state->work = parse_boolean(p->val);
        } else if (strcmp(p->key, _VBR) == 0) {
            if (state->total_vbrs == (EUCA_MAX_VBRS - 1))
                err("too many vbr= parameters");
            state->vbrs[state->total_vbrs++] = p->val;
            if (strstr(p->val, ":sda1:") != NULL || strstr(p->val, ":sda2:") != NULL || strstr(p->val, ":sda3:") != NULL) {
                num_sda_parts++;
            }
        } else if (strcmp(p->key, _ACTION) == 0) {
            if (strcmp(p->val, "download") == 0) {
                state->action = ACTION_DOWNLOAD;
            } else if (strcmp(p->val, "convert") == 0) {
                state->action = ACTION_CONVERT;
            } else {
                err("unknown action parameter '%s' for command 'prepare'", p->val);
            }
        } else {
            err("invalid parameter '%s' for command 'prepare'", p->key);
        }
    }

    // ensure mandatory params are present
    if (state->total_vbrs < 1)
        err("not a single VBR was specified");

    LOGINFO("actions: download=%s convert=%s\n",
            (state->action & ACTION_DOWNLOAD) ? ("yes") : ("no"),
            (state->action & ACTION_CONVERT) ? ("yes") : ("no"))

    // if a bootable disk is requested and the expected number of partitions is present,
    // then add the boot VBR entry so an extra, 4th, boot partition will get created
    if (state->bootable && num_sda_parts > 0) {
        char buf[1024];
        snprintf(buf, sizeof(buf), BOOT_VBR_FORMAT, num_sda_parts+1);
        state->vbrs[state->total_vbrs++] = strdup(buf);
    }

    for (i = 0; i < state->total_vbrs; i++) {
        if (vbr_add_ascii(state->vbrs[i], &(state->vm)))
            err("failed to add VBR record '%s'", state->vbrs[i]);
    }

    if (vbr_parse(&(state->vm), NULL) != EUCA_OK)
        err("failed to validate VBR records");

    // if given an empty key file, just set the pointer to NULL
    if (state->sshkey && strlen(state->sshkey) == 0) {
        EUCA_FREE(state->sshkey);
    }
    // save pointer to find it later
    req->internal = ((void *)state);
    return (EUCA_OK);
}