From c4f8f885d47375c4febcb96e7ee8f3189050cc81 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 7 Oct 2015 17:57:00 +0200 Subject: [PATCH] Port EMC scaleio to Python 3 * Import urllib modules using six.moves.urllib * MockHTTPSResponse: encode HTTP body to UTF-8 if it's Unicode, replace six.string_types with (bytes, six.text_type). * _id_to_base64(): catch also binascii.Error when calling b16decode(); encode name to UTF-8 before calling b64encode(); decode b64encode() from ASCII on Python 3 to get Unicode. * tox.ini: add cinder.tests.unit.volume.drivers.emc.scaleio to Python 3.4 Partial-Implements: blueprint cinder-python3 Change-Id: I93353d48f80971528f47c9291cd04e198632dd0b --- .../unit/volume/drivers/emc/scaleio/mocks.py | 6 ++++-- .../emc/scaleio/test_create_cloned_volume.py | 11 +++++----- .../emc/scaleio/test_create_snapshot.py | 12 ++++++----- .../test_create_volume_from_snapshot.py | 11 +++++----- .../emc/scaleio/test_delete_snapshot.py | 6 +++--- .../drivers/emc/scaleio/test_delete_volume.py | 6 +++--- .../drivers/emc/scaleio/test_extend_volume.py | 6 +++--- .../volume/drivers/emc/scaleio/test_misc.py | 6 +++--- cinder/volume/drivers/emc/scaleio.py | 21 ++++++++++++------- tests-py3.txt | 1 + 10 files changed, 50 insertions(+), 36 deletions(-) diff --git a/cinder/tests/unit/volume/drivers/emc/scaleio/mocks.py b/cinder/tests/unit/volume/drivers/emc/scaleio/mocks.py index 91bdd687a..5b8c630f6 100644 --- a/cinder/tests/unit/volume/drivers/emc/scaleio/mocks.py +++ b/cinder/tests/unit/volume/drivers/emc/scaleio/mocks.py @@ -99,18 +99,20 @@ class MockHTTPSResponse(requests.Response): def __init__(self, content, status_code=200): super(MockHTTPSResponse, self).__init__() + if isinstance(content, six.text_type): + content = content.encode('utf-8') self._content = content self.status_code = status_code def json(self, **kwargs): - if isinstance(self._content, six.string_types): + if isinstance(self._content, (bytes, six.text_type)): return super(MockHTTPSResponse, self).json(**kwargs) return self._content @property def text(self): - if not isinstance(self._content, six.string_types): + if not isinstance(self._content, (bytes, six.text_type)): return json.dumps(self._content) return super(MockHTTPSResponse, self).text diff --git a/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_cloned_volume.py b/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_cloned_volume.py index eb959dc72..a2ff534d6 100644 --- a/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_cloned_volume.py +++ b/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_cloned_volume.py @@ -14,7 +14,8 @@ # under the License. import json -import urllib + +from six.moves import urllib from cinder import context from cinder import exception @@ -36,8 +37,8 @@ class TestCreateClonedVolume(scaleio.TestScaleIODriver): self.src_volume = fake_volume.fake_volume_obj( ctx, **{'provider_id': 'pid001'}) - self.src_volume_name_2x_enc = urllib.quote( - urllib.quote( + self.src_volume_name_2x_enc = urllib.parse.quote( + urllib.parse.quote( self.driver._id_to_base64(self.src_volume.id) ) ) @@ -51,8 +52,8 @@ class TestCreateClonedVolume(scaleio.TestScaleIODriver): ctx, **self.new_volume_extras ) - self.new_volume_name_2x_enc = urllib.quote( - urllib.quote( + self.new_volume_name_2x_enc = urllib.parse.quote( + urllib.parse.quote( self.driver._id_to_base64(self.new_volume.id) ) ) diff --git a/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_snapshot.py b/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_snapshot.py index c3c5afd7b..70a01cb68 100644 --- a/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_snapshot.py +++ b/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_snapshot.py @@ -13,7 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. import json -import urllib + +from six.moves import urllib from cinder import context from cinder import db @@ -46,11 +47,12 @@ class TestCreateSnapShot(scaleio.TestScaleIODriver): self.mock_object(db, 'volume_get', self.return_fake_volume) - self.volume_name_2x_enc = urllib.quote( - urllib.quote(self.driver._id_to_base64(self.snapshot.volume_id)) + snap_vol_id = self.snapshot.volume_id + self.volume_name_2x_enc = urllib.parse.quote( + urllib.parse.quote(self.driver._id_to_base64(snap_vol_id)) ) - self.snapshot_name_2x_enc = urllib.quote( - urllib.quote(self.driver._id_to_base64(self.snapshot.id)) + self.snapshot_name_2x_enc = urllib.parse.quote( + urllib.parse.quote(self.driver._id_to_base64(self.snapshot.id)) ) self.snapshot_reply = json.dumps( diff --git a/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_volume_from_snapshot.py b/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_volume_from_snapshot.py index acf2832d7..0965f0e05 100644 --- a/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_volume_from_snapshot.py +++ b/cinder/tests/unit/volume/drivers/emc/scaleio/test_create_volume_from_snapshot.py @@ -13,7 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. import json -import urllib + +from six.moves import urllib from cinder import context from cinder import exception @@ -35,12 +36,12 @@ class TestCreateVolumeFromSnapShot(scaleio.TestScaleIODriver): ctx = context.RequestContext('fake', 'fake', auth_token=True) self.snapshot = fake_snapshot.fake_snapshot_obj(ctx) - self.snapshot_name_2x_enc = urllib.quote( - urllib.quote(self.driver._id_to_base64(self.snapshot.id)) + self.snapshot_name_2x_enc = urllib.parse.quote( + urllib.parse.quote(self.driver._id_to_base64(self.snapshot.id)) ) self.volume = fake_volume.fake_volume_obj(ctx) - self.volume_name_2x_enc = urllib.quote( - urllib.quote(self.driver._id_to_base64(self.volume.id)) + self.volume_name_2x_enc = urllib.parse.quote( + urllib.parse.quote(self.driver._id_to_base64(self.volume.id)) ) self.snapshot_reply = json.dumps( diff --git a/cinder/tests/unit/volume/drivers/emc/scaleio/test_delete_snapshot.py b/cinder/tests/unit/volume/drivers/emc/scaleio/test_delete_snapshot.py index 0ae28d077..6d49f718b 100644 --- a/cinder/tests/unit/volume/drivers/emc/scaleio/test_delete_snapshot.py +++ b/cinder/tests/unit/volume/drivers/emc/scaleio/test_delete_snapshot.py @@ -12,7 +12,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -import urllib +from six.moves import urllib from cinder import context from cinder import exception @@ -34,8 +34,8 @@ class TestDeleteSnapShot(scaleio.TestScaleIODriver): self.snapshot = fake_snapshot_obj( ctx, **{'provider_id': 'snap_1'}) - self.snapshot_name_2x_enc = urllib.quote( - urllib.quote( + self.snapshot_name_2x_enc = urllib.parse.quote( + urllib.parse.quote( self.driver._id_to_base64(self.snapshot.id) ) ) diff --git a/cinder/tests/unit/volume/drivers/emc/scaleio/test_delete_volume.py b/cinder/tests/unit/volume/drivers/emc/scaleio/test_delete_volume.py index 475982e98..eab91d57c 100644 --- a/cinder/tests/unit/volume/drivers/emc/scaleio/test_delete_volume.py +++ b/cinder/tests/unit/volume/drivers/emc/scaleio/test_delete_volume.py @@ -12,7 +12,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -import urllib +from six.moves import urllib from cinder import context from cinder import exception @@ -34,8 +34,8 @@ class TestDeleteVolume(scaleio.TestScaleIODriver): self.volume = fake_volume.fake_volume_obj( ctx, **{'provider_id': 'pid_1'}) - self.volume_name_2x_enc = urllib.quote( - urllib.quote(self.driver._id_to_base64(self.volume.id)) + self.volume_name_2x_enc = urllib.parse.quote( + urllib.parse.quote(self.driver._id_to_base64(self.volume.id)) ) self.HTTPS_MOCK_RESPONSES = { diff --git a/cinder/tests/unit/volume/drivers/emc/scaleio/test_extend_volume.py b/cinder/tests/unit/volume/drivers/emc/scaleio/test_extend_volume.py index fca55f40c..42dc498a2 100644 --- a/cinder/tests/unit/volume/drivers/emc/scaleio/test_extend_volume.py +++ b/cinder/tests/unit/volume/drivers/emc/scaleio/test_extend_volume.py @@ -12,7 +12,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -import urllib +from six.moves import urllib from cinder import context from cinder import exception @@ -42,8 +42,8 @@ class TestExtendVolume(scaleio.TestScaleIODriver): self.volume = fake_volume_obj(ctx, **{'id': 'fake_volume', 'provider_id': 'pid_1'}) - self.volume_name_2x_enc = urllib.quote( - urllib.quote(self.driver._id_to_base64(self.volume.id)) + self.volume_name_2x_enc = urllib.parse.quote( + urllib.parse.quote(self.driver._id_to_base64(self.volume.id)) ) self.HTTPS_MOCK_RESPONSES = { diff --git a/cinder/tests/unit/volume/drivers/emc/scaleio/test_misc.py b/cinder/tests/unit/volume/drivers/emc/scaleio/test_misc.py index e7e20a474..9e82a0376 100644 --- a/cinder/tests/unit/volume/drivers/emc/scaleio/test_misc.py +++ b/cinder/tests/unit/volume/drivers/emc/scaleio/test_misc.py @@ -12,7 +12,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -import urllib +from six.moves import urllib from cinder import exception from cinder.tests.unit.volume.drivers.emc import scaleio @@ -30,8 +30,8 @@ class TestMisc(scaleio.TestScaleIODriver): """ super(TestMisc, self).setUp() - self.domain_name_enc = urllib.quote(self.DOMAIN_NAME) - self.pool_name_enc = urllib.quote(self.POOL_NAME) + self.domain_name_enc = urllib.parse.quote(self.DOMAIN_NAME) + self.pool_name_enc = urllib.parse.quote(self.POOL_NAME) self.HTTPS_MOCK_RESPONSES = { self.RESPONSE_MODE.Valid: { diff --git a/cinder/volume/drivers/emc/scaleio.py b/cinder/volume/drivers/emc/scaleio.py index c74d3951e..7d80597ce 100644 --- a/cinder/volume/drivers/emc/scaleio.py +++ b/cinder/volume/drivers/emc/scaleio.py @@ -17,6 +17,7 @@ Driver for EMC ScaleIO based on ScaleIO remote CLI. """ import base64 +import binascii import json from os_brick.initiator import connector @@ -25,7 +26,7 @@ from oslo_log import log as logging from oslo_utils import units import requests import six -import urllib +from six.moves import urllib from cinder import context from cinder import exception @@ -250,9 +251,14 @@ class ScaleIODriver(driver.VolumeDriver): name = six.text_type(id).replace("-", "") try: name = base64.b16decode(name.upper()) - except TypeError: + except (TypeError, binascii.Error): pass - encoded_name = base64.b64encode(name) + encoded_name = name + if isinstance(encoded_name, six.text_type): + encoded_name = encoded_name.encode('utf-8') + encoded_name = base64.b64encode(encoded_name) + if six.PY3: + encoded_name = encoded_name.decode('ascii') LOG.debug( "Converted id %(id)s to scaleio name %(name)s.", {'id': id, 'name': encoded_name}) @@ -307,7 +313,8 @@ class ScaleIODriver(driver.VolumeDriver): " protection domain id.") raise exception.VolumeBackendAPIException(data=msg) - encoded_domain_name = urllib.quote(self.protection_domain_name, '') + domain_name = self.protection_domain_name + encoded_domain_name = urllib.parse.quote(domain_name, '') req_vars = {'server_ip': self.server_ip, 'server_port': self.server_port, 'encoded_domain_name': encoded_domain_name} @@ -341,7 +348,7 @@ class ScaleIODriver(driver.VolumeDriver): pool_name = self.storage_pool_name pool_id = self.storage_pool_id if pool_name: - encoded_domain_name = urllib.quote(pool_name, '') + encoded_domain_name = urllib.parse.quote(pool_name, '') req_vars = {'server_ip': self.server_ip, 'server_port': self.server_port, 'domain_id': domain_id, @@ -702,7 +709,7 @@ class ScaleIODriver(driver.VolumeDriver): {'domain': domain_name, 'pool': pool_name}) # Get domain id from name. - encoded_domain_name = urllib.quote(domain_name, '') + encoded_domain_name = urllib.parse.quote(domain_name, '') req_vars = {'server_ip': self.server_ip, 'server_port': self.server_port, 'encoded_domain_name': encoded_domain_name} @@ -738,7 +745,7 @@ class ScaleIODriver(driver.VolumeDriver): LOG.info(_LI("Domain id is %s."), domain_id) # Get pool id from name. - encoded_pool_name = urllib.quote(pool_name, '') + encoded_pool_name = urllib.parse.quote(pool_name, '') req_vars = {'server_ip': self.server_ip, 'server_port': self.server_port, 'domain_id': domain_id, diff --git a/tests-py3.txt b/tests-py3.txt index e933f6a31..6e06b4f16 100644 --- a/tests-py3.txt +++ b/tests-py3.txt @@ -91,6 +91,7 @@ cinder.tests.unit.test_volume_transfer cinder.tests.unit.test_volume_types cinder.tests.unit.test_volume_types_extra_specs cinder.tests.unit.test_volume_utils +cinder.tests.unit.volume.drivers.emc.scaleio cinder.tests.unit.volume.flows.test_create_volume_flow cinder.tests.unit.windows.test_smbfs cinder.tests.unit.windows.test_vhdutils -- 2.45.2