예제 #1
0
    def testDestroyExpiredZFSSnapshots_errorCaseIsFalse_destroysSnapshots(
            self, mock_find_snapshots_older_than, mock_get_current_datetime):
        FLAGS.ssh_path = '/fake/ssh'
        FLAGS.ssh_port = 1234
        FLAGS.remote_user = '******'
        mock_find_snapshots_older_than.return_value = [
            'zfs/homedirs@fake-prefix-2014-01-05--0630',
            'zfs/homedirs@fake-prefix-2014-01-06--0648'
        ]
        mock_get_current_datetime.return_value = datetime.datetime(2014, 4, 1)
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = zfs.ZFSLVMBackup(label='unused_label',
                                  source_hostname='unused',
                                  rsync_dst='unused_dst_host:/unused_dst',
                                  zfs_hostname='fake_zfs_host',
                                  dataset_name='unused_pool/unused_dataset',
                                  snapshot_expiration_days=30,
                                  settings_path=None,
                                  command_runner=mock_command_runner)
        expected_call1 = mock.call([
            '/fake/ssh', '-p', '1234', 'fake_user@fake_zfs_host', 'zfs',
            'destroy', 'zfs/homedirs@fake-prefix-2014-01-05--0630'
        ], False)
        expected_call2 = mock.call([
            '/fake/ssh', '-p', '1234', 'fake_user@fake_zfs_host', 'zfs',
            'destroy', 'zfs/homedirs@fake-prefix-2014-01-06--0648'
        ], False)

        backup._destroy_expired_zfs_snapshots(30, error_case=False)

        self.assertEqual(mock_command_runner.run.mock_calls,
                         [expected_call1, expected_call2])
예제 #2
0
    def testCreateSnapshots_multipleSnapshots_createsSnapshots(self):
        FLAGS.snapshot_suffix = '-fake_backup'
        mock_command_runner = test_lib.GetMockCommandRunner()
        # Note that setting source_hostname to 'localhost' prevents the command
        # that is run from being prefixed with an ssh command.
        backup = FakeBackup(source_hostname='localhost',
                            label='unused',
                            settings_path=None,
                            command_runner=mock_command_runner)
        expected_call_fakevolume1 = mock.call([
            'lvcreate', '-s', '-L', '1G', 'fake_volume_group/fake_volume1',
            '-n', 'fake_volume1-fake_backup'
        ], False)
        expected_call_fakevolume2 = mock.call([
            'lvcreate', '-s', '-L', '1G', 'fake_volume_group/fake_volume2',
            '-n', 'fake_volume2-fake_backup'
        ], False)

        backup.add_volume('fake_volume_group/fake_volume1', '/etc')
        backup.add_volume('fake_volume_group/fake_volume2', '/var')
        backup.run()

        mock_command_runner.run.assert_has_calls(
            [expected_call_fakevolume1, expected_call_fakevolume2],
            any_order=True)
예제 #3
0
    def testFindSnapshotsOlderThan_returnsOnlySnapshotsOlderThanX(
            self, mock_get_snapshot_creation_time, mock_get_current_datetime):
        FLAGS.zfs_snapshot_prefix = 'fake-prefix-'
        FLAGS.zfs_snapshot_timestamp_format = '%Y-%m-%d--%H%M'
        mock_get_snapshot_creation_time.side_effect = ([
            datetime.datetime(2014, 1, 5),
            datetime.datetime(2014, 3, 6)
        ])
        mock_get_current_datetime.return_value = datetime.datetime(2014, 4, 1)
        fake_stdout = ('zfs/homedirs\tfilesystem\n'
                       'zfs/homedirs@fake-prefix-2014-01-05--0630\tsnapshot\n'
                       'zfs/homedirs@fake-prefix-2014-03-06--0648\tsnapshot\n')
        mock_command_runner = test_lib.GetMockCommandRunner()
        mock_command_runner.run.return_value = (fake_stdout, str(), 0)
        backup = zfs.ZFSLVMBackup(label='unused_label',
                                  source_hostname='unused',
                                  rsync_dst='unused_dst_host:/unused_dst',
                                  zfs_hostname='unused_zfs_host',
                                  dataset_name='unused_pool/unused_dataset',
                                  snapshot_expiration_days=30,
                                  settings_path=None,
                                  command_runner=mock_command_runner)

        snapshots = backup._find_snapshots_older_than(30)

        self.assertEqual(snapshots,
                         ['zfs/homedirs@fake-prefix-2014-01-05--0630'])
