Example #1
0
class TestSyncFunctions(unittest.TestCase):

    def mock_rabbitcli(self, exchange, exchange_type, process_message=None):
        class MockRabbitMQCommonClient(RabbitMQCommonClient):
            def publish_message(self, message, routing_key=None, reply_to=None, exchange=None, correlation_id=None, on_fail=None):
                return
        return MockRabbitMQCommonClient

    @mock.patch('imgstorage.imgstoragenas.RabbitMQCommonClient')
    @mock.patch('imgstorage.imgstoragevm.RabbitMQCommonClient')
    def setUp(self, mock_rabbit_vm, mock_rabbit_sync):
        self.nas_client = NasDaemon()
        mock_rabbit_vm.publish_message = MagicMock()
        mock_rabbit_sync.publish_message = MagicMock()
        self.nas_client.process_message = MagicMock()

        self.nas_client.is_sync_node = MagicMock(return_value = True)
        self.nas_client.get_node_zpool = MagicMock(return_value = 'my_tank')

        self.nas_client.SQLITE_DB = '/tmp/test_db_%s'%uuid.uuid4()
        self.nas_client.run()

        with sqlite3.connect(self.nas_client.SQLITE_DB) as con:
            cur = con.cursor()
            cur.execute('CREATE TABLE IF NOT EXISTS zvol_calls(zvol TEXT PRIMARY KEY NOT NULL, reply_to TEXT NOT NULL, time INT NOT NULL)')
            cur.execute('CREATE TABLE IF NOT EXISTS zvols(zvol TEXT PRIMARY KEY NOT NULL, zpool TEXT NOT NULL, iscsi_target TEXT UNIQUE, remotehost TEXT)')
            cur.execute('INSERT INTO zvols VALUES (?,?,?,?) ',('vol1', None, None, None))
            cur.execute('INSERT INTO zvols VALUES (?,?,?,?) ',('vol2', 'my_tank', None, 'compute-0-1'))
            cur.execute('INSERT INTO zvols VALUES (?,?,?,?) ',('vol3_busy', 'my_tank', None, 'compute-0-1'))
            cur.execute('INSERT INTO zvol_calls VALUES (?,?,?)',('vol3_busy', 'reply_to', time.time()))
            cur.execute('INSERT INTO zvols VALUES (?,?,?,?) ',('vol4_busy', 'my_tank', 'iqn.2001-04.com.nas-0-1-vol4_busy', 'compute-0-1'))
            cur.execute('INSERT INTO zvol_calls VALUES (?,?,?)',('vol4_busy', 'reply_to', time.time()))
            con.commit()

    def tearDown(self):
        os.remove(self.nas_client.SQLITE_DB)


    @mock.patch('imgstorage.imgstoragenas.NasDaemon.download_snapshot')
    @mock.patch('imgstorage.imgstoragenas.runCommand')
    def test_zvol_unmapped_success(self, mock_run_command, mock_download_snapshot):
        zvol = 'vol4_busy'
        target = 'iqn.2001-04.com.nas-0-1-%s'%zvol
        mock_run_command.return_value = (iscsiadm_session_response%(target, zvol)).splitlines()
        self.nas_client.zvol_unmapped(
            {'action': 'zvol_unmapped', 'target':target, 'zvol': zvol, 'status':'success'},
            BasicProperties(reply_to='compute-0-3', correlation_id='message_id'))

        self.nas_client.schedule_next_sync()
        self.nas_client.pool.close()
        self.nas_client.pool.join()
        print mock_download_snapshot.mock_calls
        self.nas_client.download_snapshot.assert_called_with('my_tank', zvol, 'compute-0-3.ibnet')
        with sqlite3.connect(self.nas_client.SQLITE_DB) as con:
            cur = con.cursor()
            cur.execute('SELECT zvol, iscsi_target, remotehost FROM zvols WHERE zvol = ?',[zvol])
            self.assertSequenceEqual(cur.fetchone(), [zvol, None, 'compute-0-1'])



    @mock.patch('imgstorage.imgstoragevm.VmDaemon.is_sync_enabled', return_value=True)
    @mock.patch('imgstorage.imgstoragenas.runCommand')
    def test_zvol_synced_success(self, mock_run_command, mock_sync_enabled):
        zvol = 'vol2'
        target = 'iqn.2001-04.com.nas-0-1-%s'%zvol
        mock_run_command.return_value = (iscsiadm_session_response%(target, zvol)).splitlines()
        self.nas_client.zvol_synced(
            {'action': 'zvol_synced', 'status':'success', 'zvol':zvol},
            BasicProperties(reply_to='reply_to', correlation_id='message_id'))
        self.assertFalse(self.check_zvol_busy(zvol))

        with sqlite3.connect(self.nas_client.SQLITE_DB) as con:
            cur = con.cursor()
            cur.execute('SELECT zvol, iscsi_target, remotehost FROM zvols WHERE zvol = ?',[zvol])
            self.assertSequenceEqual(cur.fetchone(), [zvol, None, 'compute-0-1'])

    @mock.patch('imgstorage.imgstoragenas.runCommand')
    @mock.patch('imgstorage.imgstoragenas.NasDaemon.upload_snapshot')
    def test_zvol_mapped(self, mock_upload_snapshot, mock_run_command):
        zvol = 'vol4_busy'
        target = 'iqn.2001-04.com.nas-0-1-%s'%zvol
        bdev = 'sdc'
        mock_run_command.return_value = (iscsiadm_session_response%(target, zvol)).splitlines()
        self.nas_client.zvol_mapped(
            {'action': 'zvol_mapped', 'target':target, 'bdev':bdev, 'zvol':zvol, 'status':'success'},
            BasicProperties(reply_to='reply_to', correlation_id='message_id'))
        self.nas_client.schedule_next_sync()
        self.nas_client.pool.close()
        self.nas_client.pool.join()
        print mock_upload_snapshot.mock_calls
        mock_upload_snapshot.assert_called_with('my_tank', zvol, 'reply_to.ibnet')
        self.assertTrue(self.check_zvol_busy(zvol))
        with sqlite3.connect(self.nas_client.SQLITE_DB) as con:
            cur = con.cursor()
            cur.execute('SELECT zvol, iscsi_target, remotehost FROM zvols WHERE zvol = ?',[zvol])
            self.assertSequenceEqual(cur.fetchone(), [zvol, target, 'compute-0-1'])




    @mock.patch('imgstorage.imgstoragenas.runCommand')
    def test_zvol_mapped_finished(self, mock_run_command):
        zvol = 'vol4_busy'
        target = 'iqn.2001-04.com.nas-0-1-%s'%zvol
        bdev = 'sdc'
        mock_run_command.return_value = (iscsiadm_session_response%(target, zvol)).splitlines()
        self.nas_client.zvol_mapped(
            {'action': 'zvol_mapped', 'target':target, 'bdev':bdev, 'zvol':zvol, 'status':'success'},
            BasicProperties(reply_to='reply_to', correlation_id='message_id'))
        self.nas_client.sync_result = MagicMock()
        self.nas_client.sync_result.ready = MagicMock(return_value=True)
        self.nas_client.schedule_next_sync()

        self.nas_client.queue_connector.publish_message.assert_called_with(
            {'action': 'zvol_mapped', 'bdev':bdev, 'status': 'success'}, routing_key='reply_to', exchange='')

        self.assertTrue(self.check_zvol_busy(zvol))
        with sqlite3.connect(self.nas_client.SQLITE_DB) as con:
            cur = con.cursor()
            cur.execute('SELECT zvol, iscsi_target, remotehost FROM zvols WHERE zvol = ?',[zvol])
            self.assertSequenceEqual(cur.fetchone(), [zvol, target, 'compute-0-1'])

    @mock.patch('imgstorage.imgstoragenas.runCommand')
    def test_zvol_unmapped_finished_when_have_pull_scheduled(self, mock_run_command):
        zvol = 'vol4_busy'
        target = 'iqn.2001-04.com.nas-0-1-%s'%zvol
        bdev = 'sdc'
        mock_run_command.return_value = (iscsiadm_session_response%(target, zvol)).splitlines()
        with sqlite3.connect(self.nas_client.SQLITE_DB) as con:
            cur = con.cursor()
            cur.execute('INSERT INTO sync_queue VALUES(?,?,?,0,0,1)',[zvol, 'my_tank', 'compute-0-3'])
            con.commit()

            self.nas_client.zvol_unmapped(
                {'action': 'zvol_unmapped', 'target':target, 'zvol':zvol, 'status':'success'},
                BasicProperties(reply_to='reply_to', correlation_id='message_id'))
            cur.execute('SELECT is_delete_remote FROM sync_queue WHERE zvol = ?',[zvol])
            self.assertEqual(cur.fetchone()[0], 1)

            sync_result = MagicMock()
            sync_result.ready = MagicMock(return_value=True)
            self.nas_client.results[zvol] = sync_result
            self.nas_client.schedule_next_sync()

            self.assertFalse(self.check_zvol_busy(zvol))
            
            print mock_run_command.mock_calls
            mock_run_command.assert_any_call(['su', 'img-storage', '-c', '/usr/bin/ssh compute-0-3 "/sbin/zfs destroy my_tank/%s -r"'%zvol])


    @mock.patch('imgstorage.imgstoragenas.runCommand', return_value=
            ("my_tank/vm-hpcdev-pub03-1-vol@aaa\n"+
            "my_tank/vm-hpcdev-pub03-1-vol@bbb").splitlines())
    def test_find_last_snapshot(self, mock_run_command):
        zvol = 'vm-hpcdev-pub03-1-vol'
        self.assertEqual(self.nas_client.find_last_snapshot('my_tank', zvol), 'bbb')


    def check_zvol_busy(self, zvol):
        with sqlite3.connect(self.nas_client.SQLITE_DB) as con:
            cur = con.cursor()
            cur.execute('SELECT count(*) from zvol_calls where zvol = ?',[zvol])
            num_rows = cur.fetchone()[0]
            return num_rows > 0


    def assertSequenceEqual(self, it1, it2):
        self.assertEqual(tuple(it1), tuple(it2))