components/openstack/cinder/files/solaris/solarisiscsi.py
changeset 6849 f9a2279efa0d
parent 6848 8e252a37ed0d
child 6850 f8d3bc724af7
equal deleted inserted replaced
6848:8e252a37ed0d 6849:f9a2279efa0d
     1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
       
     2 
       
     3 # Copyright (c) 2015, Oracle and/or its affiliates. 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 """Generic Solaris iSCSI utilities."""
       
    18 
       
    19 import os
       
    20 import platform
       
    21 import time
       
    22 
       
    23 from oslo_concurrency import processutils as putils
       
    24 from oslo_log import log as logging
       
    25 
       
    26 from cinder.brick import exception
       
    27 from cinder.openstack.common.gettextutils import _
       
    28 
       
    29 LOG = logging.getLogger(__name__)
       
    30 
       
    31 
       
    32 class SolarisiSCSI(object):
       
    33     def __init__(self, *args, **kwargs):
       
    34         self.execute = putils.execute
       
    35 
       
    36     def _get_device_path(self, connection_properties):
       
    37         """Get the device path from the target info.
       
    38 
       
    39         The output of cmd below is like this:
       
    40         Target: iqn.2010-10.org.openstack:hostname1-tgt-grp-target
       
    41         Alias: -
       
    42         TPGT: 1
       
    43         ISID: 4000002a0000
       
    44         Connections: 1
       
    45         LUN: 1
       
    46              Vendor:  SUN
       
    47              Product: COMSTAR
       
    48              OS Device Name: /dev/rdsk/c0t600144F0FDFAD05D0000563C04030003d0s2
       
    49         LUN: 0
       
    50              Vendor:  SUN
       
    51              Product: COMSTAR
       
    52              OS Device Name: /dev/rdsk/c0t600144F0FDFAD05D0000563C02270002d0s2
       
    53 
       
    54         """
       
    55         (out, _err) = self.execute('/usr/sbin/iscsiadm', 'list',
       
    56                                    'target', '-S',
       
    57                                    connection_properties['target_iqn'])
       
    58 
       
    59         found = False
       
    60         for line in [l.strip() for l in out.splitlines()]:
       
    61             if line.startswith("LUN:"):
       
    62                 lun = line.split()[-1]
       
    63                 if int(lun) == int(connection_properties['target_lun']):
       
    64                     found = True
       
    65                     continue
       
    66             if found:
       
    67                 if line.startswith("OS Device Name:"):
       
    68                     dev_path = line.split()[-1]
       
    69                     return dev_path
       
    70                 elif line.startswith("LUN:"):
       
    71                     found = False
       
    72 
       
    73         if not found:
       
    74             LOG.error(_("No device is found for the target %s LUN %s.") %
       
    75                       (connection_properties['target_iqn'],
       
    76                        connection_properties['target_lun']))
       
    77             raise
       
    78 
       
    79     def get_initiator(self):
       
    80         """Return the iSCSI initiator node name IQN"""
       
    81         out, err = self.execute('/usr/sbin/iscsiadm', 'list', 'initiator-node')
       
    82 
       
    83         # Sample first line of command output:
       
    84         # Initiator node name: iqn.1986-03.com.sun:01:e00000000000.4f757217
       
    85         initiator_name_line = out.splitlines()[0]
       
    86         return initiator_name_line.rsplit(' ', 1)[1]
       
    87 
       
    88     def _connect_to_iscsi_portal(self, connection_properties):
       
    89         # TODO(Strony): handle the CHAP authentication
       
    90         target_ip = connection_properties['target_portal'].split(":")[0]
       
    91         self.execute('/usr/sbin/iscsiadm', 'add', 'discovery-address',
       
    92                      target_ip)
       
    93         self.execute('/usr/sbin/iscsiadm', 'modify', 'discovery',
       
    94                      '--sendtargets', 'enable')
       
    95         (out, _err) = self.execute('/usr/sbin/iscsiadm', 'list',
       
    96                                    'discovery-address', '-v',
       
    97                                    target_ip)
       
    98 
       
    99         lines = out.splitlines()
       
   100         if not lines[0].strip().startswith('Discovery Address: ') or \
       
   101                 lines[1].strip().startswith('Unable to get targets.'):
       
   102             msg = _("No iSCSI target is found.")
       
   103             LOG.error(msg)
       
   104             raise
       
   105 
       
   106         target_iqn = connection_properties['target_iqn']
       
   107         for line in [l.strip() for l in lines]:
       
   108             if line.startswith("Target name:") and \
       
   109                     line.split()[-1] == target_iqn:
       
   110                 return
       
   111         else:
       
   112             LOG.error(_("No active session is found for the target %s.") %
       
   113                       target_iqn)
       
   114             raise
       
   115 
       
   116     def connect_volume(self, connection_properties, scan_tries):
       
   117         """Attach the volume to instance_name.
       
   118 
       
   119         connection_properties for iSCSI must include:
       
   120         target_portal - ip and optional port
       
   121         target_iqn - iSCSI Qualified Name
       
   122         target_lun - LUN id of the volume
       
   123         """
       
   124         device_info = {'type': 'block'}
       
   125 
       
   126         # TODO(Strony): support the iSCSI multipath on Solaris.
       
   127         self._connect_to_iscsi_portal(connection_properties)
       
   128 
       
   129         host_device = self._get_device_path(connection_properties)
       
   130 
       
   131         # check if it is a valid device path.
       
   132         for i in range(1, scan_tries):
       
   133             if os.path.exists(host_device):
       
   134                 break
       
   135             else:
       
   136                 time.sleep(i ** 2)
       
   137         else:
       
   138             raise exception.VolumeDeviceNotFound(device=host_device)
       
   139 
       
   140         # Set the label EFI to the disk on SPARC before it is accessed and
       
   141         # make sure the correct device path with slice 0
       
   142         # (like '/dev/rdsk/c0t600xxxd0s0').
       
   143         if platform.processor() == 'sparc':
       
   144             tmp_dev_name = host_device.rsplit('s', 1)
       
   145             disk_name = tmp_dev_name[0].split('/')[-1]
       
   146             (out, _err) = self.execute('/usr/sbin/format', '-L', 'efi', '-d',
       
   147                                        disk_name)
       
   148             host_device = '%ss0' % tmp_dev_name[0]
       
   149 
       
   150         device_info['path'] = host_device
       
   151         return device_info