예제 #1
0
    def test_create_new(self, zpools, config_send):
        """Tests pyznap over 10 years and checks if newly created filesystems are correctly
        replicated"""

        fs0, fs1 = zpools
        ssh = fs1.ssh
        fs0.destroy(force=True)
        fs1.destroy(force=True)

        # have to start at 1969 as faketime only goes from 1969 to 2068
        dates = [datetime(1969 + i, 1, 1) for i in range(10)]

        for n,date in enumerate(dates):
            # at every step create a new subfilesystem
            zfs.create('{:s}/sub{:d}'.format(fs0.name, n))

            faketime = ['faketime', date.strftime('%y-%m-%d %H:%M:%S')]
            pyznap_take = faketime + ['pyznap', '--config', config_send, 'snap', '--take']
            pyznap_clean = faketime + ['pyznap', '--config', config_send, 'snap', '--clean']
            pyznap_send = faketime + ['pyznap', '--config', config_send, 'send']

            # take, send & clean snaps every 1y
            _, _ = Popen(pyznap_take).communicate()
            _, _ = Popen(pyznap_send).communicate()
            _, _ = Popen(pyznap_clean).communicate()

            # get all snapshots on fs0
            snapshots = {'frequent': [], 'hourly': [], 'daily': [], 'weekly': [], 'monthly': [], 'yearly': []}
            for snap in fs0.snapshots():
                snap_type = snap.name.split('_')[-1]
                snapshots[snap_type].append(snap)
            # check if there are not too many snapshots taken
            for snap_type, snaps in snapshots.items():
                assert len(snaps) <= SNAPSHOTS_REF[snap_type]
            # check if after N_FREQUENT runs there are N_FREQUENT 'frequent' snapshots
            if n+1 >= N_FREQUENT:
                assert len(snapshots['frequent']) == SNAPSHOTS_REF['frequent']
            # check if after N-HOURLY runs there are N-HOURLY 'hourly' snapshots
            if n+1 >= N_HOURLY:
                assert len(snapshots['hourly']) == SNAPSHOTS_REF['hourly']
            # check if after N_DAILY runs there are N_DAILY 'daily' snapshots
            if n+1 >= N_DAILY:
                assert len(snapshots['daily']) == SNAPSHOTS_REF['daily']
            # check if after N_WEEKLY runs there are N_WEEKLY 'weekly' snapshots
            if n+1 >= N_WEEKLY:
                assert len(snapshots['weekly']) == SNAPSHOTS_REF['weekly']
            # check if after N_MONTHLY runs there are N_MONTHLY 'monthly' snapshots
            if n+1 >= N_MONTHLY:
                assert len(snapshots['monthly']) == SNAPSHOTS_REF['monthly']
            # check if after N_YEARLY runs there are N_YEARLY 'yearly' snapshots
            if n+1 >= N_YEARLY:
                assert len(snapshots['yearly']) == SNAPSHOTS_REF['yearly']

            # check if filesystem is completely replicated on dest
            fs0_children = [child.name.replace(fs0.name, '') for child in zfs.find(fs0.name, types=['all'])[1:]]
            fs1_children = [child.name.replace(fs1.name, '') for child in zfs.find(fs1.name, types=['all'], ssh=ssh)[1:]]
            assert set(fs0_children) == set(fs1_children)
예제 #2
0
    def test_take_snapshot_recursive(self, zpools):
        _, fs = zpools
        ssh = fs.ssh

        fs.destroy(force=True)
        config = [{'name': 'ssh:{:d}:{}'.format(PORT, fs), 'key': KEY, 'frequent': 1, 'hourly': 1,
                   'daily': 1, 'weekly': 1, 'monthly': 1, 'yearly': 1, 'snap': True}]
        take_config(config)
        fs.snapshots()[-1].destroy(force=True)
        fs.snapshots()[-1].destroy(force=True)

        sub1 = zfs.create('{:s}/sub1'.format(fs.name), ssh=ssh)
        abc = zfs.create('{:s}/sub1/abc'.format(fs.name), ssh=ssh)
        sub1_abc = zfs.create('{:s}/sub1_abc'.format(fs.name), ssh=ssh)
        config += [{'name': 'ssh:{:d}:{}/sub1'.format(PORT, fs), 'key': KEY, 'frequent': 1, 'hourly': 1,
                    'daily': 1, 'weekly': 1, 'monthly': 1, 'yearly': 1, 'snap': False}]
        take_config(config)

        # Check fs
        snapshots = {'frequent': [], 'hourly': [], 'daily': [], 'weekly': [], 'monthly': [], 'yearly': []}
        for snap in fs.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[0][snap_type]

        # Check sub1
        snapshots = {'frequent': [], 'hourly': [], 'daily': [], 'weekly': [], 'monthly': [], 'yearly': []}
        for snap in sub1.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[0][snap_type]

        # Check abc
        snapshots = {'frequent': [], 'hourly': [], 'daily': [], 'weekly': [], 'monthly': [], 'yearly': []}
        for snap in abc.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[0][snap_type]

        # Check sub1_abc
        snapshots = {'frequent': [], 'hourly': [], 'daily': [], 'weekly': [], 'monthly': [], 'yearly': []}
        for snap in sub1_abc.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[0][snap_type]
