summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.zuul.yaml22
-rw-r--r--api-ref/source/v3/parameters.yaml14
-rw-r--r--api-ref/source/v3/volumes-v3-volumes-actions.inc4
-rw-r--r--cinder/api/contrib/volume_actions.py8
-rw-r--r--cinder/backup/api.py41
-rw-r--r--cinder/tests/unit/api/contrib/test_backups.py11
-rw-r--r--cinder/tests/unit/api/contrib/test_volume_actions.py32
-rw-r--r--cinder/tests/unit/backup/test_backup.py75
-rw-r--r--cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_rest.py16
-rw-r--r--cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py48
-rw-r--r--cinder/volume/drivers/datera/datera_common.py2
-rw-r--r--cinder/volume/drivers/dell_emc/powermax/fc.py3
-rw-r--r--cinder/volume/drivers/dell_emc/powermax/iscsi.py3
-rw-r--r--cinder/volume/drivers/dell_emc/powermax/rest.py3
-rw-r--r--cinder/volume/drivers/hpe/hpe_3par_iscsi.py17
-rw-r--r--doc/source/configuration/block-storage/drivers/hpe-3par-driver.rst6
-rw-r--r--playbooks/tempest-and-cinderlib-run.yaml7
-rw-r--r--releasenotes/notes/bug-193688-bb045badcd5aecad.yaml12
-rw-r--r--releasenotes/notes/bug-1965847-fix-backup-import-3b3ccdf740a13cff.yaml7
-rw-r--r--releasenotes/notes/bug1929429-e749f5e5a242a599.yaml8
-rw-r--r--releasenotes/notes/hpe-3par-primera-add-iscsi-5af339643dfa0928.yaml5
21 files changed, 293 insertions, 51 deletions
diff --git a/.zuul.yaml b/.zuul.yaml
index 887e5e399..71739fa81 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -63,6 +63,11 @@
irrelevant-files: *gate-irrelevant-files
- tempest-ipv6-only:
irrelevant-files: *gate-irrelevant-files
+ - openstacksdk-functional-devstack:
+ required-projects:
+ - name: opendev.org/openstack/openstacksdk
+ override-branch: stable/ussuri
+ irrelevant-files: *gate-irrelevant-files
gate:
jobs:
- cinder-grenade-mn-sub-volbak:
@@ -75,6 +80,11 @@
irrelevant-files: *gate-irrelevant-files
- tempest-ipv6-only:
irrelevant-files: *gate-irrelevant-files
+ - openstacksdk-functional-devstack:
+ required-projects:
+ - name: opendev.org/openstack/openstacksdk
+ override-branch: stable/ussuri
+ irrelevant-files: *gate-irrelevant-files
experimental:
jobs:
- tempest-cinder-v2-api:
@@ -121,16 +131,7 @@
- job:
name: cinder-plugin-ceph-tempest
parent: devstack-plugin-ceph-tempest-py3
- roles:
- - zuul: opendev.org/openstack/cinderlib
- - zuul: opendev.org/openstack/cinder-tempest-plugin
- run: playbooks/tempest-and-cinderlib-run.yaml
- post-run: playbooks/post-cinderlib.yaml
- required-projects:
- - opendev.org/openstack/cinderlib
vars:
- zuul_additional_subunit_dirs:
- - "{{ ansible_user_dir }}/{{ zuul.projects['opendev.org/openstack/cinderlib'].src_dir }}"
devstack_local_conf:
test-config:
$TEMPEST_CONFIG:
@@ -220,7 +221,8 @@
* legacy-tempest-dsvm-lvm-multibackend
timeout: 10800
required-projects:
- - opendev.org/openstack/cinder-tempest-plugin
+ - name: opendev.org/openstack/cinder-tempest-plugin
+ override-checkout: 1.3.0
vars:
tox_envlist: all
tempest_test_regex: '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)|(^cinder_tempest_plugin))'
diff --git a/api-ref/source/v3/parameters.yaml b/api-ref/source/v3/parameters.yaml
index 52a8182c0..15dfecd57 100644
--- a/api-ref/source/v3/parameters.yaml
+++ b/api-ref/source/v3/parameters.yaml
@@ -850,6 +850,13 @@ container_format:
in: body
required: false
type: string
+container_format_upload:
+ description: |
+ Container format for the new image. Default is bare. (Note: Volumes
+ of an encrypted volume type must use a bare container format.)
+ in: body
+ required: false
+ type: string
control_location:
description: |
Notional service where encryption is performed. Valid values are
@@ -1097,6 +1104,13 @@ disk_format:
in: body
required: false
type: string
+disk_format_upload:
+ description: |
+ Disk format for the new image. Default is raw. (Note: volumes of an
+ encrypted volume type can only be uploaded in raw format.)
+ in: body
+ required: false
+ type: string
display_name:
description: |
The name of volume backend capabilities.
diff --git a/api-ref/source/v3/volumes-v3-volumes-actions.inc b/api-ref/source/v3/volumes-v3-volumes-actions.inc
index 36774e318..0c73f7880 100644
--- a/api-ref/source/v3/volumes-v3-volumes-actions.inc
+++ b/api-ref/source/v3/volumes-v3-volumes-actions.inc
@@ -694,8 +694,8 @@ Request
- os-volume_upload_image: os-volume_upload_image
- image_name: image_name
- force: force_upload_vol
- - disk_format: disk_format
- - container_format: container_format
+ - disk_format: disk_format_upload
+ - container_format: container_format_upload
- visibility: visibility_min
- protected: protected
diff --git a/cinder/api/contrib/volume_actions.py b/cinder/api/contrib/volume_actions.py
index 0db41c592..97d45728c 100644
--- a/cinder/api/contrib/volume_actions.py
+++ b/cinder/api/contrib/volume_actions.py
@@ -219,6 +219,14 @@ class VolumeActionsController(wsgi.Controller):
"name": params["image_name"]}
if volume.encryption_key_id:
+ # encrypted volumes cannot be converted on upload
+ if (image_metadata['disk_format'] != 'raw'
+ or image_metadata['container_format'] != 'bare'):
+ msg = _("An encrypted volume uploaded as an image must use "
+ "'raw' disk_format and 'bare' container_format, "
+ "which are the defaults for these options.")
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
# Clone volume encryption key: the current key cannot
# be reused because it will be deleted when the volume is
# deleted.
diff --git a/cinder/backup/api.py b/cinder/backup/api.py
index 7e03348af..30a036c23 100644
--- a/cinder/backup/api.py
+++ b/cinder/backup/api.py
@@ -499,6 +499,23 @@ class API(base.Base):
msg = _('Provided backup record is missing size attribute')
raise exception.InvalidInput(reason=msg)
+ # Try to get the backup with that ID in all projects even among
+ # deleted entries (we reuse soft-deleted backups).
+ try:
+ backup = objects.BackupImport.get_by_id(
+ context.elevated(read_deleted='yes'),
+ backup_record['id'],
+ project_only=False)
+
+ # If record exists and it's not deleted we cannot proceed
+ # with the import
+ if backup.status != fields.BackupStatus.DELETED:
+ msg = _('Backup already exists in database.')
+ raise exception.InvalidBackup(reason=msg)
+ except exception.BackupNotFound:
+ pass
+
+ # Check that we're under limit by reserving quota
try:
reserve_opts = {'backups': 1,
'backup_gigabytes': backup_record['size']}
@@ -520,30 +537,16 @@ class API(base.Base):
}
try:
- try:
- # Try to get the backup with that ID in all projects even among
- # deleted entries.
- backup = objects.BackupImport.get_by_id(
- context.elevated(read_deleted='yes'),
- backup_record['id'],
- project_only=False)
-
- # If record exists and it's not deleted we cannot proceed
- # with the import
- if backup.status != fields.BackupStatus.DELETED:
- msg = _('Backup already exists in database.')
- raise exception.InvalidBackup(reason=msg)
-
- # Otherwise we'll "revive" delete backup record
+ if backup:
+ # "revive" the soft-deleted backup record retrieved earlier
backup.update(kwargs)
backup.save()
- QUOTAS.commit(context, reservations)
- except exception.BackupNotFound:
- # If record doesn't exist create it with the specific ID
+ else:
+ # create a new backup with the specified ID
backup = objects.BackupImport(context=context,
id=backup_record['id'], **kwargs)
backup.create()
- QUOTAS.commit(context, reservations)
+ QUOTAS.commit(context, reservations)
except Exception:
with excutils.save_and_reraise_exception():
try:
diff --git a/cinder/tests/unit/api/contrib/test_backups.py b/cinder/tests/unit/api/contrib/test_backups.py
index b8b247967..07184fdc8 100644
--- a/cinder/tests/unit/api/contrib/test_backups.py
+++ b/cinder/tests/unit/api/contrib/test_backups.py
@@ -2242,9 +2242,14 @@ class BackupsAPITestCase(test.TestCase):
res_dict['badRequest']['code'])
self.assertEqual('Invalid backup: Backup already exists in database.',
res_dict['badRequest']['message'])
- mock_reserve.assert_called_with(
- ctx, backups=1, backup_gigabytes=1)
- mock_rollback.assert_called_with(ctx, "fake_reservation")
+
+ # Bug #1965847: already existing backup should not be deleted
+ self.assertNotEqual(fields.BackupStatus.DELETED,
+ self._get_backup_attrib(backup.id, 'status'))
+ mock_reserve.assert_not_called()
+ mock_rollback.assert_not_called()
+ mock_commit.assert_not_called()
+
backup.destroy()
@mock.patch.object(quota.QUOTAS, 'commit')
diff --git a/cinder/tests/unit/api/contrib/test_volume_actions.py b/cinder/tests/unit/api/contrib/test_volume_actions.py
index 5651152c8..9d0e3ce3b 100644
--- a/cinder/tests/unit/api/contrib/test_volume_actions.py
+++ b/cinder/tests/unit/api/contrib/test_volume_actions.py
@@ -1006,6 +1006,38 @@ class VolumeImageActionsTest(test.TestCase):
id,
body=body)
+ @mock.patch.object(volume_api.API, 'get', fake_volume_get_obj)
+ def test_copy_volume_to_image_bad_disk_format_for_encrypted_vol(self):
+ id = ENCRYPTED_VOLUME_ID
+ vol = {"container_format": 'bare',
+ "disk_format": 'qcow2',
+ "image_name": 'image_name',
+ "force": True}
+ body = {"os-volume_upload_image": vol}
+ req = fakes.HTTPRequest.blank('/v3/%s/volumes/%s/action'
+ % (fake.PROJECT_ID, id))
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller._volume_upload_image,
+ req,
+ id,
+ body=body)
+
+ @mock.patch.object(volume_api.API, 'get', fake_volume_get_obj)
+ def test_copy_volume_to_image_bad_container_format_for_encrypted_vol(self):
+ id = ENCRYPTED_VOLUME_ID
+ vol = {"container_format": 'ovf',
+ "disk_format": 'raw',
+ "image_name": 'image_name',
+ "force": True}
+ body = {"os-volume_upload_image": vol}
+ req = fakes.HTTPRequest.blank('/v3/%s/volumes/%s/action'
+ % (fake.PROJECT_ID, id))
+ self.assertRaises(webob.exc.HTTPBadRequest,
+ self.controller._volume_upload_image,
+ req,
+ id,
+ body=body)
+
@mock.patch.object(volume_api.API, "copy_volume_to_image")
def test_copy_volume_to_image_disk_format_ploop(self,
mock_copy_to_image):
diff --git a/cinder/tests/unit/backup/test_backup.py b/cinder/tests/unit/backup/test_backup.py
index 8b5d85154..24b725c86 100644
--- a/cinder/tests/unit/backup/test_backup.py
+++ b/cinder/tests/unit/backup/test_backup.py
@@ -2050,13 +2050,86 @@ class BackupAPITestCase(BaseBackupTest):
'user_id': backup.user_id,
'volume_id': backup.volume_id,
'size': 1}
- mock_reserve.return_value = 'fake_reservation'
self.assertRaises(exception.InvalidBackup,
self.api._get_import_backup,
self.ctxt, 'fake_backup_url')
+
+ # make sure Bug #1965847 has been fixed
+ backup = db.backup_get(self.ctxt, backup.id)
+ self.assertNotEqual(fields.BackupStatus.DELETED, backup.status)
+
+ # the fix for Bug #1965847 changed the workflow in the method
+ # under test, so we check that none of this stuff happens any more
+ mock_reserve.assert_not_called()
+ mock_rollback.assert_not_called()
+ mock_commit.assert_not_called()
+
+ @mock.patch.object(objects.Backup, 'decode_record')
+ @mock.patch.object(quota.QUOTAS, 'commit')
+ @mock.patch.object(quota.QUOTAS, 'rollback')
+ @mock.patch.object(quota.QUOTAS, 'reserve')
+ def test__get_import_backup_reuse_backup(
+ self, mock_reserve, mock_rollback, mock_commit, mock_decode):
+ backup = self._create_backup_db_entry(
+ size=1,
+ status=fields.BackupStatus.DELETED)
+ mock_decode.return_value = {'id': backup.id,
+ 'project_id': backup.project_id,
+ 'user_id': backup.user_id,
+ 'volume_id': backup.volume_id,
+ 'size': 1}
+ mock_reserve.return_value = 'fake_reservation'
+ self.ctxt.user_id = 'fake_user'
+ self.ctxt.project_id = 'fake_project'
+
+ # check pre-conditions
+ self.assertNotEqual(self.ctxt.user_id, backup.user_id)
+ self.assertNotEqual(self.ctxt.project_id, backup.project_id)
+ self.assertEqual(fields.BackupStatus.DELETED, backup.status)
+
+ self.api._get_import_backup(self.ctxt, 'fake_backup_url')
+
+ # check post-conditions
+ backup = db.backup_get(self.ctxt, backup.id)
+ self.assertEqual(self.ctxt.user_id, backup.user_id)
+ self.assertEqual(self.ctxt.project_id, backup.project_id)
+ self.assertNotEqual(fields.BackupStatus.DELETED, backup.status)
+
+ mock_reserve.assert_called_with(
+ self.ctxt, backups=1, backup_gigabytes=1)
+ mock_commit.assert_called_with(self.ctxt, 'fake_reservation')
+ mock_rollback.assert_not_called()
+
+ @mock.patch.object(objects.BackupImport, '__init__')
+ @mock.patch.object(objects.BackupImport, 'get_by_id')
+ @mock.patch.object(objects.Backup, 'decode_record')
+ @mock.patch.object(quota.QUOTAS, 'commit')
+ @mock.patch.object(quota.QUOTAS, 'rollback')
+ @mock.patch.object(quota.QUOTAS, 'reserve')
+ def test__get_import_backup_rollback_situation(
+ self, mock_reserve, mock_rollback, mock_commit, mock_decode,
+ mock_get_by_id, mock_imp_init):
+ mock_decode.return_value = {'id': fake.BACKUP_ID,
+ 'project_id': fake.PROJECT_ID,
+ 'user_id': fake.USER_ID,
+ 'volume_id': fake.VOLUME_ID,
+ 'size': 1}
+ # we won't find a backup, so we'll need to create one
+ mock_get_by_id.side_effect = exception.BackupNotFound(
+ backup_id=fake.BACKUP_ID)
+ # we should make a reservation ...
+ mock_reserve.return_value = 'fake_reservation'
+ # ... but will fail to create and will have to roll back
+ mock_imp_init.side_effect = FakeBackupException,
+
+ self.assertRaises(FakeBackupException,
+ self.api._get_import_backup,
+ self.ctxt, 'fake_backup_url')
+
mock_reserve.assert_called_with(
self.ctxt, backups=1, backup_gigabytes=1)
+ mock_commit.assert_not_called()
mock_rollback.assert_called_with(self.ctxt, "fake_reservation")
@mock.patch('cinder.objects.BackupList.get_all_by_volume')
diff --git a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_rest.py b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_rest.py
index a093d16cf..05bae99e5 100644
--- a/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_rest.py
+++ b/cinder/tests/unit/volume/drivers/dell_emc/powermax/test_powermax_rest.py
@@ -601,6 +601,22 @@ class PowerMaxRestTest(test.TestCase):
self.assertTrue(is_child1)
self.assertFalse(is_child2)
+ def test_is_child_sg_in_parent_sg_case_not_matching(self):
+ lower_case_host = 'OS-hostx-SRP_1-DiamondDSS-os-fibre-PG'
+
+ is_child1 = self.rest.is_child_sg_in_parent_sg(
+ self.data.array, lower_case_host,
+ self.data.parent_sg_f)
+ self.assertTrue(is_child1)
+
+ def test_is_child_sg_in_parent_sg_spelling_mistake(self):
+ lower_case_host = 'OS-hosty-SRP_1-DiamondDSS-os-fiber-PG'
+
+ is_child1 = self.rest.is_child_sg_in_parent_sg(
+ self.data.array, lower_case_host,
+ self.data.parent_sg_f)
+ self.assertFalse(is_child1)
+
def test_add_child_sg_to_parent_sg(self):
payload = {'editStorageGroupActionParam': {
'expandStorageGroupParam': {
diff --git a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py
index 4972c7967..060e4537e 100644
--- a/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py
+++ b/cinder/tests/unit/volume/drivers/hpe/test_hpe3par.py
@@ -763,14 +763,15 @@ class HPE3PARBaseDriver(test.TestCase):
spec=True,
)
def setup_mock_client(self, _m_client, driver, conf=None, m_conf=None,
- is_primera=False):
+ is_primera=False,
+ wsapi_version=wsapi_version_latest):
_m_client = _m_client.return_value
# Configure the base constants, defaults etc...
_m_client.configure_mock(**self.mock_client_conf)
- _m_client.getWsApiVersion.return_value = self.wsapi_version_latest
+ _m_client.getWsApiVersion.return_value = wsapi_version
_m_client.is_primera_array.return_value = is_primera
@@ -8909,10 +8910,49 @@ class TestHPE3PARISCSIDriver(HPE3PARBaseDriver):
return mock_client
- def test_iscsi_primera(self):
+ def test_iscsi_primera_old(self):
+ # primera 4.0.xx.yyy
+ wsapi_version_primera_old = {'major': 1,
+ 'build': 40000128,
+ 'minor': 8,
+ 'revision': 1}
+
self.assertRaises(NotImplementedError, self.setup_mock_client,
driver=hpedriver.HPE3PARISCSIDriver,
- is_primera=True)
+ is_primera=True,
+ wsapi_version=wsapi_version_primera_old)
+
+ def test_iscsi_primera_new(self, config=None, mock_conf=None):
+ # primera 4.2.xx.yyy
+ wsapi_version_primera_new = {'major': 1,
+ 'build': 40202010,
+ 'minor': 8,
+ 'revision': 1}
+
+ self.ctxt = context.get_admin_context()
+
+ mock_client = self.setup_mock_client(
+ conf=config,
+ m_conf=mock_conf,
+ driver=hpedriver.HPE3PARISCSIDriver,
+ is_primera=True,
+ wsapi_version=wsapi_version_primera_new)
+
+ expected_get_cpgs = [
+ mock.call.getCPG(HPE3PAR_CPG),
+ mock.call.getCPG(HPE3PAR_CPG2)]
+ expected_get_ports = [mock.call.getPorts()]
+ expected_primera = [
+ mock.call.is_primera_array(),
+ mock.call.getWsApiVersion()]
+ mock_client.assert_has_calls(
+ self.standard_login +
+ expected_get_cpgs +
+ self.standard_logout +
+ expected_primera +
+ self.standard_login +
+ expected_get_ports +
+ self.standard_logout)
@ddt.data('volume', 'volume_name_id')
def test_initialize_connection(self, volume_attr):
diff --git a/cinder/volume/drivers/datera/datera_common.py b/cinder/volume/drivers/datera/datera_common.py
index a9ec14065..b60af66ee 100644
--- a/cinder/volume/drivers/datera/datera_common.py
+++ b/cinder/volume/drivers/datera/datera_common.py
@@ -285,7 +285,7 @@ def create_tenant(driver, project_id):
try:
driver.api.tenants.create(name=name)
except dfs_sdk.exceptions.ApiConflictError:
- LOG.debug("Tenant {} already exists".format(name))
+ LOG.debug("Tenant %s already exists", name)
return _format_tenant(name)
diff --git a/cinder/volume/drivers/dell_emc/powermax/fc.py b/cinder/volume/drivers/dell_emc/powermax/fc.py
index 2af3b2cd2..54017da37 100644
--- a/cinder/volume/drivers/dell_emc/powermax/fc.py
+++ b/cinder/volume/drivers/dell_emc/powermax/fc.py
@@ -134,9 +134,10 @@ class PowerMaxFCDriver(san.SanDriver, driver.FibreChannelDriver):
4.2.10 - Replica RDFG suspend fix (#1892718)
4.2.11 - Fix non-temporary snapshot delete (#1887962)
4.2.12 - Fix for create snapshot (#1939139)
+ 4.2.13 - Allow for case mismatch in SGs (bug #1929429)
"""
- VERSION = "4.2.12"
+ VERSION = "4.2.13"
# ThirdPartySystems wiki
CI_WIKI_NAME = "EMC_VMAX_CI"
diff --git a/cinder/volume/drivers/dell_emc/powermax/iscsi.py b/cinder/volume/drivers/dell_emc/powermax/iscsi.py
index 6565293b8..24abd7777 100644
--- a/cinder/volume/drivers/dell_emc/powermax/iscsi.py
+++ b/cinder/volume/drivers/dell_emc/powermax/iscsi.py
@@ -139,9 +139,10 @@ class PowerMaxISCSIDriver(san.SanISCSIDriver):
4.2.10 - Replica RDFG suspend fix (#1892718)
4.2.11 - Fix non-temporary snapshot delete (#1887962)
4.2.12 - Fix for create snapshot (#1939139)
+ 4.2.13 - Allow for case mismatch in SGs (bug #1929429)
"""
- VERSION = "4.2.12"
+ VERSION = "4.2.13"
# ThirdPartySystems wiki
CI_WIKI_NAME = "EMC_VMAX_CI"
diff --git a/cinder/volume/drivers/dell_emc/powermax/rest.py b/cinder/volume/drivers/dell_emc/powermax/rest.py
index f8b0a25ba..bf5330f4e 100644
--- a/cinder/volume/drivers/dell_emc/powermax/rest.py
+++ b/cinder/volume/drivers/dell_emc/powermax/rest.py
@@ -773,7 +773,8 @@ class PowerMaxRest(object):
parent_sg = self.get_storage_group(array, parent_name)
if parent_sg and parent_sg.get('child_storage_group'):
child_sg_list = parent_sg['child_storage_group']
- if child_name in child_sg_list:
+ if child_name.lower() in (
+ child.lower() for child in child_sg_list):
return True
return False
diff --git a/cinder/volume/drivers/hpe/hpe_3par_iscsi.py b/cinder/volume/drivers/hpe/hpe_3par_iscsi.py
index 83febae89..0d809e048 100644
--- a/cinder/volume/drivers/hpe/hpe_3par_iscsi.py
+++ b/cinder/volume/drivers/hpe/hpe_3par_iscsi.py
@@ -128,10 +128,11 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
failover. bug #1773069
4.0.4 - Added Peer Persistence feature
4.0.5 - Added Primera array check. bug #1849525
+ 4.0.6 - Allow iSCSI support for Primera 4.2 onwards
"""
- VERSION = "4.0.5"
+ VERSION = "4.0.6"
# The name of the CI wiki page.
CI_WIKI_NAME = "HPE_Storage_CI"
@@ -144,9 +145,17 @@ class HPE3PARISCSIDriver(hpebasedriver.HPE3PARDriverBase):
client_obj = common.client
is_primera = client_obj.is_primera_array()
if is_primera:
- LOG.error("For Primera, only FC is supported. "
- "iSCSI cannot be used")
- raise NotImplementedError()
+ api_version = client_obj.getWsApiVersion()
+ array_version = api_version['build']
+ LOG.debug("array version: %(version)s",
+ {'version': array_version})
+ if array_version < 40200000:
+ err_msg = (_('The iSCSI driver is not supported for '
+ 'Primera %(version)s. It is supported '
+ 'for Primera 4.2 or higher versions.')
+ % {'version': array_version})
+ LOG.error(err_msg)
+ raise NotImplementedError()
self.iscsi_ips = {}
common.client_login()
diff --git a/doc/source/configuration/block-storage/drivers/hpe-3par-driver.rst b/doc/source/configuration/block-storage/drivers/hpe-3par-driver.rst
index d013cdc03..bad3e3d4c 100644
--- a/doc/source/configuration/block-storage/drivers/hpe-3par-driver.rst
+++ b/doc/source/configuration/block-storage/drivers/hpe-3par-driver.rst
@@ -378,15 +378,15 @@ OpenStack software.
san_password=3parpass
# FIBRE CHANNEL DRIVER
- # Note: For Primera, only FC driver is supported as of now.
# (uncomment the next line to enable the FC driver)
#volume_driver=cinder.volume.drivers.hpe.hpe_3par_fc.HPE3PARFCDriver
# iSCSI DRIVER
# If you enable the iSCSI driver, you must also set values
# for hpe3par_iscsi_ips or iscsi_ip_address in this file.
- # Note: Primera currently requires the FC driver. If you
- # configure iSCSI with Primera, the driver will fail to start.
+ # Note: The iSCSI driver is supported with 3PAR (all versions)
+ # and Primera (version 4.2 or higher). If you configure iSCSI
+ # with Primera 4.0 or 4.1, the driver will fail to start.
# (uncomment the next line to enable the iSCSI driver)
#volume_driver=cinder.volume.drivers.hpe.hpe_3par_iscsi.HPE3PARISCSIDriver
diff --git a/playbooks/tempest-and-cinderlib-run.yaml b/playbooks/tempest-and-cinderlib-run.yaml
index cbb33273d..e71417d2b 100644
--- a/playbooks/tempest-and-cinderlib-run.yaml
+++ b/playbooks/tempest-and-cinderlib-run.yaml
@@ -19,7 +19,7 @@
- setup-tempest-data-dir
- acl-devstack-files
- role: run-tempest
- # ignore the errors, so that run-cinderlib-tests is always executed
+ # ignore the errors here (but consider them later), so that run-cinderlib-tests is always executed
ignore_errors: yes
- role: change-devstack-data-owner
devstack_data_subdir_changed: cinder
@@ -27,3 +27,8 @@
- role: run-cinderlib-tests
tox_install_siblings: false
cinderlib_base_dir: "{{ ansible_user_dir }}/{{ zuul.projects['opendev.org/openstack/cinderlib'].src_dir }}"
+ post_tasks:
+ - name: Fail if the first tempest run did not work
+ fail:
+ msg: "tempest run returned with an error"
+ when: tempest_run_result is defined and tempest_run_result.rc != 0
diff --git a/releasenotes/notes/bug-193688-bb045badcd5aecad.yaml b/releasenotes/notes/bug-193688-bb045badcd5aecad.yaml
new file mode 100644
index 000000000..f4a141dba
--- /dev/null
+++ b/releasenotes/notes/bug-193688-bb045badcd5aecad.yaml
@@ -0,0 +1,12 @@
+---
+fixes:
+ - |
+ `Bug #1935688 <https://bugs.launchpad.net/cinder/+bug/1935688>`_:
+ Cinder only supports uploading a volume of an encrypted volume type as an
+ image to the Image service in ``raw`` format using a ``bare`` container
+ type. Previously, ``os-volume_upload_image`` action requests to the Block
+ Storage API specifying different format option values were accepted, but
+ would result in a later failure. This condition is now checked at the API
+ layer, and ``os-volume_upload_image`` action requests on a volume of an
+ encrypted type that specify unsupported values for ``disk_format`` or
+ ``container_format`` now result in a 400 (Bad Request) response.
diff --git a/releasenotes/notes/bug-1965847-fix-backup-import-3b3ccdf740a13cff.yaml b/releasenotes/notes/bug-1965847-fix-backup-import-3b3ccdf740a13cff.yaml
new file mode 100644
index 000000000..b51efd3a8
--- /dev/null
+++ b/releasenotes/notes/bug-1965847-fix-backup-import-3b3ccdf740a13cff.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+ - |
+ `Bug #1965847 <https://bugs.launchpad.net/cinder/+bug/1965847>`_: Fixed
+ issue where importing a backup record for a backup_id that currently
+ existed had the unfortunate side effect of deleting the existing backup
+ record.
diff --git a/releasenotes/notes/bug1929429-e749f5e5a242a599.yaml b/releasenotes/notes/bug1929429-e749f5e5a242a599.yaml
new file mode 100644
index 000000000..d7a7e3d6e
--- /dev/null
+++ b/releasenotes/notes/bug1929429-e749f5e5a242a599.yaml
@@ -0,0 +1,8 @@
+---
+fixes:
+ - |
+ PowerMax driver `bug #1929429
+ <https://bugs.launchpad.net/cinder/+bug/1929429>`_: Fixes
+ child/parent storage group check so that a pattern match
+ is not case sensitive. For example, myStorageGroup should
+ equal MYSTORAGEGROUP and mystoragegroup.
diff --git a/releasenotes/notes/hpe-3par-primera-add-iscsi-5af339643dfa0928.yaml b/releasenotes/notes/hpe-3par-primera-add-iscsi-5af339643dfa0928.yaml
new file mode 100644
index 000000000..03166024b
--- /dev/null
+++ b/releasenotes/notes/hpe-3par-primera-add-iscsi-5af339643dfa0928.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ HPE 3PAR Driver: Add support of iSCSI driver for Primera 4.2
+ or higher versions.