Ejemplo n.º 1
0
    def __init__(self, conf):
        self.volumes = VolumeHelper(conf)
        self.exports = ExportHelper(conf)
        self.backups = BackupHelper(conf)
        self.cgroups = CgroupHelper(conf)
        self.api_server = conf.string('storage', 'api_server',
                                      "http://localhost:8080")
        self.api_retry = conf.int('storage', 'api_retry', 1)

        # name of node registration
        self.name = conf.string('storage', 'name', socket.gethostname())
        self.affinity_group = conf.string('storage', 'affinity_group', '')

        # management interface
        self.management_host = conf.string('server:main', 'host', '0.0.0.0')
        if self.management_host == '0.0.0.0':
            self.management_host = my_ip(self.api_server)
        self.management_port = conf.int('server:main', 'port', 8081)

        # storage interface
        self.storage_host = conf.string('storage', 'host', '127.0.0.1')
        self.storage_port = conf.int('storage', 'port', 3260)
        self.volume_type = conf.string('storage', 'volume_type', 'vtype')

        # cinder
        self.cinder_args = cinderclient.get_args(conf)
        self.rax_auth = conf.bool('cinder', 'rax_auth', True)
        if self.rax_auth:
            self.client = cinderclient.CinderClient(**self.cinder_args)
        self.cinder_host = conf.string('storage', 'cinder_host',
                                       self.management_host)
Ejemplo n.º 2
0
    def backup(self, id=None, src=None, timestamp=None):
        """
        This runs a backup job outside of the storage api,
        which is useful for performance testing backups
        """
        # Set basic Logging
        logging.basicConfig()
        # Get the lunr logger
        log = logger.get_logger()
        # Output Debug level info
        log.logger.setLevel(logging.DEBUG)
        # Load the local storage configuration
        conf = LunrConfig.from_storage_conf()
        # If no time provided, use current time
        timestamp = timestamp or time()
        # Init our helpers
        volume = VolumeHelper(conf)
        backup = BackupHelper(conf)

        try:
            # Create the snapshot
            snapshot = volume.create_snapshot(src, id, timestamp)

            # For testing non-snapshot speeds
            #snapshot = volume.get(src)
            #snapshot['backup_id'] = id
            #snapshot['origin'] = src
            #snapshot['timestamp'] = 1338410885.0
            #del snapshot['volume']

            print("Created snap-shot: ", pprint(snapshot))

            with self.timeit(snapshot['size']):
                # Backup the snapshot
                print("Starting Backup")
                backup.save(snapshot, id)

        finally:
            # Delete the snapshot if it was created
            if 'snapshot' in locals():
                self._remove_volume(snapshot['path'])
Ejemplo n.º 3
0
    def backup(self, id=None, src=None, timestamp=None):
        """
        This runs a backup job outside of the storage api,
        which is useful for performance testing backups
        """
        # Set basic Logging
        logging.basicConfig()
        # Get the lunr logger
        log = logger.get_logger()
        # Output Debug level info
        log.logger.setLevel(logging.DEBUG)
        # Load the local storage configuration
        conf = LunrConfig.from_storage_conf()
        # If no time provided, use current time
        timestamp = timestamp or time()
        # Init our helpers
        volume = VolumeHelper(conf)
        backup = BackupHelper(conf)

        try:
            # Create the snapshot
            snapshot = volume.create_snapshot(src, id, timestamp)

            # For testing non-snapshot speeds
            #snapshot = volume.get(src)
            #snapshot['backup_id'] = id
            #snapshot['origin'] = src
            #snapshot['timestamp'] = 1338410885.0
            #del snapshot['volume']

            print("Created snap-shot: ", pprint(snapshot))

            with self.timeit(snapshot['size']):
                # Backup the snapshot
                print("Starting Backup")
                backup.save(snapshot, id)

        finally:
            # Delete the snapshot if it was created
            if 'snapshot' in locals():
                self._remove_volume(snapshot['path'])
Ejemplo n.º 4
0
 def setUp(self):
     IetTest.setUp(self)
     self.tempdir = mkdtemp()
     self.conf = self.config(self.tempdir)
     self.volume = VolumeHelper(self.conf)
     self.backup = BackupHelper(self.conf)
