"Fossies" - the Fresh Open Source Software Archive

Member "manila-8.1.4/manila/tests/share/drivers/glusterfs/test_layout_volume.py" (19 Nov 2020, 44147 Bytes) of package /linux/misc/openstack/manila-8.1.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_layout_volume.py": 8.1.3_vs_8.1.4.

    1 # Copyright (c) 2014 Red Hat, Inc.
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 """ GlusterFS volume mapped share layout testcases.
   17 """
   18 
   19 import re
   20 import shutil
   21 import tempfile
   22 
   23 import ddt
   24 import mock
   25 from oslo_config import cfg
   26 
   27 from manila.common import constants
   28 from manila import context
   29 from manila import exception
   30 from manila.share import configuration as config
   31 from manila.share.drivers.glusterfs import common
   32 from manila.share.drivers.glusterfs import layout_volume
   33 from manila import test
   34 from manila.tests import fake_utils
   35 
   36 
   37 CONF = cfg.CONF
   38 
   39 
   40 def new_share(**kwargs):
   41     share = {
   42         'id': 'fakeid',
   43         'name': 'fakename',
   44         'size': 1,
   45         'share_proto': 'glusterfs',
   46     }
   47     share.update(kwargs)
   48     return share
   49 
   50 
   51 def glusterXMLOut(**kwargs):
   52 
   53     template = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   54 <cliOutput>
   55   <opRet>%(ret)d</opRet>
   56   <opErrno>%(errno)d</opErrno>
   57   <opErrstr>fake error</opErrstr>
   58 </cliOutput>"""
   59 
   60     return template % kwargs, ''
   61 
   62 
   63 FAKE_UUID1 = '11111111-1111-1111-1111-111111111111'
   64 FAKE_UUID2 = '22222222-2222-2222-2222-222222222222'
   65 
   66 
   67 @ddt.ddt
   68 class GlusterfsVolumeMappedLayoutTestCase(test.TestCase):
   69     """Tests GlusterfsVolumeMappedLayout."""
   70 
   71     def setUp(self):
   72         super(GlusterfsVolumeMappedLayoutTestCase, self).setUp()
   73         fake_utils.stub_out_utils_execute(self)
   74         self._execute = fake_utils.fake_execute
   75         self._context = context.get_admin_context()
   76 
   77         self.glusterfs_target1 = 'root@host1:/gv1'
   78         self.glusterfs_target2 = 'root@host2:/gv2'
   79         self.glusterfs_server1 = 'root@host1'
   80         self.glusterfs_server2 = 'root@host2'
   81         self.glusterfs_server1_volumes = 'manila-share-1-1G\nshare1'
   82         self.glusterfs_server2_volumes = 'manila-share-2-2G\nshare2'
   83         self.share1 = new_share(
   84             export_location=self.glusterfs_target1,
   85             status=constants.STATUS_AVAILABLE)
   86         self.share2 = new_share(
   87             export_location=self.glusterfs_target2,
   88             status=constants.STATUS_AVAILABLE)
   89         gmgr = common.GlusterManager
   90         self.gmgr1 = gmgr(self.glusterfs_server1, self._execute, None, None,
   91                           requires={'volume': False})
   92         self.gmgr2 = gmgr(self.glusterfs_server2, self._execute, None, None,
   93                           requires={'volume': False})
   94         self.glusterfs_volumes_dict = (
   95             {'root@host1:/manila-share-1-1G': {'size': 1},
   96              'root@host2:/manila-share-2-2G': {'size': 2}})
   97         self.glusterfs_used_vols = set([
   98             'root@host1:/manila-share-1-1G',
   99             'root@host2:/manila-share-2-2G'])
  100 
  101         CONF.set_default('glusterfs_servers',
  102                          [self.glusterfs_server1, self.glusterfs_server2])
  103         CONF.set_default('glusterfs_server_password',
  104                          'fake_password')
  105         CONF.set_default('glusterfs_path_to_private_key',
  106                          '/fakepath/to/privatekey')
  107         CONF.set_default('glusterfs_volume_pattern',
  108                          'manila-share-\d+-#{size}G$')
  109         CONF.set_default('driver_handles_share_servers', False)
  110 
  111         self.fake_driver = mock.Mock()
  112         self.mock_object(self.fake_driver, '_execute',
  113                          self._execute)
  114         self.fake_driver.GLUSTERFS_VERSION_MIN = (3, 6)
  115 
  116         self.fake_conf = config.Configuration(None)
  117         self.mock_object(tempfile, 'mkdtemp',
  118                          mock.Mock(return_value='/tmp/tmpKGHKJ'))
  119         self.mock_object(common.GlusterManager, 'make_gluster_call')
  120 
  121         self.fake_private_storage = mock.Mock()
  122 
  123         with mock.patch.object(layout_volume.GlusterfsVolumeMappedLayout,
  124                                '_glustermanager',
  125                                side_effect=[self.gmgr1, self.gmgr2]):
  126             self._layout = layout_volume.GlusterfsVolumeMappedLayout(
  127                 self.fake_driver, configuration=self.fake_conf,
  128                 private_storage=self.fake_private_storage)
  129         self._layout.glusterfs_versions = {self.glusterfs_server1: ('3', '6'),
  130                                            self.glusterfs_server2: ('3', '7')}
  131         self.addCleanup(fake_utils.fake_execute_set_repliers, [])
  132         self.addCleanup(fake_utils.fake_execute_clear_log)
  133 
  134     @ddt.data({"test_kwargs": {}, "requires": {"volume": True}},
  135               {"test_kwargs": {'req_volume': False},
  136                "requires": {"volume": False}})
  137     @ddt.unpack
  138     def test_glustermanager(self, test_kwargs, requires):
  139         fake_obj = mock.Mock()
  140         self.mock_object(common, 'GlusterManager',
  141                          mock.Mock(return_value=fake_obj))
  142 
  143         ret = self._layout._glustermanager(self.glusterfs_target1,
  144                                            **test_kwargs)
  145 
  146         common.GlusterManager.assert_called_once_with(
  147             self.glusterfs_target1, self._execute,
  148             self._layout.configuration.glusterfs_path_to_private_key,
  149             self._layout.configuration.glusterfs_server_password,
  150             requires=requires)
  151         self.assertEqual(fake_obj, ret)
  152 
  153     def test_compile_volume_pattern(self):
  154         volume_pattern = 'manila-share-\d+-(?P<size>\d+)G$'
  155 
  156         ret = self._layout._compile_volume_pattern()
  157 
  158         self.assertEqual(re.compile(volume_pattern), ret)
  159 
  160     @ddt.data({'root@host1:/manila-share-1-1G': 'NONE',
  161                'root@host2:/manila-share-2-2G': None},
  162               {'root@host1:/manila-share-1-1G': FAKE_UUID1,
  163                'root@host2:/manila-share-2-2G': None},
  164               {'root@host1:/manila-share-1-1G': 'foobarbaz',
  165                'root@host2:/manila-share-2-2G': FAKE_UUID2},
  166               {'root@host1:/manila-share-1-1G': FAKE_UUID1,
  167                'root@host2:/manila-share-2-2G': FAKE_UUID2})
  168     def test_fetch_gluster_volumes(self, sharemark):
  169         vol1_qualified = 'root@host1:/manila-share-1-1G'
  170         gmgr_vol1 = common.GlusterManager(vol1_qualified)
  171         gmgr_vol1.get_vol_option = mock.Mock(
  172             return_value=sharemark[vol1_qualified])
  173         vol2_qualified = 'root@host2:/manila-share-2-2G'
  174         gmgr_vol2 = common.GlusterManager(vol2_qualified)
  175         gmgr_vol2.get_vol_option = mock.Mock(
  176             return_value=sharemark[vol2_qualified])
  177         self.mock_object(
  178             self.gmgr1, 'gluster_call',
  179             mock.Mock(return_value=(self.glusterfs_server1_volumes, '')))
  180         self.mock_object(
  181             self.gmgr2, 'gluster_call',
  182             mock.Mock(return_value=(self.glusterfs_server2_volumes, '')))
  183         _glustermanager_calls = (self.gmgr1, gmgr_vol1, self.gmgr2, gmgr_vol2)
  184         self.mock_object(self._layout, '_glustermanager',
  185                          mock.Mock(side_effect=_glustermanager_calls))
  186         expected_output = {}
  187         for q, d in self.glusterfs_volumes_dict.items():
  188             if sharemark[q] not in (FAKE_UUID1, FAKE_UUID2):
  189                 expected_output[q] = d
  190 
  191         ret = self._layout._fetch_gluster_volumes()
  192 
  193         test_args = ('volume', 'list')
  194         self.gmgr1.gluster_call.assert_called_once_with(*test_args,
  195                                                         log=mock.ANY)
  196         self.gmgr2.gluster_call.assert_called_once_with(*test_args,
  197                                                         log=mock.ANY)
  198         gmgr_vol1.get_vol_option.assert_called_once_with(
  199             'user.manila-share')
  200         gmgr_vol2.get_vol_option.assert_called_once_with(
  201             'user.manila-share')
  202         self.assertEqual(expected_output, ret)
  203 
  204     def test_fetch_gluster_volumes_no_filter_used(self):
  205         vol1_qualified = 'root@host1:/manila-share-1-1G'
  206         gmgr_vol1 = common.GlusterManager(vol1_qualified)
  207         gmgr_vol1.get_vol_option = mock.Mock()
  208         vol2_qualified = 'root@host2:/manila-share-2-2G'
  209         gmgr_vol2 = common.GlusterManager(vol2_qualified)
  210         gmgr_vol2.get_vol_option = mock.Mock()
  211         self.mock_object(
  212             self.gmgr1, 'gluster_call',
  213             mock.Mock(return_value=(self.glusterfs_server1_volumes, '')))
  214         self.mock_object(
  215             self.gmgr2, 'gluster_call',
  216             mock.Mock(return_value=(self.glusterfs_server2_volumes, '')))
  217         _glustermanager_calls = (self.gmgr1, gmgr_vol1, self.gmgr2, gmgr_vol2)
  218         self.mock_object(self._layout, '_glustermanager',
  219                          mock.Mock(side_effect=_glustermanager_calls))
  220         expected_output = self.glusterfs_volumes_dict
  221 
  222         ret = self._layout._fetch_gluster_volumes(filter_used=False)
  223 
  224         test_args = ('volume', 'list')
  225         self.gmgr1.gluster_call.assert_called_once_with(*test_args,
  226                                                         log=mock.ANY)
  227         self.gmgr2.gluster_call.assert_called_once_with(*test_args,
  228                                                         log=mock.ANY)
  229         self.assertFalse(gmgr_vol1.get_vol_option.called)
  230         self.assertFalse(gmgr_vol2.get_vol_option.called)
  231         self.assertEqual(expected_output, ret)
  232 
  233     def test_fetch_gluster_volumes_no_keymatch(self):
  234         vol1_qualified = 'root@host1:/manila-share-1'
  235         gmgr_vol1 = common.GlusterManager(vol1_qualified)
  236         gmgr_vol1.get_vol_option = mock.Mock(return_value=None)
  237         self._layout.configuration.glusterfs_servers = [self.glusterfs_server1]
  238         self.mock_object(
  239             self.gmgr1, 'gluster_call',
  240             mock.Mock(return_value=('manila-share-1', '')))
  241         _glustermanager_calls = (self.gmgr1, gmgr_vol1)
  242         self.mock_object(self._layout, '_glustermanager',
  243                          mock.Mock(side_effect=_glustermanager_calls))
  244         self.mock_object(self._layout, 'volume_pattern',
  245                          re.compile('manila-share-\d+(-(?P<size>\d+)G)?$'))
  246         expected_output = {'root@host1:/manila-share-1': {'size': None}}
  247 
  248         ret = self._layout._fetch_gluster_volumes()
  249 
  250         test_args = ('volume', 'list')
  251         self.gmgr1.gluster_call.assert_called_once_with(*test_args,
  252                                                         log=mock.ANY)
  253         self.assertEqual(expected_output, ret)
  254 
  255     def test_fetch_gluster_volumes_error(self):
  256         test_args = ('volume', 'list')
  257 
  258         def raise_exception(*args, **kwargs):
  259             if(args == test_args):
  260                 raise exception.GlusterfsException()
  261 
  262         self._layout.configuration.glusterfs_servers = [self.glusterfs_server1]
  263         self.mock_object(self.gmgr1, 'gluster_call',
  264                          mock.Mock(side_effect=raise_exception))
  265         self.mock_object(self._layout, '_glustermanager',
  266                          mock.Mock(return_value=self.gmgr1))
  267         self.mock_object(layout_volume.LOG, 'error')
  268 
  269         self.assertRaises(exception.GlusterfsException,
  270                           self._layout._fetch_gluster_volumes)
  271 
  272         self.gmgr1.gluster_call.assert_called_once_with(*test_args,
  273                                                         log=mock.ANY)
  274 
  275     def test_do_setup(self):
  276         self._layout.configuration.glusterfs_servers = [self.glusterfs_server1]
  277         self.mock_object(self.gmgr1, 'get_gluster_version',
  278                          mock.Mock(return_value=('3', '6')))
  279         self.mock_object(self._layout, '_glustermanager',
  280                          mock.Mock(return_value=self.gmgr1))
  281         self.mock_object(self._layout, '_fetch_gluster_volumes',
  282                          mock.Mock(return_value=self.glusterfs_volumes_dict))
  283         self.mock_object(self._layout, '_check_mount_glusterfs')
  284         self._layout.gluster_used_vols = self.glusterfs_used_vols
  285         self.mock_object(layout_volume.LOG, 'warning')
  286 
  287         self._layout.do_setup(self._context)
  288 
  289         self._layout._fetch_gluster_volumes.assert_called_once_with(
  290             filter_used=False)
  291         self._layout._check_mount_glusterfs.assert_called_once_with()
  292         self.gmgr1.get_gluster_version.assert_called_once_with()
  293 
  294     def test_do_setup_unsupported_glusterfs_version(self):
  295         self._layout.configuration.glusterfs_servers = [self.glusterfs_server1]
  296         self.mock_object(self.gmgr1, 'get_gluster_version',
  297                          mock.Mock(return_value=('3', '5')))
  298         self.mock_object(self._layout, '_glustermanager',
  299                          mock.Mock(return_value=self.gmgr1))
  300 
  301         self.assertRaises(exception.GlusterfsException,
  302                           self._layout.do_setup, self._context)
  303 
  304         self.gmgr1.get_gluster_version.assert_called_once_with()
  305 
  306     @ddt.data(exception.GlusterfsException, RuntimeError)
  307     def test_do_setup_get_gluster_version_fails(self, exc):
  308         def raise_exception(*args, **kwargs):
  309             raise exc
  310 
  311         self._layout.configuration.glusterfs_servers = [self.glusterfs_server1]
  312         self.mock_object(self.gmgr1, 'get_gluster_version',
  313                          mock.Mock(side_effect=raise_exception))
  314         self.mock_object(self._layout, '_glustermanager',
  315                          mock.Mock(return_value=self.gmgr1))
  316 
  317         self.assertRaises(exc, self._layout.do_setup, self._context)
  318 
  319         self.gmgr1.get_gluster_version.assert_called_once_with()
  320 
  321     def test_do_setup_glusterfs_no_volumes_provided_by_backend(self):
  322         self._layout.configuration.glusterfs_servers = [self.glusterfs_server1]
  323         self.mock_object(self.gmgr1, 'get_gluster_version',
  324                          mock.Mock(return_value=('3', '6')))
  325         self.mock_object(self._layout, '_glustermanager',
  326                          mock.Mock(return_value=self.gmgr1))
  327         self.mock_object(self._layout, '_fetch_gluster_volumes',
  328                          mock.Mock(return_value={}))
  329 
  330         self.assertRaises(exception.GlusterfsException,
  331                           self._layout.do_setup, self._context)
  332 
  333         self._layout._fetch_gluster_volumes.assert_called_once_with(
  334             filter_used=False)
  335 
  336     def test_share_manager(self):
  337         self.mock_object(self._layout, '_glustermanager',
  338                          mock.Mock(return_value=self.gmgr1))
  339         self.mock_object(self._layout.private_storage,
  340                          'get', mock.Mock(return_value='host1:/gv1'))
  341 
  342         ret = self._layout._share_manager(self.share1)
  343 
  344         self._layout.private_storage.get.assert_called_once_with(
  345             self.share1['id'], 'volume')
  346         self._layout._glustermanager.assert_called_once_with('host1:/gv1')
  347         self.assertEqual(self.gmgr1, ret)
  348 
  349     def test_share_manager_no_privdata(self):
  350         self.mock_object(self._layout.private_storage,
  351                          'get', mock.Mock(return_value=None))
  352 
  353         ret = self._layout._share_manager(self.share1)
  354 
  355         self._layout.private_storage.get.assert_called_once_with(
  356             self.share1['id'], 'volume')
  357         self.assertIsNone(ret)
  358 
  359     def test_ensure_share(self):
  360         share = self.share1
  361         gmgr1 = common.GlusterManager(self.glusterfs_target1, self._execute,
  362                                       None, None)
  363         gmgr1.set_vol_option = mock.Mock()
  364         self.mock_object(self._layout, '_share_manager',
  365                          mock.Mock(return_value=gmgr1))
  366 
  367         self._layout.ensure_share(self._context, share)
  368 
  369         self._layout._share_manager.assert_called_once_with(share)
  370         self.assertIn(self.glusterfs_target1, self._layout.gluster_used_vols)
  371         gmgr1.set_vol_option.assert_called_once_with(
  372             'user.manila-share', share['id'])
  373 
  374     @ddt.data({"voldict": {"host:/share2G": {"size": 2}}, "used_vols": set(),
  375                "size": 1, "expected": "host:/share2G"},
  376               {"voldict": {"host:/share2G": {"size": 2}}, "used_vols": set(),
  377                "size": 2, "expected": "host:/share2G"},
  378               {"voldict": {"host:/share2G": {"size": 2}}, "used_vols": set(),
  379                "size": None, "expected": "host:/share2G"},
  380               {"voldict": {"host:/share2G": {"size": 2},
  381                            "host:/share": {"size": None}},
  382                "used_vols": set(["host:/share2G"]), "size": 1,
  383                "expected": "host:/share"},
  384               {"voldict": {"host:/share2G": {"size": 2},
  385                            "host:/share": {"size": None}},
  386                "used_vols": set(["host:/share2G"]), "size": 2,
  387                "expected": "host:/share"},
  388               {"voldict": {"host:/share2G": {"size": 2},
  389                "host:/share": {"size": None}},
  390                "used_vols": set(["host:/share2G"]), "size": 3,
  391                "expected": "host:/share"},
  392               {"voldict": {"host:/share2G": {"size": 2},
  393                            "host:/share": {"size": None}},
  394                "used_vols": set(["host:/share2G"]), "size": None,
  395                "expected": "host:/share"},
  396               {"voldict": {"host:/share": {}}, "used_vols": set(), "size": 1,
  397                "expected": "host:/share"},
  398               {"voldict": {"host:/share": {}}, "used_vols": set(),
  399                "size": None, "expected": "host:/share"})
  400     @ddt.unpack
  401     def test_pop_gluster_vol(self, voldict, used_vols, size, expected):
  402         gmgr = common.GlusterManager
  403         gmgr1 = gmgr(expected, self._execute, None, None)
  404         self._layout._fetch_gluster_volumes = mock.Mock(return_value=voldict)
  405         self._layout.gluster_used_vols = used_vols
  406         self._layout._glustermanager = mock.Mock(return_value=gmgr1)
  407         self._layout.volume_pattern_keys = list(voldict.values())[0].keys()
  408 
  409         result = self._layout._pop_gluster_vol(size=size)
  410 
  411         self.assertEqual(expected, result)
  412         self.assertIn(result, used_vols)
  413         self._layout._fetch_gluster_volumes.assert_called_once_with()
  414         self._layout._glustermanager.assert_called_once_with(result)
  415 
  416     @ddt.data({"voldict": {"share2G": {"size": 2}},
  417                "used_vols": set(), "size": 3},
  418               {"voldict": {"share2G": {"size": 2}},
  419                "used_vols": set(["share2G"]), "size": None})
  420     @ddt.unpack
  421     def test_pop_gluster_vol_excp(self, voldict, used_vols, size):
  422         self._layout._fetch_gluster_volumes = mock.Mock(return_value=voldict)
  423         self._layout.gluster_used_vols = used_vols
  424         self._layout.volume_pattern_keys = list(voldict.values())[0].keys()
  425 
  426         self.assertRaises(exception.GlusterfsException,
  427                           self._layout._pop_gluster_vol, size=size)
  428 
  429         self._layout._fetch_gluster_volumes.assert_called_once_with()
  430         self.assertFalse(
  431             self.fake_driver._setup_via_manager.called)
  432 
  433     def test_push_gluster_vol(self):
  434         self._layout.gluster_used_vols = set([
  435             self.glusterfs_target1, self.glusterfs_target2])
  436 
  437         self._layout._push_gluster_vol(self.glusterfs_target2)
  438 
  439         self.assertEqual(1, len(self._layout.gluster_used_vols))
  440         self.assertFalse(
  441             self.glusterfs_target2 in self._layout.gluster_used_vols)
  442 
  443     def test_push_gluster_vol_excp(self):
  444         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  445         self._layout.gluster_unused_vols_dict = {}
  446 
  447         self.assertRaises(exception.GlusterfsException,
  448                           self._layout._push_gluster_vol,
  449                           self.glusterfs_target2)
  450 
  451     @ddt.data({'vers_minor': '6',
  452                'cmd': ['find', '/tmp/tmpKGHKJ', '-mindepth', '1',
  453                        '-delete']},
  454               {'vers_minor': '7',
  455                'cmd': ['find', '/tmp/tmpKGHKJ', '-mindepth', '1', '!',
  456                        '-path', '/tmp/tmpKGHKJ/.trashcan', '!', '-path',
  457                        '/tmp/tmpKGHKJ/.trashcan/internal_op', '-delete']})
  458     @ddt.unpack
  459     def test_wipe_gluster_vol(self, vers_minor, cmd):
  460         tmpdir = '/tmp/tmpKGHKJ'
  461         gmgr = common.GlusterManager
  462         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  463         self._layout.glusterfs_versions = {
  464             self.glusterfs_server1: ('3', vers_minor)}
  465 
  466         self.mock_object(tempfile, 'mkdtemp',
  467                          mock.Mock(return_value=tmpdir))
  468         self.mock_object(self.fake_driver, '_execute', mock.Mock())
  469         self.mock_object(common, '_mount_gluster_vol', mock.Mock())
  470         self.mock_object(common, '_umount_gluster_vol', mock.Mock())
  471         self.mock_object(shutil, 'rmtree', mock.Mock())
  472 
  473         self._layout._wipe_gluster_vol(gmgr1)
  474 
  475         tempfile.mkdtemp.assert_called_once_with()
  476         common._mount_gluster_vol.assert_called_once_with(
  477             self.fake_driver._execute, gmgr1.export,
  478             tmpdir)
  479         kwargs = {'run_as_root': True}
  480         self.fake_driver._execute.assert_called_once_with(
  481             *cmd, **kwargs)
  482         common._umount_gluster_vol.assert_called_once_with(
  483             self.fake_driver._execute, tmpdir)
  484         kwargs = {'ignore_errors': True}
  485         shutil.rmtree.assert_called_once_with(tmpdir,
  486                                               **kwargs)
  487 
  488     def test_wipe_gluster_vol_mount_fail(self):
  489         tmpdir = '/tmp/tmpKGHKJ'
  490         gmgr = common.GlusterManager
  491         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  492         self._layout.glusterfs_versions = {
  493             self.glusterfs_server1: ('3', '6')}
  494         self.mock_object(tempfile, 'mkdtemp',
  495                          mock.Mock(return_value=tmpdir))
  496         self.mock_object(self.fake_driver, '_execute', mock.Mock())
  497         self.mock_object(common, '_mount_gluster_vol',
  498                          mock.Mock(side_effect=exception.GlusterfsException))
  499         self.mock_object(common, '_umount_gluster_vol', mock.Mock())
  500         self.mock_object(shutil, 'rmtree', mock.Mock())
  501 
  502         self.assertRaises(exception.GlusterfsException,
  503                           self._layout._wipe_gluster_vol,
  504                           gmgr1)
  505 
  506         tempfile.mkdtemp.assert_called_once_with()
  507         common._mount_gluster_vol.assert_called_once_with(
  508             self.fake_driver._execute, gmgr1.export,
  509             tmpdir)
  510         self.assertFalse(self.fake_driver._execute.called)
  511         self.assertFalse(common._umount_gluster_vol.called)
  512         kwargs = {'ignore_errors': True}
  513         shutil.rmtree.assert_called_once_with(tmpdir,
  514                                               **kwargs)
  515 
  516     def test_wipe_gluster_vol_error_wiping_gluster_vol(self):
  517         tmpdir = '/tmp/tmpKGHKJ'
  518         gmgr = common.GlusterManager
  519         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  520         self._layout.glusterfs_versions = {
  521             self.glusterfs_server1: ('3', '6')}
  522         cmd = ['find', '/tmp/tmpKGHKJ', '-mindepth', '1', '-delete']
  523         self.mock_object(tempfile, 'mkdtemp',
  524                          mock.Mock(return_value=tmpdir))
  525         self.mock_object(
  526             self.fake_driver, '_execute',
  527             mock.Mock(side_effect=exception.ProcessExecutionError))
  528         self.mock_object(common, '_mount_gluster_vol', mock.Mock())
  529         self.mock_object(common, '_umount_gluster_vol', mock.Mock())
  530         self.mock_object(shutil, 'rmtree', mock.Mock())
  531 
  532         self.assertRaises(exception.GlusterfsException,
  533                           self._layout._wipe_gluster_vol,
  534                           gmgr1)
  535 
  536         tempfile.mkdtemp.assert_called_once_with()
  537         common._mount_gluster_vol.assert_called_once_with(
  538             self.fake_driver._execute, gmgr1.export,
  539             tmpdir)
  540         kwargs = {'run_as_root': True}
  541         self.fake_driver._execute.assert_called_once_with(
  542             *cmd, **kwargs)
  543         common._umount_gluster_vol.assert_called_once_with(
  544             self.fake_driver._execute, tmpdir)
  545         kwargs = {'ignore_errors': True}
  546         shutil.rmtree.assert_called_once_with(tmpdir,
  547                                               **kwargs)
  548 
  549     def test_create_share(self):
  550         self._layout._pop_gluster_vol = mock.Mock(
  551             return_value=self.glusterfs_target1)
  552         gmgr1 = common.GlusterManager(self.glusterfs_target1)
  553         gmgr1.set_vol_option = mock.Mock()
  554         self.mock_object(self._layout, '_glustermanager',
  555                          mock.Mock(return_value=gmgr1))
  556         self.mock_object(self.fake_driver, '_setup_via_manager',
  557                          mock.Mock(return_value='host1:/gv1'))
  558 
  559         share = new_share()
  560         exp_locn = self._layout.create_share(self._context, share)
  561 
  562         self._layout._pop_gluster_vol.assert_called_once_with(share['size'])
  563         self.fake_driver._setup_via_manager.assert_called_once_with(
  564             {'manager': gmgr1, 'share': share})
  565         self._layout.private_storage.update.assert_called_once_with(
  566             share['id'], {'volume': self.glusterfs_target1})
  567         gmgr1.set_vol_option.assert_called_once_with(
  568             'user.manila-share', share['id'])
  569         self.assertEqual('host1:/gv1', exp_locn)
  570 
  571     def test_create_share_error(self):
  572         self._layout._pop_gluster_vol = mock.Mock(
  573             side_effect=exception.GlusterfsException)
  574 
  575         share = new_share()
  576         self.assertRaises(exception.GlusterfsException,
  577                           self._layout.create_share, self._context, share)
  578 
  579         self._layout._pop_gluster_vol.assert_called_once_with(
  580             share['size'])
  581 
  582     @ddt.data(None, '', 'Eeyore')
  583     def test_delete_share(self, clone_of):
  584         self._layout._push_gluster_vol = mock.Mock()
  585         self._layout._wipe_gluster_vol = mock.Mock()
  586         gmgr = common.GlusterManager
  587         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  588         gmgr1.set_vol_option = mock.Mock()
  589         gmgr1.get_vol_option = mock.Mock(return_value=clone_of)
  590         new_vol_addr = self.glusterfs_target1
  591         self.mock_object(self._layout, '_glustermanager',
  592                          mock.Mock(return_value=gmgr1))
  593         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  594 
  595         self._layout.delete_share(self._context, self.share1)
  596 
  597         gmgr1.get_vol_option.assert_called_once_with(
  598             'user.manila-cloned-from')
  599         self._layout._wipe_gluster_vol.assert_called_once_with(gmgr1)
  600         self.assertIn(new_vol_addr, self._layout.gluster_used_vols)
  601         self._layout._push_gluster_vol.assert_called_once_with(
  602             self.glusterfs_target1)
  603         self._layout.private_storage.delete.assert_called_once_with(
  604             self.share1['id'])
  605         gmgr1.set_vol_option.assert_has_calls([
  606             mock.call('user.manila-share', 'NONE'),
  607             mock.call('nfs.disable', 'on')
  608         ])
  609 
  610     def test_delete_share_clone(self):
  611         self._layout._push_gluster_vol = mock.Mock()
  612         self._layout._wipe_gluster_vol = mock.Mock()
  613         gmgr = common.GlusterManager
  614         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  615         gmgr1.gluster_call = mock.Mock()
  616         gmgr1.get_vol_option = mock.Mock(return_value=FAKE_UUID1)
  617         self.mock_object(self._layout, '_glustermanager',
  618                          mock.Mock(return_value=gmgr1))
  619         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  620 
  621         self._layout.delete_share(self._context, self.share1)
  622 
  623         gmgr1.get_vol_option.assert_called_once_with(
  624             'user.manila-cloned-from')
  625         self.assertFalse(self._layout._wipe_gluster_vol.called)
  626         self._layout._push_gluster_vol.assert_called_once_with(
  627             self.glusterfs_target1)
  628         self._layout.private_storage.delete.assert_called_once_with(
  629             self.share1['id'])
  630         gmgr1.gluster_call.assert_called_once_with(
  631             'volume', 'delete', 'gv1')
  632 
  633     def test_delete_share_error(self):
  634         self._layout._wipe_gluster_vol = mock.Mock()
  635         self._layout._wipe_gluster_vol.side_effect = (
  636             exception.GlusterfsException)
  637         self._layout._push_gluster_vol = mock.Mock()
  638         gmgr = common.GlusterManager
  639         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  640         gmgr1.get_vol_option = mock.Mock(return_value=None)
  641         self.mock_object(self._layout, '_glustermanager',
  642                          mock.Mock(return_value=gmgr1))
  643         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  644 
  645         self.assertRaises(exception.GlusterfsException,
  646                           self._layout.delete_share, self._context,
  647                           self.share1)
  648 
  649         self._layout._wipe_gluster_vol.assert_called_once_with(gmgr1)
  650         self.assertFalse(self._layout._push_gluster_vol.called)
  651 
  652     def test_delete_share_missing_record(self):
  653         self.mock_object(self._layout, '_share_manager',
  654                          mock.Mock(return_value=None))
  655 
  656         self._layout.delete_share(self._context, self.share1)
  657 
  658         self._layout._share_manager.assert_called_once_with(self.share1)
  659 
  660     def test_create_snapshot(self):
  661         self._layout.gluster_nosnap_vols_dict = {}
  662         self._layout.glusterfs_versions = {self.glusterfs_server1: ('3', '6')}
  663         gmgr = common.GlusterManager
  664         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  665         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  666         self.mock_object(gmgr1, 'gluster_call',
  667                          mock.Mock(
  668                              side_effect=(glusterXMLOut(ret=0, errno=0),)))
  669         self.mock_object(self._layout, '_glustermanager',
  670                          mock.Mock(return_value=gmgr1))
  671 
  672         snapshot = {
  673             'id': 'fake_snap_id',
  674             'share_id': self.share1['id'],
  675             'share': self.share1
  676         }
  677         ret = self._layout.create_snapshot(self._context, snapshot)
  678 
  679         self.assertIsNone(ret)
  680         args = ('--xml', 'snapshot', 'create', 'manila-fake_snap_id',
  681                 gmgr1.volume)
  682         gmgr1.gluster_call.assert_called_once_with(*args, log=mock.ANY)
  683 
  684     @ddt.data({'side_effect': (glusterXMLOut(ret=-1, errno=2),),
  685                '_exception': exception.GlusterfsException},
  686               {'side_effect': (('', ''),),
  687                '_exception': exception.GlusterfsException})
  688     @ddt.unpack
  689     def test_create_snapshot_error(self, side_effect, _exception):
  690         self._layout.gluster_nosnap_vols_dict = {}
  691         self._layout.glusterfs_versions = {self.glusterfs_server1: ('3', '6')}
  692         gmgr = common.GlusterManager
  693         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  694         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  695         self.mock_object(gmgr1, 'gluster_call',
  696                          mock.Mock(side_effect=side_effect))
  697         self.mock_object(self._layout, '_glustermanager',
  698                          mock.Mock(return_value=gmgr1))
  699 
  700         snapshot = {
  701             'id': 'fake_snap_id',
  702             'share_id': self.share1['id'],
  703             'share': self.share1
  704         }
  705         self.assertRaises(_exception, self._layout.create_snapshot,
  706                           self._context, snapshot)
  707 
  708         args = ('--xml', 'snapshot', 'create', 'manila-fake_snap_id',
  709                 gmgr1.volume)
  710         gmgr1.gluster_call.assert_called_once_with(*args, log=mock.ANY)
  711 
  712     @ddt.data({"vers_minor": '6', "exctype": exception.GlusterfsException},
  713               {"vers_minor": '7',
  714                "exctype": exception.ShareSnapshotNotSupported})
  715     @ddt.unpack
  716     def test_create_snapshot_no_snap(self, vers_minor, exctype):
  717         self._layout.gluster_nosnap_vols_dict = {}
  718         self._layout.glusterfs_versions = {
  719             self.glusterfs_server1: ('3', vers_minor)}
  720         gmgr = common.GlusterManager
  721         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  722         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  723         self.mock_object(gmgr1, 'gluster_call',
  724                          mock.Mock(
  725                              side_effect=(glusterXMLOut(ret=-1, errno=0),)))
  726         self.mock_object(self._layout, '_glustermanager',
  727                          mock.Mock(return_value=gmgr1))
  728 
  729         snapshot = {
  730             'id': 'fake_snap_id',
  731             'share_id': self.share1['id'],
  732             'share': self.share1
  733         }
  734         self.assertRaises(exctype, self._layout.create_snapshot, self._context,
  735                           snapshot)
  736 
  737         args = ('--xml', 'snapshot', 'create', 'manila-fake_snap_id',
  738                 gmgr1.volume)
  739         gmgr1.gluster_call.assert_called_once_with(*args, log=mock.ANY)
  740 
  741     @ddt.data({"vers_minor": '6', "exctype": exception.GlusterfsException},
  742               {"vers_minor": '7',
  743                "exctype": exception.ShareSnapshotNotSupported})
  744     @ddt.unpack
  745     def test_create_snapshot_no_snap_cached(self, vers_minor, exctype):
  746         self._layout.gluster_nosnap_vols_dict = {
  747             self.glusterfs_target1: 'fake error'}
  748         self._layout.glusterfs_versions = {
  749             self.glusterfs_server1: ('3', vers_minor)}
  750         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  751         gmgr = common.GlusterManager
  752         gmgr1 = gmgr(self.glusterfs_target1, self._execute, None, None)
  753         self.mock_object(self._layout, '_share_manager',
  754                          mock.Mock(return_value=gmgr1))
  755 
  756         snapshot = {
  757             'id': 'fake_snap_id',
  758             'share_id': self.share1['id'],
  759             'share': self.share1
  760         }
  761         self.assertRaises(exctype, self._layout.create_snapshot, self._context,
  762                           snapshot)
  763 
  764     def test_find_actual_backend_snapshot_name(self):
  765         gmgr = common.GlusterManager
  766         gmgr1 = gmgr(self.share1['export_location'], self._execute, None, None)
  767         self.mock_object(gmgr1, 'gluster_call',
  768                          mock.Mock(return_value=('fake_snap_id_xyz', '')))
  769 
  770         snapshot = {
  771             'id': 'fake_snap_id',
  772             'share_id': self.share1['id'],
  773             'share': self.share1
  774         }
  775         ret = self._layout._find_actual_backend_snapshot_name(gmgr1, snapshot)
  776 
  777         args = ('snapshot', 'list', gmgr1.volume, '--mode=script')
  778         gmgr1.gluster_call.assert_called_once_with(*args, log=mock.ANY)
  779         self.assertEqual('fake_snap_id_xyz', ret)
  780 
  781     @ddt.data('this is too bad', 'fake_snap_id_xyx\nfake_snap_id_pqr')
  782     def test_find_actual_backend_snapshot_name_bad_snap_list(self, snaplist):
  783         gmgr = common.GlusterManager
  784         gmgr1 = gmgr(self.share1['export_location'], self._execute, None, None)
  785         self.mock_object(gmgr1, 'gluster_call',
  786                          mock.Mock(return_value=(snaplist, '')))
  787 
  788         snapshot = {
  789             'id': 'fake_snap_id',
  790             'share_id': self.share1['id'],
  791             'share': self.share1
  792         }
  793         self.assertRaises(exception.GlusterfsException,
  794                           self._layout._find_actual_backend_snapshot_name,
  795                           gmgr1, snapshot)
  796 
  797         args = ('snapshot', 'list', gmgr1.volume, '--mode=script')
  798         gmgr1.gluster_call.assert_called_once_with(*args, log=mock.ANY)
  799 
  800     @ddt.data({'glusterfs_target': 'root@host1:/gv1',
  801                'glusterfs_server': 'root@host1'},
  802               {'glusterfs_target': 'host1:/gv1',
  803                'glusterfs_server': 'host1'})
  804     @ddt.unpack
  805     def test_create_share_from_snapshot(self, glusterfs_target,
  806                                         glusterfs_server):
  807         share = new_share()
  808         snapshot = {
  809             'id': 'fake_snap_id',
  810             'share_instance': new_share(export_location=glusterfs_target),
  811             'share_id': 'fake_share_id',
  812         }
  813         volume = ''.join(['manila-', share['id']])
  814         new_vol_addr = ':/'.join([glusterfs_server, volume])
  815         gmgr = common.GlusterManager
  816         old_gmgr = gmgr(glusterfs_target, self._execute, None, None)
  817         new_gmgr = gmgr(new_vol_addr, self._execute, None, None)
  818         self._layout.gluster_used_vols = set([glusterfs_target])
  819         self._layout.glusterfs_versions = {glusterfs_server: ('3', '7')}
  820         self.mock_object(old_gmgr, 'gluster_call',
  821                          mock.Mock(side_effect=[('', ''), ('', '')]))
  822         self.mock_object(new_gmgr, 'gluster_call',
  823                          mock.Mock(side_effect=[('', ''), ('', ''), ('', '')]))
  824         self.mock_object(new_gmgr, 'get_vol_option',
  825                          mock.Mock())
  826         new_gmgr.get_vol_option.return_value = (
  827             'glusterfs-server-1,client')
  828         self.mock_object(self._layout, '_find_actual_backend_snapshot_name',
  829                          mock.Mock(return_value='fake_snap_id_xyz'))
  830         self.mock_object(self._layout, '_share_manager',
  831                          mock.Mock(return_value=old_gmgr))
  832         self.mock_object(self._layout, '_glustermanager',
  833                          mock.Mock(return_value=new_gmgr))
  834         self.mock_object(self.fake_driver, '_setup_via_manager',
  835                          mock.Mock(return_value='host1:/gv1'))
  836 
  837         ret = self._layout.create_share_from_snapshot(
  838             self._context, share, snapshot, None)
  839 
  840         (self._layout._find_actual_backend_snapshot_name.
  841             assert_called_once_with(old_gmgr, snapshot))
  842         args = (('snapshot', 'activate', 'fake_snap_id_xyz',
  843                  'force', '--mode=script'),
  844                 ('snapshot', 'clone', volume, 'fake_snap_id_xyz'))
  845         old_gmgr.gluster_call.assert_has_calls(
  846             [mock.call(*a, log=mock.ANY) for a in args])
  847         args = (('volume', 'start', volume),
  848                 ('volume', 'set', volume, 'user.manila-share', share['id']),
  849                 ('volume', 'set', volume, 'user.manila-cloned-from',
  850                  snapshot['share_id']))
  851         new_gmgr.gluster_call.assert_has_calls(
  852             [mock.call(*a, log=mock.ANY) for a in args], any_order=True)
  853         self._layout._share_manager.assert_called_once_with(
  854             snapshot['share_instance'])
  855         self._layout._glustermanager.assert_called_once_with(
  856             gmgr.parse(new_vol_addr))
  857         self._layout.driver._setup_via_manager.assert_called_once_with(
  858             {'manager': new_gmgr, 'share': share},
  859             {'manager': old_gmgr, 'share': snapshot['share_instance']})
  860         self._layout.private_storage.update.assert_called_once_with(
  861             share['id'], {'volume': new_vol_addr})
  862         self.assertIn(
  863             new_vol_addr,
  864             self._layout.gluster_used_vols)
  865         self.assertEqual('host1:/gv1', ret)
  866 
  867     def test_create_share_from_snapshot_error_unsupported_gluster_version(
  868             self):
  869         glusterfs_target = 'root@host1:/gv1'
  870         glusterfs_server = 'root@host1'
  871         share = new_share()
  872         volume = ''.join(['manila-', share['id']])
  873         new_vol_addr = ':/'.join([glusterfs_server, volume])
  874         gmgr = common.GlusterManager
  875         old_gmgr = gmgr(glusterfs_target, self._execute, None, None)
  876         new_gmgr = gmgr(new_vol_addr, self._execute, None, None)
  877         self._layout.gluster_used_vols_dict = {glusterfs_target: old_gmgr}
  878         self._layout.glusterfs_versions = {glusterfs_server: ('3', '6')}
  879         self.mock_object(
  880             old_gmgr, 'gluster_call',
  881             mock.Mock(side_effect=[('', ''), ('', '')]))
  882         self.mock_object(new_gmgr, 'get_vol_option',
  883                          mock.Mock())
  884         new_gmgr.get_vol_option.return_value = (
  885             'glusterfs-server-1,client')
  886         self.mock_object(self._layout, '_find_actual_backend_snapshot_name',
  887                          mock.Mock(return_value='fake_snap_id_xyz'))
  888         self.mock_object(self._layout, '_share_manager',
  889                          mock.Mock(return_value=old_gmgr))
  890         self.mock_object(self._layout, '_glustermanager',
  891                          mock.Mock(return_value=new_gmgr))
  892 
  893         snapshot = {
  894             'id': 'fake_snap_id',
  895             'share_instance': new_share(export_location=glusterfs_target)
  896         }
  897         self.assertRaises(exception.GlusterfsException,
  898                           self._layout.create_share_from_snapshot,
  899                           self._context, share, snapshot)
  900 
  901         self.assertFalse(
  902             self._layout._find_actual_backend_snapshot_name.called)
  903         self.assertFalse(old_gmgr.gluster_call.called)
  904         self._layout._share_manager.assert_called_once_with(
  905             snapshot['share_instance'])
  906         self.assertFalse(self._layout._glustermanager.called)
  907         self.assertFalse(new_gmgr.get_vol_option.called)
  908         self.assertFalse(new_gmgr.gluster_call.called)
  909         self.assertNotIn(new_vol_addr,
  910                          self._layout.glusterfs_versions.keys())
  911 
  912     def test_delete_snapshot(self):
  913         self._layout.gluster_nosnap_vols_dict = {}
  914         gmgr = common.GlusterManager
  915         gmgr1 = gmgr(self.share1['export_location'], self._execute, None, None)
  916         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  917         self.mock_object(self._layout, '_find_actual_backend_snapshot_name',
  918                          mock.Mock(return_value='fake_snap_id_xyz'))
  919         self.mock_object(
  920             gmgr1, 'gluster_call',
  921             mock.Mock(return_value=glusterXMLOut(ret=0, errno=0)))
  922         self.mock_object(self._layout, '_glustermanager',
  923                          mock.Mock(return_value=gmgr1))
  924         snapshot = {
  925             'id': 'fake_snap_id',
  926             'share_id': self.share1['id'],
  927             'share': self.share1
  928         }
  929         ret = self._layout.delete_snapshot(self._context, snapshot)
  930 
  931         self.assertIsNone(ret)
  932         args = ('--xml', 'snapshot', 'delete', 'fake_snap_id_xyz',
  933                 '--mode=script')
  934         gmgr1.gluster_call.assert_called_once_with(*args, log=mock.ANY)
  935         (self._layout._find_actual_backend_snapshot_name.
  936             assert_called_once_with(gmgr1, snapshot))
  937 
  938     @ddt.data({'side_effect': (glusterXMLOut(ret=-1, errno=0),),
  939                '_exception': exception.GlusterfsException},
  940               {'side_effect': (('', ''),),
  941                '_exception': exception.GlusterfsException})
  942     @ddt.unpack
  943     def test_delete_snapshot_error(self, side_effect, _exception):
  944         self._layout.gluster_nosnap_vols_dict = {}
  945         gmgr = common.GlusterManager
  946         gmgr1 = gmgr(self.share1['export_location'], self._execute, None, None)
  947         self._layout.gluster_used_vols = set([self.glusterfs_target1])
  948         self.mock_object(self._layout, '_find_actual_backend_snapshot_name',
  949                          mock.Mock(return_value='fake_snap_id_xyz'))
  950         args = ('--xml', 'snapshot', 'delete', 'fake_snap_id_xyz',
  951                 '--mode=script')
  952         self.mock_object(
  953             gmgr1, 'gluster_call',
  954             mock.Mock(side_effect=side_effect))
  955         self.mock_object(self._layout, '_glustermanager',
  956                          mock.Mock(return_value=gmgr1))
  957 
  958         snapshot = {
  959             'id': 'fake_snap_id',
  960             'share_id': self.share1['id'],
  961             'share': self.share1
  962         }
  963         self.assertRaises(_exception, self._layout.delete_snapshot,
  964                           self._context, snapshot)
  965 
  966         gmgr1.gluster_call.assert_called_once_with(*args, log=mock.ANY)
  967         (self._layout._find_actual_backend_snapshot_name.
  968             assert_called_once_with(gmgr1, snapshot))
  969 
  970     @ddt.data(
  971         ('manage_existing', ('share', 'driver_options'), {}),
  972         ('unmanage', ('share',), {}),
  973         ('extend_share', ('share', 'new_size'), {'share_server': None}),
  974         ('shrink_share', ('share', 'new_size'), {'share_server': None}))
  975     def test_nonimplemented_methods(self, method_invocation):
  976         method, args, kwargs = method_invocation
  977         self.assertRaises(NotImplementedError, getattr(self._layout, method),
  978                           *args, **kwargs)