Beispiel #1
0
 def setUp(self):
     self.fqdn = "fqdn"
     self.connections = [self.fqdn, self.fqdn]
     self.connection_key = ",".join(self.connections)
     self.array_connection = ArrayConnectionManager(
         "user", "password", self.connections, XIVArrayMediator.array_type)
     array_connection_manager.array_connections_dict = {}
Beispiel #2
0
    def test_detect_array_type(self, socket_connect_test_mock):

        # arrays is a [host, open_ports] dict, note that both port 22 and 8452 are opened in ds8k
        arrays = {
            "svc_host": [SVCArrayMediator.port, ],
            "ds8k_host": [DS8KArrayMediator.port, 22],
            "xiv_host": [XIVArrayMediator.port, ],

        }

        def side_effect(host, port):
            if host in arrays and port in arrays[host]:
                return 0
            return 1

        socket_connect_test_mock.side_effect = side_effect

        self.assertEqual(
            ArrayConnectionManager("", "", ["svc_host", ]).detect_array_type(),
            SVCArrayMediator.array_type
        )

        self.assertEqual(
            ArrayConnectionManager("", "", ["ds8k_host", ]).detect_array_type(),
            DS8KArrayMediator.array_type
        )

        self.assertEqual(
            ArrayConnectionManager("", "", ["xiv_host", ]).detect_array_type(),
            XIVArrayMediator.array_type
        )

        with self.assertRaises(FailedToFindStorageSystemType):
            ArrayConnectionManager("", "", ["unkonwn_host", ]).detect_array_type()
Beispiel #3
0
    def test_connection_adds_the_new_endpoint_for_the_first_time(self, connect):
        self.assertEqual(array_connection_manager.array_connections_dict, {})
        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})

        new_fqdn = "new-fqdn"
        array_connection2 = ArrayConnectionManager("user", "password", [new_fqdn], XIVArrayMediator.array_type)

        array_connection2.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1, new_fqdn: 1})
 def setUp(self):
     self.fqdn = "fqdn"
     self.connections = [self.fqdn, self.fqdn]
     self.connection_key = ",".join(self.connections)
     self.array_connection = ArrayConnectionManager(
         "user", "password", self.connections, XIVArrayMediator.array_type)
     array_connection_manager.array_connections_dict = {}
     self.connect_patcher = patch(
         "controller.array_action.array_connection_manager.XIVArrayMediator._connect"
     )
     self.connect = self.connect_patcher.start()