Ejemplo n.º 5
0
class TestBackupHelper(IetTest):

    def setUp(self):
        IetTest.setUp(self)
        self.tempdir = mkdtemp()
        self.conf = self.config(self.tempdir)
        self.volume = VolumeHelper(self.conf)
        self.backup = BackupHelper(self.conf)

    def tearDown(self):
        backup_dir = self.conf.string('disk', 'path', None)
        # Remove the temp dir where backups are created
        shutil.rmtree(self.tempdir)
        IetTest.tearDown(self)

    @classmethod
    def setUpClass(cls):
        pass

    @classmethod
    def tearDownClass(cls):
        pass

    def test_create_snapshot(self):
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        # Assert snapshot values exist
        self.assertEquals(int(snapshot['timestamp']), 123456)
        self.assertEquals(snapshot['backup_id'], backup_id)
        self.assertEquals(snapshot['id'], backup_id)
        self.assertIn('size', snapshot)
        self.assertIn('path', snapshot)
        self.assertIn('origin', snapshot)
        self.assertTrue(path.exists(snapshot['path']))

        # Deleting the origin also removes the snapshot
        self.volume.remove(self.volume.get(volume_id)['path'])

    def test_delete_active_backup_origin_fails(self):
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        volume_id2 = str(uuid4())
        self.volume.create(volume_id2)
        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')
        # Ensure requests to delete the origin fail
        self.assertRaises(ServiceUnavailable, self.volume.delete, volume_id)
        # Should delete ok, no backup running
        self.volume.delete(volume_id2, lock=MockResourceLock())
        # Deleting the origin also removes the snapshot
        self.volume.remove(self.volume.get(volume_id)['path'])

    def test_delete_active_backup_origin_fails_is_isolated(self):
        first_vol_id = 'vol1'
        self.volume.create(first_vol_id)
        second_vol_id = 'vol11'  # contains 'vol1'
        self.volume.create(second_vol_id)
        backup_id = 'backup1'
        second_vol_snapshot = self.volume.create_snapshot(
            second_vol_id, backup_id)
        self.backup.create(second_vol_snapshot, 'backup1',
                           lock=MockResourceLock())
        # delete 'vol1' should not fail because of snapshot on 'vol11'
        self.volume.delete(first_vol_id, lock=MockResourceLock())
        # cleanup
        self.volume.delete(backup_id, lock=MockResourceLock())
        self.volume.delete(second_vol_id, lock=MockResourceLock())

    def test_snapshot_scrub(self):
        block_size = 32768
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        # Get the volume information
        volume = self.volume.get(volume_id)
        # Fill the volume with 'ZERG's
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            for i in xrange(0, size / block_size):
                # 32768 / 4 = 8192
                file.write('ZERG' * (block_size / 4))

        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        # Now that the snapshot is made, simulate users making writes
        # to the origin during a normal backup. This should generate
        # exceptions in the cow
        with directio.open(volume['path']) as file:
            # Overwrite all the zergs.
            for i in xrange(0, size / block_size):
                file.write('A' * block_size)

        # Tell scrub we don't want it to remove the cow after scrubbing
        scrub = Scrub(LunrConfig())

        # Build the cow-zero
        (cow_name, cow_path) = scrub.get_writable_cow(snapshot, volume)

        with directio.open(cow_path) as file:
            size = directio.size(cow_path)
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' in block:
                    self.assert_(True)
                    break

        with directio.open(self._ramdisk) as file:
            size = directio.size(self._ramdisk)
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' in block:
                    self.assert_(True)
                    break

        # Scrub the cow of all exceptions
        scrub.scrub_cow(cow_path)
        scrub.remove_cow(cow_name)

        # Remove & scrub the volume. LVM removes snapshot itself.
        self.volume.remove_lvm_volume(volume)

        # Read full disk for hidden zergs.
        with directio.open(self._ramdisk) as file:
            size = directio.size(self._ramdisk)
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' in block:
                    self.fail("Found zergs on disk: %s" % self._ramdisk)

    def test_writable_cow_multiline_table(self):
        # Let's do some silly math
        size = directio.size(self._ramdisk)
        megs = size / 1024 / 1024
        megs = megs - megs % 4
        # 12 megs for a volume, 4 for lvm itself
        alloc = megs - 12 - 4
        vg = self.conf.string('volume', 'volume_group', None)
        # Reserve a 4m hole at the front, and 8m at the end
        execute('lvcreate', vg, size='4m', name='tmpvol')
        execute('lvcreate', vg, size='%sm' % alloc, name='wasted')
        execute('lvremove', '%s/tmpvol' % vg, force=None)
        foo = execute('pvs', self._ramdisk)
        foo = execute('vgs', vg)
        foo = execute('lvs', vg)
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        volume = self.volume.get(volume_id)
        execute('lvremove', '%s/wasted' % vg, force=None)
        dmname = '%s-%s' % (re.sub('-', '--', vg),
                            re.sub('-', '--', volume_id))
        foo = execute('dmsetup', 'table', dmname)
        self.assert_('\n' in foo)
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')
        scrub = Scrub(LunrConfig())
        (cow_name, cow_path) = scrub.get_writable_cow(snapshot, volume)
        execute('dmsetup', 'remove', cow_name)
        self.assertTrue(True)

    def test_create_backup(self):
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        def callback():
            # Delete the snapshot after completion
            self.volume.delete(snapshot['id'])

        # Create the backup
        self.backup.create(snapshot, backup_id,
                           callback=callback,
                           lock=MockResourceLock())

        # Assert the backup exists in the dir and has the
        # same name as the volume
        backup_dir = self.conf.string('disk', 'path', None)
        self.assertTrue(path.exists(path.join(backup_dir, volume_id)))

        # Deleting the origin also removes the snapshot
        self.volume.remove(self.volume.get(volume_id)['path'])

    def test_restore_backup(self):
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)

        # Write ZERG to the volume
        volume = self.volume.get(volume_id)
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            block_size = 32768
            for i in xrange(0, size / block_size):
                file.write('ZERG' * (block_size / 4))

        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        def callback():
            # Delete the snapshot after completion
            self.volume.delete(snapshot['id'])

        # Create the backup
        self.backup.create(snapshot, backup_id,
                           callback=callback,
                           lock=MockResourceLock())

        # Deleting the origin also removes the snapshot
        self.volume.remove(self.volume.get(volume_id)['path'])

        # Create a Restore Volume
        restore_volume_id = str(uuid4())
        self.volume.create(
            restore_volume_id, backup_source_volume_id=volume_id,
            backup_id=backup_id, lock=MockResourceLock())
        volume = self.volume.get(restore_volume_id)

        # Read the restored volume, it should contain ZERGS
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' not in block:
                    self.fail("zergs missing on disk: %s" % volume['path'])

    def test_overflow_snapshot(self):
        # Better to use conf, but helper is already created.
        self.volume.max_snapshot_bytes = 4 * 1024 * 1024
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        volume = self.volume.get(volume_id)
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        def callback():
            self.volume.delete(snapshot['id'])
            self.fail("didnt get the proper error callback")

        def error_callback():
            self.volume.delete(snapshot['id'])
            error_callback.ran = True
        error_callback.ran = False
        # Overflow the snapshot! Only reserved 4m
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            block_size = 32768
            for i in xrange(0, size / block_size):
                file.write('ZERG' * (block_size / 4))
        with open(snapshot['path']) as file:
            self.assertRaises(IOError, file.read, block_size)
        self.backup.create(
            snapshot, backup_id, callback=callback,
            error_callback=error_callback, lock=MockResourceLock())
        self.assertTrue(error_callback.ran)

        # Make sure scrubbing still happened correctly.
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            block_size = 32768
            for i in xrange(0, size / block_size):
                file.write('\0' * block_size)

        # Read full disk for hidden zergs.
        with directio.open(self._ramdisk) as file:
            size = directio.size(self._ramdisk)
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' in block:
                    self.fail("Found zergs on disk: %s" % self._ramdisk)