예제 #4
0
    def testCreateSnapshots_multipleSnapshots_addsSnapshotsToTracker(self):
        FLAGS.snapshot_mount_root = '/fake_root'
        FLAGS.snapshot_suffix = '-fake_backup'
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = FakeBackup(source_hostname='localhost',
                            label='fake_backup',
                            settings_path=None,
                            command_runner=mock_command_runner)
        expected_value = [
            {
                'lv_path': 'fake_volume_group/fake_volume1-fake_backup',
                'mount_path': '/fake_root/fake_backup/etc',
                'mount_options': None,
                'created': True,
                'mount_point_created': False,
                'mounted': False,
            },
            {
                'lv_path': 'fake_volume_group/fake_volume2-fake_backup',
                'mount_path': '/fake_root/fake_backup/var',
                'mount_options': None,
                'created': True,
                'mount_point_created': False,
                'mounted': False,
            },
        ]

        backup.add_volume('fake_volume_group/fake_volume1', '/etc')
        backup.add_volume('fake_volume_group/fake_volume2', '/var')
        backup._create_snapshots()

        self.assertListEqual(expected_value, backup._lv_snapshots)
예제 #5
0
    def testMountSnapshots_withoutMountOptions_mountsWithoutMountOptions(self):
        FLAGS.snapshot_mount_root = '/fake_root'
        FLAGS.snapshot_suffix = '-fake_backup'
        mock_command_runner = test_lib.GetMockCommandRunner()
        # Note that setting source_hostname to 'localhost' prevents the command
        # that is run from being prefixed with an ssh command.
        backup = FakeBackup(source_hostname='localhost',
                            label='fake_backup',
                            settings_path=None,
                            command_runner=mock_command_runner)
        expected_call_fakevolume1 = mock.call([
            'mount', '/dev/fake_volume_group/fake_volume1-fake_backup',
            '/fake_root/fake_backup/etc'
        ], False)
        expected_call_fakevolume2 = mock.call([
            'mount', '/dev/fake_volume_group/fake_volume2-fake_backup',
            '/fake_root/fake_backup/var'
        ], False)

        backup.add_volume('fake_volume_group/fake_volume1', '/etc')
        backup.add_volume('fake_volume_group/fake_volume2', '/var')
        backup.run()

        mock_command_runner.AssertCallsInOrder(
            [expected_call_fakevolume1, expected_call_fakevolume2])
예제 #6
0
    def testWorkflowRunsInCorrectOrder(self, mock_create_snapshots,
                                       mock_mount_snapshots,
                                       mock_umount_snapshots,
                                       mock_delete_snapshots,
                                       mock_run_custom_workflow):
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = FakeBackup(source_hostname='unused',
                            label='unused',
                            settings_path=None,
                            command_runner=mock_command_runner)
        # Attach mocks to manager mock so we can track their call order.
        manager_mock = mock.MagicMock()
        manager_mock.attach_mock(mock_create_snapshots, '_create_snapshots')
        manager_mock.attach_mock(mock_mount_snapshots, '_mount_snapshots')
        manager_mock.attach_mock(mock_umount_snapshots, '_umount_snapshots')
        manager_mock.attach_mock(mock_delete_snapshots, '_delete_snapshots')
        manager_mock.attach_mock(mock_run_custom_workflow,
                                 '_run_custom_workflow')
        # Create mock.call objects and defined their expected call order.
        create_snapshots_call = mock.call._create_snapshots()
        mount_snapshots_call = mock.call._mount_snapshots()
        umount_snapshots_call = mock.call._umount_snapshots(error_case=False)
        delete_snapshots_call = mock.call._delete_snapshots(error_case=False)
        run_custom_workflow_call = mock.call._run_custom_workflow()
        expected_calls = [
            create_snapshots_call, mount_snapshots_call,
            run_custom_workflow_call, umount_snapshots_call,
            delete_snapshots_call
        ]

        backup.add_volume('fake_volume_group/fake_volume1', '/unused')
        backup.run()

        test_lib.AssertCallsInOrder(manager_mock, expected_calls)