def unmap_volume(user, password, array_addresses, array_type, vol_id,
                 initiators):
    with ArrayConnectionManager(user, password, array_addresses,
                                array_type) as array_mediator:
        host_name, _ = array_mediator.get_host_by_host_identifiers(initiators)

        array_mediator.unmap_volume(vol_id, host_name)
    def ControllerUnpublishVolume(self, request, context):
        set_current_thread_name(request.volume_id)
        logger.info("ControllerUnpublishVolume")
        try:
            try:
                utils.validate_unpublish_volume_request(request)
            except ValidationException as ex:
                logger.exception(ex)
                context.set_details(ex.message)
                context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
                return csi_pb2.ControllerUnpublishVolumeResponse()

            array_type, vol_id = utils.get_volume_id_info(request.volume_id)

            node_id_info = NodeIdInfo(request.node_id)
            node_name = node_id_info.node_name
            initiators = node_id_info.initiators
            logger.debug(
                "node name for this unpublish operation is : {0}".format(
                    node_name))

            user, password, array_addresses = utils.get_array_connection_info_from_secret(
                request.secrets)

            with ArrayConnectionManager(user, password, array_addresses,
                                        array_type) as array_mediator:
                array_mediator.unmap_volume_by_initiators(vol_id, initiators)

            logger.info("finished ControllerUnpublishVolume")
            return csi_pb2.ControllerUnpublishVolumeResponse()

        except controller_errors.VolumeAlreadyUnmappedError as ex:
            logger.debug("Idempotent case. volume is already unmapped.")
            return csi_pb2.ControllerUnpublishVolumeResponse()

        except controller_errors.PermissionDeniedError as ex:
            context.set_code(grpc.StatusCode.PERMISSION_DENIED)
            context.set_details(ex)
            return csi_pb2.ControllerPublishVolumeResponse()

        except (controller_errors.HostNotFoundError,
                controller_errors.VolumeNotFoundError) as ex:
            logger.exception(ex)
            context.set_details(ex.message)
            context.set_code(grpc.StatusCode.NOT_FOUND)
            return csi_pb2.ControllerUnpublishVolumeResponse()

        except Exception as ex:
            logger.debug("an internal exception occurred")
            logger.exception(ex)
            context.set_code(grpc.StatusCode.INTERNAL)
            context.set_details(
                'an internal exception occurred : {}'.format(ex))
            return csi_pb2.ControllerUnpublishVolumeResponse()
    def DeleteVolume(self, request, context):
        set_current_thread_name(request.volume_id)
        logger.info("DeleteVolume")
        secrets = request.secrets

        try:
            utils.validate_delete_volume_request(request)

            user, password, array_addresses = utils.get_array_connection_info_from_secret(
                secrets)

            try:
                array_type, vol_id = utils.get_volume_id_info(
                    request.volume_id)
            except controller_errors.VolumeNotFoundError as ex:
                logger.warning("volume id is invalid. error : {}".format(ex))
                return csi_pb2.DeleteVolumeResponse()

            with ArrayConnectionManager(user, password, array_addresses,
                                        array_type) as array_mediator:

                logger.debug(array_mediator)

                try:
                    array_mediator.delete_volume(vol_id)

                except controller_errors.VolumeNotFoundError as ex:
                    logger.debug(
                        "volume was not found during deletion: {0}".format(ex))

                except controller_errors.PermissionDeniedError as ex:
                    context.set_code(grpc.StatusCode.PERMISSION_DENIED)
                    context.set_details(ex)
                    return csi_pb2.DeleteVolumeResponse()

        except ValidationException as ex:
            logger.exception(ex)
            context.set_details(ex.message)
            context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
            return csi_pb2.DeleteVolumeResponse()

        except Exception as ex:
            logger.debug("an internal exception occurred")
            logger.exception(ex)
            context.set_code(grpc.StatusCode.INTERNAL)
            context.set_details(
                'an internal exception occurred : {}'.format(ex))
            return csi_pb2.DeleteVolumeResponse()

        logger.debug("generating delete volume response")
        res = csi_pb2.DeleteVolumeResponse()
        logger.info("finished DeleteVolume")
        return res
