示例#1
0
    def attach_volumes(self, task):
        """Informs the storage subsystem to attach all volumes for the node.

        :param task: The task object.
        :raises: StorageError If an underlying exception or failure
                              is detected.
        """
        node = task.node
        targets = [target.volume_id for target in task.volume_targets]

        # If there are no targets, then we have nothing to do.
        if not targets:
            return

        connector = self._generate_connector(task)
        try:
            connected = cinder.attach_volumes(task, targets, connector)
        except exception.StorageError as e:
            with excutils.save_and_reraise_exception():
                LOG.error(
                    "Error attaching volumes for node %(node)s: "
                    "%(err)s", {
                        'node': node.uuid,
                        'err': e
                    })
                self.detach_volumes(task,
                                    connector=connector,
                                    aborting_attach=True)

        if len(targets) != len(connected):
            LOG.error(
                "The number of volumes defined for node %(node)s does "
                "not match the number of attached volumes. Attempting "
                "detach and abort operation.", {'node': node.uuid})
            self.detach_volumes(task,
                                connector=connector,
                                aborting_attach=True)
            raise exception.StorageError(
                ("Mismatch between the number of "
                 "configured volume targets for "
                 "node %(uuid)s and the number of "
                 "completed attachments.") % {'uuid': node.uuid})

        for volume in connected:
            # Volumes that were already attached are
            # skipped. Updating target volume properties
            # for these volumes is nova's responsibility.
            if not volume.get('already_attached'):
                volume_uuid = volume['data']['ironic_volume_uuid']
                targets = objects.VolumeTarget.list_by_volume_id(
                    task.context, volume_uuid)

                for target in targets:
                    target.properties = volume['data']
                    target.save()
示例#2
0
    def test_attach_volumes_one_attached(self, mock_create_meta, mock_reserve,
                                         mock_init, mock_attach, mock_get,
                                         mock_set_meta, mock_session):
        """Iterate with two volumes, one already attached."""

        volume_id = '111111111-0000-0000-0000-000000000003'
        expected = [{
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'volume_id': volume_id,
                'target_lun': 2,
                'ironic_volume_uuid': '000-000'
            }
        }, {
            'already_attached': True,
            'data': {
                'volume_id': 'already_attached',
                'ironic_volume_uuid': '000-001'
            }
        }]

        volumes = [volume_id, 'already_attached']
        connector = {'foo': 'bar'}
        mock_create_meta.return_value = {'bar': 'baz'}
        mock_get.side_effect = [
            mock.Mock(attachments=[], id='000-000'),
            mock.Mock(attachments=[{
                'server_id': self.node.uuid
            }],
                      id='000-001')
        ]

        mock_init.return_value = {
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'target_lun': 2
            }
        }

        with task_manager.acquire(self.context, self.node.uuid) as task:
            attachments = cinder.attach_volumes(task, volumes, connector)

        self.assertEqual(expected, attachments)
        mock_reserve.assert_called_once_with(mock.ANY, volume_id)
        mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
        mock_attach.assert_called_once_with(mock.ANY, volume_id,
                                            self.node.instance_uuid,
                                            self.mount_point)
        mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
                                              {'bar': 'baz'})
示例#3
0
文件: cinder.py 项目: Tehsmash/ironic
    def attach_volumes(self, task):
        """Informs the storage subsystem to attach all volumes for the node.

        :param task: The task object.
        :raises: StorageError If an underlying exception or failure
                              is detected.
        """
        node = task.node
        targets = [target.volume_id for target in task.volume_targets]

        # If there are no targets, then we have nothing to do.
        if not targets:
            return

        connector = self._generate_connector(task)
        try:
            connected = cinder.attach_volumes(task, targets, connector)
        except exception.StorageError as e:
            with excutils.save_and_reraise_exception():
                LOG.error("Error attaching volumes for node %(node)s: "
                          "%(err)s", {'node': node.uuid, 'err': e})
                self.detach_volumes(task, connector=connector,
                                    aborting_attach=True)

        if len(targets) != len(connected):
            LOG.error("The number of volumes defined for node %(node)s does "
                      "not match the number of attached volumes. Attempting "
                      "detach and abort operation.", {'node': node.uuid})
            self.detach_volumes(task, connector=connector,
                                aborting_attach=True)
            raise exception.StorageError(("Mismatch between the number of "
                                          "configured volume targets for "
                                          "node %(uuid)s and the number of "
                                          "completed attachments.") %
                                         {'uuid': node.uuid})

        for volume in connected:
            # Volumes that were already attached are
            # skipped. Updating target volume properties
            # for these volumes is nova's responsibility.
            if not volume.get('already_attached'):
                volume_uuid = volume['data']['ironic_volume_uuid']
                targets = objects.VolumeTarget.list_by_volume_id(task.context,
                                                                 volume_uuid)

                for target in targets:
                    target.properties = volume['data']
                    target.save()