예제 #7
0
    def testCreateZFSSnapshot_errorCaseIsFalse_createsSnapshot(
            self, mock_get_current_datetime):
        FLAGS.zfs_snapshot_timestamp_format = '%Y-%m-%d--%H%M'
        FLAGS.zfs_snapshot_prefix = 'fake-prefix-'
        FLAGS.remote_user = '******'
        FLAGS.ssh_path = '/fake/ssh'
        FLAGS.ssh_port = 1234
        mock_get_current_datetime.return_value = datetime.datetime(
            2015, 1, 2, 3, 4)
        mock_command_runner = test_lib.GetMockCommandRunner()
        # Note that setting source_hostname to 'localhost' prevents the command
        # that is run from being prefixed with an ssh command.
        backup = zfs.ZFSLVMBackup(label='unused_label',
                                  source_hostname='localhost',
                                  rsync_dst='unused_dst_host:/unused_dst',
                                  zfs_hostname='fake_zfs_host',
                                  dataset_name='fake_pool/fake_dataset',
                                  snapshot_expiration_days=30,
                                  settings_path=None,
                                  command_runner=mock_command_runner)

        backup._create_zfs_snapshot(error_case=False)

        mock_command_runner.run.assert_called_once_with([
            '/fake/ssh', '-p', '1234', 'fake_user@fake_zfs_host', 'zfs',
            'snapshot', 'fake_pool/fake_dataset@fake-prefix-2015-01-02--0304'
        ], False)
