Esempio n. 1
0
int disconnect_iscsi_target (const char *dev_string) 
{
    int pid, retval, status;
    assert (strlen (home));

    logprintfl (EUCAINFO, "disconnect_iscsi_target invoked (dev_string=%s)\n", dev_string);

    sem_p (iscsi_sem);
    pid = fork();
    if (!pid) {
        if ( dev_string && strlen(dev_string) ) logprintfl(EUCADEBUG, "disconnect_iscsi_target(): running command: %s %s,%s\n", disconnect_storage_cmd_path, home, dev_string);
        if (vrun("%s %s,%s", disconnect_storage_cmd_path, home, dev_string) != 0) {
            logprintfl (EUCAERROR, "ERROR: disconnect_iscsi_target failed\n");
            exit(1);
        }
        exit(0);
    } else {
        retval = timewait(pid, &status, 90);
        if (retval) {
            retval = WEXITSTATUS(status);
        } else {
            kill(pid, SIGKILL);
            retval = -1;
        }
    }
    sem_v (iscsi_sem);

    return retval;
}
Esempio n. 2
0
int disconnect_iscsi_target(const char *storage_cmd_path, char *dev_string) {
    logprintfl (EUCAINFO, "disconnect_iscsi_target invoked (dev_string=%s)\n", dev_string);
    if (vrun("%s %s", storage_cmd_path, dev_string) != 0) {
	logprintfl (EUCAERROR, "ERROR: disconnect_iscsi_target failed\n");
	return -1;
    }
    return 0;
}
Esempio n. 3
0
int scMakeInstanceImage (char *userId, char *imageId, char *imageURL, char *kernelId, char *kernelURL, char *ramdiskId, char *ramdiskURL, char *instanceId, char *keyName, char **instance_path, sem * s, int convert_to_disk, long long total_disk_limit_mb) 
{
    char image_path   [BUFSIZE]; long long image_size_b = 0L;
    char kernel_path  [BUFSIZE]; long long kernel_size_b = 0L;
    char ramdisk_path [BUFSIZE]; long long ramdisk_size_b = 0L;
    char config_path  [BUFSIZE];
    char rundir_path  [BUFSIZE];
    int e = ERROR;
    
    logprintfl (EUCAINFO, "retrieving images for instance %s (disk limit=%lldMB)...\n", instanceId, total_disk_limit_mb);
    
    /* get the necessary files from Walrus, caching them if possible */
    char * image_name;
    int mount_offset = 0;
    long long limit_mb = total_disk_limit_mb;
    if (convert_to_disk) {
        image_name = "disk";
        mount_offset = 32256; /* 1st partition offset in the disk image */
    } else {
        image_name = "root";
        limit_mb -= swap_size_mb; /* account for swap, which will be a separate file */
    } 

#define CHECK_LIMIT(WHAT) \
    if (limit_mb < 1L) { \
        logprintfl (EUCAFATAL, "error: insufficient disk capacity remaining (%lldMB) in VM Type of instance %s for component %s\n", limit_mb, instanceId, WHAT); \
        return e; \
    }
    CHECK_LIMIT("swap");

    /* do kernel & ramdisk first, since either the disk or the ephemeral partition will take up the rest */
    if ((kernel_size_b=get_cached_file (userId, kernelURL, kernelId, instanceId, "kernel", kernel_path, s, 0, limit_mb))<1L) return e;
    limit_mb -= kernel_size_b/MEGABYTE;
    CHECK_LIMIT("kernel")
    if (ramdiskId && strnlen (ramdiskId, CHAR_BUFFER_SIZE) ) {
        if ((ramdisk_size_b=get_cached_file (userId, ramdiskURL, ramdiskId, instanceId, "ramdisk", ramdisk_path, s, 0, limit_mb))<1L) return e;
        limit_mb -= ramdisk_size_b/MEGABYTE;
        CHECK_LIMIT("ramdisk")
    }

    if ((image_size_b=get_cached_file (userId, imageURL, imageId, instanceId, image_name, image_path, s, convert_to_disk, limit_mb))<1L) return e;
    limit_mb -= image_size_b/MEGABYTE;

    snprintf (rundir_path, BUFSIZE, "%s/%s/%s", sc_instance_path, userId, instanceId);
   
    logprintfl (EUCAINFO, "preparing images for instance %s...\n", instanceId);
    
    /* embed the key, which is contained in keyName */
    char *key_template = NULL;
    if (keyName && strlen(keyName)) {
        int key_len = strlen(keyName);
        int fd = -1;
        int ret;
        
        key_template = strdup("/tmp/sckey.XXXXXX");
        
        if (((fd = mkstemp(key_template)) < 0)) {
            logprintfl (EUCAERROR, "failed to create a temporary key file\n"); 
        } else if ((ret = write (fd, keyName, key_len))<key_len) {
            logprintfl (EUCAERROR, "failed to write to key file %s write()=%d\n", key_template, ret);
        } else {
            close (fd);
            logprintfl (EUCAINFO, "adding key%s to the root file system at %s using (%s)\n", key_template, image_path, add_key_command_path);
        }
    } else { /* if no key was given, add_key just does tune2fs to up the filesystem mount date */
        key_template = "";
        logprintfl (EUCAINFO, "running tune2fs on the root file system at %s using (%s)\n", key_template, image_path, add_key_command_path);
    }

    /* do the key injection and/or tune2fs */
    sem_p (s);
    if (vrun("%s %d %s %s", add_key_command_path, mount_offset, image_path, key_template)!=0) {
        logprintfl (EUCAERROR, "ERROR: key injection / tune2fs command failed\n");
        /* we proceed despite the failure since maybe user embedded the key
         * into the image; also tune2fs may fail on uncrecognized but valid
         * filesystems */
    }
    sem_v (s);
    
    if (strlen(key_template)) {
        if (unlink(key_template) != 0) {
            logprintfl (EUCAWARN, "WARNING: failed to remove temporary key file %s\n", key_template);
        }
        free (key_template);
    }
    
    /* if the image is a root partition... */
    if (!convert_to_disk) {
        /* create swap partition */
        if (swap_size_mb>0) { 
            if ((e=vrun ("dd bs=1M count=%lld if=/dev/zero of=%s/swap 2>/dev/null", swap_size_mb, rundir_path)) != 0) { 
                logprintfl (EUCAINFO, "creation of swap (dd) at %s/swap failed\n", rundir_path);
                return e;
            }
            if ((e=vrun ("mkswap %s/swap >/dev/null", rundir_path)) != 0) {
                logprintfl (EUCAINFO, "initialization of swap (mkswap) at %s/swap failed\n", rundir_path);
                return e;		
            }
        }
        /* create ephemeral partition */
        if (limit_mb>0) {
            if ((e=vrun ("dd bs=1M count=%lld if=/dev/zero of=%s/ephemeral 2>/dev/null", limit_mb, rundir_path )) != 0) {
                logprintfl (EUCAINFO, "creation of ephemeral disk (dd) at %s/ephemeral failed\n", rundir_path);
                return e;
            }
            if ((e=vrun ("mkfs.ext3 -F %s/ephemeral >/dev/null 2>&1", rundir_path)) != 0) {
                logprintfl (EUCAINFO, "initialization of ephemeral disk (mkfs.ext3) at %s/ephemeral failed\n", rundir_path);
                return e;		
            }
        }
    }
    
    * instance_path = strdup (rundir_path);
    if (*instance_path==NULL) return errno;
    return 0;
}
Esempio n. 4
0
/* returns size of the file in bytes if OK, otherwise a negative error */
static long long get_cached_file (const char * user_id, const char * url, const char * file_id, const char * instance_id, const char * file_name, char * file_path, sem * s, int convert_to_disk, long long limit_mb) 
{
    char tmp_digest_path [BUFSIZE];
	char cached_dir      [BUFSIZE]; 
	char cached_path     [BUFSIZE];
	char staging_path    [BUFSIZE];
	char digest_path     [BUFSIZE];

	snprintf (file_path,       BUFSIZE, "%s/%s/%s/%s",    sc_instance_path, user_id, instance_id, file_name);
	snprintf (tmp_digest_path, BUFSIZE, "%s-digest",      file_path);
	snprintf (cached_dir,      BUFSIZE, "%s/%s/cache/%s", sc_instance_path, EUCALYPTUS_ADMIN, file_id); /* cache is in admin's directory */
	snprintf (cached_path,     BUFSIZE, "%s/%s",          cached_dir, file_name);
	snprintf (staging_path,    BUFSIZE, "%s-staging",     cached_path);
	snprintf (digest_path,     BUFSIZE, "%s-digest",      cached_path);

retry:

    /* under a lock, figure out the state of the file */
    sem_p (sc_sem); /***** acquire lock *****/
    ensure_subdirectory_exists (file_path); /* creates missing directories */

	struct stat mystat;
    int cached_exists  = ! stat (cached_path, &mystat);
    int staging_exists = ! stat (staging_path, &mystat);

    int e = ERROR;
    int action;
    enum { ABORT, VERIFY, WAIT, STAGE };
    if ( staging_exists ) {
        action = WAIT;
    } else {
        if ( cached_exists ) {
            action = VERIFY;
        } else {
            action = STAGE;
        }
    }

    /* we return the sum of these */
    long long file_size_b = 0;
    long long digest_size_b = 0;
   
    /* while still under lock, decide whether to cache */
    int should_cache = 0;
    if (action==STAGE) { 
        e = walrus_object_by_url (url, tmp_digest_path, 0); /* get the digest to see how big the file is */
        if (e==OK && stat (tmp_digest_path, &mystat)) {
            digest_size_b = (long long)mystat.st_size;
        }
        if (e==OK) {
            /* pull the size out of the digest */
            char * xml_file = file2str (tmp_digest_path);
            if (xml_file) {
                file_size_b = str2longlong (xml_file, "<size>", "</size>");
                free (xml_file);
            }
            if (file_size_b > 0) {
                long long full_size_b = file_size_b+digest_size_b;
                if (convert_to_disk) {
                    full_size_b += swap_size_mb*MEGABYTE + MEGABYTE; /* TODO: take into account extra padding required for disks (over partitions) */
                }
                if ( full_size_b/MEGABYTE + 1 > limit_mb ) {
                    logprintfl (EUCAFATAL, "error: insufficient disk capacity remaining (%lldMB) in VM Type of instance %s for component %s\n", limit_mb, instance_id, file_name);
                    action = ABORT;
                    
                } else if ( ok_to_cache (cached_path, full_size_b) ) { /* will invalidate the cache, if needed */
                    ensure_path_exists (cached_dir); /* creates missing directories */
                    should_cache = 1;
                    if ( touch (staging_path) ) { /* indicate that we'll be caching it */
                        logprintfl (EUCAERROR, "error: failed to create staging file %s\n", staging_path);
                        action = ABORT;
                    }
                }
            } else {
                logprintfl (EUCAERROR, "error: failed to obtain file size from digest %s\n", url);
                action = ABORT;
            }
        } else {
            logprintfl (EUCAERROR, "error: failed to obtain digest from %s\n", url);
            action = ABORT;
        }
    }
    sem_v (sc_sem); /***** release lock *****/
    
    switch (action) {
    case STAGE:
        logprintfl (EUCAINFO, "downloding image into %s...\n", file_path);		
        e = walrus_image_by_manifest_url (url, file_path, 1);

        /* for KVM, convert partition into disk */
        if (e==OK && convert_to_disk) { 
            sem_p (s);
            /* for the cached disk swap==0 and ephemeral==0 as we'll append them below */
            if ((e=vrun("%s %s %d %d", disk_convert_command_path, file_path, 0, 0))!=0) {
                logprintfl (EUCAERROR, "error: partition-to-disk image conversion command failed\n");
            }
            sem_v (s);
            
            /* recalculate file size now that it was converted */
            if ( stat (file_path, &mystat ) != 0 ) {
                logprintfl (EUCAERROR, "error: file %s not found\n", file_path);
            } else if (mystat.st_size < 1) {
                logprintfl (EUCAERROR, "error: file %s has the size of 0\n", file_path);
            } else {
                file_size_b = (long long)mystat.st_size;
            }
        }

        /* cache the partition or disk, if possible */
        if ( e==OK && should_cache ) {
            if ( (e=vrun ("cp -a %s %s", file_path, cached_path)) != 0) {
                logprintfl (EUCAERROR, "failed to copy file %s into cache at %s\n", file_path, cached_path);
            }
            if ( e==OK && (e=vrun ("cp -a %s %s", tmp_digest_path, digest_path)) != 0) {
                logprintfl (EUCAERROR, "failed to copy digest file %s into cache at %s\n", tmp_digest_path, digest_path);
            }
        }
        
        sem_p (sc_sem);
        if (should_cache) {
            unlink (staging_path);            
        }
        if ( e ) {
            logprintfl (EUCAERROR, "error: failed to download file from Walrus into %s\n", file_path);
            unlink (file_path);
            unlink (tmp_digest_path);
            if (should_cache) {
                unlink (cached_path);
                unlink (digest_path);
                if ( rmdir(cached_dir) ) {
                    logprintfl (EUCAWARN, "warning: failed to remove cache directory %s\n", cached_dir);
                }
            }
        }
        sem_v (sc_sem);
        break;
        
    case WAIT:
        logprintfl (EUCAINFO, "waiting for disapperance of %s...\n", staging_path);
        /* wait for staging_path to disappear, which means both either the
         * download succeeded or it failed */
        if ( (e=wait_for_file (NULL, staging_path, 180, "cached image")) ) 
            return 0L;        
        /* yes, it is OK to fall through */
        
    case VERIFY:
        logprintfl (EUCAINFO, "verifying cached file in %s...\n", cached_path);
        sem_p (sc_sem); /***** acquire lock *****/
        e = ERROR;
        if ( stat (cached_path, &mystat ) != 0 ) {
            logprintfl (EUCAERROR, "error: file %s not found\n", cached_path);
        } else if (mystat.st_size < 1) {
            logprintfl (EUCAERROR, "error: file %s has the size of 0\n", cached_path);
        } else if ((e=walrus_verify_digest (url, digest_path))<0) {
            /* negative status => digest changed */
            unlink (cached_path);
            unlink (staging_path); /* TODO: needed? */
            unlink (digest_path);
            if ( rmdir (cached_dir) ) {
                logprintfl (EUCAWARN, "warning: failed to remove cache directory %s\n", cached_dir);
            } else {
                logprintfl (EUCAINFO, "due to failure, removed cache directory %s\n", cached_dir);
            }
        } else {
            file_size_b = mystat.st_size;

            /* touch the digest so cache can use mtime for invalidation */
            if ( touch (digest_path) ) {
                logprintfl (EUCAERROR, "error: failed to touch digest file %s\n", digest_path);
            } else if ( stat (digest_path, &mystat) ) {
                logprintfl (EUCAERROR, "error: digest file %s not found\n", digest_path);
            } else {
                digest_size_b = (long long)mystat.st_size;
            }
        }
        sem_v (sc_sem); /***** release lock *****/
        
        if (e<0) { /* digest changed */
            if (action==VERIFY) { /* i.e. we did not download/waited for this file */
                /* try downloading anew */
                goto retry;
            } else {
                logprintfl (EUCAERROR, "error: digest mismatch, giving up\n");
                return 0L;
            }
        } else if (e>0) { /* problem with file or digest */
            return 0L;
            
        } else { /* all good - copy it, finally */
            ensure_subdirectory_exists (file_path); /* creates missing directories */            
            if ( (e=vrun ("cp -a %s %s", cached_path, file_path)) != 0) {
                logprintfl (EUCAERROR, "failed to copy file %s from cache at %s\n", file_path, cached_path);
                return 0L;
            }
        }
        break;
        
    case ABORT:
        logprintfl (EUCAERROR, "get_cached_file() failed (errno=%d)\n", e);
        e = ERROR;
    }

    if (e==OK && file_size_b > 0 && convert_to_disk ) { // if all went well above
        long long ephemeral_mb = limit_mb - swap_size_mb - (file_size_b+digest_size_b)/MEGABYTE;
        if ( swap_size_mb>0L || ephemeral_mb>0L ) {
            sem_p (s);
            if ((e=vrun("%s %s %lld %lld", disk_convert_command_path, file_path, swap_size_mb, ephemeral_mb))!=0) {
                logprintfl (EUCAERROR, "error: failed to add swap or ephemeral to the disk image\n");
            }
            sem_v (s);

            /* recalculate file size (again!) now that it was converted */
            if ( stat (file_path, &mystat ) != 0 ) {
                logprintfl (EUCAERROR, "error: file %s not found\n", file_path);
            } else if (mystat.st_size < 1) {
                logprintfl (EUCAERROR, "error: file %s has the size of 0\n", file_path);
            } else {
                file_size_b = (long long)mystat.st_size;
            }
        }
    }

    if (e==OK && action!=ABORT)
        return file_size_b + digest_size_b;
    return 0L;
}
Esempio n. 5
0
int scCleanupInstanceImage (char *user, char *instId) 
{
    return vrun ("rm -rf %s/%s/%s/", sc_instance_path, user, instId);
}
Esempio n. 6
0
/* perform integrity check on instances directory, including the cache:
 * remove any files from non-running Eucalyptus instances, delete files
 * from cache that are not complete, return the amount of bytes used up by
 * everything
 */
