Esempio n. 1
0
//!
//!
//!
//! @param[in] key
//! @param[in] val
//!
//! @pre
//!
//! @post
//!
static void set_global_parameter(char *key, char *val)
{
    if (strcmp(key, "debug") == 0) {
        print_debug = parse_boolean(val);
        set_debug(print_debug);
    } else if (strcmp(key, "argv") == 0) {
        print_argv = parse_boolean(val);
    } else if (strcmp(key, "work") == 0) {
        set_work_dir(val);
    } else if (strcmp(key, "work_size") == 0) {
        set_work_limit(parse_bytes(val));
    } else if (strcmp(key, "cache") == 0) {
        set_cache_dir(val);
    } else if (strcmp(key, "cache_size") == 0) {
        set_cache_limit(parse_bytes(val));
    } else if (strcmp(key, "purge_cache") == 0) {
        purge_cache = parse_boolean(val);
    } else if (strcmp(key, "cloud_cert") == 0) {
        euca_strncpy(cloud_cert_path, val, sizeof(cloud_cert_path));
    } else if (strcmp(key, "service_key") == 0) {
        euca_strncpy(service_key_path, val, sizeof(service_key_path));
    } else {
        err("unknown global parameter '%s'", key);
    }
    LOGINFO("GLOBAL: %s=%s\n", key, val);
}
Esempio n. 2
0
//!
//! Sets and opens the log file
//!
//! @param[in] file the file name of the log file. A NULL value unset the file
//!
//! @return EUCA_OK on success or EUCA_ERROR on failure
//!
int log_file_set(const char *file, const char *req_track_file)
{
    if (file == NULL) {
        // NULL means standard output
        log_file_path[0] = '\0';
        log_file_path_req_track[0] = '\0';
        return (EUCA_OK);
    }

    if (strcmp(log_file_path, file) == 0) {
        ;
    } else {
        euca_strncpy(log_file_path, file, EUCA_MAX_PATH);
        if (get_file(log_file_path, TRUE) == NULL) {
            return (EUCA_ERROR);
        }
        release_file(log_file_path);
    }

    if (req_track_file == NULL || strlen(req_track_file) == 0) {
        log_file_path_req_track[0] = '\0';
        return (EUCA_OK);
    }

    if (strcmp(log_file_path_req_track, req_track_file) == 0) {
        return (EUCA_OK);
    } else {
        euca_strncpy(log_file_path_req_track, req_track_file, EUCA_MAX_PATH);
        if (get_file(log_file_path_req_track, TRUE) == NULL) {
            return (EUCA_ERROR);
        }
        release_file(log_file_path_req_track);
    }
    return (EUCA_OK);
}
Esempio n. 3
0
//!
//! Allocate and initialize a resource structure with given information. Resource is
//! used to return information about resources
//!
//! @param[in] sNodeStatus the current node status string
//! @param[in] migrationCapable flag indicating whether node can participate in live migration
//! @param[in] sIQN
//! @param[in] memorySizeMax the maximum amount of memory available on this node
//! @param[in] memorySizeAvailable the current amount of memory available on this node
//! @param[in] diskSizeMax the maximum amount of disk space available on this node
//! @param[in] diskSizeAvailable the current amount of disk space available on this node
//! @param[in] numberOfCoresMax the maximum number of cores available on this node
//! @param[in] numberOfCoresAvailable the current number of cores available on this node
//! @param[in] sPublicSubnets the available public subnet for this node
//! @param[in] sHypervisor node's hypervisor
//!
//! @return a pointer to the newly allocated resource structure or NULL if any error occured.
//!
//! @see free_resource()
//!
//! @pre The \p sNodeStatus field must not be NULL.
//!
//! @post On success, a resource structure is allocated and initialized with the given information
//!
//! @note Caller is responsible to free the allocated memory using the free_resource() function call.
//!
ncResource *allocate_resource(const char *sNodeStatus, boolean migrationCapable, const char *sIQN, int memorySizeMax, int memorySizeAvailable, int diskSizeMax,
                              int diskSizeAvailable, int numberOfCoresMax, int numberOfCoresAvailable, const char *sPublicSubnets, const char *sHypervisor)
{
    ncResource *pResource = NULL;

    // Make sure we have a valid parameter
    if (sNodeStatus == NULL)
        return (NULL);

    // See if we can allocate our resource structure
    if ((pResource = EUCA_ZALLOC(1, sizeof(ncResource))) == NULL)
        return (NULL);

    //
    // Initialize the structure with the given values
    //
    euca_strncpy(pResource->nodeStatus, sNodeStatus, CHAR_BUFFER_SIZE);
    if (sIQN)
        euca_strncpy(pResource->iqn, sIQN, CHAR_BUFFER_SIZE);
    pResource->migrationCapable = migrationCapable;
    if (sPublicSubnets)
        euca_strncpy(pResource->publicSubnets, sPublicSubnets, CHAR_BUFFER_SIZE);
    if (sHypervisor)
        euca_strncpy(pResource->hypervisor, sHypervisor, CHAR_BUFFER_SIZE);
    pResource->memorySizeMax = memorySizeMax;
    pResource->memorySizeAvailable = memorySizeAvailable;
    pResource->diskSizeMax = diskSizeMax;
    pResource->diskSizeAvailable = diskSizeAvailable;
    pResource->numberOfCoresMax = numberOfCoresMax;
    pResource->numberOfCoresAvailable = numberOfCoresAvailable;
    return (pResource);
}
Esempio n. 4
0
//!
//! Sets the custom log prefix string
//!
//! @param[in] log_spec the log prefic specification.
//!
//! @return Always return EUCA_OK
//!
//! @pre The log_spec field should not be NULL and must have at least 1 character
//!
//! @post If the log_spec has at least 1 character, it'll be copied in our global log_custom_prefix field. This
//!       will ensure we're not overflowing our log_custom_prefix field. If log_spec is invalid, then the
//!       USE_STANDARD_PREFIX string will be applied.
//!
int log_prefix_set(const char *log_spec)
{
    // @todo eventually, enable empty prefix
    if ((log_spec == NULL) || (strlen(log_spec) == 0))
        euca_strncpy(log_custom_prefix, USE_STANDARD_PREFIX, sizeof(log_custom_prefix));
    else
        euca_strncpy(log_custom_prefix, log_spec, sizeof(log_custom_prefix));
    return (EUCA_OK);
}
Esempio n. 5
0
int imaging_init(const char *new_euca_home_path, const char *new_cloud_cert_path, const char *new_service_key_path)
{
    assert(new_euca_home_path);
    assert(new_cloud_cert_path);
    assert(new_service_key_path);
    euca_strncpy(euca_home_path, new_euca_home_path, sizeof(euca_home_path));
    euca_strncpy(cloud_cert_path, new_cloud_cert_path, sizeof(cloud_cert_path));
    euca_strncpy(service_key_path, new_service_key_path, sizeof(service_key_path));
    return EUCA_OK;
}
Esempio n. 6
0
//!
//!
//!
//! @param[in] req
//! @param[in] prev_art
//!
//! @return A pointer to the newly created artifact
//!
artifact *prepare_requirements(imager_request * req, artifact * prev_art)
{
    artifact *result = NULL;
    artifact *sentinel = NULL;
    prepare_params *state = NULL;

    assert(req);
    assert(req->internal);
    assert(prev_art == NULL);
    state = (prepare_params *) req->internal;

    // compute tree of dependencies
    sentinel = vbr_alloc_tree(&(state->vm), // the struct containing the VBR
                              state->bootable,  // TRUE when hypervisors can't take a kernel/ramdisk
                              state->work,  // TRUE when disk will be used by hypervisor on this host
                              FALSE,   // this is not a migration destination
                              state->sshkey,    // the SSH key
                              state->id);   // ID is for logging
    if (sentinel == NULL)
        err("failed to prepare image %s", state->id);

    assert(sentinel->deps[0]);
    result = sentinel->deps[0];        // result should be disk, not the dummy sentinel
    EUCA_FREE(sentinel);

    if (state->out) {
        // specified ID trumps generated one
        euca_strncpy(result->id, state->out, sizeof(result->id));
    }
    return result;
}
Esempio n. 7
0
char *find_ip_addr(void){
    char hostname[HOSTNAME_SIZE];
    if (gethostname(hostname, sizeof(hostname)) != 0) {
        fprintf(stderr, "failed to find hostname\n");
        return NULL;
    }
    fprintf(stderr, "Searching for IP by hostname %s\n", hostname);

    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_in *h;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    char ip[BUFSIZE];
    int rv;
    if ((rv = getaddrinfo(hostname, "http", &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return NULL;
    }
    int found = 0;
    for(p = servinfo; !found && p != NULL; p = p->ai_next) {
        if (!found) {
            h = (struct sockaddr_in *) p->ai_addr;
            euca_strncpy(ip, inet_ntoa(h->sin_addr), sizeof(ip));
            found = 1;
        }
    }
    freeaddrinfo(servinfo);

    return strdup(ip);
}
Esempio n. 8
0
//!
//! Updates VBR[] of the instance struct (which must be locked by
//! the caller) with new resource locations (URLs of images) if
//! such are present in the new
//!
static void update_resource_locations(virtualMachine *vm, char ** resourceLocations, int resourceLocationsLen)
{
    virtualBootRecord *vbr = NULL;
    char *id_loc = NULL;
    char *loc = NULL;

    for (int i = 0; i < EUCA_MAX_VBRS && i < vm->virtualBootRecordLen; i++) {
        vbr = &(vm->virtualBootRecord[i]);

        //Skip invalid vbr or any entry without an id since the below match will not behave correctly.
        if(vbr == NULL || strlen(vbr->id) <= 0) {
            continue;
        }

        // see if ID in the VBR is among IDs associated with resourceLocations to be updated
        for (int j = 0; j < resourceLocationsLen; j++) {
            id_loc = resourceLocations[j];

            if ((strstr(id_loc, vbr->id) == id_loc) // id_loc begins with ID
                && (strlen(id_loc) > (strlen(vbr->id) + 1))) { // id_loc has more than ID and '='
                loc = id_loc + strlen(vbr->id) + 1; // URL starts after ID and '='
                euca_strncpy(vbr->resourceLocation, loc, sizeof(vbr->resourceLocation)); // update the URL of in-memory struct
            }
        }
    }
}
Esempio n. 9
0
//!
//! Validate and initialize the Eucalyptus and hook directories to use.
//!
//! @param[in] euca_dir a string containing the Eucalyptus directory to use
//! @param[in] hooks_dir a string containing the hook directory to use
//!
//! @return EUCA_OK if the operation is successful or proper error code. Known error
//!         code returned include EUCA_ERROR.
//!
int init_hooks(const char *euca_dir, const char *hooks_dir)
{
    assert(euca_dir);
    assert(hooks_dir);

    euca_strncpy(euca_path, euca_dir, sizeof(euca_path));
    if (check_directory(euca_path))
        return (EUCA_ERROR);

    euca_strncpy(hooks_path, hooks_dir, sizeof(hooks_path));
    if (check_directory(hooks_path))
        return (EUCA_ERROR);

    LOGINFO("using hooks directory %s\n", hooks_path);
    initialized = TRUE;
    return (EUCA_OK);
}
Esempio n. 10
0
//!
//! Places raw XML result of an xpath query into buf. The query must return
//! only one element.
//!
//! @param[in] xml_path a string containing the path to the XML file to parse
//! @param[in] xpath a string contianing the XPATH expression to evaluate
//! @param[out] buf for the XML string
//! @param[in] buf_len size of the buf
//!
//! @return EUCA_OK or EUCA_ERROR
//!
int get_xpath_xml(const char *xml_path, const char *xpath, char *buf, int buf_len)
{
    int ret = EUCA_ERROR;
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr context = NULL;
    xmlXPathObjectPtr result = NULL;
    xmlNodeSetPtr nodeset = NULL;

    INIT();

    pthread_mutex_lock(&xml_mutex);
    {
        if ((doc = xmlParseFile(xml_path)) != NULL) {
            if ((context = xmlXPathNewContext(doc)) != NULL) {
                if ((result = xmlXPathEvalExpression(((const xmlChar *)xpath), context)) != NULL) {
                    if (!xmlXPathNodeSetIsEmpty(result->nodesetval)) {
                        nodeset = result->nodesetval;
                        if (nodeset->nodeNr > 1) {
                            fprintf(stderr, "multiple matches for '%s' in '%s'\n", xpath, xml_path);
                        } else {
                            xmlNodePtr node = nodeset->nodeTab[0]->xmlChildrenNode;
                            xmlBufferPtr xbuf = xmlBufferCreate();
                            if (xbuf) {
                                int len = xmlNodeDump(xbuf, doc, node, 0, 1);
                                if (len < 0) {
                                    fprintf(stderr, "failed to extract XML from %s\n", xpath);
                                } else if (len > buf_len) {
                                    fprintf(stderr, "insufficient buffer for %s\n", xpath);
                                } else {
                                    char *str = (char *)xmlBufferContent(xbuf);
                                    euca_strncpy(buf, str, buf_len);
                                    ret = EUCA_OK;
                                }
                                xmlBufferFree(xbuf);
                            } else {
                                fprintf(stderr, "failed to allocate XML buffer\n");
                            }
                        }
                    }
                    xmlXPathFreeObject(result);
                } else {
                    fprintf(stderr, "no results for '%s' in '%s'\n", xpath, xml_path);
                }
                xmlXPathFreeContext(context);
            } else {
                fprintf(stderr, "failed to set xpath '%s' context for '%s'\n", xpath, xml_path);
            }
            xmlFreeDoc(doc);
        } else {
            fprintf(stderr, "failed to parse XML in '%s'\n", xml_path);
        }
    }
    pthread_mutex_unlock(&xml_mutex);

    return ret;
}
Esempio n. 11
0
//!
//! Initialize a network configuration structure with given values.
//!
//! @param[out] pNetCfg a pointer to the resulting network configuration structure
//! @param[in]  sPvMac the private MAC string
//! @param[in]  sPvIp the private IP string
//! @param[in]  sPbIp the public IP string
//! @param[in]  vlan the network Virtual LAN
//! @param[in]  networkIndex the network index
//!
//! @return EUCA_OK on success or EUCA_ERROR on failure.
//!
//! @pre The \p pNetCfg field must not be NULL.
//!
//! @post The network configuration structure is updated with the provided information
//!
int allocate_netConfig(netConfig * pNetCfg, const char *sPvMac, const char *sPvIp, const char *sPbIp, int vlan, int networkIndex)
{
    // make sure our netconfig parameter isn't NULL
    if (pNetCfg != NULL) {
        if (sPvMac)
            euca_strncpy(pNetCfg->privateMac, sPvMac, ENET_ADDR_LEN);

        if (sPvIp)
            euca_strncpy(pNetCfg->privateIp, sPvIp, INET_ADDR_LEN);

        if (sPbIp)
            euca_strncpy(pNetCfg->publicIp, sPbIp, INET_ADDR_LEN);

        pNetCfg->networkIndex = networkIndex;
        pNetCfg->vlan = vlan;
        return (EUCA_OK);
    }

    return (EUCA_ERROR);
}
Esempio n. 12
0
//!
//! Parses the volume string and returns a newly allocated ebs_volume_data structure via the parameter.
//! Caller must free the returned structure.
//! Format expected:
//!    sc://volumeId,token.
//!    OR
//!    http://schost:port/services/Storage/volumeId,token
//!
//! @param[in] volume_string containing the encoded volume information
//! @param[in] dest a pointer to a pointer for ebs_volume_data, the referenced pointer will be set to newly allocated struct
//!
//! @return ok|fail
//!
//! @pre
//!
//! @post
//!
//! @note
//!
int deserialize_volume(char *volume_string, ebs_volume_data ** dest)
{
    if (volume_string == NULL || strlen(volume_string) <= strlen(VOLUME_STRING_PREFIX)) {
        *dest = NULL;
        return EUCA_ERROR;
    }

    ebs_volume_data *vol_data = EUCA_ZALLOC(1, sizeof(ebs_volume_data));
    if (vol_data == NULL) {
        LOGERROR("Cannot allocate memory!\n");
        *dest = NULL;
        return EUCA_ERROR;
    }

    char *volume_start = volume_string + strlen(VOLUME_STRING_PREFIX);  //skip the prefix.
    if (volume_start == NULL) {
        LOGERROR("Failed parsing token string: %s\n", volume_string);
        EUCA_FREE(vol_data);
        return EUCA_ERROR;
    }
    char *token_start = strchr(volume_start, ',');
    if (token_start == NULL) {
        LOGERROR("Failed parsing token string: %s\n", volume_string);
        EUCA_FREE(vol_data);
        return EUCA_ERROR;
    }
    token_start += sizeof(char);       //Go 1 past the comma delimiter

    if (euca_strncpy(vol_data->volumeId, volume_start, token_start - volume_start) == NULL) {
        EUCA_FREE(vol_data);
        return EUCA_ERROR;
    }

    if (euca_strncpy(vol_data->token, token_start, strlen(token_start) + 1) == NULL) {
        EUCA_FREE(vol_data);
        return EUCA_ERROR;
    }

    *dest = vol_data;
    return EUCA_OK;
}
Esempio n. 13
0
//!
//! Looks for file 'stage1' in dir.
//!
//! @param[in] dir the path where we are looking for the stage1 file
//!
//! @return EUCA_OK if the file is found or the following error code:
//!         \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions
//!         \li EUCA_NOT_FOUND_ERROR: if the 'stage1' file isn't found in the directory
//!
//! @pre The dir parameter must not be NULL
//!
//! @post If the 'stage1' file is found, the stage_file_dir variable is set.
//!
//! @note
//!
static int try_stage_dir(const char *dir)
{
    char stage_file_path[EUCA_MAX_PATH] = { 0 };
    if (dir) {
        snprintf(stage_file_path, sizeof(stage_file_path), "%s/stage1", dir);
        if (check_file(stage_file_path))
            return (EUCA_NOT_FOUND_ERROR);
        euca_strncpy(stage_files_dir, dir, sizeof(stage_files_dir));
        return (EUCA_OK);
    }
    return (EUCA_INVALID_ERROR);
}
Esempio n. 14
0
//! Not thread-safe. Initalizes semaphores etc. Must be guarded externally
int init_stats(const char *euca_home, const char *current_component_name, void (*lock_fn)(), void (*unlock_fn)()) {
    int result = EUCA_OK;

    if(euca_home == NULL ||
       current_component_name == NULL ||
       lock_fn == NULL ||
       unlock_fn == NULL) {
        LOGERROR("Cannot initialize stats subsystem due to invalid config parameters\n");
        return EUCA_INVALID_ERROR;
    }

    if(is_initialized) {
        LOGDEBUG("Stats already initialized.\n");
        return EUCA_OK;
    }

    LOGINFO("Initializing internal stats subsystem for component %s with euca home %s\n", current_component_name, euca_home);

    if(euca_strncpy(component_name, current_component_name, EUCA_MAX_PATH) <= 0) {
        LOGERROR("Failed setting stats component name to %s\n", current_component_name);
        result = EUCA_FATAL_ERROR;
        goto cleanup;
    }

    get_lock_fn = lock_fn;
    release_lock_fn = unlock_fn;

    LOGDEBUG("Registering sensors\n");
    //Register the sensors (map the function pointers, etc).
    result = register_sensor_set(component_name);
    if(result != EUCA_OK) {
        LOGERROR("Error registering internal sensor set: %d\n", result);
        goto cleanup;
    }

    LOGDEBUG("Initializing event emitter\n");
    //Initialize the event emitter
    result = init_emitter(euca_home);
    if(result != EUCA_OK) {
        LOGERROR("Error initializing emitter: %d\n", result);
        goto cleanup;
    }
    
 cleanup:
    if(result == EUCA_OK) { 
        is_initialized = TRUE;
        LOGINFO("Internal stats initialization complete\n");
    } else {
        LOGERROR("Initialization of stats system failed due to error: %d\n", result);
    }

    return result;
}
Esempio n. 15
0
//!
//! Records volume's information in the instance struct, updating the non-NULL values if the record
//! already exists
//!
//! @param[in] pInstance a pointer to our instance containing the volume information to save
//! @param[in] sVolumeId the volume identifier string (vol-XXXXXXXX)
//! @param[in] sVolumeAttachmentToken the attachment token associated with this volume and attachment
//! @param[in] sConnectionString the connection string info specific to this host's volume attachment
//! @param[in] sDevName the device name
//! @param[in] sStateName the current volume state name
//! @param[in] sXml the current volume xml
//!
//! @return a pointer to the volume if found. Otherwise NULL is returned.
//!
//! @pre \li Both \p pInstance and \p sVolumeId fields must not be NULL
//!      \li A volume with \p sVolumeId for \p pInstance should exists
//!      \li If such volume does not exists, we must have an empty slot in the volume list
//!
//! @post \li If any of \p pInstance or \p sVolumeId is NULL, the application will throw a SIGABRT signal
//!       \li If the volume is found or if we have an empty slot, the volume information will be saved
//!       \li If the volume is not found and if we do not have empty slot, NULL is returned and nothing is saved
//!
ncVolume *save_volume(ncInstance * pInstance, const char *sVolumeId, const char *sVolumeAttachmentToken, const char *sConnectionString, const char *sDevName,
                      const char *sStateName, const char *sXml)
{
    ncVolume *pVol = NULL;

    // Make sure pInstance and sVolumeId aren't NULL
    assert(pInstance != NULL);
    assert(sVolumeId != NULL);

    // Lookup for our device
    if ((pVol = find_volume(pInstance, sVolumeId)) != NULL) {
        //
        // Save our volume information
        //
        euca_strncpy(pVol->volumeId, sVolumeId, CHAR_BUFFER_SIZE);

        if (sVolumeAttachmentToken)
            euca_strncpy(pVol->attachmentToken, sVolumeAttachmentToken, CHAR_BUFFER_SIZE);

        if (sConnectionString)
            euca_strncpy(pVol->connectionString, sConnectionString, VERY_BIG_CHAR_BUFFER_SIZE);

        if (sDevName)
            euca_strncpy(pVol->devName, sDevName, CHAR_BUFFER_SIZE);

        if (sStateName)
            euca_strncpy(pVol->stateName, sStateName, CHAR_BUFFER_SIZE);

        if (sXml)
            euca_strncpy(pVol->volLibvirtXml, sXml, VERY_BIG_CHAR_BUFFER_SIZE);
    }

    return (pVol);
}
Esempio n. 16
0
//!
//! Callback used when checking for the integrity of the work blobstore.
//!
//! @param[in] bb pointer to the blockblob to examine
//!
//! @return EUCA_OK on success or EUCA_ERROR on failure
//!
//! @see check_backing_store()
//! @see blobstore_fsck()
//!
//! @pre The bb field must not be NULL.
//!
static int stale_blob_examiner(const blockblob * bb)
{
    char *s = NULL;
    char *user_id = NULL;
    char *inst_id = NULL;
    char *file = NULL;
    char path[EUCA_MAX_PATH] = "";
    char work_path[EUCA_MAX_PATH] = "";
    int work_path_len = 0;
    ncInstance *instance = NULL;

    set_path(work_path, sizeof(work_path), NULL, NULL);
    work_path_len = strlen(work_path);
    assert(work_path_len > 0);

    s = strstr(bb->blocks_path, work_path);
    if ((s == NULL) || (s != bb->blocks_path)) {
        // blob not under work blobstore path
        return (EUCA_OK);
    }
    // parse the path past the work directory base
    euca_strncpy(work_path, bb->blocks_path, sizeof(work_path));
    s = work_path + work_path_len + 1;
    user_id = strtok(s, "/");
    inst_id = strtok(NULL, "/");
    file = strtok(NULL, "/");

    if (((instance = find_instance(instances, inst_id)) == NULL)    // not found among instances => stale
        || instance->state == TEARDOWN) {   // found among instances, but is already marked as terminated

        // if this instance is not among those we know about,
        // load it into memory and report it in Teardown state
        //! @TODO technically, disk state for this instance is not gone,
        //! but it soon will be, once this examiner function returns error
        if ((instance == NULL) && ((instance = load_instance_struct(inst_id)) != NULL)) {
            LOGINFO("marking non-running instance %s as terminated\n", inst_id);
            instance->terminationTime = time(NULL); // set time to now, so record won't get expired immediately
            change_state(instance, TEARDOWN);
            int err = add_instance(instances, instance);    // we are not using locks because we assume the caller does
            if (err) {
                free_instance(&instance);
            }
        }
        // while we're here, try to delete extra files that aren't managed by the blobstore
        snprintf(path, sizeof(path), "%s/work/%s/%s", instances_path, user_id, inst_id);
        blobstore_delete_nonblobs(bb->store, path);
        return (EUCA_ERROR);
    }

    return (EUCA_OK);
}
Esempio n. 17
0
//!
//!
//!
//! @param[in] euca_home
//!
void init_iscsi(const char *euca_home)
{
    const char *tmp = NULL;
    if (euca_home) {
        tmp = euca_home;
    } else {
        if ((tmp = getenv(EUCALYPTUS_ENV_VAR_NAME)) == NULL) {
            tmp = "/opt/eucalyptus";
        }
    }

    euca_strncpy(home, tmp, sizeof(home));
    snprintf(connect_storage_cmd_path, MAX_PATH, EUCALYPTUS_CONNECT_ISCSI, home, home);
    snprintf(disconnect_storage_cmd_path, MAX_PATH, EUCALYPTUS_DISCONNECT_ISCSI, home, home);
    snprintf(get_storage_cmd_path, MAX_PATH, EUCALYPTUS_GET_ISCSI, home, home);
    iscsi_sem = sem_alloc(1, IPC_MUTEX_SEMAPHORE);
}
Esempio n. 18
0
//! Do a full init and execution run. Tests end-to-end
static int test_stats_run(const char *config_file_path) {
    print_header(__func__);
    char *(*check_call)() = testing_service_check_call;
    char *(*state_call)() = testing_service_state_call;
    const char *test_home = getenv(EUCALYPTUS_ENV_VAR_NAME);

    //Init the config file stuff
    LOGDEBUG("Setting up config files and values for init test\n");
    char configFiles[1][EUCA_MAX_PATH];
    bzero(configFiles[0], EUCA_MAX_PATH);
    euca_strncpy(configFiles[0], config_file_path, EUCA_MAX_PATH);
    configInitValues(configEntryKeysRestart, configEntryKeysNoRestart);
    readConfigFile(configFiles, 1);
    LOGDEBUG("Getting sensor list to validate config works\n");
    char *test_value = configFileValue(SENSOR_LIST_CONF_PARAM_NAME);
    if(!test_value) {
        LOGERROR("Config setup didn't work. Null value found\n");
        return EUCA_ERROR;
    } else {
        LOGINFO("Config file has enabled stats: %s\n", test_value);
    }
    LOGDEBUG("Done with config file checks\n");

    flush_sensor_registry(); //just to be sure from other tests
    initialize_message_sensor("testservice", 60, 60, test_get_msg_stats, test_set_msg_stats);
    initialize_service_state_sensor("testservice", 60, 60, state_call, check_call);

    if(init_stats(test_home, "testservice", test_lock, test_unlock) != EUCA_OK) {
        LOGERROR("Error initialing stats\n");
        flush_sensor_registry();
        return EUCA_ERROR;
    }

    LOGINFO("Setting some message stats and doing an internal run\n");
    //populate some stats for the message stats
    update_message_stats(test_msg_stats, "fakemessage", 500, 0);
    update_message_stats(test_msg_stats, "fakemessageDescribe", 250, 0);
    update_message_stats(test_msg_stats, "fakemessageRun", 200, 0);

    int ret = internal_sensor_pass(TRUE);
    flush_sensor_registry();
    return ret;
}
Esempio n. 19
0
//!
//! Sets and opens the log file
//!
//! @param[in] file the file name of the log file. A NULL value unset the file
//!
//! @return EUCA_OK on success or EUCA_ERROR on failure
//!
int log_file_set(const char *file)
{
    if (file == NULL) {
        // NULL means standard output
        log_file_path[0] = '\0';
        return (EUCA_OK);
    }

    if (strcmp(log_file_path, file) == 0) {
        // hasn't changed
        return (EUCA_OK);
    }

    euca_strncpy(log_file_path, file, EUCA_MAX_PATH);
    if (get_file(TRUE) == NULL) {
        return (EUCA_ERROR);
    }
    release_file();
    return (EUCA_OK);
}
Esempio n. 20
0
//!
//! 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)
{
    int err = EUCA_ERROR;
    char *in_path = NULL;
    char *out_path = NULL;
    char xml_buf[2048] = "";

    if (argc != 2) {
        LOGERROR("required parameters are <XSLT stylesheet path>\n");
        return (EUCA_ERROR);
    }

    euca_strncpy(xslt_path, argv[1], sizeof(xslt_path));
    in_path = tempnam(NULL, "xml-");
    out_path = tempnam(NULL, "xml-");

    create_dummy_instance(in_path);

    LOGINFO("parsing stylesheet %s\n", xslt_path);
    if ((err = apply_xslt_stylesheet(xslt_path, in_path, out_path, NULL, 0)) != EUCA_OK)
        goto out;

    LOGINFO("parsing stylesheet %s again\n", xslt_path);
    if ((err = apply_xslt_stylesheet(xslt_path, in_path, out_path, xml_buf, sizeof(xml_buf))) != EUCA_OK)
        goto out;

    LOGINFO("wrote XML to %s\n", out_path);
    if (strlen(xml_buf) < 1) {
        err = EUCA_ERROR;
        LOGERROR("failed to see XML in buffer\n");
        goto out;
    }
    cat(out_path);

out:
    remove(out_path);
    remove(in_path);
    EUCA_FREE(in_path);
    EUCA_FREE(out_path);
    return (err);
}
Esempio n. 21
0
//!
//! Initialize the XML local parameters from the NC state structure.
//!
//! @param[in] nc_state a pointer to the NC state structure to initialize
//!
static void init(struct nc_state_t *nc_state)
{
    pthread_mutex_lock(&xml_mutex);
    {
        if (!initialized) {
            xmlInitParser();
            LIBXML_TEST_VERSION;       // verifies that loaded library matches the compiled library
            xmlSubstituteEntitiesDefault(1);    // substitute entities while parsing
            xmlSetGenericErrorFunc(NULL, error_handler);    // catches errors/warnings that libxml2 writes to stderr
            xsltSetGenericErrorFunc(NULL, error_handler);   // catches errors/warnings that libslt writes to stderr
            if (nc_state != NULL) {
                config_use_virtio_root = nc_state->config_use_virtio_root;
                config_use_virtio_disk = nc_state->config_use_virtio_disk;
                config_use_virtio_net = nc_state->config_use_virtio_net;
                euca_strncpy(xslt_path, nc_state->libvirt_xslt_path, sizeof(xslt_path));
            }
            initialized = TRUE;
        }
    }
    pthread_mutex_unlock(&xml_mutex);
}
Esempio n. 22
0
//!
//!
//!
//! @param[in] req
//! @param[in] prev_art
//!
//! @return A pointer to the newly created artifact
//!
artifact *prepare_requirements(imager_request * req, artifact * prev_art)
{
    artifact *result = NULL;
    artifact *sentinel = NULL;
    prepare_params *state = NULL;

    assert(req);
    assert(req->internal);
    assert(prev_art == NULL);
    state = (prepare_params *) req->internal;

    // compute tree of dependencies
    sentinel = vbr_alloc_tree(&(state->vm), // the struct containing the VBR
                              state->bootable,  // TRUE when hypervisors can't take a kernel/ramdisk
                              state->work,  // TRUE when disk will be used by hypervisor on this host
                              ! (state->action & ACTION_DOWNLOAD),   // migration destination => do not bother with download
                              state->sshkey,    // the SSH key
                              NULL, // bail flag
                              state->id);   // ID is for logging
    if (sentinel == NULL)
        err("failed to prepare image %s", state->id);

    assert(sentinel->deps[0]);
    result = sentinel->deps[0];        // result should be disk, not the dummy sentinel
    EUCA_FREE(sentinel);

    // for disk, do_not_download means don't bother constructing it
    // so, if 'convert' action wasn't requested, we'll set do_not_download
    result->do_not_download = ! (state->action & ACTION_CONVERT); 

    if (state->out) {
        // specified ID trumps generated one
        euca_strncpy(result->id, state->out, sizeof(result->id));
    }
    return result;
}
Esempio n. 23
0
//!
//! Defines the thread that does the actual reboot of an instance.
//!
//! @param[in] arg a transparent pointer to the argument passed to this thread handler
//!
//! @return Always return NULL
//!
static void *rebooting_thread(void *arg)
{
#define REATTACH_RETRIES      3

    int i = 0;
    int err = 0;
    int error = 0;
    int rc = 0;
    int log_level_for_devstring = EUCATRACE;
    char *xml = NULL;
    char *remoteDevStr = NULL;
    char path[MAX_PATH] = "";
    char lpath[MAX_PATH] = "";
    char resourceName[1][MAX_SENSOR_NAME_LEN] = { {0} };
    char resourceAlias[1][MAX_SENSOR_NAME_LEN] = { {0} };
    ncVolume *volume = NULL;
    ncInstance *instance = ((ncInstance *) arg);
    virDomainPtr dom = NULL;
    virConnectPtr *conn = NULL;

    logprintfl(EUCADEBUG, "[%s] spawning rebooting thread\n", instance->instanceId);
    if ((xml = file2str(instance->libvirtFilePath)) == NULL) {
        logprintfl(EUCAERROR, "[%s] cannot obtain instance XML file %s\n", instance->instanceId, instance->libvirtFilePath);
        return NULL;
    }

    if ((conn = check_hypervisor_conn()) == NULL) {
        logprintfl(EUCAERROR, "[%s] cannot restart instance %s, abandoning it\n", instance->instanceId, instance->instanceId);
        change_state(instance, SHUTOFF);
        EUCA_FREE(xml);
        return NULL;
    }

    sem_p(hyp_sem);
    {
        dom = virDomainLookupByName(*conn, instance->instanceId);
    }
    sem_v(hyp_sem);

    if (dom == NULL) {
        EUCA_FREE(xml);
        return NULL;
    }

    sem_p(hyp_sem);
    {
        // for KVM, must stop and restart the instance
        logprintfl(EUCADEBUG, "[%s] destroying domain\n", instance->instanceId);
        error = virDomainDestroy(dom);  // @todo change to Shutdown? is this synchronous?
        virDomainFree(dom);
    }
    sem_v(hyp_sem);

    if (error) {
        EUCA_FREE(xml);
        return NULL;
    }
    // Add a shift to values of three of the metrics: ones that
    // drop back to zero after a reboot. The shift, which is based
    // on the latest value, ensures that values sent upstream do
    // not go backwards .
    sensor_shift_metric(instance->instanceId, "CPUUtilization");
    sensor_shift_metric(instance->instanceId, "NetworkIn");
    sensor_shift_metric(instance->instanceId, "NetworkOut");

    // domain is now shut down, create a new one with the same XML
    sem_p(hyp_sem);
    {
        logprintfl(EUCAINFO, "[%s] rebooting\n", instance->instanceId);
        dom = virDomainCreateLinux(*conn, xml, 0);
    }
    sem_v(hyp_sem);
    EUCA_FREE(xml);

    euca_strncpy(resourceName[0], instance->instanceId, MAX_SENSOR_NAME_LEN);
    sensor_refresh_resources(resourceName, resourceAlias, 1);   // refresh stats so we set base value accurately

    // re-attach each volume previously attached
    for (i = 0; i < EUCA_MAX_VOLUMES; ++i) {
        volume = &instance->volumes[i];
        if (strcmp(volume->stateName, VOL_STATE_ATTACHED) && strcmp(volume->stateName, VOL_STATE_ATTACHING))
            continue;           // skip the entry unless attached or attaching

        logprintfl(EUCADEBUG, "[%s] volumes [%d] = '%s'\n", instance->instanceId, i, volume->stateName);

        // get credentials, decrypt them
        remoteDevStr = get_iscsi_target(volume->remoteDev);
        if (!remoteDevStr || !strstr(remoteDevStr, "/dev")) {
            logprintfl(EUCAERROR, "[%s] failed to get local name of host iscsi device when re-attaching\n", instance->instanceId);
            rc = 1;
        } else {
            // set the path
            snprintf(path, sizeof(path), EUCALYPTUS_VOLUME_XML_PATH_FORMAT, instance->instancePath, volume->volumeId);  // vol-XXX.xml
            snprintf(lpath, sizeof(lpath), EUCALYPTUS_VOLUME_LIBVIRT_XML_PATH_FORMAT, instance->instancePath, volume->volumeId);    // vol-XXX-libvirt.xml

            // read in libvirt XML, which may have been modified by the hook above
            if ((xml = file2str(lpath)) == NULL) {
                logprintfl(EUCAERROR, "[%s][%s] failed to read volume XML from %s\n", instance->instanceId, volume->volumeId, lpath);
                rc = 1;
            }
        }

        EUCA_FREE(remoteDevStr);

        if (!rc) {
            // zhill - wrap with retry in case libvirt is dumb.
            err = 0;
            for (i = 1; i < REATTACH_RETRIES; i++) {
                // protect libvirt calls because we've seen problems during concurrent libvirt invocations
                sem_p(hyp_sem);
                {
                    err = virDomainAttachDevice(dom, xml);
                }
                sem_v(hyp_sem);

                if (err) {
                    logprintfl(EUCAERROR, "[%s][%s] failed to reattach volume (attempt %d of %d)\n", instance->instanceId, volume->volumeId, i,
                               REATTACH_RETRIES);
                    logprintfl(EUCADEBUG, "[%s][%s] error from virDomainAttachDevice: %d xml: %s\n", instance->instanceId, volume->volumeId, err,
                               xml);
                    sleep(3);   // sleep a bit and retry
                } else {
                    logprintfl(EUCAINFO, "[%s][%s] volume reattached as '%s'\n", instance->instanceId, volume->volumeId, volume->localDevReal);
                    break;
                }
            }

            log_level_for_devstring = EUCATRACE;
            if (err)
                log_level_for_devstring = EUCADEBUG;
            logprintfl(log_level_for_devstring, "[%s][%s] remote device string: %s\n", instance->instanceId, volume->volumeId, volume->remoteDev);
        }

        EUCA_FREE(xml);
    }

    if (dom == NULL) {
        logprintfl(EUCAERROR, "[%s] failed to restart instance\n", instance->instanceId);
        change_state(instance, SHUTOFF);
        return NULL;
    }

    sem_p(hyp_sem);
    {
        virDomainFree(dom);
    }
    sem_v(hyp_sem);
    return NULL;

#undef REATTACH_RETRIES
}
Esempio n. 24
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);
}
Esempio n. 25
0
//!
//! Loads an instance structure data from the instance.xml file under the instance's
//! work blobstore path.
//!
//! @param[in] instanceId the instance identifier string (i-XXXXXXXX)
//!
//! @return A pointer to the instance structure if successful or otherwise NULL.
//!
//! @pre The instanceId parameter must not be NULL.
//!
//! @post On success, a newly allocated pointer to the instance is returned where the stateCode
//!       is set to NO_STATE.
//!
ncInstance *load_instance_struct(const char *instanceId)
{
    DIR *insts_dir = NULL;
    char tmp_path[EUCA_MAX_PATH] = "";
    char user_paths[EUCA_MAX_PATH] = "";
    char checkpoint_path[EUCA_MAX_PATH] = "";
    ncInstance *instance = NULL;
    struct dirent *dir_entry = NULL;
    struct stat mystat = { 0 };

    // Allocate memory for our instance
    if ((instance = EUCA_ZALLOC(1, sizeof(ncInstance))) == NULL) {
        LOGERROR("out of memory (for instance struct)\n");
        return (NULL);
    }
    // We know the instance indentifier
    euca_strncpy(instance->instanceId, instanceId, sizeof(instance->instanceId));

    // we don't know userId, so we'll look for instanceId in every user's
    // directory (we're assuming that instanceIds are unique in the system)
    set_path(user_paths, sizeof(user_paths), NULL, NULL);
    if ((insts_dir = opendir(user_paths)) == NULL) {
        LOGERROR("failed to open %s\n", user_paths);
        goto free;
    }
    // Scan every path under the user path for one that conaints our instance
    while ((dir_entry = readdir(insts_dir)) != NULL) {
        snprintf(tmp_path, sizeof(tmp_path), "%s/%s/%s", user_paths, dir_entry->d_name, instance->instanceId);
        if (stat(tmp_path, &mystat) == 0) {
            // found it. Now save our user identifier
            euca_strncpy(instance->userId, dir_entry->d_name, sizeof(instance->userId));
            break;
        }
    }

    // Done with the directory
    closedir(insts_dir);
    insts_dir = NULL;

    // Did we really find one?
    if (strlen(instance->userId) < 1) {
        LOGERROR("didn't find instance %s\n", instance->instanceId);
        goto free;
    }
    // set various instance-directory-relative paths in the instance struct
    set_instance_paths(instance);

    // Check if there is a binary checkpoint file, used by versions up to 3.3,
    // and load metadata from it (as part of a "warm" upgrade from 3.3.0 and 3.3.1).
    set_path(checkpoint_path, sizeof(checkpoint_path), instance, "instance.checkpoint");
    set_path(instance->xmlFilePath, sizeof(instance->xmlFilePath), instance, INSTANCE_FILE_NAME);
    if (check_file(checkpoint_path) == 0) {
        ncInstance33 instance33;
        {                              // read in the checkpoint
            int fd = open(checkpoint_path, O_RDONLY);
            if (fd < 0) {
                LOGERROR("failed to load metadata for %s from %s: %s\n", instance->instanceId, checkpoint_path, strerror(errno));
                goto free;
            }

            size_t meta_size = (size_t) sizeof(ncInstance33);
            assert(meta_size <= SSIZE_MAX); // beyond that read() behavior is unspecified
            ssize_t bytes_read = read(fd, &instance33, meta_size);
            close(fd);
            if (bytes_read < meta_size) {
                LOGERROR("metadata checkpoint for %s (%ld bytes) in %s is too small (< %ld)\n", instance->instanceId, bytes_read, checkpoint_path, meta_size);
                goto free;
            }
        }
        // Convert the 3.3 struct into the current struct.
        // Currently, a copy is sufficient, but if ncInstance
        // ever changes so that its beginning differs from ncInstanc33,
        // we may have to write something more elaborate or to break
        // the ability to upgrade from 3.3. We attempt to detect such a
        // change with the following if-statement, which compares offsets
        // in the structs of the last member in the 3.3 version.
        if (((unsigned long)&(instance->last_stat) - (unsigned long)instance)
            != ((unsigned long)&(instance33.last_stat) - (unsigned long)&instance33)) {
            LOGERROR("BUG: upgrade from v3.3 is not possible due to changes to instance struct\n");
            goto free;
        }
        memcpy(instance, &instance33, sizeof(ncInstance33));
        LOGINFO("[%s] upgraded instance checkpoint from v3.3\n", instance->instanceId);
    } else {                           // no binary checkpoint, so we expect an XML-formatted checkpoint
        if (read_instance_xml(instance->xmlFilePath, instance) != EUCA_OK) {
            LOGERROR("failed to read instance XML\n");
            goto free;
        }
    }

    // Reset some fields for safety since they would now be wrong
    instance->stateCode = NO_STATE;
    instance->params.root = NULL;
    instance->params.kernel = NULL;
    instance->params.ramdisk = NULL;
    instance->params.swap = NULL;
    instance->params.ephemeral0 = NULL;

    // fix up the pointers
    vbr_parse(&(instance->params), NULL);

    // perform any upgrade-related manipulations to bring the struct up to date

    // save the struct back to disk after the upgrade routine had a chance to modify it
    if (gen_instance_xml(instance) != EUCA_OK) {
        LOGERROR("failed to create instance XML in %s\n", instance->xmlFilePath);
        goto free;
    }
    // remove the binary checkpoint because it is no longer needed and not used past 3.3
    unlink(checkpoint_path);

    return (instance);

free:
    EUCA_FREE(instance);
    return (NULL);
}
Esempio n. 26
0
//!
//! Initialize the backing store. Called during initialization of node controller.
//!
//! @param[in] conf_instances_path path to where the instances information are stored
//! @param[in] conf_work_size_mb the work blobstore size limit in MB (if 0 then unlimitted)
//! @param[in] conf_cache_size_mb the cache blobstore size limit in MB (if 0 then cache isn't used)
//!
//! @return EUCA_OK on success or the following error codes:
//!         \li EUCA_INVALID_ERROR: if any parameter does not meet the preconditions
//!         \li EUCA_ACCESS_ERROR: if we fail to access our cache and work directories
//!         \li EUCA_PERMISSION_ERROR: if we fail to create the cache or work stores.
//!
//! @pre The conf_instances_path field must not be NULL
//!
//! @post On success, the backing store module is initialized and the following happened:
//!       \li our global instance_path variable is set with the given conf_instance_path
//!       \li the work blobstore is created and our global work_bs variable is set
//!       \li the cache blobstore is created if necessary and the cache_bs variable is set
//!       \li the disk semaphore is created if necessary
//!
int init_backing_store(const char *conf_instances_path, unsigned int conf_work_size_mb, unsigned int conf_cache_size_mb)
{
    char cache_path[EUCA_MAX_PATH] = "";
    char work_path[EUCA_MAX_PATH] = "";
    unsigned long long cache_limit_blocks = 0;
    unsigned long long work_limit_blocks = 0;
    blobstore_snapshot_t snapshot_policy = BLOBSTORE_SNAPSHOT_ANY;

    LOGINFO("initializing backing store...\n");

    // Make sure we have a valid intance path passed to us
    if (conf_instances_path == NULL) {
        LOGERROR("INSTANCE_PATH not specified\n");
        return (EUCA_INVALID_ERROR);
    }
    // Set our global instance_path variable with the content of conf_instance_path
    euca_strncpy(instances_path, conf_instances_path, sizeof(instances_path));
    if (check_directory(instances_path)) {
        LOGERROR("INSTANCE_PATH (%s) does not exist!\n", instances_path);
        return (EUCA_ACCESS_ERROR);
    }
    // Check if our cache path exist. If not it should get crated
    snprintf(cache_path, sizeof(cache_path), "%s/cache", instances_path);
    if (ensure_directories_exist(cache_path, 0, NULL, NULL, BACKING_DIRECTORY_PERM) == -1)
        return (EUCA_ACCESS_ERROR);

    // Check if our work path exist. If not it should get crated
    snprintf(work_path, sizeof(work_path), "%s/work", instances_path);
    if (ensure_directories_exist(work_path, 0, NULL, NULL, BACKING_DIRECTORY_PERM) == -1)
        return (EUCA_ACCESS_ERROR);

    // convert MB to blocks
    cache_limit_blocks = (unsigned long long)conf_cache_size_mb *2048;
    work_limit_blocks = (unsigned long long)conf_work_size_mb *2048;

    // we take 0 as unlimited
    if (work_limit_blocks == 0) {
        work_limit_blocks = ULLONG_MAX;
    }
    // by default we let blobstore pick the snapshot policy, which
    // will use device mapper if available, which is faster than copying
    snapshot_policy = BLOBSTORE_SNAPSHOT_ANY;
    if (nc_state.disable_snapshots) {
        LOGINFO("if allocating storage, will avoid using snapshots\n");
        snapshot_policy = BLOBSTORE_SNAPSHOT_NONE;
    }
    // Set the backing store error callback function
    blobstore_set_error_function(&bs_errors);

    // Do we need to create a cache blobstore
    if (cache_limit_blocks) {
        cache_bs = blobstore_open(cache_path, cache_limit_blocks, BLOBSTORE_FLAG_CREAT, BLOBSTORE_FORMAT_DIRECTORY, BLOBSTORE_REVOCATION_LRU, snapshot_policy);
        if (cache_bs == NULL) {
            LOGERROR("failed to open/create cache blobstore: %s\n", blobstore_get_error_str(blobstore_get_error()));
            return (EUCA_PERMISSION_ERROR);
        }
    }
    // Lets open the work blobstore
    work_bs = blobstore_open(work_path, work_limit_blocks, BLOBSTORE_FLAG_CREAT, BLOBSTORE_FORMAT_FILES, BLOBSTORE_REVOCATION_NONE, snapshot_policy);
    if (work_bs == NULL) {
        LOGERROR("failed to open/create work blobstore: %s\n", blobstore_get_error_str(blobstore_get_error()));
        LOGERROR("%s\n", blobstore_get_last_trace());
        BLOBSTORE_CLOSE(cache_bs);
        return (EUCA_PERMISSION_ERROR);
    }
    // set the initial value of the semaphore to the number of
    // disk-intensive operations that can run in parallel on this node
    if (nc_state.concurrent_disk_ops && ((disk_sem = sem_alloc(nc_state.concurrent_disk_ops, IPC_MUTEX_SEMAPHORE)) == NULL)) {
        LOGERROR("failed to create and initialize disk semaphore\n");
        return (EUCA_PERMISSION_ERROR);
    }

    return (EUCA_OK);
}
Esempio n. 27
0
//!
//! Handles the instance migration request.
//!
//! @param[in]  nc a pointer to the node controller (NC) state
//! @param[in]  pMeta a pointer to the node controller (NC) metadata structure
//! @param[in]  instances metadata for the instance to migrate to destination
//! @param[in]  instancesLen number of instances in the instance list
//! @param[in]  action IP of the destination Node Controller
//! @param[in]  credentials credentials that enable the migration
//!
//! @return EUCA_OK on success or EUCA_*ERROR on failure
//!
//! @pre
//!
//! @post
static int doMigrateInstances(struct nc_state_t *nc, ncMetadata * pMeta, ncInstance ** instances, int instancesLen, char *action, char *credentials, char ** resourceLocations, int resourceLocationsLen)
{
    int ret = EUCA_OK;
    int credentials_prepared = 0;
    char *libvirt_xml_modified = NULL;

    if (instancesLen <= 0) {
        LOGERROR("called with invalid instancesLen (%d)\n", instancesLen);
        pMeta->replyString = strdup("internal error (invalid instancesLen)");
        return (EUCA_INVALID_ERROR);
    }

    LOGDEBUG("verifying %d instance[s] for migration...\n", instancesLen);
    for (int inst_idx = 0; inst_idx < instancesLen; inst_idx++) {
        LOGDEBUG("verifying instance # %d...\n", inst_idx);
        if (instances[inst_idx]) {
            ncInstance *instance_idx = instances[inst_idx];
            LOGDEBUG("[%s] proposed migration action '%s' (%s > %s) [creds=%s]\n", SP(instance_idx->instanceId), SP(action), SP(instance_idx->migration_src),
                     SP(instance_idx->migration_dst), (instance_idx->migration_credentials == NULL) ? "UNSET" : "present");
        } else {
            pMeta->replyString = strdup("internal error (instance count mismatch)");
            LOGERROR("Mismatch between migration instance count (%d) and length of instance list\n", instancesLen);
            return (EUCA_ERROR);
        }
    }

    // TO-DO: Optimize the location of this loop, placing it inside various conditionals below?
    for (int inst_idx = 0; inst_idx < instancesLen; inst_idx++) {
        ncInstance *instance_req = instances[inst_idx];
        char *sourceNodeName = instance_req->migration_src;
        char *destNodeName = instance_req->migration_dst;

        LOGDEBUG("[%s] processing instance # %d (%s > %s)\n", instance_req->instanceId, inst_idx, instance_req->migration_src, instance_req->migration_dst);

        // this is a call to the source of migration
        if (!strcmp(pMeta->nodeName, sourceNodeName)) {

            // locate the instance structure
            ncInstance *instance;
            sem_p(inst_sem);
            {
                instance = find_instance(&global_instances, instance_req->instanceId);
            }
            sem_v(inst_sem);
            if (instance == NULL) {
                LOGERROR("[%s] cannot find instance\n", instance_req->instanceId);
                pMeta->replyString = strdup("failed to locate instance to migrate");
                return (EUCA_NOT_FOUND_ERROR);
            }

            if (strcmp(action, "prepare") == 0) {
                sem_p(inst_sem);
                instance->migration_state = MIGRATION_PREPARING;
                euca_strncpy(instance->migration_src, sourceNodeName, HOSTNAME_SIZE);
                euca_strncpy(instance->migration_dst, destNodeName, HOSTNAME_SIZE);
                euca_strncpy(instance->migration_credentials, credentials, CREDENTIAL_SIZE);
                instance->migrationTime = time(NULL);
                update_resource_locations(&(instance->params), resourceLocations, resourceLocationsLen);
                save_instance_struct(instance);
                copy_instances();
                sem_v(inst_sem);

                // Establish migration-credential keys if this is the first instance preparation for this host.
                LOGINFO("[%s] migration source preparing %s > %s [creds=%s]\n", SP(instance->instanceId), SP(instance->migration_src), SP(instance->migration_dst),
                        (instance->migration_credentials == NULL) ? "UNSET" : "present");
                if (!credentials_prepared) {
                    if (generate_migration_keys(sourceNodeName, credentials, TRUE, instance) != EUCA_OK) {
                        pMeta->replyString = strdup("internal error (migration credentials generation failed)");
                        return (EUCA_SYSTEM_ERROR);
                    } else {
                        credentials_prepared++;
                    }
                }
                sem_p(inst_sem);
                instance->migration_state = MIGRATION_READY;
                save_instance_struct(instance);
                copy_instances();
                sem_v(inst_sem);

            } else if (strcmp(action, "commit") == 0) {

                sem_p(inst_sem);
                if (instance->migration_state == MIGRATION_IN_PROGRESS) {
                    LOGWARN("[%s] duplicate request to migration source to initiate %s > %s (already migrating)\n", instance->instanceId,
                            instance->migration_src, instance->migration_dst);
                    sem_v(inst_sem);
                    return (EUCA_DUPLICATE_ERROR);
                } else if (instance->migration_state != MIGRATION_READY) {
                    LOGERROR("[%s] request to commit migration %s > %s when source migration_state='%s' (not 'ready')\n", instance->instanceId,
                             SP(sourceNodeName), SP(destNodeName), migration_state_names[instance->migration_state]);
                    sem_v(inst_sem);
                    return (EUCA_UNSUPPORTED_ERROR);
                }
                instance->migration_state = MIGRATION_IN_PROGRESS;
                outgoing_migrations_in_progress++;
                LOGINFO("[%s] migration source initiating %s > %s [creds=%s] (1 of %d active outgoing migrations)\n", instance->instanceId, instance->migration_src,
                        instance->migration_dst, (instance->migration_credentials == NULL) ? "UNSET" : "present", outgoing_migrations_in_progress);
                save_instance_struct(instance);
                copy_instances();
                sem_v(inst_sem);

                // since migration may take a while, we do them in a thread
                pthread_t tcb = { 0 };
                if (pthread_create(&tcb, NULL, migrating_thread, (void *)instance)) {
                    LOGERROR("[%s] failed to spawn a migration thread\n", instance->instanceId);
                    return (EUCA_THREAD_ERROR);
                }
                set_corrid_pthread(get_corrid() != NULL ? get_corrid()->correlation_id : NULL, tcb);
                if (pthread_detach(tcb)) {
                    LOGERROR("[%s] failed to detach the migration thread\n", instance->instanceId);
                    return (EUCA_THREAD_ERROR);
                }
            } else if (strcmp(action, "rollback") == 0) {
                if ((instance->migration_state == MIGRATION_READY) || (instance->migration_state == MIGRATION_PREPARING)) {
                    LOGINFO("[%s] rolling back migration (%s > %s) on source\n", instance->instanceId, instance->migration_src, instance->migration_dst);
                    sem_p(inst_sem);
                    migration_rollback(instance);
                    sem_v(inst_sem);
                } else {
                    LOGINFO("[%s] ignoring request to roll back migration on source with instance in state %s(%s) -- duplicate rollback request?\n", instance->instanceId,
                            instance->stateName, migration_state_names[instance->migration_state]);
                }
            } else {
                LOGERROR("[%s] action '%s' is not valid\n", instance->instanceId, action);
                return (EUCA_INVALID_ERROR);
            }

        } else if (!strcmp(pMeta->nodeName, destNodeName)) {    // this is a migrate request to destination

            if (!strcmp(action, "commit")) {
                LOGERROR("[%s] action '%s' for migration (%s > %s) is not valid on destination node\n", instance_req->instanceId, action, SP(sourceNodeName), SP(destNodeName));
                return (EUCA_UNSUPPORTED_ERROR);
            } else if (!strcmp(action, "rollback")) {
                LOGINFO("[%s] rolling back migration (%s > %s) on destination\n", instance_req->instanceId, SP(sourceNodeName), SP(destNodeName));
                sem_p(inst_sem);
                {
                    ncInstance *instance = find_instance(&global_instances, instance_req->instanceId);
                    if (instance != NULL) {
                        LOGDEBUG("[%s] marked for cleanup\n", instance->instanceId);
                        change_state(instance, SHUTOFF);
                        instance->migration_state = MIGRATION_CLEANING;
                        save_instance_struct(instance);
                    }
                }
                sem_v(inst_sem);
                return EUCA_OK;
            } else if (strcmp(action, "prepare") != 0) {
                LOGERROR("[%s] action '%s' is not valid or not implemented\n", instance_req->instanceId, action);
                return (EUCA_INVALID_ERROR);
            }
            // Everything from here on is specific to "prepare" on a destination.

            // allocate a new instance struct
            ncInstance *instance = clone_instance(instance_req);
            if (instance == NULL) {
                LOGERROR("[%s] could not allocate instance struct\n", instance_req->instanceId);
                goto failed_dest;
            }

            sem_p(inst_sem);
            instance->migration_state = MIGRATION_PREPARING;
            instance->migrationTime = time(NULL); //In preparing state, so set migrationTime.
            euca_strncpy(instance->migration_src, sourceNodeName, HOSTNAME_SIZE);
            euca_strncpy(instance->migration_dst, destNodeName, HOSTNAME_SIZE);
            euca_strncpy(instance->migration_credentials, credentials, CREDENTIAL_SIZE);
            update_resource_locations(&(instance->params), resourceLocations, resourceLocationsLen);
            sem_v(inst_sem);

            // Establish migration-credential keys.
            LOGINFO("[%s] migration destination preparing %s > %s [creds=%s]\n", instance->instanceId, SP(instance->migration_src), SP(instance->migration_dst),
                    (instance->migration_credentials == NULL) ? "UNSET" : "present");
            // First, call config-file modification script to authorize source node.
            LOGDEBUG("[%s] authorizing migration source node %s\n", instance->instanceId, instance->migration_src);
            if (authorize_migration_keys("-a", instance->migration_src, instance->migration_credentials, instance, TRUE) != EUCA_OK) {
                goto failed_dest;
            }
            // Then, generate keys and restart libvirtd.
            if (generate_migration_keys(instance->migration_dst, instance->migration_credentials, TRUE, instance) != EUCA_OK) {
                goto failed_dest;
            }
            int error;

            //Fix for EUCA-10433, need instance struct in global_instances prior to doing volume ops
            //The monitor thread will now pick up the instance, so the migrationTime must be set
            sem_p(inst_sem);
            save_instance_struct(instance);
            error = add_instance(&global_instances, instance);
            copy_instances(); 
            sem_v(inst_sem);
            if (error) {
                if (error == EUCA_DUPLICATE_ERROR) {
                    LOGINFO("[%s] instance struct already exists (from previous migration?), deleting and re-adding...\n", instance->instanceId);
                    error = remove_instance(&global_instances, instance);
                    if (error) {
                        LOGERROR("[%s] could not replace (remove) instance struct, failing...\n", instance->instanceId);
                        goto failed_dest;
                    }
                    error = add_instance(&global_instances, instance);
                    if (error) {
                        LOGERROR("[%s] could not replace (add) instance struct, failing...\n", instance->instanceId);
                        goto failed_dest;
                    }
                } else {
                    LOGERROR("[%s] could not add instance struct, failing...\n", instance->instanceId);
                    goto failed_dest;
                }
            }
            
            if (vbr_parse(&(instance->params), pMeta) != EUCA_OK) {
                goto failed_dest;
            }
            // set up networking
            char brname[IF_NAME_LEN] = "";
            if (!strcmp(nc->pEucaNet->sMode, NETMODE_MANAGED)) {
                snprintf(brname, IF_NAME_LEN, "%s", instance->groupIds[0]);
            } else {
                snprintf(brname, IF_NAME_LEN, "%s", nc->pEucaNet->sBridgeDevice);
            }
            euca_strncpy(instance->params.guestNicDeviceName, brname, sizeof(instance->params.guestNicDeviceName));
            // TODO: move stuff in startup_thread() into a function?
            
            set_instance_params(instance);

            if ((error = create_instance_backing(instance, TRUE))   // create files that back the disks
                || (error = gen_instance_xml(instance)) // create euca-specific instance XML file
                || (error = gen_libvirt_instance_xml(instance))) {  // transform euca-specific XML into libvirt XML
                LOGERROR("[%s] failed to prepare images for migrating instance (error=%d)\n", instance->instanceId, error);
                goto failed_dest;
            }

            // attach any volumes
            for (int v = 0; v < EUCA_MAX_VOLUMES; v++) {
                ncVolume *volume = &instance->volumes[v];
                if (strcmp(volume->stateName, VOL_STATE_ATTACHED) && strcmp(volume->stateName, VOL_STATE_ATTACHING))
                    continue;          // skip the entry unless attached or attaching
                LOGDEBUG("[%s] volumes [%d] = '%s'\n", instance->instanceId, v, volume->stateName);

                ebs_volume_data *vol_data = NULL;
                char *libvirt_xml = NULL;
                char serial[128];
                char bus[16];
                set_serial_and_bus(volume->volumeId, volume->devName, serial, sizeof(serial), bus, sizeof(bus));

                if ((ret = connect_ebs(volume->devName, serial, bus, nc, instance->instanceId, volume->volumeId, volume->attachmentToken, &libvirt_xml, &vol_data)) != EUCA_OK) {
                    goto unroll;
                }
                // update the volume struct with connection string obtained from SC
                euca_strncpy(volume->connectionString, vol_data->connect_string, sizeof(volume->connectionString));
                // save volume info into vol-XXX-libvirt.xml for future detach
                if (create_vol_xml(instance->instanceId, volume->volumeId, libvirt_xml, &libvirt_xml_modified) != EUCA_OK) {
                    goto unroll;
                }

                continue;
unroll:
                ret = EUCA_ERROR;

                // @TODO: unroll all previous ones
                //  for (int uv = v - 1; uv >= 0; uv--) {
                //    disconnect_ebs(nc, instance->instanceId, volume->volumeId, )
                //  }

                goto failed_dest;
            }

                        // build any secondary network interface xml files
            for (int w=0; w < EUCA_MAX_NICS; w++) {
                if (strlen(instance->secNetCfgs[w].interfaceId) == 0)
                    continue;
                gen_libvirt_nic_xml(instance->instancePath, instance->secNetCfgs[w].interfaceId);
            }

            sem_p(inst_sem);
            instance->migration_state = MIGRATION_READY;
            instance->migrationTime = 0; //Reset the timer, to ensure monitoring thread handles this properly. This is required when setting BOOTING state
            instance->bootTime = time(NULL);    // otherwise nc_state.booting_cleanup_threshold will kick in
            change_state(instance, BOOTING);    // not STAGING, since in that mode we don't poll hypervisor for info
            LOGINFO("[%s] migration destination ready %s > %s\n", instance->instanceId, instance->migration_src, instance->migration_dst);
            save_instance_struct(instance);
            copy_instances();
            sem_v(inst_sem);
            continue;

failed_dest:
            sem_p(inst_sem);
            // Just making sure...
            if (instance != NULL) {
                LOGERROR("[%s] setting instance to Teardown(cleaning) after destination failure to prepare for migration\n", instance->instanceId);
                // Set state to Teardown(cleaning) so source won't wait until timeout to roll back.
                instance->migration_state = MIGRATION_CLEANING;
                instance->terminationTime = time(NULL);
                change_state(instance, TEARDOWN);
                save_instance_struct(instance);
                add_instance(&global_instances, instance);  // OK if this fails--that should mean it's already been added.
                copy_instances();
            }
            // If no remaining incoming or pending migrations, deauthorize all clients.
            // TO-DO: Consolidate with similar sequence in handlers.c into a utility function?
            if (!incoming_migrations_in_progress) {
                int incoming_migrations_pending = 0;
                LOGINFO("[%s] no remaining active incoming migrations -- checking to see if there are any pending migrations\n", instance->instanceId);
                bunchOfInstances *head = NULL;
                for (head = global_instances; head; head = head->next) {
                    if ((head->instance->migration_state == MIGRATION_PREPARING) || (head->instance->migration_state == MIGRATION_READY)) {
                        LOGINFO("[%s] is pending migration, state='%s', deferring deauthorization of migration keys\n", head->instance->instanceId,
                                migration_state_names[head->instance->migration_state]);
                        incoming_migrations_pending++;
                    }
                }
                // TO-DO: Add belt and suspenders?
                if (!incoming_migrations_pending) {
                    LOGINFO("[%s] no remaining incoming or pending migrations -- deauthorizing all migration client keys\n", instance->instanceId);
                    authorize_migration_keys("-D -r", NULL, NULL, NULL, FALSE);
                }
            }
            sem_v(inst_sem);
            // Set to generic EUCA_ERROR unless already set to a more-specific error.
            if (ret == EUCA_OK) {
                ret = EUCA_ERROR;
            }
        } else {
            LOGERROR("unexpected migration request (node %s is neither source nor destination)\n", pMeta->nodeName);
            ret = EUCA_ERROR;
        }
    }
    return ret;
}
Esempio n. 28
0
//!
//! Defines the thread that does the actual reboot of an instance.
//!
//! @param[in] arg a transparent pointer to the argument passed to this thread handler
//!
//! @return Always return NULL
//!
static void *rebooting_thread(void *arg)
{
    char *xml = NULL;
    char resourceName[1][MAX_SENSOR_NAME_LEN] = { "" };
    char resourceAlias[1][MAX_SENSOR_NAME_LEN] = { "" };
    //    ncInstance *instance = ((ncInstance *) arg);
    ncInstance *instance = NULL;
    struct nc_state_t *nc = NULL;
    virDomainPtr dom = NULL;
    virConnectPtr conn = NULL;
    rebooting_thread_params *params = ((rebooting_thread_params *) arg);
    instance = &(params->instance);
    nc = &(params->nc);

    LOGDEBUG("[%s] spawning rebooting thread\n", instance->instanceId);

    if ((conn = lock_hypervisor_conn()) == NULL) {
        LOGERROR("[%s] cannot connect to hypervisor to restart instance, giving up\n", instance->instanceId);
        EUCA_FREE(params);
        return NULL;
    }
    dom = virDomainLookupByName(conn, instance->instanceId);
    if (dom == NULL) {
        LOGERROR("[%s] cannot locate instance to reboot, giving up\n", instance->instanceId);
        unlock_hypervisor_conn();
        EUCA_FREE(params);
        return NULL;
    }
    // obtain the most up-to-date XML for domain from libvirt
    xml = virDomainGetXMLDesc(dom, 0);
    if (xml == NULL) {
        LOGERROR("[%s] cannot obtain metadata for instance to reboot, giving up\n", instance->instanceId);
        virDomainFree(dom);            // release libvirt resource
        unlock_hypervisor_conn();
        EUCA_FREE(params);
        return NULL;
    }
    virDomainFree(dom);                // release libvirt resource
    unlock_hypervisor_conn();

    // try shutdown first, then kill it if uncooperative
    if (shutdown_then_destroy_domain(instance->instanceId, TRUE) != EUCA_OK) {
        LOGERROR("[%s] failed to shutdown and destroy the instance to reboot, giving up\n", instance->instanceId);
        EUCA_FREE(params);
        return NULL;
    }
    // Add a shift to values of three of the metrics: ones that
    // drop back to zero after a reboot. The shift, which is based
    // on the latest value, ensures that values sent upstream do
    // not go backwards .
    sensor_shift_metric(instance->instanceId, "CPUUtilization");
    sensor_shift_metric(instance->instanceId, "NetworkIn");
    sensor_shift_metric(instance->instanceId, "NetworkOut");

    if ((conn = lock_hypervisor_conn()) == NULL) {
        LOGERROR("[%s] cannot connect to hypervisor to restart instance, giving up\n", instance->instanceId);
        EUCA_FREE(params);
        return NULL;
    }
    // domain is now shut down, create a new one with the same XML
    LOGINFO("[%s] rebooting\n", instance->instanceId);
    if (!strcmp(nc->pEucaNet->sMode, NETMODE_VPCMIDO)) {
        // need to sleep to allow midolman to update the VM interface
        sleep(10);
    }
    dom = virDomainCreateLinux(conn, xml, 0);
    if (dom == NULL) {
        LOGERROR("[%s] failed to restart instance\n", instance->instanceId);
        change_state(instance, SHUTOFF);
    } else {
        euca_strncpy(resourceName[0], instance->instanceId, MAX_SENSOR_NAME_LEN);
        sensor_refresh_resources(resourceName, resourceAlias, 1);   // refresh stats so we set base value accurately
        virDomainFree(dom);

        if (!strcmp(nc->pEucaNet->sMode, NETMODE_VPCMIDO)) {
            char iface[16], cmd[EUCA_MAX_PATH], obuf[256], ebuf[256], sPath[EUCA_MAX_PATH];
            int rc;
            snprintf(iface, 16, "vn_%s", instance->instanceId);
            
            // If this device does not have a 'brport' path, this isn't a bridge device
            snprintf(sPath, EUCA_MAX_PATH, "/sys/class/net/%s/brport/", iface);
            if (!check_directory(sPath)) {
                LOGDEBUG("[%s] removing instance interface %s from host bridge\n", instance->instanceId, iface);
                snprintf(cmd, EUCA_MAX_PATH, "%s brctl delif %s %s", nc->rootwrap_cmd_path, instance->params.guestNicDeviceName, iface);
                rc = timeshell(cmd, obuf, ebuf, 256, 10);
                if (rc) {
                    LOGERROR("unable to remove instance interface from bridge after launch: instance will not be able to connect to midonet (will not connect to network): check bridge/libvirt/kvm health\n");
                }
            }

            // Repeat process for secondary interfaces as well
            for (int i=0; i < EUCA_MAX_NICS; i++) {
                if (strlen(instance->secNetCfgs[i].interfaceId) == 0)
                    continue;

                snprintf(iface, 16, "vn_%s", instance->secNetCfgs[i].interfaceId);

                // If this device does not have a 'brport' path, this isn't a bridge device
                snprintf(sPath, EUCA_MAX_PATH, "/sys/class/net/%s/brport/", iface);
                if (!check_directory(sPath)) {
                    LOGDEBUG("[%s] removing instance interface %s from host bridge\n", instance->instanceId, iface);
                    snprintf(cmd, EUCA_MAX_PATH, "%s brctl delif %s %s", nc->rootwrap_cmd_path, instance->params.guestNicDeviceName, iface);
                    rc = timeshell(cmd, obuf, ebuf, 256, 10);
                    if (rc) {
                        LOGERROR("unable to remove instance interface from bridge after launch: instance will not be able to connect to midonet (will not connect to network): check bridge/libvirt/kvm health\n");
                    }
                }
            }
        }

    }
    EUCA_FREE(xml);

    unlock_hypervisor_conn();
    unset_corrid(get_corrid());
    EUCA_FREE(params);
    return NULL;
}
Esempio n. 29
0
//!
//! downloads a decrypted image from Walrus based on the manifest URL,
//! saves it to outfile
//!
//! @param[in] walrus_op
//! @param[in] verb
//! @param[in] requested_url
//! @param[in] outfile
//! @param[in] do_compress
//! @param[in] connect_timeout
//! @param[in] total_timeout
//!
//! @return EUCA_OK on success or proper error code. Known error code returned include: EUCA_ERROR.
//!
static int walrus_request_timeout(const char *walrus_op, const char *verb, const char *requested_url, const char *outfile, const int do_compress,
                                  int connect_timeout, int total_timeout)
{
    int code = EUCA_ERROR;
    char url[BUFSIZE];

    pthread_mutex_lock(&wreq_mutex);    /* lock for curl construction */

    euca_strncpy(url, requested_url, BUFSIZE);
#if defined(CAN_GZIP)
    if (do_compress)
        snprintf(url, BUFSIZE, "%s%s", requested_url, "?IsCompressed=true");
#endif /* CAN_GZIP */

    /* isolate the PATH in the URL as it will be needed for signing */
    char *url_path;
    if (strncasecmp(url, "http://", 7) != 0 && strncasecmp(url, "https://", 8) != 0) {
        logprintfl(EUCAERROR, "Walrus URL must start with http(s)://...\n");
        pthread_mutex_unlock(&wreq_mutex);
        return code;
    }
    if ((url_path = strchr(url + 8, '/')) == NULL) {    /* find first '/' after hostname */
        logprintfl(EUCAERROR, "Walrus URL has no path\n");
        pthread_mutex_unlock(&wreq_mutex);
        return code;
    }

    if (euca_init_cert()) {
        logprintfl(EUCAERROR, "failed to initialize certificate for Walrus request\n");
        pthread_mutex_unlock(&wreq_mutex);
        return code;
    }

    int fd = open(outfile, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);  // we do not truncate the file
    if (fd == -1 || lseek(fd, 0, SEEK_SET) == -1) {
        logprintfl(EUCAERROR, "failed to open %s for writing Walrus request\n", outfile);
        pthread_mutex_unlock(&wreq_mutex);
        if (fd >= 0)
            close(fd);
        return code;
    }

    logprintfl(EUCADEBUG, "will use URL: %s\n", url);

    CURL *curl;
    CURLcode result;
    curl = curl_easy_init();
    if (curl == NULL) {
        logprintfl(EUCAERROR, "could not initialize libcurl for Walrus request\n");
        close(fd);
        pthread_mutex_unlock(&wreq_mutex);
        return code;
    }

    char error_msg[CURL_ERROR_SIZE];
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_msg);
    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_header);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); //! @todo make this optional?
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 360L);  // must have at least a 360 baud modem
    curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 10L);    // abort if below speed limit for this many seconds
    // curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1); //! @todo remove the comment once we want to follow redirects (e.g., on HTTP 407)

    if (strncmp(verb, "GET", 4) == 0) {
        curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
    } else if (strncmp(verb, "HEAD", 5) == 0) {
        //! @todo HEAD isn't very useful atm since we don't look at headers
        curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
    } else {
        close(fd);
        logprintfl(EUCAERROR, "invalid HTTP verb %s in Walrus request\n", verb);
        pthread_mutex_unlock(&wreq_mutex);
        return EUCA_ERROR;      //! @todo dealloc structs before returning!
    }

    if (connect_timeout > 0) {
        curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, connect_timeout);
    }
    if (total_timeout > 0) {
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, total_timeout);
    }

    /* set up the default write function, but possibly override
     * it below, if compression is desired and possible */
    struct request params;
    params.fd = fd;
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &params);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
#if defined(CAN_GZIP)
    if (do_compress) {
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data_zlib);
    }
