"Fossies" - the Fresh Open Source Software Archive

Member "cinder-13.0.7/cinder/volume/targets/cxt.py" (4 Oct 2019, 9769 Bytes) of package /linux/misc/openstack/cinder-13.0.7.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 "cxt.py" see the Fossies "Dox" file reference documentation.

    1 # Copyright 2015 Chelsio Communications Inc.
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 
   17 import os
   18 
   19 from oslo_concurrency import processutils as putils
   20 from oslo_log import log as logging
   21 from oslo_utils import fileutils
   22 from oslo_utils import netutils
   23 
   24 from cinder import exception
   25 from cinder import utils
   26 from cinder.volume.targets import iscsi
   27 
   28 LOG = logging.getLogger(__name__)
   29 
   30 
   31 class CxtAdm(iscsi.ISCSITarget):
   32     """Chiscsi target configuration for block storage devices.
   33 
   34     This includes things like create targets, attach, detach
   35     etc.
   36     """
   37 
   38     TARGET_FMT = """
   39               target:
   40                        TargetName=%s
   41                        TargetDevice=%s
   42                        PortalGroup=1@%s
   43                  """
   44     TARGET_FMT_WITH_CHAP = """
   45                          target:
   46                                  TargetName=%s
   47                                  TargetDevice=%s
   48                                  PortalGroup=1@%s
   49                                  AuthMethod=CHAP
   50                                  Auth_CHAP_Policy=Oneway
   51                                  Auth_CHAP_Initiator=%s
   52                            """
   53 
   54     cxt_subdir = 'cxt'
   55 
   56     def __init__(self, *args, **kwargs):
   57         super(CxtAdm, self).__init__(*args, **kwargs)
   58         self.volumes_dir = self.configuration.safe_get('volumes_dir')
   59         self.volumes_dir = os.path.join(self.volumes_dir, self.cxt_subdir)
   60         self.config = self.configuration.safe_get('chiscsi_conf')
   61 
   62     def _get_volumes_dir(self):
   63         return self.volumes_dir
   64 
   65     def _get_target(self, iqn):
   66         # We can use target=iqn here, but iscsictl has no --brief mode, and
   67         # this way we save on a lot of unnecessary parsing
   68         (out, err) = utils.execute('iscsictl',
   69                                    '-c',
   70                                    'target=ALL',
   71                                    run_as_root=True)
   72         lines = out.split('\n')
   73         for line in lines:
   74             if iqn in line:
   75                 parsed = line.split()
   76                 tid = parsed[2]
   77                 return tid[3:].rstrip(',')
   78 
   79         return None
   80 
   81     def _get_iscsi_target(self, context, vol_id):
   82         return 0
   83 
   84     def _get_target_and_lun(self, context, volume):
   85         lun = 0  # For chiscsi dev starts at lun 0
   86         iscsi_target = 1
   87         return iscsi_target, lun
   88 
   89     @staticmethod
   90     def _get_portal(ip, port=None):
   91         # ipv6 addresses use [ip]:port format, ipv4 use ip:port
   92         portal_port = ':%d' % port if port else ''
   93 
   94         if netutils.is_valid_ipv4(ip):
   95             portal_ip = ip
   96         else:
   97             portal_ip = '[' + ip + ']'
   98 
   99         return portal_ip + portal_port
  100 
  101     def create_iscsi_target(self, name, tid, lun, path,
  102                             chap_auth=None, **kwargs):
  103 
  104         (out, err) = utils.execute('iscsictl',
  105                                    '-c',
  106                                    'target=ALL',
  107                                    run_as_root=True)
  108         LOG.debug("Targets prior to update: %s", out)
  109         volumes_dir = self._get_volumes_dir()
  110         fileutils.ensure_tree(volumes_dir)
  111 
  112         vol_id = name.split(':')[1]
  113 
  114         cfg_port = kwargs.get('portals_port')
  115         cfg_ips = kwargs.get('portals_ips')
  116 
  117         portals = ','.join(map(lambda ip: self._get_portal(ip, cfg_port),
  118                                cfg_ips))
  119 
  120         if chap_auth is None:
  121             volume_conf = self.TARGET_FMT % (name, path, portals)
  122         else:
  123             volume_conf = self.TARGET_FMT_WITH_CHAP % (name,
  124                                                        path, portals,
  125                                                        '"%s":"%s"' % chap_auth)
  126         LOG.debug('Creating iscsi_target for: %s', vol_id)
  127         volume_path = os.path.join(volumes_dir, vol_id)
  128 
  129         if os.path.exists(volume_path):
  130             LOG.warning('Persistence file already exists for volume, '
  131                         'found file at: %s', volume_path)
  132         utils.robust_file_write(volumes_dir, vol_id, volume_conf)
  133         LOG.debug('Created volume path %(vp)s,\n'
  134                   'content: %(vc)s',
  135                   {'vp': volume_path, 'vc': volume_conf})
  136 
  137         old_persist_file = None
  138         old_name = kwargs.get('old_name', None)
  139         if old_name:
  140             LOG.debug('Detected old persistence file for volume '
  141                       '%(vol)s at %(old_name)s',
  142                       {'vol': vol_id, 'old_name': old_name})
  143             old_persist_file = os.path.join(volumes_dir, old_name)
  144 
  145         try:
  146             # With the persistent tgts we create them
  147             # by creating the entry in the persist file
  148             # and then doing an update to get the target
  149             # created.
  150             (out, err) = utils.execute('iscsictl', '-S', 'target=%s' % name,
  151                                        '-f', volume_path,
  152                                        '-x', self.config,
  153                                        run_as_root=True)
  154         except putils.ProcessExecutionError as e:
  155             LOG.error("Failed to create iscsi target for volume "
  156                       "id:%(vol_id)s: %(e)s",
  157                       {'vol_id': vol_id, 'e': e})
  158 
  159             # Don't forget to remove the persistent file we created
  160             os.unlink(volume_path)
  161             raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
  162         finally:
  163             LOG.debug("StdOut from iscsictl -S: %s", out)
  164             LOG.debug("StdErr from iscsictl -S: %s", err)
  165 
  166         # Grab targets list for debug
  167         (out, err) = utils.execute('iscsictl',
  168                                    '-c',
  169                                    'target=ALL',
  170                                    run_as_root=True)
  171         LOG.debug("Targets after update: %s", out)
  172 
  173         iqn = '%s%s' % (self.iscsi_target_prefix, vol_id)
  174         tid = self._get_target(iqn)
  175         if tid is None:
  176             LOG.error("Failed to create iscsi target for volume "
  177                       "id:%(vol_id)s. Please verify your configuration "
  178                       "in %(volumes_dir)s'",
  179                       {'vol_id': vol_id,
  180                        'volumes_dir': volumes_dir, })
  181             raise exception.NotFound()
  182 
  183         if old_persist_file is not None and os.path.exists(old_persist_file):
  184             os.unlink(old_persist_file)
  185 
  186         return tid
  187 
  188     def remove_iscsi_target(self, tid, lun, vol_id, vol_name, **kwargs):
  189         LOG.info('Removing iscsi_target for: %s', vol_id)
  190         vol_uuid_file = vol_name
  191         volume_path = os.path.join(self._get_volumes_dir(), vol_uuid_file)
  192         if not os.path.exists(volume_path):
  193             LOG.warning('Volume path %s does not exist, '
  194                         'nothing to remove.', volume_path)
  195             return
  196 
  197         if os.path.isfile(volume_path):
  198             iqn = '%s%s' % (self.iscsi_target_prefix,
  199                             vol_uuid_file)
  200         else:
  201             raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
  202 
  203         target_exists = False
  204         try:
  205             (out, err) = utils.execute('iscsictl',
  206                                        '-c',
  207                                        'target=%s' % iqn,
  208                                        run_as_root=True)
  209             LOG.debug("StdOut from iscsictl -c: %s", out)
  210             LOG.debug("StdErr from iscsictl -c: %s", err)
  211         except putils.ProcessExecutionError as e:
  212             if "NOT found" in e.stdout:
  213                 LOG.info("No iscsi target present for volume "
  214                          "id:%(vol_id)s: %(e)s",
  215                          {'vol_id': vol_id, 'e': e})
  216                 return
  217             else:
  218                 raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
  219         else:
  220             target_exists = True
  221 
  222         try:
  223             utils.execute('iscsictl',
  224                           '-s',
  225                           'target=%s' % iqn,
  226                           run_as_root=True)
  227         except putils.ProcessExecutionError as e:
  228             # There exists a race condition where multiple calls to
  229             # remove_iscsi_target come in simultaneously. If we can poll
  230             # for a target successfully but it is gone before we can remove
  231             # it, fail silently
  232             if "is not found" in e.stderr and target_exists:
  233                 LOG.info("No iscsi target present for volume "
  234                          "id:%(vol_id)s: %(e)s",
  235                          {'vol_id': vol_id, 'e': e})
  236                 return
  237             else:
  238                 LOG.error("Failed to remove iscsi target for volume "
  239                           "id:%(vol_id)s: %(e)s",
  240                           {'vol_id': vol_id, 'e': e})
  241                 raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
  242 
  243         # Carried over from tgt
  244         # NOTE(jdg): This *should* be there still but incase
  245         # it's not we don't care, so just ignore it if was
  246         # somehow deleted between entry of this method
  247         # and here
  248         if os.path.exists(volume_path):
  249             os.unlink(volume_path)
  250         else:
  251             LOG.debug('Volume path %s not found at end, '
  252                       'of remove_iscsi_target.', volume_path)