long long scFSCK (bunchOfInstances ** instances)
{
    long long total_size = 0;
    struct stat mystat;

    if (instances==NULL) return -1;
    
    logprintfl (EUCAINFO, "checking the integrity of instances directory (%s)\n", sc_instance_path);

    /* let us not 'rm -rf /' accidentally */
    if (strlen(sc_instance_path)<2 || 
        sc_instance_path[0]!='/' ) {
        logprintfl (EUCAFATAL, "error: instances directory cannot be /, sorry\n");
        return -1; 
    }

    if (stat (sc_instance_path, &mystat) < 0) {
        logprintfl (EUCAFATAL, "error: could not stat %s\n", sc_instance_path);
        return -1;
    }
    total_size += mystat.st_size;

    DIR * insts_dir;
    if ((insts_dir=opendir(sc_instance_path))==NULL) {
        logprintfl (EUCAFATAL, "error: could not open instances directory %s\n", sc_instance_path);
        return -1;
    }

    /*** run through all users ***/

    char * cache_path = NULL;
    struct dirent * inst_dir_entry;
    while ((inst_dir_entry=readdir(insts_dir))!=NULL) {
        char * uname = inst_dir_entry->d_name;
        char user_path [BUFSIZE];
        struct dirent * user_dir_entry;
        DIR * user_dir;

        if (!strcmp(".", uname) || 
            !strcmp("..", uname))
            continue;

        snprintf (user_path, BUFSIZE, "%s/%s", sc_instance_path, uname);
        if ((user_dir=opendir(user_path))==NULL) {
            logprintfl (EUCAWARN, "warning: unopeneable directory %s\n", user_path);
            continue;
        }

        /*** run through all instances of a user ***/
        while ((user_dir_entry=readdir(user_dir))!=NULL) {
            char * iname = user_dir_entry->d_name;
            
            if (!strcmp(".", iname) ||
                !strcmp("..", iname))
                continue;
            
            char instance_path [BUFSIZE];
            snprintf (instance_path, BUFSIZE, "%s/%s", user_path, iname);

            if (!strcmp("cache", iname) &&
                	!strcmp(EUCALYPTUS_ADMIN, uname)) { /* cache is in admin's dir */
		if (cache_path) {
                    logprintfl (EUCADEBUG, "Found a second cache_path?\n");
		    free(cache_path);
		}
                cache_path = strdup (instance_path);
                continue;
            }

            /* spare directories of running instances, but count their usage */
            if (find_instance (instances, iname)) {
                long long bytes = dir_size (instance_path);
                if (bytes>0) {
                    logprintfl (EUCAINFO, "- running instance %s directory, size=%d\n", iname, bytes);
                    total_size += bytes;
                } else if (bytes==0) {
                    logprintfl (EUCAWARN, "warning: empty instance directory %s\n", instance_path);
                } else {
                    logprintfl (EUCAWARN, "warning: non-standard instance directory %s\n", instance_path);
                } 
                continue;
            }

            /* looks good - destroy it */
            if (vrun ("rm -rf %s", instance_path)) {
                logprintfl (EUCAWARN, "warning: failed to remove %s\n", instance_path);
            }
        }
        closedir (user_dir);
    }
    closedir (insts_dir);

    /*** scan the cache ***/
    long long cache_bytes = init_cache (cache_path);
    free (cache_path);
    if (cache_bytes < 0) {
        return -1;
    }
    
    return total_size + cache_bytes;
}
Esempio n. 7
0
static long long init_cache (const char * cache_path)
{
    long long total_size = 0;
    
    logprintfl (EUCAINFO, "checking the integrity of the cache directory (%s)\n", cache_path);
    
    if (cache_path==NULL) {
        logprintfl (EUCAINFO, "no cache directory yet\n");
        return total_size;
    }

    struct stat mystat;
    if (stat (cache_path, &mystat) < 0) {
        logprintfl (EUCAFATAL, "error: could not stat %s\n", cache_path);
        return -1;
    }
    total_size += mystat.st_size;
   
    DIR * cache_dir;
    if ((cache_dir=opendir(cache_path))==NULL) {
        logprintfl (EUCAFATAL, "errror: could not open cache directory %s\n", cache_path);
        return -1;
    }

    struct dirent * cache_dir_entry;
    while ((cache_dir_entry=readdir(cache_dir))!=NULL) {
        char * image_name = cache_dir_entry->d_name;
        char image_path [BUFSIZE];
        int image_size = 0;
        int image_files = 0;

        if (!strcmp(".", image_name) || 
            !strcmp("..", image_name))
            continue;
        
        DIR * image_dir;
        snprintf (image_path, BUFSIZE, "%s/%s", cache_path, image_name);
        if ((image_dir=opendir(image_path))==NULL) {
            logprintfl (EUCAWARN, "warning: unopeneable directory %s\n", image_path);
            continue;
        }

        if (stat (image_path, &mystat) < 0) {
            logprintfl (EUCAWARN, "warning: could not stat %s\n", image_path);
	    closedir(image_dir);
            continue;
        }
        image_size += mystat.st_size;
        
        /* make sure that image directory contains only two files: one
         * named X and another X-digest, also add up their sizes */
        char X        [BUFSIZE] = "";
        char X_digest [BUFSIZE] = "";
        struct dirent * image_dir_entry;
        while ((image_dir_entry=readdir(image_dir))!=NULL) {
            char name [BUFSIZE];
            strncpy (name, image_dir_entry->d_name, BUFSIZE);
            
            if (!strcmp(".", name) ||
                !strcmp("..", name))
                continue;

            image_files++;
            
            char filepath [BUFSIZE];
            snprintf (filepath, BUFSIZE, "%s/%s", image_path, name);
            if (stat (filepath, &mystat) < 0 ) {
                logprintfl (EUCAERROR, "error: could not stat file %s\n", filepath);
                break;
            }
            if (mystat.st_size < 1) {
                logprintfl (EUCAERROR, "error: empty file among cached images in %s\n", filepath);
                break;
            }
            image_size += mystat.st_size;
            
            char * suffix;
            if ((suffix=strstr (name, "-digest"))==NULL) {
                if (strlen (X)) 
                    break; /* already saw X => fail */
                strncpy (X, name, BUFSIZE);
            } else {
                if (strlen (X_digest))
                    break; /* already saw X-digest => fail */
                * suffix = '\0';
                strncpy (X_digest, name, BUFSIZE);
            }
        }
	closedir(image_dir);

        if (image_files > 0) { /* ignore empty directories */
            if (image_files != 2 || strncmp (X, X_digest, BUFSIZE) != 0 ) {
                logprintfl (EUCAERROR, "error: inconsistent state of cached image %s, deleting it\n", image_name);
                if (vrun ("rm -rf %s", image_path)) {            
                    logprintfl (EUCAWARN, "warning: failed to remove %s\n", image_path);
                }
            } else {
                char filepath [BUFSIZE];
                snprintf (filepath, BUFSIZE, "%s/%s", image_path, X);
                if (image_size>0) {
                    logprintfl (EUCAINFO, "- cached image %s directory, size=%d\n", image_name, image_size);
                    total_size += image_size;
                    add_to_cache (filepath, image_size);
                } else {
                    logprintfl (EUCAWARN, "warning: empty cached image directory %s\n", image_path);
                }
            }
        }
    }
    closedir (cache_dir);

    return total_size;
}