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
This commit is contained in:
Victor Stinner 2015-10-07 17:57:00 +02:00
parent a37618f55b
commit c4f8f885d4
10 changed files with 50 additions and 36 deletions

@ -99,18 +99,20 @@ class MockHTTPSResponse(requests.Response):
def __init__(self, content, status_code=200): def __init__(self, content, status_code=200):
super(MockHTTPSResponse, self).__init__() super(MockHTTPSResponse, self).__init__()
if isinstance(content, six.text_type):
content = content.encode('utf-8')
self._content = content self._content = content
self.status_code = status_code self.status_code = status_code
def json(self, **kwargs): 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 super(MockHTTPSResponse, self).json(**kwargs)
return self._content return self._content
@property @property
def text(self): 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 json.dumps(self._content)
return super(MockHTTPSResponse, self).text return super(MockHTTPSResponse, self).text

@ -14,7 +14,8 @@
# under the License. # under the License.
import json import json
import urllib
from six.moves import urllib
from cinder import context from cinder import context
from cinder import exception from cinder import exception
@ -36,8 +37,8 @@ class TestCreateClonedVolume(scaleio.TestScaleIODriver):
self.src_volume = fake_volume.fake_volume_obj( self.src_volume = fake_volume.fake_volume_obj(
ctx, **{'provider_id': 'pid001'}) ctx, **{'provider_id': 'pid001'})
self.src_volume_name_2x_enc = urllib.quote( self.src_volume_name_2x_enc = urllib.parse.quote(
urllib.quote( urllib.parse.quote(
self.driver._id_to_base64(self.src_volume.id) self.driver._id_to_base64(self.src_volume.id)
) )
) )
@ -51,8 +52,8 @@ class TestCreateClonedVolume(scaleio.TestScaleIODriver):
ctx, **self.new_volume_extras ctx, **self.new_volume_extras
) )
self.new_volume_name_2x_enc = urllib.quote( self.new_volume_name_2x_enc = urllib.parse.quote(
urllib.quote( urllib.parse.quote(
self.driver._id_to_base64(self.new_volume.id) self.driver._id_to_base64(self.new_volume.id)
) )
) )

