623a8c1c20
Date: Thu Sep 15 23:18:25 2016 +0000 9.0.0_rc1 retag of cinder 9.0.0.0rc1 release candidate -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJX4XxWAAoJENQWrRWsa0P+8xQQAIoDpgtGnl+3WtMBZhScaQ7H fd/QlqNzG/6lsO7BMlvkZD/L+qX/ffvqsi/qRGjuYfeklbVPOWdRCoynmQ28Xw3U HyqB6WOK7s8HAZdyoSFFCyTb6fhTPN+07ExnLgoKg1k8/J0WTy5IqCKvo0NlRMYT ldyLBufaWqCwIx096LcLVDODVgAFd9OWLJwwhsacOOIUDXa5bnAAKzqCsvQHeHcF tbkxmu/qAfhzjjNEwMOlumdnHyOHKjV2pWZm3g6LOoUxzFp7KIE2eDzdRCMvHo2Q d3yVmdyR+DZEphEwybZvAN4IWj7Zh6s05+KBxksz4ApUZ094uBBbMGVy0wodzkeC NRz6WkycVyqXfmjqyjH0PQX4DnqcInbZRcTaN0/d2KN2dhxl7bxPWFPraYssr1Do Su/S6qty8GLXdY85JUsAVmWGuyTv2l5vshFeZoHGdrtTzEKbEx0/IKCxBhh2T2eg ELFA9zmLn+NURB/j9Sw57wfXdX7oNu7/rcujCD54vKA/BhNN0SjwqHW0c7kDge2z UXcowyuMZswgGo/8UKkpa5XDy7EWYKykCT0/JejiU958bOwCP5zgu9P3nlhPUip3 PU8QabUMoRRU9vLZAVLagDWdbP77JCayxqHqqk2UEY36c5zyRGDTzL+b5eaBMcZa y27cHXfmkgicHyjV1564 =iUgO -----END PGP SIGNATURE----- Merge tag '9.0.0_rc1' into debian/newton Tagger: OpenStack Release Bot <infra-root@openstack.org> Date: Thu Sep 15 23:18:25 2016 +0000 9.0.0_rc1 retag of cinder 9.0.0.0rc1 release candidate * Edit changelog to package rc1. * Fixed os-win required version. * Refreshed no-zfssa-tests.patch and remove-zfssa-from-opts.py.patch * Add python-pep8 in build-depends-indep. Change-Id: I95fbdd936e381b27eb126ac10df61d8609e5b545
1729 lines
77 KiB
Diff
1729 lines
77 KiB
Diff
Description: No zfssa tests
|
|
Author: Thomas Goirand <zigo@debian.org>
|
|
Forwarded: not-needed
|
|
Last-Update: 2016-09-21
|
|
|
|
--- a/cinder/tests/unit/volume/drivers/test_zfssa.py 2016-09-21 09:00:44.156129355 +0200
|
|
+++ /dev/null 2016-09-01 16:08:01.266394396 +0200
|
|
@@ -1,1720 +0,0 @@
|
|
-# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
-#
|
|
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
-# not use this file except in compliance with the License. You may obtain
|
|
-# a copy of the License at
|
|
-#
|
|
-# http://www.apache.org/licenses/LICENSE-2.0
|
|
-#
|
|
-# Unless required by applicable law or agreed to in writing, software
|
|
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
-# License for the specific language governing permissions and limitations
|
|
-# under the License.
|
|
-"""Unit tests for Oracle's ZFSSA Cinder volume driver."""
|
|
-
|
|
-from datetime import date
|
|
-import json
|
|
-import math
|
|
-
|
|
-import mock
|
|
-from oslo_utils import units
|
|
-import six
|
|
-
|
|
-from cinder import context
|
|
-from cinder import exception
|
|
-from cinder.image import image_utils
|
|
-from cinder import test
|
|
-from cinder.tests.unit import fake_utils
|
|
-from cinder.tests.unit import utils
|
|
-from cinder.volume import configuration as conf
|
|
-from cinder.volume import driver
|
|
-from cinder.volume.drivers import remotefs
|
|
-from cinder.volume.drivers.zfssa import restclient as client
|
|
-from cinder.volume.drivers.zfssa import webdavclient
|
|
-from cinder.volume.drivers.zfssa import zfssaiscsi as iscsi
|
|
-from cinder.volume.drivers.zfssa import zfssanfs
|
|
-from cinder.volume.drivers.zfssa import zfssarest as rest
|
|
-
|
|
-
|
|
-nfs_logbias = 'latency'
|
|
-nfs_compression = 'off'
|
|
-zfssa_cache_dir = 'os-cinder-cache'
|
|
-
|
|
-no_virtsize_img = {
|
|
- 'id': 'no_virtsize_img_id1234',
|
|
- 'size': 654321,
|
|
- 'updated_at': date(2015, 1, 1),
|
|
-}
|
|
-
|
|
-small_img = {
|
|
- 'id': '1e5177e7-95e5-4a0f-b170-e45f4b469f6a',
|
|
- 'size': 654321,
|
|
- 'virtual_size': 2361393152,
|
|
- 'updated_at': date(2015, 1, 1),
|
|
-}
|
|
-
|
|
-large_img = {
|
|
- 'id': 'large_id5678',
|
|
- 'size': 50000000,
|
|
- 'virtual_size': 11806965760,
|
|
- 'updated_at': date(2015, 2, 2),
|
|
-}
|
|
-
|
|
-fakespecs = {
|
|
- 'prop1': 'prop1_val',
|
|
- 'prop2': 'prop2_val',
|
|
-}
|
|
-
|
|
-small_img_props = {
|
|
- 'size': 3,
|
|
-}
|
|
-
|
|
-img_props_nfs = {
|
|
- 'image_id': small_img['id'],
|
|
- 'updated_at': small_img['updated_at'].isoformat(),
|
|
- 'size': 3,
|
|
- 'name': '%(dir)s/os-cache-vol-%(name)s' % ({'dir': zfssa_cache_dir,
|
|
- 'name': small_img['id']}),
|
|
- 'id': small_img['id']
|
|
-}
|
|
-
|
|
-fakecontext = 'fakecontext'
|
|
-img_service = 'fakeimgservice'
|
|
-img_location = 'fakeimglocation'
|
|
-
|
|
-
|
|
-class ImgInfo(object):
|
|
- def __init__(self, vsize):
|
|
- self.virtual_size = vsize
|
|
-
|
|
-
|
|
-class FakeResponse(object):
|
|
- def __init__(self, statuscode, data='data'):
|
|
- self.status = statuscode
|
|
- self.data = data
|
|
-
|
|
-
|
|
-class FakeSSL(object):
|
|
- def _create_unverified_context(self):
|
|
- return 'fakecontext'
|
|
-
|
|
-
|
|
-class TestZFSSAISCSIDriver(test.TestCase):
|
|
-
|
|
- test_vol = {
|
|
- 'name': 'cindervol',
|
|
- 'size': 3,
|
|
- 'id': 1,
|
|
- 'provider_location': 'fake_location 1 2',
|
|
- 'provider_auth': 'fake_auth user pass',
|
|
- }
|
|
-
|
|
- test_vol2 = {
|
|
- 'name': 'cindervol2',
|
|
- 'size': 5,
|
|
- 'id': 2,
|
|
- 'provider_location': 'fake_location 3 4',
|
|
- 'provider_auth': 'fake_auth user pass',
|
|
- }
|
|
-
|
|
- test_snap = {
|
|
- 'name': 'cindersnap',
|
|
- 'volume_name': test_vol['name']
|
|
- }
|
|
-
|
|
- test_vol_snap = {
|
|
- 'name': 'cindersnapvol',
|
|
- 'size': test_vol['size']
|
|
- }
|
|
-
|
|
- def __init__(self, method):
|
|
- super(TestZFSSAISCSIDriver, self).__init__(method)
|
|
-
|
|
- @mock.patch.object(iscsi, 'factory_zfssa')
|
|
- def setUp(self, _factory_zfssa):
|
|
- super(TestZFSSAISCSIDriver, self).setUp()
|
|
- self._create_fake_config()
|
|
- _factory_zfssa.return_value = mock.MagicMock(spec=rest.ZFSSAApi)
|
|
- iscsi.ZFSSAISCSIDriver._execute = fake_utils.fake_execute
|
|
- self.drv = iscsi.ZFSSAISCSIDriver(configuration=self.configuration)
|
|
- self.drv.do_setup({})
|
|
-
|
|
- def _create_fake_config(self):
|
|
- self.configuration = mock.Mock(spec=conf.Configuration)
|
|
- self.configuration.san_ip = '1.1.1.1'
|
|
- self.configuration.san_login = 'user'
|
|
- self.configuration.san_password = 'passwd'
|
|
- self.configuration.zfssa_pool = 'pool'
|
|
- self.configuration.zfssa_project = 'project'
|
|
- self.configuration.zfssa_lun_volblocksize = '8k'
|
|
- self.configuration.zfssa_lun_sparse = 'false'
|
|
- self.configuration.zfssa_lun_logbias = 'latency'
|
|
- self.configuration.zfssa_lun_compression = 'off'
|
|
- self.configuration.zfssa_initiator_group = 'test-init-grp1'
|
|
- self.configuration.zfssa_initiator = \
|
|
- 'iqn.1-0.org.deb:01:d7, iqn.1-0.org.deb:01:d9'
|
|
- self.configuration.zfssa_initiator_user = ''
|
|
- self.configuration.zfssa_initiator_password = ''
|
|
- self.configuration.zfssa_initiator_config = "{'test-init-grp1':[{'iqn':\
|
|
- 'iqn.1-0.org.deb:01:d7','user':'','password':''}],'test-init-grp\
|
|
- 2':[{'iqn':'iqn.1-0.org.deb:01:d9','user':'','password':''}]}"
|
|
- self.configuration.zfssa_target_group = 'test-target-grp1'
|
|
- self.configuration.zfssa_target_user = ''
|
|
- self.configuration.zfssa_target_password = ''
|
|
- self.configuration.zfssa_target_portal = '1.1.1.1:3260'
|
|
- self.configuration.zfssa_target_interfaces = 'e1000g0'
|
|
- self.configuration.zfssa_rest_timeout = 60
|
|
- self.configuration.volume_backend_name = 'fake_zfssa'
|
|
- self.configuration.zfssa_enable_local_cache = True
|
|
- self.configuration.zfssa_cache_project = zfssa_cache_dir
|
|
- self.configuration.safe_get = self.fake_safe_get
|
|
- self.configuration.zfssa_replication_ip = '1.1.1.1'
|
|
- self.configuration.zfssa_manage_policy = 'loose'
|
|
-
|
|
- def _util_migrate_volume_exceptions(self):
|
|
- self.drv.zfssa.get_lun.return_value = (
|
|
- {'targetgroup': 'test-target-grp1'})
|
|
- self.drv.zfssa.get_asn.return_value = (
|
|
- '9a2b5a0f-e3af-6d14-9578-8825f229dc89')
|
|
- self.drv.tgt_zfssa.get_asn.return_value = (
|
|
- '9a2b5a0f-e3af-6d14-9578-8825f229dc89')
|
|
- targets = {'targets': [{'hostname': '2.2.2.2',
|
|
- 'address': '2.2.2.2:216',
|
|
- 'label': '2.2.2.2',
|
|
- 'asn':
|
|
- '9a2b5a0f-e3af-6d14-9578-8825f229dc89'}]}
|
|
-
|
|
- self.drv.zfssa.get_replication_targets.return_value = targets
|
|
- self.drv.zfssa.edit_inherit_replication_flag.return_value = {}
|
|
- self.drv.zfssa.create_replication_action.return_value = 'action-123'
|
|
- self.drv.zfssa.send_repl_update.return_value = True
|
|
-
|
|
- def test_migrate_volume(self):
|
|
- self._util_migrate_volume_exceptions()
|
|
-
|
|
- volume = self.test_vol
|
|
- volume.update({'host': 'fake_host',
|
|
- 'status': 'available',
|
|
- 'name': 'vol-1',
|
|
- 'source_volid': self.test_vol['id']})
|
|
-
|
|
- loc_info = '2.2.2.2:fake_auth:pool2:project2:test-target-grp1:2.2.2.2'
|
|
-
|
|
- host = {'host': 'stack@zfssa_iscsi#fake_zfssa',
|
|
- 'capabilities': {'vendor_name': 'Oracle',
|
|
- 'storage_protocol': 'iSCSI',
|
|
- 'location_info': loc_info}}
|
|
- ctxt = context.get_admin_context()
|
|
-
|
|
- # Test the normal case
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((True, None), result)
|
|
-
|
|
- # Test when volume status is not available
|
|
- volume['status'] = 'in-use'
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
- volume['status'] = 'available'
|
|
-
|
|
- # Test when vendor is not Oracle
|
|
- host['capabilities']['vendor_name'] = 'elcarO'
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
- host['capabilities']['vendor_name'] = 'Oracle'
|
|
-
|
|
- # Test when storage protocol is not iSCSI
|
|
- host['capabilities']['storage_protocol'] = 'not_iSCSI'
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
- host['capabilities']['storage_protocol'] = 'iSCSI'
|
|
-
|
|
- # Test when location_info is incorrect
|
|
- host['capabilities']['location_info'] = ''
|
|
- self.assertEqual((False, None), result)
|
|
- host['capabilities']['location_info'] = loc_info
|
|
-
|
|
- # Test if replication ip and replication target's address dont match
|
|
- invalid_loc_info = (
|
|
- '2.2.2.2:fake_auth:pool2:project2:test-target-grp1:9.9.9.9')
|
|
- host['capabilities']['location_info'] = invalid_loc_info
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
- host['capabilities']['location_info'] = loc_info
|
|
-
|
|
- # Test if no targets are returned
|
|
- self.drv.zfssa.get_replication_targets.return_value = {'targets': []}
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
-
|
|
- def test_migrate_volume_uninherit_exception(self):
|
|
- self._util_migrate_volume_exceptions()
|
|
-
|
|
- volume = self.test_vol
|
|
- volume.update({'host': 'fake_host',
|
|
- 'status': 'available',
|
|
- 'name': 'vol-1',
|
|
- 'source_volid': self.test_vol['id']})
|
|
-
|
|
- loc_info = '2.2.2.2:fake_auth:pool2:project2:test-target-grp1:2.2.2.2'
|
|
-
|
|
- host = {'host': 'stack@zfssa_iscsi#fake_zfssa',
|
|
- 'capabilities': {'vendor_name': 'Oracle',
|
|
- 'storage_protocol': 'iSCSI',
|
|
- 'location_info': loc_info}}
|
|
- ctxt = context.get_admin_context()
|
|
-
|
|
- self.drv.zfssa.edit_inherit_replication_flag.side_effect = (
|
|
- exception.VolumeBackendAPIException(data='uniherit ex'))
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.migrate_volume, ctxt, volume, host)
|
|
-
|
|
- def test_migrate_volume_create_action_exception(self):
|
|
- self._util_migrate_volume_exceptions()
|
|
-
|
|
- volume = self.test_vol
|
|
- volume.update({'host': 'fake_host',
|
|
- 'status': 'available',
|
|
- 'name': 'vol-1',
|
|
- 'source_volid': self.test_vol['id']})
|
|
-
|
|
- loc_info = '2.2.2.2:fake_auth:pool2:project2:test-target-grp1:2.2.2.2'
|
|
-
|
|
- host = {'host': 'stack@zfssa_iscsi#fake_zfssa',
|
|
- 'capabilities': {'vendor_name': 'Oracle',
|
|
- 'storage_protocol': 'iSCSI',
|
|
- 'location_info': loc_info}}
|
|
- ctxt = context.get_admin_context()
|
|
-
|
|
- self.drv.zfssa.create_replication_action.side_effect = (
|
|
- exception.VolumeBackendAPIException(data=
|
|
- 'failed to create action'))
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.migrate_volume, ctxt, volume, host)
|
|
-
|
|
- def test_migrate_volume_send_update_exception(self):
|
|
- self._util_migrate_volume_exceptions()
|
|
-
|
|
- volume = self.test_vol
|
|
- volume.update({'host': 'fake_host',
|
|
- 'status': 'available',
|
|
- 'name': 'vol-1',
|
|
- 'source_volid': self.test_vol['id']})
|
|
-
|
|
- loc_info = '2.2.2.2:fake_auth:pool2:project2:test-target-grp1:2.2.2.2'
|
|
-
|
|
- host = {'host': 'stack@zfssa_iscsi#fake_zfssa',
|
|
- 'capabilities': {'vendor_name': 'Oracle',
|
|
- 'storage_protocol': 'iSCSI',
|
|
- 'location_info': loc_info}}
|
|
- ctxt = context.get_admin_context()
|
|
-
|
|
- self.drv.zfssa.send_repl_update.side_effect = (
|
|
- exception.VolumeBackendAPIException(data='failed to send update'))
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.migrate_volume, ctxt, volume, host)
|
|
-
|
|
- def test_migrate_volume_sever_repl_exception(self):
|
|
- self._util_migrate_volume_exceptions()
|
|
-
|
|
- volume = self.test_vol
|
|
- volume.update({'host': 'fake_host',
|
|
- 'status': 'available',
|
|
- 'name': 'vol-1',
|
|
- 'source_volid': self.test_vol['id']})
|
|
-
|
|
- loc_info = '2.2.2.2:fake_auth:pool2:project2:test-target-grp1:2.2.2.2'
|
|
-
|
|
- host = {'host': 'stack@zfssa_iscsi#fake_zfssa',
|
|
- 'capabilities': {'vendor_name': 'Oracle',
|
|
- 'storage_protocol': 'iSCSI',
|
|
- 'location_info': loc_info}}
|
|
- ctxt = context.get_admin_context()
|
|
- self.drv.tgt_zfssa.sever_replication.side_effect = (
|
|
- exception.VolumeBackendAPIException(data=
|
|
- 'failed to sever replication'))
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.migrate_volume, ctxt, volume, host)
|
|
-
|
|
- def test_create_delete_volume(self):
|
|
- self.drv.zfssa.get_lun.return_value = {'guid':
|
|
- '00000000000000000000000000000',
|
|
- 'number': 0,
|
|
- 'initiatorgroup': 'default',
|
|
- 'size': 1,
|
|
- 'nodestroy': False}
|
|
- lcfg = self.configuration
|
|
- self.drv.create_volume(self.test_vol)
|
|
- self.drv.zfssa.create_lun.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- self.test_vol['name'],
|
|
- six.text_type(self.test_vol['size']) + 'g',
|
|
- lcfg.zfssa_target_group,
|
|
- mock.ANY)
|
|
- self.drv.delete_volume(self.test_vol)
|
|
- self.drv.zfssa.get_lun.assert_called_once_with(lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- self.test_vol['name'])
|
|
- self.drv.zfssa.delete_lun.assert_called_once_with(
|
|
- pool=lcfg.zfssa_pool,
|
|
- project=lcfg.zfssa_project,
|
|
- lun=self.test_vol['name'])
|
|
-
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_check_origin')
|
|
- def test_delete_cache_volume(self, _check_origin):
|
|
- lcfg = self.configuration
|
|
- lun2del = {
|
|
- 'guid': '00000000000000000000000000000',
|
|
- 'number': 0,
|
|
- 'initiatorgroup': 'default',
|
|
- 'size': 1,
|
|
- 'nodestroy': False,
|
|
- 'origin': {
|
|
- 'project': lcfg.zfssa_cache_project,
|
|
- 'snapshot': 'image-%s' % small_img['id'],
|
|
- 'share': 'os-cache-vol-%s' % small_img['id'],
|
|
- }
|
|
- }
|
|
- self.drv.zfssa.get_lun.return_value = lun2del
|
|
- self.drv.delete_volume(self.test_vol)
|
|
- self.drv._check_origin.assert_called_once_with(lun2del,
|
|
- self.test_vol['name'])
|
|
-
|
|
- def test_check_origin(self):
|
|
- lcfg = self.configuration
|
|
- lun2del = {
|
|
- 'guid': '00000000000000000000000000000',
|
|
- 'number': 0,
|
|
- 'initiatorgroup': 'default',
|
|
- 'size': 1,
|
|
- 'nodestroy': False,
|
|
- 'origin': {
|
|
- 'project': lcfg.zfssa_cache_project,
|
|
- 'snapshot': 'image-%s' % small_img['id'],
|
|
- 'share': 'os-cache-vol-%s' % small_img['id'],
|
|
- }
|
|
- }
|
|
- cache = lun2del['origin']
|
|
- self.drv.zfssa.num_clones.return_value = 0
|
|
- self.drv._check_origin(lun2del, 'volname')
|
|
- self.drv.zfssa.delete_lun.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_cache_project,
|
|
- cache['share'])
|
|
-
|
|
- def test_create_delete_snapshot(self):
|
|
- self.drv.zfssa.num_clones.return_value = 0
|
|
- lcfg = self.configuration
|
|
- self.drv.create_snapshot(self.test_snap)
|
|
- self.drv.zfssa.create_snapshot.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- self.test_snap['volume_name'],
|
|
- self.test_snap['name'])
|
|
- self.drv.delete_snapshot(self.test_snap)
|
|
- self.drv.zfssa.delete_snapshot.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- self.test_snap['volume_name'],
|
|
- self.test_snap['name'])
|
|
-
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_verify_clone_size')
|
|
- def test_create_volume_from_snapshot(self, _verify_clone_size):
|
|
- self.drv._verify_clone_size.return_value = True
|
|
- lcfg = self.configuration
|
|
- self.drv.create_snapshot(self.test_snap)
|
|
- self.drv.zfssa.create_snapshot.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- self.test_snap['volume_name'],
|
|
- self.test_snap['name'])
|
|
- self.drv.create_volume_from_snapshot(self.test_vol_snap,
|
|
- self.test_snap)
|
|
- self.drv._verify_clone_size.assert_called_once_with(
|
|
- self.test_snap,
|
|
- self.test_vol_snap['size'] * units.Gi)
|
|
- self.drv.zfssa.clone_snapshot.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- self.test_snap['volume_name'],
|
|
- self.test_snap['name'],
|
|
- lcfg.zfssa_project,
|
|
- self.test_vol_snap['name'])
|
|
-
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_get_provider_info')
|
|
- def test_volume_attach_detach(self, _get_provider_info):
|
|
- lcfg = self.configuration
|
|
- test_target_iqn = 'iqn.1986-03.com.sun:02:00000-aaaa-bbbb-cccc-ddddd'
|
|
- stub_val = {'provider_location':
|
|
- '%s %s 0' % (lcfg.zfssa_target_portal, test_target_iqn)}
|
|
- self.drv._get_provider_info.return_value = stub_val
|
|
-
|
|
- connector = dict(initiator='iqn.1-0.org.deb:01:d7')
|
|
- props = self.drv.initialize_connection(self.test_vol, connector)
|
|
- self.drv._get_provider_info.assert_called_once_with(self.test_vol)
|
|
- self.assertEqual('iscsi', props['driver_volume_type'])
|
|
- self.assertEqual(self.test_vol['id'], props['data']['volume_id'])
|
|
- self.assertEqual(lcfg.zfssa_target_portal,
|
|
- props['data']['target_portal'])
|
|
- self.assertEqual(test_target_iqn, props['data']['target_iqn'])
|
|
- self.assertEqual(0, props['data']['target_lun'])
|
|
- self.assertFalse(props['data']['target_discovered'])
|
|
-
|
|
- self.drv.terminate_connection(self.test_vol, '')
|
|
- self.drv.zfssa.set_lun_initiatorgroup.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- self.test_vol['name'],
|
|
- '')
|
|
-
|
|
- def test_volume_attach_detach_negative(self):
|
|
- self.drv.zfssa.get_initiator_initiatorgroup.return_value = []
|
|
-
|
|
- connector = dict(initiator='iqn.1-0.org.deb:01:d7')
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.initialize_connection,
|
|
- self.test_vol,
|
|
- connector)
|
|
-
|
|
- def test_get_volume_stats(self):
|
|
- self.drv.zfssa.get_project_stats.return_value = 2 * units.Gi,\
|
|
- 3 * units.Gi
|
|
- self.drv.zfssa.get_pool_details.return_value = \
|
|
- {"profile": "mirror:log_stripe"}
|
|
- lcfg = self.configuration
|
|
- stats = self.drv.get_volume_stats(refresh=True)
|
|
- self.drv.zfssa.get_project_stats.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project)
|
|
- self.drv.zfssa.get_pool_details.assert_called_once_with(
|
|
- lcfg.zfssa_pool)
|
|
- self.assertEqual('Oracle', stats['vendor_name'])
|
|
- self.assertEqual(self.configuration.volume_backend_name,
|
|
- stats['volume_backend_name'])
|
|
- self.assertEqual(self.drv.VERSION, stats['driver_version'])
|
|
- self.assertEqual(self.drv.protocol, stats['storage_protocol'])
|
|
- self.assertEqual(0, stats['reserved_percentage'])
|
|
- self.assertFalse(stats['QoS_support'])
|
|
- self.assertEqual(3, stats['total_capacity_gb'])
|
|
- self.assertEqual(2, stats['free_capacity_gb'])
|
|
- self.assertEqual('mirror:log_stripe', stats['zfssa_poolprofile'])
|
|
- self.assertEqual('8k', stats['zfssa_volblocksize'])
|
|
- self.assertEqual('false', stats['zfssa_sparse'])
|
|
- self.assertEqual('off', stats['zfssa_compression'])
|
|
- self.assertEqual('latency', stats['zfssa_logbias'])
|
|
-
|
|
- self.drv.zfssa.get_pool_details.return_value = {"profile": "raidz2"}
|
|
- stats = self.drv.get_volume_stats(refresh=True)
|
|
- self.assertEqual('raidz2', stats['zfssa_poolprofile'])
|
|
-
|
|
- def test_extend_volume(self):
|
|
- lcfg = self.configuration
|
|
- self.drv.extend_volume(self.test_vol, 3)
|
|
- self.drv.zfssa.set_lun_props.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- self.test_vol['name'],
|
|
- volsize= 3 * units.Gi)
|
|
-
|
|
- @mock.patch('cinder.volume.volume_types.get_volume_type_extra_specs')
|
|
- def test_get_voltype_specs(self, get_volume_type_extra_specs):
|
|
- volume_type_id = mock.sentinel.volume_type_id
|
|
- volume = {'volume_type_id': volume_type_id}
|
|
- get_volume_type_extra_specs.return_value = {
|
|
- 'zfssa:volblocksize': '128k',
|
|
- 'zfssa:compression': 'gzip'
|
|
- }
|
|
- ret = self.drv._get_voltype_specs(volume)
|
|
- self.assertEqual('128k', ret.get('volblocksize'))
|
|
- self.assertEqual(self.configuration.zfssa_lun_sparse,
|
|
- ret.get('sparse'))
|
|
- self.assertEqual('gzip', ret.get('compression'))
|
|
- self.assertEqual(self.configuration.zfssa_lun_logbias,
|
|
- ret.get('logbias'))
|
|
-
|
|
- def tearDown(self):
|
|
- super(TestZFSSAISCSIDriver, self).tearDown()
|
|
-
|
|
- def fake_safe_get(self, value):
|
|
- try:
|
|
- val = getattr(self.configuration, value)
|
|
- except AttributeError:
|
|
- val = None
|
|
- return val
|
|
-
|
|
- @mock.patch.object(image_utils, 'qemu_img_info')
|
|
- @mock.patch.object(image_utils.TemporaryImages, 'fetch')
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_verify_cache_volume')
|
|
- def test_clone_image_negative(self, _verify_cache_volume, _fetch, _info):
|
|
- # Disabling local cache feature:
|
|
- self.configuration.zfssa_enable_local_cache = False
|
|
-
|
|
- _fetch.return_value = mock.MagicMock(spec=utils.get_file_spec())
|
|
- _info.return_value = ImgInfo(small_img['virtual_size'])
|
|
- self.assertEqual((None, False),
|
|
- self.drv.clone_image(fakecontext, self.test_vol,
|
|
- img_location,
|
|
- small_img,
|
|
- img_service))
|
|
-
|
|
- self.configuration.zfssa_enable_local_cache = True
|
|
- # Creating a volume smaller than image:
|
|
- _info.return_value = ImgInfo(large_img['virtual_size'])
|
|
- self.assertEqual((None, False),
|
|
- self.drv.clone_image(fakecontext, self.test_vol,
|
|
- img_location,
|
|
- large_img,
|
|
- img_service))
|
|
-
|
|
- # Exception raised in _verify_cache_image
|
|
- _info.return_value = ImgInfo(small_img['virtual_size'])
|
|
- self.drv._verify_cache_volume.side_effect = (
|
|
- exception.VolumeBackendAPIException('fakeerror'))
|
|
- self.assertEqual((None, False),
|
|
- self.drv.clone_image(fakecontext, self.test_vol,
|
|
- img_location,
|
|
- small_img,
|
|
- img_service))
|
|
-
|
|
- @mock.patch.object(image_utils, 'qemu_img_info')
|
|
- @mock.patch.object(image_utils.TemporaryImages, 'fetch')
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_get_voltype_specs')
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_verify_cache_volume')
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, 'extend_volume')
|
|
- def test_clone_image(self, _extend_vol, _verify_cache, _get_specs,
|
|
- _fetch, _info):
|
|
- lcfg = self.configuration
|
|
- cache_vol = 'volume-os-cache-vol-%s' % small_img['id']
|
|
- cache_snap = 'image-%s' % small_img['id']
|
|
- self.drv._get_voltype_specs.return_value = fakespecs.copy()
|
|
- self.drv._verify_cache_volume.return_value = cache_vol, cache_snap
|
|
- _fetch.return_value = mock.MagicMock(spec=utils.get_file_spec())
|
|
- _info.return_value = ImgInfo(small_img['virtual_size'])
|
|
-
|
|
- model, cloned = self.drv.clone_image(fakecontext, self.test_vol2,
|
|
- img_location,
|
|
- small_img,
|
|
- img_service)
|
|
- self.drv._verify_cache_volume.assert_called_once_with(fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- fakespecs,
|
|
- small_img_props)
|
|
- self.drv.zfssa.clone_snapshot.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_cache_project,
|
|
- cache_vol,
|
|
- cache_snap,
|
|
- lcfg.zfssa_project,
|
|
- self.test_vol2['name'])
|
|
-
|
|
- self.drv.extend_volume.assert_called_once_with(self.test_vol2,
|
|
- self.test_vol2['size'])
|
|
-
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_create_cache_volume')
|
|
- def test_verify_cache_vol_no_cache_vol(self, _create_cache_vol):
|
|
- vol_name = 'os-cache-vol-%s' % small_img['id']
|
|
- self.drv.zfssa.get_lun.side_effect = exception.VolumeNotFound(
|
|
- volume_id=vol_name)
|
|
- self.drv._verify_cache_volume(fakecontext, small_img,
|
|
- img_service, fakespecs, small_img_props)
|
|
- self.drv._create_cache_volume.assert_called_once_with(fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- fakespecs,
|
|
- small_img_props)
|
|
-
|
|
- def test_verify_cache_vol_no_cache_snap(self):
|
|
- snap_name = 'image-%s' % small_img['id']
|
|
- self.drv.zfssa.get_lun_snapshot.side_effect = (
|
|
- exception.SnapshotNotFound(snapshot_id=snap_name))
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv._verify_cache_volume,
|
|
- fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- fakespecs,
|
|
- small_img_props)
|
|
-
|
|
- def test_verify_cache_vol_stale_vol(self):
|
|
- self.drv.zfssa.get_lun_snapshot.return_value = {'numclones': 5}
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv._verify_cache_volume,
|
|
- fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- fakespecs,
|
|
- small_img_props)
|
|
-
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_create_cache_volume')
|
|
- def test_verify_cache_vol_updated_vol(self, _create_cache_vol):
|
|
- lcfg = self.configuration
|
|
- updated_vol = {
|
|
- 'updated_at': date(3000, 12, 12),
|
|
- 'image_id': 'updated_id',
|
|
- }
|
|
- cachevol_name = 'os-cache-vol-%s' % small_img['id']
|
|
- self.drv.zfssa.get_lun.return_value = updated_vol
|
|
- self.drv.zfssa.get_lun_snapshot.return_value = {'numclones': 0}
|
|
- self.drv._verify_cache_volume(fakecontext, small_img,
|
|
- img_service, fakespecs, small_img_props)
|
|
- self.drv.zfssa.delete_lun.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_cache_project,
|
|
- cachevol_name)
|
|
- self.drv._create_cache_volume.assert_called_once_with(fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- fakespecs,
|
|
- small_img_props)
|
|
-
|
|
- @mock.patch.object(driver.BaseVD, 'copy_image_to_volume')
|
|
- def test_create_cache_volume(self, _copy_image):
|
|
- lcfg = self.configuration
|
|
- virtual_size = int(small_img['virtual_size'])
|
|
- volsize = math.ceil(float(virtual_size) / units.Gi)
|
|
- lunsize = "%sg" % six.text_type(int(volsize))
|
|
- volname = 'os-cache-vol-%s' % small_img['id']
|
|
- snapname = 'image-%s' % small_img['id']
|
|
- cachevol_props = {
|
|
- 'cache_name': volname,
|
|
- 'snap_name': snapname,
|
|
- }
|
|
- cachevol_props.update(small_img_props)
|
|
- cache_vol = {
|
|
- 'name': volname,
|
|
- 'id': small_img['id'],
|
|
- 'size': volsize,
|
|
- }
|
|
- lun_props = {
|
|
- 'custom:image_id': small_img['id'],
|
|
- 'custom:updated_at': (
|
|
- six.text_type(small_img['updated_at'].isoformat())),
|
|
- }
|
|
- lun_props.update(fakespecs)
|
|
-
|
|
- self.drv._create_cache_volume(fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- fakespecs,
|
|
- cachevol_props)
|
|
-
|
|
- self.drv.zfssa.create_lun.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_cache_project,
|
|
- cache_vol['name'],
|
|
- lunsize,
|
|
- lcfg.zfssa_target_group,
|
|
- lun_props)
|
|
- _copy_image.assert_called_once_with(fakecontext,
|
|
- cache_vol,
|
|
- img_service,
|
|
- small_img['id'])
|
|
- self.drv.zfssa.create_snapshot.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_cache_project,
|
|
- cache_vol['name'],
|
|
- snapname)
|
|
-
|
|
- def test_create_cache_vol_negative(self):
|
|
- lcfg = self.configuration
|
|
- volname = 'os-cache-vol-%s' % small_img['id']
|
|
- snapname = 'image-%s' % small_img['id']
|
|
- cachevol_props = {
|
|
- 'cache_name': volname,
|
|
- 'snap_name': snapname,
|
|
- }
|
|
- cachevol_props.update(small_img)
|
|
-
|
|
- self.drv.zfssa.get_lun.side_effect = exception.VolumeNotFound(
|
|
- volume_id=volname)
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv._create_cache_volume,
|
|
- fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- fakespecs,
|
|
- cachevol_props)
|
|
- self.drv.zfssa.delete_lun.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_cache_project,
|
|
- volname)
|
|
-
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_get_existing_vol')
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_verify_volume_to_manage')
|
|
- def test_volume_manage(self, _get_existing_vol, _verify_volume_to_manage):
|
|
- lcfg = self.configuration
|
|
- lcfg.zfssa_manage_policy = 'loose'
|
|
- test_vol = self.test_vol
|
|
- self.drv._get_existing_vol.return_value = test_vol
|
|
- self.drv._verify_volume_to_manage.return_value = None
|
|
- self.drv.zfssa.set_lun_props.return_value = True
|
|
- self.assertIsNone(self.drv.manage_existing({'name': 'volume-123'},
|
|
- {'source-name':
|
|
- 'volume-567'}))
|
|
- self.drv._get_existing_vol.assert_called_once_with({'source-name':
|
|
- 'volume-567'})
|
|
- self.drv._verify_volume_to_manage.assert_called_once_with(test_vol)
|
|
- self.drv.zfssa.set_lun_props.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- test_vol['name'],
|
|
- name='volume-123',
|
|
- schema={"custom:cinder_managed": True})
|
|
-
|
|
- # Case when zfssa_manage_policy is 'loose' and 'cinder_managed' is
|
|
- # set to true.
|
|
- test_vol.update({'cinder_managed': False})
|
|
- self.assertIsNone(self.drv.manage_existing({'name': 'volume-123'},
|
|
- {'source-name':
|
|
- 'volume-567'}))
|
|
-
|
|
- # Another case is when the zfssa_manage_policy is set to 'strict'
|
|
- lcfg.zfssa_manage_policy = 'strict'
|
|
- test_vol.update({'cinder_managed': False})
|
|
- self.assertIsNone(self.drv.manage_existing({'name': 'volume-123'},
|
|
- {'source-name':
|
|
- 'volume-567'}))
|
|
-
|
|
- def test_volume_manage_negative(self):
|
|
- lcfg = self.configuration
|
|
- lcfg.zfssa_manage_policy = 'strict'
|
|
- test_vol = self.test_vol
|
|
-
|
|
- if 'cinder_managed' in test_vol:
|
|
- del test_vol['cinder_managed']
|
|
-
|
|
- self.drv.zfssa.get_lun.return_value = test_vol
|
|
- self.assertRaises(exception.InvalidInput,
|
|
- self.drv.manage_existing, {'name': 'cindervol'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
- test_vol.update({'cinder_managed': True})
|
|
- self.drv.zfssa.get_lun.return_value = test_vol
|
|
- self.assertRaises(exception.ManageExistingAlreadyManaged,
|
|
- self.drv.manage_existing, {'name': 'cindervol'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
- test_vol.update({'cinder_managed': False})
|
|
- self.drv.zfssa.get_lun.return_value = test_vol
|
|
- self.assertRaises(exception.ManageExistingInvalidReference,
|
|
- self.drv.manage_existing, {'name': 'cindervol'},
|
|
- {'source-id': 'volume-567'})
|
|
-
|
|
- lcfg.zfssa_manage_policy = 'loose'
|
|
- self.assertRaises(exception.ManageExistingInvalidReference,
|
|
- self.drv.manage_existing, {'name': 'cindervol'},
|
|
- {'source-id': 'volume-567'})
|
|
-
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_verify_volume_to_manage')
|
|
- def test_volume_manage_negative_api_exception(self,
|
|
- _verify_volume_to_manage):
|
|
- lcfg = self.configuration
|
|
- lcfg.zfssa_manage_policy = 'loose'
|
|
- self.drv.zfssa.get_lun.return_value = self.test_vol
|
|
- self.drv._verify_volume_to_manage.return_value = None
|
|
- self.drv.zfssa.set_lun_props.side_effect = \
|
|
- exception.VolumeBackendAPIException(data='fake exception')
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.manage_existing, {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
- def test_volume_unmanage(self):
|
|
- lcfg = self.configuration
|
|
- self.drv.zfssa.set_lun_props.return_value = True
|
|
- self.assertIsNone(self.drv.unmanage({'name': 'volume-123'}))
|
|
- self.drv.zfssa.set_lun_props.assert_called_once_with(
|
|
- lcfg.zfssa_pool,
|
|
- lcfg.zfssa_project,
|
|
- 'volume-123',
|
|
- name='unmanaged-volume-123',
|
|
- schema={"custom:cinder_managed": False})
|
|
-
|
|
- def test_volume_unmanage_negative(self):
|
|
- self.drv.zfssa.set_lun_props.side_effect = \
|
|
- exception.VolumeBackendAPIException(data='fake exception')
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.unmanage, {'name': 'volume-123'})
|
|
-
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_get_existing_vol')
|
|
- def test_manage_existing_get_size(self, _get_existing_vol):
|
|
- test_vol = self.test_vol
|
|
- test_vol['size'] = 3 * units.Gi
|
|
- self.drv._get_existing_vol.return_value = test_vol
|
|
- self.assertEqual(3, self.drv.manage_existing_get_size(
|
|
- {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'}))
|
|
-
|
|
- @mock.patch.object(iscsi.ZFSSAISCSIDriver, '_get_existing_vol')
|
|
- def test_manage_existing_get_size_negative(self, _get_existing_vol):
|
|
- self.drv._get_existing_vol.side_effect = \
|
|
- exception.VolumeNotFound(volume_id='123')
|
|
- self.assertRaises(exception.VolumeNotFound,
|
|
- self.drv.manage_existing_get_size,
|
|
- {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
-
|
|
-class TestZFSSANFSDriver(test.TestCase):
|
|
-
|
|
- test_vol = {
|
|
- 'name': 'test-vol',
|
|
- 'id': '1',
|
|
- 'size': 3,
|
|
- 'provider_location':
|
|
- 'fakelocation',
|
|
- }
|
|
-
|
|
- test_snap = {
|
|
- 'name': 'cindersnap',
|
|
- 'volume_name': test_vol['name'],
|
|
- 'volume_size': test_vol['size']
|
|
- }
|
|
-
|
|
- test_vol_snap = {
|
|
- 'name': 'cindersnapvol',
|
|
- 'size': test_vol['size']
|
|
- }
|
|
-
|
|
- def __init__(self, method):
|
|
- super(TestZFSSANFSDriver, self).__init__(method)
|
|
-
|
|
- @mock.patch.object(zfssanfs, 'factory_zfssa')
|
|
- def setUp(self, _factory_zfssa):
|
|
- super(TestZFSSANFSDriver, self).setUp()
|
|
- self._create_fake_config()
|
|
- _factory_zfssa.return_value = mock.MagicMock(spec=rest.ZFSSANfsApi)
|
|
- self.drv = zfssanfs.ZFSSANFSDriver(configuration=self.configuration)
|
|
- self.drv._execute = fake_utils.fake_execute
|
|
- self.drv.do_setup({})
|
|
- self.drv.mount_path = 'fake_mount_path'
|
|
-
|
|
- def _create_fake_config(self):
|
|
- self.configuration = mock.Mock(spec=conf.Configuration)
|
|
- self.configuration.reserved_percentage = 0
|
|
- self.configuration.max_over_subscription_ratio = 20.0
|
|
- self.configuration.san_ip = '1.1.1.1'
|
|
- self.configuration.san_login = 'user'
|
|
- self.configuration.san_password = 'passwd'
|
|
- self.configuration.zfssa_data_ip = '2.2.2.2'
|
|
- self.configuration.zfssa_https_port = '443'
|
|
- self.configuration.zfssa_nfs_pool = 'pool'
|
|
- self.configuration.zfssa_nfs_project = 'nfs_project'
|
|
- self.configuration.zfssa_nfs_share = 'nfs_share'
|
|
- self.configuration.zfssa_nfs_share_logbias = nfs_logbias
|
|
- self.configuration.zfssa_nfs_share_compression = nfs_compression
|
|
- self.configuration.zfssa_nfs_mount_options = ''
|
|
- self.configuration.zfssa_rest_timeout = '30'
|
|
- self.configuration.zfssa_enable_local_cache = True
|
|
- self.configuration.zfssa_cache_directory = zfssa_cache_dir
|
|
- self.configuration.nfs_sparsed_volumes = 'true'
|
|
- self.configuration.zfssa_manage_policy = 'strict'
|
|
-
|
|
- def test_migrate_volume(self):
|
|
- self.drv.zfssa.get_asn.return_value = (
|
|
- '9a2b5a0f-e3af-6d14-9578-8825f229dc89')
|
|
- volume = self.test_vol
|
|
- volume.update({'host': 'fake_host',
|
|
- 'status': 'available',
|
|
- 'name': 'vol-1',
|
|
- 'source_volid': self.test_vol['id']})
|
|
-
|
|
- loc_info = '9a2b5a0f-e3af-6d14-9578-8825f229dc89:nfs_share'
|
|
-
|
|
- host = {'host': 'stack@zfssa_nfs#fake_zfssa',
|
|
- 'capabilities': {'vendor_name': 'Oracle',
|
|
- 'storage_protocol': 'nfs',
|
|
- 'location_info': loc_info}}
|
|
- ctxt = context.get_admin_context()
|
|
-
|
|
- # Test Normal case
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((True, None), result)
|
|
-
|
|
- # Test when volume status is not available
|
|
- volume['status'] = 'in-use'
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
- volume['status'] = 'available'
|
|
-
|
|
- # Test when Vendor is not Oracle
|
|
- host['capabilities']['vendor_name'] = 'elcarO'
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
- host['capabilities']['vendor_name'] = 'Oracle'
|
|
-
|
|
- # Test when storage protocol is not iSCSI
|
|
- host['capabilities']['storage_protocol'] = 'not_nfs'
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
- host['capabilities']['storage_protocol'] = 'nfs'
|
|
-
|
|
- # Test for exceptions
|
|
- host['capabilities']['location_info'] = ''
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
- host['capabilities']['location_info'] = loc_info
|
|
-
|
|
- # Test case when source and target asn dont match
|
|
- invalid_loc_info = (
|
|
- 'fake_asn*https://2.2.2.2:/shares/export/nfs_share*nfs_share')
|
|
- host['capabilities']['location_info'] = invalid_loc_info
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
-
|
|
- # Test case when source and target shares names are different
|
|
- invalid_loc_info = (
|
|
- '9a2b5a0f-e3af-6d14-9578-8825f229dc89*' +
|
|
- 'https://tgt:/shares/export/nfs_share*nfs_share_1')
|
|
- host['capabilities']['location_info'] = invalid_loc_info
|
|
- result = self.drv.migrate_volume(ctxt, volume, host)
|
|
- self.assertEqual((False, None), result)
|
|
-
|
|
- def test_create_delete_snapshot(self):
|
|
- lcfg = self.configuration
|
|
- self.drv.create_snapshot(self.test_snap)
|
|
- self.drv.zfssa.create_snapshot.assert_called_once_with(
|
|
- lcfg.zfssa_nfs_pool,
|
|
- lcfg.zfssa_nfs_project,
|
|
- lcfg.zfssa_nfs_share,
|
|
- mock.ANY)
|
|
- self.drv.zfssa.create_snapshot_of_volume_file.assert_called_once_with(
|
|
- src_file=mock.ANY,
|
|
- dst_file=self.test_snap['name'])
|
|
- self.drv.delete_snapshot(self.test_snap)
|
|
- self.drv.zfssa.delete_snapshot_of_volume_file.assert_called_with(
|
|
- src_file=self.test_snap['name'])
|
|
-
|
|
- def test_create_volume_from_snapshot(self):
|
|
- self.drv.create_snapshot(self.test_snap)
|
|
- with mock.patch.object(self.drv, '_ensure_shares_mounted'):
|
|
- self.drv.create_volume_from_snapshot(self.test_vol_snap,
|
|
- self.test_snap,
|
|
- method='COPY')
|
|
-
|
|
- self.drv.zfssa.create_volume_from_snapshot_file.\
|
|
- assert_called_once_with(src_file=self.test_snap['name'],
|
|
- dst_file=self.test_vol_snap['name'],
|
|
- method='COPY')
|
|
-
|
|
- def test_get_volume_stats(self):
|
|
- lcfg = self.configuration
|
|
- self.drv._mounted_shares = ['nfs_share']
|
|
- with mock.patch.object(self.drv, '_ensure_shares_mounted'):
|
|
- with mock.patch.object(self.drv, '_get_share_capacity_info') as \
|
|
- mock_get_share_capacity_info:
|
|
- mock_get_share_capacity_info.return_value = (1073741824,
|
|
- 9663676416)
|
|
- self.drv.zfssa.get_pool_details.return_value = \
|
|
- {"profile": "mirror:log_stripe"}
|
|
- self.drv.zfssa.get_share.return_value = {"compression": "lzjb",
|
|
- "encryption": "off",
|
|
- "logbias": "latency"}
|
|
- stats = self.drv.get_volume_stats(refresh=True)
|
|
- self.drv.zfssa.get_pool_details.assert_called_once_with(
|
|
- lcfg.zfssa_nfs_pool)
|
|
- self.drv.zfssa.get_share.assert_called_with(
|
|
- lcfg.zfssa_nfs_pool, lcfg.zfssa_nfs_project,
|
|
- lcfg.zfssa_nfs_share)
|
|
-
|
|
- self.assertEqual(1, stats['free_capacity_gb'])
|
|
- self.assertEqual(10, stats['total_capacity_gb'])
|
|
- self.assertEqual('mirror:log_stripe',
|
|
- stats['zfssa_poolprofile'])
|
|
- self.assertEqual('lzjb', stats['zfssa_compression'])
|
|
- self.assertEqual('true', stats['zfssa_sparse'])
|
|
- self.assertEqual('off', stats['zfssa_encryption'])
|
|
- self.assertEqual('latency', stats['zfssa_logbias'])
|
|
-
|
|
- self.drv.zfssa.get_pool_details.return_value = \
|
|
- {"profile": "mirror3"}
|
|
- stats = self.drv.get_volume_stats(refresh=True)
|
|
- self.assertEqual('mirror3', stats['zfssa_poolprofile'])
|
|
-
|
|
- def tearDown(self):
|
|
- super(TestZFSSANFSDriver, self).tearDown()
|
|
-
|
|
- @mock.patch.object(remotefs.RemoteFSDriver, 'delete_volume')
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, '_check_origin')
|
|
- def test_delete_volume(self, _check_origin, _delete_vol):
|
|
- self.drv.zfssa.get_volume.side_effect = self._get_volume_side_effect
|
|
- test_vol = zfssanfs.Volume()
|
|
- test_vol._name_id = small_img['id']
|
|
- test_vol.size = 3
|
|
- test_vol.provider_location = 'fakelocation'
|
|
-
|
|
- self.drv.delete_volume(test_vol)
|
|
- _delete_vol.assert_called_once_with(test_vol)
|
|
- self.drv._check_origin.assert_called_once_with(img_props_nfs['name'])
|
|
-
|
|
- def _get_volume_side_effect(self, *args, **kwargs):
|
|
- lcfg = self.configuration
|
|
- volname = six.text_type(args[0])
|
|
- if volname.startswith(lcfg.zfssa_cache_directory):
|
|
- return {'numclones': 0}
|
|
- else:
|
|
- return {'origin': img_props_nfs['name']}
|
|
-
|
|
- def test_check_origin(self):
|
|
- self.drv.zfssa.get_volume.side_effect = self._get_volume_side_effect
|
|
- self.drv._check_origin(img_props_nfs['name'])
|
|
- self.drv.zfssa.delete_file.assert_called_once_with(
|
|
- img_props_nfs['name'])
|
|
-
|
|
- @mock.patch.object(image_utils, 'qemu_img_info')
|
|
- @mock.patch.object(image_utils.TemporaryImages, 'fetch')
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, '_verify_cache_volume')
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, 'create_cloned_volume')
|
|
- def test_clone_image_negative(self, _create_clone, _verify_cache_volume,
|
|
- _fetch, _info):
|
|
- _fetch.return_value = mock.MagicMock(spec=utils.get_file_spec())
|
|
- _info.return_value = ImgInfo(small_img['virtual_size'])
|
|
-
|
|
- # Disabling local cache feature:
|
|
- self.configuration.zfssa_enable_local_cache = False
|
|
- self.assertEqual((None, False),
|
|
- self.drv.clone_image(fakecontext, self.test_vol,
|
|
- img_location,
|
|
- small_img,
|
|
- img_service))
|
|
-
|
|
- self.configuration.zfssa_enable_local_cache = True
|
|
-
|
|
- # Creating a volume smaller than image:
|
|
- _info.return_value = ImgInfo(large_img['virtual_size'])
|
|
- self.assertEqual((None, False),
|
|
- self.drv.clone_image(fakecontext, self.test_vol,
|
|
- img_location,
|
|
- large_img,
|
|
- img_service))
|
|
-
|
|
- # Exception raised in _verify_cache_image
|
|
- _info.return_value = ImgInfo(small_img['virtual_size'])
|
|
- self.drv._verify_cache_volume.side_effect = (
|
|
- exception.VolumeBackendAPIException('fakeerror'))
|
|
- self.assertEqual((None, False),
|
|
- self.drv.clone_image(fakecontext, self.test_vol,
|
|
- img_location,
|
|
- small_img,
|
|
- img_service))
|
|
-
|
|
- @mock.patch.object(image_utils, 'qemu_img_info')
|
|
- @mock.patch.object(image_utils.TemporaryImages, 'fetch')
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, 'create_cloned_volume')
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, '_verify_cache_volume')
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, 'extend_volume')
|
|
- def test_clone_image(self, _extend_vol, _verify_cache, _create_clone,
|
|
- _fetch, _info):
|
|
- _fetch.return_value = mock.MagicMock(spec=utils.get_file_spec())
|
|
- _info.return_value = ImgInfo(small_img['virtual_size'])
|
|
- self.drv._verify_cache_volume.return_value = \
|
|
- 'volume-' + img_props_nfs['id']
|
|
- prov_loc = {'provider_location': self.test_vol['provider_location']}
|
|
- self.drv.create_cloned_volume.return_value = prov_loc
|
|
- self.assertEqual((prov_loc, True),
|
|
- self.drv.clone_image(fakecontext, self.test_vol,
|
|
- img_location,
|
|
- small_img,
|
|
- img_service))
|
|
- img_props = {}
|
|
- img_props['id'] = img_props_nfs['image_id']
|
|
- img_props['image_id'] = img_props_nfs['image_id']
|
|
- img_props['updated_at'] = img_props_nfs['updated_at']
|
|
- img_props['size'] = img_props_nfs['size']
|
|
-
|
|
- self.drv._verify_cache_volume.assert_called_once_with(fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- img_props)
|
|
- cache_vol = {
|
|
- 'name': self.drv._verify_cache_volume.return_value,
|
|
- 'size': 3,
|
|
- 'id': small_img['id'],
|
|
- }
|
|
- self.drv.create_cloned_volume.assert_called_once_with(self.test_vol,
|
|
- cache_vol)
|
|
-
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, '_create_cache_volume')
|
|
- def test_verify_cache_vol_no_cache_vol(self, _create_cache_vol):
|
|
- self.drv.zfssa.get_volume.side_effect = exception.VolumeNotFound(
|
|
- volume_id=img_props_nfs['name'])
|
|
- self.drv._verify_cache_volume(fakecontext, small_img,
|
|
- img_service, img_props_nfs)
|
|
- self.drv._create_cache_volume.assert_called_once_with(fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- img_props_nfs)
|
|
-
|
|
- def test_verify_cache_vol_stale_vol(self):
|
|
- self.drv.zfssa.get_volume.return_value = {
|
|
- 'numclones': 5,
|
|
- 'updated_at': small_img['updated_at'].isoformat(),
|
|
- 'image_id': 'wrong_id',
|
|
- }
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv._verify_cache_volume,
|
|
- fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- img_props_nfs)
|
|
-
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, '_create_cache_volume')
|
|
- @mock.patch.object(remotefs.RemoteFSDriver, 'delete_volume')
|
|
- def test_verify_cache_vol_updated_vol(self, _del_vol, _create_cache_vol):
|
|
- updated_vol = {
|
|
- 'updated_at': date(3000, 12, 12),
|
|
- 'image_id': 'updated_id',
|
|
- 'numclones': 0,
|
|
- }
|
|
- self.drv.zfssa.get_volume.return_value = updated_vol
|
|
- self.drv._verify_cache_volume(fakecontext, small_img,
|
|
- img_service, img_props_nfs)
|
|
-
|
|
- self.drv._create_cache_volume.assert_called_once_with(fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- img_props_nfs)
|
|
-
|
|
- @mock.patch.object(remotefs.RemoteFSDriver, 'copy_image_to_volume')
|
|
- @mock.patch.object(remotefs.RemoteFSDriver, 'create_volume')
|
|
- def test_create_cache_volume(self, _create_vol, _copy_image):
|
|
- self.drv.zfssa.webdavclient = mock.Mock()
|
|
- self.drv._create_cache_volume(fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- img_props_nfs)
|
|
-
|
|
- self.assertEqual(1, _create_vol.call_count)
|
|
- self.assertEqual(1, _copy_image.call_count)
|
|
-
|
|
- def test_create_cache_vol_negative(self):
|
|
- self.drv.zfssa.get_lun.side_effect = (
|
|
- exception.VolumeBackendAPIException)
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv._create_cache_volume,
|
|
- fakecontext,
|
|
- small_img,
|
|
- img_service,
|
|
- img_props_nfs)
|
|
- self.drv.zfssa.delete_file.assert_called_once_with(
|
|
- 'os-cinder-cache/volume-' + img_props_nfs['id'])
|
|
-
|
|
- def test_volume_manage(self):
|
|
- lcfg = self.configuration
|
|
- lcfg.zfssa_manage_policy = 'loose'
|
|
- test_vol = self.test_vol
|
|
-
|
|
- self.drv.zfssa.get_volume.return_value = test_vol
|
|
- self.drv.zfssa.rename_volume.return_value = None
|
|
- self.drv.zfssa.set_file_props.return_value = None
|
|
- self.drv.mount_path = lcfg.zfssa_data_ip + ':' + 'fake_mountpoint'
|
|
- self.assertEqual({'provider_location': self.drv.mount_path},
|
|
- self.drv.manage_existing({'name': 'volume-123'},
|
|
- {'source-name':
|
|
- 'volume-567'}))
|
|
-
|
|
- self.drv.zfssa.get_volume.assert_called_once_with('volume-567')
|
|
- self.drv.zfssa.rename_volume.assert_called_once_with('volume-567',
|
|
- 'volume-123')
|
|
- self.drv.zfssa.set_file_props.assert_called_once_with(
|
|
- 'volume-123', {'cinder_managed': 'True'})
|
|
- # Test when 'zfssa_manage_policy' is set to 'strict'.
|
|
- lcfg.zfssa_manage_policy = 'strict'
|
|
- test_vol.update({'cinder_managed': 'False'})
|
|
- self.drv.zfssa.get_volume.return_value = test_vol
|
|
- self.assertEqual({'provider_location': self.drv.mount_path},
|
|
- self.drv.manage_existing({'name': 'volume-123'},
|
|
- {'source-name':
|
|
- 'volume-567'}))
|
|
-
|
|
- def test_volume_manage_negative_no_source_name(self):
|
|
- self.assertRaises(exception.ManageExistingInvalidReference,
|
|
- self.drv.manage_existing,
|
|
- {'name': 'volume-123'},
|
|
- {'source-id': 'volume-567'})
|
|
-
|
|
- def test_volume_manage_negative_backend_exception(self):
|
|
- self.drv.zfssa.get_volume.side_effect = \
|
|
- exception.VolumeNotFound(volume_id='volume-567')
|
|
- self.assertRaises(exception.InvalidInput,
|
|
- self.drv.manage_existing,
|
|
- {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
- def test_volume_manage_negative_verify_fail(self):
|
|
- lcfg = self.configuration
|
|
- lcfg.zfssa_manage_policy = 'strict'
|
|
- test_vol = self.test_vol
|
|
- test_vol['cinder_managed'] = ''
|
|
-
|
|
- self.drv.zfssa.get_volume.return_value = test_vol
|
|
- self.assertRaises(exception.InvalidInput,
|
|
- self.drv.manage_existing,
|
|
- {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
- test_vol.update({'cinder_managed': 'True'})
|
|
- self.drv.zfssa.get_volume.return_value = test_vol
|
|
- self.assertRaises(exception.ManageExistingAlreadyManaged,
|
|
- self.drv.manage_existing,
|
|
- {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, '_verify_volume_to_manage')
|
|
- def test_volume_manage_negative_rename_fail(self,
|
|
- _verify_volume_to_manage):
|
|
- test_vol = self.test_vol
|
|
- test_vol.update({'cinder_managed': 'False'})
|
|
- self.drv.zfssa.get_volume.return_value = test_vol
|
|
- self.drv._verify_volume_to_manage.return_value = None
|
|
- self.drv.zfssa.rename_volume.side_effect = \
|
|
- exception.VolumeBackendAPIException(data="fake exception")
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.manage_existing, {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, '_verify_volume_to_manage')
|
|
- def test_volume_manage_negative_set_prop_fail(self,
|
|
- _verify_volume_to_manage):
|
|
- test_vol = self.test_vol
|
|
- test_vol.update({'cinder_managed': 'False'})
|
|
- self.drv.zfssa.get_volume.return_value = test_vol
|
|
- self.drv._verify_volume_to_manage.return_value = None
|
|
- self.drv.zfssa.rename_volume.return_value = None
|
|
- self.drv.zfssa.set_file_props.side_effect = \
|
|
- exception.VolumeBackendAPIException(data="fake exception")
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.manage_existing, {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
- def test_volume_unmanage(self):
|
|
- test_vol = self.test_vol
|
|
- test_vol.update({'cinder_managed': 'True'})
|
|
- self.drv.zfssa.rename_volume.return_value = None
|
|
- self.drv.zfssa.set_file_props.return_value = None
|
|
- self.assertIsNone(self.drv.unmanage(test_vol))
|
|
- new_vol_name = 'unmanaged-' + test_vol['name']
|
|
- self.drv.zfssa.rename_volume.assert_called_once_with(test_vol['name'],
|
|
- new_vol_name)
|
|
- self.drv.zfssa.set_file_props.assert_called_once_with(
|
|
- new_vol_name, {'cinder_managed': 'False'})
|
|
-
|
|
- def test_volume_unmanage_negative_rename_fail(self):
|
|
- test_vol = self.test_vol
|
|
- test_vol.update({'cinder_managed': 'True'})
|
|
- self.drv.zfssa.rename_volume.side_effect = \
|
|
- exception.VolumeBackendAPIException(data="fake exception")
|
|
- self.drv.zfssa.set_file_props.return_value = None
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.unmanage, test_vol)
|
|
-
|
|
- def test_volume_unmanage_negative_set_prop_fail(self):
|
|
- test_vol = self.test_vol
|
|
- test_vol.update({'cinder_managed': 'True'})
|
|
- self.drv.zfssa.rename_volume.return_value = None
|
|
- self.drv.zfssa.set_file_props.side_effect = \
|
|
- exception.VolumeBackendAPIException(data="fake exception")
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.unmanage, test_vol)
|
|
-
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, '_get_mount_point_for_share')
|
|
- def test_manage_existing_get_size(self, _get_mount_point_for_share):
|
|
- self.drv._get_mount_point_for_share.return_value = \
|
|
- '/fake/mnt/fake_share/'
|
|
- self.drv._mounted_shares = []
|
|
- self.drv._mounted_shares.append('fake_share')
|
|
- file = mock.Mock(st_size=123 * units.Gi)
|
|
- with mock.patch('os.path.isfile', return_value=True):
|
|
- with mock.patch('os.stat', return_value=file):
|
|
- self.assertEqual(float(file.st_size / units.Gi),
|
|
- self.drv.manage_existing_get_size(
|
|
- {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'}))
|
|
-
|
|
- @mock.patch.object(zfssanfs.ZFSSANFSDriver, '_get_mount_point_for_share')
|
|
- def test_manage_existing_get_size_negative(self,
|
|
- _get_mount_point_for_share):
|
|
- self.drv._get_mount_point_for_share.return_value = \
|
|
- '/fake/mnt/fake_share/'
|
|
- self.drv._mounted_shares = []
|
|
- self.drv._mounted_shares.append('fake_share')
|
|
- with mock.patch('os.path.isfile', return_value=True):
|
|
- with mock.patch('os.stat', side_effect=OSError):
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.drv.manage_existing_get_size,
|
|
- {'name': 'volume-123'},
|
|
- {'source-name': 'volume-567'})
|
|
-
|
|
-
|
|
-class TestZFSSAApi(test.TestCase):
|
|
-
|
|
- @mock.patch.object(rest, 'factory_restclient')
|
|
- def setUp(self, _restclient):
|
|
- super(TestZFSSAApi, self).setUp()
|
|
- self.host = 'fakehost'
|
|
- self.user = 'fakeuser'
|
|
- self.url = None
|
|
- self.pool = 'fakepool'
|
|
- self.project = 'fakeproject'
|
|
- self.vol = 'fakevol'
|
|
- self.snap = 'fakesnapshot'
|
|
- self.clone = 'fakeclone'
|
|
- self.targetalias = 'fakealias'
|
|
- _restclient.return_value = mock.MagicMock(spec=client.RestClientURL)
|
|
- self.zfssa = rest.ZFSSAApi()
|
|
- self.zfssa.set_host('fakehost')
|
|
- self.pool_url = '/api/storage/v1/pools/'
|
|
-
|
|
- def _create_response(self, status, data='data'):
|
|
- response = FakeResponse(status, data)
|
|
- return response
|
|
-
|
|
- def test_create_project(self):
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.OK)
|
|
- self.zfssa.create_project(self.pool, self.project)
|
|
- expected_svc = self.pool_url + self.pool + '/projects/' + self.project
|
|
- self.zfssa.rclient.get.assert_called_with(expected_svc)
|
|
-
|
|
- def test_create_initiator(self):
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.OK)
|
|
- initiator = 'iqn.1986-03.com.sun:02:00000-aaaa-bbbb-cccc-ddddd'
|
|
- alias = 'init-group'
|
|
- self.zfssa.create_initiator(initiator, alias)
|
|
- self.zfssa.rclient.get.assert_called_with(
|
|
- '/api/san/v1/iscsi/initiators/alias=' + alias)
|
|
-
|
|
- def test_create_target(self):
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.NOT_FOUND)
|
|
- ret_val = json.dumps(
|
|
- {'target': {'iqn':
|
|
- 'iqn.1986-03.com.sun:02:00000-aaaa-bbbb-cccc-ddddd'}})
|
|
- self.zfssa.rclient.post.return_value = self._create_response(
|
|
- client.Status.CREATED, ret_val)
|
|
- alias = 'tgt-group'
|
|
- self.zfssa.create_target(alias)
|
|
- self.zfssa.rclient.post.assert_called_with('/api/san/v1/iscsi/targets',
|
|
- {'alias': alias})
|
|
-
|
|
- def test_get_target(self):
|
|
- ret_val = json.dumps(
|
|
- {'target': {'href': 'fake_href',
|
|
- 'alias': 'tgt-group',
|
|
- 'iqn':
|
|
- 'iqn.1986-03.com.sun:02:00000-aaaa-bbbb-cccc-ddddd',
|
|
- 'targetchapuser': '',
|
|
- 'targetchapsecret': '',
|
|
- 'interfaces': ['nge0']}})
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.OK, ret_val)
|
|
- ret = self.zfssa.get_target('tgt-group')
|
|
- self.zfssa.rclient.get.assert_called_once_with(
|
|
- '/api/san/v1/iscsi/targets/alias=tgt-group')
|
|
- self.assertEqual('iqn.1986-03.com.sun:02:00000-aaaa-bbbb-cccc-ddddd',
|
|
- ret)
|
|
-
|
|
- def test_verify_pool(self):
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.OK)
|
|
- self.zfssa.verify_pool(self.pool)
|
|
- self.zfssa.rclient.get.assert_called_with(self.pool_url + self.pool)
|
|
-
|
|
- def test_verify_project(self):
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.NOT_FOUND)
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.zfssa.verify_project,
|
|
- self.pool,
|
|
- self.project)
|
|
-
|
|
- def test_verify_initiator(self):
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.OK)
|
|
- self.zfssa.verify_initiator('iqn.1-0.org.deb:01:d7')
|
|
- self.zfssa.rclient.get.assert_called_with(
|
|
- '/api/san/v1/iscsi/initiators/iqn.1-0.org.deb:01:d7')
|
|
-
|
|
- def test_verify_target(self):
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.BAD_REQUEST)
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.zfssa.verify_target,
|
|
- self.targetalias)
|
|
-
|
|
- def test_create_delete_lun(self):
|
|
- arg = json.dumps({'name': self.vol,
|
|
- 'initiatorgroup': 'com.sun.ms.vss.hg.maskAll'})
|
|
- self.zfssa.rclient.post.return_value = self._create_response(
|
|
- client.Status.CREATED, data=arg)
|
|
- self.zfssa.create_lun(self.pool, self.project, self.vol, 1, 'tgt-grp',
|
|
- None)
|
|
- expected_arg = {'name': self.vol,
|
|
- 'volsize': 1,
|
|
- 'targetgroup': 'tgt-grp',
|
|
- 'initiatorgroup': 'com.sun.ms.vss.hg.maskAll'}
|
|
- self.zfssa.rclient.post.assert_called_with(
|
|
- self.pool_url + self.pool + '/projects/' + self.project + '/luns',
|
|
- expected_arg)
|
|
-
|
|
- self.zfssa.rclient.delete.return_value = self._create_response(
|
|
- client.Status.NO_CONTENT)
|
|
- self.zfssa.delete_lun(self.pool, self.project, self.vol)
|
|
- self.zfssa.rclient.delete.assert_called_with(
|
|
- self.pool_url + self.pool + '/projects/' + self.project +
|
|
- '/luns/' + self.vol)
|
|
-
|
|
- def test_create_delete_snapshot(self):
|
|
- self.zfssa.rclient.post.return_value = self._create_response(
|
|
- client.Status.CREATED)
|
|
- self.zfssa.create_snapshot(self.pool,
|
|
- self.project,
|
|
- self.vol,
|
|
- self.snap)
|
|
- expected_arg = {'name': self.snap}
|
|
- self.zfssa.rclient.post.assert_called_with(
|
|
- self.pool_url + self.pool + '/projects/' + self.project +
|
|
- '/luns/' + self.vol + '/snapshots', expected_arg)
|
|
-
|
|
- self.zfssa.rclient.delete.return_value = self._create_response(
|
|
- client.Status.NO_CONTENT)
|
|
- self.zfssa.delete_snapshot(self.pool,
|
|
- self.project,
|
|
- self.vol,
|
|
- self.snap)
|
|
- self.zfssa.rclient.delete.assert_called_with(
|
|
- self.pool_url + self.pool + '/projects/' + self.project +
|
|
- '/luns/' + self.vol + '/snapshots/' + self.snap)
|
|
-
|
|
- def test_clone_snapshot(self):
|
|
- self.zfssa.rclient.put.return_value = self._create_response(
|
|
- client.Status.CREATED)
|
|
- self.zfssa.clone_snapshot(self.pool,
|
|
- self.project,
|
|
- self.vol,
|
|
- self.snap,
|
|
- self.project,
|
|
- self.clone)
|
|
- expected_svc = '/api/storage/v1/pools/' + self.pool + '/projects/' + \
|
|
- self.project + '/luns/' + self.vol + '/snapshots/' + self.snap + \
|
|
- '/clone'
|
|
- expected_arg = {'project': self.project,
|
|
- 'share': self.clone,
|
|
- 'nodestroy': True}
|
|
- self.zfssa.rclient.put.assert_called_with(expected_svc, expected_arg)
|
|
-
|
|
- def test_get_project_stats(self):
|
|
- ret_val = json.dumps({"project": {"name": self.project,
|
|
- "space_available": 15754895360,
|
|
- "space_total": 25754895360,
|
|
- "dedup": False,
|
|
- "logbias": "latency",
|
|
- "encryption": "off"}})
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.OK, ret_val)
|
|
- self.zfssa.get_project_stats(self.pool, self.project)
|
|
- expected_svc = '/api/storage/v1/pools/' + self.pool + '/projects/' + \
|
|
- self.project
|
|
- self.zfssa.rclient.get.assert_called_with(expected_svc)
|
|
-
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.NOT_FOUND)
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.zfssa.get_project_stats,
|
|
- self.pool,
|
|
- self.project)
|
|
-
|
|
-
|
|
-class TestZFSSANfsApi(test.TestCase):
|
|
-
|
|
- @mock.patch.object(rest, 'factory_restclient')
|
|
- def setUp(self, _restclient):
|
|
- super(TestZFSSANfsApi, self).setUp()
|
|
- self.host = 'fakehost'
|
|
- self.user = 'fakeuser'
|
|
- self.url = None
|
|
- self.pool = 'fakepool'
|
|
- self.project = 'fakeproject'
|
|
- self.share = 'fakeshare'
|
|
- self.snap = 'fakesnapshot'
|
|
- self.targetalias = 'fakealias'
|
|
- _restclient.return_value = mock.MagicMock(spec=client.RestClientURL)
|
|
- self.webdavclient = mock.MagicMock(spec=webdavclient.ZFSSAWebDAVClient)
|
|
- self.zfssa = rest.ZFSSANfsApi()
|
|
- self.zfssa.set_host('fakehost')
|
|
- self.pool_url = '/api/storage/v1/pools/'
|
|
-
|
|
- def _create_response(self, status, data='data'):
|
|
- response = FakeResponse(status, data)
|
|
- return response
|
|
-
|
|
- def test_verify_share(self):
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.OK)
|
|
- self.zfssa.verify_share(self.pool, self.project, self.share)
|
|
- self.zfssa.rclient.get.assert_called_with(self.pool_url + self.pool +
|
|
- '/projects/' + self.project +
|
|
- '/filesystems/' + self.share)
|
|
-
|
|
- def test_create_delete_snapshot(self):
|
|
- self.zfssa.rclient.post.return_value = self._create_response(
|
|
- client.Status.CREATED)
|
|
- self.zfssa.create_snapshot(self.pool,
|
|
- self.project,
|
|
- self.share,
|
|
- self.snap)
|
|
- expected_arg = {'name': self.snap}
|
|
- self.zfssa.rclient.post.assert_called_with(
|
|
- self.pool_url + self.pool + '/projects/' + self.project +
|
|
- '/filesystems/' + self.share + '/snapshots', expected_arg)
|
|
-
|
|
- self.zfssa.rclient.delete.return_value = self._create_response(
|
|
- client.Status.NO_CONTENT)
|
|
- self.zfssa.delete_snapshot(self.pool,
|
|
- self.project,
|
|
- self.share,
|
|
- self.snap)
|
|
- self.zfssa.rclient.delete.assert_called_with(
|
|
- self.pool_url + self.pool + '/projects/' + self.project +
|
|
- '/filesystems/' + self.share + '/snapshots/' + self.snap)
|
|
-
|
|
- def create_delete_snapshot_of_volume_file(self):
|
|
- src_file = "fake_src_file"
|
|
- dst_file = "fake_dst_file"
|
|
- self.zfssa.create_snapshot_of_volume_file(src_file=src_file,
|
|
- dst_file=dst_file)
|
|
- self.zfssa.webdavclient.request.assert_called_once_with(
|
|
- src_file=src_file,
|
|
- dst_file=dst_file,
|
|
- method='COPY')
|
|
- self.zfssa.delete_snapshot_of_volume_file(src_file=src_file)
|
|
- self.zfssa.webdavclient.request.assert_called_once_with(
|
|
- src_file=src_file, method='DELETE')
|
|
-
|
|
- def test_get_share(self):
|
|
- ret_val = json.dumps({'filesystem': 'test_fs'})
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.OK, ret_val)
|
|
- ret = self.zfssa.get_share(self.pool, self.project, self.share)
|
|
- self.zfssa.rclient.get.assert_called_with(self.pool_url + self.pool +
|
|
- '/projects/' + self.project +
|
|
- '/filesystems/' + self.share)
|
|
- self.assertEqual('test_fs', ret)
|
|
-
|
|
- def test_create_share(self):
|
|
- self.zfssa.rclient.get.return_value = self._create_response(
|
|
- client.Status.NOT_FOUND)
|
|
- self.zfssa.rclient.post.return_value = self._create_response(
|
|
- client.Status.BAD_REQUEST)
|
|
- self.assertRaises(exception.VolumeBackendAPIException,
|
|
- self.zfssa.create_share,
|
|
- self.pool,
|
|
- self.project,
|
|
- self.share,
|
|
- {})
|
|
-
|
|
- @mock.patch.object(rest.ZFSSANfsApi, '_change_service_state')
|
|
- @mock.patch.object(rest.ZFSSANfsApi, 'verify_service')
|
|
- def test_enable_disable_modify_service(self,
|
|
- verify_service,
|
|
- _change_service_state):
|
|
- self.zfssa.enable_service('http')
|
|
- self.zfssa._change_service_state.assert_called_with(
|
|
- 'http', state='enable')
|
|
- self.zfssa.verify_service.assert_called_with('http')
|
|
-
|
|
- self.zfssa.disable_service('http')
|
|
- self.zfssa._change_service_state.assert_called_with(
|
|
- 'http', state='disable')
|
|
- self.zfssa.verify_service.assert_called_with('http', status='offline')
|
|
-
|
|
- ret_val = json.dumps({'service': {
|
|
- "href": "/api/service/v1/services/http",
|
|
- "<status>": "online",
|
|
- "require_login": False,
|
|
- "protocols": "http/https",
|
|
- "listen_port": 81,
|
|
- "https_port": 443}})
|
|
- self.zfssa.rclient.put.return_value = self._create_response(
|
|
- client.Status.ACCEPTED, ret_val)
|
|
- args = {'listen_port': 81}
|
|
- self.zfssa.modify_service('http', args)
|
|
- self.zfssa.rclient.put.called_with('/api/service/v1/services/http',
|
|
- args)
|
|
-
|
|
-
|
|
-class TestRestClientURL(test.TestCase):
|
|
- def setUp(self):
|
|
- super(TestRestClientURL, self).setUp()
|
|
- self.timeout = 60
|
|
- self.url = '1.1.1.1'
|
|
- self.client = client.RestClientURL(self.url, timeout=self.timeout)
|
|
-
|
|
- @mock.patch.object(client.RestClientURL, 'request')
|
|
- def test_post(self, _request):
|
|
- path = '/api/storage/v1/pools'
|
|
- body = {'name': 'fakepool'}
|
|
- self.client.post(path, body=body)
|
|
- self.client.request.assert_called_with(path, 'POST', body)
|
|
-
|
|
- @mock.patch.object(client.RestClientURL, 'request')
|
|
- def test_get(self, _request):
|
|
- path = '/api/storage/v1/pools'
|
|
- self.client.get(path)
|
|
- self.client.request.assert_called_with(path, 'GET')
|
|
-
|
|
- @mock.patch.object(client.RestClientURL, 'request')
|
|
- def test_put(self, _request):
|
|
- path = '/api/storage/v1/pools'
|
|
- body = {'name': 'fakepool'}
|
|
- self.client.put(path, body=body)
|
|
- self.client.request.assert_called_with(path, 'PUT', body)
|
|
-
|
|
- @mock.patch.object(client.RestClientURL, 'request')
|
|
- def test_delete(self, _request):
|
|
- path = '/api/storage/v1/pools'
|
|
- self.client.delete(path)
|
|
- self.client.request.assert_called_with(path, 'DELETE')
|
|
-
|
|
- @mock.patch.object(client.RestClientURL, 'request')
|
|
- def test_head(self, _request):
|
|
- path = '/api/storage/v1/pools'
|
|
- self.client.head(path)
|
|
- self.client.request.assert_called_with(path, 'HEAD')
|
|
-
|
|
- @mock.patch.object(client, 'RestResult')
|
|
- @mock.patch.object(client.urllib.request, 'Request')
|
|
- @mock.patch.object(client.urllib.request, 'urlopen')
|
|
- def test_request(self, _urlopen, _Request, _RestResult):
|
|
- path = '/api/storage/v1/pools'
|
|
- _urlopen.return_value = mock.Mock()
|
|
- self.client.request(path, mock.ANY)
|
|
- _Request.assert_called_with(self.url + path, None, self.client.headers)
|
|
- self.assertEqual(1, _urlopen.call_count)
|
|
- _RestResult.assert_called_with(response=mock.ANY)
|
|
-
|
|
- @mock.patch.object(client, 'RestResult')
|
|
- @mock.patch.object(client.urllib.request, 'Request')
|
|
- @mock.patch.object(client.urllib.request, 'urlopen')
|
|
- @mock.patch.object(client, 'ssl', new_callable=FakeSSL)
|
|
- def test_ssl_with_context(self, _ssl, _urlopen, _Request, _RestResult):
|
|
- """Test PEP476 certificate opt_out fix. """
|
|
- path = '/api/storage/v1/pools'
|
|
- _urlopen.return_value = mock.Mock()
|
|
- self.client.request(path, mock.ANY)
|
|
- _urlopen.assert_called_once_with(mock.ANY,
|
|
- timeout=self.timeout,
|
|
- context='fakecontext')
|
|
-
|
|
- @mock.patch.object(client, 'RestResult')
|
|
- @mock.patch.object(client.urllib.request, 'Request')
|
|
- @mock.patch.object(client.urllib.request, 'urlopen')
|
|
- @mock.patch.object(client, 'ssl', new_callable=object)
|
|
- def test_ssl_no_context(self, _ssl, _urlopen, _Request, _RestResult):
|
|
- """Verify the PEP476 fix backward compatibility. """
|
|
- path = '/api/storage/v1/pools'
|
|
- _urlopen.return_value = mock.Mock()
|
|
- self.client.request(path, mock.ANY)
|
|
- _urlopen.assert_called_once_with(mock.ANY, timeout=self.timeout)
|