"Fossies" - the Fresh Open Source Software Archive

Member "cinder-14.0.2/cinder/volume/targets/iet.py" (4 Oct 2019, 8641 Bytes) of package /linux/misc/openstack/cinder-14.0.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "iet.py" see the Fossies "Dox" file reference documentation.

    1 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    2 #    not use this file except in compliance with the License. You may obtain
    3 #    a copy of the License at
    4 #
    5 #         http://www.apache.org/licenses/LICENSE-2.0
    6 #
    7 #    Unless required by applicable law or agreed to in writing, software
    8 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    9 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   10 #    License for the specific language governing permissions and limitations
   11 #    under the License.
   12 
   13 import os
   14 import re
   15 import stat
   16 
   17 from oslo_concurrency import processutils as putils
   18 from oslo_log import log as logging
   19 
   20 from cinder import exception
   21 import cinder.privsep.targets.iet
   22 from cinder import utils
   23 from cinder.volume.targets import iscsi
   24 
   25 LOG = logging.getLogger(__name__)
   26 
   27 
   28 class IetAdm(iscsi.ISCSITarget):
   29     VERSION = '0.1'
   30 
   31     def __init__(self, *args, **kwargs):
   32         super(IetAdm, self).__init__(*args, **kwargs)
   33         self.iet_conf = self.configuration.safe_get('iet_conf')
   34         self.iscsi_iotype = self.configuration.safe_get('iscsi_iotype')
   35         self.auth_type = 'IncomingUser'
   36         self.iet_sessions = '/proc/net/iet/session'
   37 
   38     def _get_target(self, iqn):
   39 
   40         # Find existing iSCSI target session from /proc/net/iet/session
   41         #
   42         # tid:2 name:iqn.2010-10.org:volume-222
   43         #     sid:562950561399296 initiator:iqn.1994-05.com:5a6894679665
   44         #         cid:0 ip:192.168.122.1 state:active hd:none dd:none
   45         # tid:1 name:iqn.2010-10.org:volume-111
   46         #     sid:281475567911424 initiator:iqn.1994-05.com:5a6894679665
   47         #         cid:0 ip:192.168.122.1 state:active hd:none dd:none
   48 
   49         iscsi_target = 0
   50         try:
   51             with open(self.iet_sessions, 'r') as f:
   52                 sessions = f.read()
   53         except Exception:
   54             LOG.exception("Failed to open iet session list for %s", iqn)
   55             raise
   56 
   57         session_list = re.split('^tid:(?m)', sessions)[1:]
   58         for ses in session_list:
   59             m = re.match(r'(\d+) name:(\S+)\s+', ses)
   60             if m and iqn in m.group(2):
   61                 return m.group(1)
   62 
   63         return iscsi_target
   64 
   65     def _get_iscsi_target(self, context, vol_id):
   66         pass
   67 
   68     def _get_target_and_lun(self, context, volume):
   69 
   70         # For ietadm dev starts at lun 0
   71         lun = 0
   72 
   73         # Using 0, ietadm tries to search empty tid for creating
   74         # new iSCSI target
   75         iscsi_target = 0
   76 
   77         # Find existing iSCSI target based on iqn
   78         iqn = '%svolume-%s' % (self.iscsi_target_prefix, volume['id'])
   79         iscsi_target = self._get_target(iqn)
   80 
   81         return iscsi_target, lun
   82 
   83     def create_iscsi_target(self, name, tid, lun, path,
   84                             chap_auth=None, **kwargs):
   85 
   86         config_auth = None
   87         vol_id = name.split(':')[1]
   88 
   89         # Check the target is already existing.
   90         tmp_tid = self._get_target(name)
   91 
   92         # Create a new iSCSI target. If a target already exists,
   93         # the command returns 234, but we ignore it.
   94         try:
   95             cinder.privsep.targets.iet.new_target(name, tid)
   96             tid = self._get_target(name)
   97             cinder.privsep.targets.iet.new_logicalunit(
   98                 tid, lun, path, self._iotype(path))
   99 
  100             if chap_auth is not None:
  101                 (username, password) = chap_auth
  102                 config_auth = ' '.join((self.auth_type,) + chap_auth)
  103                 cinder.privsep.targets.iet.new_auth(
  104                     tid, self.auth_type, username, password)
  105         except putils.ProcessExecutionError:
  106             LOG.exception("Failed to create iscsi target for volume "
  107                           "id:%s", vol_id)
  108             raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
  109 
  110         # Update config file only if new scsi target is created.
  111         if not tmp_tid:
  112             self.update_config_file(name, tid, path, config_auth)
  113 
  114         return tid
  115 
  116     def update_config_file(self, name, tid, path, config_auth):
  117 
  118         conf_file = self.iet_conf
  119         vol_id = name.split(':')[1]
  120 
  121         # If config file does not exist, create a blank conf file and
  122         # add configuration for the volume on the new file.
  123         if not os.path.exists(conf_file):
  124             try:
  125                 utils.execute("truncate", conf_file, "--size=0",
  126                               run_as_root=True)
  127             except putils.ProcessExecutionError:
  128                 LOG.exception("Failed to create %(conf)s for volume "
  129                               "id:%(vol_id)s",
  130                               {'conf': conf_file, 'vol_id': vol_id})
  131                 raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
  132 
  133         try:
  134             volume_conf = """
  135                     Target %s
  136                         %s
  137                         Lun 0 Path=%s,Type=%s
  138             """ % (name, config_auth, path, self._iotype(path))
  139 
  140             with utils.temporary_chown(conf_file):
  141                 with open(conf_file, 'a+') as f:
  142                     f.write(volume_conf)
  143         except Exception:
  144             LOG.exception("Failed to update %(conf)s for volume "
  145                           "id:%(vol_id)s",
  146                           {'conf': conf_file, 'vol_id': vol_id})
  147             raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
  148 
  149     def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs):
  150         LOG.info("Removing iscsi_target for volume: %s", vol_id)
  151 
  152         try:
  153             cinder.privsep.targets.iet.delete_logicalunit(tid, lun)
  154             session_info = self._find_sid_cid_for_target(tid, vol_name, vol_id)
  155             if session_info:
  156                 sid, cid = session_info
  157                 cinder.privsep.targets.iet.force_delete_target(tid, sid, cid)
  158 
  159             cinder.privsep.targets.iet.delete_target(tid)
  160         except putils.ProcessExecutionError:
  161             LOG.exception("Failed to remove iscsi target for volume "
  162                           "id:%s", vol_id)
  163             raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
  164 
  165         vol_uuid_file = vol_name
  166         conf_file = self.iet_conf
  167         if os.path.exists(conf_file):
  168             try:
  169                 with utils.temporary_chown(conf_file):
  170                     with open(conf_file, 'r+') as iet_conf_text:
  171                         full_txt = iet_conf_text.readlines()
  172                         new_iet_conf_txt = []
  173                         count = 0
  174                         for line in full_txt:
  175                             if count > 0:
  176                                 count -= 1
  177                                 continue
  178                             elif vol_uuid_file in line:
  179                                 count = 2
  180                                 continue
  181                             else:
  182                                 new_iet_conf_txt.append(line)
  183 
  184                         iet_conf_text.seek(0)
  185                         iet_conf_text.truncate(0)
  186                         iet_conf_text.writelines(new_iet_conf_txt)
  187             except Exception:
  188                 LOG.exception("Failed to update %(conf)s for volume id "
  189                               "%(vol_id)s after removing iscsi target",
  190                               {'conf': conf_file, 'vol_id': vol_id})
  191                 raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
  192         else:
  193             LOG.warning("Failed to update %(conf)s for volume id "
  194                         "%(vol_id)s after removing iscsi target. "
  195                         "%(conf)s does not exist.",
  196                         {'conf': conf_file, 'vol_id': vol_id})
  197 
  198     def _find_sid_cid_for_target(self, tid, name, vol_id):
  199         """Find sid, cid for existing iscsi target"""
  200 
  201         try:
  202             with open(self.iet_sessions, 'r') as f:
  203                 sessions = f.read()
  204         except Exception as e:
  205             LOG.info("Failed to open iet session list for "
  206                      "%(vol_id)s: %(e)s",
  207                      {'vol_id': vol_id, 'e': e})
  208             return None
  209 
  210         session_list = re.split('^tid:(?m)', sessions)[1:]
  211         for ses in session_list:
  212             m = re.match(r'(\d+) name:(\S+)\s+sid:(\d+).+\s+cid:(\d+)', ses)
  213             if m and tid in m.group(1) and name in m.group(2):
  214                 return m.group(3), m.group(4)
  215 
  216     def _is_block(self, path):
  217         mode = os.stat(path).st_mode
  218         return stat.S_ISBLK(mode)
  219 
  220     def _iotype(self, path):
  221         if self.iscsi_iotype == 'auto':
  222             return 'blockio' if self._is_block(path) else 'fileio'
  223         else:
  224             return self.iscsi_iotype