예제 #8
0
    def testRunCommand_commandIsNotStringOrList_raisesException(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        with self.assertRaises(TypeError):
            test_workflow.run_command(None)
예제 #9
0
    def testRunCommand_commandHasNonZeroExitCode_rasiesException(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        # Return empty strings for stdout and stderr and 1 for the exit code.
        mock_command_runner.run.return_value = (str(), str(), 1)
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        with self.assertRaises(workflow.NonZeroExitCode):
            test_workflow.run_command('test_command')
예제 #10
0
    def testRunCommand_commandIsList_commandIsRunWithoutShell(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        test_workflow.run_command(
            ['test_command', '--test_flag', 'test_arg'], host='localhost')

        mock_command_runner.run.assert_called_once_with(
            ['test_command', '--test_flag', 'test_arg'], False)
예제 #11
0
    def testRunCommand_commandIsString_commandIsRunInShell(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        test_workflow.run_command(
            'test_command --test_flag test_arg', host='localhost')

        mock_command_runner.run.assert_called_once_with(
            'test_command --test_flag test_arg', True)
예제 #12
0
    def testMountSnapshots_mountPointAlreadyExists_backupFails(
            self, mock_ismount):
        mock_ismount.return_value = True
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = FakeBackup(source_hostname='unused',
                            label='unused',
                            settings_path=None,
                            command_runner=mock_command_runner)
        backup.add_volume('fake_volume_group/fake_volume1', '/unused')

        self.assertFalse(backup.run())
    def testRemoveOlderThan_errorCaseIsTrue_doesNotTrimBackups(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = rdiff_backup_wrapper.RdiffBackup(
            label='unused',
            source_hostname='unused',
            settings_path=None,
            command_runner=mock_command_runner)

        backup._remove_older_than('60D', error_case=True)

        self.assertFalse(mock_command_runner.run.called)
예제 #14
0
    def testDeleteSnapshots_multipleSnapshots_marksSnapshotsAsDeleted(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = FakeBackup(source_hostname='unused',
                            label='unused',
                            settings_path=None,
                            command_runner=mock_command_runner)
        backup.add_volume('fake_volume_group/fake_volume1', '/unused1')
        backup.add_volume('fake_volume_group/fake_volume2', '/unused2')
        backup.run()

        self.assertFalse(backup._lv_snapshots[0]['created'])
        self.assertFalse(backup._lv_snapshots[1]['created'])
예제 #15
0
    def testRunCustomWorkflow_updatesTopLevelSrcDir2SnapshotMountPointBasePath(
            self):
        FLAGS.snapshot_mount_root = '/fake_root'
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = lvm.RdiffLVMBackup(source_hostname='unused',
                                    label='fake_backup',
                                    settings_path=None,
                                    command_runner=mock_command_runner)

        backup.run()

        self.assertEqual(backup.top_level_src_dir, '/fake_root/fake_backup')
예제 #16
0
    def testRunCommand_returnsStdoutAndStdErr(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        # Return fake strings for stdout and stderr and 0 for the exit code.
        mock_command_runner.run.return_value = ('fake_stdout', 'fake_stderr',
                                                0)
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        stdout, stderr = test_workflow.run_command('test_command')

        self.assertEqual(stdout, 'fake_stdout')
        self.assertEqual(stderr, 'fake_stderr')
예제 #17
0
    def testRunCommandWithRetries_firstTrySucceeds_commandNotRetried(
            self, unused_mock_sleep):
        mock_command_runner = test_lib.GetMockCommandRunner()
        # Return empty strings for stdout and stderr and 0 (success) for the
        # exit code.
        mock_command_runner.run.return_value = (str(), str(), 0)
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        test_workflow.run_command_with_retries('test_command')

        self.assertEqual(mock_command_runner.run.call_count, 1)
예제 #18
0
    def testRunCustomWorkflow_prefixesIncludeDirs(self):
        FLAGS.snapshot_mount_root = '/fake_root'
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = lvm.RdiffLVMBackup(source_hostname='unused',
                                    label='fake_backup',
                                    settings_path=None,
                                    command_runner=mock_command_runner)

        backup.add_volume('fake_volume_group/fake_volume', '/var')
        backup.include('/var')
        backup.run()

        self.assertEqual(backup._includes, ['/fake_root/fake_backup/var'])
예제 #19
0
    def testDestroyExpiredZFSSnapshots_errorCaseIsTrue_doesNothing(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = zfs.ZFSLVMBackup(label='unused_label',
                                  source_hostname='unused',
                                  rsync_dst='unused_dst_host:/unused_dst',
                                  zfs_hostname='unused_zfs_host',
                                  dataset_name='unused_pool/unused_dataset',
                                  snapshot_expiration_days=30,
                                  settings_path=None,
                                  command_runner=mock_command_runner)

        backup._destroy_expired_zfs_snapshots(30, error_case=True)

        self.assertFalse(mock_command_runner.run.called)
예제 #20
0
    def testMountSnapshots_multipleSnapshots_marksMountPointAsCreated(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = FakeBackup(source_hostname='unused',
                            label='unused',
                            settings_path=None,
                            command_runner=mock_command_runner)

        backup.add_volume('fake_volume_group/fake_volume1', '/unused1')
        backup.add_volume('fake_volume_group/fake_volume2', '/unused2')
        backup._create_snapshots()
        backup._mount_snapshots()

        self.assertTrue(backup._lv_snapshots[0]['mount_point_created'])
        self.assertTrue(backup._lv_snapshots[1]['mount_point_created'])
예제 #21
0
    def testRunCommandWithRetries_maxRetriesReached_raisesException(
            self, unused_mock_sleep):
        FLAGS.max_retries = 1
        mock_command_runner = test_lib.GetMockCommandRunner()
        return1 = (str(), str(), 1)  # command failed
        return2 = (str(), str(), 1)  # command failed
        return3 = (str(), str(), 0)  # command succeeded
        mock_command_runner.run.side_effect = [return1, return2, return3]
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        with self.assertRaises(workflow.NonZeroExitCode):
            test_workflow.run_command_with_retries('test_command')
예제 #22
0
    def testRunCommandWithRetries_firstTryFails_commandRetried(
            self, unused_mock_sleep):
        FLAGS.max_retries = 1
        mock_command_runner = test_lib.GetMockCommandRunner()
        return1 = (str(), str(), 1)  # command failed
        return2 = (str(), str(), 0)  # command succeeded
        mock_command_runner.run.side_effect = [return1, return2]
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        test_workflow.run_command_with_retries('test_command')

        self.assertEqual(mock_command_runner.run.call_count, 2)
    def testRemoveOlderThan_timespecIsNone_backupsNotTrimmed(
            self, mock_remove_older_than):
        FLAGS.remove_older_than_timespec = None
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = rdiff_backup_wrapper.RdiffBackup(
            remove_older_than_timespec=None,
            label='unused',
            source_hostname='unused',
            settings_path=None,
            command_runner=mock_command_runner)

        backup.include('/unused')
        backup.run()

        self.assertFalse(mock_remove_older_than.called)
예제 #24
0
    def testRunCommand_hostIsNotLocalhost_sshArgumentsAdded(self):
        FLAGS.remote_user = '******'
        FLAGS.ssh_path = '/fake/ssh'
        FLAGS.ssh_port = 1234
        mock_command_runner = test_lib.GetMockCommandRunner()
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        test_workflow.run_command(
            'test_command --test_flag test_arg', host='fake_host')

        mock_command_runner.run.assert_called_once_with(
            ['/fake/ssh', '-p', '1234', 'test_user@fake_host', 'test_command',
             '--test_flag', 'test_arg'], False)
예제 #25
0
    def testRunCommandWithRetries_firstTryFails_sleepsBetweenRetries(
            self, mock_sleep):
        FLAGS.max_retries = 1
        FLAGS.retry_interval = 7
        mock_command_runner = test_lib.GetMockCommandRunner()
        return1 = (str(), str(), 1)  # command failed
        return2 = (str(), str(), 0)  # command succeeded
        mock_command_runner.run.side_effect = [return1, return2]
        test_workflow = workflow.BaseWorkflow(
            label='unused', settings_path=None,
            command_runner=mock_command_runner)

        test_workflow.run_command_with_retries('test_command')

        mock_sleep.assert_called_once_with(7)
    def testRemoveOlderThan_errorCaseIsFalse_trimsBackups(self):
        FLAGS.rdiff_backup_path = '/fake/rdiff-backup'
        FLAGS.backup_store_path = '/fake/backup-store'
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = rdiff_backup_wrapper.RdiffBackup(
            label='fake_backup',
            source_hostname='unused',
            settings_path=None,
            command_runner=mock_command_runner)

        backup._remove_older_than('60D', error_case=False)

        mock_command_runner.run.assert_called_once_with([
            '/fake/rdiff-backup', '--force', '--remove-older-than', '60D',
            '/fake/backup-store/fake_backup'
        ], False)
    def testRemoveOlderThan_timespecArgIsNone_timespecFlagUsed(
            self, mock_remove_older_than):
        FLAGS.remove_older_than_timespec = '13D'
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = rdiff_backup_wrapper.RdiffBackup(
            remove_older_than_timespec=None,
            label='unused',
            source_hostname='unused',
            settings_path=None,
            command_runner=mock_command_runner)

        backup.include('/unused')
        backup.run()

        mock_remove_older_than.assert_called_once_with(timespec='13D',
                                                       error_case=False)
    def testRunCustomWorkflow_sourceHostnameIsLocalhost_sourceIsPath(self):
        FLAGS.rdiff_backup_path = '/fake/rdiff-backup'
        FLAGS.backup_store_path = '/fake/backup-store'
        FLAGS.top_level_src_dir = '/'
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = rdiff_backup_wrapper.RdiffBackup(
            label='fake_backup',
            source_hostname='localhost',
            settings_path=None,
            command_runner=mock_command_runner)

        backup.include('/fake_dir')
        backup.run()

        mock_command_runner.run.assert_called_once_with([
            '/fake/rdiff-backup', '--include', '/fake_dir', '--exclude', '**',
            '/', '/fake/backup-store/fake_backup'
        ], False)
    def testRemoveOlderThan_timespecIsNotNone_backupsTrimmed(self):
        FLAGS.rdiff_backup_path = '/fake/rdiff-backup'
        FLAGS.backup_store_path = '/fake/backup-store'
        mock_command_runner = test_lib.GetMockCommandRunner()
        backup = rdiff_backup_wrapper.RdiffBackup(
            remove_older_than_timespec='60D',
            label='fake_backup',
            source_hostname='unused',
            settings_path=None,
            command_runner=mock_command_runner)

        backup.include('/unused')
        backup.run()

        mock_command_runner.run.assert_called_with([
            '/fake/rdiff-backup', '--force', '--remove-older-than', '60D',
            '/fake/backup-store/fake_backup'
        ], False)
예제 #30
0
    def testGetSnapshotCreationTime_parsesCreationTime(self):
        mock_command_runner = test_lib.GetMockCommandRunner()
        mock_command_runner.run.return_value = ('Sat Jan  3  6:48 2015', str(),
                                                0)
        backup = zfs.ZFSLVMBackup(label='unused_label',
                                  source_hostname='unused',
                                  rsync_dst='unused_dst_host:/unused_dst',
                                  zfs_hostname='fake_zfs_host',
                                  dataset_name='unused_pool/unused_dataset',
                                  snapshot_expiration_days=30,
                                  settings_path=None,
                                  command_runner=mock_command_runner)
        expected_creation_time = datetime.datetime(2015, 1, 3, 6, 48)

        creation_time = backup._get_snapshot_creation_time(
            'unused_pool/unused_snapshot')

        self.assertEqual(creation_time, expected_creation_time)