예제 #3
0
    def test_send_compress(self, zpools):
        """Checks if send_snap totally replicates a filesystem"""
        fs1, fs0 = zpools # here fs0 is the remote pool
        ssh = fs0.ssh

        fs0.destroy(force=True)
        fs1.destroy(force=True)

        fs0.snapshot('snap0')
        zfs.create('{:s}/sub1'.format(fs0.name), ssh=ssh)
        fs0.snapshot('snap1', recursive=True)
        zfs.create('{:s}/sub2'.format(fs0.name), ssh=ssh)
        fs0.snapshot('snap2', recursive=True)
        fs0.snapshot('snap3', recursive=True)
        zfs.create('{:s}/sub2/abc'.format(fs0.name), ssh=ssh)
        fs0.snapshot('snap4', recursive=True)
        fs0.snapshot('snap5', recursive=True)

        for compression in ['none', 'lzop', 'lz4']:
            fs1.destroy(force=True)
            config = [{'name': 'ssh:{:d}:{}'.format(PORT, fs0), 'key': KEY, 'dest': [fs1.name], 'compress': [compression]}]
            send_config(config)

            fs0_children = [child.name.replace(fs0.name, '') for child in zfs.find(fs0.name, types=['all'], ssh=ssh)[1:]]
            fs1_children = [child.name.replace(fs1.name, '') for child in zfs.find(fs1.name, types=['all'])[1:]]
            assert set(fs0_children) == set(fs1_children)
예제 #4
0
    def test_send_incremental(self, zpools):
        fs1, fs0 = zpools # here fs0 is the remote pool
        ssh = fs0.ssh

        fs0.destroy(force=True)
        fs1.destroy(force=True)

        fs0.snapshot('snap0', recursive=True)
        zfs.create('{:s}/sub1'.format(fs0.name), ssh=ssh)
        fs0.snapshot('snap1', recursive=True)
        config = [{'name': 'ssh:{:d}:{}'.format(PORT, fs0), 'key': KEY, 'dest': [fs1.name], 'compress': None}]
        send_config(config)
        fs0_children = [child.name.replace(fs0.name, '') for child in zfs.find(fs0.name, types=['all'], ssh=ssh)[1:]]
        fs1_children = [child.name.replace(fs1.name, '') for child in zfs.find(fs1.name, types=['all'])[1:]]
        assert set(fs0_children) == set(fs1_children)

        zfs.create('{:s}/sub2'.format(fs0.name), ssh=ssh)
        fs0.snapshot('snap2', recursive=True)
        config = [{'name': 'ssh:{:d}:{}'.format(PORT, fs0), 'key': KEY, 'dest': [fs1.name], 'compress': None}]
        send_config(config)
        fs0_children = [child.name.replace(fs0.name, '') for child in zfs.find(fs0.name, types=['all'], ssh=ssh)[1:]]
        fs1_children = [child.name.replace(fs1.name, '') for child in zfs.find(fs1.name, types=['all'])[1:]]
        assert set(fs0_children) == set(fs1_children)

        zfs.create('{:s}/sub3'.format(fs0.name), ssh=ssh)
        fs0.snapshot('snap3', recursive=True)
        config = [{'name': 'ssh:{:d}:{}'.format(PORT, fs0), 'key': KEY, 'dest': [fs1.name], 'compress': None}]
        send_config(config)
        fs0_children = [child.name.replace(fs0.name, '') for child in zfs.find(fs0.name, types=['all'], ssh=ssh)[1:]]
        fs1_children = [child.name.replace(fs1.name, '') for child in zfs.find(fs1.name, types=['all'])[1:]]
        assert set(fs0_children) == set(fs1_children)