@ -13,7 +13,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import json import json
import urllib
from six.moves import urllib
from cinder import context from cinder import context
from cinder import db from cinder import db
@ -46,11 +47,12 @@ class TestCreateSnapShot(scaleio.TestScaleIODriver):
self.mock_object(db, 'volume_get', self.return_fake_volume) self.mock_object(db, 'volume_get', self.return_fake_volume)
self.volume_name_2x_enc = urllib.quote( snap_vol_id = self.snapshot.volume_id
urllib.quote(self.driver._id_to_base64(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( self.snapshot_name_2x_enc = urllib.parse.quote(
urllib.quote(self.driver._id_to_base64(self.snapshot.id)) urllib.parse.quote(self.driver._id_to_base64(self.snapshot.id))
) )
self.snapshot_reply = json.dumps( self.snapshot_reply = json.dumps(

@ -13,7 +13,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import json import json
import urllib
from six.moves import urllib
from cinder import context from cinder import context
from cinder import exception from cinder import exception
@ -35,12 +36,12 @@ class TestCreateVolumeFromSnapShot(scaleio.TestScaleIODriver):
ctx = context.RequestContext('fake', 'fake', auth_token=True) ctx = context.RequestContext('fake', 'fake', auth_token=True)
self.snapshot = fake_snapshot.fake_snapshot_obj(ctx) self.snapshot = fake_snapshot.fake_snapshot_obj(ctx)
self.snapshot_name_2x_enc = urllib.quote( self.snapshot_name_2x_enc = urllib.parse.quote(
urllib.quote(self.driver._id_to_base64(self.snapshot.id)) urllib.parse.quote(self.driver._id_to_base64(self.snapshot.id))
) )
self.volume = fake_volume.fake_volume_obj(ctx) self.volume = fake_volume.fake_volume_obj(ctx)
self.volume_name_2x_enc = urllib.quote( self.volume_name_2x_enc = urllib.parse.quote(
urllib.quote(self.driver._id_to_base64(self.volume.id)) urllib.parse.quote(self.driver._id_to_base64(self.volume.id))
) )
self.snapshot_reply = json.dumps( self.snapshot_reply = json.dumps(

@ -12,7 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import urllib from six.moves import urllib
from cinder import context from cinder import context
from cinder import exception from cinder import exception
@ -34,8 +34,8 @@ class TestDeleteSnapShot(scaleio.TestScaleIODriver):
self.snapshot = fake_snapshot_obj( self.snapshot = fake_snapshot_obj(
ctx, **{'provider_id': 'snap_1'}) ctx, **{'provider_id': 'snap_1'})
self.snapshot_name_2x_enc = urllib.quote( self.snapshot_name_2x_enc = urllib.parse.quote(
urllib.quote( urllib.parse.quote(
self.driver._id_to_base64(self.snapshot.id) self.driver._id_to_base64(self.snapshot.id)
) )
) )

@ -12,7 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import urllib from six.moves import urllib
from cinder import context from cinder import context
from cinder import exception from cinder import exception
@ -34,8 +34,8 @@ class TestDeleteVolume(scaleio.TestScaleIODriver):
self.volume = fake_volume.fake_volume_obj( self.volume = fake_volume.fake_volume_obj(
ctx, **{'provider_id': 'pid_1'}) ctx, **{'provider_id': 'pid_1'})
self.volume_name_2x_enc = urllib.quote( self.volume_name_2x_enc = urllib.parse.quote(
urllib.quote(self.driver._id_to_base64(self.volume.id)) urllib.parse.quote(self.driver._id_to_base64(self.volume.id))
) )
self.HTTPS_MOCK_RESPONSES = { self.HTTPS_MOCK_RESPONSES = {

@ -12,7 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import urllib from six.moves import urllib
from cinder import context from cinder import context
from cinder import exception from cinder import exception
@ -42,8 +42,8 @@ class TestExtendVolume(scaleio.TestScaleIODriver):
self.volume = fake_volume_obj(ctx, **{'id': 'fake_volume', self.volume = fake_volume_obj(ctx, **{'id': 'fake_volume',
'provider_id': 'pid_1'}) 'provider_id': 'pid_1'})
self.volume_name_2x_enc = urllib.quote( self.volume_name_2x_enc = urllib.parse.quote(
urllib.quote(self.driver._id_to_base64(self.volume.id)) urllib.parse.quote(self.driver._id_to_base64(self.volume.id))
) )
self.HTTPS_MOCK_RESPONSES = { self.HTTPS_MOCK_RESPONSES = {

@ -12,7 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import urllib from six.moves import urllib
from cinder import exception from cinder import exception
from cinder.tests.unit.volume.drivers.emc import scaleio from cinder.tests.unit.volume.drivers.emc import scaleio
@ -30,8 +30,8 @@ class TestMisc(scaleio.TestScaleIODriver):
""" """
super(TestMisc, self).setUp() super(TestMisc, self).setUp()
self.domain_name_enc = urllib.quote(self.DOMAIN_NAME) self.domain_name_enc = urllib.parse.quote(self.DOMAIN_NAME)
self.pool_name_enc = urllib.quote(self.POOL_NAME) self.pool_name_enc = urllib.parse.quote(self.POOL_NAME)
self.HTTPS_MOCK_RESPONSES = { self.HTTPS_MOCK_RESPONSES = {
self.RESPONSE_MODE.Valid: { self.RESPONSE_MODE.Valid: {

@ -17,6 +17,7 @@ Driver for EMC ScaleIO based on ScaleIO remote CLI.
""" """
import base64 import base64
import binascii
import json import json
from os_brick.initiator import connector from os_brick.initiator import connector
@ -25,7 +26,7 @@ from oslo_log import log as logging
from oslo_utils import units from oslo_utils import units
import requests import requests
import six import six
import urllib from six.moves import urllib
from cinder import context from cinder import context
from cinder import exception from cinder import exception
@ -250,9 +251,14 @@ class ScaleIODriver(driver.VolumeDriver):
name = six.text_type(id).replace("-", "") name = six.text_type(id).replace("-", "")
try: try:
name = base64.b16decode(name.upper()) name = base64.b16decode(name.upper())
except TypeError: except (TypeError, binascii.Error):
pass 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( LOG.debug(
"Converted id %(id)s to scaleio name %(name)s.", "Converted id %(id)s to scaleio name %(name)s.",
{'id': id, 'name': encoded_name}) {'id': id, 'name': encoded_name})
@ -307,7 +313,8 @@ class ScaleIODriver(driver.VolumeDriver):
" protection domain id.") " protection domain id.")
raise exception.VolumeBackendAPIException(data=msg) 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, req_vars = {'server_ip': self.server_ip,
'server_port': self.server_port, 'server_port': self.server_port,
'encoded_domain_name': encoded_domain_name} 'encoded_domain_name': encoded_domain_name}
@ -341,7 +348,7 @@ class ScaleIODriver(driver.VolumeDriver):
pool_name = self.storage_pool_name pool_name = self.storage_pool_name
pool_id = self.storage_pool_id pool_id = self.storage_pool_id
if pool_name: 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, req_vars = {'server_ip': self.server_ip,
'server_port': self.server_port, 'server_port': self.server_port,
'domain_id': domain_id, 'domain_id': domain_id,
@ -702,7 +709,7 @@ class ScaleIODriver(driver.VolumeDriver):
{'domain': domain_name, {'domain': domain_name,
'pool': pool_name}) 'pool': pool_name})
# Get domain id from 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, req_vars = {'server_ip': self.server_ip,
'server_port': self.server_port, 'server_port': self.server_port,
'encoded_domain_name': encoded_domain_name} 'encoded_domain_name': encoded_domain_name}
@ -738,7 +745,7 @@ class ScaleIODriver(driver.VolumeDriver):
LOG.info(_LI("Domain id is %s."), domain_id) LOG.info(_LI("Domain id is %s."), domain_id)
# Get pool id from name. # 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, req_vars = {'server_ip': self.server_ip,
'server_port': self.server_port, 'server_port': self.server_port,
'domain_id': domain_id, 'domain_id': domain_id,

@ -91,6 +91,7 @@ cinder.tests.unit.test_volume_transfer
cinder.tests.unit.test_volume_types cinder.tests.unit.test_volume_types
cinder.tests.unit.test_volume_types_extra_specs cinder.tests.unit.test_volume_types_extra_specs
cinder.tests.unit.test_volume_utils 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.volume.flows.test_create_volume_flow
cinder.tests.unit.windows.test_smbfs cinder.tests.unit.windows.test_smbfs
cinder.tests.unit.windows.test_vhdutils cinder.tests.unit.windows.test_vhdutils