Ejemplo n.º 6
0
 def setUp(self):
     IetTest.setUp(self)
     self.tempdir = mkdtemp()
     self.conf = self.config(self.tempdir)
     self.volume = VolumeHelper(self.conf)
     self.backup = BackupHelper(self.conf)
Ejemplo n.º 7
0
class TestBackupHelper(IetTest):
    def setUp(self):
        IetTest.setUp(self)
        self.tempdir = mkdtemp()
        self.conf = self.config(self.tempdir)
        self.volume = VolumeHelper(self.conf)
        self.backup = BackupHelper(self.conf)

    def tearDown(self):
        backup_dir = self.conf.string('disk', 'path', None)
        # Remove the temp dir where backups are created
        shutil.rmtree(self.tempdir)
        IetTest.tearDown(self)

    @classmethod
    def setUpClass(cls):
        pass

    @classmethod
    def tearDownClass(cls):
        pass

    def test_create_snapshot(self):
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        # Assert snapshot values exist
        self.assertEquals(int(snapshot['timestamp']), 123456)
        self.assertEquals(snapshot['backup_id'], backup_id)
        self.assertEquals(snapshot['id'], backup_id)
        self.assertIn('size', snapshot)
        self.assertIn('path', snapshot)
        self.assertIn('origin', snapshot)
        self.assertTrue(path.exists(snapshot['path']))

        # Deleting the origin also removes the snapshot
        self.volume.remove(self.volume.get(volume_id)['path'])

    def test_delete_active_backup_origin_fails(self):
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        volume_id2 = str(uuid4())
        self.volume.create(volume_id2)
        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')
        # Ensure requests to delete the origin fail
        self.assertRaises(ServiceUnavailable, self.volume.delete, volume_id)
        # Should delete ok, no backup running
        self.volume.delete(volume_id2, lock=MockResourceLock())
        # Deleting the origin also removes the snapshot
        self.volume.remove(self.volume.get(volume_id)['path'])

    def test_delete_active_backup_origin_fails_is_isolated(self):
        first_vol_id = 'vol1'
        self.volume.create(first_vol_id)
        second_vol_id = 'vol11'  # contains 'vol1'
        self.volume.create(second_vol_id)
        backup_id = 'backup1'
        second_vol_snapshot = self.volume.create_snapshot(
            second_vol_id, backup_id)
        self.backup.create(second_vol_snapshot,
                           'backup1',
                           lock=MockResourceLock())
        # delete 'vol1' should not fail because of snapshot on 'vol11'
        self.volume.delete(first_vol_id, lock=MockResourceLock())
        # cleanup
        self.volume.delete(backup_id, lock=MockResourceLock())
        self.volume.delete(second_vol_id, lock=MockResourceLock())

    def test_snapshot_scrub(self):
        block_size = 32768
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        # Get the volume information
        volume = self.volume.get(volume_id)
        # Fill the volume with 'ZERG's
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            for i in xrange(0, size / block_size):
                # 32768 / 4 = 8192
                file.write('ZERG' * (block_size / 4))

        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        # Now that the snapshot is made, simulate users making writes
        # to the origin during a normal backup. This should generate
        # exceptions in the cow
        with directio.open(volume['path']) as file:
            # Overwrite all the zergs.
            for i in xrange(0, size / block_size):
                file.write('A' * block_size)

        # Tell scrub we don't want it to remove the cow after scrubbing
        scrub = Scrub(LunrConfig())

        # Build the cow-zero
        (cow_name, cow_path) = scrub.get_writable_cow(snapshot, volume)

        with directio.open(cow_path) as file:
            size = directio.size(cow_path)
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' in block:
                    self.assert_(True)
                    break

        with directio.open(self._ramdisk) as file:
            size = directio.size(self._ramdisk)
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' in block:
                    self.assert_(True)
                    break

        # Scrub the cow of all exceptions
        scrub.scrub_cow(cow_path)
        scrub.remove_cow(cow_name)

        # Remove & scrub the volume. LVM removes snapshot itself.
        self.volume.remove_lvm_volume(volume)

        # Read full disk for hidden zergs.
        with directio.open(self._ramdisk) as file:
            size = directio.size(self._ramdisk)
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' in block:
                    self.fail("Found zergs on disk: %s" % self._ramdisk)

    def test_writable_cow_multiline_table(self):
        # Let's do some silly math
        size = directio.size(self._ramdisk)
        megs = size / 1024 / 1024
        megs = megs - megs % 4
        # 12 megs for a volume, 4 for lvm itself
        alloc = megs - 12 - 4
        vg = self.conf.string('volume', 'volume_group', None)
        # Reserve a 4m hole at the front, and 8m at the end
        execute('lvcreate', vg, size='4m', name='tmpvol')
        execute('lvcreate', vg, size='%sm' % alloc, name='wasted')
        execute('lvremove', '%s/tmpvol' % vg, force=None)
        foo = execute('pvs', self._ramdisk)
        foo = execute('vgs', vg)
        foo = execute('lvs', vg)
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        volume = self.volume.get(volume_id)
        execute('lvremove', '%s/wasted' % vg, force=None)
        dmname = '%s-%s' % (re.sub('-', '--', vg), re.sub(
            '-', '--', volume_id))
        foo = execute('dmsetup', 'table', dmname)
        self.assert_('\n' in foo)
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')
        scrub = Scrub(LunrConfig())
        (cow_name, cow_path) = scrub.get_writable_cow(snapshot, volume)
        execute('dmsetup', 'remove', cow_name)
        self.assertTrue(True)

    def test_create_backup(self):
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        def callback():
            # Delete the snapshot after completion
            self.volume.delete(snapshot['id'])

        # Create the backup
        self.backup.create(snapshot,
                           backup_id,
                           callback=callback,
                           lock=MockResourceLock())

        # Assert the backup exists in the dir and has the
        # same name as the volume
        backup_dir = self.conf.string('disk', 'path', None)
        self.assertTrue(path.exists(path.join(backup_dir, volume_id)))

        # Deleting the origin also removes the snapshot
        self.volume.remove(self.volume.get(volume_id)['path'])

    def test_restore_backup(self):
        # Create a Volume
        volume_id = str(uuid4())
        self.volume.create(volume_id)

        # Write ZERG to the volume
        volume = self.volume.get(volume_id)
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            block_size = 32768
            for i in xrange(0, size / block_size):
                file.write('ZERG' * (block_size / 4))

        # Create a snap-shot with a timestamp of 123456
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        def callback():
            # Delete the snapshot after completion
            self.volume.delete(snapshot['id'])

        # Create the backup
        self.backup.create(snapshot,
                           backup_id,
                           callback=callback,
                           lock=MockResourceLock())

        # Deleting the origin also removes the snapshot
        self.volume.remove(self.volume.get(volume_id)['path'])

        # Create a Restore Volume
        restore_volume_id = str(uuid4())
        self.volume.create(restore_volume_id,
                           backup_source_volume_id=volume_id,
                           backup_id=backup_id,
                           lock=MockResourceLock())
        volume = self.volume.get(restore_volume_id)

        # Read the restored volume, it should contain ZERGS
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' not in block:
                    self.fail("zergs missing on disk: %s" % volume['path'])

    def test_overflow_snapshot(self):
        # Better to use conf, but helper is already created.
        self.volume.max_snapshot_bytes = 4 * 1024 * 1024
        volume_id = str(uuid4())
        self.volume.create(volume_id)
        volume = self.volume.get(volume_id)
        backup_id = str(uuid4())
        snapshot = self.volume.create_snapshot(volume_id, backup_id, '123456')

        def callback():
            self.volume.delete(snapshot['id'])
            self.fail("didnt get the proper error callback")

        def error_callback():
            self.volume.delete(snapshot['id'])
            error_callback.ran = True

        error_callback.ran = False
        # Overflow the snapshot! Only reserved 4m
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            block_size = 32768
            for i in xrange(0, size / block_size):
                file.write('ZERG' * (block_size / 4))
        with open(snapshot['path']) as file:
            self.assertRaises(IOError, file.read, block_size)
        self.backup.create(snapshot,
                           backup_id,
                           callback=callback,
                           error_callback=error_callback,
                           lock=MockResourceLock())
        self.assertTrue(error_callback.ran)

        # Make sure scrubbing still happened correctly.
        with directio.open(volume['path']) as file:
            size = directio.size(volume['path'])
            block_size = 32768
            for i in xrange(0, size / block_size):
                file.write('\0' * block_size)

        # Read full disk for hidden zergs.
        with directio.open(self._ramdisk) as file:
            size = directio.size(self._ramdisk)
            for i in xrange(0, size / block_size):
                block = file.read(block_size)
                if 'ZERG' in block:
                    self.fail("Found zergs on disk: %s" % self._ramdisk)