示例#4
0
    def test_attach_volumes_attach_set_meta_failure(
            self, mock_log, mock_create_meta, mock_is_attached, mock_reserve,
            mock_init, mock_attach, mock_get, mock_set_meta, mock_session):
        """Attach a volume and tolerate set_metadata failure."""

        expected = [{
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'volume_id': '111111111-0000-0000-0000-000000000003',
                'target_lun': 2,
                'ironic_volume_uuid': '000-000'
            }
        }]
        volume_id = '111111111-0000-0000-0000-000000000003'
        volumes = [volume_id]
        connector = {'foo': 'bar'}
        mock_create_meta.return_value = {'bar': 'baz'}
        mock_is_attached.return_value = False
        mock_get.return_value = mock.Mock(attachments=[], id='000-000')
        mock_init.return_value = {
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'target_lun': 2
            }
        }
        mock_set_meta.side_effect = cinder_exceptions.NotAcceptable(
            http_client.NOT_ACCEPTABLE)

        with task_manager.acquire(self.context, self.node.uuid) as task:
            attachments = cinder.attach_volumes(task, volumes, connector)

        self.assertEqual(expected, attachments)
        mock_reserve.assert_called_once_with(mock.ANY, volume_id)
        mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
        mock_attach.assert_called_once_with(mock.ANY, volume_id,
                                            self.node.instance_uuid,
                                            self.mount_point)
        mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
                                              {'bar': 'baz'})
        mock_get.assert_called_once_with(mock.ANY, volume_id)
        mock_is_attached.assert_called_once_with(mock.ANY,
                                                 mock_get.return_value)
        self.assertTrue(mock_log.warning.called)
示例#5
0
    def test_attach_volumes_one_attached(
            self, mock_create_meta, mock_reserve, mock_init, mock_attach,
            mock_get, mock_set_meta, mock_session):
        """Iterate with two volumes, one already attached."""

        volume_id = '111111111-0000-0000-0000-000000000003'
        expected = [
            {'driver_volume_type': 'iscsi',
             'data': {
                 'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                 'target_portal': '127.0.0.0.1:3260',
                 'volume_id': volume_id,
                 'target_lun': 2,
                 'ironic_volume_uuid': '000-000'}},
            {'already_attached': True,
             'data': {
                 'volume_id': 'already_attached',
                 'ironic_volume_uuid': '000-001'}}]

        volumes = [volume_id, 'already_attached']

        connector = {'foo': 'bar'}
        mock_create_meta.return_value = {'bar': 'baz'}
        mock_get.side_effect = [
            mock.Mock(attachments=[], id='000-000'),
            mock.Mock(attachments=[{'server_id': self.node.uuid}],
                      id='000-001')
        ]

        mock_init.return_value = {
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'target_lun': 2}}

        with task_manager.acquire(self.context, self.node.uuid) as task:
            attachments = cinder.attach_volumes(task, volumes, connector)

        self.assertEqual(expected, attachments)
        mock_reserve.assert_called_once_with(mock.ANY, volume_id)
        mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
        mock_attach.assert_called_once_with(mock.ANY, volume_id,
                                            self.node.instance_uuid, None)
        mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
                                              {'bar': 'baz'})
