"Fossies" - the Fresh Open Source Software Archive

Member "cinder-14.0.2/cinder/tests/unit/volume/drivers/netapp/dataontap/test_nfs_cmode.py" (4 Oct 2019, 73756 Bytes) of package /linux/misc/openstack/cinder-14.0.2.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 last Fossies "Diffs" side-by-side code changes report for "test_nfs_cmode.py": 14.0.2_vs_15.0.0.

    1 # Copyright (c) 2014 Andrew Kerr.  All rights reserved.
    2 # Copyright (c) 2015 Tom Barron.  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 Mock unit tests for the NetApp cmode nfs storage driver
   17 """
   18 
   19 import hashlib
   20 import uuid
   21 
   22 import ddt
   23 import mock
   24 from os_brick.remotefs import remotefs as remotefs_brick
   25 from oslo_utils import units
   26 
   27 from cinder import exception
   28 from cinder.image import image_utils
   29 from cinder.objects import fields
   30 from cinder import test
   31 from cinder.tests.unit.volume.drivers.netapp.dataontap import fakes as fake
   32 from cinder.tests.unit.volume.drivers.netapp.dataontap.utils import fakes as \
   33     fake_ssc
   34 from cinder.tests.unit.volume.drivers.netapp import fakes as na_fakes
   35 from cinder import utils
   36 from cinder.volume.drivers.netapp.dataontap.client import api as netapp_api
   37 from cinder.volume.drivers.netapp.dataontap.client import client_cmode
   38 from cinder.volume.drivers.netapp.dataontap import nfs_base
   39 from cinder.volume.drivers.netapp.dataontap import nfs_cmode
   40 from cinder.volume.drivers.netapp.dataontap.performance import perf_cmode
   41 from cinder.volume.drivers.netapp.dataontap.utils import capabilities
   42 from cinder.volume.drivers.netapp.dataontap.utils import data_motion
   43 from cinder.volume.drivers.netapp.dataontap.utils import loopingcalls
   44 from cinder.volume.drivers.netapp.dataontap.utils import utils as dot_utils
   45 from cinder.volume.drivers.netapp import utils as na_utils
   46 from cinder.volume.drivers import nfs
   47 from cinder.volume import utils as volume_utils
   48 
   49 
   50 @ddt.ddt
   51 class NetAppCmodeNfsDriverTestCase(test.TestCase):
   52     def setUp(self):
   53         super(NetAppCmodeNfsDriverTestCase, self).setUp()
   54 
   55         kwargs = {
   56             'configuration': self.get_config_cmode(),
   57             'host': 'openstack@nfscmode',
   58         }
   59 
   60         with mock.patch.object(utils, 'get_root_helper',
   61                                return_value=mock.Mock()):
   62             with mock.patch.object(remotefs_brick, 'RemoteFsClient',
   63                                    return_value=mock.Mock()):
   64                 self.driver = nfs_cmode.NetAppCmodeNfsDriver(**kwargs)
   65                 self.driver._mounted_shares = [fake.NFS_SHARE]
   66                 self.driver.ssc_vols = True
   67                 self.driver.vserver = fake.VSERVER_NAME
   68                 self.driver.ssc_enabled = True
   69                 self.driver.perf_library = mock.Mock()
   70                 self.driver.ssc_library = mock.Mock()
   71                 self.driver.zapi_client = mock.Mock()
   72                 self.driver.using_cluster_credentials = True
   73 
   74     def get_config_cmode(self):
   75         config = na_fakes.create_configuration_cmode()
   76         config.netapp_storage_protocol = 'nfs'
   77         config.netapp_login = 'admin'
   78         config.netapp_password = 'pass'
   79         config.netapp_server_hostname = '127.0.0.1'
   80         config.netapp_transport_type = 'http'
   81         config.netapp_server_port = '80'
   82         config.netapp_vserver = fake.VSERVER_NAME
   83         config.netapp_copyoffload_tool_path = 'copyoffload_tool_path'
   84         config.netapp_api_trace_pattern = 'fake_regex'
   85         return config
   86 
   87     @ddt.data({'active_backend_id': None, 'targets': ['dev1', 'dev2']},
   88               {'active_backend_id': None, 'targets': []},
   89               {'active_backend_id': 'dev1', 'targets': []},
   90               {'active_backend_id': 'dev1', 'targets': ['dev1', 'dev2']})
   91     @ddt.unpack
   92     def test_init_driver_for_replication(self, active_backend_id,
   93                                          targets):
   94         kwargs = {
   95             'configuration': self.get_config_cmode(),
   96             'host': 'openstack@nfscmode',
   97             'active_backend_id': active_backend_id,
   98         }
   99         self.mock_object(data_motion.DataMotionMixin,
  100                          'get_replication_backend_names',
  101                          return_value=targets)
  102         with mock.patch.object(utils, 'get_root_helper',
  103                                return_value=mock.Mock()):
  104             with mock.patch.object(remotefs_brick, 'RemoteFsClient',
  105                                    return_value=mock.Mock()):
  106                 nfs_driver = nfs_cmode.NetAppCmodeNfsDriver(**kwargs)
  107 
  108                 self.assertEqual(active_backend_id,
  109                                  nfs_driver.failed_over_backend_name)
  110                 self.assertEqual(active_backend_id is not None,
  111                                  nfs_driver.failed_over)
  112                 self.assertEqual(len(targets) > 0,
  113                                  nfs_driver.replication_enabled)
  114 
  115     @mock.patch.object(perf_cmode, 'PerformanceCmodeLibrary', mock.Mock())
  116     @mock.patch.object(client_cmode, 'Client', mock.Mock())
  117     @mock.patch.object(capabilities.CapabilitiesLibrary,
  118                        'cluster_user_supported')
  119     @mock.patch.object(capabilities.CapabilitiesLibrary,
  120                        'check_api_permissions')
  121     @mock.patch.object(nfs.NfsDriver, 'do_setup')
  122     @mock.patch.object(na_utils, 'check_flags')
  123     def test_do_setup(self, mock_check_flags, mock_super_do_setup,
  124                       mock_check_api_permissions, mock_cluster_user_supported):
  125         self.mock_object(
  126             dot_utils, 'get_backend_configuration',
  127             return_value=self.get_config_cmode())
  128 
  129         self.driver.do_setup(mock.Mock())
  130 
  131         self.assertTrue(mock_check_flags.called)
  132         self.assertTrue(mock_super_do_setup.called)
  133         mock_check_api_permissions.assert_called_once_with()
  134         mock_cluster_user_supported.assert_called_once_with()
  135 
  136     def test__update_volume_stats(self):
  137         mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
  138         self.mock_object(self.driver, 'get_filter_function')
  139         self.mock_object(self.driver, 'get_goodness_function')
  140         self.mock_object(self.driver, '_spawn_clean_cache_job')
  141         self.driver.zapi_client = mock.Mock()
  142         self.mock_object(self.driver, '_get_pool_stats', return_value={})
  143         expected_stats = {
  144             'driver_version': self.driver.VERSION,
  145             'pools': {},
  146             'sparse_copy_volume': True,
  147             'replication_enabled': False,
  148             'storage_protocol': 'nfs',
  149             'vendor_name': 'NetApp',
  150             'volume_backend_name': 'NetApp_NFS_Cluster_direct',
  151         }
  152 
  153         retval = self.driver._update_volume_stats()
  154 
  155         self.assertIsNone(retval)
  156         self.assertTrue(self.driver._spawn_clean_cache_job.called)
  157         self.assertEqual(1, mock_debug_log.call_count)
  158         self.assertEqual(expected_stats, self.driver._stats)
  159 
  160     @ddt.data({'replication_backends': [], 'cluster_credentials': False},
  161               {'replication_backends': ['target_1', 'target_2'],
  162                'cluster_credentials': True})
  163     @ddt.unpack
  164     def test_get_pool_stats(self, replication_backends, cluster_credentials):
  165         self.driver.using_cluster_credentials = cluster_credentials
  166         self.driver.zapi_client = mock.Mock()
  167         ssc = {
  168             'vola': {
  169                 'pool_name': '10.10.10.10:/vola',
  170                 'thick_provisioning_support': True,
  171                 'thin_provisioning_support': False,
  172                 'netapp_thin_provisioned': 'false',
  173                 'netapp_compression': 'false',
  174                 'netapp_mirrored': 'false',
  175                 'netapp_dedup': 'true',
  176                 'netapp_aggregate': 'aggr1',
  177                 'netapp_raid_type': 'raid_dp',
  178                 'netapp_disk_type': 'SSD',
  179                 'consistent_group_snapshot_enabled': True,
  180             },
  181         }
  182         mock_get_ssc = self.mock_object(self.driver.ssc_library,
  183                                         'get_ssc',
  184                                         return_value=ssc)
  185         mock_get_aggrs = self.mock_object(self.driver.ssc_library,
  186                                           'get_ssc_aggregates',
  187                                           return_value=['aggr1'])
  188 
  189         self.mock_object(self.driver, 'get_replication_backend_names',
  190                          return_value=replication_backends)
  191 
  192         total_capacity_gb = na_utils.round_down(
  193             fake.TOTAL_BYTES // units.Gi, '0.01')
  194         free_capacity_gb = na_utils.round_down(
  195             fake.AVAILABLE_BYTES // units.Gi, '0.01')
  196         capacity = {
  197             'reserved_percentage': fake.RESERVED_PERCENTAGE,
  198             'max_over_subscription_ratio': fake.MAX_OVER_SUBSCRIPTION_RATIO,
  199             'total_capacity_gb': total_capacity_gb,
  200             'free_capacity_gb': free_capacity_gb,
  201         }
  202         self.mock_object(self.driver,
  203                          '_get_share_capacity_info',
  204                          return_value=capacity)
  205         self.mock_object(self.driver.zapi_client,
  206                          'get_flexvol_dedupe_used_percent',
  207                          return_value=55.0)
  208 
  209         aggr_capacities = {
  210             'aggr1': {
  211                 'percent-used': 45,
  212                 'size-available': 59055800320.0,
  213                 'size-total': 107374182400.0,
  214             },
  215         }
  216         mock_get_aggr_capacities = self.mock_object(
  217             self.driver.zapi_client, 'get_aggregate_capacities',
  218             return_value=aggr_capacities)
  219 
  220         self.driver.perf_library.get_node_utilization_for_pool = (
  221             mock.Mock(return_value=30.0))
  222 
  223         result = self.driver._get_pool_stats(filter_function='filter',
  224                                              goodness_function='goodness')
  225 
  226         expected = [{
  227             'pool_name': '10.10.10.10:/vola',
  228             'reserved_percentage': fake.RESERVED_PERCENTAGE,
  229             'max_over_subscription_ratio': fake.MAX_OVER_SUBSCRIPTION_RATIO,
  230             'multiattach': True,
  231             'total_capacity_gb': total_capacity_gb,
  232             'free_capacity_gb': free_capacity_gb,
  233             'netapp_dedupe_used_percent': 55.0,
  234             'netapp_aggregate_used_percent': 45,
  235             'utilization': 30.0,
  236             'filter_function': 'filter',
  237             'goodness_function': 'goodness',
  238             'thick_provisioning_support': True,
  239             'thin_provisioning_support': False,
  240             'netapp_thin_provisioned': 'false',
  241             'netapp_compression': 'false',
  242             'netapp_mirrored': 'false',
  243             'netapp_dedup': 'true',
  244             'netapp_aggregate': 'aggr1',
  245             'netapp_raid_type': 'raid_dp',
  246             'netapp_disk_type': 'SSD',
  247             'consistencygroup_support': True,
  248             'consistent_group_snapshot_enabled': True,
  249             'replication_enabled': False,
  250             'online_extend_support': False,
  251         }]
  252 
  253         expected[0].update({'QoS_support': cluster_credentials})
  254         if not cluster_credentials:
  255             expected[0].update({
  256                 'netapp_aggregate_used_percent': 0,
  257                 'netapp_dedupe_used_percent': 0
  258             })
  259 
  260         if replication_backends:
  261             expected[0].update({
  262                 'replication_enabled': True,
  263                 'replication_count': len(replication_backends),
  264                 'replication_targets': replication_backends,
  265                 'replication_type': 'async',
  266             })
  267 
  268         self.assertEqual(expected, result)
  269         mock_get_ssc.assert_called_once_with()
  270         if cluster_credentials:
  271             mock_get_aggrs.assert_called_once_with()
  272             mock_get_aggr_capacities.assert_called_once_with(['aggr1'])
  273 
  274     @ddt.data({}, None)
  275     def test_get_pool_stats_no_ssc_vols(self, ssc):
  276 
  277         mock_get_ssc = self.mock_object(self.driver.ssc_library,
  278                                         'get_ssc',
  279                                         return_value=ssc)
  280 
  281         pools = self.driver._get_pool_stats()
  282 
  283         self.assertListEqual([], pools)
  284         mock_get_ssc.assert_called_once_with()
  285 
  286     def test_update_ssc(self):
  287 
  288         mock_ensure_shares_mounted = self.mock_object(
  289             self.driver, '_ensure_shares_mounted')
  290         mock_get_pool_map = self.mock_object(
  291             self.driver, '_get_flexvol_to_pool_map',
  292             return_value='fake_map')
  293         mock_update_ssc = self.mock_object(
  294             self.driver.ssc_library, 'update_ssc')
  295 
  296         result = self.driver._update_ssc()
  297 
  298         self.assertIsNone(result)
  299         mock_ensure_shares_mounted.assert_called_once_with()
  300         mock_get_pool_map.assert_called_once_with()
  301         mock_update_ssc.assert_called_once_with('fake_map')
  302 
  303     def test_get_pool_map(self):
  304 
  305         self.driver.zapi_client = mock.Mock()
  306         mock_get_operational_lif_addresses = self.mock_object(
  307             self.driver.zapi_client, 'get_operational_lif_addresses',
  308             return_value=[fake.SHARE_IP])
  309         mock_resolve_hostname = self.mock_object(
  310             utils, 'resolve_hostname', return_value=fake.SHARE_IP)
  311         mock_get_flexvol = self.mock_object(
  312             self.driver.zapi_client, 'get_flexvol',
  313             return_value={'name': fake.NETAPP_VOLUME})
  314 
  315         result = self.driver._get_flexvol_to_pool_map()
  316 
  317         expected = {
  318             fake.NETAPP_VOLUME: {
  319                 'pool_name': fake.NFS_SHARE,
  320             },
  321         }
  322         self.assertEqual(expected, result)
  323         mock_get_operational_lif_addresses.assert_called_once_with()
  324         mock_resolve_hostname.assert_called_once_with(fake.SHARE_IP)
  325         mock_get_flexvol.assert_called_once_with(flexvol_path=fake.EXPORT_PATH)
  326 
  327     def test_get_pool_map_address_not_found(self):
  328 
  329         self.driver.zapi_client = mock.Mock()
  330         self.mock_object(self.driver.zapi_client,
  331                          'get_operational_lif_addresses',
  332                          return_value=[])
  333         self.mock_object(utils,
  334                          'resolve_hostname',
  335                          return_value=fake.SHARE_IP)
  336 
  337         result = self.driver._get_flexvol_to_pool_map()
  338 
  339         self.assertEqual({}, result)
  340 
  341     def test_get_pool_map_flexvol_not_found(self):
  342 
  343         self.driver.zapi_client = mock.Mock()
  344         self.mock_object(self.driver.zapi_client,
  345                          'get_operational_lif_addresses',
  346                          return_value=[fake.SHARE_IP])
  347         self.mock_object(utils,
  348                          'resolve_hostname',
  349                          return_value=fake.SHARE_IP)
  350         side_effect = exception.VolumeBackendAPIException(data='fake_data')
  351         self.mock_object(self.driver.zapi_client,
  352                          'get_flexvol',
  353                          side_effect=side_effect)
  354 
  355         result = self.driver._get_flexvol_to_pool_map()
  356 
  357         self.assertEqual({}, result)
  358 
  359     @ddt.data(['/mnt/img-id1', '/mnt/img-id2'], [])
  360     def test__shortlist_del_eligible_files(self, old_files):
  361         self.driver.zapi_client = mock.Mock()
  362         self.driver.zapi_client.get_file_usage = mock.Mock(return_value='1000')
  363         mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
  364         self.mock_object(self.driver, '_get_vserver_and_exp_vol',
  365                          return_value=('openstack', 'fake_share'))
  366         expected_list = [(o, '1000') for o in old_files]
  367 
  368         observed_list = self.driver._shortlist_del_eligible_files(
  369             'fake_ip:fake_share', old_files)
  370 
  371         self.assertEqual(expected_list, observed_list)
  372         self.assertEqual(1, mock_debug_log.call_count)
  373 
  374     @ddt.data({'ip': None, 'shares': None},
  375               {'ip': 'fake_ip', 'shares': ['fip:/fsh1']})
  376     @ddt.unpack
  377     def test__share_match_for_ip_no_match(self, ip, shares):
  378         def side_effect(arg):
  379             if arg == 'fake_ip':
  380                 return 'openstack'
  381             return None
  382 
  383         self.mock_object(self.driver, '_get_vserver_for_ip',
  384                          side_effect=side_effect)
  385         mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
  386 
  387         retval = self.driver._share_match_for_ip(ip, shares)
  388 
  389         self.assertIsNone(retval)
  390         self.assertEqual(1, mock_debug_log.call_count)
  391 
  392     def test__share_match_for_ip(self):
  393         shares = ['fip:/fsh1']
  394         self.mock_object(self.driver, '_get_vserver_for_ip',
  395                          return_value='openstack')
  396         mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
  397 
  398         retval = self.driver._share_match_for_ip('fip', shares)
  399 
  400         self.assertEqual('fip:/fsh1', retval)
  401         self.assertEqual(1, mock_debug_log.call_count)
  402 
  403     def test__get_vserver_for_ip_ignores_zapi_exception(self):
  404         self.driver.zapi_client = mock.Mock()
  405         self.driver.zapi_client.get_if_info_by_ip = mock.Mock(
  406             side_effect=exception.NotFound)
  407 
  408         vserver = self.driver._get_vserver_for_ip('FAKE_IP')
  409 
  410         self.assertIsNone(vserver)
  411 
  412     def test__get_vserver_for_ip(self):
  413         self.driver.zapi_client = mock.Mock()
  414         self.driver.zapi_client.get_if_info_by_ip = mock.Mock(
  415             return_value=fake.get_fake_ifs())
  416 
  417         vserver = self.driver._get_vserver_for_ip('FAKE_IP')
  418 
  419         self.assertIsNone(vserver)
  420 
  421     def test_check_for_setup_error(self):
  422         super_check_for_setup_error = self.mock_object(
  423             nfs_base.NetAppNfsDriver, 'check_for_setup_error')
  424         mock_add_looping_tasks = self.mock_object(
  425             self.driver, '_add_looping_tasks')
  426 
  427         self.driver.check_for_setup_error()
  428 
  429         self.assertEqual(1, super_check_for_setup_error.call_count)
  430         self.assertEqual(1, mock_add_looping_tasks.call_count)
  431         mock_add_looping_tasks.assert_called_once_with()
  432 
  433     @ddt.data({'replication_enabled': True, 'failed_over': False,
  434                'cluster_credentials': True},
  435               {'replication_enabled': True, 'failed_over': True,
  436                'cluster_credentials': True},
  437               {'replication_enabled': False, 'failed_over': False,
  438                'cluster_credentials': False})
  439     @ddt.unpack
  440     def test_handle_housekeeping_tasks(
  441             self, replication_enabled, failed_over, cluster_credentials):
  442         self.driver.using_cluster_credentials = cluster_credentials
  443         ensure_mirrors = self.mock_object(data_motion.DataMotionMixin,
  444                                           'ensure_snapmirrors')
  445         self.mock_object(self.driver.ssc_library, 'get_ssc_flexvol_names',
  446                          return_value=fake_ssc.SSC.keys())
  447         mock_remove_unused_qos_policy_groups = self.mock_object(
  448             self.driver.zapi_client, 'remove_unused_qos_policy_groups')
  449         self.driver.replication_enabled = replication_enabled
  450         self.driver.failed_over = failed_over
  451 
  452         self.driver._handle_housekeeping_tasks()
  453 
  454         if self.driver.using_cluster_credentials:
  455             mock_remove_unused_qos_policy_groups.assert_called_once_with()
  456         else:
  457             mock_remove_unused_qos_policy_groups.assert_not_called()
  458 
  459         if replication_enabled and not failed_over:
  460             ensure_mirrors.assert_called_once_with(
  461                 self.driver.configuration, self.driver.backend_name,
  462                 fake_ssc.SSC.keys())
  463         else:
  464             self.assertFalse(ensure_mirrors.called)
  465 
  466     def test_handle_ems_logging(self):
  467 
  468         volume_list = ['vol0', 'vol1', 'vol2']
  469         self.mock_object(
  470             self.driver, '_get_backing_flexvol_names',
  471             return_value=volume_list)
  472         self.mock_object(
  473             dot_utils, 'build_ems_log_message_0',
  474             return_value='fake_base_ems_log_message')
  475         self.mock_object(
  476             dot_utils, 'build_ems_log_message_1',
  477             return_value='fake_pool_ems_log_message')
  478         mock_send_ems_log_message = self.mock_object(
  479             self.driver.zapi_client, 'send_ems_log_message')
  480 
  481         self.driver._handle_ems_logging()
  482 
  483         mock_send_ems_log_message.assert_has_calls([
  484             mock.call('fake_base_ems_log_message'),
  485             mock.call('fake_pool_ems_log_message'),
  486         ])
  487         dot_utils.build_ems_log_message_0.assert_called_once_with(
  488             self.driver.driver_name, self.driver.app_version)
  489         dot_utils.build_ems_log_message_1.assert_called_once_with(
  490             self.driver.driver_name, self.driver.app_version,
  491             self.driver.vserver, volume_list, [])
  492 
  493     def test_delete_volume(self):
  494         fake_provider_location = 'fake_provider_location'
  495         fake_volume = {'provider_location': fake_provider_location}
  496         self.mock_object(self.driver, '_delete_backing_file_for_volume')
  497         self.mock_object(na_utils,
  498                          'get_valid_qos_policy_group_info',
  499                          return_value='fake_qos_policy_group_info')
  500 
  501         self.driver.delete_volume(fake_volume)
  502 
  503         self.driver._delete_backing_file_for_volume.assert_called_once_with(
  504             fake_volume)
  505         na_utils.get_valid_qos_policy_group_info.assert_called_once_with(
  506             fake_volume)
  507         (self.driver.zapi_client.mark_qos_policy_group_for_deletion.
  508          assert_called_once_with('fake_qos_policy_group_info'))
  509 
  510     def test_delete_volume_exception_path(self):
  511         fake_provider_location = 'fake_provider_location'
  512         fake_volume = {'provider_location': fake_provider_location}
  513         self.mock_object(self.driver, '_delete_backing_file_for_volume')
  514         self.mock_object(na_utils,
  515                          'get_valid_qos_policy_group_info',
  516                          return_value='fake_qos_policy_group_info')
  517         self.mock_object(
  518             self.driver.zapi_client,
  519             'mark_qos_policy_group_for_deletion',
  520             side_effect=exception.NetAppDriverException)
  521 
  522         self.driver.delete_volume(fake_volume)
  523 
  524         self.driver._delete_backing_file_for_volume.assert_called_once_with(
  525             fake_volume)
  526         na_utils.get_valid_qos_policy_group_info.assert_called_once_with(
  527             fake_volume)
  528         (self.driver.zapi_client.mark_qos_policy_group_for_deletion.
  529          assert_called_once_with('fake_qos_policy_group_info'))
  530 
  531     def test_delete_backing_file_for_volume(self):
  532         mock_filer_delete = self.mock_object(self.driver, '_delete_file')
  533         mock_super_delete = self.mock_object(nfs_base.NetAppNfsDriver,
  534                                              'delete_volume')
  535 
  536         self.driver._delete_backing_file_for_volume(fake.NFS_VOLUME)
  537 
  538         mock_filer_delete.assert_called_once_with(
  539             fake.NFS_VOLUME['id'], fake.NFS_VOLUME['name'])
  540         self.assertEqual(0, mock_super_delete.call_count)
  541 
  542     @ddt.data(True, False)
  543     def test_delete_backing_file_for_volume_exception_path(self, super_exc):
  544         mock_exception_log = self.mock_object(nfs_cmode.LOG, 'exception')
  545         exception_call_count = 2 if super_exc else 1
  546         mock_filer_delete = self.mock_object(self.driver, '_delete_file')
  547         mock_filer_delete.side_effect = [Exception]
  548         mock_super_delete = self.mock_object(nfs_base.NetAppNfsDriver,
  549                                              'delete_volume')
  550         if super_exc:
  551             mock_super_delete.side_effect = [Exception]
  552 
  553         self.driver._delete_backing_file_for_volume(fake.NFS_VOLUME)
  554 
  555         mock_filer_delete.assert_called_once_with(
  556             fake.NFS_VOLUME['id'], fake.NFS_VOLUME['name'])
  557         mock_super_delete.assert_called_once_with(fake.NFS_VOLUME)
  558         self.assertEqual(exception_call_count, mock_exception_log.call_count)
  559 
  560     def test_delete_snapshot(self):
  561         mock_get_location = self.mock_object(self.driver,
  562                                              '_get_provider_location')
  563         mock_get_location.return_value = fake.PROVIDER_LOCATION
  564         mock_delete_backing = self.mock_object(
  565             self.driver, '_delete_backing_file_for_snapshot')
  566 
  567         self.driver.delete_snapshot(fake.test_snapshot)
  568 
  569         mock_delete_backing.assert_called_once_with(fake.test_snapshot)
  570 
  571     def test_delete_backing_file_for_snapshot(self):
  572         mock_filer_delete = self.mock_object(self.driver, '_delete_file')
  573         mock_super_delete = self.mock_object(nfs_base.NetAppNfsDriver,
  574                                              'delete_snapshot')
  575 
  576         self.driver._delete_backing_file_for_snapshot(fake.test_snapshot)
  577 
  578         mock_filer_delete.assert_called_once_with(
  579             fake.test_snapshot['volume_id'], fake.test_snapshot['name'])
  580         self.assertEqual(0, mock_super_delete.call_count)
  581 
  582     @ddt.data(True, False)
  583     def test_delete_backing_file_for_snapshot_exception_path(self, super_exc):
  584         mock_exception_log = self.mock_object(nfs_cmode.LOG, 'exception')
  585         exception_call_count = 2 if super_exc else 1
  586         mock_filer_delete = self.mock_object(self.driver, '_delete_file')
  587         mock_filer_delete.side_effect = [Exception]
  588         mock_super_delete = self.mock_object(nfs_base.NetAppNfsDriver,
  589                                              'delete_snapshot')
  590         if super_exc:
  591             mock_super_delete.side_effect = [Exception]
  592 
  593         self.driver._delete_backing_file_for_snapshot(fake.test_snapshot)
  594 
  595         mock_filer_delete.assert_called_once_with(
  596             fake.test_snapshot['volume_id'], fake.test_snapshot['name'])
  597         mock_super_delete.assert_called_once_with(fake.test_snapshot)
  598         self.assertEqual(exception_call_count, mock_exception_log.call_count)
  599 
  600     def test_delete_file(self):
  601         mock_get_vs_ip = self.mock_object(self.driver, '_get_export_ip_path')
  602         mock_get_vs_ip.return_value = (fake.SHARE_IP, fake.EXPORT_PATH)
  603         mock_get_vserver = self.mock_object(self.driver, '_get_vserver_for_ip')
  604         mock_get_vserver.return_value = fake.VSERVER_NAME
  605         mock_zapi_get_vol = self.driver.zapi_client.get_vol_by_junc_vserver
  606         mock_zapi_get_vol.return_value = fake.FLEXVOL
  607         mock_zapi_delete = self.driver.zapi_client.delete_file
  608 
  609         self.driver._delete_file(
  610             fake.test_snapshot['volume_id'], fake.test_snapshot['name'])
  611 
  612         mock_get_vs_ip.assert_called_once_with(
  613             volume_id=fake.test_snapshot['volume_id'])
  614         mock_get_vserver.assert_called_once_with(fake.SHARE_IP)
  615         mock_zapi_get_vol.assert_called_once_with(
  616             fake.VSERVER_NAME, fake.EXPORT_PATH)
  617         mock_zapi_delete.assert_called_once_with(
  618             '/vol/%s/%s' % (fake.FLEXVOL, fake.test_snapshot['name']))
  619 
  620     def test_do_qos_for_volume_no_exception(self):
  621 
  622         mock_get_info = self.mock_object(na_utils,
  623                                          'get_valid_qos_policy_group_info')
  624         mock_get_info.return_value = fake.QOS_POLICY_GROUP_INFO
  625         mock_provision_qos = self.driver.zapi_client.provision_qos_policy_group
  626         mock_set_policy = self.mock_object(self.driver,
  627                                            '_set_qos_policy_group_on_volume')
  628         mock_error_log = self.mock_object(nfs_cmode.LOG, 'error')
  629         mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
  630         mock_cleanup = self.mock_object(self.driver,
  631                                         '_cleanup_volume_on_failure')
  632 
  633         self.driver._do_qos_for_volume(fake.NFS_VOLUME, fake.EXTRA_SPECS)
  634 
  635         mock_get_info.assert_has_calls([
  636             mock.call(fake.NFS_VOLUME, fake.EXTRA_SPECS)])
  637         mock_provision_qos.assert_has_calls([
  638             mock.call(fake.QOS_POLICY_GROUP_INFO)])
  639         mock_set_policy.assert_has_calls([
  640             mock.call(fake.NFS_VOLUME, fake.QOS_POLICY_GROUP_INFO)])
  641         self.assertEqual(0, mock_error_log.call_count)
  642         self.assertEqual(0, mock_debug_log.call_count)
  643         self.assertEqual(0, mock_cleanup.call_count)
  644 
  645     def test_do_qos_for_volume_exception_w_cleanup(self):
  646         mock_get_info = self.mock_object(na_utils,
  647                                          'get_valid_qos_policy_group_info')
  648         mock_get_info.return_value = fake.QOS_POLICY_GROUP_INFO
  649         mock_provision_qos = self.driver.zapi_client.provision_qos_policy_group
  650         mock_set_policy = self.mock_object(self.driver,
  651                                            '_set_qos_policy_group_on_volume')
  652         mock_set_policy.side_effect = netapp_api.NaApiError
  653         mock_error_log = self.mock_object(nfs_cmode.LOG, 'error')
  654         mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
  655         mock_cleanup = self.mock_object(self.driver,
  656                                         '_cleanup_volume_on_failure')
  657 
  658         self.assertRaises(netapp_api.NaApiError,
  659                           self.driver._do_qos_for_volume,
  660                           fake.NFS_VOLUME,
  661                           fake.EXTRA_SPECS)
  662 
  663         mock_get_info.assert_has_calls([
  664             mock.call(fake.NFS_VOLUME, fake.EXTRA_SPECS)])
  665         mock_provision_qos.assert_has_calls([
  666             mock.call(fake.QOS_POLICY_GROUP_INFO)])
  667         mock_set_policy.assert_has_calls([
  668             mock.call(fake.NFS_VOLUME, fake.QOS_POLICY_GROUP_INFO)])
  669         self.assertEqual(1, mock_error_log.call_count)
  670         self.assertEqual(1, mock_debug_log.call_count)
  671         mock_cleanup.assert_has_calls([
  672             mock.call(fake.NFS_VOLUME)])
  673 
  674     def test_do_qos_for_volume_exception_no_cleanup(self):
  675 
  676         mock_get_info = self.mock_object(na_utils,
  677                                          'get_valid_qos_policy_group_info')
  678         mock_get_info.side_effect = exception.Invalid
  679         mock_provision_qos = self.driver.zapi_client.provision_qos_policy_group
  680         mock_set_policy = self.mock_object(self.driver,
  681                                            '_set_qos_policy_group_on_volume')
  682         mock_error_log = self.mock_object(nfs_cmode.LOG, 'error')
  683         mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
  684         mock_cleanup = self.mock_object(self.driver,
  685                                         '_cleanup_volume_on_failure')
  686 
  687         self.assertRaises(exception.Invalid, self.driver._do_qos_for_volume,
  688                           fake.NFS_VOLUME, fake.EXTRA_SPECS, cleanup=False)
  689 
  690         mock_get_info.assert_has_calls([
  691             mock.call(fake.NFS_VOLUME, fake.EXTRA_SPECS)])
  692         self.assertEqual(0, mock_provision_qos.call_count)
  693         self.assertEqual(0, mock_set_policy.call_count)
  694         self.assertEqual(1, mock_error_log.call_count)
  695         self.assertEqual(0, mock_debug_log.call_count)
  696         self.assertEqual(0, mock_cleanup.call_count)
  697 
  698     def test_set_qos_policy_group_on_volume(self):
  699 
  700         mock_get_name_from_info = self.mock_object(
  701             na_utils, 'get_qos_policy_group_name_from_info')
  702         mock_get_name_from_info.return_value = fake.QOS_POLICY_GROUP_NAME
  703 
  704         mock_extract_host = self.mock_object(volume_utils, 'extract_host')
  705         mock_extract_host.return_value = fake.NFS_SHARE
  706 
  707         mock_get_flex_vol_name =\
  708             self.driver.zapi_client.get_vol_by_junc_vserver
  709         mock_get_flex_vol_name.return_value = fake.FLEXVOL
  710 
  711         mock_file_assign_qos = self.driver.zapi_client.file_assign_qos
  712 
  713         self.driver._set_qos_policy_group_on_volume(fake.NFS_VOLUME,
  714                                                     fake.QOS_POLICY_GROUP_INFO)
  715 
  716         mock_get_name_from_info.assert_has_calls([
  717             mock.call(fake.QOS_POLICY_GROUP_INFO)])
  718         mock_extract_host.assert_has_calls([
  719             mock.call(fake.NFS_HOST_STRING, level='pool')])
  720         mock_get_flex_vol_name.assert_has_calls([
  721             mock.call(fake.VSERVER_NAME, fake.EXPORT_PATH)])
  722         mock_file_assign_qos.assert_has_calls([
  723             mock.call(fake.FLEXVOL, fake.QOS_POLICY_GROUP_NAME,
  724                       fake.NFS_VOLUME['name'])])
  725 
  726     def test_set_qos_policy_group_on_volume_no_info(self):
  727 
  728         mock_get_name_from_info = self.mock_object(
  729             na_utils, 'get_qos_policy_group_name_from_info')
  730 
  731         mock_extract_host = self.mock_object(volume_utils, 'extract_host')
  732 
  733         mock_get_flex_vol_name =\
  734             self.driver.zapi_client.get_vol_by_junc_vserver
  735 
  736         mock_file_assign_qos = self.driver.zapi_client.file_assign_qos
  737 
  738         self.driver._set_qos_policy_group_on_volume(fake.NFS_VOLUME,
  739                                                     None)
  740 
  741         self.assertEqual(0, mock_get_name_from_info.call_count)
  742         self.assertEqual(0, mock_extract_host.call_count)
  743         self.assertEqual(0, mock_get_flex_vol_name.call_count)
  744         self.assertEqual(0, mock_file_assign_qos.call_count)
  745 
  746     def test_set_qos_policy_group_on_volume_no_name(self):
  747 
  748         mock_get_name_from_info = self.mock_object(
  749             na_utils, 'get_qos_policy_group_name_from_info')
  750         mock_get_name_from_info.return_value = None
  751 
  752         mock_extract_host = self.mock_object(volume_utils, 'extract_host')
  753 
  754         mock_get_flex_vol_name =\
  755             self.driver.zapi_client.get_vol_by_junc_vserver
  756 
  757         mock_file_assign_qos = self.driver.zapi_client.file_assign_qos
  758 
  759         self.driver._set_qos_policy_group_on_volume(fake.NFS_VOLUME,
  760                                                     fake.QOS_POLICY_GROUP_INFO)
  761 
  762         mock_get_name_from_info.assert_has_calls([
  763             mock.call(fake.QOS_POLICY_GROUP_INFO)])
  764         self.assertEqual(0, mock_extract_host.call_count)
  765         self.assertEqual(0, mock_get_flex_vol_name.call_count)
  766         self.assertEqual(0, mock_file_assign_qos.call_count)
  767 
  768     @ddt.data({'share': None, 'is_snapshot': False},
  769               {'share': None, 'is_snapshot': True},
  770               {'share': 'fake_share', 'is_snapshot': False},
  771               {'share': 'fake_share', 'is_snapshot': True})
  772     @ddt.unpack
  773     def test_clone_backing_file_for_volume(self, share, is_snapshot):
  774 
  775         mock_get_vserver_and_exp_vol = self.mock_object(
  776             self.driver, '_get_vserver_and_exp_vol',
  777             return_value=(fake.VSERVER_NAME, fake.FLEXVOL))
  778 
  779         self.driver._clone_backing_file_for_volume(
  780             fake.FLEXVOL, 'fake_clone', fake.VOLUME_ID, share=share,
  781             is_snapshot=is_snapshot)
  782 
  783         mock_get_vserver_and_exp_vol.assert_called_once_with(
  784             fake.VOLUME_ID, share)
  785         self.driver.zapi_client.clone_file.assert_called_once_with(
  786             fake.FLEXVOL, fake.FLEXVOL, 'fake_clone', fake.VSERVER_NAME,
  787             is_snapshot=is_snapshot)
  788 
  789     def test__clone_backing_file_for_volume(self):
  790         body = fake.get_fake_net_interface_get_iter_response()
  791         self.driver.zapi_client.get_if_info_by_ip = mock.Mock(
  792             return_value=[netapp_api.NaElement(body)])
  793         self.driver.zapi_client.get_vol_by_junc_vserver = mock.Mock(
  794             return_value='nfsvol')
  795         self.mock_object(self.driver, '_get_export_ip_path',
  796                          return_value=('127.0.0.1', 'fakepath'))
  797 
  798         retval = self.driver._clone_backing_file_for_volume(
  799             'vol', 'clone', 'vol_id', share='share', is_snapshot=True)
  800 
  801         self.assertIsNone(retval)
  802         self.driver.zapi_client.clone_file.assert_called_once_with(
  803             'nfsvol', 'vol', 'clone', None, is_snapshot=True)
  804 
  805     def test_copy_from_img_service_copyoffload_nonexistent_binary_path(self):
  806         self.mock_object(nfs_cmode.LOG, 'debug')
  807         drv = self.driver
  808         context = object()
  809         volume = {'id': 'vol_id', 'name': 'name',
  810                   'host': 'openstack@nfscmode#192.128.1.1:/mnt_point'}
  811         image_service = mock.Mock()
  812         image_service.get_location.return_value = (mock.Mock(), mock.Mock())
  813         image_service.show.return_value = {'size': 0}
  814         image_id = 'image_id'
  815         drv._client = mock.Mock()
  816         drv._client.get_api_version = mock.Mock(return_value=(1, 20))
  817         nfs_base.NetAppNfsDriver._find_image_in_cache = mock.Mock(
  818             return_value=[])
  819         drv._construct_image_nfs_url = mock.Mock(return_value=["nfs://1"])
  820         drv._check_get_nfs_path_segs = mock.Mock(
  821             return_value=("test:test", "dr"))
  822         drv._get_ip_verify_on_cluster = mock.Mock(return_value="192.128.1.1")
  823         drv._get_mount_point_for_share = mock.Mock(return_value='mnt_point')
  824         drv._check_share_can_hold_size = mock.Mock()
  825         # Raise error as if the copyoffload file can not be found
  826         drv._clone_file_dst_exists = mock.Mock(side_effect=OSError())
  827         drv._discover_file_till_timeout = mock.Mock()
  828 
  829         # Verify the original error is propagated
  830         self.assertRaises(OSError, drv._copy_from_img_service,
  831                           context, volume, image_service, image_id)
  832 
  833         drv._discover_file_till_timeout.assert_not_called()
  834 
  835     @mock.patch.object(image_utils, 'qemu_img_info')
  836     def test_copy_from_img_service_raw_copyoffload_workflow_success(
  837             self, mock_qemu_img_info):
  838         drv = self.driver
  839         volume = {'id': 'vol_id', 'name': 'name', 'size': 1,
  840                   'host': 'openstack@nfscmode#ip1:/mnt_point'}
  841         image_id = 'image_id'
  842         context = object()
  843         image_service = mock.Mock()
  844         image_service.get_location.return_value = ('nfs://ip1/openstack/img',
  845                                                    None)
  846         image_service.show.return_value = {'size': 1, 'disk_format': 'raw'}
  847 
  848         drv._check_get_nfs_path_segs =\
  849             mock.Mock(return_value=('ip1', '/openstack'))
  850         drv._get_ip_verify_on_cluster = mock.Mock(return_value='ip1')
  851         drv._get_host_ip = mock.Mock(return_value='ip2')
  852         drv._get_export_path = mock.Mock(return_value='/exp_path')
  853         drv._get_provider_location = mock.Mock(return_value='share')
  854         drv._execute = mock.Mock()
  855         drv._get_mount_point_for_share = mock.Mock(return_value='mnt_point')
  856         drv._discover_file_till_timeout = mock.Mock(return_value=True)
  857         img_inf = mock.Mock()
  858         img_inf.file_format = 'raw'
  859         mock_qemu_img_info.return_value = img_inf
  860         drv._check_share_can_hold_size = mock.Mock()
  861         drv._move_nfs_file = mock.Mock(return_value=True)
  862         drv._delete_file_at_path = mock.Mock()
  863         drv._clone_file_dst_exists = mock.Mock()
  864         drv._post_clone_image = mock.Mock()
  865 
  866         retval = drv._copy_from_img_service(
  867             context, volume, image_service, image_id)
  868 
  869         self.assertTrue(retval)
  870         drv._get_ip_verify_on_cluster.assert_any_call('ip1')
  871         drv._check_share_can_hold_size.assert_called_with(
  872             'ip1:/mnt_point', 1)
  873         self.assertEqual(1, drv._execute.call_count)
  874 
  875     @mock.patch.object(image_utils, 'convert_image')
  876     @mock.patch.object(image_utils, 'qemu_img_info')
  877     @mock.patch('os.path.exists')
  878     @mock.patch('cinder.privsep.path')
  879     def test_copy_from_img_service_qcow2_copyoffload_workflow_success(
  880             self, mock_touch, mock_exists, mock_qemu_img_info,
  881             mock_cvrt_image):
  882         drv = self.driver
  883         cinder_mount_point_base = '/opt/stack/data/cinder/mnt/'
  884         # To get the cinder mount point directory, we use:
  885         mount_dir = hashlib.md5(
  886             '203.0.113.122:/cinder-flexvol1'.encode('utf-8')).hexdigest()
  887         cinder_mount_point = cinder_mount_point_base + mount_dir
  888         destination_copied_file = (
  889             '/cinder-flexvol1/a155308c-0290-497b-b278-4cdd01de0253'
  890         )
  891         volume = {'id': 'vol_id', 'name': 'name', 'size': 1,
  892                   'host': 'openstack@nfscmode#203.0.113.122:/cinder-flexvol1'}
  893         image_id = 'image_id'
  894         context = object()
  895         image_service = mock.Mock()
  896         image_service.get_location.return_value = (
  897             'nfs://203.0.113.122/glance-flexvol1', None)
  898         image_service.show.return_value = {'size': 1,
  899                                            'disk_format': 'qcow2'}
  900         drv._check_get_nfs_path_segs = (
  901             mock.Mock(return_value=('203.0.113.122', '/openstack'))
  902         )
  903 
  904         drv._get_ip_verify_on_cluster = mock.Mock(return_value='203.0.113.122')
  905         drv._execute = mock.Mock()
  906         drv._execute_as_root = False
  907         drv._get_mount_point_for_share = mock.Mock(
  908             return_value=cinder_mount_point)
  909         img_inf = mock.Mock()
  910         img_inf.file_format = 'raw'
  911         mock_qemu_img_info.return_value = img_inf
  912         drv._check_share_can_hold_size = mock.Mock()
  913 
  914         drv._move_nfs_file = mock.Mock(return_value=True)
  915         drv._delete_file_at_path = mock.Mock()
  916         drv._clone_file_dst_exists = mock.Mock()
  917         drv._post_clone_image = mock.Mock()
  918         self.mock_object(uuid, 'uuid4', mock.Mock(
  919             return_value='a155308c-0290-497b-b278-4cdd01de0253'))
  920 
  921         retval = drv._copy_from_img_service(
  922             context, volume, image_service, image_id)
  923 
  924         self.assertTrue(retval)
  925         drv._get_ip_verify_on_cluster.assert_any_call('203.0.113.122')
  926         drv._check_share_can_hold_size.assert_called_with(
  927             '203.0.113.122:/cinder-flexvol1', 1)
  928 
  929         # _execute must be called once for copy-offload and again to touch
  930         # the top directory to refresh cache
  931         drv._execute.assert_has_calls(
  932             [
  933                 mock.call(
  934                     'copyoffload_tool_path', '203.0.113.122',
  935                     '203.0.113.122', '/openstack/glance-flexvol1',
  936                     destination_copied_file, run_as_root=False,
  937                     check_exit_code=0
  938                 )
  939             ]
  940         )
  941         self.assertEqual(1, drv._execute.call_count)
  942         self.assertEqual(2, drv._delete_file_at_path.call_count)
  943         self.assertEqual(1, drv._clone_file_dst_exists.call_count)
  944 
  945     def test_copy_from_cache_copyoffload_success(self):
  946         drv = self.driver
  947         volume = {'id': 'vol_id', 'name': 'name', 'size': 1,
  948                   'host': 'openstack@nfscmode#192.128.1.1:/exp_path'}
  949         image_id = 'image_id'
  950         cache_result = [('ip1:/openstack', 'img-cache-imgid')]
  951         drv._get_ip_verify_on_cluster = mock.Mock(return_value='ip1')
  952         drv._execute = mock.Mock()
  953         drv._register_image_in_cache = mock.Mock()
  954         drv._post_clone_image = mock.Mock()
  955 
  956         copied = drv._copy_from_cache(volume, image_id, cache_result)
  957 
  958         self.assertTrue(copied)
  959         drv._get_ip_verify_on_cluster.assert_any_call('ip1')
  960         drv._execute.assert_called_once_with(
  961             'copyoffload_tool_path', 'ip1', 'ip1',
  962             '/openstack/img-cache-imgid', '/exp_path/name',
  963             run_as_root=False, check_exit_code=0)
  964 
  965     def test_unmanage(self):
  966         mock_get_info = self.mock_object(na_utils,
  967                                          'get_valid_qos_policy_group_info')
  968         mock_get_info.return_value = fake.QOS_POLICY_GROUP_INFO
  969 
  970         mock_mark_for_deletion =\
  971             self.driver.zapi_client.mark_qos_policy_group_for_deletion
  972 
  973         super_unmanage = self.mock_object(nfs_base.NetAppNfsDriver, 'unmanage')
  974 
  975         self.driver.unmanage(fake.NFS_VOLUME)
  976 
  977         mock_get_info.assert_has_calls([mock.call(fake.NFS_VOLUME)])
  978         mock_mark_for_deletion.assert_has_calls([
  979             mock.call(fake.QOS_POLICY_GROUP_INFO)])
  980         super_unmanage.assert_has_calls([mock.call(fake.NFS_VOLUME)])
  981 
  982     def test_unmanage_invalid_qos(self):
  983         mock_get_info = self.mock_object(na_utils,
  984                                          'get_valid_qos_policy_group_info')
  985         mock_get_info.side_effect = exception.Invalid
  986 
  987         super_unmanage = self.mock_object(nfs_base.NetAppNfsDriver, 'unmanage')
  988 
  989         self.driver.unmanage(fake.NFS_VOLUME)
  990 
  991         mock_get_info.assert_has_calls([mock.call(fake.NFS_VOLUME)])
  992         super_unmanage.assert_has_calls([mock.call(fake.NFS_VOLUME)])
  993 
  994     def test_add_looping_tasks(self):
  995         mock_update_ssc = self.mock_object(self.driver, '_update_ssc')
  996         mock_handle_housekeeping = self.mock_object(
  997             self.driver, '_handle_housekeeping_tasks')
  998         mock_add_task = self.mock_object(self.driver.loopingcalls, 'add_task')
  999         mock_super_add_looping_tasks = self.mock_object(
 1000             nfs_base.NetAppNfsDriver, '_add_looping_tasks')
 1001 
 1002         self.driver._add_looping_tasks()
 1003 
 1004         mock_update_ssc.assert_called_once_with()
 1005         mock_add_task.assert_has_calls([
 1006             mock.call(mock_update_ssc,
 1007                       loopingcalls.ONE_HOUR,
 1008                       loopingcalls.ONE_HOUR),
 1009             mock.call(mock_handle_housekeeping,
 1010                       loopingcalls.TEN_MINUTES,
 1011                       0)])
 1012         mock_super_add_looping_tasks.assert_called_once_with()
 1013 
 1014     @ddt.data({'type_match': True, 'expected': True},
 1015               {'type_match': False, 'expected': False})
 1016     @ddt.unpack
 1017     def test_is_share_clone_compatible(self, type_match, expected):
 1018 
 1019         mock_get_flexvol_name_for_share = self.mock_object(
 1020             self.driver, '_get_flexvol_name_for_share',
 1021             return_value='fake_flexvol')
 1022         mock_is_share_vol_type_match = self.mock_object(
 1023             self.driver, '_is_share_vol_type_match', return_value=type_match)
 1024 
 1025         result = self.driver._is_share_clone_compatible(fake.VOLUME,
 1026                                                         fake.NFS_SHARE)
 1027 
 1028         self.assertEqual(expected, result)
 1029         mock_get_flexvol_name_for_share.assert_called_once_with(fake.NFS_SHARE)
 1030         mock_is_share_vol_type_match.assert_called_once()
 1031 
 1032     @ddt.data({'flexvols': ['volume1', 'volume2'], 'expected': True},
 1033               {'flexvols': ['volume3', 'volume4'], 'expected': False},
 1034               {'flexvols': [], 'expected': False})
 1035     @ddt.unpack
 1036     def test_is_share_vol_type_match(self, flexvols, expected):
 1037 
 1038         mock_get_volume_extra_specs = self.mock_object(
 1039             na_utils, 'get_volume_extra_specs',
 1040             return_value='fake_extra_specs')
 1041         mock_get_matching_flexvols_for_extra_specs = self.mock_object(
 1042             self.driver.ssc_library, 'get_matching_flexvols_for_extra_specs',
 1043             return_value=flexvols)
 1044 
 1045         result = self.driver._is_share_vol_type_match(fake.VOLUME,
 1046                                                       fake.NFS_SHARE,
 1047                                                       'volume1')
 1048 
 1049         self.assertEqual(expected, result)
 1050         mock_get_volume_extra_specs.assert_called_once_with(fake.VOLUME)
 1051         mock_get_matching_flexvols_for_extra_specs.assert_called_once_with(
 1052             'fake_extra_specs')
 1053 
 1054     @ddt.data({'share': 'volume1', 'expected': 'volume1'},
 1055               {'share': 'volume3', 'expected': None})
 1056     @ddt.unpack
 1057     def test_get_flexvol_name_for_share(self, share, expected):
 1058 
 1059         mock_get_ssc = self.mock_object(
 1060             self.driver.ssc_library, 'get_ssc', return_value=fake_ssc.SSC)
 1061 
 1062         result = self.driver._get_flexvol_name_for_share(share)
 1063 
 1064         self.assertEqual(expected, result)
 1065         mock_get_ssc.assert_called_once_with()
 1066 
 1067     def test_get_flexvol_name_for_share_no_ssc_vols(self):
 1068 
 1069         mock_get_ssc = self.mock_object(
 1070             self.driver.ssc_library, 'get_ssc', return_value={})
 1071 
 1072         result = self.driver._get_flexvol_name_for_share('fake_share')
 1073 
 1074         self.assertIsNone(result)
 1075         mock_get_ssc.assert_called_once_with()
 1076 
 1077     def test_find_image_location_with_local_copy(self):
 1078         local_share = '/share'
 1079         cache_result = [
 1080             ('ip1:/openstack', 'img-cache-imgid'),
 1081             ('ip2:/openstack', 'img-cache-imgid'),
 1082             (local_share, 'img-cache-imgid'),
 1083             ('ip3:/openstack', 'img-cache-imgid'),
 1084         ]
 1085 
 1086         mock_extract_host = self.mock_object(volume_utils, 'extract_host')
 1087         mock_extract_host.return_value = local_share
 1088 
 1089         cache_copy, found_local_copy = self.driver._find_image_location(
 1090             cache_result, fake.VOLUME)
 1091 
 1092         self.assertEqual(cache_result[2], cache_copy)
 1093         self.assertTrue(found_local_copy)
 1094 
 1095     def test_find_image_location_with_remote_copy(self):
 1096         cache_result = [('ip1:/openstack', 'img-cache-imgid')]
 1097 
 1098         mock_extract_host = self.mock_object(volume_utils, 'extract_host')
 1099         mock_extract_host.return_value = '/share'
 1100 
 1101         cache_copy, found_local_copy = self.driver._find_image_location(
 1102             cache_result, fake.VOLUME)
 1103 
 1104         self.assertEqual(cache_result[0], cache_copy)
 1105         self.assertFalse(found_local_copy)
 1106 
 1107     def test_find_image_location_without_cache_copy(self):
 1108         cache_result = []
 1109         mock_extract_host = self.mock_object(volume_utils, 'extract_host')
 1110         mock_extract_host.return_value = '/share'
 1111 
 1112         cache_copy, found_local_copy = self.driver._find_image_location(
 1113             cache_result, fake.VOLUME)
 1114 
 1115         self.assertIsNone(cache_copy)
 1116         self.assertFalse(found_local_copy)
 1117 
 1118     def test_clone_file_dest_exists(self):
 1119         self.driver._get_vserver_and_exp_vol = mock.Mock(
 1120             return_value=(fake.VSERVER_NAME, fake.EXPORT_PATH))
 1121         self.driver.zapi_client.clone_file = mock.Mock()
 1122 
 1123         self.driver._clone_file_dst_exists(
 1124             fake.NFS_SHARE, fake.IMAGE_FILE_ID, fake.VOLUME['name'],
 1125             dest_exists=True)
 1126 
 1127         self.driver._get_vserver_and_exp_vol.assert_called_once_with(
 1128             share=fake.NFS_SHARE)
 1129         self.driver.zapi_client.clone_file.assert_called_once_with(
 1130             fake.EXPORT_PATH, fake.IMAGE_FILE_ID, fake.VOLUME['name'],
 1131             fake.VSERVER_NAME, dest_exists=True)
 1132 
 1133     @ddt.data((fake.NFS_SHARE, fake.SHARE_IP),
 1134               (fake.NFS_SHARE_IPV6, fake.IPV6_ADDRESS))
 1135     @ddt.unpack
 1136     def test_get_source_ip_and_path(self, share, ip):
 1137         self.driver._get_ip_verify_on_cluster = mock.Mock(
 1138             return_value=ip)
 1139 
 1140         src_ip, src_path = self.driver._get_source_ip_and_path(
 1141             share, fake.IMAGE_FILE_ID)
 1142 
 1143         self.assertEqual(ip, src_ip)
 1144         assert_path = fake.EXPORT_PATH + '/' + fake.IMAGE_FILE_ID
 1145         self.assertEqual(assert_path, src_path)
 1146         self.driver._get_ip_verify_on_cluster.assert_called_once_with(ip)
 1147 
 1148     def test_get_destination_ip_and_path(self):
 1149         self.driver._get_ip_verify_on_cluster = mock.Mock(
 1150             return_value=fake.SHARE_IP)
 1151         mock_extract_host = self.mock_object(volume_utils, 'extract_host')
 1152         mock_extract_host.return_value = fake.NFS_SHARE
 1153 
 1154         dest_ip, dest_path = self.driver._get_destination_ip_and_path(
 1155             fake.VOLUME)
 1156 
 1157         self.assertEqual(fake.SHARE_IP, dest_ip)
 1158         assert_path = fake.EXPORT_PATH + '/' + fake.LUN_NAME
 1159         self.assertEqual(assert_path, dest_path)
 1160         self.driver._get_ip_verify_on_cluster.assert_called_once_with(
 1161             fake.SHARE_IP)
 1162 
 1163     def test_clone_image_copyoffload_from_cache_success(self):
 1164         drv = self.driver
 1165         context = object()
 1166         volume = {'id': 'vol_id', 'name': 'name',
 1167                   'host': 'openstack@nfscmode#192.128.1.1:/mnt_point'}
 1168         image_service = object()
 1169         image_location = 'img-loc'
 1170         image_id = 'image_id'
 1171         image_meta = {'id': image_id}
 1172         drv.zapi_client = mock.Mock()
 1173         drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
 1174         nfs_base.NetAppNfsDriver._find_image_in_cache = mock.Mock(
 1175             return_value=[('share', 'img')])
 1176         nfs_base.NetAppNfsDriver._direct_nfs_clone = mock.Mock(
 1177             return_value=False)
 1178         drv._copy_from_cache = mock.Mock(return_value=True)
 1179 
 1180         drv.clone_image(context, volume, image_location, image_meta,
 1181                         image_service)
 1182 
 1183         drv._copy_from_cache.assert_called_once_with(
 1184             volume, image_id, [('share', 'img')])
 1185 
 1186     def test_clone_image_copyoffload_from_img_service(self):
 1187         drv = self.driver
 1188         context = object()
 1189         volume = {'id': 'vol_id', 'name': 'name',
 1190                   'host': 'openstack@nfscmode#192.128.1.1:/mnt_point',
 1191                   'provider_location': '192.128.1.1:/mnt_point'}
 1192         image_service = object()
 1193         image_id = 'image_id'
 1194         image_meta = {'id': image_id}
 1195         image_location = 'img-loc'
 1196         drv.zapi_client = mock.Mock()
 1197         drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
 1198         nfs_base.NetAppNfsDriver._find_image_in_cache = mock.Mock(
 1199             return_value=[])
 1200         nfs_base.NetAppNfsDriver._direct_nfs_clone = mock.Mock(
 1201             return_value=False)
 1202         nfs_base.NetAppNfsDriver._post_clone_image = mock.Mock(
 1203             return_value=True)
 1204         drv._copy_from_img_service = mock.Mock(return_value=True)
 1205 
 1206         retval = drv.clone_image(
 1207             context, volume, image_location, image_meta, image_service)
 1208 
 1209         self.assertEqual(retval, (
 1210             {'provider_location': '192.128.1.1:/mnt_point',
 1211              'bootable': True}, True))
 1212         drv._copy_from_img_service.assert_called_once_with(
 1213             context, volume, image_service, image_id)
 1214 
 1215     def test_clone_image_copyoffload_failure(self):
 1216         mock_log = self.mock_object(nfs_cmode, 'LOG')
 1217         drv = self.driver
 1218         context = object()
 1219         volume = {'id': 'vol_id', 'name': 'name'}
 1220         image_service = object()
 1221         image_id = 'image_id'
 1222         image_meta = {'id': image_id}
 1223         image_location = 'img-loc'
 1224         drv.zapi_client = mock.Mock()
 1225         drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
 1226         nfs_base.NetAppNfsDriver._find_image_in_cache = mock.Mock(
 1227             return_value=[])
 1228         nfs_base.NetAppNfsDriver._direct_nfs_clone = mock.Mock(
 1229             return_value=False)
 1230         drv._copy_from_img_service = mock.Mock(side_effect=Exception())
 1231 
 1232         retval = drv.clone_image(
 1233             context, volume, image_location, image_meta, image_service)
 1234 
 1235         self.assertEqual(retval, ({'bootable': False,
 1236                                    'provider_location': None}, False))
 1237         drv._copy_from_img_service.assert_called_once_with(
 1238             context, volume, image_service, image_id)
 1239         mock_log.info.assert_not_called()
 1240 
 1241     def test_copy_from_remote_cache(self):
 1242         source_ip = '192.0.1.1'
 1243         source_path = '/openstack/img-cache-imgid'
 1244         cache_copy = ('192.0.1.1:/openstack', fake.IMAGE_FILE_ID)
 1245         dest_path = fake.EXPORT_PATH + '/' + fake.VOLUME['name']
 1246         self.driver._execute = mock.Mock()
 1247         self.driver._get_source_ip_and_path = mock.Mock(
 1248             return_value=(source_ip, source_path))
 1249         self.driver._get_destination_ip_and_path = mock.Mock(
 1250             return_value=(fake.SHARE_IP, dest_path))
 1251         self.driver._register_image_in_cache = mock.Mock()
 1252 
 1253         self.driver._copy_from_remote_cache(
 1254             fake.VOLUME, fake.IMAGE_FILE_ID, cache_copy)
 1255 
 1256         self.driver._execute.assert_called_once_with(
 1257             'copyoffload_tool_path', source_ip, fake.SHARE_IP,
 1258             source_path, dest_path, run_as_root=False, check_exit_code=0)
 1259         self.driver._get_source_ip_and_path.assert_called_once_with(
 1260             cache_copy[0], fake.IMAGE_FILE_ID)
 1261         self.driver._get_destination_ip_and_path.assert_called_once_with(
 1262             fake.VOLUME)
 1263         self.driver._register_image_in_cache.assert_called_once_with(
 1264             fake.VOLUME, fake.IMAGE_FILE_ID)
 1265 
 1266     def test_copy_from_cache_workflow_remote_location(self):
 1267         cache_result = [('ip1:/openstack', fake.IMAGE_FILE_ID),
 1268                         ('ip2:/openstack', fake.IMAGE_FILE_ID),
 1269                         ('ip3:/openstack', fake.IMAGE_FILE_ID)]
 1270         self.driver._find_image_location = mock.Mock(return_value=[
 1271             cache_result[0], False])
 1272         self.driver._copy_from_remote_cache = mock.Mock()
 1273         self.driver._post_clone_image = mock.Mock()
 1274 
 1275         copied = self.driver._copy_from_cache(
 1276             fake.VOLUME, fake.IMAGE_FILE_ID, cache_result)
 1277 
 1278         self.assertTrue(copied)
 1279         self.driver._copy_from_remote_cache.assert_called_once_with(
 1280             fake.VOLUME, fake.IMAGE_FILE_ID, cache_result[0])
 1281 
 1282     def test_copy_from_cache_workflow_remote_location_no_copyoffload(self):
 1283         cache_result = [('ip1:/openstack', fake.IMAGE_FILE_ID),
 1284                         ('ip2:/openstack', fake.IMAGE_FILE_ID),
 1285                         ('ip3:/openstack', fake.IMAGE_FILE_ID)]
 1286         self.driver._find_image_location = mock.Mock(return_value=[
 1287             cache_result[0], False])
 1288         self.driver._copy_from_remote_cache = mock.Mock()
 1289         self.driver._post_clone_image = mock.Mock()
 1290         self.driver.configuration.netapp_copyoffload_tool_path = None
 1291 
 1292         copied = self.driver._copy_from_cache(
 1293             fake.VOLUME, fake.IMAGE_FILE_ID, cache_result)
 1294 
 1295         self.assertFalse(copied)
 1296         self.driver._copy_from_remote_cache.assert_not_called()
 1297 
 1298     def test_copy_from_cache_workflow_local_location(self):
 1299         local_share = '/share'
 1300         cache_result = [
 1301             ('ip1:/openstack', 'img-cache-imgid'),
 1302             ('ip2:/openstack', 'img-cache-imgid'),
 1303             (local_share, 'img-cache-imgid'),
 1304             ('ip3:/openstack', 'img-cache-imgid'),
 1305         ]
 1306         self.driver._find_image_location = mock.Mock(return_value=[
 1307             cache_result[2], True])
 1308         self.driver._clone_file_dst_exists = mock.Mock()
 1309         self.driver._post_clone_image = mock.Mock()
 1310 
 1311         copied = self.driver._copy_from_cache(
 1312             fake.VOLUME, fake.IMAGE_FILE_ID, cache_result)
 1313 
 1314         self.assertTrue(copied)
 1315         self.driver._clone_file_dst_exists.assert_called_once_with(
 1316             local_share, fake.IMAGE_FILE_ID, fake.VOLUME['name'],
 1317             dest_exists=True)
 1318 
 1319     def test_copy_from_cache_workflow_no_location(self):
 1320         cache_result = []
 1321         self.driver._find_image_location = mock.Mock(
 1322             return_value=(None, False))
 1323 
 1324         copied = self.driver._copy_from_cache(
 1325             fake.VOLUME, fake.IMAGE_FILE_ID, cache_result)
 1326 
 1327         self.assertFalse(copied)
 1328 
 1329     def test_copy_from_cache_workflow_exception(self):
 1330         cache_result = [('ip1:/openstack', fake.IMAGE_FILE_ID)]
 1331         self.driver._find_image_location = mock.Mock(return_value=[
 1332             cache_result[0], False])
 1333         self.driver._copy_from_remote_cache = mock.Mock(
 1334             side_effect=Exception)
 1335         self.driver._post_clone_image = mock.Mock()
 1336 
 1337         copied = self.driver._copy_from_cache(
 1338             fake.VOLUME, fake.IMAGE_FILE_ID, cache_result)
 1339 
 1340         self.assertFalse(copied)
 1341         self.driver._copy_from_remote_cache.assert_called_once_with(
 1342             fake.VOLUME, fake.IMAGE_FILE_ID, cache_result[0])
 1343         self.assertFalse(self.driver._post_clone_image.called)
 1344 
 1345     @ddt.data({'secondary_id': 'dev0', 'configured_targets': ['dev1']},
 1346               {'secondary_id': 'dev3', 'configured_targets': ['dev1', 'dev2']},
 1347               {'secondary_id': 'dev1', 'configured_targets': []},
 1348               {'secondary_id': None, 'configured_targets': []})
 1349     @ddt.unpack
 1350     def test_failover_host_invalid_replication_target(self, secondary_id,
 1351                                                       configured_targets):
 1352         """This tests executes a method in the DataMotionMixin."""
 1353         self.driver.backend_name = 'dev0'
 1354         self.mock_object(data_motion.DataMotionMixin,
 1355                          'get_replication_backend_names',
 1356                          return_value=configured_targets)
 1357         complete_failover_call = self.mock_object(
 1358             data_motion.DataMotionMixin, '_complete_failover')
 1359 
 1360         self.assertRaises(exception.InvalidReplicationTarget,
 1361                           self.driver.failover_host, 'fake_context', [],
 1362                           secondary_id=secondary_id)
 1363         self.assertFalse(complete_failover_call.called)
 1364 
 1365     def test_failover_host_unable_to_failover(self):
 1366         """This tests executes a method in the DataMotionMixin."""
 1367         self.driver.backend_name = 'dev0'
 1368         self.mock_object(data_motion.DataMotionMixin, '_complete_failover',
 1369                          side_effect=exception.NetAppDriverException)
 1370         self.mock_object(data_motion.DataMotionMixin,
 1371                          'get_replication_backend_names',
 1372                          return_value=['dev1', 'dev2'])
 1373         self.mock_object(self.driver.ssc_library, 'get_ssc_flexvol_names',
 1374                          return_value=fake_ssc.SSC.keys())
 1375         self.mock_object(self.driver, '_update_zapi_client')
 1376 
 1377         self.assertRaises(exception.UnableToFailOver,
 1378                           self.driver.failover_host, 'fake_context', [],
 1379                           secondary_id='dev1')
 1380         data_motion.DataMotionMixin._complete_failover.assert_called_once_with(
 1381             'dev0', ['dev1', 'dev2'], fake_ssc.SSC.keys(), [],
 1382             failover_target='dev1')
 1383         self.assertFalse(self.driver._update_zapi_client.called)
 1384 
 1385     def test_failover_host(self):
 1386         """This tests executes a method in the DataMotionMixin."""
 1387         self.driver.backend_name = 'dev0'
 1388         self.mock_object(data_motion.DataMotionMixin, '_complete_failover',
 1389                          return_value=('dev1', []))
 1390         self.mock_object(data_motion.DataMotionMixin,
 1391                          'get_replication_backend_names',
 1392                          return_value=['dev1', 'dev2'])
 1393         self.mock_object(self.driver.ssc_library, 'get_ssc_flexvol_names',
 1394                          return_value=fake_ssc.SSC.keys())
 1395         self.mock_object(self.driver, '_update_zapi_client')
 1396 
 1397         actual_active, vol_updates, __ = self.driver.failover_host(
 1398             'fake_context', [], secondary_id='dev1', groups=[])
 1399 
 1400         data_motion.DataMotionMixin._complete_failover.assert_called_once_with(
 1401             'dev0', ['dev1', 'dev2'], fake_ssc.SSC.keys(), [],
 1402             failover_target='dev1')
 1403         self.driver._update_zapi_client.assert_called_once_with('dev1')
 1404         self.assertTrue(self.driver.failed_over)
 1405         self.assertEqual('dev1', self.driver.failed_over_backend_name)
 1406         self.assertEqual('dev1', actual_active)
 1407         self.assertEqual([], vol_updates)
 1408 
 1409     def test_delete_group_snapshot(self):
 1410         mock_delete_backing_file = self.mock_object(
 1411             self.driver, '_delete_backing_file_for_snapshot')
 1412         snapshots = [fake.VG_SNAPSHOT]
 1413 
 1414         model_update, snapshots_model_update = (
 1415             self.driver.delete_group_snapshot(
 1416                 fake.VG_CONTEXT, fake.VG_SNAPSHOT, snapshots))
 1417 
 1418         mock_delete_backing_file.assert_called_once_with(fake.VG_SNAPSHOT)
 1419         self.assertIsNone(model_update)
 1420         self.assertIsNone(snapshots_model_update)
 1421 
 1422     def test_get_snapshot_backing_flexvol_names(self):
 1423         snapshots = [
 1424             {'volume': {'host': 'hostA@192.168.99.25#/fake/volume1'}},
 1425             {'volume': {'host': 'hostA@192.168.1.01#/fake/volume2'}},
 1426             {'volume': {'host': 'hostA@192.168.99.25#/fake/volume3'}},
 1427             {'volume': {'host': 'hostA@192.168.99.25#/fake/volume1'}},
 1428         ]
 1429 
 1430         ssc = {
 1431             'volume1': {'pool_name': '/fake/volume1', },
 1432             'volume2': {'pool_name': '/fake/volume2', },
 1433             'volume3': {'pool_name': '/fake/volume3', },
 1434         }
 1435 
 1436         mock_get_ssc = self.mock_object(self.driver.ssc_library, 'get_ssc')
 1437         mock_get_ssc.return_value = ssc
 1438 
 1439         hosts = [snap['volume']['host'] for snap in snapshots]
 1440         flexvols = self.driver._get_flexvol_names_from_hosts(hosts)
 1441 
 1442         mock_get_ssc.assert_called_once_with()
 1443         self.assertEqual(3, len(flexvols))
 1444         self.assertIn('volume1', flexvols)
 1445         self.assertIn('volume2', flexvols)
 1446         self.assertIn('volume3', flexvols)
 1447 
 1448     def test_get_backing_flexvol_names(self):
 1449         mock_ssc_library = self.mock_object(
 1450             self.driver.ssc_library, 'get_ssc')
 1451 
 1452         self.driver._get_backing_flexvol_names()
 1453 
 1454         mock_ssc_library.assert_called_once_with()
 1455 
 1456     def test_create_group(self):
 1457 
 1458         model_update = self.driver.create_group(
 1459             fake.VG_CONTEXT, fake.VOLUME_GROUP)
 1460 
 1461         self.assertEqual('available', model_update['status'])
 1462 
 1463     def test_update_group(self):
 1464 
 1465         model_update, add_volumes_update, remove_volumes_update = (
 1466             self.driver.update_group(fake.VG_CONTEXT, "foo"))
 1467 
 1468         self.assertIsNone(add_volumes_update)
 1469         self.assertIsNone(remove_volumes_update)
 1470 
 1471     @ddt.data(None,
 1472               {'replication_status': fields.ReplicationStatus.ENABLED})
 1473     def test_create_group_from_src(self, volume_model_update):
 1474         volume_model_update = volume_model_update or {}
 1475         volume_model_update.update(
 1476             {'provider_location': fake.PROVIDER_LOCATION})
 1477         mock_create_volume_from_snapshot = self.mock_object(
 1478             self.driver, 'create_volume_from_snapshot',
 1479             return_value=volume_model_update)
 1480 
 1481         model_update, volumes_model_update = (
 1482             self.driver.create_group_from_src(
 1483                 fake.VG_CONTEXT, fake.VOLUME_GROUP, [fake.VOLUME],
 1484                 group_snapshot=fake.VG_SNAPSHOT,
 1485                 sorted_snapshots=[fake.SNAPSHOT]))
 1486 
 1487         expected_volumes_model_updates = [{'id': fake.VOLUME['id']}]
 1488         expected_volumes_model_updates[0].update(volume_model_update)
 1489         mock_create_volume_from_snapshot.assert_called_once_with(
 1490             fake.VOLUME, fake.SNAPSHOT)
 1491         self.assertIsNone(model_update)
 1492         self.assertEqual(expected_volumes_model_updates, volumes_model_update)
 1493 
 1494     @ddt.data(None,
 1495               {'replication_status': fields.ReplicationStatus.ENABLED})
 1496     def test_create_group_from_src_source_vols(self, volume_model_update):
 1497         self.driver.zapi_client = mock.Mock()
 1498         mock_get_snapshot_flexvols = self.mock_object(
 1499             self.driver, '_get_flexvol_names_from_hosts')
 1500         mock_get_snapshot_flexvols.return_value = (set([fake.VG_POOL_NAME]))
 1501         mock_clone_backing_file = self.mock_object(
 1502             self.driver, '_clone_backing_file_for_volume')
 1503         fake_snapshot_name = 'snapshot-temp-' + fake.VOLUME_GROUP['id']
 1504         mock_busy = self.mock_object(
 1505             self.driver.zapi_client, 'wait_for_busy_snapshot')
 1506         self.mock_object(self.driver, '_get_volume_model_update',
 1507                          return_value=volume_model_update)
 1508 
 1509         model_update, volumes_model_update = (
 1510             self.driver.create_group_from_src(
 1511                 fake.VG_CONTEXT, fake.VOLUME_GROUP, [fake.VG_VOLUME],
 1512                 source_group=fake.VOLUME_GROUP,
 1513                 sorted_source_vols=[fake.SOURCE_VG_VOLUME]))
 1514 
 1515         expected_volumes_model_updates = [{
 1516             'id': fake.VG_VOLUME['id'],
 1517             'provider_location': fake.PROVIDER_LOCATION,
 1518         }]
 1519         if volume_model_update:
 1520             expected_volumes_model_updates[0].update(volume_model_update)
 1521         mock_get_snapshot_flexvols.assert_called_once_with(
 1522             [fake.SOURCE_VG_VOLUME['host']])
 1523         self.driver.zapi_client.create_cg_snapshot.assert_called_once_with(
 1524             set([fake.VG_POOL_NAME]), fake_snapshot_name)
 1525         mock_clone_backing_file.assert_called_once_with(
 1526             fake.SOURCE_VG_VOLUME['name'], fake.VG_VOLUME['name'],
 1527             fake.SOURCE_VG_VOLUME['id'], source_snapshot=fake_snapshot_name)
 1528         mock_busy.assert_called_once_with(
 1529             fake.VG_POOL_NAME, fake_snapshot_name)
 1530         self.driver.zapi_client.delete_snapshot.assert_called_once_with(
 1531             fake.VG_POOL_NAME, fake_snapshot_name)
 1532         self.assertIsNone(model_update)
 1533         self.assertEqual(expected_volumes_model_updates, volumes_model_update)
 1534 
 1535     def test_create_group_from_src_invalid_parms(self):
 1536         model_update, volumes_model_update = (
 1537             self.driver.create_group_from_src(
 1538                 fake.VG_CONTEXT, fake.VOLUME_GROUP, [fake.VOLUME]))
 1539 
 1540         self.assertIn('error', model_update['status'])
 1541 
 1542     def test_create_group_snapshot_raise_exception(self):
 1543         mock_is_cg_snapshot = self.mock_object(
 1544             volume_utils, 'is_group_a_cg_snapshot_type', return_value=True)
 1545         mock__get_flexvol_names = self.mock_object(
 1546             self.driver, '_get_flexvol_names_from_hosts')
 1547 
 1548         self.mock_object(self.driver.zapi_client, 'create_cg_snapshot',
 1549                          side_effect=netapp_api.NaApiError)
 1550 
 1551         self.assertRaises(exception.NetAppDriverException,
 1552                           self.driver.create_group_snapshot,
 1553                           fake.VG_CONTEXT,
 1554                           fake.VOLUME_GROUP,
 1555                           [fake.VG_SNAPSHOT])
 1556 
 1557         mock_is_cg_snapshot.assert_called_once_with(fake.VOLUME_GROUP)
 1558         mock__get_flexvol_names.assert_called_once_with(
 1559             [fake.VG_SNAPSHOT['volume']['host']])
 1560 
 1561     def test_create_group_snapshot(self):
 1562         mock_is_cg_snapshot = self.mock_object(
 1563             volume_utils, 'is_group_a_cg_snapshot_type', return_value=False)
 1564         mock__clone_backing_file_for_volume = self.mock_object(
 1565             self.driver, '_clone_backing_file_for_volume')
 1566 
 1567         model_update, snapshots_model_update = (
 1568             self.driver.create_group_snapshot(fake.VG_CONTEXT,
 1569                                               fake.VOLUME_GROUP,
 1570                                               [fake.SNAPSHOT]))
 1571 
 1572         self.assertIsNone(model_update)
 1573         self.assertIsNone(snapshots_model_update)
 1574         mock_is_cg_snapshot.assert_called_once_with(fake.VOLUME_GROUP)
 1575         mock__clone_backing_file_for_volume.assert_called_once_with(
 1576             fake.SNAPSHOT['volume_name'], fake.SNAPSHOT['name'],
 1577             fake.SNAPSHOT['volume_id'], is_snapshot=True)
 1578 
 1579     def test_create_consistent_group_snapshot(self):
 1580         mock_is_cg_snapshot = self.mock_object(
 1581             volume_utils, 'is_group_a_cg_snapshot_type', return_value=True)
 1582 
 1583         self.driver.zapi_client = mock.Mock()
 1584         mock_get_snapshot_flexvols = self.mock_object(
 1585             self.driver, '_get_flexvol_names_from_hosts')
 1586         mock_get_snapshot_flexvols.return_value = (set([fake.VG_POOL_NAME]))
 1587         mock_clone_backing_file = self.mock_object(
 1588             self.driver, '_clone_backing_file_for_volume')
 1589         mock_busy = self.mock_object(
 1590             self.driver.zapi_client, 'wait_for_busy_snapshot')
 1591 
 1592         model_update, snapshots_model_update = (
 1593             self.driver.create_group_snapshot(fake.VG_CONTEXT,
 1594                                               fake.VOLUME_GROUP,
 1595                                               [fake.VG_SNAPSHOT]))
 1596 
 1597         self.assertIsNone(model_update)
 1598         self.assertIsNone(snapshots_model_update)
 1599         mock_is_cg_snapshot.assert_called_once_with(fake.VOLUME_GROUP)
 1600         mock_get_snapshot_flexvols.assert_called_once_with(
 1601             [fake.VG_SNAPSHOT['volume']['host']])
 1602         self.driver.zapi_client.create_cg_snapshot.assert_called_once_with(
 1603             set([fake.VG_POOL_NAME]), fake.VOLUME_GROUP_ID)
 1604         mock_clone_backing_file.assert_called_once_with(
 1605             fake.VG_SNAPSHOT['volume']['name'], fake.VG_SNAPSHOT['name'],
 1606             fake.VG_SNAPSHOT['volume']['id'],
 1607             source_snapshot=fake.VOLUME_GROUP_ID)
 1608         mock_busy.assert_called_once_with(
 1609             fake.VG_POOL_NAME, fake.VOLUME_GROUP_ID)
 1610         self.driver.zapi_client.delete_snapshot.assert_called_once_with(
 1611             fake.VG_POOL_NAME, fake.VOLUME_GROUP_ID)
 1612 
 1613     def test_create_group_snapshot_busy_snapshot(self):
 1614         self.mock_object(volume_utils, 'is_group_a_cg_snapshot_type',
 1615                          return_value=True)
 1616         self.driver.zapi_client = mock.Mock()
 1617         snapshot = fake.VG_SNAPSHOT
 1618         snapshot['volume'] = fake.VG_VOLUME
 1619         mock_get_snapshot_flexvols = self.mock_object(
 1620             self.driver, '_get_flexvol_names_from_hosts')
 1621         mock_get_snapshot_flexvols.return_value = (set([fake.VG_POOL_NAME]))
 1622         mock_clone_backing_file = self.mock_object(
 1623             self.driver, '_clone_backing_file_for_volume')
 1624         mock_busy = self.mock_object(
 1625             self.driver.zapi_client, 'wait_for_busy_snapshot')
 1626         mock_busy.side_effect = exception.SnapshotIsBusy(snapshot['name'])
 1627         mock_mark_snapshot_for_deletion = self.mock_object(
 1628             self.driver.zapi_client, 'mark_snapshot_for_deletion')
 1629 
 1630         self.driver.create_group_snapshot(
 1631             fake.VG_CONTEXT, fake.VG_SNAPSHOT, [snapshot])
 1632 
 1633         mock_get_snapshot_flexvols.assert_called_once_with(
 1634             [snapshot['volume']['host']])
 1635         self.driver.zapi_client.create_cg_snapshot.assert_called_once_with(
 1636             set([fake.VG_POOL_NAME]), fake.VG_SNAPSHOT_ID)
 1637         mock_clone_backing_file.assert_called_once_with(
 1638             snapshot['volume']['name'], snapshot['name'],
 1639             snapshot['volume']['id'], source_snapshot=fake.VG_SNAPSHOT_ID)
 1640         mock_busy.assert_called_once_with(
 1641             fake.VG_POOL_NAME, fake.VG_SNAPSHOT_ID)
 1642         self.driver.zapi_client.delete_snapshot.assert_not_called()
 1643         mock_mark_snapshot_for_deletion.assert_called_once_with(
 1644             fake.VG_POOL_NAME, fake.VG_SNAPSHOT_ID)
 1645 
 1646     def test_delete_group_volume_delete_failure(self):
 1647         self.mock_object(self.driver, '_delete_file', side_effect=Exception)
 1648 
 1649         model_update, volumes = self.driver.delete_group(
 1650             fake.VG_CONTEXT, fake.VOLUME_GROUP, [fake.VG_VOLUME])
 1651 
 1652         self.assertEqual('deleted', model_update['status'])
 1653         self.assertEqual('error_deleting', volumes[0]['status'])
 1654 
 1655     def test_delete_group(self):
 1656         mock_delete_file = self.mock_object(
 1657             self.driver, '_delete_file')
 1658 
 1659         model_update, volumes = self.driver.delete_group(
 1660             fake.VG_CONTEXT, fake.VOLUME_GROUP, [fake.VG_VOLUME])
 1661 
 1662         self.assertEqual('deleted', model_update['status'])
 1663         self.assertEqual('deleted', volumes[0]['status'])
 1664         mock_delete_file.assert_called_once_with(
 1665             fake.VG_VOLUME_ID, fake.VG_VOLUME_NAME)