def map_volume(user, password, array_addresses, array_type, vol_id,
               initiators):
    with ArrayConnectionManager(user, password, array_addresses,
                                array_type) as array_mediator:
        host_name, connectivity_types = array_mediator.get_host_by_host_identifiers(
            initiators)

        logger.debug("hostname : {}, connectivity_types  : {}".format(
            host_name, connectivity_types))

        connectivity_type = utils.choose_connectivity_type(connectivity_types)

        if FC_CONNECTIVITY_TYPE == connectivity_type:
            array_initiators = array_mediator.get_array_fc_wwns(host_name)
        else:
            array_initiators = array_mediator.get_array_iqns()
        mappings = array_mediator.get_volume_mappings(vol_id)
        if len(mappings) >= 1:
            logger.debug(
                "{0} mappings have been found for volume. the mappings are: {1}"
                .format(len(mappings), mappings))
            if len(mappings) == 1:
                mapping = list(mappings)[0]
                if mapping == host_name:
                    logger.debug(
                        "idempotent case - volume is already mapped to host.")
                    return mappings[
                        mapping], connectivity_type, array_initiators
            raise controller_errors.VolumeMappedToMultipleHostsError(mappings)

        logger.debug(
            "no mappings were found for volume. mapping vol : {0} to host : {1}"
            .format(vol_id, host_name))

        try:
            lun = array_mediator.map_volume(vol_id, host_name)
            logger.debug("lun : {}".format(lun))
        except controller_errors.LunAlreadyInUseError as ex:
            logger.warning(
                "Lun was already in use. re-trying the operation. {0}".format(
                    ex))
            for i in range(array_mediator.max_lun_retries - 1):
                try:
                    lun = array_mediator.map_volume(vol_id, host_name)
                    break
                except controller_errors.LunAlreadyInUseError as inner_ex:
                    logger.warning(
                        "re-trying map volume. try #{0}. {1}".format(
                            i, inner_ex))
            else:  # will get here only if the for statement is false.
                raise ex

        return lun, connectivity_type, array_initiators
    def CreateVolume(self, request, context):
        set_current_thread_name(request.name)
        logger.info("create volume")
        try:
            utils.validate_create_volume_request(request)
        except ValidationException as ex:
            logger.error("failed request validation")
            logger.exception(ex)
            context.set_details(ex.message)
            context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
            return csi_pb2.CreateVolumeResponse()

        volume_name = request.name
        logger.debug("volume name : {}".format(volume_name))

        if config.PARAMETERS_PREFIX in request.parameters:
            volume_prefix = request.parameters[config.PARAMETERS_PREFIX]
            volume_full_name = volume_prefix + settings.NAME_PREFIX_SEPARATOR + volume_name
        else:
            volume_prefix = ""
            volume_full_name = volume_name

        secrets = request.secrets
        user, password, array_addresses = utils.get_array_connection_info_from_secret(
            secrets)

        pool = request.parameters[config.PARAMETERS_POOL]
        capabilities = {
            key: value
            for key, value in request.parameters.items() if key in [
                config.PARAMETERS_CAPABILITIES_SPACEEFFICIENCY,
            ]
        }

        try:
            # TODO : pass multiple array addresses
            with ArrayConnectionManager(user, password,
                                        array_addresses) as array_mediator:
                logger.debug(array_mediator)

                if len(volume_prefix
                       ) > array_mediator.max_volume_prefix_length:
                    raise controller_errors.IllegalObjectName(
                        "The volume name prefix {} is too long, max allowed length is {}"
                        .format(
                            volume_prefix,
                            array_mediator.max_volume_prefix_length,
                        ))

                if len(volume_full_name) > array_mediator.max_vol_name_length:
                    raise controller_errors.IllegalObjectName(
                        "The volume name {} is too long, max allowed length is {}"
                        .format(
                            volume_full_name,
                            array_mediator.max_vol_name_length,
                        ))

                size = request.capacity_range.required_bytes

                if size == 0:
                    size = array_mediator.minimal_volume_size_in_bytes
                    logger.debug(
                        "requested size is 0 so the default size will be used : {0} "
                        .format(size))
                try:
                    vol = array_mediator.get_volume(
                        volume_full_name,
                        volume_context=request.parameters,
                        volume_prefix=volume_prefix,
                    )

                except controller_errors.VolumeNotFoundError as ex:
                    logger.debug(
                        "volume was not found. creating a new volume with parameters: {0}"
                        .format(request.parameters))

                    array_mediator.validate_supported_capabilities(
                        capabilities)
                    vol = array_mediator.create_volume(volume_full_name, size,
                                                       capabilities, pool,
                                                       volume_prefix)

                else:
                    logger.debug("volume found : {}".format(vol))

                    if not (vol.capacity_bytes
                            == request.capacity_range.required_bytes):
                        context.set_details(
                            "Volume was already created with different size.")
                        context.set_code(grpc.StatusCode.ALREADY_EXISTS)
                        return csi_pb2.CreateVolumeResponse()

                logger.debug("generating create volume response")
                res = utils.generate_csi_create_volume_response(vol)
                logger.info("finished create volume")
                return res

        except (controller_errors.IllegalObjectName,
                controller_errors.StorageClassCapabilityNotSupported,
                controller_errors.PoolDoesNotExist,
                controller_errors.PoolDoesNotMatchCapabilities) as ex:
            context.set_details(ex.message)
            context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
            return csi_pb2.CreateVolumeResponse()
        except controller_errors.PermissionDeniedError as ex:
            context.set_code(grpc.StatusCode.PERMISSION_DENIED)
            context.set_details(ex)
            return csi_pb2.CreateVolumeResponse()
        except controller_errors.VolumeAlreadyExists as ex:
            context.set_details(ex.message)
            context.set_code(grpc.StatusCode.ALREADY_EXISTS)
            return csi_pb2.CreateVolumeResponse()
        except Exception as ex:
            logger.error("an internal exception occurred")
            logger.exception(ex)
            context.set_code(grpc.StatusCode.INTERNAL)
            context.set_details(
                'an internal exception occurred : {}'.format(ex))
            return csi_pb2.CreateVolumeResponse()
    def ControllerPublishVolume(self, request, context):
        set_current_thread_name(request.volume_id)
        logger.info("ControllerPublishVolume")
        try:
            utils.validate_publish_volume_request(request)

            array_type, vol_id = utils.get_volume_id_info(request.volume_id)

            node_id_info = NodeIdInfo(request.node_id)
            node_name = node_id_info.node_name
            initiators = node_id_info.initiators

            logger.debug(
                "node name for this publish operation is : {0}".format(
                    node_name))

            user, password, array_addresses = utils.get_array_connection_info_from_secret(
                request.secrets)
            with ArrayConnectionManager(user, password, array_addresses,
                                        array_type) as array_mediator:
                lun, connectivity_type, array_initiators = array_mediator.map_volume_by_initiators(
                    vol_id, initiators)
            logger.info("finished ControllerPublishVolume")
            res = utils.generate_csi_publish_volume_response(
                lun, connectivity_type, self.cfg, array_initiators)
            return res

        except controller_errors.VolumeMappedToMultipleHostsError as ex:
            logger.exception(ex)
            context.set_details(ex.message)
            context.set_code(grpc.StatusCode.FAILED_PRECONDITION)
            return csi_pb2.ControllerPublishVolumeResponse()

        except controller_errors.PermissionDeniedError as ex:
            context.set_code(grpc.StatusCode.PERMISSION_DENIED)
            context.set_details(ex)
            return csi_pb2.ControllerPublishVolumeResponse()

        except (controller_errors.LunAlreadyInUseError,
                controller_errors.NoAvailableLunError) as ex:
            logger.exception(ex)
            context.set_details(ex.message)
            context.set_code(grpc.StatusCode.RESOURCE_EXHAUSTED)
            return csi_pb2.ControllerPublishVolumeResponse()

        except (controller_errors.HostNotFoundError,
                controller_errors.VolumeNotFoundError,
                controller_errors.BadNodeIdError,
                controller_errors.NoIscsiTargetsFoundError) as ex:
            logger.exception(ex)
            context.set_details(ex.message)
            context.set_code(grpc.StatusCode.NOT_FOUND)
            return csi_pb2.ControllerPublishVolumeResponse()

        except (ValidationException,
                controller_errors.UnsupportedConnectivityTypeError) as ex:
            logger.exception(ex)
            context.set_details(ex.message)
            context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
            return csi_pb2.ControllerPublishVolumeResponse()

        except Exception as ex:
            logger.debug("an internal exception occurred")
            logger.exception(ex)
            context.set_code(grpc.StatusCode.INTERNAL)
            context.set_details(
                'an internal exception occurred : {}'.format(ex))
            return csi_pb2.ControllerPublishVolumeResponse()
