"Fossies" - the Fresh Open Source Software Archive

Member "cinder-17.1.0/cinder/tests/unit/volume/drivers/ibm/test_storwize_svc.py" (8 Mar 2021, 539910 Bytes) of package /linux/misc/openstack/cinder-17.1.0.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_storwize_svc.py": 17.0.1_vs_17.1.0.

    1 # Copyright 2015 IBM Corp.
    2 # Copyright 2012 OpenStack Foundation
    3 # All Rights Reserved.
    4 #
    5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    6 #    not use this file except in compliance with the License. You may obtain
    7 #    a copy of the License at
    8 #
    9 #         http://www.apache.org/licenses/LICENSE-2.0
   10 #
   11 #    Unless required by applicable law or agreed to in writing, software
   12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   14 #    License for the specific language governing permissions and limitations
   15 #    under the License.
   16 #
   17 """Tests for the IBM Storwize family and SVC volume driver."""
   18 
   19 import json
   20 import random
   21 import re
   22 import time
   23 from unittest import mock
   24 
   25 import ddt
   26 from oslo_concurrency import processutils
   27 from oslo_config import cfg
   28 from oslo_service import loopingcall
   29 from oslo_utils import importutils
   30 from oslo_utils import units
   31 import paramiko
   32 import six
   33 
   34 from cinder import context
   35 from cinder import exception
   36 from cinder.i18n import _
   37 from cinder import objects
   38 from cinder.objects import fields
   39 from cinder import ssh_utils
   40 from cinder.tests.unit import fake_constants as fake
   41 from cinder.tests.unit import test
   42 from cinder.tests.unit import utils as testutils
   43 from cinder import utils
   44 from cinder.volume import configuration as conf
   45 from cinder.volume.drivers.ibm.storwize_svc import (
   46     replication as storwize_rep)
   47 from cinder.volume.drivers.ibm.storwize_svc import storwize_const
   48 from cinder.volume.drivers.ibm.storwize_svc import storwize_svc_common
   49 from cinder.volume.drivers.ibm.storwize_svc import storwize_svc_fc
   50 from cinder.volume.drivers.ibm.storwize_svc import storwize_svc_iscsi
   51 from cinder.volume import group_types
   52 from cinder.volume import qos_specs
   53 from cinder.volume import volume_types
   54 from cinder.volume import volume_utils
   55 
   56 SVC_POOLS = ['openstack', 'openstack1']
   57 
   58 CONF = cfg.CONF
   59 
   60 
   61 def _get_test_pool(get_all=False):
   62     if get_all:
   63         return SVC_POOLS
   64     else:
   65         return SVC_POOLS[0]
   66 
   67 
   68 class StorwizeSVCManagementSimulator(object):
   69     def __init__(self, pool_name):
   70         self._flags = {'storwize_svc_volpool_name': pool_name}
   71         self._volumes_list = {}
   72         self._hosts_list = {}
   73         self._mappings_list = {}
   74         self._fcmappings_list = {}
   75         self._fcconsistgrp_list = {}
   76         self._rcrelationship_list = {}
   77         self._partnership_list = {}
   78         self._partnershipcandidate_list = {}
   79         self._rcconsistgrp_list = {}
   80         self._system_list = {'storwize-svc-sim': {'id': '0123456789ABCDEF',
   81                                                   'name': 'storwize-svc-sim'},
   82                              'aux-svc-sim': {'id': 'ABCDEF0123456789',
   83                                              'name': 'aux-svc-sim'}}
   84         self._other_pools = {'openstack2': {}, 'openstack3': {}}
   85         self._next_cmd_error = {
   86             'lsportip': '',
   87             'lsfabric': '',
   88             'lsiscsiauth': '',
   89             'lsnodecanister': '',
   90             'mkvdisk': '',
   91             'lsvdisk': '',
   92             'lsfcmap': '',
   93             'prestartfcmap': '',
   94             'startfcmap': '',
   95             'rmfcmap': '',
   96             'lslicense': '',
   97             'lsguicapabilities': '',
   98             'lshost': '',
   99             'lsrcrelationship': ''
  100         }
  101         self._errors = {
  102             'CMMVC5701E': ('', 'CMMVC5701E No object ID was specified.'),
  103             'CMMVC6035E': ('', 'CMMVC6035E The action failed as the '
  104                                'object already exists.'),
  105             'CMMVC5753E': ('', 'CMMVC5753E The specified object does not '
  106                                'exist or is not a suitable candidate.'),
  107             'CMMVC5707E': ('', 'CMMVC5707E Required parameters are missing.'),
  108             'CMMVC6581E': ('', 'CMMVC6581E The command has failed because '
  109                                'the maximum number of allowed iSCSI '
  110                                'qualified names (IQNs) has been reached, '
  111                                'or the IQN is already assigned or is not '
  112                                'valid.'),
  113             'CMMVC5754E': ('', 'CMMVC5754E The specified object does not '
  114                                'exist, or the name supplied does not meet '
  115                                'the naming rules.'),
  116             'CMMVC6071E': ('', 'CMMVC6071E The VDisk-to-host mapping was '
  117                                'not created because the VDisk is already '
  118                                'mapped to a host.'),
  119             'CMMVC5879E': ('', 'CMMVC5879E The VDisk-to-host mapping was '
  120                                'not created because a VDisk is already '
  121                                'mapped to this host with this SCSI LUN.'),
  122             'CMMVC5840E': ('', 'CMMVC5840E The virtual disk (VDisk) was '
  123                                'not deleted because it is mapped to a '
  124                                'host or because it is part of a FlashCopy '
  125                                'or Remote Copy mapping, or is involved in '
  126                                'an image mode migrate.'),
  127             'CMMVC6527E': ('', 'CMMVC6527E The name that you have entered '
  128                                'is not valid. The name can contain letters, '
  129                                'numbers, spaces, periods, dashes, and '
  130                                'underscores. The name must begin with a '
  131                                'letter or an underscore. The name must not '
  132                                'begin or end with a space.'),
  133             'CMMVC5871E': ('', 'CMMVC5871E The action failed because one or '
  134                                'more of the configured port names is in a '
  135                                'mapping.'),
  136             'CMMVC5924E': ('', 'CMMVC5924E The FlashCopy mapping was not '
  137                                'created because the source and target '
  138                                'virtual disks (VDisks) are different sizes.'),
  139             'CMMVC6303E': ('', 'CMMVC6303E The create failed because the '
  140                                'source and target VDisks are the same.'),
  141             'CMMVC7050E': ('', 'CMMVC7050E The command failed because at '
  142                                'least one node in the I/O group does not '
  143                                'support compressed VDisks.'),
  144             'CMMVC6430E': ('', 'CMMVC6430E The command failed because the '
  145                                'target and source managed disk groups must '
  146                                'be different.'),
  147             'CMMVC6353E': ('', 'CMMVC6353E The command failed because the '
  148                                'copy specified does not exist.'),
  149             'CMMVC6446E': ('', 'The command failed because the managed disk '
  150                                'groups have different extent sizes.'),
  151             # Catch-all for invalid state transitions:
  152             'CMMVC5903E': ('', 'CMMVC5903E The FlashCopy mapping was not '
  153                                'changed because the mapping or consistency '
  154                                'group is another state.'),
  155             'CMMVC5709E': ('', 'CMMVC5709E [-%(VALUE)s] is not a supported '
  156                                'parameter.'),
  157             'CMMVC5982E': ('', 'CMMVC5982E The operation was not performed '
  158                                'because it is not valid given the current '
  159                                'relationship state.'),
  160             'CMMVC5963E': ('', 'CMMVC5963E No direction has been defined.'),
  161             'CMMVC5713E': ('', 'CMMVC5713E Some parameters are mutually '
  162                                'exclusive.'),
  163             'CMMVC5804E': ('', 'CMMVC5804E The action failed because an '
  164                                'object that was specified in the command '
  165                                'does not exist.'),
  166             'CMMVC6065E': ('', 'CMMVC6065E The action failed as the object '
  167                                'is not in a group.'),
  168             'CMMVC9012E': ('', 'CMMVC9012E The copy type differs from other '
  169                                'copies already in the consistency group.'),
  170         }
  171         self._fc_transitions = {'begin': {'make': 'idle_or_copied'},
  172                                 'idle_or_copied': {'prepare': 'preparing',
  173                                                    'delete': 'end',
  174                                                    'delete_force': 'end'},
  175                                 'preparing': {'flush_failed': 'stopped',
  176                                               'wait': 'prepared'},
  177                                 'end': None,
  178                                 'stopped': {'prepare': 'preparing',
  179                                             'delete_force': 'end'},
  180                                 'prepared': {'stop': 'stopped',
  181                                              'start': 'copying'},
  182                                 'copying': {'wait': 'idle_or_copied',
  183                                             'stop': 'stopping'},
  184                                 # Assume the worst case where stopping->stopped
  185                                 # rather than stopping idle_or_copied
  186                                 'stopping': {'wait': 'stopped'},
  187                                 }
  188 
  189         self._fc_cg_transitions = {'begin': {'make': 'empty'},
  190                                    'empty': {'add': 'idle_or_copied'},
  191                                    'idle_or_copied': {'prepare': 'preparing',
  192                                                       'delete': 'end',
  193                                                       'delete_force': 'end'},
  194                                    'preparing': {'flush_failed': 'stopped',
  195                                                  'wait': 'prepared'},
  196                                    'end': None,
  197                                    'stopped': {'prepare': 'preparing',
  198                                                'delete_force': 'end'},
  199                                    'prepared': {'stop': 'stopped',
  200                                                 'start': 'copying',
  201                                                 'delete_force': 'end',
  202                                                 'delete': 'end'},
  203                                    'copying': {'wait': 'idle_or_copied',
  204                                                'stop': 'stopping',
  205                                                'delete_force': 'end',
  206                                                'delete': 'end'},
  207                                    # Assume the case where stopping->stopped
  208                                    # rather than stopping idle_or_copied
  209                                    'stopping': {'wait': 'stopped'},
  210                                    }
  211         self._rc_transitions = {'inconsistent_stopped':
  212                                 {'start': 'inconsistent_copying',
  213                                  'stop': 'inconsistent_stopped',
  214                                  'delete': 'end',
  215                                  'delete_force': 'end'},
  216                                 'inconsistent_copying': {
  217                                     'wait': 'consistent_synchronized',
  218                                     'start': 'inconsistent_copying',
  219                                     'stop': 'inconsistent_stopped',
  220                                     'delete': 'end',
  221                                     'delete_force': 'end'},
  222                                 'consistent_synchronized': {
  223                                     'start': 'consistent_synchronized',
  224                                     'stop': 'consistent_stopped',
  225                                     'stop_access': 'idling',
  226                                     'delete': 'end',
  227                                     'delete_force': 'end'},
  228                                 'consistent_copying': {
  229                                     'start': 'consistent_copying',
  230                                     'stop': 'consistent_stopped',
  231                                     'stop_access': 'idling',
  232                                     'delete': 'end',
  233                                     'delete_force': 'end'},
  234                                 'consistent_stopped':
  235                                 {'start': 'consistent_synchronized',
  236                                  'stop': 'consistent_stopped',
  237                                  'delete': 'end',
  238                                  'delete_force': 'end'},
  239                                 'end': None,
  240                                 'idling': {
  241                                     'start': 'inconsistent_copying',
  242                                     'stop': 'inconsistent_stopped',
  243                                     'stop_access': 'idling',
  244                                     'delete': 'end',
  245                                     'delete_force': 'end'},
  246                                 }
  247         self._rccg_transitions = {'empty': {'add': 'inconsistent_stopped',
  248                                             'delete': 'end',
  249                                             'delete_force': 'end'},
  250                                   'inconsistent_stopped':
  251                                       {'start': 'inconsistent_copying',
  252                                        'stop': 'inconsistent_stopped',
  253                                        'delete': 'end',
  254                                        'delete_force': 'end'},
  255                                   'inconsistent_copying': {
  256                                       'wait': 'consistent_synchronized',
  257                                       'start': 'inconsistent_copying',
  258                                       'stop': 'inconsistent_stopped',
  259                                       'delete': 'end',
  260                                       'delete_force': 'end'},
  261                                   'consistent_synchronized': {
  262                                       'start': 'consistent_synchronized',
  263                                       'stop': 'consistent_stopped',
  264                                       'stop_access': 'idling',
  265                                       'delete': 'end',
  266                                       'delete_force': 'end'},
  267                                   'consistent_stopped':
  268                                       {'start': 'consistent_synchronized',
  269                                        'stop': 'consistent_stopped',
  270                                        'delete': 'end',
  271                                        'delete_force': 'end'},
  272                                   'consistent_copying': {
  273                                       'start': 'consistent_copying',
  274                                       'stop': 'consistent_stopped',
  275                                       'stop_access': 'idling',
  276                                       'delete': 'end',
  277                                       'delete_force': 'end'},
  278                                   'end': None,
  279                                   'idling': {
  280                                       'start': 'inconsistent_copying',
  281                                       'stop': 'inconsistent_stopped',
  282                                       'stop_access': 'idling',
  283                                       'delete': 'end',
  284                                       'delete_force': 'end'},
  285                                   }
  286 
  287     def _state_transition(self, function, fcmap):
  288         if (function == 'wait' and
  289                 'wait' not in self._fc_transitions[fcmap['status']]):
  290             return ('', '')
  291 
  292         if fcmap['status'] == 'copying' and function == 'wait':
  293             if fcmap['copyrate'] != '0':
  294                 if fcmap['progress'] == '0':
  295                     fcmap['progress'] = '50'
  296                 else:
  297                     fcmap['progress'] = '100'
  298                     fcmap['status'] = 'idle_or_copied'
  299             return ('', '')
  300         else:
  301             try:
  302                 curr_state = fcmap['status']
  303                 fcmap['status'] = self._fc_transitions[curr_state][function]
  304                 return ('', '')
  305             except Exception:
  306                 return self._errors['CMMVC5903E']
  307 
  308     def _fc_cg_state_transition(self, function, fc_consistgrp):
  309         if (function == 'wait' and
  310                 'wait' not in self._fc_transitions[fc_consistgrp['status']]):
  311             return ('', '')
  312 
  313         try:
  314             curr_state = fc_consistgrp['status']
  315             fc_consistgrp['status'] \
  316                 = self._fc_cg_transitions[curr_state][function]
  317             return ('', '')
  318         except Exception:
  319             return self._errors['CMMVC5903E']
  320 
  321     # Find an unused ID
  322     @staticmethod
  323     def _find_unused_id(d):
  324         ids = []
  325         for v in d.values():
  326             ids.append(int(v['id']))
  327         ids.sort()
  328         for index, n in enumerate(ids):
  329             if n > index:
  330                 return six.text_type(index)
  331         return six.text_type(len(ids))
  332 
  333     # Check if name is valid
  334     @staticmethod
  335     def _is_invalid_name(name):
  336         if re.match(r'^[a-zA-Z_][\w._-]*$', name):
  337             return False
  338         return True
  339 
  340     # Convert argument string to dictionary
  341     @staticmethod
  342     def _cmd_to_dict(arg_list):
  343         no_param_args = [
  344             'autodelete',
  345             'bytes',
  346             'compressed',
  347             'force',
  348             'nohdr',
  349             'nofmtdisk',
  350             'noconsistgrp',
  351             'global',
  352             'access',
  353             'start',
  354             'thin',
  355             'removehostmappings',
  356             'removefcmaps',
  357             'removercrelationships'
  358         ]
  359         one_param_args = [
  360             'chapsecret',
  361             'cleanrate',
  362             'copy',
  363             'copyrate',
  364             'delim',
  365             'easytier',
  366             'filtervalue',
  367             'grainsize',
  368             'hbawwpn',
  369             'host',
  370             'iogrp',
  371             'iscsiname',
  372             'mdiskgrp',
  373             'name',
  374             'rsize',
  375             'scsi',
  376             'size',
  377             'source',
  378             'target',
  379             'unit',
  380             'vdisk',
  381             'warning',
  382             'wwpn',
  383             'primary',
  384             'consistgrp',
  385             'master',
  386             'aux',
  387             'cluster',
  388             'linkbandwidthmbits',
  389             'backgroundcopyrate',
  390             'copies',
  391             'cyclingmode',
  392             'cycleperiodseconds',
  393             'masterchange',
  394             'auxchange',
  395             'pool',
  396             'site',
  397             'buffersize',
  398         ]
  399         no_or_one_param_args = [
  400             'autoexpand',
  401         ]
  402 
  403         # Handle the special case of lsnode which is a two-word command
  404         # Use the one word version of the command internally
  405         if arg_list[0] in ('svcinfo', 'svctask'):
  406             if arg_list[1] == 'lsnode':
  407                 if len(arg_list) > 4:  # e.g. svcinfo lsnode -delim ! <node id>
  408                     ret = {'cmd': 'lsnode', 'node_id': arg_list[-1]}
  409                 else:
  410                     ret = {'cmd': 'lsnodecanister'}
  411             else:
  412                 ret = {'cmd': arg_list[1]}
  413             arg_list.pop(0)
  414         else:
  415             ret = {'cmd': arg_list[0]}
  416 
  417         skip = False
  418         for i in range(1, len(arg_list)):
  419             if skip:
  420                 skip = False
  421                 continue
  422             # Check for a quoted command argument for volumes and strip
  423             # quotes so that the simulater can match it later. Just
  424             # match against test naming convensions for now.
  425             if arg_list[i][0] == '"' and ('volume' in arg_list[i] or
  426                                           'snapshot' in arg_list[i]):
  427                 arg_list[i] = arg_list[i][1:-1]
  428             if arg_list[i][0] == '-':
  429                 if arg_list[i][1:] in no_param_args:
  430                     ret[arg_list[i][1:]] = True
  431                 elif arg_list[i][1:] in one_param_args:
  432                     ret[arg_list[i][1:]] = arg_list[i + 1]
  433                     skip = True
  434                 elif arg_list[i][1:] in no_or_one_param_args:
  435                     if i == (len(arg_list) - 1) or arg_list[i + 1][0] == '-':
  436                         ret[arg_list[i][1:]] = True
  437                     else:
  438                         ret[arg_list[i][1:]] = arg_list[i + 1]
  439                         skip = True
  440                 else:
  441                     raise exception.InvalidInput(
  442                         reason=_('unrecognized argument %s') % arg_list[i])
  443             else:
  444                 ret['obj'] = arg_list[i]
  445         return ret
  446 
  447     @staticmethod
  448     def _print_info_cmd(rows, delim=' ', nohdr=False, **kwargs):
  449         """Generic function for printing information."""
  450         if nohdr:
  451             del rows[0]
  452 
  453         for index in range(len(rows)):
  454             rows[index] = delim.join(rows[index])
  455         return ('%s' % '\n'.join(rows), '')
  456 
  457     @staticmethod
  458     def _print_info_obj_cmd(header, row, delim=' ', nohdr=False):
  459         """Generic function for printing information for a specific object."""
  460         objrows = []
  461         for idx, val in enumerate(header):
  462             objrows.append([val, row[idx]])
  463 
  464         if nohdr:
  465             for index in range(len(objrows)):
  466                 objrows[index] = ' '.join(objrows[index][1:])
  467         for index in range(len(objrows)):
  468             objrows[index] = delim.join(objrows[index])
  469         return ('%s' % '\n'.join(objrows), '')
  470 
  471     @staticmethod
  472     def _convert_bytes_units(bytestr):
  473         num = int(bytestr)
  474         unit_array = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
  475         unit_index = 0
  476 
  477         while num > 1024:
  478             num = num / 1024
  479             unit_index += 1
  480 
  481         return '%d%s' % (num, unit_array[unit_index])
  482 
  483     @staticmethod
  484     def _convert_units_bytes(num, unit):
  485         unit_array = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
  486         unit_index = 0
  487 
  488         while unit.lower() != unit_array[unit_index].lower():
  489             num = num * 1024
  490             unit_index += 1
  491 
  492         return six.text_type(num)
  493 
  494     def _cmd_lslicense(self, **kwargs):
  495         rows = [None] * 3
  496         rows[0] = ['used_compression_capacity', '0.08']
  497         rows[1] = ['license_compression_capacity', '0']
  498         if self._next_cmd_error['lslicense'] == 'no_compression':
  499             self._next_cmd_error['lslicense'] = ''
  500             rows[2] = ['license_compression_enclosures', '0']
  501         else:
  502             rows[2] = ['license_compression_enclosures', '1']
  503         return self._print_info_cmd(rows=rows, **kwargs)
  504 
  505     def _cmd_lsguicapabilities(self, **kwargs):
  506         rows = [None] * 2
  507         if self._next_cmd_error['lsguicapabilities'] == 'no_compression':
  508             self._next_cmd_error['lsguicapabilities'] = ''
  509             rows[0] = ['license_scheme', '0']
  510         else:
  511             rows[0] = ['license_scheme', 'flex']
  512         rows[1] = ['product_key', storwize_const.DEV_MODEL_SVC]
  513         return self._print_info_cmd(rows=rows, **kwargs)
  514 
  515     # Print mostly made-up stuff in the correct syntax
  516     def _cmd_lssystem(self, **kwargs):
  517         rows = [None] * 4
  518         rows[0] = ['id', '0123456789ABCDEF']
  519         rows[1] = ['name', 'storwize-svc-sim']
  520         rows[2] = ['code_level', '7.2.0.0 (build 87.0.1311291000)']
  521         rows[3] = ['topology', '']
  522         return self._print_info_cmd(rows=rows, **kwargs)
  523 
  524     def _cmd_lssystem_aux(self, **kwargs):
  525         rows = [None] * 4
  526         rows[0] = ['id', 'ABCDEF0123456789']
  527         rows[1] = ['name', 'aux-svc-sim']
  528         rows[2] = ['code_level', '7.2.0.0 (build 87.0.1311291000)']
  529         rows[3] = ['topology', '']
  530         return self._print_info_cmd(rows=rows, **kwargs)
  531 
  532     # Print mostly made-up stuff in the correct syntax, assume -bytes passed
  533     def _cmd_lsmdiskgrp(self, **kwargs):
  534         pool_num = len(self._flags['storwize_svc_volpool_name'])
  535         rows = []
  536         rows.append(['id', 'name', 'status', 'mdisk_count',
  537                      'vdisk_count', 'capacity', 'extent_size',
  538                      'free_capacity', 'virtual_capacity', 'used_capacity',
  539                      'real_capacity', 'overallocation', 'warning',
  540                      'easy_tier', 'easy_tier_status', 'site_id',
  541                      'data_reduction'])
  542         for i in range(pool_num):
  543             row_data = [str(i + 1),
  544                         self._flags['storwize_svc_volpool_name'][i], 'online',
  545                         '1', six.text_type(len(self._volumes_list)),
  546                         '3573412790272', '256', '3529926246400',
  547                         '1693247906775',
  548                         '26843545600', '38203734097', '47', '80', 'auto',
  549                         'inactive', '', 'no']
  550             rows.append(row_data)
  551         rows.append([str(pool_num + 1), 'openstack2', 'online',
  552                      '1', '0', '3573412790272', '256',
  553                      '3529432325160', '1693247906775', '26843545600',
  554                      '38203734097', '47', '80', 'auto', 'inactive', '', 'no'])
  555         rows.append([str(pool_num + 2), 'openstack3', 'offline',
  556                      '1', '0', '3573412790272', '128',
  557                      '3529432325160', '1693247906775', '26843545600',
  558                      '38203734097', '47', '80', 'auto', 'inactive', '', 'yes'])
  559         rows.append([str(pool_num + 3), 'hyperswap1', 'online',
  560                      '1', '0', '3573412790272', '256',
  561                      '3529432325160', '1693247906775', '26843545600',
  562                      '38203734097', '47', '80', 'auto', 'inactive', '1', 'no'])
  563         rows.append([str(pool_num + 4), 'hyperswap2', 'online',
  564                      '1', '0', '3573412790272', '128',
  565                      '3529432325160', '1693247906775', '26843545600',
  566                      '38203734097', '47', '80', 'auto', 'inactive', '2', 'no'])
  567         rows.append([str(pool_num + 5), 'dr_pool1', 'online',
  568                      '1', '0', '3573412790272', '128', '3529432325160',
  569                      '1693247906775', '26843545600', '38203734097', '47', '80',
  570                      'auto', 'inactive', '1', 'yes'])
  571         rows.append([str(pool_num + 6), 'dr_pool2', 'online',
  572                      '1', '0', '3573412790272', '128', '3529432325160',
  573                      '1693247906775', '26843545600', '38203734097', '47', '80',
  574                      'auto', 'inactive', '2', 'yes'])
  575         if 'obj' not in kwargs:
  576             return self._print_info_cmd(rows=rows, **kwargs)
  577         else:
  578             pool_name = kwargs['obj'].strip('\'\"')
  579             if pool_name == kwargs['obj']:
  580                 raise exception.InvalidInput(
  581                     reason=_('obj missing quotes %s') % kwargs['obj'])
  582             elif pool_name in self._flags['storwize_svc_volpool_name']:
  583                 for each_row in rows:
  584                     if pool_name in each_row:
  585                         row = each_row
  586                         break
  587             elif pool_name == 'openstack2':
  588                 row = rows[-6]
  589             elif pool_name == 'openstack3':
  590                 row = rows[-5]
  591             elif pool_name == 'hyperswap1':
  592                 row = rows[-4]
  593             elif pool_name == 'hyperswap2':
  594                 row = rows[-3]
  595             elif pool_name == 'dr_pool1':
  596                 row = rows[-2]
  597             elif pool_name == 'dr_pool2':
  598                 row = rows[-1]
  599             else:
  600                 return self._errors['CMMVC5754E']
  601             objrows = []
  602             for idx, val in enumerate(rows[0]):
  603                 objrows.append([val, row[idx]])
  604             if 'nohdr' in kwargs:
  605                 for index in range(len(objrows)):
  606                     objrows[index] = ' '.join(objrows[index][1:])
  607 
  608             if 'delim' in kwargs:
  609                 for index in range(len(objrows)):
  610                     objrows[index] = kwargs['delim'].join(objrows[index])
  611 
  612             return ('%s' % '\n'.join(objrows), '')
  613 
  614     def _get_mdiskgrp_id(self, mdiskgrp):
  615         grp_num = len(self._flags['storwize_svc_volpool_name'])
  616         if mdiskgrp in self._flags['storwize_svc_volpool_name']:
  617             for i in range(grp_num):
  618                 if mdiskgrp == self._flags['storwize_svc_volpool_name'][i]:
  619                     return i + 1
  620         elif mdiskgrp == 'openstack2':
  621             return grp_num + 1
  622         elif mdiskgrp == 'openstack3':
  623             return grp_num + 2
  624         else:
  625             return None
  626 
  627     # Print mostly made-up stuff in the correct syntax
  628     def _cmd_lsnodecanister(self, **kwargs):
  629         rows = [None] * 3
  630         rows[0] = ['id', 'name', 'UPS_serial_number', 'WWNN', 'status',
  631                    'IO_group_id', 'IO_group_name', 'config_node',
  632                    'UPS_unique_id', 'hardware', 'iscsi_name', 'iscsi_alias',
  633                    'panel_name', 'enclosure_id', 'canister_id',
  634                    'enclosure_serial_number', 'site_id']
  635         rows[1] = ['1', 'node1', '', '123456789ABCDEF0', 'online', '0',
  636                    'io_grp0',
  637                    'yes', '123456789ABCDEF0', '100',
  638                    'iqn.1982-01.com.ibm:1234.sim.node1', '', '01-1', '1', '1',
  639                    '0123ABC', '1']
  640         rows[2] = ['2', 'node2', '', '123456789ABCDEF1', 'online', '1',
  641                    'io_grp0',
  642                    'no', '123456789ABCDEF1', '100',
  643                    'iqn.1982-01.com.ibm:1234.sim.node2', '', '01-2', '1', '2',
  644                    '0123ABC', '2']
  645 
  646         if self._next_cmd_error['lsnodecanister'] == 'header_mismatch':
  647             rows[0].pop(2)
  648             self._next_cmd_error['lsnodecanister'] = ''
  649         if self._next_cmd_error['lsnodecanister'] == 'remove_field':
  650             for row in rows:
  651                 row.pop(0)
  652             self._next_cmd_error['lsnodecanister'] = ''
  653 
  654         return self._print_info_cmd(rows=rows, **kwargs)
  655 
  656     # Print information of every single node of SVC
  657     def _cmd_lsnode(self, **kwargs):
  658         node_infos = dict()
  659         node_infos['1'] = r'''id!1
  660 name!node1
  661 port_id!500507680210C744
  662 port_status!active
  663 port_speed!8Gb
  664 port_id!500507680220C744
  665 port_status!active
  666 port_speed!8Gb
  667 '''
  668         node_infos['2'] = r'''id!2
  669 name!node2
  670 port_id!500507680220C745
  671 port_status!active
  672 port_speed!8Gb
  673 port_id!500507680230C745
  674 port_status!inactive
  675 port_speed!N/A
  676 '''
  677         node_id = kwargs.get('node_id', None)
  678         stdout = node_infos.get(node_id, '')
  679         return stdout, ''
  680 
  681     # Print made up stuff for the ports
  682     def _cmd_lsportfc(self, **kwargs):
  683         node_1 = [None] * 7
  684         node_1[0] = ['id', 'fc_io_port_id', 'port_id', 'type',
  685                      'port_speed', 'node_id', 'node_name', 'WWPN',
  686                      'nportid', 'status', 'attachment']
  687         node_1[1] = ['0', '1', '1', 'fc', '8Gb', '1', 'node1',
  688                      '5005076802132ADE', '012E00', 'active', 'switch']
  689         node_1[2] = ['1', '2', '2', 'fc', '8Gb', '1', 'node1',
  690                      '5005076802232ADE', '012E00', 'active', 'switch']
  691         node_1[3] = ['2', '3', '3', 'fc', '8Gb', '1', 'node1',
  692                      '5005076802332ADE', '9B0600', 'active', 'switch']
  693         node_1[4] = ['3', '4', '4', 'fc', '8Gb', '1', 'node1',
  694                      '5005076802432ADE', '012A00', 'active', 'switch']
  695         node_1[5] = ['4', '5', '5', 'fc', '8Gb', '1', 'node1',
  696                      '5005076802532ADE', '014A00', 'active', 'switch']
  697         node_1[6] = ['5', '6', '4', 'ethernet', 'N/A', '1', 'node1',
  698                      '5005076802632ADE', '000000',
  699                      'inactive_unconfigured', 'none']
  700 
  701         node_2 = [None] * 7
  702         node_2[0] = ['id', 'fc_io_port_id', 'port_id', 'type',
  703                      'port_speed', 'node_id', 'node_name', 'WWPN',
  704                      'nportid', 'status', 'attachment']
  705         node_2[1] = ['6', '7', '7', 'fc', '8Gb', '2', 'node2',
  706                      '5005086802132ADE', '012E00', 'active', 'switch']
  707         node_2[2] = ['7', '8', '8', 'fc', '8Gb', '2', 'node2',
  708                      '5005086802232ADE', '012E00', 'active', 'switch']
  709         node_2[3] = ['8', '9', '9', 'fc', '8Gb', '2', 'node2',
  710                      '5005086802332ADE', '9B0600', 'active', 'switch']
  711         node_2[4] = ['9', '10', '10', 'fc', '8Gb', '2', 'node2',
  712                      '5005086802432ADE', '012A00', 'active', 'switch']
  713         node_2[5] = ['10', '11', '11', 'fc', '8Gb', '2', 'node2',
  714                      '5005086802532ADE', '014A00', 'active', 'switch']
  715         node_2[6] = ['11', '12', '12', 'ethernet', 'N/A', '2', 'node2',
  716                      '5005086802632ADE', '000000',
  717                      'inactive_unconfigured', 'none']
  718         node_infos = [node_1, node_2]
  719         node_id = int(kwargs['filtervalue'].split('=')[1]) - 1
  720 
  721         return self._print_info_cmd(rows=node_infos[node_id], **kwargs)
  722 
  723     def _cmd_lstargetportfc(self, **kwargs):
  724         ports = [None] * 17
  725         ports[0] = ['id', 'WWPN', 'WWNN', 'port_id', 'owning_node_id',
  726                     'current_node_id', 'nportid', 'host_io_permitted',
  727                     'virtualized']
  728         ports[1] = ['0', '5005076801106CFE', '5005076801106CFE', '1', '1',
  729                     '1', '042200', 'no', 'no']
  730         ports[2] = ['0', '5005076801996CFE', '5005076801106CFE', '1', '1',
  731                     '1', '042200', 'yes', 'yes']
  732         ports[3] = ['0', '5005076801206CFE', '5005076801106CFE', '2', '1',
  733                     '1', '042200', 'no', 'no']
  734         ports[4] = ['0', '5005076801A96CFE', '5005076801106CFE', '2', '1',
  735                     '1', '042200', 'yes', 'yes']
  736         ports[5] = ['0', '5005076801306CFE', '5005076801106CFE', '3', '1',
  737                     '', '042200', 'no', 'no']
  738         ports[6] = ['0', '5005076801B96CFE', '5005076801106CFE', '3', '1',
  739                     '', '042200', 'yes', 'yes']
  740         ports[7] = ['0', '5005076801406CFE', '5005076801106CFE', '4', '1',
  741                     '', '042200', 'no', 'no']
  742         ports[8] = ['0', '5005076801C96CFE', '5005076801106CFE', '4', '1',
  743                     '', '042200', 'yes', 'yes']
  744         ports[9] = ['0', '5005076801101806', '5005076801101806', '1', '2',
  745                     '2', '042200', 'no', 'no']
  746         ports[10] = ['0', '5005076801991806', '5005076801101806', '1', '2',
  747                      '2', '042200', 'yes', 'yes']
  748         ports[11] = ['0', '5005076801201806', '5005076801101806', '2', '2',
  749                      '2', '042200', 'no', 'no']
  750         ports[12] = ['0', '5005076801A91806', '5005076801101806', '2', '2',
  751                      '2', '042200', 'yes', 'yes']
  752         ports[13] = ['0', '5005076801301806', '5005076801101806', '3', '2',
  753                      '', '042200', 'no', 'no']
  754         ports[14] = ['0', '5005076801B91806', '5005076801101806', '3', '2',
  755                      '', '042200', 'yes', 'yes']
  756         ports[15] = ['0', '5005076801401806', '5005076801101806', '4', '2',
  757                      '', '042200', 'no', 'no']
  758         ports[16] = ['0', '5005076801C91806', '5005076801101806', '4', '2',
  759                      '', '042200', 'yes', 'yes']
  760 
  761         if 'filtervalue' in kwargs:
  762             rows = []
  763             rows.append(['id', 'WWPN', 'WWNN', 'port_id', 'owning_node_id',
  764                          'current_node_id', 'nportid', 'host_io_permitted',
  765                          'virtualized'])
  766 
  767             if ':' in kwargs['filtervalue']:
  768                 filter1 = kwargs['filtervalue'].split(':')[0]
  769                 filter2 = kwargs['filtervalue'].split(':')[1]
  770                 value1 = filter1.split('=')[1]
  771                 value2 = filter2.split('=')[1]
  772                 for v in ports:
  773                     if(six.text_type(v[5]) == value1 and six.text_type(
  774                             v[7]) == value2):
  775                         rows.append(v)
  776             else:
  777                 value = kwargs['filtervalue'].split('=')[1]
  778                 for v in ports:
  779                     if six.text_type(v[5]) == value:
  780                         rows.append(v)
  781         else:
  782             rows = ports
  783         return self._print_info_cmd(rows=rows, **kwargs)
  784 
  785     # Print mostly made-up stuff in the correct syntax
  786     def _cmd_lsportip(self, **kwargs):
  787         if self._next_cmd_error['lsportip'] == 'ip_no_config':
  788             self._next_cmd_error['lsportip'] = ''
  789             ip_addr1 = ''
  790             ip_addr2 = ''
  791             gw = ''
  792         else:
  793             ip_addr1 = '1.234.56.78'
  794             ip_addr2 = '1.234.56.79'
  795             ip_addr3 = '1.234.56.80'
  796             ip_addr4 = '1.234.56.81'
  797             gw = '1.234.56.1'
  798 
  799         rows = [None] * 17
  800         rows[0] = ['id', 'node_id', 'node_name', 'IP_address', 'mask',
  801                    'gateway', 'IP_address_6', 'prefix_6', 'gateway_6', 'MAC',
  802                    'duplex', 'state', 'speed', 'failover', 'link_state']
  803         rows[1] = ['1', '1', 'node1', ip_addr1, '255.255.255.0',
  804                    gw, '', '', '', '01:23:45:67:89:00', 'Full',
  805                    'online', '1Gb/s', 'no', 'active']
  806         rows[2] = ['1', '1', 'node1', '', '', '', '', '', '',
  807                    '01:23:45:67:89:00', 'Full', 'online', '1Gb/s', 'yes', '']
  808         rows[3] = ['2', '1', 'node1', ip_addr3, '255.255.255.0',
  809                    gw, '', '', '', '01:23:45:67:89:01', 'Full',
  810                    'configured', '1Gb/s', 'no', 'active']
  811         rows[4] = ['2', '1', 'node1', '', '', '', '', '', '',
  812                    '01:23:45:67:89:01', 'Full', 'unconfigured', '1Gb/s',
  813                    'yes', 'inactive']
  814         rows[5] = ['3', '1', 'node1', '', '', '', '', '', '', '', '',
  815                    'unconfigured', '', 'no', '']
  816         rows[6] = ['3', '1', 'node1', '', '', '', '', '', '', '', '',
  817                    'unconfigured', '', 'yes', '']
  818         rows[7] = ['4', '1', 'node1', '', '', '', '', '', '', '', '',
  819                    'unconfigured', '', 'no', '']
  820         rows[8] = ['4', '1', 'node1', '', '', '', '', '', '', '', '',
  821                    'unconfigured', '', 'yes', '']
  822         rows[9] = ['1', '2', 'node2', ip_addr2, '255.255.255.0',
  823                    gw, '', '', '', '01:23:45:67:89:02', 'Full',
  824                    'online', '1Gb/s', 'no', '']
  825         rows[10] = ['1', '2', 'node2', '', '', '', '', '', '',
  826                     '01:23:45:67:89:02', 'Full', 'online', '1Gb/s', 'yes', '']
  827         rows[11] = ['2', '2', 'node2', ip_addr4, '255.255.255.0',
  828                     gw, '', '', '', '01:23:45:67:89:03', 'Full',
  829                     'configured', '1Gb/s', 'no', 'inactive']
  830         rows[12] = ['2', '2', 'node2', '', '', '', '', '', '',
  831                     '01:23:45:67:89:03', 'Full', 'unconfigured', '1Gb/s',
  832                     'yes', '']
  833         rows[13] = ['3', '2', 'node2', '', '', '', '', '', '', '', '',
  834                     'unconfigured', '', 'no', '']
  835         rows[14] = ['3', '2', 'node2', '', '', '', '', '', '', '', '',
  836                     'unconfigured', '', 'yes', '']
  837         rows[15] = ['4', '2', 'node2', '', '', '', '', '', '', '', '',
  838                     'unconfigured', '', 'no', '']
  839         rows[16] = ['4', '2', 'node2', '', '', '', '', '', '', '', '',
  840                     'unconfigured', '', 'yes', '']
  841 
  842         if self._next_cmd_error['lsportip'] == 'header_mismatch':
  843             rows[0].pop(2)
  844             self._next_cmd_error['lsportip'] = ''
  845         if self._next_cmd_error['lsportip'] == 'remove_field':
  846             for row in rows:
  847                 row.pop(1)
  848             self._next_cmd_error['lsportip'] = ''
  849 
  850         return self._print_info_cmd(rows=rows, **kwargs)
  851 
  852     def _cmd_lsfabric(self, **kwargs):
  853         if self._next_cmd_error['lsfabric'] == 'no_hosts':
  854             return ('', '')
  855         host_name = kwargs['host'].strip('\'\"') if 'host' in kwargs else None
  856         target_wwpn = kwargs['wwpn'] if 'wwpn' in kwargs else None
  857         host_infos = []
  858         for hv in self._hosts_list.values():
  859             if (not host_name) or (hv['host_name'] == host_name):
  860                 if not target_wwpn or target_wwpn in hv['wwpns']:
  861                     host_infos.append(hv)
  862                     break
  863         if not len(host_infos):
  864             return ('', '')
  865         rows = []
  866         rows.append(['remote_wwpn', 'remote_nportid', 'id', 'node_name',
  867                      'local_wwpn', 'local_port', 'local_nportid', 'state',
  868                      'name', 'cluster_name', 'type'])
  869         for host_info in host_infos:
  870             for wwpn in host_info['wwpns']:
  871                 rows.append([wwpn, '123456', host_info['id'], 'nodeN',
  872                              'AABBCCDDEEFF0011', '1', '0123ABC', 'active',
  873                              host_info['host_name'], '', 'host'])
  874         if self._next_cmd_error['lsfabric'] == 'header_mismatch':
  875             rows[0].pop(0)
  876             self._next_cmd_error['lsfabric'] = ''
  877         if self._next_cmd_error['lsfabric'] == 'remove_field':
  878             for row in rows:
  879                 row.pop(0)
  880             self._next_cmd_error['lsfabric'] = ''
  881         if self._next_cmd_error['lsfabric'] == 'remove_rows':
  882             rows = []
  883         return self._print_info_cmd(rows=rows, **kwargs)
  884 
  885     # Create a vdisk
  886     def _cmd_mkvdisk(self, **kwargs):
  887         # We only save the id/uid, name, and size - all else will be made up
  888         volume_info = {}
  889         volume_info['id'] = self._find_unused_id(self._volumes_list)
  890         volume_info['uid'] = ('ABCDEF' * 3) + ('0' * 14) + volume_info['id']
  891 
  892         mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
  893         sec_pool = None
  894         is_mirror_vol = False
  895         if 'copies' in kwargs:
  896             # it is a mirror volume
  897             pool_split = mdiskgrp.split(':')
  898             if len(pool_split) != 2:
  899                 raise exception.InvalidInput(
  900                     reason=_('mdiskgrp %s is invalid for mirror '
  901                              'volume') % kwargs['mdiskgrp'])
  902             else:
  903                 is_mirror_vol = True
  904                 mdiskgrp = pool_split[0]
  905                 sec_pool = pool_split[1]
  906 
  907         if mdiskgrp == kwargs['mdiskgrp']:
  908             raise exception.InvalidInput(
  909                 reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
  910         mdiskgrp_id = self._get_mdiskgrp_id(mdiskgrp)
  911         sec_pool_id = self._get_mdiskgrp_id(sec_pool)
  912         volume_info['mdisk_grp_name'] = mdiskgrp
  913         volume_info['mdisk_grp_id'] = str(mdiskgrp_id)
  914 
  915         if 'name' in kwargs:
  916             volume_info['name'] = kwargs['name'].strip('\'\"')
  917         else:
  918             volume_info['name'] = 'vdisk' + volume_info['id']
  919 
  920         # Assume size and unit are given, store it in bytes
  921         capacity = int(kwargs['size'])
  922         unit = kwargs['unit']
  923         volume_info['capacity'] = self._convert_units_bytes(capacity, unit)
  924         volume_info['IO_group_id'] = kwargs['iogrp']
  925         volume_info['IO_group_name'] = 'io_grp%s' % kwargs['iogrp']
  926         volume_info['RC_name'] = ''
  927         volume_info['RC_id'] = ''
  928 
  929         if 'easytier' in kwargs:
  930             if kwargs['easytier'] == 'on':
  931                 volume_info['easy_tier'] = 'on'
  932             else:
  933                 volume_info['easy_tier'] = 'off'
  934 
  935         if 'rsize' in kwargs:
  936             volume_info['formatted'] = 'no'
  937             # Fake numbers
  938             volume_info['used_capacity'] = '786432'
  939             volume_info['real_capacity'] = '21474816'
  940             volume_info['free_capacity'] = '38219264'
  941             if 'warning' in kwargs:
  942                 volume_info['warning'] = kwargs['warning'].rstrip('%')
  943             else:
  944                 volume_info['warning'] = '80'
  945             if 'autoexpand' in kwargs:
  946                 volume_info['autoexpand'] = 'on'
  947             else:
  948                 volume_info['autoexpand'] = 'off'
  949             if 'grainsize' in kwargs:
  950                 volume_info['grainsize'] = kwargs['grainsize']
  951             else:
  952                 volume_info['grainsize'] = '32'
  953             if 'compressed' in kwargs:
  954                 volume_info['compressed_copy'] = 'yes'
  955             else:
  956                 volume_info['compressed_copy'] = 'no'
  957         else:
  958             volume_info['used_capacity'] = volume_info['capacity']
  959             volume_info['real_capacity'] = volume_info['capacity']
  960             volume_info['free_capacity'] = '0'
  961             volume_info['warning'] = ''
  962             volume_info['autoexpand'] = ''
  963             volume_info['grainsize'] = ''
  964             volume_info['compressed_copy'] = 'no'
  965             volume_info['formatted'] = 'yes'
  966             if 'nofmtdisk' in kwargs:
  967                 if kwargs['nofmtdisk']:
  968                     volume_info['formatted'] = 'no'
  969 
  970         vol_cp = {'id': '0',
  971                   'status': 'online',
  972                   'sync': 'yes',
  973                   'primary': 'yes',
  974                   'mdisk_grp_id': str(mdiskgrp_id),
  975                   'mdisk_grp_name': mdiskgrp,
  976                   'easy_tier': (volume_info[
  977                       'easy_tier'] if 'easy_tier' in volume_info else 'on'),
  978                   'compressed_copy': volume_info['compressed_copy']}
  979         volume_info['copies'] = {'0': vol_cp}
  980         if is_mirror_vol:
  981             vol_cp1 = {'id': '1',
  982                        'status': 'online',
  983                        'sync': 'yes',
  984                        'primary': 'no',
  985                        'mdisk_grp_id': str(sec_pool_id),
  986                        'mdisk_grp_name': sec_pool,
  987                        'easy_tier': (volume_info['easy_tier']
  988                                      if 'easy_tier' in volume_info else 'on'),
  989                        'compressed_copy': volume_info['compressed_copy']}
  990             volume_info['copies']['1'] = vol_cp1
  991 
  992         if volume_info['name'] in self._volumes_list:
  993             return self._errors['CMMVC6035E']
  994         else:
  995             self._volumes_list[volume_info['name']] = volume_info
  996             return ('Virtual Disk, id [%s], successfully created' %
  997                     (volume_info['id']), '')
  998 
  999     # Delete a vdisk
 1000     def _cmd_rmvdisk(self, **kwargs):
 1001         force = True if 'force' in kwargs else False
 1002 
 1003         if 'force' not in kwargs and 'force_unmap' in kwargs:
 1004             force_unmap = True
 1005         else:
 1006             force_unmap = False
 1007 
 1008         if 'obj' not in kwargs:
 1009             return self._errors['CMMVC5701E']
 1010         vol_name = kwargs['obj'].strip('\'\"')
 1011 
 1012         if vol_name not in self._volumes_list:
 1013             return self._errors['CMMVC5753E']
 1014 
 1015         if not force and not force_unmap:
 1016             for mapping in self._mappings_list.values():
 1017                 if mapping['vol'] == vol_name:
 1018                     return self._errors['CMMVC5840E']
 1019             for fcmap in self._fcmappings_list.values():
 1020                 if ((fcmap['source'] == vol_name) or
 1021                         (fcmap['target'] == vol_name)):
 1022                     return self._errors['CMMVC5840E']
 1023 
 1024         del self._volumes_list[vol_name]
 1025         return ('', '')
 1026 
 1027     def _cmd_expandvdisksize(self, **kwargs):
 1028         if 'obj' not in kwargs:
 1029             return self._errors['CMMVC5701E']
 1030         vol_name = kwargs['obj'].strip('\'\"')
 1031 
 1032         # Assume unit is gb
 1033         if 'size' not in kwargs:
 1034             return self._errors['CMMVC5707E']
 1035         size = int(kwargs['size'])
 1036 
 1037         if vol_name not in self._volumes_list:
 1038             return self._errors['CMMVC5753E']
 1039 
 1040         curr_size = int(self._volumes_list[vol_name]['capacity'])
 1041         addition = size * units.Gi
 1042         self._volumes_list[vol_name]['capacity'] = (
 1043             six.text_type(curr_size + addition))
 1044         return ('', '')
 1045 
 1046     def _get_fcmap_info(self, vol_name):
 1047         ret_vals = {
 1048             'fc_id': '',
 1049             'fc_name': '',
 1050             'fc_map_count': '0',
 1051         }
 1052         for fcmap in self._fcmappings_list.values():
 1053             if ((fcmap['source'] == vol_name) or
 1054                     (fcmap['target'] == vol_name)):
 1055                 ret_vals['fc_id'] = fcmap['id']
 1056                 ret_vals['fc_name'] = fcmap['name']
 1057                 ret_vals['fc_map_count'] = '1'
 1058         return ret_vals
 1059 
 1060     # List information about vdisks
 1061     def _cmd_lsvdisk(self, **kwargs):
 1062         rows = []
 1063         rows.append(['id', 'name', 'IO_group_id', 'IO_group_name',
 1064                      'status', 'mdisk_grp_id', 'mdisk_grp_name',
 1065                      'capacity', 'type', 'FC_id', 'FC_name', 'RC_id',
 1066                      'RC_name', 'vdisk_UID', 'fc_map_count', 'copy_count',
 1067                      'fast_write_state', 'se_copy_count', 'RC_change'])
 1068 
 1069         for vol in self._volumes_list.values():
 1070             if (('filtervalue' not in kwargs) or
 1071                (kwargs['filtervalue'] == 'name=' + vol['name']) or
 1072                (kwargs['filtervalue'] == 'vdisk_UID=' + vol['uid'])):
 1073                 fcmap_info = self._get_fcmap_info(vol['name'])
 1074 
 1075                 if 'bytes' in kwargs:
 1076                     cap = self._convert_bytes_units(vol['capacity'])
 1077                 else:
 1078                     cap = vol['capacity']
 1079                 rows.append([six.text_type(vol['id']), vol['name'],
 1080                              vol['IO_group_id'],
 1081                              vol['IO_group_name'], 'online', '0',
 1082                              _get_test_pool(),
 1083                              cap, 'striped',
 1084                              fcmap_info['fc_id'], fcmap_info['fc_name'],
 1085                              '', '', vol['uid'],
 1086                              fcmap_info['fc_map_count'], '1', 'empty',
 1087                              '1', 'no'])
 1088         if 'obj' not in kwargs:
 1089             return self._print_info_cmd(rows=rows, **kwargs)
 1090         else:
 1091             if kwargs['obj'] not in self._volumes_list:
 1092                 return self._errors['CMMVC5754E']
 1093             vol = self._volumes_list[kwargs['obj']]
 1094             fcmap_info = self._get_fcmap_info(vol['name'])
 1095             cap = vol['capacity']
 1096             cap_u = vol['used_capacity']
 1097             cap_r = vol['real_capacity']
 1098             cap_f = vol['free_capacity']
 1099             if 'bytes' not in kwargs:
 1100                 for item in [cap, cap_u, cap_r, cap_f]:
 1101                     item = self._convert_bytes_units(item)
 1102             rows = []
 1103 
 1104             rows.append(['id', six.text_type(vol['id'])])
 1105             rows.append(['name', vol['name']])
 1106             rows.append(['IO_group_id', vol['IO_group_id']])
 1107             rows.append(['IO_group_name', vol['IO_group_name']])
 1108             rows.append(['status', 'online'])
 1109             rows.append(['capacity', cap])
 1110             rows.append(['formatted', vol['formatted']])
 1111             rows.append(['mdisk_id', ''])
 1112             rows.append(['mdisk_name', ''])
 1113             rows.append(['FC_id', fcmap_info['fc_id']])
 1114             rows.append(['FC_name', fcmap_info['fc_name']])
 1115             rows.append(['RC_id', vol['RC_id']])
 1116             rows.append(['RC_name', vol['RC_name']])
 1117             rows.append(['vdisk_UID', vol['uid']])
 1118             rows.append(['throttling', '0'])
 1119 
 1120             if self._next_cmd_error['lsvdisk'] == 'blank_pref_node':
 1121                 rows.append(['preferred_node_id', ''])
 1122                 self._next_cmd_error['lsvdisk'] = ''
 1123             elif self._next_cmd_error['lsvdisk'] == 'no_pref_node':
 1124                 self._next_cmd_error['lsvdisk'] = ''
 1125             else:
 1126                 rows.append(['preferred_node_id', '1'])
 1127             rows.append(['fast_write_state', 'empty'])
 1128             rows.append(['cache', 'readwrite'])
 1129             rows.append(['udid', ''])
 1130             rows.append(['fc_map_count', fcmap_info['fc_map_count']])
 1131             rows.append(['sync_rate', '50'])
 1132             rows.append(['copy_count', '1'])
 1133             rows.append(['se_copy_count', '0'])
 1134             rows.append(['mirror_write_priority', 'latency'])
 1135             rows.append(['RC_change', 'no'])
 1136 
 1137             for copy in vol['copies'].values():
 1138                 rows.append(['copy_id', copy['id']])
 1139                 rows.append(['status', copy['status']])
 1140                 rows.append(['primary', copy['primary']])
 1141                 rows.append(['mdisk_grp_id', copy['mdisk_grp_id']])
 1142                 rows.append(['mdisk_grp_name', copy['mdisk_grp_name']])
 1143                 rows.append(['type', 'striped'])
 1144                 rows.append(['used_capacity', cap_u])
 1145                 rows.append(['real_capacity', cap_r])
 1146                 rows.append(['free_capacity', cap_f])
 1147                 rows.append(['easy_tier', copy['easy_tier']])
 1148                 rows.append(['compressed_copy', copy['compressed_copy']])
 1149                 rows.append(['autoexpand', vol['autoexpand']])
 1150                 rows.append(['warning', vol['warning']])
 1151                 rows.append(['grainsize', vol['grainsize']])
 1152 
 1153             if 'nohdr' in kwargs:
 1154                 for index in range(len(rows)):
 1155                     rows[index] = ' '.join(rows[index][1:])
 1156 
 1157             if 'delim' in kwargs:
 1158                 for index in range(len(rows)):
 1159                     rows[index] = kwargs['delim'].join(rows[index])
 1160             return ('%s' % '\n'.join(rows), '')
 1161 
 1162     def _cmd_lsiogrp(self, **kwargs):
 1163         rows = [None] * 6
 1164         rows[0] = ['id', 'name', 'node_count', 'vdisk_count', 'host_count']
 1165         rows[1] = ['0', 'io_grp0', '2', '0', '4']
 1166         rows[2] = ['1', 'io_grp1', '2', '0', '4']
 1167         rows[3] = ['2', 'io_grp2', '0', '0', '4']
 1168         rows[4] = ['3', 'io_grp3', '0', '0', '4']
 1169         rows[5] = ['4', 'recovery_io_grp', '0', '0', '0']
 1170         return self._print_info_cmd(rows=rows, **kwargs)
 1171 
 1172     def _add_port_to_host(self, host_info, **kwargs):
 1173         if 'iscsiname' in kwargs:
 1174             added_key = 'iscsi_names'
 1175             added_val = kwargs['iscsiname'].strip('\'\"')
 1176         elif 'hbawwpn' in kwargs:
 1177             added_key = 'wwpns'
 1178             added_val = kwargs['hbawwpn'].strip('\'\"')
 1179         else:
 1180             return self._errors['CMMVC5707E']
 1181 
 1182         host_info[added_key].append(added_val)
 1183 
 1184         for v in self._hosts_list.values():
 1185             if v['id'] == host_info['id']:
 1186                 continue
 1187             for port in v[added_key]:
 1188                 if port == added_val:
 1189                     return self._errors['CMMVC6581E']
 1190         return ('', '')
 1191 
 1192     # Make a host
 1193     def _cmd_mkhost(self, **kwargs):
 1194         host_info = {}
 1195         host_info['id'] = self._find_unused_id(self._hosts_list)
 1196 
 1197         if 'name' in kwargs:
 1198             host_name = kwargs['name'].strip('\'\"')
 1199         else:
 1200             host_name = 'host' + six.text_type(host_info['id'])
 1201 
 1202         if self._is_invalid_name(host_name):
 1203             return self._errors['CMMVC6527E']
 1204 
 1205         if host_name in self._hosts_list:
 1206             return self._errors['CMMVC6035E']
 1207 
 1208         host_info['host_name'] = host_name
 1209         host_info['iscsi_names'] = []
 1210         host_info['wwpns'] = []
 1211 
 1212         if 'site' in kwargs:
 1213             host_info['site_name'] = kwargs['site'].strip('\'\"')
 1214         else:
 1215             host_info['site_name'] = ''
 1216         out, err = self._add_port_to_host(host_info, **kwargs)
 1217         if not len(err):
 1218             self._hosts_list[host_name] = host_info
 1219             return ('Host, id [%s], successfully created' %
 1220                     (host_info['id']), '')
 1221         else:
 1222             return (out, err)
 1223 
 1224     # Add ports to an existing host
 1225     def _cmd_addhostport(self, **kwargs):
 1226         if 'obj' not in kwargs:
 1227             return self._errors['CMMVC5701E']
 1228         host_name = kwargs['obj'].strip('\'\"')
 1229 
 1230         if host_name not in self._hosts_list:
 1231             return self._errors['CMMVC5753E']
 1232 
 1233         host_info = self._hosts_list[host_name]
 1234         return self._add_port_to_host(host_info, **kwargs)
 1235 
 1236     # Change host properties
 1237     def _cmd_chhost(self, **kwargs):
 1238         if 'obj' not in kwargs:
 1239             return self._errors['CMMVC5701E']
 1240         host_name = kwargs['obj'].strip('\'\"')
 1241 
 1242         if host_name not in self._hosts_list:
 1243             return self._errors['CMMVC5753E']
 1244 
 1245         if 'chapsecret' in kwargs:
 1246             secret = kwargs['chapsecret'].strip('\'\"')
 1247             self._hosts_list[host_name]['chapsecret'] = secret
 1248 
 1249         if 'site' in kwargs:
 1250             site_name = kwargs['site'].strip('\'\"')
 1251             self._hosts_list[host_name]['site_name'] = site_name
 1252 
 1253         if 'chapsecret' not in kwargs and 'site' not in kwargs:
 1254             return self._errors['CMMVC5707E']
 1255 
 1256         return ('', '')
 1257 
 1258     # Remove a host
 1259     def _cmd_rmhost(self, **kwargs):
 1260         if 'obj' not in kwargs:
 1261             return self._errors['CMMVC5701E']
 1262 
 1263         host_name = kwargs['obj'].strip('\'\"')
 1264         if host_name not in self._hosts_list:
 1265             return self._errors['CMMVC5753E']
 1266 
 1267         for v in self._mappings_list.values():
 1268             if (v['host'] == host_name):
 1269                 return self._errors['CMMVC5871E']
 1270 
 1271         del self._hosts_list[host_name]
 1272         return ('', '')
 1273 
 1274     # List information about hosts
 1275     def _cmd_lshost(self, **kwargs):
 1276         if 'obj' not in kwargs:
 1277             rows = []
 1278             rows.append(['id', 'name', 'port_count', 'iogrp_count',
 1279                          'status', 'site_name'])
 1280 
 1281             found = False
 1282             # Sort hosts by names to give predictable order for tests
 1283             # depend on it.
 1284             for host_name in sorted(self._hosts_list.keys()):
 1285                 host = self._hosts_list[host_name]
 1286                 filterstr = 'name=' + host['host_name']
 1287                 if (('filtervalue' not in kwargs) or
 1288                         (kwargs['filtervalue'] == filterstr)):
 1289                     rows.append([host['id'], host['host_name'], '1', '4',
 1290                                 'offline', host['site_name']])
 1291                     found = True
 1292             if found:
 1293                 return self._print_info_cmd(rows=rows, **kwargs)
 1294             else:
 1295                 return ('', '')
 1296         else:
 1297             if self._next_cmd_error['lshost'] == 'missing_host':
 1298                 self._next_cmd_error['lshost'] = ''
 1299                 return self._errors['CMMVC5754E']
 1300             elif self._next_cmd_error['lshost'] == 'bigger_troubles':
 1301                 return self._errors['CMMVC6527E']
 1302             host_name = kwargs['obj'].strip('\'\"')
 1303             if host_name not in self._hosts_list:
 1304                 return self._errors['CMMVC5754E']
 1305             if (self._next_cmd_error['lshost'] == 'fail_fastpath' and
 1306                     host_name == 'DifferentHost'):
 1307                 return self._errors['CMMVC5701E']
 1308             host = self._hosts_list[host_name]
 1309             rows = []
 1310             rows.append(['id', host['id']])
 1311             rows.append(['name', host['host_name']])
 1312             rows.append(['port_count', '1'])
 1313             rows.append(['type', 'generic'])
 1314             rows.append(['mask', '1111'])
 1315             rows.append(['iogrp_count', '4'])
 1316             rows.append(['status', 'online'])
 1317             rows.append(['site_name', host['site_name']])
 1318             for port in host['iscsi_names']:
 1319                 rows.append(['iscsi_name', port])
 1320                 rows.append(['node_logged_in_count', '0'])
 1321                 rows.append(['state', 'offline'])
 1322             for port in host['wwpns']:
 1323                 rows.append(['WWPN', port])
 1324                 rows.append(['node_logged_in_count', '0'])
 1325                 rows.append(['state', 'active'])
 1326 
 1327             if 'nohdr' in kwargs:
 1328                 for index in range(len(rows)):
 1329                     rows[index] = ' '.join(rows[index][1:])
 1330 
 1331             if 'delim' in kwargs:
 1332                 for index in range(len(rows)):
 1333                     rows[index] = kwargs['delim'].join(rows[index])
 1334 
 1335             return ('%s' % '\n'.join(rows), '')
 1336 
 1337     # List iSCSI authorization information about hosts
 1338     def _cmd_lsiscsiauth(self, **kwargs):
 1339         if self._next_cmd_error['lsiscsiauth'] == 'no_info':
 1340             self._next_cmd_error['lsiscsiauth'] = ''
 1341             return ('', '')
 1342         rows = []
 1343         rows.append(['type', 'id', 'name', 'iscsi_auth_method',
 1344                      'iscsi_chap_secret'])
 1345 
 1346         for host in self._hosts_list.values():
 1347             method = 'none'
 1348             secret = ''
 1349             if 'chapsecret' in host:
 1350                 method = 'chap'
 1351                 secret = host['chapsecret']
 1352             rows.append(['host', host['id'], host['host_name'], method,
 1353                          secret])
 1354         return self._print_info_cmd(rows=rows, **kwargs)
 1355 
 1356     # Create a vdisk-host mapping
 1357     def _cmd_mkvdiskhostmap(self, **kwargs):
 1358         mapping_info = {}
 1359         mapping_info['id'] = self._find_unused_id(self._mappings_list)
 1360         if 'host' not in kwargs:
 1361             return self._errors['CMMVC5707E']
 1362         mapping_info['host'] = kwargs['host'].strip('\'\"')
 1363 
 1364         if 'scsi' in kwargs:
 1365             mapping_info['lun'] = kwargs['scsi'].strip('\'\"')
 1366         else:
 1367             mapping_info['lun'] = mapping_info['id']
 1368 
 1369         if 'obj' not in kwargs:
 1370             return self._errors['CMMVC5707E']
 1371         mapping_info['vol'] = kwargs['obj'].strip('\'\"')
 1372 
 1373         if mapping_info['vol'] not in self._volumes_list:
 1374             return self._errors['CMMVC5753E']
 1375 
 1376         if mapping_info['host'] not in self._hosts_list:
 1377             return self._errors['CMMVC5754E']
 1378 
 1379         if mapping_info['vol'] in self._mappings_list:
 1380             return self._errors['CMMVC6071E']
 1381 
 1382         for v in self._mappings_list.values():
 1383             if ((v['host'] == mapping_info['host']) and
 1384                     (v['lun'] == mapping_info['lun'])):
 1385                 return self._errors['CMMVC5879E']
 1386 
 1387         for v in self._mappings_list.values():
 1388             if (v['vol'] == mapping_info['vol']) and ('force' not in kwargs):
 1389                 return self._errors['CMMVC6071E']
 1390 
 1391         self._mappings_list[mapping_info['id']] = mapping_info
 1392         return ('Virtual Disk to Host map, id [%s], successfully created'
 1393                 % (mapping_info['id']), '')
 1394 
 1395     # Delete a vdisk-host mapping
 1396     def _cmd_rmvdiskhostmap(self, **kwargs):
 1397         if 'host' not in kwargs:
 1398             return self._errors['CMMVC5707E']
 1399         host = kwargs['host'].strip('\'\"')
 1400 
 1401         if 'obj' not in kwargs:
 1402             return self._errors['CMMVC5701E']
 1403         vol = kwargs['obj'].strip('\'\"')
 1404 
 1405         mapping_ids = []
 1406         for v in self._mappings_list.values():
 1407             if v['vol'] == vol:
 1408                 mapping_ids.append(v['id'])
 1409         if not mapping_ids:
 1410             return self._errors['CMMVC5753E']
 1411 
 1412         this_mapping = None
 1413         for mapping_id in mapping_ids:
 1414             if self._mappings_list[mapping_id]['host'] == host:
 1415                 this_mapping = mapping_id
 1416         if this_mapping is None:
 1417             return self._errors['CMMVC5753E']
 1418 
 1419         del self._mappings_list[this_mapping]
 1420         return ('', '')
 1421 
 1422     # List information about host->vdisk mappings
 1423     def _cmd_lshostvdiskmap(self, **kwargs):
 1424         host_name = kwargs['obj'].strip('\'\"')
 1425 
 1426         if host_name not in self._hosts_list:
 1427             return self._errors['CMMVC5754E']
 1428 
 1429         rows = []
 1430         rows.append(['id', 'name', 'SCSI_id', 'vdisk_id', 'vdisk_name',
 1431                      'vdisk_UID'])
 1432 
 1433         for mapping in self._mappings_list.values():
 1434             if (host_name == '') or (mapping['host'] == host_name):
 1435                 volume = self._volumes_list[mapping['vol']]
 1436                 rows.append([mapping['id'], mapping['host'],
 1437                             mapping['lun'], volume['id'],
 1438                             volume['name'], volume['uid']])
 1439 
 1440         return self._print_info_cmd(rows=rows, **kwargs)
 1441 
 1442     # List information about vdisk->host mappings
 1443     def _cmd_lsvdiskhostmap(self, **kwargs):
 1444         mappings_found = 0
 1445         vdisk_name = kwargs['obj'].strip('\'\"')
 1446 
 1447         if vdisk_name not in self._volumes_list:
 1448             return self._errors['CMMVC5753E']
 1449 
 1450         rows = []
 1451         rows.append(['id name', 'SCSI_id', 'host_id', 'host_name', 'vdisk_UID',
 1452                      'IO_group_id', 'IO_group_name'])
 1453 
 1454         for mapping in self._mappings_list.values():
 1455             if (mapping['vol'] == vdisk_name):
 1456                 mappings_found += 1
 1457                 volume = self._volumes_list[mapping['vol']]
 1458                 host = self._hosts_list[mapping['host']]
 1459                 rows.append([volume['id'], mapping['lun'], host['id'],
 1460                             host['host_name'], volume['uid'],
 1461                             volume['IO_group_id'], volume['IO_group_name']])
 1462 
 1463         if mappings_found:
 1464             return self._print_info_cmd(rows=rows, **kwargs)
 1465         else:
 1466             return ('', '')
 1467 
 1468     # Create a FlashCopy mapping
 1469     def _cmd_mkfcmap(self, **kwargs):
 1470         source = ''
 1471         target = ''
 1472         copyrate = kwargs['copyrate'] if 'copyrate' in kwargs else '50'
 1473 
 1474         if 'source' not in kwargs:
 1475             return self._errors['CMMVC5707E']
 1476         source = kwargs['source'].strip('\'\"')
 1477         if source not in self._volumes_list:
 1478             return self._errors['CMMVC5754E']
 1479 
 1480         if 'target' not in kwargs:
 1481             return self._errors['CMMVC5707E']
 1482         target = kwargs['target'].strip('\'\"')
 1483         if target not in self._volumes_list:
 1484             return self._errors['CMMVC5754E']
 1485 
 1486         if source == target:
 1487             return self._errors['CMMVC6303E']
 1488 
 1489         if (self._volumes_list[source]['capacity'] !=
 1490                 self._volumes_list[target]['capacity']):
 1491             return self._errors['CMMVC5754E']
 1492 
 1493         fcmap_info = {}
 1494         fcmap_info['source'] = source
 1495         fcmap_info['target'] = target
 1496         fcmap_info['id'] = self._find_unused_id(self._fcmappings_list)
 1497         fcmap_info['name'] = 'fcmap' + fcmap_info['id']
 1498         fcmap_info['copyrate'] = copyrate
 1499         fcmap_info['progress'] = '0'
 1500         fcmap_info['autodelete'] = True if 'autodelete' in kwargs else False
 1501         fcmap_info['status'] = 'idle_or_copied'
 1502         fcmap_info['rc_controlled'] = 'no'
 1503 
 1504         # Add fcmap to consistency group
 1505         if 'consistgrp' in kwargs:
 1506             consistgrp = kwargs['consistgrp']
 1507 
 1508             # if is digit, assume is cg id, else is cg name
 1509             cg_id = 0
 1510             if not consistgrp.isdigit():
 1511                 for consistgrp_key in self._fcconsistgrp_list.keys():
 1512                     if (self._fcconsistgrp_list[consistgrp_key]['name']
 1513                             == consistgrp):
 1514                         cg_id = consistgrp_key
 1515                         fcmap_info['consistgrp'] = consistgrp_key
 1516                         break
 1517             else:
 1518                 if int(consistgrp) in self._fcconsistgrp_list.keys():
 1519                     cg_id = int(consistgrp)
 1520 
 1521             # If can't find exist consistgrp id, return not exist error
 1522             if not cg_id:
 1523                 return self._errors['CMMVC5754E']
 1524 
 1525             fcmap_info['consistgrp'] = cg_id
 1526             # Add fcmap to consistgrp
 1527             self._fcconsistgrp_list[cg_id]['fcmaps'][fcmap_info['id']] = (
 1528                 fcmap_info['name'])
 1529             self._fc_cg_state_transition('add',
 1530                                          self._fcconsistgrp_list[cg_id])
 1531 
 1532         self._fcmappings_list[fcmap_info['id']] = fcmap_info
 1533 
 1534         return('FlashCopy Mapping, id [' + fcmap_info['id'] +
 1535                '], successfully created', '')
 1536 
 1537     def _cmd_prestartfcmap(self, **kwargs):
 1538         if 'obj' not in kwargs:
 1539             return self._errors['CMMVC5701E']
 1540         id_num = kwargs['obj']
 1541 
 1542         if self._next_cmd_error['prestartfcmap'] == 'bad_id':
 1543             id_num = -1
 1544             self._next_cmd_error['prestartfcmap'] = ''
 1545 
 1546         try:
 1547             fcmap = self._fcmappings_list[id_num]
 1548         except KeyError:
 1549             return self._errors['CMMVC5753E']
 1550 
 1551         return self._state_transition('prepare', fcmap)
 1552 
 1553     def _cmd_startfcmap(self, **kwargs):
 1554         if 'obj' not in kwargs:
 1555             return self._errors['CMMVC5701E']
 1556         id_num = kwargs['obj']
 1557 
 1558         if self._next_cmd_error['startfcmap'] == 'bad_id':
 1559             id_num = -1
 1560             self._next_cmd_error['startfcmap'] = ''
 1561 
 1562         try:
 1563             fcmap = self._fcmappings_list[id_num]
 1564         except KeyError:
 1565             return self._errors['CMMVC5753E']
 1566 
 1567         return self._state_transition('start', fcmap)
 1568 
 1569     def _cmd_stopfcmap(self, **kwargs):
 1570         if 'obj' not in kwargs:
 1571             return self._errors['CMMVC5701E']
 1572         id_num = kwargs['obj']
 1573 
 1574         try:
 1575             fcmap = self._fcmappings_list[id_num]
 1576         except KeyError:
 1577             return self._errors['CMMVC5753E']
 1578 
 1579         return self._state_transition('stop', fcmap)
 1580 
 1581     def _cmd_rmfcmap(self, **kwargs):
 1582         if 'obj' not in kwargs:
 1583             return self._errors['CMMVC5701E']
 1584         id_num = kwargs['obj']
 1585         force = True if 'force' in kwargs else False
 1586 
 1587         if self._next_cmd_error['rmfcmap'] == 'bad_id':
 1588             id_num = -1
 1589             self._next_cmd_error['rmfcmap'] = ''
 1590 
 1591         try:
 1592             fcmap = self._fcmappings_list[id_num]
 1593         except KeyError:
 1594             return self._errors['CMMVC5753E']
 1595 
 1596         function = 'delete_force' if force else 'delete'
 1597         ret = self._state_transition(function, fcmap)
 1598         if fcmap['status'] == 'end':
 1599             del self._fcmappings_list[id_num]
 1600         return ret
 1601 
 1602     def _cmd_lsvdiskfcmappings(self, **kwargs):
 1603         if 'obj' not in kwargs:
 1604             return self._errors['CMMVC5707E']
 1605         vdisk = kwargs['obj']
 1606         rows = []
 1607         rows.append(['id', 'name'])
 1608         for v in self._fcmappings_list.values():
 1609             if v['source'] == vdisk or v['target'] == vdisk:
 1610                 rows.append([v['id'], v['name']])
 1611         return self._print_info_cmd(rows=rows, **kwargs)
 1612 
 1613     def _cmd_chfcmap(self, **kwargs):
 1614         if 'obj' not in kwargs:
 1615             return self._errors['CMMVC5707E']
 1616         id_num = kwargs['obj']
 1617 
 1618         try:
 1619             fcmap = self._fcmappings_list[id_num]
 1620         except KeyError:
 1621             return self._errors['CMMVC5753E']
 1622 
 1623         for key in ['name', 'copyrate', 'autodelete']:
 1624             if key in kwargs:
 1625                 fcmap[key] = kwargs[key]
 1626         return ('', '')
 1627 
 1628     def _cmd_lsfcmap(self, **kwargs):
 1629         rows = []
 1630         rows.append(['id', 'name', 'source_vdisk_id', 'source_vdisk_name',
 1631                      'target_vdisk_id', 'target_vdisk_name', 'group_id',
 1632                      'group_name', 'status', 'progress', 'copy_rate',
 1633                      'clean_progress', 'incremental', 'partner_FC_id',
 1634                      'partner_FC_name', 'restoring', 'start_time',
 1635                      'rc_controlled'])
 1636 
 1637         # Assume we always get a filtervalue argument
 1638         filter_key = kwargs['filtervalue'].split('=')[0]
 1639         filter_value = kwargs['filtervalue'].split('=')[1]
 1640         to_delete = []
 1641         for k, v in self._fcmappings_list.items():
 1642             if six.text_type(v[filter_key]) == filter_value:
 1643                 source = self._volumes_list[v['source']]
 1644                 target = self._volumes_list[v['target']]
 1645                 self._state_transition('wait', v)
 1646 
 1647                 if self._next_cmd_error['lsfcmap'] == 'speed_up':
 1648                     self._next_cmd_error['lsfcmap'] = ''
 1649                     curr_state = v['status']
 1650                     while self._state_transition('wait', v) == ("", ""):
 1651                         if curr_state == v['status']:
 1652                             break
 1653                         curr_state = v['status']
 1654 
 1655                 if ((v['status'] == 'idle_or_copied' and v['autodelete'] and
 1656                      v['progress'] == '100') or (v['status'] == 'end')):
 1657                     to_delete.append(k)
 1658                 else:
 1659                     rows.append([v['id'], v['name'], source['id'],
 1660                                  source['name'], target['id'], target['name'],
 1661                                  '', '', v['status'], v['progress'],
 1662                                  v['copyrate'], '100', 'off', '', '', 'no', '',
 1663                                  v['rc_controlled']])
 1664 
 1665         for d in to_delete:
 1666             del self._fcmappings_list[d]
 1667 
 1668         return self._print_info_cmd(rows=rows, **kwargs)
 1669 
 1670     # Create a FlashCopy mapping
 1671     def _cmd_mkfcconsistgrp(self, **kwargs):
 1672         fcconsistgrp_info = {}
 1673         fcconsistgrp_info['id'] = self._find_unused_id(self._fcconsistgrp_list)
 1674 
 1675         if 'name' in kwargs:
 1676             fcconsistgrp_info['name'] = kwargs['name'].strip('\'\"')
 1677         else:
 1678             fcconsistgrp_info['name'] = 'fccstgrp' + fcconsistgrp_info['id']
 1679 
 1680         if 'autodelete' in kwargs:
 1681             fcconsistgrp_info['autodelete'] = True
 1682         else:
 1683             fcconsistgrp_info['autodelete'] = False
 1684         fcconsistgrp_info['status'] = 'empty'
 1685         fcconsistgrp_info['start_time'] = None
 1686         fcconsistgrp_info['fcmaps'] = {}
 1687 
 1688         self._fcconsistgrp_list[fcconsistgrp_info['id']] = fcconsistgrp_info
 1689 
 1690         return('FlashCopy Consistency Group, id [' + fcconsistgrp_info['id'] +
 1691                '], successfully created', '')
 1692 
 1693     def _cmd_prestartfcconsistgrp(self, **kwargs):
 1694         if 'obj' not in kwargs:
 1695             return self._errors['CMMVC5701E']
 1696         cg_name = kwargs['obj']
 1697 
 1698         cg_id = 0
 1699         for cg_id in self._fcconsistgrp_list.keys():
 1700             if cg_name == self._fcconsistgrp_list[cg_id]['name']:
 1701                 break
 1702 
 1703         return self._fc_cg_state_transition('prepare',
 1704                                             self._fcconsistgrp_list[cg_id])
 1705 
 1706     def _cmd_startfcconsistgrp(self, **kwargs):
 1707         if 'obj' not in kwargs:
 1708             return self._errors['CMMVC5701E']
 1709         cg_name = kwargs['obj']
 1710 
 1711         cg_id = 0
 1712         for cg_id in self._fcconsistgrp_list.keys():
 1713             if cg_name == self._fcconsistgrp_list[cg_id]['name']:
 1714                 break
 1715 
 1716         return self._fc_cg_state_transition('start',
 1717                                             self._fcconsistgrp_list[cg_id])
 1718 
 1719     def _cmd_stopfcconsistgrp(self, **kwargs):
 1720         if 'obj' not in kwargs:
 1721             return self._errors['CMMVC5701E']
 1722         id_num = kwargs['obj']
 1723 
 1724         try:
 1725             fcconsistgrps = self._fcconsistgrp_list[id_num]
 1726         except KeyError:
 1727             return self._errors['CMMVC5753E']
 1728 
 1729         return self._fc_cg_state_transition('stop', fcconsistgrps)
 1730 
 1731     def _cmd_rmfcconsistgrp(self, **kwargs):
 1732         if 'obj' not in kwargs:
 1733             return self._errors['CMMVC5701E']
 1734         cg_name = kwargs['obj']
 1735         force = True if 'force' in kwargs else False
 1736 
 1737         cg_id = 0
 1738         for cg_id in self._fcconsistgrp_list.keys():
 1739             if cg_name == self._fcconsistgrp_list[cg_id]['name']:
 1740                 break
 1741         if not cg_id:
 1742             return self._errors['CMMVC5753E']
 1743         fcconsistgrps = self._fcconsistgrp_list[cg_id]
 1744 
 1745         function = 'delete_force' if force else 'delete'
 1746         ret = self._fc_cg_state_transition(function, fcconsistgrps)
 1747         if fcconsistgrps['status'] == 'end':
 1748             del self._fcconsistgrp_list[cg_id]
 1749         return ret
 1750 
 1751     def _cmd_lsfcconsistgrp(self, **kwargs):
 1752         rows = []
 1753 
 1754         if 'obj' not in kwargs:
 1755             rows.append(['id', 'name', 'status' 'start_time'])
 1756 
 1757             for fcconsistgrp in self._fcconsistgrp_list.values():
 1758                 rows.append([fcconsistgrp['id'],
 1759                              fcconsistgrp['name'],
 1760                              fcconsistgrp['status'],
 1761                              fcconsistgrp['start_time']])
 1762             return self._print_info_cmd(rows=rows, **kwargs)
 1763         else:
 1764             fcconsistgrp = None
 1765             cg_id = 0
 1766             for cg_id in self._fcconsistgrp_list.keys():
 1767                 if self._fcconsistgrp_list[cg_id]['name'] == kwargs['obj']:
 1768                     fcconsistgrp = self._fcconsistgrp_list[cg_id]
 1769                     break
 1770             rows = []
 1771             rows.append(['id', six.text_type(cg_id)])
 1772             rows.append(['name', fcconsistgrp['name']])
 1773             rows.append(['status', fcconsistgrp['status']])
 1774             rows.append(['autodelete',
 1775                          six.text_type(fcconsistgrp['autodelete'])])
 1776             rows.append(['start_time',
 1777                          six.text_type(fcconsistgrp['start_time'])])
 1778 
 1779             for fcmap_id in fcconsistgrp['fcmaps'].keys():
 1780                 rows.append(['FC_mapping_id', six.text_type(fcmap_id)])
 1781                 rows.append(['FC_mapping_name',
 1782                              fcconsistgrp['fcmaps'][fcmap_id]])
 1783 
 1784             if 'delim' in kwargs:
 1785                 for index in range(len(rows)):
 1786                     rows[index] = kwargs['delim'].join(rows[index])
 1787             self._fc_cg_state_transition('wait', fcconsistgrp)
 1788             return ('%s' % '\n'.join(rows), '')
 1789 
 1790     def _cmd_migratevdisk(self, **kwargs):
 1791         if 'mdiskgrp' not in kwargs or 'vdisk' not in kwargs:
 1792             return self._errors['CMMVC5707E']
 1793         mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
 1794         vdisk = kwargs['vdisk'].strip('\'\"')
 1795         copy_id = kwargs['copy']
 1796         if vdisk not in self._volumes_list:
 1797             return self._errors['CMMVC5753E']
 1798         mdiskgrp_id = str(self._get_mdiskgrp_id(mdiskgrp))
 1799 
 1800         self._volumes_list[vdisk]['mdisk_grp_name'] = mdiskgrp
 1801         self._volumes_list[vdisk]['mdisk_grp_id'] = mdiskgrp_id
 1802 
 1803         vol = self._volumes_list[vdisk]
 1804         vol['copies'][copy_id]['mdisk_grp_name'] = mdiskgrp
 1805         vol['copies'][copy_id]['mdisk_grp_id'] = mdiskgrp_id
 1806         return ('', '')
 1807 
 1808     def _cmd_addvdiskcopy(self, **kwargs):
 1809         if 'obj' not in kwargs:
 1810             return self._errors['CMMVC5701E']
 1811         vol_name = kwargs['obj'].strip('\'\"')
 1812         if vol_name not in self._volumes_list:
 1813             return self._errors['CMMVC5753E']
 1814         vol = self._volumes_list[vol_name]
 1815         if 'mdiskgrp' not in kwargs:
 1816             return self._errors['CMMVC5707E']
 1817         mdiskgrp = kwargs['mdiskgrp'].strip('\'\"')
 1818         if mdiskgrp == kwargs['mdiskgrp']:
 1819             raise exception.InvalidInput(
 1820                 reason=_('mdiskgrp missing quotes %s') % kwargs['mdiskgrp'])
 1821         auto_del = True if 'autodelete' in kwargs else False
 1822 
 1823         copy_info = {}
 1824         copy_info['id'] = self._find_unused_id(vol['copies'])
 1825         copy_info['status'] = 'online'
 1826         copy_info['sync'] = 'no'
 1827         copy_info['primary'] = 'no'
 1828         copy_info['mdisk_grp_name'] = mdiskgrp
 1829         copy_info['mdisk_grp_id'] = str(self._get_mdiskgrp_id(mdiskgrp))
 1830 
 1831         if 'easytier' in kwargs:
 1832             if kwargs['easytier'] == 'on':
 1833                 copy_info['easy_tier'] = 'on'
 1834             else:
 1835                 copy_info['easy_tier'] = 'off'
 1836         if 'rsize' in kwargs:
 1837             if 'compressed' in kwargs:
 1838                 copy_info['compressed_copy'] = 'yes'
 1839             else:
 1840                 copy_info['compressed_copy'] = 'no'
 1841         vol['copies'][copy_info['id']] = copy_info
 1842         if auto_del:
 1843             del_copy_id = None
 1844             for v in vol['copies'].values():
 1845                 if v['id'] != copy_info['id']:
 1846                     del_copy_id = v['id']
 1847                     break
 1848             if del_copy_id:
 1849                 del vol['copies'][del_copy_id]
 1850         return ('Vdisk [%(vid)s] copy [%(cid)s] successfully created' %
 1851                 {'vid': vol['id'], 'cid': copy_info['id']}, '')
 1852 
 1853     def _cmd_lsvdiskcopy(self, **kwargs):
 1854         if 'obj' not in kwargs:
 1855             return self._errors['CMMVC5804E']
 1856         name = kwargs['obj']
 1857         vol = self._volumes_list[name]
 1858         rows = []
 1859         rows.append(['vdisk_id', 'vdisk_name', 'copy_id', 'status', 'sync',
 1860                      'primary', 'mdisk_grp_id', 'mdisk_grp_name', 'capacity',
 1861                      'type', 'se_copy', 'easy_tier', 'easy_tier_status',
 1862                      'compressed_copy'])
 1863         for copy in vol['copies'].values():
 1864             rows.append([vol['id'], vol['name'], copy['id'],
 1865                         copy['status'], copy['sync'], copy['primary'],
 1866                         copy['mdisk_grp_id'], copy['mdisk_grp_name'],
 1867                         vol['capacity'], 'striped', 'yes', copy['easy_tier'],
 1868                         'inactive', copy['compressed_copy']])
 1869         if 'copy' not in kwargs:
 1870             return self._print_info_cmd(rows=rows, **kwargs)
 1871         else:
 1872             copy_id = kwargs['copy'].strip('\'\"')
 1873             if copy_id not in vol['copies']:
 1874                 return self._errors['CMMVC6353E']
 1875             copy = vol['copies'][copy_id]
 1876             rows = []
 1877             rows.append(['vdisk_id', vol['id']])
 1878             rows.append(['vdisk_name', vol['name']])
 1879             rows.append(['capacity', vol['capacity']])
 1880             rows.append(['copy_id', copy['id']])
 1881             rows.append(['status', copy['status']])
 1882             rows.append(['sync', copy['sync']])
 1883             copy['sync'] = 'yes'
 1884             rows.append(['primary', copy['primary']])
 1885             rows.append(['mdisk_grp_id', copy['mdisk_grp_id']])
 1886             rows.append(['mdisk_grp_name', copy['mdisk_grp_name']])
 1887             rows.append(['easy_tier', copy['easy_tier']])
 1888             rows.append(['easy_tier_status', 'inactive'])
 1889             rows.append(['compressed_copy', copy['compressed_copy']])
 1890             rows.append(['autoexpand', vol['autoexpand']])
 1891 
 1892             if 'delim' in kwargs:
 1893                 for index in range(len(rows)):
 1894                     rows[index] = kwargs['delim'].join(rows[index])
 1895 
 1896             return ('%s' % '\n'.join(rows), '')
 1897 
 1898     def _cmd_rmvdiskcopy(self, **kwargs):
 1899         if 'obj' not in kwargs:
 1900             return self._errors['CMMVC5701E']
 1901         vol_name = kwargs['obj'].strip('\'\"')
 1902         if 'copy' not in kwargs:
 1903             return self._errors['CMMVC5707E']
 1904         copy_id = kwargs['copy'].strip('\'\"')
 1905         if vol_name not in self._volumes_list:
 1906             return self._errors['CMMVC5753E']
 1907         vol = self._volumes_list[vol_name]
 1908         if copy_id not in vol['copies']:
 1909             return self._errors['CMMVC6353E']
 1910         del vol['copies'][copy_id]
 1911 
 1912         return ('', '')
 1913 
 1914     def _cmd_lsvdisks_from_filter(self, filter_name, value):
 1915         volumes = []
 1916         if filter_name == 'mdisk_grp_name':
 1917             for vol in self._volumes_list:
 1918                 vol_info = self._volumes_list[vol]
 1919                 if vol_info['mdisk_grp_name'] == value:
 1920                     volumes.append(vol)
 1921         return volumes
 1922 
 1923     def _cmd_chvdisk(self, **kwargs):
 1924         if 'obj' not in kwargs:
 1925             return self._errors['CMMVC5701E']
 1926         vol_name = kwargs['obj'].strip('\'\"')
 1927         vol = self._volumes_list[vol_name]
 1928         kwargs.pop('obj')
 1929 
 1930         params = ['name', 'warning', 'udid',
 1931                   'autoexpand', 'easytier', 'primary']
 1932         for key, value in kwargs.items():
 1933             if key == 'easytier':
 1934                 vol['easy_tier'] = value
 1935                 for copy in vol['copies'].values():
 1936                     vol['copies'][copy['id']]['easy_tier'] = value
 1937                 continue
 1938             if key == 'warning':
 1939                 vol['warning'] = value.rstrip('%')
 1940                 continue
 1941             if key == 'name':
 1942                 vol['name'] = value
 1943                 del self._volumes_list[vol_name]
 1944                 self._volumes_list[value] = vol
 1945             if key == 'primary':
 1946                 if value == '0':
 1947                     self._volumes_list[vol_name]['copies']['0']['primary']\
 1948                         = 'yes'
 1949                     self._volumes_list[vol_name]['copies']['1']['primary']\
 1950                         = 'no'
 1951                 elif value == '1':
 1952                     self._volumes_list[vol_name]['copies']['0']['primary']\
 1953                         = 'no'
 1954                     self._volumes_list[vol_name]['copies']['1']['primary']\
 1955                         = 'yes'
 1956                 else:
 1957                     err = self._errors['CMMVC6353E'][1] % {'VALUE': key}
 1958                     return ('', err)
 1959             if key in params:
 1960                 vol[key] = value
 1961                 if key == 'autoexpand':
 1962                     for copy in vol['copies'].values():
 1963                         vol['copies'][copy['id']]['autoexpand'] = value
 1964             else:
 1965                 err = self._errors['CMMVC5709E'][1] % {'VALUE': key}
 1966                 return ('', err)
 1967         return ('', '')
 1968 
 1969     def _cmd_movevdisk(self, **kwargs):
 1970         if 'obj' not in kwargs:
 1971             return self._errors['CMMVC5701E']
 1972         vol_name = kwargs['obj'].strip('\'\"')
 1973         vol = self._volumes_list[vol_name]
 1974 
 1975         if 'iogrp' not in kwargs:
 1976             return self._errors['CMMVC5707E']
 1977 
 1978         iogrp = kwargs['iogrp']
 1979         if iogrp.isdigit():
 1980             vol['IO_group_id'] = iogrp
 1981             vol['IO_group_name'] = 'io_grp%s' % iogrp
 1982         else:
 1983             vol['IO_group_id'] = iogrp[6:]
 1984             vol['IO_group_name'] = iogrp
 1985         return ('', '')
 1986 
 1987     def _cmd_addvdiskaccess(self, **kwargs):
 1988         if 'obj' not in kwargs:
 1989             return self._errors['CMMVC5701E']
 1990         return ('', '')
 1991 
 1992     def _cmd_rmvdiskaccess(self, **kwargs):
 1993         if 'obj' not in kwargs:
 1994             return self._errors['CMMVC5701E']
 1995         return ('', '')
 1996 
 1997     # list vdisk sync process
 1998     def _cmd_lsvdisksyncprogress(self, **kwargs):
 1999         if 'obj' not in kwargs:
 2000             return self._errors['CMMVC5804E']
 2001         name = kwargs['obj']
 2002         copy_id = kwargs.get('copy', None)
 2003         vol = self._volumes_list[name]
 2004         rows = []
 2005         rows.append(['vdisk_id', 'vdisk_name', 'copy_id', 'progress',
 2006                      'estimated_completion_time'])
 2007         copy_found = False
 2008         for copy in vol['copies'].values():
 2009             if not copy_id or copy_id == copy['id']:
 2010                 copy_found = True
 2011                 row = [vol['id'], name, copy['id']]
 2012                 if copy['sync'] == 'yes':
 2013                     row.extend(['100', ''])
 2014                 else:
 2015                     row.extend(['50', '140210115226'])
 2016                     copy['sync'] = 'yes'
 2017                 rows.append(row)
 2018         if not copy_found:
 2019             return self._errors['CMMVC5804E']
 2020         return self._print_info_cmd(rows=rows, **kwargs)
 2021 
 2022     def _add_host_to_list(self, connector):
 2023         host_info = {}
 2024         host_info['id'] = self._find_unused_id(self._hosts_list)
 2025         host_info['host_name'] = connector['host']
 2026         host_info['iscsi_names'] = []
 2027         host_info['site_name'] = ''
 2028         host_info['wwpns'] = []
 2029         if 'initiator' in connector:
 2030             host_info['iscsi_names'].append(connector['initiator'])
 2031         if 'wwpns' in connector:
 2032             host_info['wwpns'] = host_info['wwpns'] + connector['wwpns']
 2033         self._hosts_list[connector['host']] = host_info
 2034 
 2035     def _host_in_list(self, host_name):
 2036         for k in self._hosts_list:
 2037             if k.startswith(host_name):
 2038                 return k
 2039         return None
 2040 
 2041     # Replication related command
 2042     # Create a remote copy
 2043     def _cmd_mkrcrelationship(self, **kwargs):
 2044         master_vol = ''
 2045         aux_vol = ''
 2046         aux_cluster = ''
 2047         master_sys = self._system_list['storwize-svc-sim']
 2048         aux_sys = self._system_list['aux-svc-sim']
 2049 
 2050         if 'master' not in kwargs:
 2051             return self._errors['CMMVC5707E']
 2052         master_vol = kwargs['master'].strip('\'\"')
 2053         if master_vol not in self._volumes_list:
 2054             return self._errors['CMMVC5754E']
 2055 
 2056         if 'aux' not in kwargs:
 2057             return self._errors['CMMVC5707E']
 2058         aux_vol = kwargs['aux'].strip('\'\"')
 2059         if aux_vol not in self._volumes_list:
 2060             return self._errors['CMMVC5754E']
 2061 
 2062         if 'cluster' not in kwargs:
 2063             return self._errors['CMMVC5707E']
 2064         aux_cluster = kwargs['cluster'].strip('\'\"')
 2065         if aux_cluster != aux_sys['name']:
 2066             return self._errors['CMMVC5754E']
 2067 
 2068         if (self._volumes_list[master_vol]['capacity'] !=
 2069                 self._volumes_list[aux_vol]['capacity']):
 2070             return self._errors['CMMVC5754E']
 2071 
 2072         cyclingmode = None
 2073         if 'cyclingmode' in kwargs:
 2074             cyclingmode = kwargs['cyclingmode'].strip('\'\"')
 2075 
 2076         rcrel_info = {}
 2077         rcrel_info['id'] = self._find_unused_id(self._rcrelationship_list)
 2078         rcrel_info['name'] = 'rcrel' + rcrel_info['id']
 2079         rcrel_info['master_cluster_id'] = master_sys['id']
 2080         rcrel_info['master_cluster_name'] = master_sys['name']
 2081         rcrel_info['master_vdisk_id'] = self._volumes_list[master_vol]['id']
 2082         rcrel_info['master_vdisk_name'] = master_vol
 2083         rcrel_info['aux_cluster_id'] = aux_sys['id']
 2084         rcrel_info['aux_cluster_name'] = aux_sys['name']
 2085         rcrel_info['aux_vdisk_id'] = self._volumes_list[aux_vol]['id']
 2086         rcrel_info['aux_vdisk_name'] = aux_vol
 2087         rcrel_info['primary'] = 'master'
 2088         rcrel_info['consistency_group_id'] = ''
 2089         rcrel_info['consistency_group_name'] = ''
 2090         rcrel_info['state'] = 'inconsistent_stopped'
 2091         rcrel_info['bg_copy_priority'] = '50'
 2092         rcrel_info['progress'] = '0'
 2093         rcrel_info['freeze_time'] = ''
 2094         rcrel_info['status'] = 'online'
 2095         rcrel_info['sync'] = ''
 2096         rcrel_info['copy_type'] = 'global' if 'global' in kwargs else 'metro'
 2097         rcrel_info['cycling_mode'] = cyclingmode if cyclingmode else ''
 2098         rcrel_info['cycle_period_seconds'] = '300'
 2099         rcrel_info['master_change_vdisk_id'] = ''
 2100         rcrel_info['master_change_vdisk_name'] = ''
 2101         rcrel_info['aux_change_vdisk_id'] = ''
 2102         rcrel_info['aux_change_vdisk_name'] = ''
 2103 
 2104         self._rcrelationship_list[rcrel_info['name']] = rcrel_info
 2105         self._volumes_list[master_vol]['RC_name'] = rcrel_info['name']
 2106         self._volumes_list[master_vol]['RC_id'] = rcrel_info['id']
 2107         self._volumes_list[aux_vol]['RC_name'] = rcrel_info['name']
 2108         self._volumes_list[aux_vol]['RC_id'] = rcrel_info['id']
 2109         return('RC Relationship, id [' + rcrel_info['id'] +
 2110                '], successfully created', '')
 2111 
 2112     def _cmd_lsrcrelationship(self, **kwargs):
 2113         rows = []
 2114 
 2115         if 'obj' in kwargs:
 2116             name = kwargs['obj']
 2117             for k, v in self._rcrelationship_list.items():
 2118                 if six.text_type(v['name']) == name:
 2119                     self._rc_state_transition('wait', v)
 2120 
 2121                     if self._next_cmd_error['lsrcrelationship'] == 'speed_up':
 2122                         self._next_cmd_error['lsrcrelationship'] = ''
 2123                         curr_state = v['status']
 2124                         while self._rc_state_transition('wait', v) == ("", ""):
 2125                             if curr_state == v['status']:
 2126                                 break
 2127                             curr_state = v['status']
 2128 
 2129                     rows.append(['id', v['id']])
 2130                     rows.append(['name', v['name']])
 2131                     rows.append(['master_cluster_id', v['master_cluster_id']])
 2132                     rows.append(['master_cluster_name',
 2133                                 v['master_cluster_name']])
 2134                     rows.append(['master_vdisk_id', v['master_vdisk_id']])
 2135                     rows.append(['master_vdisk_name', v['master_vdisk_name']])
 2136                     rows.append(['aux_cluster_id', v['aux_cluster_id']])
 2137                     rows.append(['aux_cluster_name', v['aux_cluster_name']])
 2138                     rows.append(['aux_vdisk_id', v['aux_vdisk_id']])
 2139                     rows.append(['aux_vdisk_name', v['aux_vdisk_name']])
 2140                     rows.append(['consistency_group_id',
 2141                                  v['consistency_group_id']])
 2142                     rows.append(['primary', v['primary']])
 2143                     rows.append(['consistency_group_name',
 2144                                  v['consistency_group_name']])
 2145                     rows.append(['state', v['state']])
 2146                     rows.append(['bg_copy_priority', v['bg_copy_priority']])
 2147                     rows.append(['progress', v['progress']])
 2148                     rows.append(['freeze_time', v['freeze_time']])
 2149                     rows.append(['status', v['status']])
 2150                     rows.append(['sync', v['sync']])
 2151                     rows.append(['copy_type', v['copy_type']])
 2152                     rows.append(['cycling_mode', v['cycling_mode']])
 2153                     rows.append(['cycle_period_seconds',
 2154                                  v['cycle_period_seconds']])
 2155                     rows.append(['master_change_vdisk_id',
 2156                                  v['master_change_vdisk_id']])
 2157                     rows.append(['master_change_vdisk_name',
 2158                                  v['master_change_vdisk_name']])
 2159                     rows.append(['aux_change_vdisk_id',
 2160                                  v['aux_change_vdisk_id']])
 2161                     rows.append(['aux_change_vdisk_name',
 2162                                  v['aux_change_vdisk_name']])
 2163 
 2164         if 'nohdr' in kwargs:
 2165             for index in range(len(rows)):
 2166                 rows[index] = ' '.join(rows[index][1:])
 2167         if 'delim' in kwargs:
 2168             for index in range(len(rows)):
 2169                 rows[index] = kwargs['delim'].join(rows[index])
 2170 
 2171         return ('%s' % '\n'.join(rows), '')
 2172 
 2173     def _cmd_startrcrelationship(self, **kwargs):
 2174         if 'obj' not in kwargs:
 2175             return self._errors['CMMVC5701E']
 2176         id_num = kwargs['obj']
 2177 
 2178         primary_vol = None
 2179         if 'primary' in kwargs:
 2180             primary_vol = kwargs['primary'].strip('\'\"')
 2181 
 2182         try:
 2183             rcrel = self._rcrelationship_list[id_num]
 2184         except KeyError:
 2185             return self._errors['CMMVC5753E']
 2186 
 2187         if rcrel['state'] == 'idling' and not primary_vol:
 2188             return self._errors['CMMVC5963E']
 2189 
 2190         self._rc_state_transition('start', rcrel)
 2191         if primary_vol:
 2192             self._rcrelationship_list[id_num]['primary'] = primary_vol
 2193         return ('', '')
 2194 
 2195     def _cmd_stoprcrelationship(self, **kwargs):
 2196         if 'obj' not in kwargs:
 2197             return self._errors['CMMVC5701E']
 2198         id_num = kwargs['obj']
 2199         force_access = True if 'access' in kwargs else False
 2200 
 2201         try:
 2202             rcrel = self._rcrelationship_list[id_num]
 2203         except KeyError:
 2204             return self._errors['CMMVC5753E']
 2205 
 2206         function = 'stop_access' if force_access else 'stop'
 2207         self._rc_state_transition(function, rcrel)
 2208         if force_access:
 2209             self._rcrelationship_list[id_num]['primary'] = ''
 2210         return ('', '')
 2211 
 2212     def _cmd_switchrcrelationship(self, **kwargs):
 2213         if 'obj' not in kwargs:
 2214             return self._errors['CMMVC5707E']
 2215         id_num = kwargs['obj']
 2216 
 2217         try:
 2218             rcrel = self._rcrelationship_list[id_num]
 2219         except KeyError:
 2220             return self._errors['CMMVC5753E']
 2221 
 2222         if rcrel['state'] == storwize_const.REP_CONSIS_SYNC:
 2223             rcrel['primary'] = kwargs['primary']
 2224             return ('', '')
 2225         else:
 2226             return self._errors['CMMVC5753E']
 2227 
 2228     def _cmd_chrcrelationship(self, **kwargs):
 2229         if 'obj' not in kwargs:
 2230             return self._errors['CMMVC5701E']
 2231         id_num = kwargs['obj']
 2232 
 2233         try:
 2234             rcrel = self._rcrelationship_list[id_num]
 2235         except KeyError:
 2236             return self._errors['CMMVC5753E']
 2237 
 2238         remove_from_rccg = True if 'noconsistgrp' in kwargs else False
 2239         add_to_rccg = True if 'consistgrp' in kwargs else False
 2240         if remove_from_rccg:
 2241             if rcrel['consistency_group_name']:
 2242                 rccg_name = rcrel['consistency_group_name']
 2243             else:
 2244                 return self._errors['CMMVC6065E']
 2245         elif add_to_rccg:
 2246             rccg_name = (kwargs['consistgrp'].strip('\'\"')
 2247                          if 'consistgrp' in kwargs else None)
 2248         else:
 2249             return self._chrcrelationship_attr(**kwargs)
 2250 
 2251         try:
 2252             rccg = self._rcconsistgrp_list[rccg_name]
 2253         except KeyError:
 2254             return self._errors['CMMVC5753E']
 2255 
 2256         if remove_from_rccg:
 2257             rcrel['consistency_group_name'] = ''
 2258             rcrel['consistency_group_id'] = ''
 2259 
 2260             if int(rccg['relationship_count']) > 0:
 2261                 rccg['relationship_count'] = str(
 2262                     int(rccg['relationship_count']) - 1)
 2263             if rccg['relationship_count'] == '0':
 2264                 rccg['state'] = 'empty'
 2265                 rccg['copy_type'] = 'empty_group'
 2266         else:
 2267             if rccg['copy_type'] == 'empty_group':
 2268                 rccg['copy_type'] = rcrel['copy_type']
 2269             elif rccg['copy_type'] != rcrel['copy_type']:
 2270                 return self._errors['CMMVC9012E']
 2271 
 2272             rcrel['consistency_group_name'] = rccg['name']
 2273             rcrel['consistency_group_id'] = rccg['id']
 2274             rccg['relationship_count'] = str(
 2275                 int(rccg['relationship_count']) + 1)
 2276             if rccg['state'] == 'empty':
 2277                 rccg['state'] = rcrel['state']
 2278                 rccg['primary'] = rcrel['primary']
 2279                 rccg['cycling_mode'] = rcrel['cycling_mode']
 2280                 rccg['cycle_period_seconds'] = rcrel['cycle_period_seconds']
 2281 
 2282         return '', ''
 2283 
 2284     def _cmd_rmrcrelationship(self, **kwargs):
 2285         if 'obj' not in kwargs:
 2286             return self._errors['CMMVC5701E']
 2287         id_num = kwargs['obj']
 2288         force = True if 'force' in kwargs else False
 2289 
 2290         try:
 2291             rcrel = self._rcrelationship_list[id_num]
 2292         except KeyError:
 2293             return self._errors['CMMVC5753E']
 2294 
 2295         function = 'delete_force' if force else 'delete'
 2296         self._rc_state_transition(function, rcrel)
 2297         if rcrel['state'] == 'end':
 2298             self._volumes_list[rcrel['master_vdisk_name']]['RC_name'] = ''
 2299             self._volumes_list[rcrel['master_vdisk_name']]['RC_id'] = ''
 2300             self._volumes_list[rcrel['aux_vdisk_name']]['RC_name'] = ''
 2301             self._volumes_list[rcrel['aux_vdisk_name']]['RC_id'] = ''
 2302             del self._rcrelationship_list[id_num]
 2303 
 2304         return ('', '')
 2305 
 2306     def _chrcrelationship_attr(self, **kwargs):
 2307         if 'obj' not in kwargs:
 2308             return self._errors['CMMVC5707E']
 2309         id_num = kwargs['obj']
 2310 
 2311         try:
 2312             rcrel = self._rcrelationship_list[id_num]
 2313         except KeyError:
 2314             return self._errors['CMMVC5753E']
 2315 
 2316         nonull_num = 0
 2317         masterchange = None
 2318         if 'masterchange' in kwargs:
 2319             masterchange = kwargs['masterchange'].strip('\'\"')
 2320             nonull_num += 1
 2321 
 2322         auxchange = None
 2323         if 'auxchange' in kwargs:
 2324             auxchange = kwargs['auxchange'].strip('\'\"')
 2325             nonull_num += 1
 2326 
 2327         cycleperiodseconds = None
 2328         if 'cycleperiodseconds' in kwargs:
 2329             cycleperiodseconds = kwargs['cycleperiodseconds'].strip('\'\"')
 2330             nonull_num += 1
 2331 
 2332         if nonull_num > 1:
 2333             return self._errors['CMMVC5713E']
 2334         elif masterchange:
 2335             rcrel['master_change_vdisk_name'] = masterchange
 2336             return ('', '')
 2337         elif auxchange:
 2338             rcrel['aux_change_vdisk_name'] = auxchange
 2339             return ('', '')
 2340         elif cycleperiodseconds:
 2341             rcrel['cycle_period_seconds'] = cycleperiodseconds
 2342         return ('', '')
 2343 
 2344     def _rc_state_transition(self, function, rcrel):
 2345         if (function == 'wait' and
 2346                 'wait' not in self._rc_transitions[rcrel['state']]):
 2347             return ('', '')
 2348 
 2349         if rcrel['state'] == 'inconsistent_copying' and function == 'wait':
 2350             if rcrel['progress'] == '0':
 2351                 rcrel['progress'] = '50'
 2352             elif (storwize_const.GMCV_MULTI == rcrel['cycling_mode']
 2353                   and storwize_const.GLOBAL == rcrel['copy_type']):
 2354                 rcrel['progress'] = '100'
 2355                 rcrel['state'] = 'consistent_copying'
 2356             else:
 2357                 rcrel['progress'] = '100'
 2358                 rcrel['state'] = 'consistent_synchronized'
 2359             return ('', '')
 2360         else:
 2361             try:
 2362                 curr_state = rcrel['state']
 2363                 rcrel['state'] = self._rc_transitions[curr_state][function]
 2364                 return ('', '')
 2365             except Exception:
 2366                 return self._errors['CMMVC5982E']
 2367 
 2368     def _rccg_state_transition(self, function, rccg):
 2369         if (function == 'wait' and
 2370                 'wait' not in self._rccg_transitions[rccg['state']]):
 2371             return ('', '')
 2372 
 2373         if rccg['state'] == 'inconsistent_copying' and function == 'wait':
 2374             if rccg['cycling_mode'] == storwize_const.GMCV_MULTI:
 2375                 rccg['state'] = storwize_const.REP_CONSIS_COPYING
 2376             else:
 2377                 rccg['state'] = storwize_const.REP_CONSIS_SYNC
 2378             for rcrel_info in self._rcrelationship_list.values():
 2379                 if rcrel_info['consistency_group_name'] == rccg['name']:
 2380                     rcrel_info['progress'] = '100'
 2381                     rcrel_info['state'] = rccg['state']
 2382             return ('', '')
 2383         else:
 2384             try:
 2385                 curr_state = rccg['state']
 2386                 rccg['state'] = self._rccg_transitions[curr_state][function]
 2387                 return ('', '')
 2388             except Exception:
 2389                 return self._errors['CMMVC5982E']
 2390 
 2391     def _cmd_mkrcconsistgrp(self, **kwargs):
 2392         master_sys = self._system_list['storwize-svc-sim']
 2393         aux_sys = self._system_list['aux-svc-sim']
 2394         if 'cluster' not in kwargs:
 2395             return self._errors['CMMVC5707E']
 2396         aux_cluster = kwargs['cluster'].strip('\'\"')
 2397         if (aux_cluster != aux_sys['name'] and
 2398                 aux_cluster != master_sys['name']):
 2399             return self._errors['CMMVC5754E']
 2400 
 2401         rccg_info = {}
 2402         rccg_info['id'] = self._find_unused_id(self._rcconsistgrp_list)
 2403 
 2404         if 'name' in kwargs:
 2405             rccg_info['name'] = kwargs['name'].strip('\'\"')
 2406         else:
 2407             rccg_info['name'] = self.driver._get_rccg_name(None,
 2408                                                            rccg_info['id'])
 2409         rccg_info['master_cluster_id'] = master_sys['id']
 2410         rccg_info['master_cluster_name'] = master_sys['name']
 2411         rccg_info['aux_cluster_id'] = aux_sys['id']
 2412         rccg_info['aux_cluster_name'] = aux_sys['name']
 2413 
 2414         rccg_info['primary'] = ''
 2415         rccg_info['state'] = 'empty'
 2416         rccg_info['relationship_count'] = '0'
 2417 
 2418         rccg_info['freeze_time'] = ''
 2419         rccg_info['status'] = ''
 2420         rccg_info['sync'] = ''
 2421         rccg_info['copy_type'] = 'empty_group'
 2422         rccg_info['cycling_mode'] = ''
 2423         rccg_info['cycle_period_seconds'] = '300'
 2424         self._rcconsistgrp_list[rccg_info['name']] = rccg_info
 2425 
 2426         return('RC Consistency Group, id [' + rccg_info['id'] +
 2427                '], successfully created', '')
 2428 
 2429     def _cmd_lsrcconsistgrp(self, **kwargs):
 2430         rows = []
 2431 
 2432         if 'obj' not in kwargs:
 2433             rows.append(['id', 'name', 'master_cluster_id',
 2434                          'master_cluster_name', 'aux_cluster_id',
 2435                          'aux_cluster_name', 'primary', 'state',
 2436                          'relationship_count', 'copy_type',
 2437                          'cycling_mode', 'freeze_time'])
 2438             for rccg_info in self._rcconsistgrp_list.values():
 2439                 rows.append([rccg_info['id'], rccg_info['name'],
 2440                              rccg_info['master_cluster_id'],
 2441                              rccg_info['master_cluster_name'],
 2442                              rccg_info['aux_cluster_id'],
 2443                              rccg_info['aux_cluster_name'],
 2444                              rccg_info['primary'], rccg_info['state'],
 2445                              rccg_info['relationship_count'],
 2446                              rccg_info['copy_type'], rccg_info['cycling_mode'],
 2447                              rccg_info['freeze_time']])
 2448             return self._print_info_cmd(rows=rows, **kwargs)
 2449         else:
 2450             try:
 2451                 rccg_info = self._rcconsistgrp_list[kwargs['obj']]
 2452             except KeyError:
 2453                 return self._errors['CMMVC5804E']
 2454 
 2455             rows = []
 2456             rows.append(['id', rccg_info['id']])
 2457             rows.append(['name', rccg_info['name']])
 2458             rows.append(['master_cluster_id', rccg_info['master_cluster_id']])
 2459             rows.append(['master_cluster_name',
 2460                          rccg_info['master_cluster_name']])
 2461             rows.append(['aux_cluster_id', rccg_info['aux_cluster_id']])
 2462             rows.append(['aux_cluster_name', rccg_info['aux_cluster_name']])
 2463             rows.append(['primary', rccg_info['primary']])
 2464             rows.append(['state', rccg_info['state']])
 2465             rows.append(['relationship_count',
 2466                          rccg_info['relationship_count']])
 2467             rows.append(['freeze_time', rccg_info['freeze_time']])
 2468             rows.append(['status', rccg_info['status']])
 2469             rows.append(['sync', rccg_info['sync']])
 2470             rows.append(['copy_type', rccg_info['copy_type']])
 2471             rows.append(['cycling_mode', rccg_info['cycling_mode']])
 2472             rows.append(['cycle_period_seconds',
 2473                          rccg_info['cycle_period_seconds']])
 2474 
 2475             if 'delim' in kwargs:
 2476                 for index in range(len(rows)):
 2477                     rows[index] = kwargs['delim'].join(rows[index])
 2478             return ('%s' % '\n'.join(rows), '')
 2479 
 2480     def _cmd_startrcconsistgrp(self, **kwargs):
 2481         if 'obj' not in kwargs:
 2482             return self._errors['CMMVC5701E']
 2483         id_num = kwargs['obj']
 2484 
 2485         primary = (kwargs['primary'].strip('\'\"') if 'primary'
 2486                                                       in kwargs else None)
 2487         try:
 2488             rccg = self._rcconsistgrp_list[id_num]
 2489         except KeyError:
 2490             return self._errors['CMMVC5753E']
 2491 
 2492         if rccg['state'] == 'idling' and not primary:
 2493             return self._errors['CMMVC5963E']
 2494 
 2495         self._rccg_state_transition('start', rccg)
 2496         for rcrel_info in self._rcrelationship_list.values():
 2497             if rcrel_info['consistency_group_name'] == rccg:
 2498                 self._rc_state_transition('start', rcrel_info)
 2499         if primary:
 2500             self._rcconsistgrp_list[id_num]['primary'] = primary
 2501             for rcrel_info in self._rcrelationship_list.values():
 2502                 if rcrel_info['consistency_group_name'] == rccg['name']:
 2503                     rcrel_info['primary'] = primary
 2504         return ('', '')
 2505 
 2506     def _cmd_stoprcconsistgrp(self, **kwargs):
 2507         if 'obj' not in kwargs:
 2508             return self._errors['CMMVC5701E']
 2509         id_num = kwargs['obj']
 2510         force_access = True if 'access' in kwargs else False
 2511 
 2512         try:
 2513             rccg = self._rcconsistgrp_list[id_num]
 2514         except KeyError:
 2515             return self._errors['CMMVC5753E']
 2516 
 2517         function = 'stop_access' if force_access else 'stop'
 2518         self._rccg_state_transition(function, rccg)
 2519         for rcrel_info in self._rcrelationship_list.values():
 2520             if rcrel_info['consistency_group_name'] == rccg['name']:
 2521                 self._rc_state_transition(function, rcrel_info)
 2522         if force_access:
 2523             self._rcconsistgrp_list[id_num]['primary'] = ''
 2524             for rcrel_info in self._rcrelationship_list.values():
 2525                 if rcrel_info['consistency_group_name'] == rccg['name']:
 2526                     rcrel_info['primary'] = ''
 2527         return ('', '')
 2528 
 2529     def _cmd_switchrcconsistgrp(self, **kwargs):
 2530         if 'obj' not in kwargs:
 2531             return self._errors['CMMVC5707E']
 2532         id_num = kwargs['obj']
 2533 
 2534         try:
 2535             rccg = self._rcconsistgrp_list[id_num]
 2536         except KeyError:
 2537             return self._errors['CMMVC5753E']
 2538 
 2539         if (rccg['state'] == storwize_const.REP_CONSIS_SYNC or
 2540                 (rccg['cycling_mode'] == storwize_const.GMCV_MULTI and
 2541                  rccg['state'] == storwize_const.REP_CONSIS_COPYING)):
 2542             rccg['primary'] = kwargs['primary']
 2543             for rcrel_info in self._rcrelationship_list.values():
 2544                 if rcrel_info['consistency_group_name'] == rccg['name']:
 2545                     rcrel_info['primary'] = kwargs['primary']
 2546             return ('', '')
 2547         else:
 2548             return self._errors['CMMVC5753E']
 2549 
 2550     def _cmd_rmrcconsistgrp(self, **kwargs):
 2551         if 'obj' not in kwargs:
 2552             return self._errors['CMMVC5701E']
 2553         rccg_name = kwargs['obj'].strip('\'\"')
 2554         force = True if 'force' in kwargs else False
 2555 
 2556         try:
 2557             rccg = self._rcconsistgrp_list[rccg_name]
 2558         except KeyError:
 2559             return self._errors['CMMVC5804E']
 2560 
 2561         function = 'delete_force' if force else 'delete'
 2562         self._rccg_state_transition(function, rccg)
 2563         if rccg['state'] == 'end':
 2564             for rcrel_info in self._rcrelationship_list.values():
 2565                 if rcrel_info['consistency_group_name'] == rccg['name']:
 2566                     rcrel_info['consistency_group_name'] = ''
 2567                     rcrel_info['consistency_group_id'] = ''
 2568             del self._rcconsistgrp_list[rccg_name]
 2569         return ('', '')
 2570 
 2571     def _cmd_lspartnershipcandidate(self, **kwargs):
 2572         rows = [None] * 4
 2573         master_sys = self._system_list['storwize-svc-sim']
 2574         aux_sys = self._system_list['aux-svc-sim']
 2575         rows[0] = ['id', 'configured', 'name']
 2576         rows[1] = [master_sys['id'], 'no', master_sys['name']]
 2577         rows[2] = [aux_sys['id'], 'no', aux_sys['name']]
 2578         rows[3] = ['0123456789001234', 'no', 'fake_svc']
 2579         return self._print_info_cmd(rows=rows, **kwargs)
 2580 
 2581     def _cmd_lspartnership(self, **kwargs):
 2582         rows = []
 2583         rows.append(['id', 'name', 'location', 'partnership',
 2584                      'type', 'cluster_ip', 'event_log_sequence'])
 2585 
 2586         master_sys = self._system_list['storwize-svc-sim']
 2587         if master_sys['name'] not in self._partnership_list:
 2588             local_info = {}
 2589             local_info['id'] = master_sys['id']
 2590             local_info['name'] = master_sys['name']
 2591             local_info['location'] = 'local'
 2592             local_info['type'] = ''
 2593             local_info['cluster_ip'] = ''
 2594             local_info['event_log_sequence'] = ''
 2595             local_info['chap_secret'] = ''
 2596             local_info['linkbandwidthmbits'] = ''
 2597             local_info['backgroundcopyrate'] = ''
 2598             local_info['partnership'] = ''
 2599             self._partnership_list[master_sys['id']] = local_info
 2600 
 2601         # Assume we always get a filtervalue argument
 2602         filter_key = kwargs['filtervalue'].split('=')[0]
 2603         filter_value = kwargs['filtervalue'].split('=')[1]
 2604         for k, v in self._partnership_list.items():
 2605             if six.text_type(v[filter_key]) == filter_value:
 2606                 rows.append([v['id'], v['name'], v['location'],
 2607                              v['partnership'], v['type'], v['cluster_ip'],
 2608                              v['event_log_sequence']])
 2609         return self._print_info_cmd(rows=rows, **kwargs)
 2610 
 2611     def _cmd_mkippartnership(self, **kwargs):
 2612         if 'clusterip' not in kwargs:
 2613             return self._errors['CMMVC5707E']
 2614         clusterip = kwargs['master'].strip('\'\"')
 2615 
 2616         if 'linkbandwidthmbits' not in kwargs:
 2617             return self._errors['CMMVC5707E']
 2618         bandwidth = kwargs['linkbandwidthmbits'].strip('\'\"')
 2619 
 2620         if 'backgroundcopyrate' not in kwargs:
 2621             return self._errors['CMMVC5707E']
 2622         copyrate = kwargs['backgroundcopyrate'].strip('\'\"')
 2623 
 2624         if clusterip == '192.168.10.21':
 2625             partner_info_id = self._system_list['storwize-svc-sim']['id']
 2626             partner_info_name = self._system_list['storwize-svc-sim']['name']
 2627         else:
 2628             partner_info_id = self._system_list['aux-svc-sim']['id']
 2629             partner_info_name = self._system_list['aux-svc-sim']['name']
 2630 
 2631         partner_info = {}
 2632         partner_info['id'] = partner_info_id
 2633         partner_info['name'] = partner_info_name
 2634         partner_info['location'] = 'remote'
 2635         partner_info['type'] = 'ipv4'
 2636         partner_info['cluster_ip'] = clusterip
 2637         partner_info['event_log_sequence'] = ''
 2638         partner_info['chap_secret'] = ''
 2639         partner_info['linkbandwidthmbits'] = bandwidth
 2640         partner_info['backgroundcopyrate'] = copyrate
 2641         partner_info['partnership'] = 'fully_configured'
 2642 
 2643         self._partnership_list[partner_info['id']] = partner_info
 2644         return('', '')
 2645 
 2646     def _cmd_mkfcpartnership(self, **kwargs):
 2647         if 'obj' not in kwargs:
 2648             return self._errors['CMMVC5701E']
 2649         peer_sys = kwargs['obj']
 2650 
 2651         if 'linkbandwidthmbits' not in kwargs:
 2652             return self._errors['CMMVC5707E']
 2653         bandwidth = kwargs['linkbandwidthmbits'].strip('\'\"')
 2654 
 2655         if 'backgroundcopyrate' not in kwargs:
 2656             return self._errors['CMMVC5707E']
 2657         copyrate = kwargs['backgroundcopyrate'].strip('\'\"')
 2658 
 2659         partner_info = {}
 2660         partner_info['id'] = self._system_list[peer_sys]['id']
 2661         partner_info['name'] = peer_sys
 2662         partner_info['location'] = 'remote'
 2663         partner_info['type'] = 'fc'
 2664         partner_info['cluster_ip'] = ''
 2665         partner_info['event_log_sequence'] = ''
 2666         partner_info['chap_secret'] = ''
 2667         partner_info['linkbandwidthmbits'] = bandwidth
 2668         partner_info['backgroundcopyrate'] = copyrate
 2669         partner_info['partnership'] = 'fully_configured'
 2670         self._partnership_list[partner_info['id']] = partner_info
 2671         return('', '')
 2672 
 2673     def _cmd_chpartnership(self, **kwargs):
 2674         if 'obj' not in kwargs:
 2675             return self._errors['CMMVC5701E']
 2676         peer_sys = kwargs['obj']
 2677         if peer_sys not in self._partnership_list:
 2678             return self._errors['CMMVC5753E']
 2679 
 2680         partner_state = ('fully_configured' if 'start' in kwargs
 2681                          else 'fully_configured_stopped')
 2682         self._partnership_list[peer_sys]['partnership'] = partner_state
 2683         return('', '')
 2684 
 2685     # The main function to run commands on the management simulator
 2686     def execute_command(self, cmd, check_exit_code=True):
 2687         try:
 2688             kwargs = self._cmd_to_dict(cmd)
 2689         except IndexError:
 2690             return self._errors['CMMVC5707E']
 2691 
 2692         command = kwargs.pop('cmd')
 2693         func = getattr(self, '_cmd_' + command)
 2694         out, err = func(**kwargs)
 2695 
 2696         if (check_exit_code) and (len(err) != 0):
 2697             raise processutils.ProcessExecutionError(exit_code=1,
 2698                                                      stdout=out,
 2699                                                      stderr=err,
 2700                                                      cmd=' '.join(cmd))
 2701 
 2702         return (out, err)
 2703 
 2704     # After calling this function, the next call to the specified command will
 2705     # result in in the error specified
 2706     def error_injection(self, cmd, error):
 2707         self._next_cmd_error[cmd] = error
 2708 
 2709     def change_vdiskcopy_attr(self, vol_name, key, value, copy="primary"):
 2710         if copy == 'primary':
 2711             self._volumes_list[vol_name]['copies']['0'][key] = value
 2712         elif copy == 'secondary':
 2713             self._volumes_list[vol_name]['copies']['1'][key] = value
 2714         else:
 2715             msg = _("The copy should be primary or secondary")
 2716             raise exception.InvalidInput(reason=msg)
 2717 
 2718     def create_site_volume_and_fcmapping(self, kwargs, name, sitepool,
 2719                                          fcmapping=False, source=None):
 2720 
 2721         sitepool_id = self._get_mdiskgrp_id(sitepool)
 2722         site_volume_info = {}
 2723         site_volume_info['id'] = self._find_unused_id(self._volumes_list)
 2724         site_volume_info['uid'] = ('ABCDEF' * 3) + (
 2725             '0' * 14) + site_volume_info['id']
 2726 
 2727         site_volume_info['mdisk_grp_name'] = sitepool
 2728         site_volume_info['mdisk_grp_id'] = str(sitepool_id)
 2729 
 2730         if 'name' in kwargs or 'obj' in kwargs:
 2731             site_volume_info['name'] = name
 2732         else:
 2733             site_volume_info['name'] = name + site_volume_info['id']
 2734         # Assume size and unit are given, store it in bytes
 2735         if "size" in kwargs:
 2736             capacity = int(kwargs['size'])
 2737             unit = kwargs['unit']
 2738             site_volume_info['capacity'] = self._convert_units_bytes(
 2739                 capacity, unit)
 2740         else:
 2741             site_volume_info['capacity'] = source['capacity']
 2742         site_volume_info['IO_group_id'] = '0'
 2743         site_volume_info['IO_group_name'] = 'io_grp0'
 2744         site_volume_info['RC_name'] = ''
 2745         site_volume_info['RC_id'] = ''
 2746 
 2747         if 'thin' in kwargs or 'compressed' in kwargs:
 2748             site_volume_info['formatted'] = 'no'
 2749             # Fake numbers
 2750             site_volume_info['used_capacity'] = '786432'
 2751             site_volume_info['real_capacity'] = '21474816'
 2752             site_volume_info['free_capacity'] = '38219264'
 2753             if 'warning' in kwargs:
 2754                 site_volume_info['warning'] = kwargs['warning'].rstrip('%')
 2755             else:
 2756                 site_volume_info['warning'] = '80'
 2757 
 2758             if 'noautoexpand' in kwargs:
 2759                 site_volume_info['autoexpand'] = 'off'
 2760             else:
 2761                 site_volume_info['autoexpand'] = 'on'
 2762 
 2763             if 'compressed' in kwargs:
 2764                 site_volume_info['compressed_copy'] = 'yes'
 2765             else:
 2766                 site_volume_info['compressed_copy'] = 'no'
 2767 
 2768             if 'thin' in kwargs:
 2769                 site_volume_info['formatted'] = 'no'
 2770                 # Fake numbers
 2771                 site_volume_info['used_capacity'] = '786432'
 2772                 site_volume_info['real_capacity'] = '21474816'
 2773                 site_volume_info['free_capacity'] = '38219264'
 2774                 if 'grainsize' in kwargs:
 2775                     site_volume_info['grainsize'] = kwargs['grainsize']
 2776                 else:
 2777                     site_volume_info['grainsize'] = '32'
 2778         else:
 2779             site_volume_info['used_capacity'] = site_volume_info['capacity']
 2780             site_volume_info['real_capacity'] = site_volume_info['capacity']
 2781             site_volume_info['free_capacity'] = '0'
 2782             site_volume_info['warning'] = ''
 2783             site_volume_info['autoexpand'] = ''
 2784             site_volume_info['grainsize'] = ''
 2785             site_volume_info['compressed_copy'] = 'no'
 2786             site_volume_info['formatted'] = 'yes'
 2787 
 2788         vol_cp = {'id': '0',
 2789                   'status': 'online',
 2790                   'sync': 'yes',
 2791                   'primary': 'yes',
 2792                   'mdisk_grp_id': str(sitepool_id),
 2793                   'mdisk_grp_name': sitepool,
 2794                   'easy_tier': 'on',
 2795                   'compressed_copy': site_volume_info['compressed_copy']}
 2796         site_volume_info['copies'] = {'0': vol_cp}
 2797 
 2798         if site_volume_info['name'] in self._volumes_list:
 2799             return self._errors['CMMVC6035E']
 2800         else:
 2801             self._volumes_list[site_volume_info['name']] = site_volume_info
 2802 
 2803         # create a flashcopy mapping for site volume and site flashcopy volume
 2804         if fcmapping:
 2805             site_fcmap_info = {}
 2806             site_fcmap_info['source'] = source['name']
 2807             site_fcmap_info['target'] = site_volume_info['name']
 2808             site_fcmap_info['id'] = self._find_unused_id(self._fcmappings_list)
 2809             site_fcmap_info['name'] = 'fcmap' + site_fcmap_info['id']
 2810             site_fcmap_info['copyrate'] = '50'
 2811             site_fcmap_info['progress'] = '0'
 2812             site_fcmap_info['autodelete'] = (True if 'autodelete' in kwargs
 2813                                              else False)
 2814             site_fcmap_info['status'] = 'idle_or_copied'
 2815             site_fcmap_info['rc_controlled'] = 'yes'
 2816 
 2817             self._fcmappings_list[site_fcmap_info['id']] = site_fcmap_info
 2818 
 2819         return site_volume_info
 2820 
 2821     def _cmd_mkvolume(self, **kwargs):
 2822         pool = kwargs['pool'].strip('\'\"')
 2823         pool_split = pool.split(':')
 2824         if len(pool_split) != 2:
 2825             raise exception.InvalidInput(
 2826                 reason=_('pool %s is invalid for hyperswap '
 2827                          'volume') % kwargs['pool'])
 2828         else:
 2829             site1pool = pool_split[0]
 2830             site2pool = pool_split[1]
 2831 
 2832         if pool == kwargs['pool']:
 2833             raise exception.InvalidInput(
 2834                 reason=_('pool missing quotes %s') % kwargs['pool'])
 2835 
 2836         if 'name' in kwargs:
 2837             site1name = kwargs['name'].strip('\'\"')
 2838             site1fcname = 'fcsite1' + kwargs['name'].strip('\'\"')
 2839             site2name = 'site2' + kwargs['name'].strip('\'\"')
 2840             site2fcname = 'fcsite2' + kwargs['name'].strip('\'\"')
 2841         else:
 2842             site1name = 'vdisk'
 2843             site1fcname = 'fcsite1vdisk'
 2844             site2name = 'site2vdisk'
 2845             site2fcname = 'fcsite2vdisk'
 2846 
 2847         # create hyperswap volume on site1
 2848         site1_volume_info = self.create_site_volume_and_fcmapping(
 2849             kwargs, site1name, site1pool, False, None)
 2850         # create flashcopy volume on site1
 2851         self.create_site_volume_and_fcmapping(kwargs, site1fcname, site1pool,
 2852                                               True, site1_volume_info)
 2853         # create hyperswap volume on site2
 2854         site2_volume_info = self.create_site_volume_and_fcmapping(
 2855             kwargs, site2name, site2pool, False, site1_volume_info)
 2856         # create flashcopy volume on site2
 2857         self.create_site_volume_and_fcmapping(kwargs, site2fcname, site2pool,
 2858                                               True, site2_volume_info)
 2859 
 2860         # Create remote copy for site1volume and site2volume
 2861         master_sys = self._system_list['storwize-svc-sim']
 2862         aux_sys = self._system_list['storwize-svc-sim']
 2863         rcrel_info = {}
 2864         rcrel_info['id'] = self._find_unused_id(self._rcrelationship_list)
 2865         rcrel_info['name'] = 'rcrel' + rcrel_info['id']
 2866         rcrel_info['master_cluster_id'] = master_sys['id']
 2867         rcrel_info['master_cluster_name'] = master_sys['name']
 2868         rcrel_info['master_vdisk_id'] = site1_volume_info['id']
 2869         rcrel_info['master_vdisk_name'] = site1_volume_info['name']
 2870         rcrel_info['aux_cluster_id'] = aux_sys['id']
 2871         rcrel_info['aux_cluster_name'] = aux_sys['name']
 2872         rcrel_info['aux_vdisk_id'] = site2_volume_info['id']
 2873         rcrel_info['aux_vdisk_name'] = site2_volume_info['name']
 2874         rcrel_info['primary'] = 'master'
 2875         rcrel_info['consistency_group_id'] = ''
 2876         rcrel_info['consistency_group_name'] = ''
 2877         rcrel_info['state'] = 'inconsistent_stopped'
 2878         rcrel_info['bg_copy_priority'] = '50'
 2879         rcrel_info['progress'] = '0'
 2880         rcrel_info['freeze_time'] = ''
 2881         rcrel_info['status'] = 'online'
 2882         rcrel_info['sync'] = ''
 2883         rcrel_info['copy_type'] = 'activeactive'
 2884         rcrel_info['cycling_mode'] = ''
 2885         rcrel_info['cycle_period_seconds'] = '300'
 2886         rcrel_info['master_change_vdisk_id'] = ''
 2887         rcrel_info['master_change_vdisk_name'] = ''
 2888         rcrel_info['aux_change_vdisk_id'] = ''
 2889         rcrel_info['aux_change_vdisk_name'] = ''
 2890 
 2891         self._rcrelationship_list[rcrel_info['name']] = rcrel_info
 2892         site1_volume_info['RC_name'] = rcrel_info['name']
 2893         site1_volume_info['RC_id'] = rcrel_info['id']
 2894         site2_volume_info['RC_name'] = rcrel_info['name']
 2895         site2_volume_info['RC_id'] = rcrel_info['id']
 2896         return ('Hyperswap volume, id [%s], successfully created' %
 2897                 (site1_volume_info['id']), '')
 2898 
 2899     def _cmd_addvolumecopy(self, **kwargs):
 2900 
 2901         if 'obj' not in kwargs:
 2902             return self._errors['CMMVC5701E']
 2903         vol_name = kwargs['obj'].strip('\'\"')
 2904         site1_volume_info = self._volumes_list[vol_name]
 2905         site1pool = site1_volume_info['mdisk_grp_name']
 2906         site2pool = kwargs['pool'].strip('\'\"')
 2907         site1fcname = 'fcsite1' + vol_name
 2908         site2name = 'site2' + vol_name
 2909         site2fcname = 'fcsite2' + vol_name
 2910 
 2911         # create flashcopy volume on site1
 2912         self.create_site_volume_and_fcmapping(kwargs, site1fcname, site1pool,
 2913                                               True, site1_volume_info)
 2914         # create hyperswap volume on site2
 2915         site2_volume_info = self.create_site_volume_and_fcmapping(
 2916             kwargs, site2name, site1pool, False, site1_volume_info)
 2917         # create flashcopy volume on site2
 2918         self.create_site_volume_and_fcmapping(kwargs, site2fcname, site2pool,
 2919                                               True, site2_volume_info)
 2920 
 2921         # create remote copy for site1volume and site2volume
 2922         master_sys = self._system_list['storwize-svc-sim']
 2923         aux_sys = self._system_list['storwize-svc-sim']
 2924         rcrel_info = {}
 2925         rcrel_info['id'] = self._find_unused_id(self._rcrelationship_list)
 2926         rcrel_info['name'] = 'rcrel' + rcrel_info['id']
 2927         rcrel_info['master_cluster_id'] = master_sys['id']
 2928         rcrel_info['master_cluster_name'] = master_sys['name']
 2929         rcrel_info['master_vdisk_id'] = site1_volume_info['id']
 2930         rcrel_info['master_vdisk_name'] = site1_volume_info['name']
 2931         rcrel_info['aux_cluster_id'] = aux_sys['id']
 2932         rcrel_info['aux_cluster_name'] = aux_sys['name']
 2933         rcrel_info['aux_vdisk_id'] = site2_volume_info['id']
 2934         rcrel_info['aux_vdisk_name'] = site2_volume_info['name']
 2935         rcrel_info['primary'] = 'master'
 2936         rcrel_info['consistency_group_id'] = ''
 2937         rcrel_info['consistency_group_name'] = ''
 2938         rcrel_info['state'] = 'inconsistent_stopped'
 2939         rcrel_info['bg_copy_priority'] = '50'
 2940         rcrel_info['progress'] = '0'
 2941         rcrel_info['freeze_time'] = ''
 2942         rcrel_info['status'] = 'online'
 2943         rcrel_info['sync'] = ''
 2944         rcrel_info['copy_type'] = 'activeactive'
 2945         rcrel_info['cycling_mode'] = ''
 2946         rcrel_info['cycle_period_seconds'] = '300'
 2947         rcrel_info['master_change_vdisk_id'] = ''
 2948         rcrel_info['master_change_vdisk_name'] = ''
 2949         rcrel_info['aux_change_vdisk_id'] = ''
 2950         rcrel_info['aux_change_vdisk_name'] = ''
 2951 
 2952         self._rcrelationship_list[rcrel_info['name']] = rcrel_info
 2953         site1_volume_info['RC_name'] = rcrel_info['name']
 2954         site1_volume_info['RC_id'] = rcrel_info['id']
 2955         site2_volume_info['RC_name'] = rcrel_info['name']
 2956         site2_volume_info['RC_id'] = rcrel_info['id']
 2957         return ('', '')
 2958 
 2959     def _cmd_rmvolumecopy(self, **kwargs):
 2960 
 2961         if 'obj' not in kwargs:
 2962             return self._errors['CMMVC5701E']
 2963         vol_name = kwargs['obj'].strip('\'\"')
 2964         site1_volume_info = self._volumes_list[vol_name]
 2965         site2_volume_info = self._volumes_list['site2' + vol_name]
 2966 
 2967         del self._rcrelationship_list[self._volumes_list[vol_name]['RC_name']]
 2968         site1fcmap = None
 2969         site2fcmap = None
 2970         for fcmap in self._fcmappings_list.values():
 2971             if ((fcmap['source'] == vol_name) and
 2972                     (fcmap['target'] == 'fcsite1' + vol_name)):
 2973                 site1fcmap = fcmap
 2974                 continue
 2975             elif ((fcmap['source'] == 'site2' + vol_name) and
 2976                     (fcmap['target'] == 'fcsite2' + vol_name)):
 2977                 site2fcmap = fcmap
 2978                 continue
 2979 
 2980         if site1fcmap:
 2981             del self._fcmappings_list[site1fcmap['id']]
 2982         if site2fcmap:
 2983             del self._fcmappings_list[site2fcmap['id']]
 2984 
 2985         del site2_volume_info
 2986         site1_volume_info['RC_name'] = ''
 2987         site1_volume_info['RC_id'] = ''
 2988         return ('', '')
 2989 
 2990     def _cmd_rmvolume(self, **kwargs):
 2991         removehostmappings = True if 'removehostmappings' in kwargs else False
 2992 
 2993         if 'obj' not in kwargs:
 2994             return self._errors['CMMVC5701E']
 2995         vol_name = kwargs['obj'].strip('\'\"')
 2996 
 2997         if vol_name not in self._volumes_list:
 2998             return self._errors['CMMVC5753E']
 2999 
 3000         site1fcmap = None
 3001         site2fcmap = None
 3002         for fcmap in self._fcmappings_list.values():
 3003             if ((fcmap['source'] == vol_name) and
 3004                     (fcmap['target'] == 'fcsite1' + vol_name)):
 3005                 site1fcmap = fcmap
 3006                 continue
 3007             elif ((fcmap['source'] == 'site2' + vol_name) and
 3008                     (fcmap['target'] == 'fcsite2' + vol_name)):
 3009                 site2fcmap = fcmap
 3010                 continue
 3011         if site1fcmap:
 3012             del self._fcmappings_list[site1fcmap['id']]
 3013         if site2fcmap:
 3014             del self._fcmappings_list[site2fcmap['id']]
 3015 
 3016         if not removehostmappings:
 3017             for mapping in self._mappings_list.values():
 3018                 if mapping['vol'] == vol_name:
 3019                     return self._errors['CMMVC5840E']
 3020 
 3021         del self._rcrelationship_list[self._volumes_list[vol_name]['RC_name']]
 3022         del self._volumes_list[vol_name]
 3023         del self._volumes_list['fcsite1' + vol_name]
 3024         del self._volumes_list['site2' + vol_name]
 3025         del self._volumes_list['fcsite2' + vol_name]
 3026         return ('', '')
 3027 
 3028 
 3029 class StorwizeSVCISCSIFakeDriver(storwize_svc_iscsi.StorwizeSVCISCSIDriver):
 3030     def __init__(self, *args, **kwargs):
 3031         super(StorwizeSVCISCSIFakeDriver, self).__init__(*args, **kwargs)
 3032 
 3033     def set_fake_storage(self, fake):
 3034         self.fake_storage = fake
 3035 
 3036     def _run_ssh(self, cmd, check_exit_code=True, attempts=1):
 3037         utils.check_ssh_injection(cmd)
 3038         ret = self.fake_storage.execute_command(cmd, check_exit_code)
 3039 
 3040         return ret
 3041 
 3042 
 3043 class StorwizeSVCFcFakeDriver(storwize_svc_fc.StorwizeSVCFCDriver):
 3044     def __init__(self, *args, **kwargs):
 3045         super(StorwizeSVCFcFakeDriver, self).__init__(*args, **kwargs)
 3046 
 3047     def set_fake_storage(self, fake):
 3048         self.fake_storage = fake
 3049 
 3050     def _run_ssh(self, cmd, check_exit_code=True, attempts=1):
 3051         utils.check_ssh_injection(cmd)
 3052         ret = self.fake_storage.execute_command(cmd, check_exit_code)
 3053 
 3054         return ret
 3055 
 3056 
 3057 class StorwizeSVCISCSIDriverTestCase(test.TestCase):
 3058     @mock.patch.object(time, 'sleep')
 3059     def setUp(self, mock_sleep):
 3060         super(StorwizeSVCISCSIDriverTestCase, self).setUp()
 3061         self.USESIM = True
 3062         if self.USESIM:
 3063             self.iscsi_driver = StorwizeSVCISCSIFakeDriver(
 3064                 configuration=conf.Configuration([], conf.SHARED_CONF_GROUP))
 3065             self.host_site = {'site1': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3066             self._def_flags = {'san_ip': 'hostname',
 3067                                'san_login': 'user',
 3068                                'san_password': 'pass',
 3069                                'storwize_svc_volpool_name': ['openstack'],
 3070                                'storwize_svc_flashcopy_timeout': 20,
 3071                                'storwize_svc_flashcopy_rate': 49,
 3072                                'storwize_svc_multipath_enabled': False,
 3073                                'storwize_svc_allow_tenant_qos': True,
 3074                                'storwize_preferred_host_site': self.host_site}
 3075             wwpns = [
 3076                 six.text_type(random.randint(0, 9999999999999999)).zfill(16),
 3077                 six.text_type(random.randint(0, 9999999999999999)).zfill(16)]
 3078             initiator = 'test.initiator.%s' % six.text_type(
 3079                 random.randint(10000, 99999))
 3080             self._connector = {'ip': '1.234.56.78',
 3081                                'host': 'storwize-svc-test',
 3082                                'wwpns': wwpns,
 3083                                'initiator': initiator}
 3084             self.sim = StorwizeSVCManagementSimulator(['openstack'])
 3085 
 3086             self.iscsi_driver.set_fake_storage(self.sim)
 3087             self.ctxt = context.get_admin_context()
 3088 
 3089         self._reset_flags()
 3090         self.ctxt = context.get_admin_context()
 3091         db_driver = CONF.db_driver
 3092         self.db = importutils.import_module(db_driver)
 3093         self.iscsi_driver.db = self.db
 3094         self.iscsi_driver.do_setup(None)
 3095         self.iscsi_driver.check_for_setup_error()
 3096         self.iscsi_driver._helpers.check_fcmapping_interval = 0
 3097 
 3098     def _set_flag(self, flag, value):
 3099         group = self.iscsi_driver.configuration.config_group
 3100         self.override_config(flag, value, group)
 3101 
 3102     def _reset_flags(self):
 3103         CONF.reset()
 3104         for k, v in self._def_flags.items():
 3105             self._set_flag(k, v)
 3106 
 3107     def _create_volume(self, **kwargs):
 3108         pool = _get_test_pool()
 3109         prop = {'host': 'openstack@svc#%s' % pool,
 3110                 'size': 1,
 3111                 'volume_type_id': self.vt['id']}
 3112         for p in prop.keys():
 3113             if p not in kwargs:
 3114                 kwargs[p] = prop[p]
 3115         vol = testutils.create_volume(self.ctxt, **kwargs)
 3116         self.iscsi_driver.create_volume(vol)
 3117         return vol
 3118 
 3119     def _delete_volume(self, volume):
 3120         self.iscsi_driver.delete_volume(volume)
 3121         self.db.volume_destroy(self.ctxt, volume['id'])
 3122 
 3123     def _generate_vol_info(self, vol_name, vol_id):
 3124         pool = _get_test_pool()
 3125         prop = {'mdisk_grp_name': pool}
 3126         if vol_name:
 3127             prop.update(volume_name=vol_name,
 3128                         volume_id=vol_id,
 3129                         volume_size=10)
 3130         else:
 3131             prop.update(size=10,
 3132                         volume_type_id=None,
 3133                         mdisk_grp_name=pool,
 3134                         host='openstack@svc#%s' % pool)
 3135         vol = testutils.create_volume(self.ctxt, **prop)
 3136         return vol
 3137 
 3138     def _generate_snap_info(self, vol_id, size=10):
 3139         prop = {'volume_id': vol_id,
 3140                 'volume_size': size}
 3141         snap = testutils.create_snapshot(self.ctxt, **prop)
 3142         return snap
 3143 
 3144     def _assert_vol_exists(self, name, exists):
 3145         is_vol_defined = self.iscsi_driver._helpers.is_vdisk_defined(name)
 3146         self.assertEqual(exists, is_vol_defined)
 3147 
 3148     def test_storwize_svc_iscsi_validate_connector(self):
 3149         conn_neither = {'host': 'host'}
 3150         conn_iscsi = {'host': 'host', 'initiator': 'foo'}
 3151         conn_fc = {'host': 'host', 'wwpns': 'bar'}
 3152         conn_both = {'host': 'host', 'initiator': 'foo', 'wwpns': 'bar'}
 3153 
 3154         self.iscsi_driver._state['enabled_protocols'] = set(['iSCSI'])
 3155         self.iscsi_driver.validate_connector(conn_iscsi)
 3156         self.iscsi_driver.validate_connector(conn_both)
 3157         self.assertRaises(exception.InvalidConnectorException,
 3158                           self.iscsi_driver.validate_connector, conn_fc)
 3159         self.assertRaises(exception.InvalidConnectorException,
 3160                           self.iscsi_driver.validate_connector, conn_neither)
 3161 
 3162         self.iscsi_driver._state['enabled_protocols'] = set(['iSCSI', 'FC'])
 3163         self.iscsi_driver.validate_connector(conn_iscsi)
 3164         self.iscsi_driver.validate_connector(conn_both)
 3165         self.assertRaises(exception.InvalidConnectorException,
 3166                           self.iscsi_driver.validate_connector, conn_neither)
 3167 
 3168     def test_storwize_terminate_iscsi_connection(self):
 3169         # create a iSCSI volume
 3170         volume_iSCSI = self._create_volume()
 3171         extra_spec = {'capabilities:storage_protocol': '<in> iSCSI'}
 3172         vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
 3173         volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
 3174 
 3175         connector = {'host': 'storwize-svc-host',
 3176                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3177                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3178                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3179 
 3180         self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
 3181         self.iscsi_driver.terminate_connection(volume_iSCSI, connector)
 3182 
 3183     def test_storwize_get_host_from_connector_with_both_fc_iscsi_host(self):
 3184         volume_iSCSI = self._create_volume()
 3185         extra_spec = {'capabilities:storage_protocol': '<in> iSCSI'}
 3186         vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
 3187         volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
 3188 
 3189         connector = {'host': 'storwize-svc-host',
 3190                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3191         if self.USESIM:
 3192             self.sim._cmd_mkhost(name='storwize-svc-host-99999999',
 3193                                  hbawwpn='123')
 3194             self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
 3195             self.iscsi_driver.terminate_connection(volume_iSCSI, connector)
 3196 
 3197     def test_storwize_iscsi_connection_snapshot(self):
 3198         # create a iSCSI volume
 3199         volume_iSCSI = self._create_volume()
 3200         snapshot = self._generate_snap_info(volume_iSCSI.id)
 3201         self.iscsi_driver.create_snapshot(snapshot)
 3202         connector = {'host': 'storwize-svc-host',
 3203                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3204                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3205                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3206 
 3207         self.iscsi_driver.initialize_connection_snapshot(snapshot, connector)
 3208         self.iscsi_driver.terminate_connection_snapshot(snapshot, connector)
 3209 
 3210     def test_storwize_replication_failover_iscsi_connection_snapshot(self):
 3211         volume_iSCSI = self._create_volume()
 3212         snapshot = self._generate_snap_info(volume_iSCSI.id)
 3213         self.iscsi_driver.create_snapshot(snapshot)
 3214         connector = {'host': 'storwize-svc-host',
 3215                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3216                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3217                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3218         # a snapshot of a replication failover volume. attach will be failed
 3219         with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver,
 3220                                '_get_volume_replicated_type') as rep_type:
 3221             rep_type.return_value = True
 3222             with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver,
 3223                                    '_get_vol_sys_info') as sys_info:
 3224                 sys_info.return_value = {'volume_name': 'voliscsi',
 3225                                          'backend_helper':
 3226                                              'self._aux_backend_helpers',
 3227                                          'node_state': 'self._state'}
 3228                 self.assertRaises(exception.VolumeDriverException,
 3229                                   self.iscsi_driver.
 3230                                   initialize_connection_snapshot,
 3231                                   snapshot,
 3232                                   connector)
 3233 
 3234     def test_storwize_initialize_iscsi_connection_with_host_site(self):
 3235         connector = {'host': 'storwize-svc-host',
 3236                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3237                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3238                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3239 
 3240         volume_iSCSI_1 = self._create_volume()
 3241         volume_iSCSI = self._create_volume()
 3242         extra_spec = {'drivers:volume_topology': 'hyperswap',
 3243                       'peer_pool': 'openstack1'}
 3244         vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
 3245         volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
 3246         volume_iSCSI_2 = self._create_volume()
 3247         volume_iSCSI_2['volume_type_id'] = vol_type_iSCSI['id']
 3248         self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
 3249         host_name = self.iscsi_driver._helpers.get_host_from_connector(
 3250             connector, iscsi=True)
 3251         host_info = self.iscsi_driver._helpers.ssh.lshost(host=host_name)
 3252         self.assertEqual('site1', host_info[0]['site_name'])
 3253         self.iscsi_driver.terminate_connection(volume_iSCSI, connector)
 3254         self.iscsi_driver.initialize_connection(volume_iSCSI_1, connector)
 3255         self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
 3256 
 3257         host_site = {'site1': 'iqn.1993-08.org.debian:01:eac5ccc1aaa',
 3258                      'site2': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3259         self._set_flag('storwize_preferred_host_site', host_site)
 3260         self.assertRaises(exception.InvalidConfigurationValue,
 3261                           self.iscsi_driver.initialize_connection,
 3262                           volume_iSCSI_2,
 3263                           connector)
 3264 
 3265     @mock.patch.object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
 3266                        '_do_terminate_connection')
 3267     @mock.patch.object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
 3268                        '_do_initialize_connection')
 3269     def test_storwize_do_terminate_iscsi_connection(self, init_conn,
 3270                                                     term_conn):
 3271         # create an iSCSI volume
 3272         volume_iSCSI = self._create_volume()
 3273         extra_spec = {'capabilities:storage_protocol': '<in> iSCSI'}
 3274         vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
 3275         volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
 3276 
 3277         connector = {'host': 'storwize-svc-host',
 3278                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3279                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3280                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3281 
 3282         self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
 3283         self.iscsi_driver.terminate_connection(volume_iSCSI, connector)
 3284         init_conn.assert_called_once_with(volume_iSCSI, connector)
 3285         term_conn.assert_called_once_with(volume_iSCSI, connector)
 3286 
 3287     @mock.patch.object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
 3288                        '_do_terminate_connection')
 3289     def test_storwize_initialize_iscsi_connection_failure(self, term_conn):
 3290         # create an iSCSI volume
 3291         volume_iSCSI = self._create_volume()
 3292         extra_spec = {'capabilities:storage_protocol': '<in> iSCSI'}
 3293         vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
 3294         volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
 3295 
 3296         connector = {'host': 'storwize-svc-host',
 3297                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3298                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3299                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3300 
 3301         self.iscsi_driver._state['storage_nodes'] = {}
 3302         self.assertRaises(exception.VolumeBackendAPIException,
 3303                           self.iscsi_driver.initialize_connection,
 3304                           volume_iSCSI, connector)
 3305         term_conn.assert_called_once_with(volume_iSCSI, connector)
 3306 
 3307     def test_storwize_terminate_iscsi_connection_multi_attach(self):
 3308         # create an iSCSI volume
 3309         volume_iSCSI = self._create_volume()
 3310         extra_spec = {'capabilities:storage_protocol': '<in> iSCSI'}
 3311         vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
 3312         volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
 3313 
 3314         connector = {'host': 'storwize-svc-host',
 3315                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3316                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3317                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3318         connector2 = {'host': 'STORWIZE-SVC-HOST',
 3319                       'wwnns': ['30000090fa17311e', '30000090fa17311f'],
 3320                       'wwpns': ['ffff000000000000', 'ffff000000000001'],
 3321                       'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1bbb'}
 3322 
 3323         # map and unmap the volume to two hosts normal case
 3324         self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
 3325         self.iscsi_driver.initialize_connection(volume_iSCSI, connector2)
 3326         for conn in [connector, connector2]:
 3327             host = self.iscsi_driver._helpers.get_host_from_connector(
 3328                 conn, iscsi=True)
 3329             self.assertIsNotNone(host)
 3330         self.iscsi_driver.terminate_connection(volume_iSCSI, connector)
 3331         self.iscsi_driver.terminate_connection(volume_iSCSI, connector2)
 3332         # validate that the host entries are deleted
 3333         for conn in [connector, connector2]:
 3334             host = self.iscsi_driver._helpers.get_host_from_connector(conn)
 3335             self.assertIsNone(host)
 3336         # map and unmap the volume to two hosts with the mapping removed
 3337         self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
 3338         self.iscsi_driver.initialize_connection(volume_iSCSI, connector2)
 3339         # Test multiple attachments case
 3340         host_name = self.iscsi_driver._helpers.get_host_from_connector(
 3341             connector2, iscsi=True)
 3342         self.iscsi_driver._helpers.unmap_vol_from_host(
 3343             volume_iSCSI['name'], host_name)
 3344         host_name = self.iscsi_driver._helpers.get_host_from_connector(
 3345             connector2, iscsi=True)
 3346         self.assertIsNotNone(host_name)
 3347         with mock.patch.object(storwize_svc_common.StorwizeSSH,
 3348                                'rmvdiskhostmap') as rmmap:
 3349             rmmap.side_effect = Exception('boom')
 3350             self.iscsi_driver.terminate_connection(volume_iSCSI,
 3351                                                    connector2)
 3352         host_name = self.iscsi_driver._helpers.get_host_from_connector(
 3353             connector2, iscsi=True)
 3354         self.assertIsNone(host_name)
 3355         # Test single attachment case
 3356         self.iscsi_driver._helpers.unmap_vol_from_host(
 3357             volume_iSCSI['name'], host_name)
 3358         with mock.patch.object(storwize_svc_common.StorwizeSSH,
 3359                                'rmvdiskhostmap') as rmmap:
 3360             rmmap.side_effect = Exception('boom')
 3361             self.iscsi_driver.terminate_connection(volume_iSCSI, connector)
 3362         # validate that the host entries are deleted
 3363         for conn in [connector, connector2]:
 3364             host = self.iscsi_driver._helpers.get_host_from_connector(
 3365                 conn, iscsi=True)
 3366         self.assertIsNone(host)
 3367 
 3368     def test_storwize_initialize_iscsi_connection_single_path(self):
 3369         # Test the return value for _get_iscsi_properties
 3370 
 3371         connector = {'host': 'storwize-svc-host',
 3372                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3373                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3374                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3375         # Expected single path host-volume map return value
 3376         exp_s_path = {'driver_volume_type': 'iscsi',
 3377                       'data': {'target_discovered': False,
 3378                                'target_iqn':
 3379                                    'iqn.1982-01.com.ibm:1234.sim.node1',
 3380                                'target_portal': '1.234.56.78:3260',
 3381                                'target_lun': 0,
 3382                                'auth_method': 'CHAP',
 3383                                'discovery_auth_method': 'CHAP'}}
 3384 
 3385         volume_iSCSI = self._create_volume()
 3386         extra_spec = {'capabilities:storage_protocol': '<in> iSCSI'}
 3387         vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
 3388         volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
 3389 
 3390         # Make sure that the volumes have been created
 3391         self._assert_vol_exists(volume_iSCSI['name'], True)
 3392 
 3393         # Check case where no hosts exist
 3394         ret = self.iscsi_driver._helpers.get_host_from_connector(
 3395             connector, iscsi=True)
 3396         self.assertIsNone(ret)
 3397 
 3398         # Initialize connection to map volume to a host
 3399         ret = self.iscsi_driver.initialize_connection(
 3400             volume_iSCSI, connector)
 3401         self.assertEqual(exp_s_path['driver_volume_type'],
 3402                          ret['driver_volume_type'])
 3403 
 3404         # Check the single path host-volume map return value
 3405         for k, v in exp_s_path['data'].items():
 3406             self.assertEqual(v, ret['data'][k])
 3407 
 3408         ret = self.iscsi_driver._helpers.get_host_from_connector(
 3409             connector, iscsi=True)
 3410         self.assertIsNotNone(ret)
 3411 
 3412     def test_storwize_initialize_iscsi_connection_multipath(self):
 3413         # Test the return value for _get_iscsi_properties
 3414 
 3415         connector = {'host': 'storwize-svc-host',
 3416                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3417                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3418                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa',
 3419                      'multipath': True}
 3420 
 3421         # Expected multipath host-volume map return value
 3422         exp_m_path = {'driver_volume_type': 'iscsi',
 3423                       'data': {'target_discovered': False,
 3424                                'target_iqn':
 3425                                    'iqn.1982-01.com.ibm:1234.sim.node1',
 3426                                'target_portal': '1.234.56.78:3260',
 3427                                'target_lun': 0,
 3428                                'target_iqns': [
 3429                                    'iqn.1982-01.com.ibm:1234.sim.node1',
 3430                                    'iqn.1982-01.com.ibm:1234.sim.node1',
 3431                                    'iqn.1982-01.com.ibm:1234.sim.node2'],
 3432                                'target_portals':
 3433                                    ['1.234.56.78:3260',
 3434                                     '1.234.56.80:3260',
 3435                                     '1.234.56.79:3260'],
 3436                                'target_luns': [0, 0, 0],
 3437                                'auth_method': 'CHAP',
 3438                                'discovery_auth_method': 'CHAP'}}
 3439 
 3440         volume_iSCSI = self._create_volume()
 3441         extra_spec = {'capabilities:storage_protocol': '<in> iSCSI'}
 3442         vol_type_iSCSI = volume_types.create(self.ctxt, 'iSCSI', extra_spec)
 3443         volume_iSCSI['volume_type_id'] = vol_type_iSCSI['id']
 3444 
 3445         # Check case where no hosts exist
 3446         ret = self.iscsi_driver._helpers.get_host_from_connector(
 3447             connector, iscsi=True)
 3448         self.assertIsNone(ret)
 3449 
 3450         # Initialize connection to map volume to a host
 3451         ret = self.iscsi_driver.initialize_connection(
 3452             volume_iSCSI, connector)
 3453         self.assertEqual(exp_m_path['driver_volume_type'],
 3454                          ret['driver_volume_type'])
 3455 
 3456         # Check the multipath host-volume map return value
 3457         # target_iqns and target_portals have no guaranteed order
 3458         six.assertCountEqual(self,
 3459                              exp_m_path['data']['target_iqns'],
 3460                              ret['data']['target_iqns'])
 3461         del exp_m_path['data']['target_iqns']
 3462 
 3463         six.assertCountEqual(self,
 3464                              exp_m_path['data']['target_portals'],
 3465                              ret['data']['target_portals'])
 3466         del exp_m_path['data']['target_portals']
 3467 
 3468         for k, v in exp_m_path['data'].items():
 3469             self.assertEqual(v, ret['data'][k])
 3470 
 3471         ret = self.iscsi_driver._helpers.get_host_from_connector(
 3472             connector, iscsi=True)
 3473         self.assertIsNotNone(ret)
 3474 
 3475     def test_storwize_svc_iscsi_host_maps(self):
 3476         # Create two volumes to be used in mappings
 3477 
 3478         ctxt = context.get_admin_context()
 3479         volume1 = self._generate_vol_info(None, None)
 3480         self.iscsi_driver.create_volume(volume1)
 3481         volume2 = self._generate_vol_info(None, None)
 3482         self.iscsi_driver.create_volume(volume2)
 3483 
 3484         # Create volume types that we created
 3485         types = {}
 3486         for protocol in ['iSCSI']:
 3487             opts = {'storage_protocol': '<in> ' + protocol}
 3488             types[protocol] = volume_types.create(ctxt, protocol, opts)
 3489 
 3490         expected = {'iSCSI': {'driver_volume_type': 'iscsi',
 3491                               'data': {'target_discovered': False,
 3492                                        'target_iqn':
 3493                                        'iqn.1982-01.com.ibm:1234.sim.node1',
 3494                                        'target_portal': '1.234.56.78:3260',
 3495                                        'target_lun': 0,
 3496                                        'auth_method': 'CHAP',
 3497                                        'discovery_auth_method': 'CHAP'}}}
 3498 
 3499         volume1['volume_type_id'] = types[protocol]['id']
 3500         volume2['volume_type_id'] = types[protocol]['id']
 3501 
 3502         # Check case where no hosts exist
 3503         if self.USESIM:
 3504             ret = self.iscsi_driver._helpers.get_host_from_connector(
 3505                 self._connector)
 3506             self.assertIsNone(ret)
 3507 
 3508         # Make sure that the volumes have been created
 3509         self._assert_vol_exists(volume1['name'], True)
 3510         self._assert_vol_exists(volume2['name'], True)
 3511 
 3512         # Initialize connection from the first volume to a host
 3513         ret = self.iscsi_driver.initialize_connection(
 3514             volume1, self._connector)
 3515         self.assertEqual(expected[protocol]['driver_volume_type'],
 3516                          ret['driver_volume_type'])
 3517         for k, v in expected[protocol]['data'].items():
 3518             self.assertEqual(v, ret['data'][k])
 3519 
 3520         # Initialize again, should notice it and do nothing
 3521         ret = self.iscsi_driver.initialize_connection(
 3522             volume1, self._connector)
 3523         self.assertEqual(expected[protocol]['driver_volume_type'],
 3524                          ret['driver_volume_type'])
 3525         for k, v in expected[protocol]['data'].items():
 3526             self.assertEqual(v, ret['data'][k])
 3527 
 3528         # Try to delete the 1st volume (should fail because it is mapped)
 3529         self.assertRaises(exception.VolumeBackendAPIException,
 3530                           self.iscsi_driver.delete_volume,
 3531                           volume1)
 3532 
 3533         ret = self.iscsi_driver.terminate_connection(volume1,
 3534                                                      self._connector)
 3535         if self.USESIM:
 3536             ret = self.iscsi_driver._helpers.get_host_from_connector(
 3537                 self._connector)
 3538             self.assertIsNone(ret)
 3539 
 3540         # Check cases with no auth set for host
 3541         if self.USESIM:
 3542             for auth_enabled in [True, False]:
 3543                 for host_exists in ['yes-auth', 'yes-noauth', 'no']:
 3544                     self._set_flag('storwize_svc_iscsi_chap_enabled',
 3545                                    auth_enabled)
 3546                     case = 'en' + six.text_type(
 3547                         auth_enabled) + 'ex' + six.text_type(host_exists)
 3548                     conn_na = {'initiator': 'test:init:%s' %
 3549                                             random.randint(10000, 99999),
 3550                                'ip': '11.11.11.11',
 3551                                'host': 'host-%s' % case}
 3552                     if host_exists.startswith('yes'):
 3553                         self.sim._add_host_to_list(conn_na)
 3554                         if host_exists == 'yes-auth':
 3555                             kwargs = {'chapsecret': 'foo',
 3556                                       'obj': conn_na['host']}
 3557                             self.sim._cmd_chhost(**kwargs)
 3558                     volume1['volume_type_id'] = types['iSCSI']['id']
 3559 
 3560                     init_ret = self.iscsi_driver.initialize_connection(volume1,
 3561                                                                        conn_na)
 3562                     host_name = self.sim._host_in_list(conn_na['host'])
 3563                     chap_ret = (
 3564                         self.iscsi_driver._helpers.get_chap_secret_for_host(
 3565                             host_name))
 3566                     if auth_enabled or host_exists == 'yes-auth':
 3567                         self.assertIn('auth_password', init_ret['data'])
 3568                         self.assertIsNotNone(chap_ret)
 3569                     else:
 3570                         self.assertNotIn('auth_password', init_ret['data'])
 3571                         self.assertIsNone(chap_ret)
 3572                     self.iscsi_driver.terminate_connection(volume1, conn_na)
 3573         self._set_flag('storwize_svc_iscsi_chap_enabled', True)
 3574 
 3575         # Test no preferred node
 3576         if self.USESIM:
 3577             self.sim.error_injection('lsvdisk', 'no_pref_node')
 3578             self.assertRaises(exception.VolumeBackendAPIException,
 3579                               self.iscsi_driver.initialize_connection,
 3580                               volume1, self._connector)
 3581 
 3582         # Initialize connection from the second volume to the host with no
 3583         # preferred node set if in simulation mode, otherwise, just
 3584         # another initialize connection.
 3585         if self.USESIM:
 3586             self.sim.error_injection('lsvdisk', 'blank_pref_node')
 3587         self.iscsi_driver.initialize_connection(volume2, self._connector)
 3588 
 3589         # Try to remove connection from host that doesn't exist (should fail)
 3590         conn_no_exist = self._connector.copy()
 3591         conn_no_exist['initiator'] = 'i_dont_exist'
 3592         conn_no_exist['wwpns'] = ['0000000000000000']
 3593         self.assertRaises(exception.VolumeDriverException,
 3594                           self.iscsi_driver.terminate_connection,
 3595                           volume1,
 3596                           conn_no_exist)
 3597 
 3598         # Try to remove connection from volume that isn't mapped (should print
 3599         # message but NOT fail)
 3600         unmapped_vol = self._generate_vol_info(None, None)
 3601         self.iscsi_driver.create_volume(unmapped_vol)
 3602         self.iscsi_driver.terminate_connection(unmapped_vol, self._connector)
 3603         self.iscsi_driver.delete_volume(unmapped_vol)
 3604 
 3605         # Remove the mapping from the 1st volume and delete it
 3606         self.iscsi_driver.terminate_connection(volume1, self._connector)
 3607         self.iscsi_driver.delete_volume(volume1)
 3608         self._assert_vol_exists(volume1['name'], False)
 3609 
 3610         # Make sure our host still exists
 3611         host_name = self.iscsi_driver._helpers.get_host_from_connector(
 3612             self._connector, iscsi=True)
 3613         self.assertIsNotNone(host_name)
 3614 
 3615         # Remove the mapping from the 2nd volume. The host should
 3616         # be automatically removed because there are no more mappings.
 3617         self.iscsi_driver.terminate_connection(volume2, self._connector)
 3618 
 3619         # Check if we successfully terminate connections when the host is not
 3620         # specified (see bug #1244257)
 3621         fake_conn = {'ip': '127.0.0.1', 'initiator': 'iqn.fake'}
 3622         self.iscsi_driver.initialize_connection(volume2, self._connector)
 3623         host_name = self.iscsi_driver._helpers.get_host_from_connector(
 3624             self._connector, iscsi=True)
 3625         self.assertIsNotNone(host_name)
 3626         self.iscsi_driver.terminate_connection(volume2, fake_conn)
 3627         host_name = self.iscsi_driver._helpers.get_host_from_connector(
 3628             self._connector, iscsi=True)
 3629         self.assertIsNone(host_name)
 3630         self.iscsi_driver.delete_volume(volume2)
 3631         self._assert_vol_exists(volume2['name'], False)
 3632 
 3633         # Delete volume types that we created
 3634         for protocol in ['iSCSI']:
 3635             volume_types.destroy(ctxt, types[protocol]['id'])
 3636 
 3637         # Check if our host still exists (it should not)
 3638         if self.USESIM:
 3639             ret = (
 3640                 self.iscsi_driver._helpers.get_host_from_connector(
 3641                     self._connector, iscsi=True))
 3642             self.assertIsNone(ret)
 3643 
 3644     def test_storwize_svc_iscsi_multi_host_maps(self):
 3645         # We can't test connecting to multiple hosts from a single host when
 3646         # using real storage
 3647         if not self.USESIM:
 3648             return
 3649 
 3650         # Create a volume to be used in mappings
 3651         ctxt = context.get_admin_context()
 3652         volume = self._generate_vol_info(None, None)
 3653         self.iscsi_driver.create_volume(volume)
 3654 
 3655         # Create volume types for protocols
 3656         types = {}
 3657         for protocol in ['iSCSI']:
 3658             opts = {'storage_protocol': '<in> ' + protocol}
 3659             types[protocol] = volume_types.create(ctxt, protocol, opts)
 3660 
 3661         # Create a connector for the second 'host'
 3662         wwpns = [six.text_type(random.randint(0, 9999999999999999)).zfill(16),
 3663                  six.text_type(random.randint(0, 9999999999999999)).zfill(16)]
 3664         initiator = 'test.initiator.%s' % six.text_type(random.randint(10000,
 3665                                                                        99999))
 3666         conn2 = {'ip': '1.234.56.79',
 3667                  'host': 'storwize-svc-test2',
 3668                  'wwpns': wwpns,
 3669                  'initiator': initiator}
 3670 
 3671         # Check protocols for iSCSI
 3672         volume['volume_type_id'] = types[protocol]['id']
 3673 
 3674         # Make sure that the volume has been created
 3675         self._assert_vol_exists(volume['name'], True)
 3676 
 3677         self.iscsi_driver.initialize_connection(volume, self._connector)
 3678 
 3679         self._set_flag('storwize_svc_multihostmap_enabled', False)
 3680         self.assertRaises(
 3681             exception.CinderException,
 3682             self.iscsi_driver.initialize_connection, volume, conn2)
 3683 
 3684         self._set_flag('storwize_svc_multihostmap_enabled', True)
 3685         self.iscsi_driver.initialize_connection(volume, conn2)
 3686 
 3687         self.iscsi_driver.terminate_connection(volume, conn2)
 3688         self.iscsi_driver.terminate_connection(volume, self._connector)
 3689 
 3690     def test_add_vdisk_copy_iscsi(self):
 3691         # Ensure only iSCSI is available
 3692         self.iscsi_driver._state['enabled_protocols'] = set(['iSCSI'])
 3693         volume = self._generate_vol_info(None, None)
 3694         self.iscsi_driver.create_volume(volume)
 3695         self.iscsi_driver.add_vdisk_copy(volume['name'], 'fake-pool', None)
 3696 
 3697 
 3698 class StorwizeSVCFcDriverTestCase(test.TestCase):
 3699     @mock.patch.object(time, 'sleep')
 3700     def setUp(self, mock_sleep):
 3701         super(StorwizeSVCFcDriverTestCase, self).setUp()
 3702         self.USESIM = True
 3703         if self.USESIM:
 3704             self.fc_driver = StorwizeSVCFcFakeDriver(
 3705                 configuration=conf.Configuration(None))
 3706             self._def_flags = {'san_ip': 'hostname',
 3707                                'san_login': 'user',
 3708                                'san_password': 'pass',
 3709                                'storwize_svc_volpool_name':
 3710                                SVC_POOLS,
 3711                                'storwize_svc_flashcopy_timeout': 20,
 3712                                'storwize_svc_flashcopy_rate': 49,
 3713                                'storwize_svc_multipath_enabled': False,
 3714                                'storwize_svc_allow_tenant_qos': True}
 3715             wwpns = [
 3716                 six.text_type(random.randint(0, 9999999999999999)).zfill(16),
 3717                 six.text_type(random.randint(0, 9999999999999999)).zfill(16)]
 3718             initiator = 'test.initiator.%s' % six.text_type(
 3719                 random.randint(10000, 99999))
 3720             self._connector = {'ip': '1.234.56.78',
 3721                                'host': 'storwize-svc-test',
 3722                                'wwpns': wwpns,
 3723                                'initiator': initiator}
 3724             self.sim = StorwizeSVCManagementSimulator(SVC_POOLS)
 3725 
 3726             self.fc_driver.set_fake_storage(self.sim)
 3727             self.ctxt = context.get_admin_context()
 3728 
 3729         self._reset_flags()
 3730         self.ctxt = context.get_admin_context()
 3731         db_driver = self.fc_driver.configuration.db_driver
 3732         self.db = importutils.import_module(db_driver)
 3733         self.fc_driver.db = self.db
 3734         self.fc_driver.do_setup(None)
 3735         self.fc_driver.check_for_setup_error()
 3736         self.fc_driver._helpers.check_fcmapping_interval = 0
 3737 
 3738     def _set_flag(self, flag, value):
 3739         group = self.fc_driver.configuration.config_group
 3740         self.fc_driver.configuration.set_override(flag, value, group)
 3741 
 3742     def _reset_flags(self):
 3743         self.fc_driver.configuration.local_conf.reset()
 3744         for k, v in self._def_flags.items():
 3745             self._set_flag(k, v)
 3746 
 3747     def _create_volume(self, **kwargs):
 3748         pool = _get_test_pool()
 3749         prop = {'host': 'openstack@svc#%s' % pool,
 3750                 'size': 1,
 3751                 'volume_type_id': self.vt['id']}
 3752         for p in prop.keys():
 3753             if p not in kwargs:
 3754                 kwargs[p] = prop[p]
 3755         vol = testutils.create_volume(self.ctxt, **kwargs)
 3756         self.fc_driver.create_volume(vol)
 3757         return vol
 3758 
 3759     def _delete_volume(self, volume):
 3760         self.fc_driver.delete_volume(volume)
 3761         self.db.volume_destroy(self.ctxt, volume['id'])
 3762 
 3763     def _generate_vol_info(self, vol_name, vol_id):
 3764         pool = _get_test_pool()
 3765         prop = {'mdisk_grp_name': pool}
 3766         if vol_name:
 3767             prop.update(volume_name=vol_name,
 3768                         volume_id=vol_id,
 3769                         volume_size=10)
 3770         else:
 3771             prop.update(size=10,
 3772                         volume_type_id=None,
 3773                         mdisk_grp_name=pool,
 3774                         host='openstack@svc#%s' % pool)
 3775         vol = testutils.create_volume(self.ctxt, **prop)
 3776         return vol
 3777 
 3778     def _generate_snap_info(self, vol_id, size=10):
 3779         prop = {'volume_id': vol_id,
 3780                 'volume_size': size}
 3781         snap = testutils.create_snapshot(self.ctxt, **prop)
 3782         return snap
 3783 
 3784     def _assert_vol_exists(self, name, exists):
 3785         is_vol_defined = self.fc_driver._helpers.is_vdisk_defined(name)
 3786         self.assertEqual(exists, is_vol_defined)
 3787 
 3788     def test_storwize_get_host_with_fc_connection(self):
 3789         # Create a FC host
 3790         del self._connector['initiator']
 3791         helper = self.fc_driver._helpers
 3792         host_name = helper.create_host(self._connector)
 3793 
 3794         # Remove the first wwpn from connector, and then try get host
 3795         wwpns = self._connector['wwpns']
 3796         wwpns.remove(wwpns[0])
 3797         host_name = helper.get_host_from_connector(self._connector)
 3798 
 3799         self.assertIsNotNone(host_name)
 3800 
 3801     def test_storwize_fc_connection_snapshot(self):
 3802         # create a fc volume snapshot
 3803         volume_fc = self._create_volume()
 3804         snapshot = self._generate_snap_info(volume_fc.id)
 3805         self.fc_driver.create_snapshot(snapshot)
 3806         connector = {'host': 'storwize-svc-host',
 3807                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3808                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3809                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3810 
 3811         self.fc_driver.initialize_connection_snapshot(snapshot, connector)
 3812         self.fc_driver.terminate_connection_snapshot(snapshot, connector)
 3813 
 3814     def test_storwize_replication_failover_fc_connection_snapshot(self):
 3815         volume_fc = self._create_volume()
 3816         volume_fc['replication_status'] = fields.ReplicationStatus.FAILED_OVER
 3817         snapshot = self._generate_snap_info(volume_fc.id)
 3818         self.fc_driver.create_snapshot(snapshot)
 3819         connector = {'host': 'storwize-svc-host',
 3820                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3821                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3822                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3823         # a snapshot of a replication failover volume. attach will be failed
 3824         with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver,
 3825                                '_get_volume_replicated_type') as rep_type:
 3826             rep_type.return_value = True
 3827             with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver,
 3828                                    '_get_vol_sys_info') as sys_info:
 3829                 sys_info.return_value = {'volume_name': 'volfc',
 3830                                          'backend_helper':
 3831                                              'self._aux_backend_helpers',
 3832                                          'node_state': 'self._state'}
 3833                 self.assertRaises(exception.VolumeDriverException,
 3834                                   self.fc_driver.
 3835                                   initialize_connection_snapshot,
 3836                                   snapshot,
 3837                                   connector)
 3838 
 3839     def test_storwize_get_host_with_fc_connection_with_volume(self):
 3840         # create a FC volume
 3841         volume_fc = self._generate_vol_info(None, None)
 3842         self.fc_driver.create_volume(volume_fc)
 3843         extra_spec = {'capabilities:storage_protocol': '<in> FC'}
 3844         vol_type_fc = volume_types.create(self.ctxt, 'FC', extra_spec)
 3845         volume_fc['volume_type_id'] = vol_type_fc['id']
 3846 
 3847         connector = {'host': 'storwize-svc-host',
 3848                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 3849                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 3850                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 3851         self.fc_driver.initialize_connection(volume_fc, connector)
 3852         # Create a FC host
 3853         helper = self.fc_driver._helpers
 3854 
 3855         host_name = helper.get_host_from_connector(
 3856             connector, volume_fc['name'])
 3857         self.assertIsNotNone(host_name)
 3858 
 3859     def test_storwize_get_host_from_connector_with_lshost_failure(self):
 3860         self.skipTest('Bug 1640205')
 3861         self._connector.pop('initiator')
 3862         helper = self.fc_driver._helpers
 3863         # Create two hosts. The first is not related to the connector and
 3864         # we use the simulator for that. The second is for the connector.
 3865         # We will force the missing_host error for the first host, but
 3866         # then tolerate and find the second host on the slow path normally.
 3867         if self.USESIM:
 3868             self.sim._cmd_mkhost(name='storwize-svc-test-9', hbawwpn='123456')
 3869         helper.create_host(self._connector)
 3870         # tell lshost to fail while calling get_host_from_connector
 3871         if self.USESIM:
 3872             # tell lshost to fail while called from get_host_from_connector
 3873             self.sim.error_injection('lshost', 'missing_host')
 3874             # tell lsfabric to skip rows so that we skip past fast path
 3875             self.sim.error_injection('lsfabric', 'remove_rows')
 3876         # Run test
 3877         host_name = helper.get_host_from_connector(self._connector)
 3878 
 3879         self.assertIsNotNone(host_name)
 3880         # Need to assert that lshost was actually called. The way
 3881         # we do that is check that the next simulator error for lshost
 3882         # has been reset.
 3883         self.assertEqual(self.sim._next_cmd_error['lshost'], '',
 3884                          "lshost was not called in the simulator. The "
 3885                          "queued error still remains.")
 3886 
 3887     def test_storwize_get_host_from_connector_with_lshost_failure2(self):
 3888         self._connector.pop('initiator')
 3889         self._connector['wwpns'] = []  # Clearing will skip over fast-path
 3890         helper = self.fc_driver._helpers
 3891         if self.USESIM:
 3892             # Add a host to the simulator. We don't need it to match the
 3893             # connector since we will force a bad failure for lshost.
 3894             self.sim._cmd_mkhost(name='DifferentHost', hbawwpn='123456')
 3895             # tell lshost to fail badly while called from
 3896             # get_host_from_connector
 3897             self.sim.error_injection('lshost', 'bigger_troubles')
 3898             self.assertRaises(exception.VolumeBackendAPIException,
 3899                               helper.get_host_from_connector,
 3900                               self._connector)
 3901 
 3902     def test_storwize_get_host_from_connector_not_found(self):
 3903         self._connector.pop('initiator')
 3904         helper = self.fc_driver._helpers
 3905         # Create some hosts. The first is not related to the connector and
 3906         # we use the simulator for that. The second is for the connector.
 3907         # We will force the missing_host error for the first host, but
 3908         # then tolerate and find the second host on the slow path normally.
 3909         if self.USESIM:
 3910             self.sim._cmd_mkhost(name='storwize-svc-test-3', hbawwpn='1234567')
 3911             self.sim._cmd_mkhost(name='storwize-svc-test-2', hbawwpn='2345678')
 3912             self.sim._cmd_mkhost(name='storwize-svc-test-1', hbawwpn='3456789')
 3913             self.sim._cmd_mkhost(name='A-Different-host', hbawwpn='9345678')
 3914             self.sim._cmd_mkhost(name='B-Different-host', hbawwpn='8345678')
 3915             self.sim._cmd_mkhost(name='C-Different-host', hbawwpn='7345678')
 3916         # tell lshost to fail while calling get_host_from_connector
 3917         if self.USESIM:
 3918             # tell lsfabric to skip rows so that we skip past fast path
 3919             self.sim.error_injection('lsfabric', 'remove_rows')
 3920         # Run test
 3921         host_name = helper.get_host_from_connector(self._connector)
 3922 
 3923         self.assertIsNone(host_name)
 3924 
 3925     def test_storwize_get_host_from_connector_fast_path(self):
 3926         self._connector.pop('initiator')
 3927         helper = self.fc_driver._helpers
 3928         # Create two hosts. Our lshost will return the hosts in sorted
 3929         # Order. The extra host will be returned before the target
 3930         # host. If we get detailed lshost info on our host without
 3931         # gettting detailed info on the other host we used the fast path
 3932         if self.USESIM:
 3933             self.sim._cmd_mkhost(name='A-DifferentHost', hbawwpn='123456')
 3934         helper.create_host(self._connector)
 3935         # tell lshost to fail while calling get_host_from_connector
 3936         if self.USESIM:
 3937             # tell lshost to fail while called from get_host_from_connector
 3938             self.sim.error_injection('lshost', 'fail_fastpath')
 3939             # tell lsfabric to skip rows so that we skip past fast path
 3940             self.sim.error_injection('lsfabric', 'remove_rows')
 3941         # Run test
 3942         host_name = helper.get_host_from_connector(self._connector)
 3943 
 3944         self.assertIsNotNone(host_name)
 3945         # Need to assert that lshost was actually called. The way
 3946         # we do that is check that the next simulator error for lshost
 3947         # has not been reset.
 3948         self.assertEqual(self.sim._next_cmd_error['lshost'], 'fail_fastpath',
 3949                          "lshost was not called in the simulator. The "
 3950                          "queued error still remains.")
 3951 
 3952     def test_storwize_initiator_multiple_wwpns_connected(self):
 3953 
 3954         # Generate us a test volume
 3955         volume = self._create_volume()
 3956 
 3957         # Fibre Channel volume type
 3958         extra_spec = {'capabilities:storage_protocol': '<in> FC'}
 3959         vol_type = volume_types.create(self.ctxt, 'FC', extra_spec)
 3960 
 3961         volume['volume_type_id'] = vol_type['id']
 3962 
 3963         # Make sure that the volumes have been created
 3964         self._assert_vol_exists(volume['name'], True)
 3965 
 3966         # Set up one WWPN that won't match and one that will.
 3967         self.fc_driver._state['storage_nodes']['1']['WWPN'] = [
 3968             '123456789ABCDEF0', 'AABBCCDDEEFF0010']
 3969 
 3970         wwpns = ['ff00000000000000', 'ff00000000000001']
 3971         connector = {'host': 'storwize-svc-test', 'wwpns': wwpns}
 3972 
 3973         with mock.patch.object(storwize_svc_common.StorwizeHelpers,
 3974                                'get_conn_fc_wwpns') as get_mappings:
 3975             mapped_wwpns = ['AABBCCDDEEFF0001', 'AABBCCDDEEFF0002',
 3976                             'AABBCCDDEEFF0010', 'AABBCCDDEEFF0012']
 3977             get_mappings.return_value = mapped_wwpns
 3978 
 3979             # Initialize the connection
 3980             init_ret = self.fc_driver.initialize_connection(volume, connector)
 3981 
 3982             # Make sure we return all wwpns which where mapped as part of the
 3983             # connection
 3984             self.assertEqual(mapped_wwpns,
 3985                              init_ret['data']['target_wwn'])
 3986 
 3987     def test_storwize_svc_fc_validate_connector(self):
 3988         conn_neither = {'host': 'host'}
 3989         conn_iscsi = {'host': 'host', 'initiator': 'foo'}
 3990         conn_fc = {'host': 'host', 'wwpns': 'bar'}
 3991         conn_both = {'host': 'host', 'initiator': 'foo', 'wwpns': 'bar'}
 3992 
 3993         self.fc_driver._state['enabled_protocols'] = set(['FC'])
 3994         self.fc_driver.validate_connector(conn_fc)
 3995         self.fc_driver.validate_connector(conn_both)
 3996         self.assertRaises(exception.InvalidConnectorException,
 3997                           self.fc_driver.validate_connector, conn_iscsi)
 3998         self.assertRaises(exception.InvalidConnectorException,
 3999                           self.fc_driver.validate_connector, conn_neither)
 4000 
 4001         self.fc_driver._state['enabled_protocols'] = set(['iSCSI', 'FC'])
 4002         self.fc_driver.validate_connector(conn_fc)
 4003         self.fc_driver.validate_connector(conn_both)
 4004         self.assertRaises(exception.InvalidConnectorException,
 4005                           self.fc_driver.validate_connector, conn_neither)
 4006 
 4007     def test_storwize_terminate_fc_connection(self):
 4008         # create a FC volume
 4009         volume_fc = self._create_volume()
 4010         extra_spec = {'capabilities:storage_protocol': '<in> FC'}
 4011         vol_type_fc = volume_types.create(self.ctxt, 'FC', extra_spec)
 4012         volume_fc['volume_type_id'] = vol_type_fc['id']
 4013 
 4014         connector = {'host': 'storwize-svc-host',
 4015                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 4016                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 4017                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 4018 
 4019         self.fc_driver.initialize_connection(volume_fc, connector)
 4020         self.fc_driver.initialize_connection(volume_fc, connector)
 4021         self.fc_driver.terminate_connection(volume_fc, connector)
 4022         with mock.patch.object(
 4023                 storwize_svc_common.StorwizeSSH,
 4024                 'mkvdiskhostmap') as mkvdiskhostmap:
 4025             ex = exception.VolumeBackendAPIException(data='CMMVC5879E')
 4026             mkvdiskhostmap.side_effect = [ex, ex, mock.MagicMock()]
 4027             self.fc_driver.initialize_connection(volume_fc, connector)
 4028             self.fc_driver.terminate_connection(volume_fc, connector)
 4029             mkvdiskhostmap.side_effect = ex
 4030             self.assertRaises(exception.VolumeBackendAPIException,
 4031                               self.fc_driver.initialize_connection,
 4032                               volume_fc,
 4033                               connector)
 4034             ex1 = exception.VolumeBackendAPIException(data='CMMVC6071E')
 4035             mkvdiskhostmap.side_effect = ex1
 4036             self._set_flag('storwize_svc_multihostmap_enabled', False)
 4037             self.assertRaises(exception.VolumeDriverException,
 4038                               self.fc_driver.initialize_connection,
 4039                               volume_fc,
 4040                               connector)
 4041             ex2 = exception.VolumeBackendAPIException(data='CMMVC5707E')
 4042             mkvdiskhostmap.side_effect = ex2
 4043             self.assertRaises(exception.VolumeBackendAPIException,
 4044                               self.fc_driver.initialize_connection,
 4045                               volume_fc,
 4046                               connector)
 4047 
 4048     def test_storwize_initialize_fc_connection_with_host_site(self):
 4049         connector = {'host': 'storwize-svc-host',
 4050                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 4051                      'wwpns': ['ffff000000000000', 'ffff000000000001'],
 4052                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 4053         # attach hyperswap volume without host_site
 4054         volume_fc = self._create_volume()
 4055         extra_spec = {'drivers:volume_topology': 'hyperswap',
 4056                       'peer_pool': 'openstack1'}
 4057         vol_type_fc = volume_types.create(self.ctxt, 'FC', extra_spec)
 4058         volume_fc['volume_type_id'] = vol_type_fc['id']
 4059         volume_fc_2 = self._create_volume()
 4060         volume_fc_2['volume_type_id'] = vol_type_fc['id']
 4061 
 4062         self.assertRaises(exception.VolumeDriverException,
 4063                           self.fc_driver.initialize_connection,
 4064                           volume_fc,
 4065                           connector)
 4066         # the wwpns of 1 host config to 2 different sites
 4067         host_site = {'site1': 'ffff000000000000',
 4068                      'site2': 'ffff000000000001'}
 4069         self.fc_driver.configuration.set_override(
 4070             'storwize_preferred_host_site', host_site)
 4071         self.assertRaises(exception.InvalidConfigurationValue,
 4072                           self.fc_driver.initialize_connection,
 4073                           volume_fc,
 4074                           connector)
 4075         # All the wwpns of this host are not configured.
 4076         host_site_2 = {'site1': 'ff00000000000000',
 4077                        'site2': 'ff00000000000001'}
 4078         self.fc_driver.configuration.set_override(
 4079             'storwize_preferred_host_site', host_site_2)
 4080         self.assertRaises(exception.VolumeDriverException,
 4081                           self.fc_driver.initialize_connection,
 4082                           volume_fc,
 4083                           connector)
 4084 
 4085         # All the wwpns of this host are configured
 4086         host_site_3 = {'site1': 'ffff000000000000&ffff000000000001'}
 4087         self.fc_driver.configuration.set_override(
 4088             'storwize_preferred_host_site', host_site_3)
 4089         self.fc_driver.initialize_connection(volume_fc, connector)
 4090         host_name = self.fc_driver._helpers.get_host_from_connector(
 4091             connector, iscsi=True)
 4092         host_info = self.fc_driver._helpers.ssh.lshost(host=host_name)
 4093         self.assertEqual('site1', host_info[0]['site_name'])
 4094 
 4095         # Partial wwpns of this host are configured
 4096         host_site_4 = {'site1': 'ff00000000000000',
 4097                        'site2': 'ffff000000000001'}
 4098         self.fc_driver.configuration.set_override(
 4099             'storwize_preferred_host_site', host_site_4)
 4100         self.assertRaises(exception.InvalidConfigurationValue,
 4101                           self.fc_driver.initialize_connection,
 4102                           volume_fc_2,
 4103                           connector)
 4104 
 4105     @mock.patch.object(storwize_svc_fc.StorwizeSVCFCDriver,
 4106                        '_do_terminate_connection')
 4107     @mock.patch.object(storwize_svc_fc.StorwizeSVCFCDriver,
 4108                        '_do_initialize_connection')
 4109     def test_storwize_do_terminate_fc_connection(self, init_conn,
 4110                                                  term_conn):
 4111         # create a FC volume
 4112         volume_fc = self._create_volume()
 4113         extra_spec = {'capabilities:storage_protocol': '<in> FC'}
 4114         vol_type_fc = volume_types.create(self.ctxt, 'FC', extra_spec)
 4115         volume_fc['volume_type_id'] = vol_type_fc['id']
 4116 
 4117         connector = {'host': 'storwize-svc-host',
 4118                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 4119                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 4120                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 4121 
 4122         self.fc_driver.initialize_connection(volume_fc, connector)
 4123         self.fc_driver.terminate_connection(volume_fc, connector)
 4124         init_conn.assert_called_once_with(volume_fc, connector)
 4125         term_conn.assert_called_once_with(volume_fc, connector)
 4126 
 4127     @mock.patch.object(storwize_svc_fc.StorwizeSVCFCDriver,
 4128                        '_do_terminate_connection')
 4129     def test_storwize_initialize_fc_connection_failure(self, term_conn):
 4130         # create a FC volume
 4131         volume_fc = self._create_volume()
 4132         extra_spec = {'capabilities:storage_protocol': '<in> FC'}
 4133         vol_type_fc = volume_types.create(self.ctxt, 'FC', extra_spec)
 4134         volume_fc['volume_type_id'] = vol_type_fc['id']
 4135 
 4136         connector = {'host': 'storwize-svc-host',
 4137                      'wwnns': ['20000090fa17311e', '20000090fa17311f'],
 4138                      'wwpns': ['ff00000000000000', 'ff00000000000001'],
 4139                      'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
 4140 
 4141         self.fc_driver._state['storage_nodes'] = {}
 4142         self.assertRaises(exception.VolumeBackendAPIException,
 4143                           self.fc_driver.initialize_connection,
 4144                           volume_fc, connector)
 4145         term_conn.assert_called_once_with(volume_fc, connector)
 4146 
 4147     def test_storwize_terminate_fc_connection_multi_attach(self):
 4148         # create a FC volume
 4149         volume_fc = self._create_volume()
 4150         extra_spec = {'capabilities:storage_protocol': '<in> FC'}
 4151         vol_type_fc = volume_types.create(self.ctxt, 'FC', extra_spec)
 4152         volume_fc['volume_type_id'] = vol_type_fc['