Răsfoiți Sursa

Move backup writer initialization to Coriolis core

The Coriolis providers currently duplicate the code that initializes
the backup writers and returns the backup writer connection info.

We'll move that along with the corresponding constants to Coriolis
core.

Coriolis providers are free to define custom backup providers if
necessary.
Lucian Petrut 2 săptămâni în urmă
părinte
comite
0ecdb8acd4

+ 61 - 0
coriolis/providers/backup_writers.py

@@ -22,6 +22,7 @@ from six import with_metaclass
 
 
 from coriolis import constants
 from coriolis import constants
 from coriolis import data_transfer
 from coriolis import data_transfer
+from coriolis import events
 from coriolis import exception
 from coriolis import exception
 from coriolis.providers import provider_utils
 from coriolis.providers import provider_utils
 from coriolis import utils
 from coriolis import utils
@@ -51,6 +52,18 @@ BACKUP_WRITERS = [
     BACKUP_WRITER_FILE
     BACKUP_WRITER_FILE
 ]
 ]
 
 
+# Common data transfer mechanisms exposed to Coriolis users.
+DATA_TRANSFER_MECHANISM_SSH = "SSH"
+DATA_TRANSFER_MECHANISM_HTTPS = "HTTPS"
+# Can't be the same as replicator port.
+DATA_TRANSFER_MECHANISM_HTTPS_PORT = 5566
+
+# The file writer is meant for testing purposes and will not be exposed here.
+DATA_TRANSFER_MECHANISM_MAP = {
+    DATA_TRANSFER_MECHANISM_SSH: BACKUP_WRITER_SSH,
+    DATA_TRANSFER_MECHANISM_HTTPS: BACKUP_WRITER_HTTP,
+}
+
 _WRITER_ERR_MAP = {
 _WRITER_ERR_MAP = {
     -1: "ERR_MORE_MSG",
     -1: "ERR_MORE_MSG",
     0: "ERR_DONE",
     0: "ERR_DONE",
@@ -176,6 +189,54 @@ class BackupWritersFactory(object):
             raise exception.CoriolisException(
             raise exception.CoriolisException(
                 "Missing credentials in connection info")
                 "Missing credentials in connection info")
 
 
+    @classmethod
+    def get_backup_writer_connection_info(
+        cls,
+        event_manager: events.EventManager,
+        ssh_connection_info: dict,
+        data_transfer_mechanism: str,
+    ) -> dict:
+        """Initialize the backup writer and obtain connection info.
+
+        :param ssh_connection_info: a dict containing the following keys:
+            * ip
+            * port - usually SSH port (22)
+            * username
+            * password
+            * pkey - Paramiko keypair
+        :param data_transfer_mechanism: SSH or HTTPS
+        :returns: a dict describing the backend type and backup writer
+                  connection details, used to subsequently retrieve the
+                  backup writer.
+        """
+        if data_transfer_mechanism == DATA_TRANSFER_MECHANISM_HTTPS:
+            event_manager.progress_update(
+                "Setting up HTTPS backup writer service on disk copy worker VM"
+            )
+            writer_bootstrapper = HTTPBackupWriterBootstrapper(
+                ssh_connection_info,
+                DATA_TRANSFER_MECHANISM_HTTPS_PORT,
+            )
+            https_conn_info = writer_bootstrapper.setup_writer()
+            writer_conn_info = {
+                "backend": DATA_TRANSFER_MECHANISM_MAP[
+                    DATA_TRANSFER_MECHANISM_HTTPS],
+                "connection_details": https_conn_info,
+            }
+        elif data_transfer_mechanism == DATA_TRANSFER_MECHANISM_SSH:
+            writer_conn_info = {
+                "backend": DATA_TRANSFER_MECHANISM_MAP[
+                    DATA_TRANSFER_MECHANISM_SSH],
+                "connection_details": ssh_connection_info,
+            }
+        else:
+            raise ValueError(
+                "Unhandleable data transfer mechanism '%s'" % (
+                    data_transfer_mechanism)
+            )
+
+        return writer_conn_info
+
 
 
 class BaseBackupWriterImpl(with_metaclass(abc.ABCMeta)):
 class BaseBackupWriterImpl(with_metaclass(abc.ABCMeta)):
     def __init__(self, path, disk_id):
     def __init__(self, path, disk_id):

+ 43 - 0
coriolis/tests/providers/test_backup_writers.py

@@ -164,6 +164,49 @@ class BackupWritersFactoryTestCase(test_base.CoriolisBaseTestCase):
         self.assertRaises(exception.CoriolisException,
         self.assertRaises(exception.CoriolisException,
                           self._get_factory, {"backend": "ssh"})
                           self._get_factory, {"backend": "ssh"})
 
 
+    @mock.patch.object(backup_writers, "HTTPBackupWriterBootstrapper")
+    def test_get_conn_info_https(self, mock_https_bootstrapper):
+        mechanism = backup_writers.DATA_TRANSFER_MECHANISM_HTTPS
+        factory = backup_writers.BackupWritersFactory
+        writer_conn_info = factory.get_backup_writer_connection_info(
+            event_manager=mock.Mock(),
+            ssh_connection_info=mock.sentinel.instance_conn_info,
+            data_transfer_mechanism=mechanism,
+        )
+        self.assertEqual(
+            writer_conn_info["backend"], backup_writers.BACKUP_WRITER_HTTP)
+        self.assertEqual(
+            writer_conn_info["connection_details"],
+            mock_https_bootstrapper.return_value.setup_writer.return_value)
+        mock_https_bootstrapper.assert_called_once_with(
+            mock.sentinel.instance_conn_info,
+            backup_writers.DATA_TRANSFER_MECHANISM_HTTPS_PORT,
+        )
+
+    def test_get_conn_info_ssh(self):
+        mechanism = backup_writers.DATA_TRANSFER_MECHANISM_SSH
+        factory = backup_writers.BackupWritersFactory
+        writer_conn_info = factory.get_backup_writer_connection_info(
+            event_manager=mock.Mock(),
+            ssh_connection_info=mock.sentinel.instance_conn_info,
+            data_transfer_mechanism=mechanism,
+        )
+        self.assertEqual(
+            writer_conn_info["backend"], backup_writers.BACKUP_WRITER_SSH)
+        self.assertEqual(
+            writer_conn_info["connection_details"],
+            mock.sentinel.instance_conn_info)
+
+    def test_get_conn_info_unsupported(self):
+        factory = backup_writers.BackupWritersFactory
+        self.assertRaises(
+            ValueError,
+            factory.get_backup_writer_connection_info,
+            event_manager=mock.Mock(),
+            ssh_connection_info=mock.sentinel.instance_conn_info,
+            data_transfer_mechanism="fake-mechanism",
+        )
+
 
 
 class BaseBackupWriterTestCase(test_base.CoriolisBaseTestCase):
 class BaseBackupWriterTestCase(test_base.CoriolisBaseTestCase):
     """Test suite for the Coriolis BaseBackupWriter class."""
     """Test suite for the Coriolis BaseBackupWriter class."""