Beispiel #11
0
class TestGetconnection(unittest.TestCase):

    def setUp(self):
        self.fqdn = "fqdn"
        self.connections = [self.fqdn, self.fqdn]
        self.connection_key = ",".join(self.connections)
        self.array_connection = ArrayConnectionManager(
            "user", "password", self.connections, XIVArrayMediator.array_type)
        array_connection_manager.array_connections_dict = {}

    def tearDown(self):
        array_connection_manager.array_connections_dict = {}

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_connection_adds_the_new_endpoint_for_the_first_time(self, connect):
        self.assertEqual(array_connection_manager.array_connections_dict, {})
        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})

        new_fqdn = "new-fqdn"
        array_connection2 = ArrayConnectionManager("user", "password", [new_fqdn], XIVArrayMediator.array_type)

        array_connection2.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1, new_fqdn: 1})

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_connection_adds_connections_to_connection_dict(self, connect):
        self.assertEqual(array_connection_manager.array_connections_dict, {})
        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})

        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 2})

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_connection_returns_error_on_too_many_connection(self, connect):
        array_connection_manager.array_connections_dict = {
            self.connection_key: array_connection_manager.XIVArrayMediator.max_connections}
        with self.assertRaises(NoConnectionAvailableException):
            self.array_connection.get_array_connection()

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_connection_returns_error_from_connect_function(self, connect):
        error_msg = "some error"
        connect.side_effect = [Exception(error_msg)]

        with self.assertRaises(Exception) as ex:
            self.array_connection.get_array_connection()

        self.assertTrue(error_msg in str(ex.exception))

    @patch("controller.array_action.array_connection_manager._socket_connect_test")
    def test_detect_array_type(self, socket_connect_test_mock):

        # arrays is a [host, open_ports] dict, note that both port 22 and 8452 are opened in ds8k
        arrays = {
            "svc_host": [SVCArrayMediator.port, ],
            "ds8k_host": [DS8KArrayMediator.port, 22],
            "xiv_host": [XIVArrayMediator.port, ],

        }

        def side_effect(host, port):
            if host in arrays and port in arrays[host]:
                return 0
            return 1

        socket_connect_test_mock.side_effect = side_effect

        self.assertEqual(
            ArrayConnectionManager("", "", ["svc_host", ]).detect_array_type(),
            SVCArrayMediator.array_type
        )

        self.assertEqual(
            ArrayConnectionManager("", "", ["ds8k_host", ]).detect_array_type(),
            DS8KArrayMediator.array_type
        )

        self.assertEqual(
            ArrayConnectionManager("", "", ["xiv_host", ]).detect_array_type(),
            XIVArrayMediator.array_type
        )

        with self.assertRaises(FailedToFindStorageSystemType):
            ArrayConnectionManager("", "", ["unkonwn_host", ]).detect_array_type()

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_exit_reduces_connection_to_zero(self, connect):
        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})

        self.array_connection.__exit__("", "", None)
        self.assertEqual(array_connection_manager.array_connections_dict, {})

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_exit_reduces_connection(self, connect):
        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})

        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 2})

        self.array_connection.__exit__("", "", None)
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})
Beispiel #12
0
 def setUp(self):
     self.fqdn = "fqdn"
     self.array_connection = ArrayConnectionManager(
         "user", "password", [self.fqdn, self.fqdn], XIVArrayMediator.array_type)