예제 #5
0
def create_dataset(name, name_log, ssh=None, dry_run=False):
    """Creates a dataset and logs success/fail

    Parameters
    ----------
    name : {str}
        Name of the dataset to be created
    name_log : {str}
        Name used for logging
    ssh : {SSH}, optional
        Open ssh connection, by default None
    dry_run : {boolean}, optional
        Dry run, don't change ZFS pool

    Returns
    -------
    int
        0 if success, 1 if not
    """
    logger = logging.getLogger(__name__)
    try:
        zfs.create(name, ssh=ssh, force=True, dry_run=dry_run)
    except CalledProcessError as err:
        message = err.stderr.rstrip()
        if message == "filesystem successfully created, but it may only be mounted by root":
            logger.info(
                'Successfully created {:s}, but cannot mount as non-root...'.
                format(name_log))
            return 0
        else:
            logger.info('Error while creating {}: \'{:s}\'...'.format(
                name_log, message))
            return 1
    except Exception as err:
        logger.error('Error while creating {:s}: {}...'.format(name_log, err))
        return 1
    else:
        logger.info('Successfully created {:s}...'.format(name_log))
        return 0
예제 #6
0
    def test_send_incremental(self, zpools):
        fs0, fs1 = zpools
        fs0.destroy(force=True)
        fs1.destroy(force=True)
        config = [{'name': fs0.name, 'dest': [fs1.name]}]

        fs0.snapshot('snap0', recursive=True)
        zfs.create('{:s}/sub1'.format(fs0.name))
        fs0.snapshot('snap1', recursive=True)
        send_config(config)
        fs0_children = [
            child.name.replace(fs0.name, '')
            for child in zfs.find(fs0.name, types=['all'])[1:]
        ]
        fs1_children = [
            child.name.replace(fs1.name, '')
            for child in zfs.find(fs1.name, types=['all'])[1:]
        ]
        assert set(fs0_children) == set(fs1_children)

        zfs.create('{:s}/sub2'.format(fs0.name))
        fs0.snapshot('snap2', recursive=True)
        send_config(config)
        fs0_children = [
            child.name.replace(fs0.name, '')
            for child in zfs.find(fs0.name, types=['all'])[1:]
        ]
        fs1_children = [
            child.name.replace(fs1.name, '')
            for child in zfs.find(fs1.name, types=['all'])[1:]
        ]
        assert set(fs0_children) == set(fs1_children)

        zfs.create('{:s}/sub3'.format(fs0.name))
        fs0.snapshot('snap3', recursive=True)
        send_config(config)
        fs0_children = [
            child.name.replace(fs0.name, '')
            for child in zfs.find(fs0.name, types=['all'])[1:]
        ]
        fs1_children = [
            child.name.replace(fs1.name, '')
            for child in zfs.find(fs1.name, types=['all'])[1:]
        ]
        assert set(fs0_children) == set(fs1_children)
예제 #7
0
    def test_send_full(self, zpools):
        """Checks if send_snap totally replicates a filesystem"""
        fs0, fs1 = zpools
        fs0.destroy(force=True)
        fs1.destroy(force=True)
        config = [{'name': fs0.name, 'dest': [fs1.name]}]

        fs0.snapshot('snap0')
        zfs.create('{:s}/sub1'.format(fs0.name))
        fs0.snapshot('snap1', recursive=True)
        zfs.create('{:s}/sub2'.format(fs0.name))
        fs0.snapshot('snap2', recursive=True)
        zfs.create('{:s}/sub3'.format(fs0.name))
        fs0.snapshot('snap3', recursive=True)
        fs0.snapshot('snap4', recursive=True)
        fs0.snapshot('snap5', recursive=True)
        zfs.create('{:s}/sub3/abc'.format(fs0.name))
        fs0.snapshot('snap6', recursive=True)
        zfs.create('{:s}/sub3/abc_abc'.format(fs0.name))
        fs0.snapshot('snap7', recursive=True)
        zfs.create('{:s}/sub3/efg'.format(fs0.name))
        fs0.snapshot('snap8', recursive=True)
        fs0.snapshot('snap9', recursive=True)
        send_config(config)

        fs0_children = [
            child.name.replace(fs0.name, '')
            for child in zfs.find(fs0.name, types=['all'])[1:]
        ]
        fs1_children = [
            child.name.replace(fs1.name, '')
            for child in zfs.find(fs1.name, types=['all'])[1:]
        ]
        assert set(fs0_children) == set(fs1_children)
