Best Python code snippet using avocado_python
huawei_iscsi.py
Source:huawei_iscsi.py  
1# vim: tabstop=4 shiftwidth=4 softtabstop=42# Copyright (c) 2012 Huawei Technologies Co., Ltd.3# Copyright (c) 2012 OpenStack LLC.4# All Rights Reserved.5#6#    Licensed under the Apache License, Version 2.0 (the "License"); you may7#    not use this file except in compliance with the License. You may obtain8#    a copy of the License at9#10#         http://www.apache.org/licenses/LICENSE-2.011#12#    Unless required by applicable law or agreed to in writing, software13#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT14#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the15#    License for the specific language governing permissions and limitations16#    under the License.17"""18Volume driver for HUAWEI T series and Dorado storage systems.19"""20import re21import socket22import time23from oslo.config import cfg24from xml.etree import ElementTree as ET25from cinder import exception26from cinder.openstack.common import excutils27from cinder.openstack.common import log as logging28from cinder import utils29from cinder.volume import driver30LOG = logging.getLogger(__name__)31huawei_opt = [32    cfg.StrOpt('cinder_huawei_conf_file',33               default='/etc/cinder/cinder_huawei_conf.xml',34               help='config data for cinder huawei plugin')]35HOST_GROUP_NAME = 'HostGroup_OpenStack'36HOST_NAME_PREFIX = 'Host_'37HOST_PORT_PREFIX = 'HostPort_'38VOL_AND_SNAP_NAME_FREFIX = 'OpenStack_'39READBUFFERSIZE = 819240class SSHConnection(utils.SSHPool):41    """An SSH connetion class .42    For some reasons, we can not use method ssh_execute defined in utils to43    send CLI commands. Here we define a new class inherited to SSHPool. Use44    method create() to build a new SSH client and use invoke_shell() to start45    an interactive shell session on the storage system.46    """47    def __init__(self, ip, port, login, password, conn_timeout,48                 privatekey=None, *args, **kwargs):49        self.ssh = None50        super(SSHConnection, self).__init__(ip, port, conn_timeout, login,51                                            password, privatekey=None,52                                            *args, **kwargs)53    def connect(self):54        """Create an SSH client and open an interactive SSH channel."""55        self.ssh = self.create()56        self.channel = self.ssh.invoke_shell()57        self.channel.resize_pty(600, 800)58    def close(self):59        """Close SSH connection."""60        self.channel.close()61        self.ssh.close()62    def read(self, timeout=None):63        """Read data from SSH channel."""64        result = ''65        user_flg = self.login + ':/>$'66        self.channel.settimeout(timeout)67        while True:68            try:69                result = result + self.channel.recv(READBUFFERSIZE)70            except socket.timeout:71                break72            else:73                # If we get the complete result string, then no need to wait74                # until time out.75                if re.search(user_flg, result) or re.search('(y/n)', result):76                    break77        return result78    def send_cmd(self, strcmd, timeout, waitstr=None):79        """Send SSH commands and return results."""80        info = ''81        self.channel.send(strcmd + '\n')82        result = self.read(timeout)83        info = '\r\n'.join(result.split('\r\n')[1:-1])84        return info85class HuaweiISCSIDriver(driver.ISCSIDriver):86    """Huawei T series and Dorado iSCSI volume driver."""87    def __init__(self, *args, **kwargs):88        super(HuaweiISCSIDriver, self).__init__(*args, **kwargs)89        self.configuration.append_config_values(huawei_opt)90        self.device_type = {}91        self.login_info = {}92        self.hostgroup_id = None93        # Flag to tell whether the other controller is available94        # if the current controller can not be connected to.95        self.controller_alterable = True96    def do_setup(self, context):97        """Check config file."""98        LOG.debug(_('do_setup.'))99        self._check_conf_file()100        # Create hostgroup.101        self.login_info = self._get_login_info()102        hostgroup_name = HOST_GROUP_NAME103        self.hostgroup_id = self._find_hostgroup(hostgroup_name)104        if not self.hostgroup_id:105            self._create_hostgroup(hostgroup_name)106            self.hostgroup_id = self._find_hostgroup(hostgroup_name)107    def check_for_setup_error(self):108        """Try to connect with device and get device type."""109        LOG.debug(_('check_for_setup_error.'))110        self.login_info = self._get_login_info()111        self.device_type = self._get_device_type()112        if not self.device_type['type']:113            err_msg = (_('check_for_setup_error: Can not get device type.'))114            LOG.error(err_msg)115            raise exception.VolumeBackendAPIException(data=err_msg)116        LOG.debug(_('check_for_setup_error: Device type is:%(type)s, '117                    'version is:%(version)s.')118                  % {'type': self.device_type['type'],119                     'version': self.device_type['version']})120        # Now only version V1 is supported.121        if self.device_type['version'] != 'V100R':122            err_msg = (_('check_for_setup_error: Product version not right. '123                         'Please make sure the product version is V1.'))124            LOG.error(err_msg)125            raise exception.VolumeBackendAPIException(data=err_msg)126    def create_volume(self, volume):127        """Create a new volume."""128        volume_name = self._name_translate(volume['name'])129        LOG.debug(_('create_volume:volume name: %s.') % volume_name)130        self.login_info = self._get_login_info()131        if int(volume['size']) == 0:132            volume_sise = '100M'133        else:134            volume_sise = '%sG' % volume['size']135        self._create_volume(volume_name, volume_sise)136    def delete_volume(self, volume):137        """Delete a volume."""138        volume_name = self._name_translate(volume['name'])139        LOG.debug(_('delete_volume: volume name: %s.') % volume_name)140        self.login_info = self._get_login_info()141        volume_id = self._find_lun(volume_name)142        if volume_id:143            self._delete_volume(volume_name, volume_id)144        else:145            err_msg = (_('delete_volume:No need to delete volume.'146                         'Volume %(name)s does not exist.')147                       % {'name': volume['name']})148            LOG.error(err_msg)149    def create_export(self, context, volume):150        """Driver entry point to get the  export info for a new volume."""151        volume_name = self._name_translate(volume['name'])152        LOG.debug(_('create_export: volume name:%s') % volume['name'])153        lun_id = self._find_lun(volume_name)154        if not lun_id:155            err_msg = (_('create_export:Volume %(name)s does not exist.')156                       % {'name': volume_name})157            LOG.error(err_msg)158            raise exception.VolumeBackendAPIException(data=err_msg)159        return {'provider_location': lun_id}160    def ensure_export(self, context, volume):161        """Driver entry point to get the export info for a existing volume."""162        pass163    def remove_export(self, context, volume_id):164        """Driver entry point to remove an export for a volume."""165        pass166    def initialize_connection(self, volume, connector):167        """Map a volume to a host and return target iSCSI information."""168        initiator_name = connector['initiator']169        volume_name = self._name_translate(volume['name'])170        LOG.debug(_('initialize_connection: volume name: %(volume)s. '171                    'initiator name: %(ini)s.')172                  % {'volume': volume_name,173                     'ini': initiator_name})174        host_name = HOST_NAME_PREFIX + str(hash(initiator_name))175        host_id = self._find_host_in_hostgroup(host_name, self.hostgroup_id)176        if not host_id:177            self._add_host(host_name, self.hostgroup_id)178            host_id = self._find_host_in_hostgroup(host_name,179                                                   self.hostgroup_id)180        # Create an initiator.181        added = self._check_initiator(initiator_name)182        if not added:183            self._add_initiator(initiator_name)184        # Add the initiator to host.185        port_name = HOST_PORT_PREFIX + str(hash(initiator_name))186        port_info = initiator_name187        portadded = False188        hostport_info = self._get_hostport_info(host_id)189        if hostport_info:190            for hostport in hostport_info:191                if hostport['info'] == initiator_name:192                    portadded = True193                    break194        if not portadded:195            self._add_hostport(port_name, host_id, port_info)196        LOG.debug(_('initialize_connection:host name: %(host)s,'197                    'initiator name: %(ini)s, '198                    'hostport name: %(port)s')199                  % {'host': host_name,200                     'ini': initiator_name,201                     'port': port_name})202        # Get target iSCSI iqn.203        iscsi_conf = self._get_iscsi_info()204        target_ip = None205        for ini in iscsi_conf['Initiator']:206            if ini['Name'] == initiator_name:207                target_ip = ini['TargetIP']208                break209        if not target_ip:210            target_ip = iscsi_conf['DefaultTargetIP']211        target_iqn = self._get_tgt_iqn(target_ip)212        if not target_iqn:213            err_msg = (_('initialize_connection:'214                         'Failed to find target iSCSI iqn.'))215            LOG.error(err_msg)216            raise exception.VolumeBackendAPIException(data=err_msg)217        # Map a LUN to a host if not mapped.218        lun_id = self._find_lun(volume_name)219        if not lun_id:220            err_msg = (_('initialize_connection:Failed to find the '221                         'given volume. '222                         'volume name:%(volume)s.')223                       % {'volume': volume_name})224            raise exception.VolumeBackendAPIException(data=err_msg)225        hostlun_id = None226        map_info = self._get_map_info(host_id)227        # Make sure the hostLUN ID starts from 1.228        new_hostlun_id = 1229        new_hostlunid_found = False230        if map_info:231            for map in map_info:232                if map['devlunid'] == lun_id:233                    hostlun_id = map['hostlunid']234                    break235                elif not new_hostlunid_found:236                    if new_hostlun_id < int(map['hostlunid']):237                        new_hostlunid_found = True238                    else:239                        new_hostlun_id = int(map['hostlunid']) + 1240        # The LUN is not mapped to the host.241        if not hostlun_id:242            self._map_lun(lun_id, host_id, new_hostlun_id)243            hostlun_id = self._get_hostlunid(host_id, lun_id)244        # Return iSCSI properties.245        properties = {}246        properties['target_discovered'] = False247        properties['target_portal'] = ('%s:%s' % (target_ip, '3260'))248        properties['target_iqn'] = target_iqn249        properties['target_lun'] = int(hostlun_id)250        properties['volume_id'] = volume['id']251        auth = volume['provider_auth']252        if auth:253            (auth_method, auth_username, auth_secret) = auth.split()254            properties['auth_method'] = auth_method255            properties['auth_username'] = auth_username256            properties['auth_password'] = auth_secret257        return {'driver_volume_type': 'iscsi', 'data': properties}258    def terminate_connection(self, volume, connector, **kwargs):259        """Delete map between a volume and a host."""260        initiator_name = connector['initiator']261        volume_name = self._name_translate(volume['name'])262        LOG.debug(_('terminate_connection:volume name: %(volume)s, '263                    'initiator name: %(ini)s.')264                  % {'volume': volume_name,265                     'ini': initiator_name})266        self.login_info = self._get_login_info()267        host_name = HOST_NAME_PREFIX + str(hash(initiator_name))268        host_id = self._find_host_in_hostgroup(host_name, self.hostgroup_id)269        if not host_id:270            err_msg = (_('terminate_connection:Host does not exist. '271                         'Host name:%(host)s.')272                       % {'host': host_name})273            LOG.error(err_msg)274            raise exception.VolumeBackendAPIException(data=err_msg)275        # Delete host map.276        lun_id = self._find_lun(volume_name)277        if not lun_id:278            err_msg = (_('terminate_connection:volume does not exist.'279                         'volume name:%(volume)s')280                       % {'volume': volume_name})281            LOG.error(err_msg)282            raise exception.VolumeBackendAPIException(data=err_msg)283        map_id = None284        mapnum = 0285        map_info = self._get_map_info(host_id)286        if map_info:287            mapnum = len(map_info)288            for map in map_info:289                if map['devlunid'] == lun_id:290                    map_id = map['mapid']291                    break292        if map_id:293            self._delete_map(map_id)294            mapnum = mapnum - 1295        else:296            LOG.error(_('terminate_connection:No map between host '297                        'and volume. Host name:%(hostname)s,'298                        'volume name:%(volumename)s.')299                      % {'hostname': host_name,300                         'volumename': volume_name})301        # Delete host initiator when no LUN mapped to it.302        portnum = 0303        hostportinfo = self._get_hostport_info(host_id)304        if hostportinfo:305            portnum = len(hostportinfo)306            for hostport in hostportinfo:307                if hostport['info'] == initiator_name and mapnum == 0:308                    self._delete_hostport(hostport['id'])309                    self._delete_initiator(initiator_name)310                    portnum = portnum - 1311                    break312        else:313            LOG.error(_('terminate_connection:No initiator is added '314                        'to the host. Host name:%(hostname)s')315                      % {'hostname': host_name})316        # Delete host when no initiator added to it.317        if portnum == 0:318            self._delete_host(host_id)319    def create_snapshot(self, snapshot):320        """Create a snapshot."""321        snapshot_name = self._name_translate(snapshot['name'])322        volume_name = self._name_translate(snapshot['volume_name'])323        LOG.debug(_('create_snapshot:snapshot name:%(snapshot)s, '324                    'volume name:%(volume)s.')325                  % {'snapshot': snapshot_name,326                     'volume': volume_name})327        self.login_info = self._get_login_info()328        if self.device_type['type'] == 'Dorado2100 G2':329            err_msg = (_('create_snapshot:Device does not support snapshot.'))330            LOG.error(err_msg)331            raise exception.VolumeBackendAPIException(data=err_msg)332        if self._is_resource_pool_enough() is False:333            err_msg = (_('create_snapshot:'334                         'Resource pool needs 1GB valid size at least.'))335            LOG.error(err_msg)336            raise exception.VolumeBackendAPIException(data=err_msg)337        lun_id = self._find_lun(volume_name)338        if not lun_id:339            err_msg = (_('create_snapshot:Volume does not exist.'340                         'Volume name:%(name)s')341                       % {'name': volume_name})342            LOG.error(err_msg)343            raise exception.VolumeBackendAPIException(data=err_msg)344        self._create_snapshot(snapshot_name, lun_id)345        snapshot_id = self._find_snapshot(snapshot_name)346        if not snapshot_id:347            err_msg = (_('create_snapshot:Snapshot does not exist.'348                         'Snapshot name:%(name)s')349                       % {'name': snapshot_name})350            LOG.error(err_msg)351            raise exception.VolumeBackendAPIException(data=err_msg)352        self._active_snapshot(snapshot_id)353    def delete_snapshot(self, snapshot):354        """Delete a snapshot."""355        snapshot_name = self._name_translate(snapshot['name'])356        volume_name = self._name_translate(snapshot['volume_name'])357        LOG.debug(_('delete_snapshot:snapshot name:%(snapshot)s, '358                    'volume name:%(volume)s.')359                  % {'snapshot': snapshot_name,360                     'volume': volume_name})361        self.login_info = self._get_login_info()362        if self.device_type['type'] == 'Dorado2100 G2':363            err_msg = (_('delete_snapshot:Device does not support snapshot.'))364            LOG.error(err_msg)365            raise exception.VolumeBackendAPIException(data=err_msg)366        snapshot_id = self._find_snapshot(snapshot_name)367        if snapshot_id:368            self._disable_snapshot(snapshot_id)369            self._delete_snapshot(snapshot_id)370        else:371            err_msg = (_('delete_snapshot:Snapshot does not exist. '372                         'snapshot name:%(snap)s')373                       % {'snap': snapshot_name})374            LOG.debug(err_msg)375    def create_volume_from_snapshot(self, volume, snapshot):376        """Create a volume from a snapshot.377        We use LUNcopy to create a new LUN from snapshot.378        """379        snapshot_name = self._name_translate(snapshot['name'])380        volume_name = self._name_translate(volume['name'])381        LOG.debug(_('create_volume_from_snapshot:snapshot '382                    'name:%(snapshot)s, '383                    'volume name:%(volume)s.')384                  % {'snapshot': snapshot_name,385                     'volume': volume_name})386        self.login_info = self._get_login_info()387        if self.device_type['type'].find('Dorado') > -1:388            err_msg = (_('create_volume_from_snapshot:Device does '389                         'not support create volume from snapshot. '390                         'Volume name:%(volume)s, '391                         'snapshot name:%(snapshot)s.')392                       % {'volume': volume_name,393                          'snapshot': snapshot_name})394            LOG.error(err_msg)395            raise exception.VolumeBackendAPIException(data=err_msg)396        snapshot_id = self._find_snapshot(snapshot_name)397        if not snapshot_id:398            err_msg = (_('create_volume_from_snapshot:Snapshot does not exist.'399                         'Snapshot name:%(name)s')400                       % {'name': snapshot_name})401            LOG.error(err_msg)402            raise exception.VolumeBackendAPIException(data=err_msg)403        # Create a target LUN.404        if int(volume['size']) == 0:405            volume_size = '%sG' % snapshot['volume_size']406        else:407            volume_size = '%sG' % volume['size']408        self._create_volume(volume_name, volume_size)409        volume_id = self._find_lun(volume_name)410        luncopy_name = volume_name411        try:412            self._create_luncopy(luncopy_name, snapshot_id, volume_id)413            luncopy_id = self._find_luncopy(luncopy_name)414            self._start_luncopy(luncopy_id)415            self._wait_for_luncopy(luncopy_name)416        # If LUNcopy failed,we should delete the target volume.417        except Exception:418            with excutils.save_and_reraise_exception():419                self._delete_luncopy(luncopy_id)420                self._delete_volume(volume_name, volume_id)421        self._delete_luncopy(luncopy_id)422    def get_volume_stats(self, refresh=False):423        """Get volume status.424        If 'refresh' is True, run update the stats first.425        """426        if refresh:427            self._update_volume_status()428        return self._stats429    def _check_conf_file(self):430        """Check the config file, make sure the key elements are set."""431        root = self._read_xml()432        try:433            IP1 = root.findtext('Storage/ControllerIP0')434            IP2 = root.findtext('Storage/ControllerIP1')435            username = root.findtext('Storage/UserName')436            pwd = root.findtext('Storage/UserPassword')437            pool = root.findall('LUN/StoragePool')438            isconfwrong = False439            if ((not IP1 and not IP2) or440                    (not username) or441                    (not pwd) or442                    (not pool)):443                isconfwrong = True444            elif not pool[0].attrib['Name']:445                isconfwrong = True446            if isconfwrong is True:447                err_msg = (_('Config file is wrong. '448                             'Controler IP, UserName, UserPassword and '449                             'StoragePool must be set.'))450                LOG.error(err_msg)451                raise exception.InvalidInput(reason=err_msg)452        except Exception as err:453            LOG.error(_('_check_conf_file: %s') % str(err))454            raise exception.VolumeBackendAPIException(data=err)455    def _read_xml(self):456        """Open xml file."""457        filename = self.configuration.cinder_huawei_conf_file458        try:459            tree = ET.parse(filename)460            root = tree.getroot()461        except Exception as err:462            LOG.error(_('_read_xml:%s') % err)463            raise exception.VolumeBackendAPIException(data=err)464        return root465    def _get_login_info(self):466        """Get login IP, username and password from config file."""467        logininfo = {}468        root = self._read_xml()469        try:470            logininfo['ControllerIP0'] = root.findtext('Storage/ControllerIP0')471            logininfo['ControllerIP1'] = root.findtext('Storage/ControllerIP1')472            logininfo['UserName'] = root.findtext('Storage/UserName')473            logininfo['UserPassword'] = root.findtext('Storage/UserPassword')474        except Exception as err:475            LOG.debug(_('_get_login_info error. %s') % err)476            raise exception.VolumeBackendAPIException(data=err)477        return logininfo478    def _get_lun_set_info(self):479        """Get parameters from config file for creating LUN."""480        # Default LUN set information481        lunsetinfo = {'LUNType': 'Thick',482                      'StripUnitSize': '64',483                      'WriteType': '1',484                      'MirrorSwitch': '1',485                      'PrefetchType': '3',486                      'PrefetchValue': '0',487                      'PrefetchTimes': '0',488                      'StoragePool': 'RAID_001'}489        root = self._read_xml()490        try:491            luntype = root.findtext('LUN/LUNType')492            if luntype in ['Thick', 'Thin']:493                lunsetinfo['LUNType'] = luntype494            elif luntype is not '' or luntype is not None:495                err_msg = (_('Config file is wrong. LUNType must be "Thin"'496                             ' or "Thick". LUNType:%(type)s')497                           % {'type': luntype})498                raise exception.VolumeBackendAPIException(data=err_msg)499            # Here we do not judge whether the parameters are right.500            # CLI will return error responses if the parameters not right.501            stripunitsize = root.findtext('LUN/StripUnitSize')502            if stripunitsize is not '' and stripunitsize is not None:503                lunsetinfo['StripUnitSize'] = stripunitsize504            writetype = root.findtext('LUN/WriteType')505            if writetype is not '' and writetype is not None:506                lunsetinfo['WriteType'] = writetype507            mirrorswitch = root.findtext('LUN/MirrorSwitch')508            if mirrorswitch is not '' and mirrorswitch is not None:509                lunsetinfo['MirrorSwitch'] = mirrorswitch510            if self.device_type['type'] == 'Tseries':511                pooltype = luntype512                prefetch = root.find('LUN/Prefetch')513                if ((prefetch is not None) and514                        (prefetch.attrib['Type'] != '')):515                    lunsetinfo['PrefetchType'] = prefetch.attrib['Type']516                    if lunsetinfo['PrefetchType'] == '1':517                        lunsetinfo['PrefetchValue'] = prefetch.attrib['Value']518                    elif lunsetinfo['PrefetchType'] == '2':519                        lunsetinfo['PrefetchTimes'] = prefetch.attrib['Value']520                else:521                    LOG.debug(_('_get_lun_set_info:Use default prefetch type. '522                                'Prefetch type:Intelligent.'))523            # No need to set Prefetch type for Dorado.524            elif self.device_type['type'] == 'Dorado5100':525                pooltype = 'Thick'526            elif self.device_type['type'] == 'Dorado2100 G2':527                return lunsetinfo528            poolsinfo = self._find_pool_info(pooltype)529            if not poolsinfo:530                err_msg = (_('_get_lun_set_info:No available pools! '531                             'Please check whether storage pool is created.'))532                LOG.error(err_msg)533                raise exception.VolumeBackendAPIException(data=err_msg)534            pools = root.findall('LUN/StoragePool')535            lunsetinfo['StoragePool'] = \536                self._get_maximum_pool(pools, poolsinfo, luntype)537        except Exception as err:538            LOG.error(_('_get_lun_set_info:%s') % err)539            raise exception.VolumeBackendAPIException(data=err)540        return lunsetinfo541    def _find_pool_info(self, pooltype):542        """Return pools information created in storage device."""543        if pooltype == 'Thick':544            cli_cmd = ('showrg')545        else:546            cli_cmd = ('showpool')547        out = self._execute_cli(cli_cmd)548        en = out.split('\r\n')549        if len(en) <= 6:550            return None551        pools_list = []552        for i in range(6, len(en) - 2):553            r = en[i].split()554            pools_list.append(r)555        return pools_list556    def _get_maximum_pool(self, poolinconf, poolindev, luntype):557        """Get the maximum pool from config file.558        According to the given pools' name in config file,559        we select the pool of maximum free capacity.560        """561        maxpoolid = None562        maxpoolsize = 0563        if luntype == 'Thin':564            nameindex = 1565            sizeindex = 4566        else:567            nameindex = 5568            sizeindex = 3569        for pool in poolinconf:570            poolname = pool.attrib['Name']571            for pooldetail in poolindev:572                if pooldetail[nameindex] == poolname:573                    if int(float(pooldetail[sizeindex])) > maxpoolsize:574                        maxpoolid = pooldetail[0]575                        maxpoolsize = int(float(pooldetail[sizeindex]))576                    break577        if maxpoolid:578            return maxpoolid579        else:580            err_msg = (_('_get_maximum_pool:maxpoolid is None.'581                         'Please check config file and make sure '582                         'the "Name" in "StoragePool" is right.'))583            raise exception.VolumeBackendAPIException(data=err_msg)584    def _get_iscsi_info(self):585        """Get iSCSI info from config file."""586        iscsiinfo = {}587        root = self._read_xml()588        try:589            iscsiinfo['DefaultTargetIP'] = \590                root.findtext('iSCSI/DefaultTargetIP')591            initiator_list = []592            for dic in root.findall('iSCSI/Initiator'):593                initiator_list.append(dic.attrib)594            iscsiinfo['Initiator'] = initiator_list595        except Exception as err:596            LOG.error(_('_get_iscsi_info:%s') % str(err))597        return iscsiinfo598    def _execute_cli(self, cmd):599        """Build SSH connection to execute CLI commands.600        If the connection to first controller time out,601        try to connect to the other controller.602        """603        user = self.login_info['UserName']604        pwd = self.login_info['UserPassword']605        while True:606            if self.controller_alterable:607                ip = self.login_info['ControllerIP0']608            else:609                ip = self.login_info['ControllerIP1']610            try:611                ssh = SSHConnection(ip, 22, user, pwd, 30)612                ssh.connect()613                while True:614                    out = ssh.send_cmd(cmd, 30)615                    if out.find('(y/n)') > -1:616                        cmd = 'y'617                    else:618                        break619                ssh.close()620            except Exception as err:621                if ((not self.controller_alterable) and622                        (str(err).find('timed out') > -1)):623                    self.controller_alterable = False624                    LOG.debug(_('_execute_cli:Connect to controller0 %(ctr0)s'625                                ' time out.Try to Connect to controller1 '626                                '%(ctr1)s.')627                              % {'ctr0': self.login_info['ControllerIP0'],628                                 'ctr1': self.login_info['ControllerIP1']})629                    continue630                else:631                    LOG.error(_('_execute_cli:%s') % err)632                    raise exception.VolumeBackendAPIException(data=err)633            index = out.find(user + ':/>')634            if index > -1:635                return out[index:]636            else:637                return out638    def _name_translate(self, name):639        """Form new names because of the 32-character limit on names."""640        newname = VOL_AND_SNAP_NAME_FREFIX + str(hash(name))641        LOG.debug(_('_name_translate:Name in cinder: %(old)s, '642                    'new name in storage system: %(new)s')643                  % {'old': name,644                     'new': newname})645        return newname646    def _find_lun(self, name):647        """Get the ID of a LUN with the given LUN name."""648        cli_cmd = ('showlun')649        out = self._execute_cli(cli_cmd)650        en = out.split('\r\n')651        if len(en) <= 6:652            return None653        if 'Dorado2100 G2' == self.device_type['type']:654            d = 2655        elif 'Dorado5100' == self.device_type['type']:656            d = 1657        else:658            d = 0659        for i in range(6, len(en) - 2):660            r = en[i].split()661            if r[6 - d] == name:662                return r[0]663        return None664    def _create_hostgroup(self, hostgroupname):665        """Create a host group."""666        cli_cmd = ('createhostgroup -n %(name)s'667                   % {'name': hostgroupname})668        out = self._execute_cli(cli_cmd)669        if not re.search('command operates successfully', out):670            err_msg = (_('_create_hostgroup:Failed to Create hostgroup. '671                         'Hostgroup name: %(name)s. '672                         'out:%(out)s.')673                       % {'name': hostgroupname,674                          'out': out})675            LOG.error(err_msg)676            raise exception.VolumeBackendAPIException(data=err_msg)677    def _find_hostgroup(self, groupname):678        """Get the given hostgroup ID."""679        cli_cmd = ('showhostgroup')680        out = self._execute_cli(cli_cmd)681        en = out.split('\r\n')682        if len(en) <= 6:683            return None684        for i in range(6, len(en) - 2):685            r = en[i].split()686            if r[1] == groupname:687                return r[0]688        return None689    def _add_host(self, hostname, hostgroupid):690        """Add a new host."""691        cli_cmd = ('addhost -group %(groupid)s -n %(hostname)s -t 0'692                   % {'groupid': hostgroupid,693                      'hostname': hostname})694        out = self._execute_cli(cli_cmd)695        if not re.search('command operates successfully', out):696            err_msg = (_('_add_host:Failed to add host to hostgroup.'697                         'host name:%(host)s '698                         'hostgroup id:%(hostgroup)s '699                         'out:%(out)s')700                       % {'host': hostname,701                          'hostgroup': hostgroupid,702                          'out': out})703            LOG.error(err_msg)704            raise exception.VolumeBackendAPIException(data=err_msg)705    def _check_initiator(self, ininame):706        """Check whether the initiator is already added."""707        cli_cmd = ('showiscsiini -ini %(name)s'708                   % {'name': ininame})709        out = self._execute_cli(cli_cmd)710        if out.find('Initiator Information') > -1:711            return True712        else:713            return False714    def _add_initiator(self, ininame):715        """Add a new initiator to storage device."""716        cli_cmd = ('addiscsiini -n %(name)s'717                   % {'name': ininame})718        out = self._execute_cli(cli_cmd)719        if not re.search('command operates successfully', out):720            err_msg = (_('_add_initiator:Failed to add initiator.'721                         'initiator name:%(name)s '722                         'out:%(out)s')723                       % {'name': ininame,724                          'out': out})725            LOG.error(err_msg)726            raise exception.VolumeBackendAPIException(data=err_msg)727    def _delete_initiator(self, ininame):728        """Delete an initiator."""729        cli_cmd = ('deliscsiini -n %(name)s'730                   % {'name': ininame})731        out = self._execute_cli(cli_cmd)732        if not re.search('command operates successfully', out):733            err_msg = (_('_delete_initiator:ERROE:Failed to delete initiator.'734                         'initiator name:%(name)s '735                         'out:%(out)s')736                       % {'name': ininame,737                          'out': out})738            LOG.error(err_msg)739    def _find_host_in_hostgroup(self, hostname, hostgroupid):740        """Get the given host ID."""741        cli_cmd = ('showhost -group %(groupid)s'742                   % {'groupid': hostgroupid})743        out = self._execute_cli(cli_cmd)744        en = out.split('\r\n')745        if len(en) < 6:746            return None747        for i in range(6, len(en) - 2):748            r = en[i].split()749            if r[1] == hostname:750                return r[0]751        return None752    def _get_hostport_info(self, hostid):753        """Get hostports details of the given host."""754        cli_cmd = ('showhostport -host %(hostid)s'755                   % {'hostid': hostid})756        out = self._execute_cli(cli_cmd)757        en = out.split('\r\n')758        if len(en) < 6:759            return None760        hostportinfo = []761        list_key = ['id', 'name', 'info', 'type', 'hostid',762                    'linkstatus', 'multioathtype']763        for i in range(6, len(en) - 2):764            list_val = en[i].split()765            hostport_dic = dict(map(None, list_key, list_val))766            hostportinfo.append(hostport_dic)767        return hostportinfo768    def _add_hostport(self, portname, hostid, portinfo, multipathtype=0):769        """Add a host port."""770        cli_cmd = ('addhostport -host %(id)s -type 5 '771                   '-info %(info)s -n %(name)s -mtype %(mtype)s'772                   % {'id': hostid,773                      'info': portinfo,774                      'name': portname,775                      'mtype': multipathtype})776        out = self._execute_cli(cli_cmd)777        if not re.search('command operates successfully', out):778            err_msg = (_('_add_hostport:Failed to add hostport. '779                         'port name:%(port)s'780                         'port information:%(info)s '781                         'host id:%(host)s'782                         'out:%(out)s')783                       % {'port': portname,784                          'info': portinfo,785                          'host': hostid,786                          'out': out})787            LOG.error(err_msg)788            raise exception.VolumeBackendAPIException(data=err_msg)789    def _delete_hostport(self, portid):790        """Delete a host port."""791        cli_cmd = ('delhostport -force -p %(portid)s'792                   % {'portid': portid})793        out = self._execute_cli(cli_cmd)794        if not re.search('command operates successfully', out):795            err_msg = (_('_delete_hostport:Failed to delete host port. '796                         'port id:%(portid)s')797                       % {'portid': portid})798            LOG.error(err_msg)799    def _get_tgt_iqn(self, iscsiip):800        """Get target iSCSI iqn."""801        LOG.debug(_('_get_tgt_iqn:iSCSI IP is %s.') % iscsiip)802        cli_cmd = ('showiscsitgtname')803        out = self._execute_cli(cli_cmd)804        en = out.split('\r\n')805        if len(en) < 4:806            return None807        index = en[4].find('iqn')808        iqn_prefix = en[4][index:]809        iqn_prefix.strip()810        iscsiip_info = self._get_iscsi_ip_info(iscsiip)811        if iscsiip_info:812            if iscsiip_info['ctrid'] == 'A':813                ctr = '0'814            elif iscsiip_info['ctrid'] == 'B':815                ctr = '1'816            interface = '0' + iscsiip_info['interfaceid']817            port = iscsiip_info['portid'].replace('P', '0')818            iqn_suffix = ctr + '02' + interface + port819            for i in range(0, len(iqn_suffix)):820                if iqn_suffix[i] != '0':821                    iqn_suffix = iqn_suffix[i:]822                    break823            if self.device_type['type'] == 'Tseries':824                iqn = iqn_prefix + ':' + iqn_suffix + ':' \825                    + iscsiip_info['ipaddress']826            elif self.device_type['type'] == "Dorado2100 G2":827                iqn = iqn_prefix + ":" + iscsiip_info['ipaddress'] + "-" \828                    + iqn_suffix829            else:830                iqn = iqn_prefix + ':' + iscsiip_info['ipaddress']831            LOG.debug(_('_get_tgt_iqn:iSCSI target iqn is:%s') % iqn)832            return iqn833        else:834            return None835    def _get_iscsi_ip_info(self, iscsiip):836        """Get iSCSI IP infomation of storage device."""837        cli_cmd = ('showiscsiip')838        out = self._execute_cli(cli_cmd)839        en = out.split('\r\n')840        if len(en) < 6:841            return None842        iscsiIPinfo = {}843        for i in range(6, len(en) - 2):844            r = en[i].split()845            if r[3] == iscsiip:846                iscsiIPinfo['ctrid'] = r[0]847                iscsiIPinfo['interfaceid'] = r[1]848                iscsiIPinfo['portid'] = r[2]849                iscsiIPinfo['ipaddress'] = r[3]850                return iscsiIPinfo851        return None852    def _map_lun(self, lunid, hostid, new_hostlun_id):853        """Map a lun to a host.854        Here we give the hostlun ID which starts from 1.855        """856        cli_cmd = ('addhostmap -host %(hostid)s -devlun %(lunid)s'857                   '-hostlun %(hostlunid)s'858                   % {'hostid': hostid,859                      'lunid': lunid,860                      'hostlunid': new_hostlun_id})861        out = self._execute_cli(cli_cmd)862        if not re.search('command operates successfully', out):863            err_msg = (_('_map_lun:Failed to add hostmap.'864                         'hostid:%(host)s'865                         'lunid:%(lun)s'866                         'hostlunid:%(hostlunid)s.'867                         'out:%(out)s')868                       % {'host': hostid,869                          'lun': lunid,870                          'hostlunid': new_hostlun_id,871                          'out': out})872            LOG.error(err_msg)873            raise exception.VolumeBackendAPIException(data=err_msg)874    def _get_hostlunid(self, hostid, lunid):875        """Get the hostLUN ID of a LUN according host ID and LUN ID."""876        mapinfo = self._get_map_info(hostid)877        if mapinfo:878            for map in mapinfo:879                if map['devlunid'] == lunid:880                    return map['hostlunid']881        return None882    def _delete_map(self, mapid, attempts=1):883        """Remove the map."""884        cli_cmd = ('delhostmap -force -map %(mapid)s'885                   % {'mapid': mapid})886        while attempts >= 0:887            attempts -= 1888            out = self._execute_cli(cli_cmd)889            # We retry to delete host map 10s later if there are890            # IOs accessing the system.891            if re.search('command operates successfully', out):892                break893            else:894                if re.search('there are IOs accessing the system', out):895                    time.sleep(10)896                    LOG.debug(_('_delete_map:There are IOs accessing '897                                'the system. Retry to delete host map. '898                                'map id:%(mapid)s')899                              % {'mapid': mapid})900                    continue901                else:902                    err_msg = (_('_delete_map:Failed to delete host map.'903                                 ' mapid:%(mapid)s '904                                 'out:%(out)s')905                               % {'mapid': mapid,906                                  'out': out})907                    LOG.error(err_msg)908                    raise exception.VolumeBackendAPIException(data=err_msg)909    def _delete_host(self, hostid):910        """Delete a host."""911        cli_cmd = ('delhost -force -host %(hostid)s'912                   % {'hostid': hostid})913        out = self._execute_cli(cli_cmd)914        if not re.search('command operates successfully', out):915            err_msg = (_('Error: Failed delete host,host id: %(hostid)s.'916                         'out:%(out)s')917                       % {'hostid': hostid,918                          'out': out})919            LOG.error(err_msg)920            raise exception.VolumeBackendAPIException(data=err_msg)921    def _get_map_info(self, hostid):922        """Get map infomation of the given host.923        This method return a map information list. Every item in the list924        is a dictionary. The dictionarie includes three keys: mapid,925        devlunid, hostlunid. These items are sorted by hostlunid value926        from small to large.927        """928        cli_cmd = ('showhostmap -host %(hostid)s'929                   % {'hostid': hostid})930        out = self._execute_cli(cli_cmd)931        en = out.split('\r\n')932        if len(en) <= 6:933            return None934        mapinfo = []935        list_tmp = []936        list_key = ['mapid', 'devlunid', 'hostlunid']937        for i in range(6, len(en) - 2):938            list_tmp = en[i].split()939            list_val = [list_tmp[0], list_tmp[2], list_tmp[4]]940            dic = dict(map(None, list_key, list_val))941            inserted = False942            mapinfo_length = len(mapinfo)943            if mapinfo_length == 0:944                mapinfo.append(dic)945                continue946            for index in range(0, mapinfo_length):947                if (int(mapinfo[mapinfo_length - index - 1]['hostlunid']) <948                        int(dic['hostlunid'])):949                    mapinfo.insert(mapinfo_length - index, dic)950                    inserted = True951                    break952            if not inserted:953                mapinfo.insert(0, dic)954        return mapinfo955    def _get_device_type(self):956        """Get the storage device type and product version."""957        cli_cmd = ('showsys')958        out = self._execute_cli(cli_cmd)959        en = out.split('\r\n')960        if len(en) <= 6:961            return None962        for line in en:963            if re.search('Device Type', line):964                if re.search('T$', line):965                    device_type = 'Tseries'966                elif re.search('Dorado2100 G2$', line):967                    device_type = 'Dorado2100 G2'968                elif re.search('Dorado5100$', line):969                    device_type = 'Dorado5100'970                else:971                    device_type = None972                continue973            if re.search('Product Version', line):974                if re.search('V100R+', line):975                    product_version = 'V100R'976                else:977                    product_version = None978                break979        r = {'type': device_type, 'version': product_version}980        return r981    def _active_snapshot(self, snapshotid):982        """Active a snapshot."""983        cli_cmd = ('actvsnapshot -snapshot %(snapshotid)s'984                   % {'snapshotid': snapshotid})985        out = self._execute_cli(cli_cmd)986        if not re.search('command operates successfully', out):987            err_msg = (_('_active_snapshot:Failed to active snapshot. '988                         'snapshot id:%(name)s. '989                         'out:%(out)s')990                       % {'name': snapshotid,991                          'out': out})992            LOG.error(err_msg)993            raise exception.VolumeBackendAPIException(data=err_msg)994    def _disable_snapshot(self, snapshotid):995        """Disable a snapshot."""996        cli_cmd = ('disablesnapshot -snapshot %(snapshotid)s'997                   % {'snapshotid': snapshotid})998        out = self._execute_cli(cli_cmd)999        if not re.search('command operates successfully', out):1000            err_msg = (_('_disable_snapshot:Failed to disable snapshot. '1001                         'snapshot id:%(id)s. '1002                         'out:%(out)s')1003                       % {'id': snapshotid,1004                          'out': out})1005            LOG.error(err_msg)1006            raise exception.VolumeBackendAPIException(data=err_msg)1007    def _delete_snapshot(self, snapshotid):1008        """Delete a snapshot."""1009        cli_cmd = ('delsnapshot -snapshot %(snapshotid)s'1010                   % {'snapshotid': snapshotid})1011        out = self._execute_cli(cli_cmd)1012        if not re.search('command operates successfully', out):1013            err_msg = (_('_delete_snapshot:Failed to delete snapshot. '1014                         'snapshot id:%(id)s. '1015                         'out:%(out)s')1016                       % {'id': snapshotid,1017                          'out': out})1018            LOG.error(err_msg)1019            raise exception.VolumeBackendAPIException(data=err_msg)1020    def _create_volume(self, name, size):1021        """Create a new volume with the given name and size."""1022        lunsetinfo = self._get_lun_set_info()1023        cli_cmd = ('createlun -n %(name)s -lunsize %(size)s '1024                   '-wrtype %(wrtype)s '1025                   % {'name': name,1026                      'size': size,1027                      'wrtype': lunsetinfo['WriteType']})1028        # If write type is "write through", no need to set mirror switch.1029        if lunsetinfo['WriteType'] != '2':1030            cli_cmd = cli_cmd + ('-mirrorsw %(mirrorsw)s '1031                                 % {'mirrorsw': lunsetinfo['MirrorSwitch']})1032        # Differences exist between "Thin" and "thick" LUN for CLI commands.1033        luntype = lunsetinfo['LUNType']1034        if luntype == 'Thin':1035            dorado2100g2_luntype = '2'1036            Tseries = ('-pool %(pool)s '1037                       % {'pool': lunsetinfo['StoragePool']})1038        else:1039            dorado2100g2_luntype = '3'1040            Tseries = ('-rg %(raidgroup)s -susize %(susize)s '1041                       % {'raidgroup': lunsetinfo['StoragePool'],1042                          'susize': lunsetinfo['StripUnitSize']})1043        prefetch_value_or_times = ''1044        pretype = '-pretype %s ' % lunsetinfo['PrefetchType']1045        # If constant prefetch, we should set prefetch value.1046        if lunsetinfo['PrefetchType'] == '1':1047            prefetch_value_or_times = '-value %s' % lunsetinfo['PrefetchValue']1048        # If variable prefetch, we should set prefetch mutiple.1049        elif lunsetinfo['PrefetchType'] == '2':1050            prefetch_value_or_times = '-times %s' % lunsetinfo['PrefetchTimes']1051        if self.device_type['type'] == 'Tseries':1052            cli_cmd = cli_cmd + Tseries + pretype + prefetch_value_or_times1053        elif self.device_type['type'] == 'Dorado5100':1054            cli_cmd = cli_cmd + ('-rg %(raidgroup)s -susize %(susize)s'1055                                 % {'raidgroup': lunsetinfo['StoragePool'],1056                                    'susize': lunsetinfo['StripUnitSize']})1057        elif self.device_type['type'] == 'Dorado2100 G2':1058            cli_cmd = cli_cmd + ('-type %(type)s'1059                                 % {'type': dorado2100g2_luntype})1060        out = self._execute_cli(cli_cmd)1061        if not re.search('command operates successfully', out):1062            err_msg = (_('_create_volume:Failed to Create volume. '1063                         'volume name:%(name)s. '1064                         'out:%(out)s')1065                       % {'name': name,1066                          'out': out})1067            LOG.error(err_msg)1068            raise exception.VolumeBackendAPIException(data=err_msg)1069    def _delete_volume(self, name, lunid):1070        """Delete a volume."""1071        cli_cmd = ('dellun -force -lun %s' % (lunid))1072        out = self._execute_cli(cli_cmd)1073        if not re.search('command operates successfully', out):1074            err_msg = (_('_delete_volume:Failed to delete volume. '1075                         'Volume name:%(name)s '1076                         'out:%(out)s')1077                       % {'name': name,1078                          'out': out})1079            LOG.error(err_msg)1080            raise exception.VolumeBackendAPIException(data=err_msg)1081    def _create_luncopy(self, luncopyname, srclunid, tgtlunid):1082        """Create a LUNcopy."""1083        cli_cmd = ('createluncopy -n %(name)s -l 4 -slun %(srclunid)s '1084                   '-tlun %(tgtlunid)s'1085                   % {'name': luncopyname,1086                      'srclunid': srclunid,1087                      'tgtlunid': tgtlunid})1088        out = self._execute_cli(cli_cmd)1089        if not re.search('command operates successfully', out):1090            err_msg = (_('_create_luncopy:Failed to Create LUNcopy. '1091                         'LUNcopy name:%(name)s '1092                         'out:%(out)s')1093                       % {'name': luncopyname,1094                          'out': out})1095            LOG.error(err_msg)1096            raise exception.VolumeBackendAPIException(data=err_msg)1097    def _start_luncopy(self, luncopyid):1098        """Starte a LUNcopy."""1099        cli_cmd = ('chgluncopystatus -luncopy %(luncopyid)s -start'1100                   % {'luncopyid': luncopyid})1101        out = self._execute_cli(cli_cmd)1102        if not re.search('command operates successfully', out):1103            err_msg = (_('_start_luncopy:Failed to start LUNcopy. '1104                         'LUNcopy id:%(luncopyid)s '1105                         'out:%(out)s')1106                       % {'luncopyid': luncopyid,1107                          'out': out})1108            LOG.error(err_msg)1109            raise exception.VolumeBackendAPIException(data=err_msg)1110    def _find_luncopy(self, luncopyname):1111        """Get the given LUNcopy's ID."""1112        cli_cmd = ('showluncopy')1113        out = self._execute_cli(cli_cmd)1114        en = out.split('\r\n')1115        if len(en) <= 6:1116            return None1117        for i in range(6, len(en) - 2):1118            r = en[i].split()1119            if r[0] == luncopyname:1120                luncopyid = r[1]1121                return luncopyid1122        return None1123    def _wait_for_luncopy(self, luncopyname):1124        """Wait for LUNcopy to complete."""1125        while True:1126            luncopy_info = self._get_luncopy_info(luncopyname)1127            if luncopy_info['state'] == 'Complete':1128                break1129            elif luncopy_info['status'] != 'Normal':1130                err_msg = (_('_wait_for_luncopy:LUNcopy status isnot normal. '1131                             'LUNcopy name:%(luncopyname)s')1132                           % {'luncopyname': luncopyname})1133                LOG.error(err_msg)1134                raise exception.VolumeBackendAPIException(data=err_msg)1135            time.sleep(10)1136    def _get_luncopy_info(self, luncopyname):1137        """Get LUNcopy information."""1138        cli_cmd = ('showluncopy')1139        out = self._execute_cli(cli_cmd)1140        en = out.split('\r\n')1141        if len(en) <= 6:1142            return None1143        luncopyinfo = {}1144        for i in range(6, len(en) - 2):1145            r = en[i].split()1146            if r[0] == luncopyname:1147                luncopyinfo['name'] = r[0]1148                luncopyinfo['id'] = r[1]1149                luncopyinfo['state'] = r[3]1150                luncopyinfo['status'] = r[4]1151                return luncopyinfo1152        return None1153    def _delete_luncopy(self, luncopyid):1154        """Delete a LUNcopy."""1155        cli_cmd = ('delluncopy -luncopy %(id)s'1156                   % {'id': luncopyid})1157        out = self._execute_cli(cli_cmd)1158        if not re.search('command operates successfully', out):1159            err_msg = (_('_delete_luncopy:Failed to delete LUNcopy. '1160                         'LUNcopy id:%(luncopyid)s '1161                         'out:%(out)s')1162                       % {'luncopyid': luncopyid,1163                          'out': out})1164            LOG.error(err_msg)1165            raise exception.VolumeBackendAPIException(data=err_msg)1166    def _create_snapshot(self, snapshotname, srclunid):1167        """Create a snapshot with snapshot name and source LUN ID."""1168        cli_cmd = ('createsnapshot -lun %(lunid)s -n %(snapname)s'1169                   % {'lunid': srclunid,1170                      'snapname': snapshotname})1171        out = self._execute_cli(cli_cmd)1172        if not re.search('command operates successfully', out):1173            err_msg = (_('_create_snapshot:Failed to Create snapshot. '1174                         'Snapshot name:%(name)s '1175                         'out:%(out)s')1176                       % {'name': snapshotname,1177                          'out': out})1178            LOG.error(err_msg)1179            raise exception.VolumeBackendAPIException(data=err_msg)1180    def _find_snapshot(self, snapshotname):1181        """Get the given snapshot ID."""1182        cli_cmd = ('showsnapshot')1183        out = self._execute_cli(cli_cmd)1184        en = out.split('\r\n')1185        if len(en) <= 6:1186            return None1187        for i in range(6, len(en) - 2):1188            r = en[i].split()1189            if r[0] == snapshotname:1190                return r[1]1191        return None1192    def _is_resource_pool_enough(self):1193        """Check whether resource pools' valid size is more than 1G."""1194        cli_cmd = ('showrespool')1195        out = self._execute_cli(cli_cmd)1196        en = re.split('\r\n', out)1197        if len(en) <= 6:1198            LOG.error(_('_is_resource_pool_enough:Resource pool for snapshot'1199                        'not be added.'))1200            return False1201        resource_pools = []1202        list_key = ['pool id', 'size', 'usage', 'valid size',1203                    'alarm threshold']1204        for i in range(6, len(en) - 2):1205            list_val = en[i].split()1206            dic = dict(map(None, list_key, list_val))1207            resource_pools.append(dic)1208        for pool in resource_pools:1209            if float(pool['valid size']) < 1024.0:1210                return False1211        return True1212    def _update_volume_status(self):1213        """Retrieve status info from volume group."""1214        LOG.debug(_("Updating volume status"))1215        data = {}1216        backend_name = self.configuration.safe_get('volume_backend_name')1217        data["volume_backend_name"] = backend_name or 'HuaweiISCSIDriver'1218        data['vendor_name'] = 'Huawei'1219        data['driver_version'] = '1.0'1220        data['storage_protocol'] = 'iSCSI'1221        data['total_capacity_gb'] = 'infinite'1222        data['free_capacity_gb'] = self._get_free_capacity()1223        data['reserved_percentage'] = 01224        self._stats = data1225    def _get_free_capacity(self):1226        """Get total free capacity of pools."""1227        self.login_info = self._get_login_info()1228        self.device_type = self._get_device_type()1229        root = self._read_xml()1230        lun_type = root.findtext('LUN/LUNType')1231        if (self.device_type['type'] == 'Dorado5100' or not lun_type):1232            lun_type = 'Thick'1233        elif self.device_type['type'] == 'Dorado2100 G2':1234            lun_type = 'Thin'1235        poolinfo_dev = self._find_pool_info(lun_type)1236        pools_conf = root.findall('LUN/StoragePool')1237        total_free_capacity = 01238        for poolinfo in poolinfo_dev:1239            if self.device_type['type'] == 'Dorado2100 G2':1240                total_free_capacity += float(poolinfo[2])1241                continue1242            for pool in pools_conf:1243                if ((self.device_type['type'] == 'Dorado5100') and1244                        (poolinfo[5] == pool.attrib['Name'])):1245                    total_free_capacity += float(poolinfo[3])1246                    break1247                else:1248                    if ((lun_type == 'Thick') and1249                            (poolinfo[5] == pool.attrib['Name'])):1250                        total_free_capacity += float(poolinfo[3])1251                        break1252                    elif poolinfo[1] == pool.attrib['Name']:1253                        total_free_capacity += float(poolinfo[4])1254                        break...wlantest.py
Source:wlantest.py  
...89        if os.path.isfile('../../wlantest/wlantest_cli'):90            self.wlantest_cli = '../../wlantest/wlantest_cli'91        else:92            self.wlantest_cli = 'wlantest_cli'93    def cli_cmd(self, params):94        if self.remote_host is not None:95            exe = self.setup_params["wlantest_cli"]96            ret = self.remote_host.execute([exe] + params)97            if ret[0] != 0:98                raise Exception("wlantest_cli failed")99            return ret[1]100        else:101            return subprocess.check_output([self.wlantest_cli] + params)102    def flush(self):103        res = self.cli_cmd(["flush"])104        if "FAIL" in res:105            raise Exception("wlantest_cli flush failed")106    def relog(self):107        res = self.cli_cmd(["relog"])108        if "FAIL" in res:109            raise Exception("wlantest_cli relog failed")110    def add_passphrase(self, passphrase):111        res = self.cli_cmd(["add_passphrase", passphrase])112        if "FAIL" in res:113            raise Exception("wlantest_cli add_passphrase failed")114    def add_wepkey(self, key):115        res = self.cli_cmd(["add_wepkey", key])116        if "FAIL" in res:117            raise Exception("wlantest_cli add_key failed")118    def info_bss(self, field, bssid):119        res = self.cli_cmd(["info_bss", field, bssid])120        if "FAIL" in res:121            raise Exception("Could not get BSS info from wlantest for " + bssid)122        return res123    def get_bss_counter(self, field, bssid):124        try:125            res = self.cli_cmd(["get_bss_counter", field, bssid])126        except Exception, e:127            return 0128        if "FAIL" in res:129            return 0130        return int(res)131    def clear_bss_counters(self, bssid):132        self.cli_cmd(["clear_bss_counters", bssid])133    def info_sta(self, field, bssid, addr):134        res = self.cli_cmd(["info_sta", field, bssid, addr])135        if "FAIL" in res:136            raise Exception("Could not get STA info from wlantest for " + addr)137        return res138    def get_sta_counter(self, field, bssid, addr):139        res = self.cli_cmd(["get_sta_counter", field, bssid, addr])140        if "FAIL" in res:141            raise Exception("wlantest_cli command failed")142        return int(res)143    def clear_sta_counters(self, bssid, addr):144        res = self.cli_cmd(["clear_sta_counters", bssid, addr])145        if "FAIL" in res:146            raise Exception("wlantest_cli command failed")147    def tdls_clear(self, bssid, addr1, addr2):148        self.cli_cmd(["clear_tdls_counters", bssid, addr1, addr2])149    def get_tdls_counter(self, field, bssid, addr1, addr2):150        res = self.cli_cmd(["get_tdls_counter", field, bssid, addr1, addr2])151        if "FAIL" in res:152            raise Exception("wlantest_cli command failed")153        return int(res)154    def require_ap_pmf_mandatory(self, bssid):155        res = self.info_bss("rsn_capab", bssid)156        if "MFPR" not in res:157            raise Exception("AP did not require PMF")158        if "MFPC" not in res:159            raise Exception("AP did not enable PMF")160        res = self.info_bss("key_mgmt", bssid)161        if "PSK-SHA256" not in res:162            raise Exception("AP did not enable SHA256-based AKM for PMF")163    def require_ap_pmf_optional(self, bssid):164        res = self.info_bss("rsn_capab", bssid)165        if "MFPR" in res:166            raise Exception("AP required PMF")167        if "MFPC" not in res:168            raise Exception("AP did not enable PMF")169    def require_ap_no_pmf(self, bssid):170        res = self.info_bss("rsn_capab", bssid)171        if "MFPR" in res:172            raise Exception("AP required PMF")173        if "MFPC" in res:174            raise Exception("AP enabled PMF")175    def require_sta_pmf_mandatory(self, bssid, addr):176        res = self.info_sta("rsn_capab", bssid, addr)177        if "MFPR" not in res:178            raise Exception("STA did not require PMF")179        if "MFPC" not in res:180            raise Exception("STA did not enable PMF")181    def require_sta_pmf(self, bssid, addr):182        res = self.info_sta("rsn_capab", bssid, addr)183        if "MFPC" not in res:184            raise Exception("STA did not enable PMF")185    def require_sta_no_pmf(self, bssid, addr):186        res = self.info_sta("rsn_capab", bssid, addr)187        if "MFPC" in res:188            raise Exception("STA enabled PMF")189    def require_sta_key_mgmt(self, bssid, addr, key_mgmt):190        res = self.info_sta("key_mgmt", bssid, addr)191        if key_mgmt not in res:192            raise Exception("Unexpected STA key_mgmt")193    def get_tx_tid(self, bssid, addr, tid):194        res = self.cli_cmd(["get_tx_tid", bssid, addr, str(tid)])195        if "FAIL" in res:196            raise Exception("wlantest_cli command failed")197        return int(res)198    def get_rx_tid(self, bssid, addr, tid):199        res = self.cli_cmd(["get_rx_tid", bssid, addr, str(tid)])200        if "FAIL" in res:201            raise Exception("wlantest_cli command failed")202        return int(res)203    def get_tid_counters(self, bssid, addr):204        tx = {}205        rx = {}206        for tid in range(0, 17):207            tx[tid] = self.get_tx_tid(bssid, addr, tid)208            rx[tid] = self.get_rx_tid(bssid, addr, tid)...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
