def test_dtl_modifications_multi_node_cluster_without_domains(self):
        """
        Various validations related to DTL target changes on a multi node cluster without Domains
            * vPool DTL: True
                * Set DTL for vDisk
                * Disable DTL for vDisk
            * vPool DTL: False
                * Set DTL for vDisk
                * Disable DTL for vDisk
        """
        structure = DalHelper.build_dal_structure(
            structure={
                'vpools': [1, 2],
                'storagerouters': [1, 2, 3],
                'storagedrivers':
                [(1, 1, 1), (2, 1, 2), (3, 1, 3),
                 (4, 2, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
                'mds_services': [(1, 1), (2, 2), (3, 3),
                                 (4, 4)],  # (<id>, <storagedriver_id>),
                'vdisks': [(1, 1, 1, 1), (2, 1, 1, 1), (3, 1, 1, 1),
                           (4, 1, 1, 1), (5, 4, 2, 1)]
            })  # (<id>, <storagedriver_id>, <vpool_id>, <mds_id>)
        # Set DTL with DTL enabled for vPool (default)
        vdisks = structure['vdisks']
        vdisk = vdisks[1]
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'a_sync'})
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        possible_sds = [
            sd for sd in structure['storagedrivers'].values()
            if sd.storagerouter_guid != vdisk.storagerouter_guid
        ]
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(
            first=dtl_config.mode,
            second=StorageDriverClient.VDISK_DTL_MODE_MAP['a_sync'])
        self.assertIn(member=dtl_config.host,
                      container=[sd.storage_ip for sd in possible_sds])
        self.assertIn(member=dtl_config.port,
                      container=[sd.ports['dtl'] for sd in possible_sds])

        # Disable DTL with DTL enabled for vPool
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'no_sync'})
        vdisk.discard()
        self.assertTrue(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='disabled', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertIsNone(obj=vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id))

        # Switch DTL mode (default is a_sync)
        vdisk = vdisks[2]
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'sync'})
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(first=dtl_config.mode,
                         second=StorageDriverClient.VDISK_DTL_MODE_MAP['sync'])
        self.assertIn(member=dtl_config.host,
                      container=[sd.storage_ip for sd in possible_sds])
        self.assertIn(member=dtl_config.port,
                      container=[sd.ports['dtl'] for sd in possible_sds])

        # Set DTL with DTL disabled for vPool
        vpool_1 = structure['vpools'][1]
        DalHelper.set_vpool_storage_driver_configuration(
            vpool=vpool_1,
            config={
                'filesystem': {
                    'fs_dtl_host':
                    '',
                    'fs_dtl_config_mode':
                    StorageDriverClient.VOLDRV_DTL_MANUAL_MODE
                }
            })
        vpool_1.invalidate_dynamics('configuration')
        self.assertFalse(expr=vpool_1.configuration['dtl_enabled'])

        vdisk = vdisks[3]
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'a_sync'})
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        possible_sds = [
            sd for sd in structure['storagedrivers'].values()
            if sd.storagerouter_guid != vdisk.storagerouter_guid
        ]
        self.assertTrue(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(
            first=dtl_config.mode,
            second=StorageDriverClient.VDISK_DTL_MODE_MAP['a_sync'])
        self.assertIn(member=dtl_config.host,
                      container=[sd.storage_ip for sd in possible_sds])
        self.assertIn(member=dtl_config.port,
                      container=[sd.ports['dtl'] for sd in possible_sds])

        # Disable DTL with DTL disabled for vPool
        self.assertFalse(expr=vpool_1.configuration['dtl_enabled'])

        vdisk = vdisks[4]
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'no_sync'})
        vdisk.discard()
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='disabled', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertIsNone(obj=vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id))

        # Set DTL for vDisk on vPool only on 1 node
        vdisk = vdisks[5]
        with self.assertRaises(Exception):
            VDiskController.set_config_params(
                vdisk.guid, new_config_params={'dtl_mode': 'a_sync'})
        vdisk.discard()
        logs = [
            log for log in Logger._logs['lib']
            if 'No possible StorageRouters' in log and vdisk.name in log
        ]
        self.assertEqual(first=1, second=len(logs))
        self.assertEqual(first='ERROR', second=Logger._logs['lib'][logs[0]])
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_standalone', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertIsNone(obj=vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id))
    def test_dtl_modifications_multi_node_cluster_with_domains(self):
        """
        Various validations related to DTL target changes on a multi node cluster with Domains
            * vPool DTL: True
                * Set DTL for vDisk to Domains 1, 2
                * Disable DTL for vDisk
                * Set DTL for vDisk to Domain 1
                * Set DTL for vDisk to unspecified target
            * vPool DTL: False
                * Set DTL for vDisk
                * Disable DTL for vDisk
        """
        structure = DalHelper.build_dal_structure(
            structure={
                'vpools': [1],
                'storagerouters': [1, 2, 3, 4, 5, 6],
                'storagedrivers':
                [(1, 1, 1), (2, 1, 2), (3, 1, 3), (4, 1, 4),
                 (5, 1, 5)],  # (<id>, <vpool_id>, <storagerouter_id>)
                'mds_services': [(1, 1), (2, 2), (3, 3), (4, 4),
                                 (5, 5)],  # (<id>, <storagedriver_id>),
                'vdisks': [
                    (1, 1, 1, 1), (2, 1, 1, 1), (3, 1, 1, 1), (4, 1, 1, 1),
                    (5, 1, 1, 1), (6, 1, 1, 1), (7, 1, 1, 1), (8, 1, 1, 1)
                ],  # (<id>, <storagedriver_id>, <vpool_id>, <mds_id>)
                'domains': [1, 2],
                'storagerouter_domains': [(1, 1, 1, False), (2, 1, 2, True),
                                          (3, 2, 1, False), (4, 2, 2, True),
                                          (5, 3, 2, False), (6, 4, 2, False),
                                          (7, 4, 1, True), (8, 5, 2, True),
                                          (9, 6, 2, False)]
            })  # (<srd_id>, <sr_id>, <domain_id>, <backup>)
        # SR | reg dom | rec dom |
        #  1 |  dom1   |  dom2   |
        #  2 |  dom1   |  dom2   |
        #  3 |  dom2   |         |
        #  4 |  dom2   |  dom1   |
        #  5 |         |  dom2   |
        #  6 |  dom2   |         |

        domain_1 = structure['domains'][1]
        domain_2 = structure['domains'][2]
        storagerouters = structure['storagerouters']

        # Set DTL with DTL enabled for vPool (default)
        vdisks = structure['vdisks']
        vdisk = vdisks[1]
        VDiskController.set_config_params(vdisk.guid,
                                          new_config_params={
                                              'dtl_mode':
                                              'a_sync',
                                              'dtl_target':
                                              [domain_1.guid, domain_2.guid]
                                          })
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        possible_sds = [
            storagerouters[3].storagedrivers[0],
            storagerouters[4].storagedrivers[0]
        ]
        self.assertTrue(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=2, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(
            first=dtl_config.mode,
            second=StorageDriverClient.VDISK_DTL_MODE_MAP['a_sync'])
        self.assertIn(member=dtl_config.host,
                      container=[sd.storage_ip for sd in possible_sds])
        self.assertIn(member=dtl_config.port,
                      container=[sd.ports['dtl'] for sd in possible_sds])

        # Disable DTL with DTL enabled for vPool
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'no_sync'})
        vdisk.discard()
        self.assertTrue(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='disabled', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertIsNone(obj=vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id))

        # Set DTL to StorageRouter in regular Domain
        vdisk = vdisks[2]
        VDiskController.set_config_params(vdisk.guid,
                                          new_config_params={
                                              'dtl_mode': 'a_sync',
                                              'dtl_target': [domain_1.guid]
                                          })
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        self.assertTrue(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=1, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(
            first=dtl_config.mode,
            second=StorageDriverClient.VDISK_DTL_MODE_MAP['a_sync'])
        self.assertEqual(first=dtl_config.host,
                         second=storagerouters[2].storagedrivers[0].storage_ip)
        self.assertEqual(
            first=dtl_config.port,
            second=storagerouters[2].storagedrivers[0].ports['dtl'])

        # Set DTL to any target
        vdisk = vdisks[3]
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'a_sync'})
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(
            first=dtl_config.mode,
            second=StorageDriverClient.VDISK_DTL_MODE_MAP['a_sync'])
        self.assertIn(member=dtl_config.host,
                      container=[sd.storage_ip for sd in possible_sds])
        self.assertIn(member=dtl_config.port,
                      container=[sd.ports['dtl'] for sd in possible_sds])

        # Set DTL with DTL disabled for vPool
        vpool_1 = structure['vpools'][1]
        DalHelper.set_vpool_storage_driver_configuration(
            vpool=vpool_1,
            config={
                'filesystem': {
                    'fs_dtl_host':
                    '',
                    'fs_dtl_config_mode':
                    StorageDriverClient.VOLDRV_DTL_MANUAL_MODE
                }
            })
        vpool_1.invalidate_dynamics('configuration')
        self.assertFalse(expr=vpool_1.configuration['dtl_enabled'])

        vdisk = vdisks[4]
        VDiskController.set_config_params(vdisk.guid,
                                          new_config_params={
                                              'dtl_mode':
                                              'a_sync',
                                              'dtl_target':
                                              [domain_1.guid, domain_2.guid]
                                          })
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        possible_sds = [
            storagerouters[3].storagedrivers[0],
            storagerouters[4].storagedrivers[0]
        ]
        self.assertTrue(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=2, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(
            first=dtl_config.mode,
            second=StorageDriverClient.VDISK_DTL_MODE_MAP['a_sync'])
        self.assertIn(member=dtl_config.host,
                      container=[sd.storage_ip for sd in possible_sds])
        self.assertIn(member=dtl_config.port,
                      container=[sd.ports['dtl'] for sd in possible_sds])

        # Disable DTL with DTL disabled for vPool
        self.assertFalse(expr=vpool_1.configuration['dtl_enabled'])

        vdisk = vdisks[5]
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'no_sync'})
        vdisk.discard()
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='disabled', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertIsNone(obj=vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id))

        # Set DTL to StorageRouter in regular Domain on DTL disabled vPool
        vdisk = vdisks[6]
        VDiskController.set_config_params(vdisk.guid,
                                          new_config_params={
                                              'dtl_mode': 'a_sync',
                                              'dtl_target': [domain_1.guid]
                                          })
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        self.assertTrue(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=1, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(
            first=dtl_config.mode,
            second=StorageDriverClient.VDISK_DTL_MODE_MAP['a_sync'])
        self.assertEqual(first=dtl_config.host,
                         second=storagerouters[2].storagedrivers[0].storage_ip)
        self.assertEqual(
            first=dtl_config.port,
            second=storagerouters[2].storagedrivers[0].ports['dtl'])

        # Set DTL to any target on DTL disabled vPool
        vdisk = vdisks[7]
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'a_sync'})
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        self.assertTrue(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(
            first=dtl_config.mode,
            second=StorageDriverClient.VDISK_DTL_MODE_MAP['a_sync'])
        self.assertIn(member=dtl_config.host,
                      container=[sd.storage_ip for sd in possible_sds])
        self.assertIn(member=dtl_config.port,
                      container=[sd.ports['dtl'] for sd in possible_sds])

        # Set DTL to any target in regular Domain, then add recovery Domain --> checkup_required
        DalHelper.set_vpool_storage_driver_configuration(
            vpool=vpool_1,
            config={
                'filesystem': {
                    'fs_dtl_host':
                    '',
                    'fs_dtl_config_mode':
                    StorageDriverClient.VOLDRV_DTL_AUTOMATIC_MODE
                }
            })
        vpool_1.invalidate_dynamics('configuration')
        self.assertTrue(expr=vpool_1.configuration['dtl_enabled'])

        for domain in storagerouters[1].domains:
            if domain.backup is True:
                domain.delete(
                )  # Remove recovery Domain for StorageRouter hosting the vDisk

        vdisk = vdisks[8]
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'a_sync'})
        vdisk.discard()
        dtl_config = vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id)
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_sync', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertEqual(
            first=dtl_config.mode,
            second=StorageDriverClient.VDISK_DTL_MODE_MAP['a_sync'])
        self.assertEqual(first=dtl_config.host,
                         second=storagerouters[2].storagedrivers[0].storage_ip)
        self.assertEqual(
            first=dtl_config.port,
            second=storagerouters[2].storagedrivers[0].ports['dtl'])

        DalHelper.build_dal_structure(
            structure={'storagerouter_domains': [
                (10, 1, 2, True)
            ]},  # Restore recovery Domain for StorageRouter hosting the vDisk
            previous_structure=structure)

        vdisk.invalidate_dynamics('dtl_status')
        self.assertEqual(first='checkup_required', second=vdisk.dtl_status)
    def test_dtl_modifications_single_node_cluster_with_domains(self):
        """
        Various validations related to DTL target changes on a single node cluster with Domains
            * vPool DTL: True
                * Set DTL for vDisk
                * Disable DTL for vDisk
            * vPool DTL: False
                * Set DTL for vDisk
                * Disable DTL for vDisk
                * Set DTL for vDisk on vPool which only runs on 1 node
        """
        structure = DalHelper.build_dal_structure(
            structure={
                'vpools': [1],
                'storagerouters': [1],
                'storagedrivers':
                [(1, 1, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
                'mds_services': [(1, 1)],  # (<id>, <storagedriver_id>),
                'vdisks': [
                    (1, 1, 1, 1), (2, 1, 1, 1), (3, 1, 1, 1), (4, 1, 1, 1)
                ],  # (<id>, <storagedriver_id>, <vpool_id>, <mds_id>)
                'domains': [1, 2],
                'storagerouter_domains': [(1, 1, 1, True), (2, 1, 2, False)]
            })  # (<srd_id>, <sr_id>, <domain_id>, <backup>)
        vdisks = structure['vdisks']
        vpool_1 = structure['vpools'][1]
        domain_1 = structure['domains'][1]
        domain_2 = structure['domains'][2]

        # Set DTL with DTL enabled for vPool (default)
        vdisk = vdisks[1]
        with self.assertRaises(Exception):
            VDiskController.set_config_params(vdisk.guid,
                                              new_config_params={
                                                  'dtl_mode': 'a_sync',
                                                  'dtl_target':
                                                  [domain_1.guid]
                                              })
        logs = [
            log for log in Logger._logs['lib']
            if 'No possible StorageRouters' in log and vdisk.name in log
        ]
        vdisk.discard()
        self.assertEqual(first=1, second=len(logs))
        self.assertEqual(first='ERROR', second=Logger._logs['lib'][logs[0]])
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='ok_standalone', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertIsNone(obj=vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id))

        # Disable DTL with specifying DTL targets
        vdisk = vdisks[2]
        with self.assertRaises(ValueError):
            VDiskController.set_config_params(vdisk.guid,
                                              new_config_params={
                                                  'dtl_mode': 'no_sync',
                                                  'dtl_target':
                                                  [domain_1.guid]
                                              })

        # Disable DTL with DTL enabled for vPool
        dtl_config = DTLConfig(host='10.0.0.1', mode='Synchronous', port=10000)
        vdisk.storagedriver_client.set_manual_dtl_config(
            volume_id=vdisk.volume_id, config=dtl_config
        )  # Set config otherwise set_config_params won't do anything since current config is already 'no_sync'
        vdisk.invalidate_dynamics('info')
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'no_sync'})
        vdisk.discard()
        self.assertTrue(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='disabled', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertIsNone(obj=vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id))

        # Set DTL with DTL disabled for vPool
        DalHelper.set_vpool_storage_driver_configuration(
            vpool=vpool_1,
            config={
                'filesystem': {
                    'fs_dtl_host':
                    '',
                    'fs_dtl_config_mode':
                    StorageDriverClient.VOLDRV_DTL_MANUAL_MODE
                }
            })
        vpool_1.invalidate_dynamics('configuration')
        self.assertFalse(expr=vpool_1.configuration['dtl_enabled'])

        vdisk = vdisks[3]
        with self.assertRaises(Exception):
            VDiskController.set_config_params(
                vdisk.guid,
                new_config_params={
                    'dtl_mode': 'a_sync',
                    'dtl_target': [domain_1.guid, domain_2.guid]
                })
        logs = [
            log for log in Logger._logs['lib']
            if 'No possible StorageRouters' in log and vdisk.name in log
        ]
        vdisk.discard()
        self.assertEqual(first=1, second=len(logs))
        self.assertEqual(first='ERROR', second=Logger._logs['lib'][logs[0]])
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='disabled', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertIsNone(obj=vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id))

        # Disable DTL with DTL disabled for vPool
        self.assertFalse(expr=vpool_1.configuration['dtl_enabled'])

        vdisk = vdisks[4]
        VDiskController.set_config_params(
            vdisk.guid, new_config_params={'dtl_mode': 'no_sync'})
        vdisk.discard()
        self.assertFalse(expr=vdisk.has_manual_dtl)
        self.assertEqual(first='disabled', second=vdisk.dtl_status)
        self.assertEqual(first=0, second=len(vdisk.domains_dtl_guids))
        self.assertIsNone(obj=vdisk.storagedriver_client.get_dtl_config(
            volume_id=vdisk.volume_id))