예제 #8
0
    def test_clean_recursive(self, zpools):
        fs, _ = zpools
        fs.destroy(force=True)
        sub1 = zfs.create('{:s}/sub1'.format(fs.name))
        abc = zfs.create('{:s}/sub1/abc'.format(fs.name))
        abc_efg = zfs.create('{:s}/sub1/abc_efg'.format(fs.name))
        sub2 = zfs.create('{:s}/sub2'.format(fs.name))
        efg = zfs.create('{:s}/sub2/efg'.format(fs.name))
        hij = zfs.create('{:s}/sub2/efg/hij'.format(fs.name))
        klm = zfs.create('{:s}/sub2/efg/hij/klm'.format(fs.name))
        sub3 = zfs.create('{:s}/sub3'.format(fs.name))

        config = [{
            'name': fs.name,
            'frequent': 1,
            'hourly': 1,
            'daily': 1,
            'weekly': 1,
            'monthly': 1,
            'yearly': 1,
            'snap': True
        }]
        take_config(config)

        config = [{
            'name': fs.name,
            'frequent': 1,
            'hourly': 0,
            'daily': 1,
            'weekly': 0,
            'monthly': 0,
            'yearly': 0,
            'clean': True
        }, {
            'name': '{}/sub2'.format(fs),
            'frequent': 0,
            'hourly': 1,
            'daily': 0,
            'weekly': 1,
            'monthly': 0,
            'yearly': 1,
            'clean': True
        }, {
            'name': '{}/sub3'.format(fs),
            'frequent': 1,
            'hourly': 0,
            'daily': 1,
            'weekly': 0,
            'monthly': 1,
            'yearly': 0,
            'clean': False
        }, {
            'name': '{}/sub1/abc'.format(fs),
            'frequent': 0,
            'hourly': 0,
            'daily': 0,
            'weekly': 1,
            'monthly': 1,
            'yearly': 1,
            'clean': True
        }, {
            'name': '{}/sub2/efg/hij'.format(fs),
            'frequent': 0,
            'hourly': 0,
            'daily': 0,
            'weekly': 0,
            'monthly': 0,
            'yearly': 0,
            'clean': True
        }]
        clean_config(config)

        # Check parent filesystem
        snapshots = {
            'frequent': [],
            'hourly': [],
            'daily': [],
            'weekly': [],
            'monthly': [],
            'yearly': []
        }
        for snap in fs.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[0][snap_type]
        # Check sub1
        snapshots = {
            'frequent': [],
            'hourly': [],
            'daily': [],
            'weekly': [],
            'monthly': [],
            'yearly': []
        }
        for snap in sub1.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[0][snap_type]
        # Check sub1/abc
        snapshots = {
            'frequent': [],
            'hourly': [],
            'daily': [],
            'weekly': [],
            'monthly': [],
            'yearly': []
        }
        for snap in abc.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[3][snap_type]
        # Check sub1/abc_efg
        snapshots = {
            'frequent': [],
            'hourly': [],
            'daily': [],
            'weekly': [],
            'monthly': [],
            'yearly': []
        }
        for snap in abc_efg.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[0][snap_type]
        # Check sub2
        snapshots = {
            'frequent': [],
            'hourly': [],
            'daily': [],
            'weekly': [],
            'monthly': [],
            'yearly': []
        }
        for snap in sub2.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[1][snap_type]
        # Check sub2/efg
        snapshots = {
            'frequent': [],
            'hourly': [],
            'daily': [],
            'weekly': [],
            'monthly': [],
            'yearly': []
        }
        for snap in efg.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[1][snap_type]
        # Check sub2/efg/hij
        snapshots = {
            'frequent': [],
            'hourly': [],
            'daily': [],
            'weekly': [],
            'monthly': [],
            'yearly': []
        }
        for snap in hij.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[4][snap_type]
        # Check sub2/efg/hij/klm
        snapshots = {
            'frequent': [],
            'hourly': [],
            'daily': [],
            'weekly': [],
            'monthly': [],
            'yearly': []
        }
        for snap in klm.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == config[4][snap_type]
        # Check sub3
        snapshots = {
            'frequent': [],
            'hourly': [],
            'daily': [],
            'weekly': [],
            'monthly': [],
            'yearly': []
        }
        for snap in sub3.snapshots():
            snap_type = snap.name.split('_')[-1]
            snapshots[snap_type].append(snap)

        for snap_type, snaps in snapshots.items():
            assert len(snaps) == 1
