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; }
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; }
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; }
/* 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; }
int scCleanupInstanceImage (char *user, char *instId) { return vrun ("rm -rf %s/%s/%s/", sc_instance_path, user, instId); }
/* 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; }
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; }