def sync_fs(self, verbose): #TODO: add progress bar into rsync somehow log.info("Starting Sync Process") exclude_list = "" if self.system_excludes != None and len(self.system_excludes) > 0: for exclude_item in self.system_excludes: exclude_list += '--exclude "%s" ' % (exclude_item) if self.user_excludes != None and len(self.user_excludes) > 0: for exclude_item in self.user_excludes: exclude_list += '--exclude "%s" ' % (exclude_item) # Let's not forget to add the --delete-exclude flag to rsync else # previously synced files which now match an exclude rule will not get # deleted and will stay in the synced image. if len(exclude_list) > 0: exclude_list += " --delete-excluded" flags = '' if verbose: flags += '--stats --progress ' cmd = "rsync -a --sparse %s --delete %s / %s" % (flags, exclude_list, self.mountpoint) log.debug("%s" % cmd) p = subprocess.Popen(cmd, shell=True, env=config.get_restricted_env()).wait() if p: log.error("Rsync encountered an issue. return code: '%s'" % p) raise ImageUtilError("Rsync failed. Aborting.") log.info("Sync Complete")
def __call__(self, args): # If you need to make a call to the repoman server, you can use the # self.get_repoman_client(args) method. log.info('foo subcommand called.') # TODO: Put your implementation code here... return
def delegator(self, args): log.info('repoman subcommand called: %s' % (self.command)) log.debug('args: %s' % (args)) # Validate CLI arguments first log.debug('Validating arguments...') self.validate_args(args) # Now we can delegate to the child class self.__call__(args)
def validate_args(self, args): if args.new_name and not re.match('^[a-zA-Z0-9_-]+$', args.new_name): raise InvalidArgumentError('Invalid group name syntax. Please see "repoman help %s" for acceptable username syntax.' % (self.command)) if args.permissions: for permission in args.permissions.split(','): if permission not in valid_permissions: log.info('Invalid permission detected: %s' % (permission)) raise InvalidArgumentError('Invalid permission: %s\nPlease chose one or more permission from the following list:\n[%s]' % (permission, ', '.join(valid_permissions)))
def __call__(self, args): # Check if sudo... if os.getuid() != 0: raise SubcommandFailure(self, "Error. This command requires root privileges, try again with sudo.") kwargs={} name = args.image # Check for proper Gzip extension (if needed) if args.gzip: if name and name.endswith('.gz'): pass else: log.info("Enforcing '.gz' extension.") name += '.gz' print ("WARNING: gzip option found, but your image name does not" " end in '.gz'. Modifying image name to enforce this.") print "New image name: '%s'" % (name) kwargs['name'] = name # Check to see if the image name has the '.gz' suffix and # compression not enabled. Having uncompressed images named with # a '.gz' suffix will break things in Nimbus. if (not args.gzip) and name.endswith('.gz'): print ("WARNING: The image name you gave ends with '.gz' but you did not enable image compression with the --gzip command line argument. Having uncompressed images with a '.gz' suffix to the image name can cause problems in some cloud frameworks.") if not yes_or_no('Do you want to continue? [yes]/[n]o: '): print "Aborting. Please select a new image name or enable compression via the --gzip command line argument." return exists = False try: image = self.get_repoman_client(args).describe_image(name, args.owner) if image: log.info("Found existing image") exists = True except RepomanError,e: if e.status == 404: log.debug("Did not find an existing image in repository with same name.") pass else: log.error("Unexpected response occurred when testing if image exists.") log.error("%s" % e) raise SubcommandFailure(self, "Unexpected response from server occurred when testing if image exists.", e)
def download_image(self, image, dest=None): if not dest: dest = './%s' % image # Check to see if requested image existing in the repo. # This will raise an exception if it does not. log.info("Checking to see if image slot exists on repository before download") resp = self._get('/api/images/%s' % image) # Check to make sure destination is not an existing directory. if os.path.isdir(dest): raise RepomanError('Cannot create %s. Specified destination already exist and is a directory.' % (dest)) # If the destination already exists, make sure we can overwrite it. if os.path.isfile(dest): try: fp = open(dest, 'w') except IOError, e: if e.errno == errno.EACCES: raise RepomanError('Cannot overwrite %s. Specified destination already exist and you don\'t have permissions to write to it.' % (dest))
def uploaded_image_exist(self, image, owner, hypervisor='xen'): """ This method will test if an image has an uploaded file for a given hypervisor. """ log.info("Checking to see if image %s, owner %s, has an uploaded file for hypervisor %s" % (image, owner, hypervisor)) if owner: resp = self._get('/api/images/%s/%s' % (owner, image)) else: resp = self._get('/api/images/%s' % (image)) if resp.status != 200: log.info("Image slot does not yet exist.") raise RepomanError('Image does not yet exist.', resp) if owner: url = 'https://' + config.host + '/api/images/raw/%s/%s/%s' % (owner, hypervisor, image) else: url = 'https://' + config.host + '/api/images/raw/%s/%s' % (hypervisor, image) try: cmd = ['curl', '--cert', config.proxy, '--insecure', '--head', url] log.debug(" ".join(cmd)) p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=config.get_restricted_env()) if not p: log.error("Error calling: %s" % (cmd)) raise RepomanError("Error checking if image %s, owner %s, has an uploaded file for hypervisor %s" % (image, owner, hypervisor)) log.info("Command complete") stdout = p.communicate()[0] log.debug(stdout) m = re.search('^HTTP/.+200 OK', stdout, flags=re.M) if m: log.info("Uploaded file exist for image %s, owner %s, hypervisor %s." % (image, owner, hypervisor)) return True else: log.info("Uploaded file does not exist for image %s, owner %s, hypervisor %s." % (image, owner, hypervisor)) return False except Exception, e: log.error("%s" % e) raise RepomanError(str(e))
def snapshot_system(self, start_fresh=False, verbose=False, clean=False): if verbose: ch = logging.StreamHandler() ch.setLevel(logging.INFO) formatter = logging.Formatter("%(levelname)s - %(message)s") ch.setFormatter(formatter) log.addHandler(ch) log.debug("Obtaining lock") if not self.obtain_lock(): log.error("Unable to obtain lock") raise ImageUtilError("Unable to obtain lock") snapshot_success = False try: self._snapshot_system(start_fresh, verbose, clean) snapshot_success = True finally: log.debug("Releasing lock") self.destroy_lock() log.info("Unmounting Image") self.umount_image() if self.partition and snapshot_success: self.install_mbr(self.imagepath)
def _snapshot_system(self, start_fresh=False, verbose=False, clean=False): exists = self.image_exists() if clean: log.info("Cleaning existing snapshot first.") start_fresh=True elif not exists: log.info("No existing image found, creating a new one") start_fresh=True elif exists: log.info("Existing image found, attempting to use.") image_stats = self.stat(self.imagepath) log.debug("Image stats:\n%s" % (image_stats)) if self.imagesize: # requested size does not match current size if self.imagesize != image_stats['size']: log.warning("Requested size (%d) does not match current file (%d). Starting from scratch." % (self.imagesize, image_stats['size'])) start_fresh = True else: # image size does not match partition size if image_stats['size'] != self.statvfs()['size']: log.warning("Root partition size does not match image size. Starting from scratch") start_fresh = True if start_fresh: # makesure image is unmounted, then destroy and recreate image. log.info("Unmounting Image") self.umount_image() log.info("Destroying old files") self.destroy_files(self.imagepath, self.mountpoint) log.info("Creating new image") self.create_image(self.imagepath, self.imagesize) try: log.info("Syncing file system") self.mount_image() self.sync_fs(verbose) self.umount_image() except ImageUtilError, e: # Cleanup after failed sync self.umount_image() self.destroy_files(self.imagepath, self.mountpoint) raise e
def upload_image(self, image, owner, image_file, gzip=False, hypervisor='xen'): log.info("Checking to see if image slot exists on repository") if owner: resp = self._get('/api/images/%s/%s' % (owner, image)) else: resp = self._get('/api/images/%s' % (image)) if resp.status != 200: log.info("Image slot does not yet exist.") raise RepomanError('Image does not yet exist. Create an image before uploading to it', resp) # Check if the source is a directory. If it is, then raise an # exception. if os.path.isdir(image_file): raise RepomanError('Specified source is a directory: %s\nSource must be a file.' % (image_file)) # Check if the source file exists. if not os.path.exists(image_file): raise RepomanError('Specified source not found: %s' % (image_file)) if owner: url = 'https://' + config.host + '/api/images/raw/%s/%s/%s' % (owner, hypervisor, image) else: url = 'https://' + config.host + '/api/images/raw/%s/%s' % (hypervisor, image) try: if gzip: log.info("Performing gzip on image prior to upload") print "Gzipping image before upload" gzip_image = os.path.join(os.path.dirname(image_file), image) gzip = subprocess.Popen("gzip --stdout %s > %s" % (image_file, gzip_image), shell=True, env=config.get_restricted_env()) gzip.wait() image_file = gzip_image log.info('Gzip complete') args = ['curl', '--cert', config.proxy, '--insecure', '-T', image_file, url] cmd = " ".join(args) log.info("Running command: '%s'" % cmd) curl = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, env=config.get_restricted_env()) for line in curl.stdout.readlines(): print line log.info("Command complete") # Cleanup gzip file if needed. if gzip: try: log.info("Cleaning up %s" % (image_file)) os.remove(image_file) except Exception, e: pass except Exception, e: log.error("%s" % e) raise RepomanError(str(e))
resp = self._get('/api/images/%s' % image) # Check to make sure destination is not an existing directory. if os.path.isdir(dest): raise RepomanError('Cannot create %s. Specified destination already exist and is a directory.' % (dest)) # If the destination already exists, make sure we can overwrite it. if os.path.isfile(dest): try: fp = open(dest, 'w') except IOError, e: if e.errno == errno.EACCES: raise RepomanError('Cannot overwrite %s. Specified destination already exist and you don\'t have permissions to write to it.' % (dest)) url = 'https://' + config.host + '/api/images/raw/%s' % image log.info("Downloading image From:'%s' To:'%s'" % (url, dest)) try: args = ['curl', '--cert', config.proxy, '--insecure', url, '>', dest] cmd = " ".join(args) log.info("Running Command: '%s'" % cmd) p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, env=config.get_restricted_env()) for line in p.stdout.readlines(): print line log.info("Command complete") except Exception, e: log.error("%s" % e) print e