class TestGetconnection(unittest.TestCase):

    def setUp(self):
        self.fqdn = "fqdn"
        self.connections = [self.fqdn, self.fqdn]
        self.connection_key = ",".join(self.connections)
        self.array_connection = ArrayConnectionManager(
            "user", "password", self.connections, XIVArrayMediator.array_type)
        array_connection_manager.array_connections_dict = {}

    def tearDown(self):
        array_connection_manager.array_connections_dict = {}

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_connection_adds_the_new_endpoint_for_the_first_time(self, connect):
        self.assertEqual(array_connection_manager.array_connections_dict, {})
        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})

        new_fqdn = "new-fqdn"
        array_connection2 = ArrayConnectionManager("user", "password", [new_fqdn], XIVArrayMediator.array_type)

        array_connection2.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1, new_fqdn: 1})

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_connection_adds_connections_to_connection_dict(self, connect):
        self.assertEqual(array_connection_manager.array_connections_dict, {})
        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})

        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 2})

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_connection_returns_error_on_too_many_connection(self, connect):
        array_connection_manager.array_connections_dict = {
            self.connection_key: array_connection_manager.XIVArrayMediator.max_connections}
        with self.assertRaises(NoConnectionAvailableException):
            self.array_connection.get_array_connection()

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_connection_returns_error_from_connect_function(self, connect):
        error_msg = "some error"
        connect.side_effect = [Exception(error_msg)]

        with self.assertRaises(Exception) as ex:
            self.array_connection.get_array_connection()

        self.assertTrue(error_msg in str(ex.exception))

    @patch("controller.array_action.array_connection_manager._socket_connect_test")
    def test_detect_array_type(self, socket_connet):
        socket_connet.side_effect = [0, 1]

        res = self.array_connection.detect_array_type()
        self.assertEqual(res, XIVArrayMediator.array_type)

        socket_connet.side_effect = [1, 1, 0, 0]

        res = self.array_connection.detect_array_type()
        self.assertEqual(res, SVCArrayMediator.array_type)

        socket_connet.side_effect = [1, 1, 1, 1]
        with self.assertRaises(FailedToFindStorageSystemType):
            self.array_connection.detect_array_type()

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_exit_reduces_connection_to_zero(self, connect):
        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})

        self.array_connection.__exit__("", "", None)
        self.assertEqual(array_connection_manager.array_connections_dict, {})

    @patch("controller.array_action.array_connection_manager.XIVArrayMediator._connect")
    def test_exit_reduces_connection(self, connect):
        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})

        self.array_connection.get_array_connection()
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 2})

        self.array_connection.__exit__("", "", None)
        self.assertEqual(array_connection_manager.array_connections_dict, {self.connection_key: 1})