components/openstack/cinder/files/solaris/zfs.py
branchs11-update
changeset 4072 db0cec748ec0
parent 3178 77584387a894
child 4937 8f0976d7e40e
equal deleted inserted replaced
4067:4be1f488dda8 4072:db0cec748ec0
     1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
     1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
     2 # Copyright (c) 2012 OpenStack LLC.
     2 # Copyright (c) 2012 OpenStack LLC.
     3 # All Rights Reserved.
     3 # All Rights Reserved.
     4 #
     4 #
     5 # Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
     5 # Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
     6 #
     6 #
     7 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     7 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
     8 #    not use this file except in compliance with the License. You may obtain
     8 #    not use this file except in compliance with the License. You may obtain
     9 #    a copy of the License at
     9 #    a copy of the License at
    10 #
    10 #
    18 """
    18 """
    19 Drivers for Solaris ZFS operations in local and iSCSI modes
    19 Drivers for Solaris ZFS operations in local and iSCSI modes
    20 """
    20 """
    21 
    21 
    22 import abc
    22 import abc
    23 import os
    23 import time
    24 
    24 
    25 from oslo.config import cfg
    25 from oslo.config import cfg
    26 
    26 
    27 from cinder import exception
    27 from cinder import exception
    28 from cinder.image import image_utils
    28 from cinder.image import image_utils
       
    29 from cinder.i18n import _
    29 from cinder.openstack.common import log as logging
    30 from cinder.openstack.common import log as logging
    30 from cinder.openstack.common import processutils
    31 from cinder.openstack.common import processutils
    31 from cinder.volume import driver
    32 from cinder.volume import driver
    32 
    33 
    33 from solaris_install.target.size import Size
    34 from solaris_install.target.size import Size
   114         Firstly, the volume should be checked if it is a cloned one. If yes,
   115         Firstly, the volume should be checked if it is a cloned one. If yes,
   115         its parent snapshot with prefix 'tmp-snapshot-' should be deleted as
   116         its parent snapshot with prefix 'tmp-snapshot-' should be deleted as
   116         well after it is removed.
   117         well after it is removed.
   117         """
   118         """
   118         zvol = self._get_zvol_path(volume)
   119         zvol = self._get_zvol_path(volume)
   119         if not os.path.exists(zvol):
   120         try:
       
   121             (out, _err) = self._execute('/usr/bin/ls', zvol)
       
   122         except processutils.ProcessExecutionError:
   120             LOG.debug(_("The volume path '%s' doesn't exist") % zvol)
   123             LOG.debug(_("The volume path '%s' doesn't exist") % zvol)
   121             return
   124             return
   122 
   125 
   123         zfs_volume = self._get_zfs_volume_name(volume)
   126         zfs_volume = self._get_zfs_volume_name(volume)
   124         origin_snapshot = self._get_zfs_property('origin', zfs_volume)
   127         origin_snapshot = self._get_zfs_property('origin', zfs_volume)
   168 
   171 
   169     def initialize_connection(self, volume, connector):
   172     def initialize_connection(self, volume, connector):
   170         """Initialize the connection and returns connection info."""
   173         """Initialize the connection and returns connection info."""
   171         volume_path = '%s/volume-%s' % (self.configuration.zfs_volume_base,
   174         volume_path = '%s/volume-%s' % (self.configuration.zfs_volume_base,
   172                                         volume['id'])
   175                                         volume['id'])
       
   176         properties = {}
       
   177         properties['device_path'] = self._get_zvol_path(volume)
       
   178 
   173         return {
   179         return {
   174             'driver_volume_type': 'local',
   180             'driver_volume_type': 'local',
   175             'volume_path': volume_path,
   181             'volume_path': volume_path,
   176             'data': {}
   182             'data': properties
   177         }
   183         }
   178 
   184 
   179     def terminate_connection(self, volume, connector, **kwargs):
   185     def terminate_connection(self, volume, connector, **kwargs):
   180         """Disconnection from the connector."""
   186         """Disconnection from the connector."""
   181         pass
   187         pass
   269     """Abstract base class for common COMSTAR operations."""
   275     """Abstract base class for common COMSTAR operations."""
   270     __metaclass__ = abc.ABCMeta
   276     __metaclass__ = abc.ABCMeta
   271 
   277 
   272     def __init__(self, *args, **kwargs):
   278     def __init__(self, *args, **kwargs):
   273         super(STMFDriver, self).__init__(*args, **kwargs)
   279         super(STMFDriver, self).__init__(*args, **kwargs)
       
   280 
       
   281     def _stmf_execute(self, *cmd):
       
   282         """Handle the possible race during the local execution."""
       
   283         tries = 0
       
   284         while True:
       
   285             try:
       
   286                 self._execute(*cmd)
       
   287                 return
       
   288             except processutils.ProcessExecutionError as ex:
       
   289                 tries = tries + 1
       
   290 
       
   291                 if tries >= self.configuration.num_shell_tries or \
       
   292                         'resource busy' not in ex.stderr:
       
   293                     raise
       
   294 
       
   295                 time.sleep(tries ** 2)
   274 
   296 
   275     def _check_target(self, target, protocol):
   297     def _check_target(self, target, protocol):
   276         """Verify if the target exists."""
   298         """Verify if the target exists."""
   277         (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-target')
   299         (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-target')
   278 
   300 
   359                 break
   381                 break
   360             if line.startswith("Lun"):
   382             if line.startswith("Lun"):
   361                 view_and_lun['lun'] = int(line.split()[2])
   383                 view_and_lun['lun'] = int(line.split()[2])
   362 
   384 
   363         if view_and_lun['view'] is None or view_and_lun['lun'] is None:
   385         if view_and_lun['view'] is None or view_and_lun['lun'] is None:
   364             LOG.error(_("Failed to get the view_entry or LUN of the LU '%s'.")
   386             err_msg = (_("Failed to get the view_entry or LUN of the LU '%s'.")
   365                       % lu)
   387                        % lu)
   366             raise
   388             raise exception.VolumeBackendAPIException(data=err_msg)
   367         else:
   389         else:
   368             LOG.debug(_("The view_entry and LUN of LU '%s' are '%s' and '%d'.")
   390             LOG.debug(_("The view_entry and LUN of LU '%s' are '%s' and '%d'.")
   369                       % (lu, view_and_lun['view'], view_and_lun['lun']))
   391                       % (lu, view_and_lun['view'], view_and_lun['lun']))
   370 
   392 
   371         return view_and_lun
   393         return view_and_lun
   381     def create_export(self, context, volume):
   403     def create_export(self, context, volume):
   382         """Export the volume."""
   404         """Export the volume."""
   383         zvol = self._get_zvol_path(volume)
   405         zvol = self._get_zvol_path(volume)
   384 
   406 
   385         # Create a Logical Unit (LU)
   407         # Create a Logical Unit (LU)
   386         self._execute('/usr/sbin/stmfadm', 'create-lu', zvol)
   408         self._stmf_execute('/usr/sbin/stmfadm', 'create-lu', zvol)
   387         luid = self._get_luid(volume)
   409         luid = self._get_luid(volume)
   388         if not luid:
   410         if not luid:
   389             msg = (_("Failed to create LU for volume '%s'")
   411             msg = (_("Failed to create LU for volume '%s'")
   390                    % volume['name'])
   412                    % volume['name'])
   391             raise exception.VolumeBackendAPIException(data=msg)
   413             raise exception.VolumeBackendAPIException(data=msg)
   392 
   414 
   393         # Create a target group and a target belonging to the target group
   415         # Create a target group and a target belonging to the target group
   394         target_group = 'tg-%s' % volume['name']
   416         target_group = 'tg-%s' % volume['name']
   395         self._execute('/usr/sbin/stmfadm', 'create-tg', target_group)
   417         self._stmf_execute('/usr/sbin/stmfadm', 'create-tg', target_group)
   396 
   418 
   397         target_name = '%s%s' % (self.configuration.iscsi_target_prefix,
   419         target_name = '%s%s' % (self.configuration.iscsi_target_prefix,
   398                                 volume['name'])
   420                                 volume['name'])
   399         self._execute('/usr/sbin/stmfadm', 'add-tg-member', '-g',
   421         self._stmf_execute('/usr/sbin/stmfadm', 'add-tg-member', '-g',
   400                       target_group, target_name)
   422                            target_group, target_name)
   401 
   423 
   402         self._execute('/usr/sbin/itadm', 'create-target', '-n', target_name)
   424         self._stmf_execute('/usr/sbin/itadm', 'create-target', '-n',
       
   425                            target_name)
   403         assert self._check_target(target_name, 'iSCSI')
   426         assert self._check_target(target_name, 'iSCSI')
   404 
   427 
   405         # Add a view entry to the logical unit with the specified LUN, 8776
   428         # Add a view entry to the logical unit with the specified LUN, 8776
   406         if luid is not None:
   429         if luid is not None:
   407             self._execute('/usr/sbin/stmfadm', 'add-view', '-n', 8776, '-t',
   430             self._stmf_execute('/usr/sbin/stmfadm', 'add-view', '-n', '8776',
   408                           target_group, luid)
   431                                '-t', target_group, luid)
   409 
   432 
   410     def remove_export(self, context, volume):
   433     def remove_export(self, context, volume):
   411         """Remove an export for a volume.
   434         """Remove an export for a volume.
   412 
   435 
   413         All of the related elements about the volume, including the
   436         All of the related elements about the volume, including the
   420 
   443 
   421         # Remove the view entry
   444         # Remove the view entry
   422         if luid is not None:
   445         if luid is not None:
   423             view_lun = self._get_view_and_lun(luid)
   446             view_lun = self._get_view_and_lun(luid)
   424             if view_lun['view']:
   447             if view_lun['view']:
   425                 self._execute('/usr/sbin/stmfadm', 'remove-view', '-l',
   448                 self._stmf_execute('/usr/sbin/stmfadm', 'remove-view', '-l',
   426                               luid, view_lun['view'])
   449                                    luid, view_lun['view'])
   427 
   450 
   428         # Remove the target and its target group
   451         # Remove the target and its target group
   429         if self._check_target(target_name, 'iSCSI'):
   452         if self._check_target(target_name, 'iSCSI'):
   430             self._execute('/usr/sbin/stmfadm', 'offline-target', target_name)
   453             self._stmf_execute('/usr/sbin/stmfadm', 'offline-target',
   431             self._execute('/usr/sbin/itadm', 'delete-target', '-f',
   454                                target_name)
   432                           target_name)
   455             self._stmf_execute('/usr/sbin/itadm', 'delete-target', '-f',
       
   456                                target_name)
   433 
   457 
   434         if self._check_tg(target_group):
   458         if self._check_tg(target_group):
   435             self._execute('/usr/sbin/stmfadm', 'delete-tg', target_group)
   459             self._stmf_execute('/usr/sbin/stmfadm', 'delete-tg', target_group)
   436 
   460 
   437         # Remove the LU
   461         # Remove the LU
   438         if luid is not None:
   462         if luid is not None:
   439             self._execute('/usr/sbin/stmfadm', 'delete-lu', luid)
   463             self._stmf_execute('/usr/sbin/stmfadm', 'delete-lu', luid)
   440 
   464 
   441     def _get_iscsi_properties(self, volume):
   465     def _get_iscsi_properties(self, volume):
   442         """Get iSCSI configuration
   466         """Get iSCSI configuration
   443 
   467 
   444         Now we use the discovery address as the default approach to add
   468         Now we use the discovery address as the default approach to add
   465                                 volume['name'])
   489                                 volume['name'])
   466         properties = {}
   490         properties = {}
   467 
   491 
   468         properties['target_discovered'] = True
   492         properties['target_discovered'] = True
   469         properties['target_iqn'] = target_name
   493         properties['target_iqn'] = target_name
       
   494 
   470         properties['target_portal'] = ('%s:%d' %
   495         properties['target_portal'] = ('%s:%d' %
   471                                        (self.configuration.iscsi_ip_address,
   496                                        (self.configuration.iscsi_ip_address,
   472                                         self.configuration.iscsi_port))
   497                                         self.configuration.iscsi_port))
   473         view_lun = self._get_view_and_lun(luid)
   498         view_lun = self._get_view_and_lun(luid)
   474         if view_lun['lun']:
   499         if view_lun['lun'] is not None:
   475             properties['target_lun'] = view_lun['lun']
   500             properties['target_lun'] = view_lun['lun']
   476         properties['volume_id'] = volume['id']
   501         properties['volume_id'] = volume['id']
   477 
   502 
   478         auth = volume['provider_auth']
   503         auth = volume['provider_auth']
   479         if auth:
   504         if auth:
   604     def create_export(self, context, volume):
   629     def create_export(self, context, volume):
   605         """Export the volume."""
   630         """Export the volume."""
   606         zvol = self._get_zvol_path(volume)
   631         zvol = self._get_zvol_path(volume)
   607 
   632 
   608         # Create a Logical Unit (LU)
   633         # Create a Logical Unit (LU)
   609         self._execute('/usr/sbin/stmfadm', 'create-lu', zvol)
   634         self._stmf_execute('/usr/sbin/stmfadm', 'create-lu', zvol)
   610         luid = self._get_luid(volume)
   635         luid = self._get_luid(volume)
   611         if not luid:
   636         if not luid:
   612             msg = (_("Failed to create logic unit for volume '%s'")
   637             msg = (_("Failed to create logic unit for volume '%s'")
   613                    % volume['name'])
   638                    % volume['name'])
   614             raise exception.VolumeBackendAPIException(data=msg)
   639             raise exception.VolumeBackendAPIException(data=msg)
   624                          "into the expected target group '%s'.") %
   649                          "into the expected target group '%s'.") %
   625                        (wwn, target_group))
   650                        (wwn, target_group))
   626                 raise exception.VolumeBackendAPIException(data=msg)
   651                 raise exception.VolumeBackendAPIException(data=msg)
   627 
   652 
   628             # Create a target group for the wwn
   653             # Create a target group for the wwn
   629             self._execute('/usr/sbin/stmfadm', 'create-tg', target_group)
   654             self._stmf_execute('/usr/sbin/stmfadm', 'create-tg', target_group)
   630 
   655 
   631             # Enable the target and add it to the 'tg-wwn-xxx' group
   656             # Enable the target and add it to the 'tg-wwn-xxx' group
   632             self._execute('/usr/sbin/stmfadm', 'offline-target',
   657             self._stmf_execute('/usr/sbin/stmfadm', 'offline-target',
   633                           'wwn.%s' % wwn)
   658                                'wwn.%s' % wwn)
   634             self._execute('/usr/sbin/stmfadm', 'add-tg-member', '-g',
   659             self._stmf_execute('/usr/sbin/stmfadm', 'add-tg-member', '-g',
   635                           target_group, 'wwn.%s' % wwn)
   660                                target_group, 'wwn.%s' % wwn)
   636             self._execute('/usr/sbin/stmfadm', 'online-target', 'wwn.%s' % wwn)
   661             self._stmf_execute('/usr/sbin/stmfadm', 'online-target',
       
   662                                'wwn.%s' % wwn)
   637         assert self._target_in_tg(wwn, target_group)
   663         assert self._target_in_tg(wwn, target_group)
   638 
   664 
   639         # Add a logical unit view entry
   665         # Add a logical unit view entry
   640         # TODO(Strony): replace the auto assigned LUN with '-n' option
   666         # TODO(Strony): replace the auto assigned LUN with '-n' option
   641         if luid is not None:
   667         if luid is not None:
   642             self._execute('/usr/sbin/stmfadm', 'add-view', '-t',
   668             self._stmf_execute('/usr/sbin/stmfadm', 'add-view', '-t',
   643                           target_group, luid)
   669                                target_group, luid)
   644 
   670 
   645     def remove_export(self, context, volume):
   671     def remove_export(self, context, volume):
   646         """Remove an export for a volume."""
   672         """Remove an export for a volume."""
   647         luid = self._get_luid(volume)
   673         luid = self._get_luid(volume)
   648 
   674 
   651             wwn = wwns[0]
   677             wwn = wwns[0]
   652             target_wwn = 'wwn.%s' % wwn
   678             target_wwn = 'wwn.%s' % wwn
   653             target_group = 'tg-wwn-%s' % wwn
   679             target_group = 'tg-wwn-%s' % wwn
   654             view_lun = self._get_view_and_lun(luid)
   680             view_lun = self._get_view_and_lun(luid)
   655             if view_lun['view']:
   681             if view_lun['view']:
   656                 self._execute('/usr/sbin/stmfadm', 'remove-view', '-l',
   682                 self._stmf_execute('/usr/sbin/stmfadm', 'remove-view', '-l',
   657                               luid, view_lun['view'])
   683                                    luid, view_lun['view'])
   658 
   684 
   659             # Remove the target group when only one LU exists.
   685             # Remove the target group when only one LU exists.
   660             if self._only_lu(luid):
   686             if self._only_lu(luid):
   661                 if self._check_target(target_wwn, 'Channel'):
   687                 if self._check_target(target_wwn, 'Channel'):
   662                     self._execute('/usr/sbin/stmfadm', 'offline-target',
   688                     self._stmf_execute('/usr/sbin/stmfadm', 'offline-target',
   663                                   target_wwn)
   689                                        target_wwn)
   664                 if self._check_tg(target_group):
   690                 if self._check_tg(target_group):
   665                     self._execute('/usr/sbin/stmfadm', 'delete-tg',
   691                     self._stmf_execute('/usr/sbin/stmfadm', 'delete-tg',
   666                                   target_group)
   692                                        target_group)
   667 
   693 
   668             # Remove the LU
   694             # Remove the LU
   669             self._execute('/usr/sbin/stmfadm', 'delete-lu', luid)
   695             self._stmf_execute('/usr/sbin/stmfadm', 'delete-lu', luid)
   670 
   696 
   671     def _get_fc_properties(self, volume):
   697     def _get_fc_properties(self, volume):
   672         """Get Fibre Channel configuration.
   698         """Get Fibre Channel configuration.
   673 
   699 
   674         :target_discovered:    boolean indicating whether discovery was used
   700         :target_discovered:    boolean indicating whether discovery was used
   691         properties = {}
   717         properties = {}
   692 
   718 
   693         properties['target_discovered'] = True
   719         properties['target_discovered'] = True
   694         properties['target_wwn'] = wwns
   720         properties['target_wwn'] = wwns
   695         view_lun = self._get_view_and_lun(luid)
   721         view_lun = self._get_view_and_lun(luid)
   696         if view_lun['lun']:
   722         if view_lun['lun'] is not None:
   697             properties['target_lun'] = view_lun['lun']
   723             properties['target_lun'] = view_lun['lun']
   698         return properties
   724         return properties
   699 
   725 
   700     def initialize_connection(self, volume, connector):
   726     def initialize_connection(self, volume, connector):
   701         """Initializes the connection and returns connection info.
   727         """Initializes the connection and returns connection info.