#endif /* CAN_GZIP */

    struct curl_slist *headers = NULL;  /* beginning of a DLL with headers */
    headers = curl_slist_append(headers, "Authorization: Euca");

    char op_hdr[STRSIZE];
    if (walrus_op != NULL) {
        snprintf(op_hdr, STRSIZE, "EucaOperation: %s", walrus_op);
        headers = curl_slist_append(headers, op_hdr);
    }

    time_t t = time(NULL);
    char date_str[26];
    if (ctime_r(&t, date_str) == NULL) {
        close(fd);
        pthread_mutex_unlock(&wreq_mutex);
        return EUCA_ERROR;
    }
    assert(strlen(date_str) + 7 <= STRSIZE);
    char *newline = strchr(date_str, '\n');
    if (newline != NULL) {
        *newline = '\0';
    }                           // remove newline that terminates asctime() output
    char date_hdr[STRSIZE];
    snprintf(date_hdr, STRSIZE, "Date: %s", date_str);
    headers = curl_slist_append(headers, date_hdr);

    char *cert_str = euca_get_cert(0);  /* read the cloud-wide cert */
    if (cert_str == NULL) {
        close(fd);
        pthread_mutex_unlock(&wreq_mutex);
        return EUCA_ERROR;
    }
    char *cert64_str = base64_enc((unsigned char *)cert_str, strlen(cert_str));
    assert(strlen(cert64_str) + 11 <= BUFSIZE);
    char cert_hdr[BUFSIZE];
    snprintf(cert_hdr, BUFSIZE, "EucaCert: %s", cert64_str);
    logprintfl(EUCATRACE, "base64 certificate: %s\n", get_string_stats(cert64_str));
    headers = curl_slist_append(headers, cert_hdr);
    EUCA_FREE(cert64_str);
    EUCA_FREE(cert_str);

    char *sig_str = euca_sign_url(verb, date_str, url_path);    /* create Walrus-compliant sig */
    if (sig_str == NULL) {
        close(fd);
        pthread_mutex_unlock(&wreq_mutex);
        return EUCA_ERROR;
    }
    assert(strlen(sig_str) + 16 <= BUFSIZE);
    char sig_hdr[BUFSIZE];
    snprintf(sig_hdr, BUFSIZE, "EucaSignature: %s", sig_str);
    headers = curl_slist_append(headers, sig_hdr);

    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);    /* register headers */
    if (walrus_op) {
        logprintfl(EUCADEBUG, "writing %s/%s output\n", verb, walrus_op);
        logprintfl(EUCADEBUG, "        from %s\n", url);
        logprintfl(EUCADEBUG, "        to %s\n", outfile);
    } else {
        logprintfl(EUCADEBUG, "writing %s output to %s\n", verb, outfile);
    }
    int retries = TOTAL_RETRIES;
    int timeout = FIRST_TIMEOUT;
    do {
        params.total_wrote = 0L;
        params.total_calls = 0L;
#if defined(CAN_GZIP)
        if (do_compress) {
            /* allocate zlib inflate state */
            params.strm.zalloc = Z_NULL;
            params.strm.zfree = Z_NULL;
            params.strm.opaque = Z_NULL;
            params.strm.avail_in = 0;
            params.strm.next_in = Z_NULL;
            params.ret = inflateInit2(&(params.strm), 31);
            if (params.ret != Z_OK) {
                zerr(params.ret, "walrus_request");
                break;
            }
        }
#endif /* CAN_GZIP */

        //! @todo There used to be a 'pthread_mutex_unlock(&wreq_mutex)' before curl invocation
        //! and a 'lock' after it, but under heavy load we were seeing failures inside
        //! libcurl code that would propagate to NC, implying lack of thread safety in
        //! the library. For now, we will serialize all curl operations, but in the future
        //! an approach to parallelizing Walrus downloads is necessary
        result = curl_easy_perform(curl);   /* do it */
        logprintfl(EUCADEBUG, "wrote %lld byte(s) in %lld write(s)\n", params.total_wrote, params.total_calls);

#if defined(CAN_GZIP)
        if (do_compress) {
            inflateEnd(&(params.strm));
            if (params.ret != Z_STREAM_END) {
                zerr(params.ret, "walrus_request");
            }
        }
#endif /* CAN_GZIP */

        if (result) {           // curl error (connection or transfer failed)
            logprintfl(EUCAERROR, "curl error: %s (%d)\n", error_msg, result);

        } else {
            long httpcode;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpcode);
            //! @todo pull out response message, too

            switch (httpcode) {
            case 200L:         /* all good */
                logprintfl(EUCAINFO, "downloaded %s\n", outfile);
                code = EUCA_OK;
                break;
            case 408L:         /* timeout, retry */
                logprintfl(EUCAWARN, "server responded with HTTP code %ld (timeout) for %s\n", httpcode, url);
                //logcat (EUCADEBUG, outfile); /* dump the error from outfile into the log */
                break;
            default:           /* some kind of error */
                logprintfl(EUCAERROR, "server responded with HTTP code %ld for %s\n", httpcode, url);
                //logcat (EUCADEBUG, outfile); /* dump the error from outfile into the log */
                retries = 0;
                break;
            }
        }

        if (code != EUCA_OK && retries > 0) {
            logprintfl(EUCAWARN, "download retry %d of %d will commence in %d sec for %s\n", retries, TOTAL_RETRIES, timeout, url);
            sleep(timeout);
            lseek(fd, 0L, SEEK_SET);
            timeout <<= 1;
            if (timeout > MAX_TIMEOUT)
                timeout = MAX_TIMEOUT;
        }

        retries--;
    } while (code != EUCA_OK && retries > 0);
    close(fd);

    if (code != EUCA_OK) {
        logprintfl(EUCAWARN, "removing %s\n", outfile);
        remove(outfile);
    }

    EUCA_FREE(sig_str);
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    pthread_mutex_unlock(&wreq_mutex);
    return code;
}
Esempio n. 30
0
//!
//! Allocate and initialize an instance structure with given information. Instances are
//! present in instance-related requests.
//!
//! @param[in] sUUID the unique user identifier string
//! @param[in] sInstanceId the instance identifier string (i-XXXXXXXX)
//! @param[in] sReservationId the reservation identifier string
//! @param[in] pVirtMachine a pointer to our virtual machine parametes
//! @param[in] sStateName the current instance state name string
//! @param[in] stateCode the current instance state code
//! @param[in] sUserId the user identifier string
//! @param[in] sOwnerId the owner identifier string
//! @param[in] sAccountId the account identifier string
//! @param[in] pNetCfg a pointer to the network configuration of this instance
//! @param[in] sKeyName the SSH key name to use
//! @param[in] sUserData user data string to pass to the instance
//! @param[in] sLaunchIndex the instance's launch index
//! @param[in] sPlatform the instance's platform type
//! @param[in] expiryTime the instance's expiration time before it reaches running
//! @param[in] asGroupNames an array list of group name string
//! @param[in] groupNamesSize the number of group name in the asGroupNames list
//! @param[in] asGroupIds an array list of group identifier string
//! @param[in] groupIdsSize the number of group name in the asGroupIds list
//!
//! @return a pointer to the newly allocated instance structure or NULL if any error occured.
//!
//! @see add_instance()
//! @see free_instance()
//!
//! @post On succes an instance structure is allocated and initialized with the given information.
//!
ncInstance *allocate_instance(const char *sUUID, const char *sInstanceId, const char *sReservationId, virtualMachine * pVirtMachine,
                              const char *sStateName, int stateCode, const char *sUserId, const char *sOwnerId, const char *sAccountId,
                              netConfig * pNetCfg, const char *sKeyName, const char *sUserData, const char *sLaunchIndex, const char *sPlatform,
                              int expiryTime, char **asGroupNames, int groupNamesSize, char **asGroupIds, int groupIdsSize)
{
    u32 i = 0;
    ncInstance *pInstance = NULL;

    /* zeroed out for cleaner-looking checkpoints and strings that are empty unless set */
    if ((pInstance = EUCA_ZALLOC(1, sizeof(ncInstance))) == NULL)
        return (NULL);

    if (sUserData)
        euca_strncpy(pInstance->userData, sUserData, CHAR_BUFFER_SIZE * 32);

    if (sLaunchIndex)
        euca_strncpy(pInstance->launchIndex, sLaunchIndex, CHAR_BUFFER_SIZE);

    if (sPlatform)
        euca_strncpy(pInstance->platform, sPlatform, CHAR_BUFFER_SIZE);

    pInstance->groupNamesSize = groupNamesSize;
    if ((asGroupNames != NULL) && (groupNamesSize > 0)) {
        for (i = 0; i < groupNamesSize && asGroupNames[i]; i++)
            euca_strncpy(pInstance->groupNames[i], asGroupNames[i], CHAR_BUFFER_SIZE);
    }

    pInstance->groupIdsSize = groupIdsSize;
    if ((asGroupIds != NULL) && (groupIdsSize > 0)) {
        for (i = 0; i < groupIdsSize && asGroupIds[i]; i++)
            euca_strncpy(pInstance->groupIds[i], asGroupIds[i], CHAR_BUFFER_SIZE);
    }

    if (pNetCfg != NULL)
        memcpy(&(pInstance->ncnet), pNetCfg, sizeof(netConfig));

    if (sUUID)
        euca_strncpy(pInstance->uuid, sUUID, CHAR_BUFFER_SIZE);

    if (sInstanceId)
        euca_strncpy(pInstance->instanceId, sInstanceId, CHAR_BUFFER_SIZE);

    if (sKeyName)
        euca_strncpy(pInstance->keyName, sKeyName, CHAR_BUFFER_SIZE * 4);

    if (sReservationId)
        euca_strncpy(pInstance->reservationId, sReservationId, CHAR_BUFFER_SIZE);

    if (sStateName)
        euca_strncpy(pInstance->stateName, sStateName, CHAR_BUFFER_SIZE);

    if (sUserId)
        euca_strncpy(pInstance->userId, sUserId, CHAR_BUFFER_SIZE);

    if (sOwnerId)
        euca_strncpy(pInstance->ownerId, sOwnerId, CHAR_BUFFER_SIZE);

    if (sAccountId)
        euca_strncpy(pInstance->accountId, sAccountId, CHAR_BUFFER_SIZE);

    if (pVirtMachine)
        memcpy(&(pInstance->params), pVirtMachine, sizeof(virtualMachine));

    pInstance->stateCode = stateCode;
    euca_strncpy(pInstance->bundleTaskStateName, bundling_progress_names[NOT_BUNDLING], CHAR_BUFFER_SIZE);
    pInstance->expiryTime = expiryTime;
    return (pInstance);
}