# HG changeset patch # User Qiang Strony Zhang # Date 1444416858 25200 # Node ID 8f0976d7e40e25fcf8086ae2b6b4fc92a697a43c # Parent 79af241b48341febfb232e4b75606f82333cec7f PSARC 2015/289 OpenStack Cinder Enhancements 20938366 cinder backup and volume-migration need to be supported in openstack 21215160 cinder SAN needs Paramiko 21365620 cinder volume backups sometimes fail on SPARC diff -r 79af241b4834 -r 8f0976d7e40e components/openstack/cinder/cinder.p5m --- a/components/openstack/cinder/cinder.p5m Fri Oct 09 09:55:13 2015 -0700 +++ b/components/openstack/cinder/cinder.p5m Fri Oct 09 11:54:18 2015 -0700 @@ -609,6 +609,9 @@ # force a dependency on osprofiler; pkgdepend work is needed to flush this out. depend type=require fmri=library/python/osprofiler-$(PYV) +# force a dependency on paramiko; pkgdepend work is needed to flush this out. +depend type=require fmri=library/python/paramiko-$(PYV) + # force a dependency on paste; pkgdepend work is needed to flush this out. depend type=require fmri=library/python/paste-$(PYV) diff -r 79af241b4834 -r 8f0976d7e40e components/openstack/cinder/files/cinder-volume-setup --- a/components/openstack/cinder/files/cinder-volume-setup Fri Oct 09 09:55:13 2015 -0700 +++ b/components/openstack/cinder/files/cinder-volume-setup Fri Oct 09 11:54:18 2015 -0700 @@ -36,6 +36,17 @@ parser = ConfigParser.ConfigParser() parser.read(cinder_conf) + # check if the SAN storage is used. + try: + local = parser.get("DEFAULT", "san_is_local") + except ConfigParser.NoOptionError: + local = False + + # The script only handles the setup for local access as it needs to + # run in the remote node in the SAN environment. + if not local: + return smf_include.SMF_EXIT_OK + # retrieve the top-level dataset or just get the default (rpool/cinder) try: top_ds = parser.get("DEFAULT", "zfs_volume_base") diff -r 79af241b4834 -r 8f0976d7e40e components/openstack/cinder/files/cinder.exec_attr --- a/components/openstack/cinder/files/cinder.exec_attr Fri Oct 09 09:55:13 2015 -0700 +++ b/components/openstack/cinder/files/cinder.exec_attr Fri Oct 09 11:54:18 2015 -0700 @@ -1,8 +1,18 @@ OpenStack Block Storage Management:solaris:cmd:RO::/usr/bin/cinder-manage:\ uid=cinder;gid=cinder +cinder-volume:solaris:cmd:RO::/usr/bin/chown:euid=0 + +cinder-volume:solaris:cmd:RO::/usr/bin/dd:privs=file_dac_read + +cinder-volume:solaris:cmd:RO::/usr/sbin/fcadm:privs=file_dac_read,sys_devices + cinder-volume:solaris:cmd:RO::/usr/sbin/fcinfo:privs=file_dac_read,sys_devices +cinder-volume:solaris:cmd:RO::/usr/sbin/format:euid=0 + +cinder-volume:solaris:cmd:RO::/usr/sbin/iscsiadm:euid=0 + cinder-volume:solaris:cmd:RO::/usr/sbin/itadm:uid=0 cinder-volume:solaris:cmd:RO::/usr/sbin/stmfadm:euid=0 diff -r 79af241b4834 -r 8f0976d7e40e components/openstack/cinder/files/solaris/solarisfc.py --- a/components/openstack/cinder/files/solaris/solarisfc.py Fri Oct 09 09:55:13 2015 -0700 +++ b/components/openstack/cinder/files/solaris/solarisfc.py Fri Oct 09 11:54:18 2015 -0700 @@ -17,6 +17,7 @@ """Generic Solaris Fibre Channel utilities.""" import os +import platform import time from cinder.brick import exception @@ -107,7 +108,7 @@ for wwpn in wwpns: self.execute('/usr/sbin/fcadm', 'force-lip', wwpn) - def get_device_path(self, wwn): + def _get_device_path(self, wwn): """Get the Device Name of the WWN""" try: out, err = self.execute('/usr/sbin/fcinfo', 'logical-unit', '-v') @@ -146,7 +147,7 @@ # a refresh. for i in range(1, scan_tries): LOG.debug("Looking for Fibre Channel device") - host_dev = self.get_device_path(wwn) + host_dev = self._get_device_path(wwn) if host_dev is not None and os.path.exists(host_dev): break @@ -158,5 +159,15 @@ LOG.error(msg) raise exception.NoFibreChannelVolumeDeviceFound() + # Set the label EFI to the disk on SPARC before it is accessed and + # make sure the correct device path with slice 0 + # (like '/dev/rdsk/c0t600xxxd0s0'). + if platform.processor() == 'sparc': + tmp_dev_name = host_device.rsplit('s', 1) + disk_name = tmp_dev_name[0].split('/')[-1] + (out, _err) = self.execute('/usr/sbin/format', '-L', 'efi', '-d', + disk_name) + host_device = '%ss0' % tmp_dev_name[0] + device_info['path'] = host_dev return device_info diff -r 79af241b4834 -r 8f0976d7e40e components/openstack/cinder/files/solaris/solarisiscsi.py --- a/components/openstack/cinder/files/solaris/solarisiscsi.py Fri Oct 09 09:55:13 2015 -0700 +++ b/components/openstack/cinder/files/solaris/solarisiscsi.py Fri Oct 09 11:54:18 2015 -0700 @@ -17,6 +17,7 @@ """Generic Solaris iSCSI utilities.""" import os +import platform import time from cinder.brick import exception @@ -31,13 +32,6 @@ def __init__(self, *args, **kwargs): self.execute = putils.execute - def disconnect_iscsi(self): - """Disable the iSCSI discovery method to detach the volume - from instance_name. - """ - self.execute('/usr/sbin/iscsiadm', 'modify', 'discovery', - '--sendtargets', 'disable') - def _get_device_path(self, connection_properties): """Get the device path from the target info.""" (out, _err) = self.execute('/usr/sbin/iscsiadm', 'list', @@ -114,5 +108,15 @@ else: raise exception.VolumeDeviceNotFound(device=host_device) + # Set the label EFI to the disk on SPARC before it is accessed and + # make sure the correct device path with slice 0 + # (like '/dev/rdsk/c0t600xxxd0s0'). + if platform.processor() == 'sparc': + tmp_dev_name = host_device.rsplit('s', 1) + disk_name = tmp_dev_name[0].split('/')[-1] + (out, _err) = self.execute('/usr/sbin/format', '-L', 'efi', '-d', + disk_name) + host_device = '%ss0' % tmp_dev_name[0] + device_info['path'] = host_device return device_info diff -r 79af241b4834 -r 8f0976d7e40e components/openstack/cinder/files/solaris/zfs.py --- a/components/openstack/cinder/files/solaris/zfs.py Fri Oct 09 09:55:13 2015 -0700 +++ b/components/openstack/cinder/files/solaris/zfs.py Fri Oct 09 11:54:18 2015 -0700 @@ -20,16 +20,21 @@ """ import abc +import fcntl +import os +import socket +import subprocess import time from oslo.config import cfg from cinder import exception +from cinder.i18n import _ from cinder.image import image_utils -from cinder.i18n import _ from cinder.openstack.common import log as logging from cinder.openstack.common import processutils from cinder.volume import driver +from cinder.volume.drivers.san.san import SanDriver from solaris_install.target.size import Size @@ -44,13 +49,24 @@ FLAGS.register_opts(solaris_zfs_opts) -class ZFSVolumeDriver(driver.VolumeDriver): +class ZFSVolumeDriver(SanDriver): """Local ZFS volume operations.""" protocol = 'local' def __init__(self, *args, **kwargs): - super(ZFSVolumeDriver, self).__init__(*args, **kwargs) + super(ZFSVolumeDriver, self).__init__(execute=self.solaris_execute, + *args, **kwargs) self.configuration.append_config_values(solaris_zfs_opts) + self.run_local = self.configuration.san_is_local + self.hostname = socket.gethostname() + + def solaris_execute(self, *cmd, **kwargs): + """Execute the command locally or remotely.""" + if self.run_local: + return processutils.execute(*cmd, **kwargs) + else: + return super(ZFSVolumeDriver, self)._run_ssh(cmd, + check_exit_code=True) def check_for_setup_error(self): """Check the setup error.""" @@ -59,7 +75,7 @@ def create_volume(self, volume): """Create a volume.""" size = '%sG' % volume['size'] - zfs_volume = self._get_zfs_volume_name(volume) + zfs_volume = self._get_zfs_volume_name(volume['name']) # Create a ZFS volume cmd = ['/usr/sbin/zfs', 'create', '-V', size, zfs_volume] @@ -78,7 +94,7 @@ # Create a ZFS clone zfs_snapshot = self._get_zfs_snap_name(snapshot) - zfs_volume = self._get_zfs_volume_name(volume) + zfs_volume = self._get_zfs_volume_name(volume['name']) cmd = ['/usr/sbin/zfs', 'clone', zfs_snapshot, zfs_volume] self._execute(*cmd) @@ -102,7 +118,7 @@ # Create a ZFS clone zfs_snapshot = self._get_zfs_snap_name(tmp_snapshot) - zfs_volume = self._get_zfs_volume_name(volume) + zfs_volume = self._get_zfs_volume_name(volume['name']) cmd = ['/usr/sbin/zfs', 'clone', zfs_snapshot, zfs_volume] self._execute(*cmd) @@ -123,7 +139,7 @@ LOG.debug(_("The volume path '%s' doesn't exist") % zvol) return - zfs_volume = self._get_zfs_volume_name(volume) + zfs_volume = self._get_zfs_volume_name(volume['name']) origin_snapshot = self._get_zfs_property('origin', zfs_volume) tmp_cloned_vol = False @@ -205,37 +221,86 @@ def copy_image_to_volume(self, context, volume, image_service, image_id): """Fetch the image from image_service and write it to the volume.""" - image_utils.fetch_to_raw(context, - image_service, - image_id, - self.local_path(volume)) + raise NotImplementedError() def copy_volume_to_image(self, context, volume, image_service, image_meta): """Copy the volume to the specified image.""" - image_utils.upload_volume(context, - image_service, - image_meta, - self.local_path(volume)) + raise NotImplementedError() def _get_zfs_property(self, prop, dataset): """Get the value of property for the dataset.""" - (out, _err) = self._execute('/usr/sbin/zfs', 'get', '-H', '-o', - 'value', prop, dataset) - return out.rstrip() + try: + (out, _err) = self._execute('/usr/sbin/zfs', 'get', '-H', '-o', + 'value', prop, dataset) + return out.rstrip() + except processutils.ProcessExecutionError: + LOG.info(_("Failed to get the property '%s' of the dataset '%s'") % + (prop, dataset)) + return None def _get_zfs_snap_name(self, snapshot): """Get the snapshot path.""" return "%s/%s@%s" % (self.configuration.zfs_volume_base, snapshot['volume_name'], snapshot['name']) - def _get_zfs_volume_name(self, volume): + def _get_zfs_volume_name(self, volume_name): """Add the pool name to get the ZFS volume.""" return "%s/%s" % (self.configuration.zfs_volume_base, - volume['name']) + volume_name) + + def _piped_execute(self, cmd1, cmd2): + """Pipe output of cmd1 into cmd2.""" + LOG.debug(_("Piping cmd1='%s' into cmd2='%s'") % + (' '.join(cmd1), ' '.join(cmd2))) + + try: + p1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + except: + LOG.error(_("_piped_execute '%s' failed.") % (cmd1)) + raise + + # Set the pipe to be blocking because evenlet.green.subprocess uses + # the non-blocking pipe. + flags = fcntl.fcntl(p1.stdout, fcntl.F_GETFL) & (~os.O_NONBLOCK) + fcntl.fcntl(p1.stdout, fcntl.F_SETFL, flags) + + p2 = subprocess.Popen(cmd2, stdin=p1.stdout, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + p1.stdout.close() + stdout, stderr = p2.communicate() + if p2.returncode: + msg = (_("_piped_execute failed with the info '%s' and '%s'.") % + (stdout, stderr)) + raise exception.VolumeBackendAPIException(data=msg) + + def _zfs_send_recv(self, src, dst, remote=False): + """Replicate the ZFS dataset by calling zfs send/recv cmd""" + src_snapshot = {'volume_name': src['name'], + 'name': 'tmp-snapshot-%s' % src['id']} + src_snapshot_name = self._get_zfs_snap_name(src_snapshot) + prop_type = self._get_zfs_property('type', src_snapshot_name) + # Delete the temporary snapshot if it already exists + if prop_type == 'snapshot': + self.delete_snapshot(src_snapshot) + # Create a temporary snapshot of volume + self.create_snapshot(src_snapshot) + src_snapshot_name = self._get_zfs_snap_name(src_snapshot) + + cmd1 = ['/usr/sbin/zfs', 'send', src_snapshot_name] + cmd2 = ['/usr/sbin/zfs', 'receive', dst] + self._piped_execute(cmd1, cmd2) + + # Delete the temporary src snapshot and dst snapshot + self.delete_snapshot(src_snapshot) + dst_snapshot_name = "%s@tmp-snapshot-%s" % (dst, src['id']) + cmd = ['/usr/sbin/zfs', 'destroy', dst_snapshot_name] + self._execute(*cmd) def _get_zvol_path(self, volume): """Get the ZFS volume path.""" - return "/dev/zvol/rdsk/%s" % self._get_zfs_volume_name(volume) + return "/dev/zvol/rdsk/%s" % self._get_zfs_volume_name(volume['name']) def _update_volume_stats(self): """Retrieve volume status info.""" @@ -256,13 +321,17 @@ (Size(used_size) + Size(avail_size)).get(Size.gb_units) stats['free_capacity_gb'] = Size(avail_size).get(Size.gb_units) stats['reserved_percentage'] = self.configuration.reserved_percentage + stats['location_info'] =\ + ('ZFSVolumeDriver:%(hostname)s:%(zfs_volume_base)s' % + {'hostname': self.hostname, + 'zfs_volume_base': self.configuration.zfs_volume_base}) self._stats = stats def extend_volume(self, volume, new_size): """Extend an existing volume's size.""" volsize_str = 'volsize=%sg' % new_size - zfs_volume = self._get_zfs_volume_name(volume) + zfs_volume = self._get_zfs_volume_name(volume['name']) try: self._execute('/usr/sbin/zfs', 'set', volsize_str, zfs_volume) except Exception: @@ -270,6 +339,56 @@ % {'new_size': new_size}) raise exception.VolumeBackendAPIException(data=msg) + def rename_volume(self, src, dst): + """Rename the volume from src to dst in the same zpool.""" + cmd = ['/usr/sbin/zfs', 'rename', src, dst] + self._execute(*cmd) + + LOG.debug(_("Rename the volume '%s' to '%s'") % (src, dst)) + + def migrate_volume(self, context, volume, host): + """Migrate the volume among different backends on the same server. + + The volume migration can only run locally by calling zfs send/recv + cmds and the specified host needs to be on the same server with the + host. But, one exception is when the src and dst volume are located + under the same zpool locally or remotely, the migration will be done + by just renaming the volume. + :param context: context + :param volume: a dictionary describing the volume to migrate + :param host: a dictionary describing the host to migrate to + """ + false_ret = (False, None) + if volume['status'] != 'available': + LOG.debug(_("Status of volume '%s' is '%s', not 'available'.") % + (volume['name'], volume['status'])) + return false_ret + + if 'capabilities' not in host or \ + 'location_info' not in host['capabilities']: + LOG.debug(_("No location_info or capabilities are in host info")) + return false_ret + + info = host['capabilities']['location_info'] + if (self.hostname != info.split(':')[1]): + LOG.debug(_("Migration between two different servers '%s' and " + "'%s' is not supported yet.") % + (self.hostname, info.split(':')[1])) + return false_ret + + dst_volume = "%s/%s" % (info.split(':')[-1], volume['name']) + src_volume = self._get_zfs_volume_name(volume['name']) + # check if the src and dst volume are under the same zpool + if (src_volume.split('/')[0] == dst_volume.split('/')[0]): + self.rename_volume(src_volume, dst_volume) + else: + self._zfs_send_recv(volume, dst_volume) + # delete the source volume + self.delete_volume(volume) + + provider_location = {} + return (True, provider_location) + class STMFDriver(ZFSVolumeDriver): """Abstract base class for common COMSTAR operations.""" @@ -492,8 +611,14 @@ properties['target_discovered'] = True properties['target_iqn'] = target_name + # Here the san_is_local means that the cinder-volume runs in the + # iSCSI target with iscsi_ip_address. + if self.configuration.san_is_local: + target_ip = self.configuration.iscsi_ip_address + else: + target_ip = self.configuration.san_ip properties['target_portal'] = ('%s:%d' % - (self.configuration.iscsi_ip_address, + (target_ip, self.configuration.iscsi_port)) view_lun = self._get_view_and_lun(luid) if view_lun['lun'] is not None: diff -r 79af241b4834 -r 8f0976d7e40e components/openstack/cinder/patches/01-requirements.patch --- a/components/openstack/cinder/patches/01-requirements.patch Fri Oct 09 09:55:13 2015 -0700 +++ b/components/openstack/cinder/patches/01-requirements.patch Fri Oct 09 11:54:18 2015 -0700 @@ -1,19 +1,17 @@ In-house patch to remove unnecessary dependencies from Cinder's requirements files. The specific reasons are as follows: -kombu Not applicable +kombu Not applicable -oslo.rootwrap Not applicable to Solaris +oslo.rootwrap Not applicable to Solaris -paramiko Not applicable to Solaris (various drivers specific) +pycrypto Not applicable to Solaris (various drivers specific) -pycrypto Not applicable to Solaris (various drivers specific) - -rtslib-fb Not applicable to Solaris (Linux iSCSI specific) +rtslib-fb Not applicable to Solaris (Linux iSCSI specific) ---- cinder-2014.2.2/cinder.egg-info/requires.txt.~1~ 2015-02-05 08:05:50.000000000 -0800 -+++ cinder-2014.2.2/cinder.egg-info/requires.txt 2015-02-23 13:49:52.736413251 -0800 -@@ -6,18 +6,14 @@ eventlet>=0.15.1,<0.16.0 +--- cinder-2014.2.2/cinder.egg-info/requires.txt.orig 2015-05-27 22:55:59.906826810 -0700 ++++ cinder-2014.2.2/cinder.egg-info/requires.txt 2015-05-27 22:57:00.022877081 -0700 +@@ -6,18 +6,15 @@ greenlet>=0.3.2 iso8601>=0.1.9 keystonemiddleware>=1.0.0 @@ -25,14 +23,14 @@ oslo.messaging>=1.4.0,!=1.5.0,<1.6.0 -oslo.rootwrap>=1.3.0 osprofiler>=0.3.0 # Apache-2.0 --paramiko>=1.13.0 + paramiko>=1.13.0 Paste PasteDeploy>=1.5.0 -pycrypto>=2.6 python-barbicanclient>=2.1.0,!=3.0.0,<3.0.2 python-glanceclient>=0.14.0 python-novaclient>=2.18.0 -@@ -25,7 +21,6 @@ python-swiftclient>=2.2.0 +@@ -25,7 +22,6 @@ requests>=1.2.1,!=2.4.0 Routes>=1.12.3,!=2.0 taskflow>=0.4,<0.7.0 @@ -40,9 +38,9 @@ six>=1.7.0 SQLAlchemy>=0.8.4,<=0.9.99,!=0.9.0,!=0.9.1,!=0.9.2,!=0.9.3,!=0.9.4,!=0.9.5,!=0.9.6 sqlalchemy-migrate==0.9.1 ---- cinder-2014.2.2/requirements.txt.~1~ 2015-02-05 08:03:26.000000000 -0800 -+++ cinder-2014.2.2/requirements.txt 2015-02-23 13:52:20.137709426 -0800 -@@ -10,18 +10,14 @@ eventlet>=0.15.1,<0.16.0 +--- cinder-2014.2.2/requirements.txt.orig 2015-05-27 22:57:45.226877884 -0700 ++++ cinder-2014.2.2/requirements.txt 2015-05-27 22:58:25.817248288 -0700 +@@ -10,18 +10,15 @@ greenlet>=0.3.2 iso8601>=0.1.9 keystonemiddleware>=1.0.0 @@ -54,14 +52,14 @@ oslo.messaging>=1.4.0,!=1.5.0,<1.6.0 -oslo.rootwrap>=1.3.0 osprofiler>=0.3.0 # Apache-2.0 --paramiko>=1.13.0 + paramiko>=1.13.0 Paste PasteDeploy>=1.5.0 -pycrypto>=2.6 python-barbicanclient>=2.1.0,!=3.0.0,<3.0.2 python-glanceclient>=0.14.0 python-novaclient>=2.18.0 -@@ -29,7 +25,6 @@ python-swiftclient>=2.2.0 +@@ -29,7 +26,6 @@ requests>=1.2.1,!=2.4.0 Routes>=1.12.3,!=2.0 taskflow>=0.4,<0.7.0 @@ -69,3 +67,4 @@ six>=1.7.0 SQLAlchemy>=0.8.4,<=0.9.99,!=0.9.0,!=0.9.1,!=0.9.2,!=0.9.3,!=0.9.4,!=0.9.5,!=0.9.6 sqlalchemy-migrate==0.9.1 + diff -r 79af241b4834 -r 8f0976d7e40e components/openstack/cinder/patches/04-volume-backup.patch --- a/components/openstack/cinder/patches/04-volume-backup.patch Fri Oct 09 09:55:13 2015 -0700 +++ b/components/openstack/cinder/patches/04-volume-backup.patch Fri Oct 09 11:54:18 2015 -0700 @@ -1,8 +1,8 @@ This patch is to replace the linux-specific codes with the solaris codes to support the cinder backup on the Solaris. ---- cinder-2014.2.2/cinder/brick/initiator/connector.py.~1~ 2014-10-16 06:26:26.000000000 -0700 -+++ cinder-2014.2.2/cinder/brick/initiator/connector.py 2015-01-04 23:12:23.661116812 -0800 +--- cinder-2014.2.2/cinder/brick/initiator/connector.py.~1~ 2015-02-05 08:03:26.000000000 -0800 ++++ cinder-2014.2.2/cinder/brick/initiator/connector.py 2015-04-20 21:05:25.881159722 -0700 @@ -15,6 +15,7 @@ import os @@ -58,7 +58,16 @@ super(ISCSIConnector, self).__init__(root_helper, driver=driver, execute=execute, device_scan_attempts= -@@ -192,6 +204,9 @@ +@@ -181,6 +193,8 @@ + + def set_execute(self, execute): + super(ISCSIConnector, self).set_execute(execute) ++ if sys.platform == 'sunos5': ++ return + self._linuxscsi.set_execute(execute) + + @synchronized('connect_volume') +@@ -192,6 +206,9 @@ target_iqn - iSCSI Qualified Name target_lun - LUN id of the volume """ @@ -68,18 +77,17 @@ device_info = {'type': 'block'} -@@ -262,6 +277,10 @@ +@@ -262,6 +279,9 @@ target_iqn - iSCSI Qualified Name target_lun - LUN id of the volume """ + if sys.platform == 'sunos5': -+ self._solarisiscsi.disconnect_iscsi() + return + # Moved _rescan_iscsi and _rescan_multipath # from _disconnect_volume_multipath_iscsi to here. # Otherwise, if we do rescan after _linuxscsi.remove_multipath_device -@@ -306,6 +325,9 @@ +@@ -306,6 +326,9 @@ def get_initiator(self): """Secure helper to read file as root.""" @@ -89,7 +97,7 @@ file_path = '/etc/iscsi/initiatorname.iscsi' try: lines, _err = self._execute('cat', file_path, run_as_root=True, -@@ -555,8 +577,11 @@ +@@ -555,8 +578,11 @@ execute=putils.execute, use_multipath=False, device_scan_attempts=DEVICE_SCAN_ATTEMPTS_DEFAULT, *args, **kwargs): @@ -103,7 +111,16 @@ super(FibreChannelConnector, self).__init__(root_helper, driver=driver, execute=execute, device_scan_attempts= -@@ -578,6 +603,10 @@ +@@ -566,6 +592,8 @@ + + def set_execute(self, execute): + super(FibreChannelConnector, self).set_execute(execute) ++ if sys.platform == 'sunos5': ++ return + self._linuxscsi.set_execute(execute) + self._linuxfc.set_execute(execute) + +@@ -578,6 +606,10 @@ target_iqn - iSCSI Qualified Name target_lun - LUN id of the volume """ @@ -114,7 +131,7 @@ LOG.debug("execute = %s" % self._execute) device_info = {'type': 'block'} -@@ -686,6 +715,13 @@ +@@ -686,6 +718,13 @@ target_wwn - iSCSI Qualified Name target_lun - LUN id of the volume """ @@ -130,15 +147,18 @@ # If this is a multipath device, we need to search again ---- cinder-2014.2.2/cinder/utils.py.~1~ 2014-10-16 06:26:26.000000000 -0700 -+++ cinder-2014.2.2/cinder/utils.py 2015-01-04 23:26:04.305688145 -0800 -@@ -137,8 +137,9 @@ +--- cinder-2014.2.2/cinder/utils.py.~1~ 2015-02-05 08:03:26.000000000 -0800 ++++ cinder-2014.2.2/cinder/utils.py 2015-04-20 20:46:27.658908715 -0700 +@@ -137,8 +137,12 @@ def execute(*cmd, **kwargs): """Convenience wrapper around oslo's execute() method.""" - if 'run_as_root' in kwargs and 'root_helper' not in kwargs: - kwargs['root_helper'] = get_root_helper() -+ if sys.platform != 'sunos5': ++ if sys.platform == 'sunos5': ++ if 'run_as_root' in kwargs: ++ kwargs['run_as_root'] = False ++ else: + if 'run_as_root' in kwargs and 'root_helper' not in kwargs: + kwargs['root_helper'] = get_root_helper() return processutils.execute(*cmd, **kwargs) diff -r 79af241b4834 -r 8f0976d7e40e components/openstack/cinder/patches/06-no-san-remote.patch --- a/components/openstack/cinder/patches/06-no-san-remote.patch Fri Oct 09 09:55:13 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -This internal-only patch is to prevent Cinder's SanDriver from -attempting to use the Paramiko-based routines until the latter is -integrated into Solaris. It also provides a specific error in the case -where san_is_local=false is defined in the configuration and a driver -is specified that attempts to use that configuration (which implies, -again, an attempt to use Paramiko). - ---- cinder-2014.2.2/cinder/volume/drivers/san/san.py.~1~ 2015-02-05 08:03:26.000000000 -0800 -+++ cinder-2014.2.2/cinder/volume/drivers/san/san.py 2015-04-22 00:54:38.481125902 -0700 -@@ -29,7 +29,6 @@ from cinder.i18n import _ - from cinder.openstack.common import excutils - from cinder.openstack.common import log as logging - from cinder.openstack.common import processutils --from cinder import ssh_utils - from cinder import utils - from cinder.volume import driver - -@@ -165,10 +164,8 @@ class SanDriver(driver.VolumeDriver): - def check_for_setup_error(self): - """Returns an error if prerequisites aren't met.""" - if not self.run_local: -- if not (self.configuration.san_password or -- self.configuration.san_private_key): -- raise exception.InvalidInput( -- reason=_('Specify san_password or san_private_key')) -+ raise exception.InvalidInput( -+ reason=_("san_is_local=false is not currently supported.")) - - # The san_ip must always be set, because we use it for the target - if not self.configuration.san_ip: