def test_glance_delete_all(self):
     self.common_start()
     self.assertTrue(glance.glance_import(os.devnull, name=self._IMG_NAME, diskformat='raw'))
     self.assertTrue(glance.glance_import(os.devnull, name=self._IMG_NAME, diskformat='raw'))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     self.assertTrue(glance.glance_delete_all(self._IMG_NAME))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
 def test_glance_main_emptyname_delete_byid(self):
     self.common_start()
     self.assertTrue(self._IMG_ID is not None)
     self.assertTrue(len(self._IMG_ID) > 0)
     self.assertTrue(glance.main(['-v', '-d', self._IMG_ID]))
     self.assertFalse(glance.glance_exists(self._IMG_ID))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
Exemple #3
0
 def test_glance_main_emptyname_delete_byid(self):
     self.common_start()
     self.assertTrue(self._IMG_ID is not None)
     self.assertTrue(len(self._IMG_ID) > 0)
     self.assertTrue(glance.main(['-v', '-d', self._IMG_ID]))
     self.assertFalse(glance.glance_exists(self._IMG_ID))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
 def test_glance_rename_inexistent(self):
     old = '_rename_test'
     self.common_start()
     self.assertFalse(glance.glance_exists(self._IMG_NAME + old))
     self.assertFalse(glance.glance_exists(self._IMG_NAME + 'inexistent'))
     self.assertFalse(glance.glance_rename(self._IMG_NAME + 'inexistent', self._IMG_NAME + old))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     self.assertFalse(glance.glance_exists(self._IMG_NAME + old))
     self.assertFalse(glance.glance_exists(self._IMG_NAME + 'inexistent'))
 def test_glance_rename_and_back(self):
     old = '_rename_test'
     self.common_start()
     self.assertFalse(glance.glance_exists(self._IMG_NAME + old))
     self.assertTrue(glance.glance_rename(self._IMG_NAME, self._IMG_NAME + old))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
     self.assertTrue(glance.glance_exists(self._IMG_NAME + old))
     self.assertTrue(glance.glance_rename(self._IMG_NAME + old, self._IMG_NAME))
     self.assertFalse(glance.glance_exists(self._IMG_NAME + old))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
 def common_start(self, filename=os.devnull):
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
     self._IMG_ID = glance.glance_import_id(filename, name=self._IMG_NAME, diskformat='raw')
     # Be extra careful, to avoid calling glance_delete_all with wrong parameters
     self.assertTrue(self._IMG_ID is not None)
     self.assertTrue(self._IMG_ID is not False)
     self.assertTrue(len(self._IMG_ID) > 0)
     self.assertTrue(self._IMG_ID)
     self.assertTrue(glance.glance_exists(self._IMG_ID))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
Exemple #7
0
 def test_glance_rename_inexistent(self):
     old = '_rename_test'
     self.common_start()
     self.assertFalse(glance.glance_exists(self._IMG_NAME + old))
     self.assertFalse(glance.glance_exists(self._IMG_NAME + 'inexistent'))
     self.assertFalse(
         glance.glance_rename(self._IMG_NAME + 'inexistent',
                              self._IMG_NAME + old))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     self.assertFalse(glance.glance_exists(self._IMG_NAME + old))
     self.assertFalse(glance.glance_exists(self._IMG_NAME + 'inexistent'))
Exemple #8
0
 def common_start(self, filename=os.devnull):
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
     self._IMG_ID = glance.glance_import_id(filename,
                                            name=self._IMG_NAME,
                                            diskformat='raw')
     # Be extra careful, to avoid calling glance_delete_all with wrong parameters
     self.assertTrue(self._IMG_ID is not None)
     self.assertTrue(self._IMG_ID is not False)
     self.assertTrue(len(self._IMG_ID) > 0)
     self.assertTrue(self._IMG_ID)
     self.assertTrue(glance.glance_exists(self._IMG_ID))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
Exemple #9
0
 def test_glance_rename_and_back(self):
     old = '_rename_test'
     self.common_start()
     self.assertFalse(glance.glance_exists(self._IMG_NAME + old))
     self.assertTrue(
         glance.glance_rename(self._IMG_NAME, self._IMG_NAME + old))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
     self.assertTrue(glance.glance_exists(self._IMG_NAME + old))
     self.assertTrue(
         glance.glance_rename(self._IMG_NAME + old, self._IMG_NAME))
     self.assertFalse(glance.glance_exists(self._IMG_NAME + old))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
Exemple #10
0
 def test_glance_delete_all(self):
     self.common_start()
     self.assertTrue(
         glance.glance_import(os.devnull,
                              name=self._IMG_NAME,
                              diskformat='raw'))
     self.assertTrue(
         glance.glance_import(os.devnull,
                              name=self._IMG_NAME,
                              diskformat='raw'))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     self.assertTrue(glance.glance_delete_all(self._IMG_NAME))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
 def test_glance_exists_raise(self):
     with self.assertRaises(TypeError):
         glance.glance_exists(None)
     with self.assertRaises(TypeError):
         glance.glance_exists(True)
     with self.assertRaises(TypeError):
         glance.glance_exists(False)
     with self.assertRaises(TypeError):
         glance.glance_exists([])
Exemple #12
0
 def test_glance_exists_raise(self):
     with self.assertRaises(TypeError):
         glance.glance_exists(None)
     with self.assertRaises(TypeError):
         glance.glance_exists(True)
     with self.assertRaises(TypeError):
         glance.glance_exists(False)
     with self.assertRaises(TypeError):
         glance.glance_exists([])
 def test_glance_rename_multi(self):
     # Rename multiple images with same name...
     self.common_start()
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     IMG_ID = glance.glance_import_id(os.devnull, name=self._IMG_NAME, diskformat='raw')
     self.assertTrue(IMG_ID)
     self.assertTrue(glance.glance_exists(IMG_ID))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     self.assertTrue(len(glance.glance_ids(self._IMG_NAME)) == 2)
     self.assertTrue(glance.glance_rename(self._IMG_NAME, self._IMG_NAME + '_rename_multi'))
     # One has been renamed, the other stayed as-is...
     self.assertTrue(glance.glance_exists(self._IMG_NAME + '_rename_multi'))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     self.assertTrue(glance.glance_exists(self._IMG_ID))
     self.assertTrue(glance.glance_exists(IMG_ID))
     # Get it back to its previous name, so that it is cleaned up
     self.assertTrue(glance.glance_rename(self._IMG_NAME + '_rename_multi', self._IMG_NAME))
Exemple #14
0
 def test_glance_rename_multi(self):
     # Rename multiple images with same name...
     self.common_start()
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     IMG_ID = glance.glance_import_id(os.devnull,
                                      name=self._IMG_NAME,
                                      diskformat='raw')
     self.assertTrue(IMG_ID)
     self.assertTrue(glance.glance_exists(IMG_ID))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     self.assertTrue(len(glance.glance_ids(self._IMG_NAME)) == 2)
     self.assertTrue(
         glance.glance_rename(self._IMG_NAME,
                              self._IMG_NAME + '_rename_multi'))
     # One has been renamed, the other stayed as-is...
     self.assertTrue(glance.glance_exists(self._IMG_NAME + '_rename_multi'))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
     self.assertTrue(glance.glance_exists(self._IMG_ID))
     self.assertTrue(glance.glance_exists(IMG_ID))
     # Get it back to its previous name, so that it is cleaned up
     self.assertTrue(
         glance.glance_rename(self._IMG_NAME + '_rename_multi',
                              self._IMG_NAME))
Exemple #15
0
    def test_glance_delete_fail_quiet(self):
        self.common_start()
        self.assertTrue(glance.glance_delete(self._IMG_NAME, quiet=True))
        self.assertFalse(glance.glance_exists(self._IMG_NAME))

        self.assertFalse(glance.glance_delete(self._IMG_NAME, quiet=True))
Exemple #16
0
 def test_glance_delete_id(self):
     self.common_start()
     self.assertTrue(glance.glance_delete(self._IMG_ID))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
     self.assertFalse(glance.glance_exists(self._IMG_ID))
 def test_glance_delete_id(self):
     self.common_start()
     self.assertTrue(glance.glance_delete(self._IMG_ID))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
     self.assertFalse(glance.glance_exists(self._IMG_ID))
Exemple #18
0
 def test_glance_exists_false(self):
     self.assertFalse(glance.glance_exists(''))
     self.assertFalse(glance.glance_exists('Nonexistent'))
     self.assertFalse(glance.glance_exists(u''))
     self.assertFalse(glance.glance_exists(u'Nonexistent'))
 def test_glance_main_ok_verbose(self):
     self.common_start()
     self.assertTrue(glance.main(['-v', '-d', self._IMG_NAME]))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
 def test_glance_main_fail_wrong_param_name(self):
     self.common_start()
     with self.assertRaises(SystemExit):
         with utils.devnull('stderr'):
             glance.main([self._IMG_NAME])
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
 def test_glance_exists_false(self):
     self.assertFalse(glance.glance_exists(''))
     self.assertFalse(glance.glance_exists('Nonexistent'))
     self.assertFalse(glance.glance_exists(u''))
     self.assertFalse(glance.glance_exists(u'Nonexistent'))
 def test_glance_rename_to_same_name(self):
     self.common_start()
     # This should be a NO-OP...
     self.assertTrue(glance.glance_rename(self._IMG_NAME, self._IMG_NAME))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
 def test_glance_main_ok_nodelete(self):
     self.common_start()
     self.assertTrue(glance.main(['-v']))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
Exemple #24
0
 def test_glance_rename_to_same_name(self):
     self.common_start()
     # This should be a NO-OP...
     self.assertTrue(glance.glance_rename(self._IMG_NAME, self._IMG_NAME))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
Exemple #25
0
 def test_glance_main_ok_nodelete(self):
     self.common_start()
     self.assertTrue(glance.main(['-v']))
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
Exemple #26
0
 def test_glance_main_ok_verbose(self):
     self.common_start()
     self.assertTrue(glance.main(['-v', '-d', self._IMG_NAME]))
     self.assertFalse(glance.glance_exists(self._IMG_NAME))
Exemple #27
0
 def test_glance_main_fail_wrong_param_name(self):
     self.common_start()
     with self.assertRaises(SystemExit):
         with utils.devnull('stderr'):
             glance.main([self._IMG_NAME])
     self.assertTrue(glance.glance_exists(self._IMG_NAME))
Exemple #28
0
def main(sys_argv=sys.argv[1:]):

    # Handle CLI arguments
    args = do_argparse(sys_argv)

    # Check glance availability early
    if not args.dryrun and not glance.glance_ok():
        vprint('local glance command-line client problem')
        return False

    # Guess which mode are we operating in
    image_type = None
    desc = args.descriptor
    vprint('descriptor: ' + desc)
    if desc.startswith('http://') or desc.startswith('https://'):
        image_type = 'url'
    elif os.path.exists(desc):
        ext = os.path.splitext(desc)[1]
        if ext == '.xml':
            image_type = 'xml'
        elif ext == '.json':
            image_type = 'json'
        else:
            image_type = 'image'
    else:
        if args.cernlist:
            image_type = 'cern'
        elif len(desc) == 27:
            try:
                # This was assumed to be SLMP ID encoding format, apparently not
                #base64.decodestring(desc)
                image_type = 'market'
            except binascii.Error:
                vprint('probably invalid StratusLab marketplace ID:', desc)
        else:
            vprint('unknown descriptor')

    if image_type is None:
        vprint('Cannot guess mode of operation')
        return False
    vprint('Image type: ' + image_type)

    # Prepare VM image metadata
    if image_type == 'market':
        # Get xml metadata file from StratusLab marketplace
        metadata_url_base = 'https://marketplace.stratuslab.eu/marketplace/metadata/'
        sl_md_url = metadata_url_base + args.descriptor
        local_metadata_file = get_url(sl_md_url)
        if local_metadata_file is None:
            vprint('cannot get xml metadata file from StratuLab marketplace: ' + sl_md_url)
            return False
        else:
            vprint('downloaded xml metadata file from StratuLab marketplace: ' + sl_md_url)
            vprint('into local file: ' + local_metadata_file)
            meta = md.MetaStratusLabXml(local_metadata_file)
    elif image_type == 'cern':
        meta = md.MetaCern(args.cernlist, args.descriptor)
    elif image_type == 'json':
        meta = md.MetaStratusLabJson(args.descriptor)
    elif image_type == 'xml':
        meta = md.MetaStratusLabXml(args.descriptor)

    if image_type in ('image', 'url'):
        metadata = {'checksums': {}, 'format': 'raw'}
    else:
        metadata = meta.get_metadata()

    # Ensure we have something to work on
    if not metadata:
        vprint('Cannot retrieve metadata')
        return False

    # Retrieve image in a local file
    if image_type == 'image':
        # Already a local file
        local_image_file = args.descriptor
    else:
        # Download from network location
        if image_type in ('xml', 'json', 'market', 'cern'):
            url = metadata['location']
        elif image_type == 'url':
            url = args.descriptor
        local_image_file = get_url(url)
        if not local_image_file or not os.path.exists(local_image_file):
            vprint('cannot download from: ' + url)
            return False
        vprint(local_image_file + ': downloaded image from: ' + url)

    # VM images are compressed, but checksums are for uncompressed files
    compressed = ('compression' in metadata and metadata['compression'] and
                  metadata['compression'].lower() != 'none')
    if compressed:
        chext = '.' + metadata['compression']
        decomp = decompressor.Decompressor(local_image_file, ext=chext)
        res, local_image_file = decomp.doit(delete=(not args.keeptemps))
        if not res:
            vprint(local_image_file + ': cannot uncompress')
            return False
        vprint(local_image_file + ': uncompressed file')

    if image_type == 'image':
        base_name = os.path.basename(local_image_file)
    elif image_type == 'url':
        base_name = os.path.basename(urlsplit(url)[2])

    # Choose VM image name
    name = args.name
    if name is None:
        if image_type in ('image', 'url'):
            name, ext = os.path.splitext(base_name)
        elif image_type in ('xml', 'json', 'market', 'cern'):
            name = meta.get_name()
    vprint(local_image_file + ': VM image name: ' + name)

    # Populate metadata message digests to be verified, from checksum files
    if args.sums_files:
        if image_type in ('xml', 'json', 'market', 'cern'):
            raise NotImplementedError
        else:
            base_fn = base_name
        re_chks_line = re.compile(r'(?P<digest>[a-zA-Z0-9]+)\s+(?P<filename>.+)')
        for sum_file in args.sums_files:
            if sum_file.startswith(('http://', 'https://')):
                local_sum_file = get_url(sum_file)
                if not local_sum_file or not os.path.exists(local_sum_file):
                    vprint('cannot download from: ' + sum_file)
                    return False
                vprint(local_sum_file + ': downloaded checksum file from: ' +
                       sum_file)
                sum_file = local_sum_file
            with open(sum_file, 'rb') as sum_f:
                vprint(sum_file + ': loading checksums...')
                for line in sum_f:
                    match = re_chks_line.match(line)
                    if match and base_fn == match.group('filename'):
                        vprint(sum_file + ': matched filenames: ' + base_fn +
                               ' == ' + match.group('filename'))
                        ret = add_checksum(match.group('digest'), metadata,
                                           overrides=True)
                        if not ret:
                            vprint(sum_file + ': cannot add_checksum(' +
                                   match.group('digest') + ')')
                            return False

    # Populate metadata message digests to be verified, from CLI parameters
    if args.digests:
        digs = [dig for dig in args.digests.split(':') if dig]
        for dig in digs:
            ret = add_checksum(dig, metadata, overrides=True)
            if not ret:
                return False

    # Verify image size
    size_ok = True
    if 'bytes' in metadata:
        size_expected = int(metadata['bytes'])
        size_actual = os.path.getsize(local_image_file)
        size_ok = size_expected == size_actual

        if size_ok:
            vprint('%s: size: OK: %s' % (local_image_file, size_t(size_actual)))
        else:
            vprint('%s: size: expected: %d' % (local_image_file, size_expected))
            vprint('%s: size:   actual: %d' % (local_image_file, size_actual))
            if not args.force:
                return False

    # Verify image checksums
    verified = len(metadata['checksums'])
    if not args.nocheck:
        verified = 0
        if size_ok:
            if len(metadata['checksums']) > 0:
                vprint(local_image_file + ': verifying checksums')
                verified = check_digests(local_image_file, metadata, args.force)
            elif image_type not in ('xml', 'json', 'market', 'cern'):
                vprint(local_image_file +
                       ': no checksum to verify (forgot "-s" CLI option ?)')
            else:
                vprint(local_image_file +
                       ': no checksum to verify found in metadata...')
        else:
            if args.force:
                vprint(local_image_file +
                       ': size differ, but forcing the use of recomputed md5')
                metadata['checksums'] = {'md5': '0' * 32}
                check_digests(local_image_file, metadata, args.force)
            else:
                vprint(local_image_file +
                       ': size differ, not verifying checksums')

    # If image already exists, download it to backup directory prior to deleting
    if not args.dryrun and glance.glance_exists(name):
        if args.backupdir:
            backupdir = args.backupdir
        else:
            backupdir = os.environ.get('GLANCING_BACKUP_DIR', '/tmp/glancing')

        do_backup = True
        if not os.path.exists(backupdir):
            os.mkdir(backupdir)
        elif not os.path.isdir(backupdir):
            vprint(backupdir + ' exists but is not a directory, sorry '
                   'cannot backup old images...')
            do_backup = False

        if do_backup:
            fn_local = os.path.join(backupdir, name)
            status = glance.glance_download(name, fn_local)
            if not status:
                return False
        glance.glance_delete(name, quiet=(not utils.get_verbose()))

    # Import image into glance
    if not args.dryrun:
        if (size_ok and len(metadata['checksums']) == verified) or args.force:
            vprint(local_image_file + ': importing into glance as "%s"' %
                   str(name))
            md5 = metadata['checksums'].get('md5', None)
            ret = glance.glance_import(local_image_file, md5, name,
                                       metadata['format'])
            if not ret:
                return False
        else:
            return False
    else:
        if not args.force and (not size_ok or
                               not len(metadata['checksums']) == verified):
            return False

    # TODO: the following should be done even if something went wrong...

    # Keep downloaded image file
    if not image_type == 'image' and not args.keeptemps:
        vprint(local_image_file + ': deleting temporary file')
        os.remove(local_image_file)

    # That's all folks !
    return True
    def test_glance_delete_fail_quiet(self):
        self.common_start()
        self.assertTrue(glance.glance_delete(self._IMG_NAME, quiet=True))
        self.assertFalse(glance.glance_exists(self._IMG_NAME))

        self.assertFalse(glance.glance_delete(self._IMG_NAME, quiet=True))