예제 #9
0
    def test_send_raw(self, zpools):
        """Checks if raw_send works"""
        fs0, fs1 = zpools
        fs0.destroy(force=True)
        fs1.destroy(force=True)

        raw_send = ['yes']
        config = [{'name': fs0.name, 'dest': [fs1.name], 'raw_send': raw_send}]

        zfs.create('{:s}/sub1'.format(fs0.name), props={'compression': 'gzip'})
        zfs.create('{:s}/sub2'.format(fs0.name), props={'compression': 'lz4'})
        zfs.create('{:s}/sub3'.format(fs0.name), props={'compression': 'gzip'})
        zfs.create('{:s}/sub3/abc'.format(fs0.name))
        zfs.create('{:s}/sub3/abc_abc'.format(fs0.name))
        zfs.create('{:s}/sub3/efg'.format(fs0.name))
        fs0.snapshot('snap', recursive=True)
        send_config(config)

        fs0_children = set([
            child.name.replace(fs0.name, '')
            for child in zfs.find(fs0.name, types=['all'])[1:]
        ])
        fs1_children = set([
            child.name.replace(fs1.name, '')
            for child in zfs.find(fs1.name, types=['all'])[1:]
        ])

        assert set(fs0_children) == set(fs1_children)
예제 #10
0
    def test_send_exclude(self, zpools):
        """Checks if exclude rules work"""
        fs0, fs1 = zpools
        fs0.destroy(force=True)
        fs1.destroy(force=True)

        exclude = ['*/sub1', '*/sub3/abc', '*/sub3/efg']
        config = [{'name': fs0.name, 'dest': [fs1.name], 'exclude': [exclude]}]

        zfs.create('{:s}/sub1'.format(fs0.name))
        zfs.create('{:s}/sub2'.format(fs0.name))
        zfs.create('{:s}/sub3'.format(fs0.name))
        zfs.create('{:s}/sub3/abc'.format(fs0.name))
        zfs.create('{:s}/sub3/abc_abc'.format(fs0.name))
        zfs.create('{:s}/sub3/efg'.format(fs0.name))
        fs0.snapshot('snap', recursive=True)
        send_config(config)

        fs0_children = set([
            child.name.replace(fs0.name, '')
            for child in zfs.find(fs0.name, types=['all'])[1:]
        ])
        fs1_children = set([
            child.name.replace(fs1.name, '')
            for child in zfs.find(fs1.name, types=['all'])[1:]
        ])
        # remove unwanted datasets/snapshots
        for match in exclude:
            fs0_children -= set(fnmatch.filter(fs0_children, match))
            fs0_children -= set(fnmatch.filter(fs0_children, match + '@snap'))

        assert set(fs0_children) == set(fs1_children)
예제 #11
0
    def test_send_exclude(self, zpools):
        """Checks if send_snap totally replicates a filesystem"""
        fs1, fs0 = zpools # here fs0 is the remote pool
        ssh = fs0.ssh
        fs0.destroy(force=True)
        fs1.destroy(force=True)

        exclude = ['*/sub1', '*/sub3/abc', '*/sub3/efg']
        config = [{'name': 'ssh:{:d}:{}'.format(PORT, fs0), 'dest': [fs1.name], 'exclude': [exclude]}]

        zfs.create('{:s}/sub1'.format(fs0.name), ssh=ssh)
        zfs.create('{:s}/sub2'.format(fs0.name), ssh=ssh)
        zfs.create('{:s}/sub3'.format(fs0.name), ssh=ssh)
        zfs.create('{:s}/sub3/abc'.format(fs0.name), ssh=ssh)
        zfs.create('{:s}/sub3/abc_abc'.format(fs0.name), ssh=ssh)
        zfs.create('{:s}/sub3/efg'.format(fs0.name), ssh=ssh)
        fs0.snapshot('snap', recursive=True)
        send_config(config)

        fs0_children = set([child.name.replace(fs0.name, '') for child in zfs.find(fs0.name, types=['all'], ssh=ssh)[1:]])
        fs1_children = set([child.name.replace(fs1.name, '') for child in zfs.find(fs1.name, types=['all'])[1:]])
        # remove unwanted datasets/snapshots
        for match in exclude:
            fs0_children -= set(fnmatch.filter(fs0_children, match))
            fs0_children -= set(fnmatch.filter(fs0_children, match + '@snap'))

        assert set(fs0_children) == set(fs1_children)