示例#6
0
    def test_attach_volumes_attach_set_meta_failure(
            self, mock_log, mock_create_meta, mock_is_attached,
            mock_reserve, mock_init, mock_attach, mock_get, mock_set_meta,
            mock_session):
        """Attach a volume and tolerate set_metadata failure."""

        expected = [{
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'volume_id': '111111111-0000-0000-0000-000000000003',
                'target_lun': 2,
                'ironic_volume_uuid': '000-000'}}]
        volume_id = '111111111-0000-0000-0000-000000000003'
        volumes = [volume_id]
        connector = {'foo': 'bar'}
        mock_create_meta.return_value = {'bar': 'baz'}
        mock_is_attached.return_value = False
        mock_get.return_value = mock.Mock(attachments=[], id='000-000')
        mock_init.return_value = {
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'target_lun': 2}}
        mock_set_meta.side_effect = cinder_exceptions.NotAcceptable(
            http_client.NOT_ACCEPTABLE)

        with task_manager.acquire(self.context, self.node.uuid) as task:
            attachments = cinder.attach_volumes(task, volumes, connector)

        self.assertEqual(expected, attachments)
        mock_reserve.assert_called_once_with(mock.ANY, volume_id)
        mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
        mock_attach.assert_called_once_with(mock.ANY, volume_id,
                                            self.node.instance_uuid,
                                            self.mount_point)
        mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
                                              {'bar': 'baz'})
        mock_get.assert_called_once_with(mock.ANY, volume_id)
        mock_is_attached.assert_called_once_with(mock.ANY,
                                                 mock_get.return_value)
        self.assertTrue(mock_log.warning.called)
示例#7
0
    def test_attach_volumes(self, mock_create_meta, mock_is_attached,
                            mock_reserve, mock_init, mock_attach, mock_get,
                            mock_set_meta, mock_session):
        """Iterate once on a single volume with success."""

        volume_id = '111111111-0000-0000-0000-000000000003'
        expected = [{
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'volume_id': volume_id,
                'target_lun': 2,
                'ironic_volume_uuid': '000-001'
            }
        }]
        volumes = [volume_id]

        connector = {'foo': 'bar'}
        mock_create_meta.return_value = {'bar': 'baz'}
        mock_is_attached.return_value = False
        mock_get.return_value = mock.Mock(attachments=[], id='000-001')

        mock_init.return_value = {
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'target_lun': 2
            }
        }

        with task_manager.acquire(self.context, self.node.uuid) as task:
            attachments = cinder.attach_volumes(task, volumes, connector)

        self.assertEqual(expected, attachments)
        mock_reserve.assert_called_once_with(mock.ANY, volume_id)
        mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
        mock_attach.assert_called_once_with(mock.ANY, volume_id,
                                            self.node.instance_uuid, None)
        mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
                                              {'bar': 'baz'})
        mock_get.assert_called_once_with(mock.ANY, volume_id)
示例#8
0
    def test_attach_volumes(self, mock_create_meta, mock_is_attached,
                            mock_reserve, mock_init, mock_attach, mock_get,
                            mock_set_meta, mock_session):
        """Iterate once on a single volume with success."""

        volume_id = '111111111-0000-0000-0000-000000000003'
        expected = [{
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'volume_id': volume_id,
                'target_lun': 2,
                'ironic_volume_uuid': '000-001'}}]
        volumes = [volume_id]

        connector = {'foo': 'bar'}
        mock_create_meta.return_value = {'bar': 'baz'}
        mock_is_attached.return_value = False
        mock_get.return_value = mock.Mock(attachments=[], id='000-001')

        mock_init.return_value = {
            'driver_volume_type': 'iscsi',
            'data': {
                'target_iqn': 'iqn.2010-10.org.openstack:volume-00000002',
                'target_portal': '127.0.0.0.1:3260',
                'target_lun': 2}}

        with task_manager.acquire(self.context, self.node.uuid) as task:
            attachments = cinder.attach_volumes(task, volumes, connector)

        self.assertEqual(expected, attachments)
        mock_reserve.assert_called_once_with(mock.ANY, volume_id)
        mock_init.assert_called_once_with(mock.ANY, volume_id, connector)
        mock_attach.assert_called_once_with(mock.ANY, volume_id,
                                            self.node.instance_uuid,
                                            self.mount_point)
        mock_set_meta.assert_called_once_with(mock.ANY, volume_id,
                                              {'bar': 'baz'})
        mock_get.assert_called_once_with(mock.ANY, volume_id)