22031461 volume attachment failed
22161814 cinder can do 'stmfadm delete-lu' twice leaving volumes in error
22270883 iSCSI driver setup fails when the target is offline
22309444 Cinder IPS package group does not install in non-global Zones
21952273 default value in volume_dd_blocksize=1M in cinder.conf not supported by solaris
--- a/components/openstack/cinder/cinder.p5m Wed Jan 20 16:02:48 2016 -0800
+++ b/components/openstack/cinder/cinder.p5m Sat Jan 23 12:02:26 2016 -0800
@@ -20,7 +20,7 @@
#
#
-# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
#
<transform file path=lib/svc/method/.* -> add pkg.depend.bypass-generate .*/smf_include.*>
@@ -45,6 +45,7 @@
set name=org.opensolaris.arc-caseid value=PSARC/2013/350 value=PSARC/2014/054 \
value=PSARC/2014/208 value=PSARC/2015/110
set name=org.opensolaris.consolidation value=$(CONSOLIDATION)
+set name=variant.opensolaris.zone value=global value=nonglobal
#
dir path=etc/cinder owner=cinder group=cinder mode=0700
file path=etc/cinder/api-paste.ini owner=cinder group=cinder mode=0644 \
@@ -551,10 +552,12 @@
depend type=require fmri=__TBD pkg.debug.depend.file=usr/sbin/fcinfo
# force a dependency on package delivering itadm(1M)
-depend type=require fmri=__TBD pkg.debug.depend.file=usr/sbin/itadm
+depend type=require fmri=__TBD pkg.debug.depend.file=usr/sbin/itadm \
+ variant.opensolaris.zone=global
# force a dependency on package delivering stmfadm(1M)
-depend type=require fmri=__TBD pkg.debug.depend.file=usr/sbin/stmfadm
+depend type=require fmri=__TBD pkg.debug.depend.file=usr/sbin/stmfadm \
+ variant.opensolaris.zone=global
# force a dependency on package delivering zfs(1M)
depend type=require fmri=__TBD pkg.debug.depend.file=usr/sbin/zfs
--- a/components/openstack/cinder/files/cinder.conf Wed Jan 20 16:02:48 2016 -0800
+++ b/components/openstack/cinder/files/cinder.conf Sat Jan 23 12:02:26 2016 -0800
@@ -2090,9 +2090,11 @@
# Options defined in cinder.volume.drivers.solaris.zfs
#
-# The base dataset for ZFS cinder volumes.
+# The base dataset for ZFS cinder volumes. (string value)
#zfs_volume_base=rpool/cinder
+# iSCSI target group name. (string value)
+#zfs_target_group=tgt-grp
#
# Options defined in cinder.volume.drivers.solidfire
--- a/components/openstack/cinder/files/cinder.exec_attr Wed Jan 20 16:02:48 2016 -0800
+++ b/components/openstack/cinder/files/cinder.exec_attr Sat Jan 23 12:02:26 2016 -0800
@@ -3,7 +3,7 @@
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/bin/dd:privs={zone}\:/devices/*
cinder-volume:solaris:cmd:RO::/usr/sbin/fcadm:privs=file_dac_read,sys_devices
--- a/components/openstack/cinder/files/solaris/solarisiscsi.py Wed Jan 20 16:02:48 2016 -0800
+++ b/components/openstack/cinder/files/solaris/solarisiscsi.py Sat Jan 23 12:02:26 2016 -0800
@@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -33,18 +33,46 @@
self.execute = putils.execute
def _get_device_path(self, connection_properties):
- """Get the device path from the target info."""
+ """Get the device path from the target info.
+
+ The output of cmd below is like this:
+ Target: iqn.2010-10.org.openstack:hostname1-tgt-grp-target
+ Alias: -
+ TPGT: 1
+ ISID: 4000002a0000
+ Connections: 1
+ LUN: 1
+ Vendor: SUN
+ Product: COMSTAR
+ OS Device Name: /dev/rdsk/c0t600144F0FDFAD05D0000563C04030003d0s2
+ LUN: 0
+ Vendor: SUN
+ Product: COMSTAR
+ OS Device Name: /dev/rdsk/c0t600144F0FDFAD05D0000563C02270002d0s2
+
+ """
(out, _err) = self.execute('/usr/sbin/iscsiadm', 'list',
'target', '-S',
connection_properties['target_iqn'])
+ found = False
for line in [l.strip() for l in out.splitlines()]:
- if line.startswith("OS Device Name:"):
- dev_path = line.split()[-1]
- return dev_path
- else:
- LOG.error(_("No device is found for the target %s.") %
- connection_properties['target_iqn'])
+ if line.startswith("LUN:"):
+ lun = line.split()[-1]
+ if int(lun) == int(connection_properties['target_lun']):
+ found = True
+ continue
+ if found:
+ if line.startswith("OS Device Name:"):
+ dev_path = line.split()[-1]
+ return dev_path
+ elif line.startswith("LUN:"):
+ found = False
+
+ if not found:
+ LOG.error(_("No device is found for the target %s LUN %s.") %
+ (connection_properties['target_iqn'],
+ connection_properties['target_lun']))
raise
def get_initiator(self):
--- a/components/openstack/cinder/files/solaris/zfs.py Wed Jan 20 16:02:48 2016 -0800
+++ b/components/openstack/cinder/files/solaris/zfs.py Sat Jan 23 12:02:26 2016 -0800
@@ -2,7 +2,7 @@
# Copyright (c) 2012 OpenStack LLC.
# All Rights Reserved.
#
-# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -44,7 +44,10 @@
solaris_zfs_opts = [
cfg.StrOpt('zfs_volume_base',
default='rpool/cinder',
- help='The base dataset for ZFS volumes.'), ]
+ help='The base dataset for ZFS volumes.'),
+ cfg.StrOpt('zfs_target_group',
+ default='tgt-grp',
+ help='iSCSI target group name.'), ]
FLAGS.register_opts(solaris_zfs_opts)
@@ -414,47 +417,46 @@
time.sleep(tries ** 2)
def _check_target(self, target, protocol):
- """Verify if the target exists."""
- (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-target')
-
- for line in [l.strip() for l in out.splitlines()]:
- if line.startswith("Target:"):
- if target == line.split()[-1]:
+ """Verify the target and check its status."""
+ try:
+ (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-target',
+ '-v', target)
+ tmp_protocol = None
+ status = None
+ for line in [l.strip() for l in out.splitlines()]:
+ if line.startswith("Operational"):
+ status = line.split()[-1]
+ if line.startswith("Protocol"):
+ tmp_protocol = line.split()[-1]
break
- else:
- LOG.debug(_("The target '%s' doesn't exist") % target)
- return False
-
- # Verify if the target protocol is iSCSI.
- (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-target',
- '-v', target)
-
- for line in [l.strip() for l in out.splitlines()]:
- if line.startswith("Target:"):
- tmp_target = line.split()[-1]
- if line.startswith("Operational"):
- status = line.split()[-1]
- if line.startswith("Protocol"):
- tmp_protocol = line.split()[-1]
- break
-
- return (tmp_target == target and status == 'Online' and
- tmp_protocol == protocol)
+ if tmp_protocol == protocol:
+ return status
+ else:
+ err_msg = (_("'%s' does not match the listed protocol '%s'"
+ " for target '%s'.")
+ % (protocol, tmp_protocol, target))
+ except processutils.ProcessExecutionError as error:
+ if 'not found' in error.stderr:
+ LOG.debug(_("The target '%s' is not found.") % target)
+ return None
+ else:
+ err_msg = (_("Failed to list the target '%s': '%s'")
+ % (target, error.stderr))
+ raise exception.VolumeBackendAPIException(data=err_msg)
def _check_tg(self, tg):
"""Check if the target group exists."""
- (out, _err) = self._execute('/usr/sbin/stmfadm', 'list-tg')
- found = False
-
- for line in [l.strip() for l in out.splitlines()]:
- if line.startswith("Target"):
- if tg == line.split()[-1]:
- found = True
- break
- else:
- LOG.debug(_("The target group '%s' doesn't exist") % tg)
-
- return found
+ try:
+ self._execute('/usr/sbin/stmfadm', 'list-tg', tg)
+ return True
+ except processutils.ProcessExecutionError as error:
+ if 'not found' in error.stderr:
+ LOG.debug(_("The target group '%s' is not found.") % tg)
+ return False
+ else:
+ err_msg = (_("Failed to list the target group '%s': '%s'")
+ % (tg, error.stderr))
+ raise exception.VolumeBackendAPIException(data=err_msg)
def _get_luid(self, volume):
"""Get the LU corresponding to the volume."""
@@ -519,6 +521,34 @@
def __init__(self, *args, **kwargs):
super(ZFSISCSIDriver, self).__init__(*args, **kwargs)
+ def do_setup(self, context):
+ """Setup the target and target group."""
+ target_group = self.configuration.zfs_target_group
+ target_name = '%s%s-%s-target' % \
+ (self.configuration.iscsi_target_prefix,
+ self.hostname,
+ target_group)
+
+ if not self._check_tg(target_group):
+ self._stmf_execute('/usr/sbin/stmfadm', 'create-tg', target_group)
+ target_status = self._check_target(target_name, 'iSCSI')
+ if target_status == 'Online':
+ return
+
+ if target_status is None:
+ # Create and add the target into the target group
+ self._stmf_execute('/usr/sbin/itadm', 'create-target', '-n',
+ target_name)
+ self._stmf_execute('/usr/sbin/stmfadm', 'offline-target',
+ target_name)
+ self._stmf_execute('/usr/sbin/stmfadm', 'add-tg-member', '-g',
+ target_group, target_name)
+
+ # Online the target from the 'Offline' status
+ self._stmf_execute('/usr/sbin/stmfadm', 'online-target',
+ target_name)
+ assert self._check_target(target_name, 'iSCSI') == 'Online'
+
def create_export(self, context, volume):
"""Export the volume."""
zvol = self._get_zvol_path(volume)
@@ -531,23 +561,10 @@
% volume['name'])
raise exception.VolumeBackendAPIException(data=msg)
- # Create a target group and a target belonging to the target group
- target_group = 'tg-%s' % volume['name']
- self._stmf_execute('/usr/sbin/stmfadm', 'create-tg', target_group)
-
- target_name = '%s%s' % (self.configuration.iscsi_target_prefix,
- volume['name'])
- self._stmf_execute('/usr/sbin/stmfadm', 'add-tg-member', '-g',
- target_group, target_name)
-
- self._stmf_execute('/usr/sbin/itadm', 'create-target', '-n',
- target_name)
- assert self._check_target(target_name, 'iSCSI')
-
- # Add a view entry to the logical unit with the specified LUN, 8776
- if luid is not None:
- self._stmf_execute('/usr/sbin/stmfadm', 'add-view', '-n', '8776',
- '-t', target_group, luid)
+ # Add a view entry to the logical unit
+ target_group = self.configuration.zfs_target_group
+ self._stmf_execute('/usr/sbin/stmfadm', 'add-view',
+ '-t', target_group, luid)
def remove_export(self, context, volume):
"""Remove an export for a volume.
@@ -556,31 +573,24 @@
target, target group, view entry and lu, are deleted.
"""
luid = self._get_luid(volume)
+
+ # Remove the LU
+ if luid is not None:
+ self._stmf_execute('/usr/sbin/stmfadm', 'delete-lu', luid)
+
+ # Remove the target and its target group if they were created by
+ # earlier versions of the volume driver
target_group = 'tg-%s' % volume['name']
target_name = '%s%s' % (self.configuration.iscsi_target_prefix,
volume['name'])
- # Remove the view entry
- if luid is not None:
- view_lun = self._get_view_and_lun(luid)
- if view_lun['view']:
- self._stmf_execute('/usr/sbin/stmfadm', 'remove-view', '-l',
- luid, view_lun['view'])
-
- # Remove the target and its target group
- if self._check_target(target_name, 'iSCSI'):
- self._stmf_execute('/usr/sbin/stmfadm', 'offline-target',
- target_name)
+ if self._check_target(target_name, 'iSCSI') is not None:
self._stmf_execute('/usr/sbin/itadm', 'delete-target', '-f',
target_name)
if self._check_tg(target_group):
self._stmf_execute('/usr/sbin/stmfadm', 'delete-tg', target_group)
- # Remove the LU
- if luid is not None:
- self._stmf_execute('/usr/sbin/stmfadm', 'delete-lu', luid)
-
def _get_iscsi_properties(self, volume):
"""Get iSCSI configuration
@@ -606,6 +616,12 @@
target_name = '%s%s' % (self.configuration.iscsi_target_prefix,
volume['name'])
+ if self._check_target(target_name, 'iSCSI') is None:
+ target_name = '%s%s-%s-target' % \
+ (self.configuration.iscsi_target_prefix,
+ self.hostname,
+ self.configuration.zfs_target_group)
+
properties = {}
properties['target_discovered'] = True
@@ -809,7 +825,7 @@
# Remove the target group when only one LU exists.
if self._only_lu(luid):
- if self._check_target(target_wwn, 'Channel'):
+ if self._check_target(target_wwn, 'Channel') == 'Online':
self._stmf_execute('/usr/sbin/stmfadm', 'offline-target',
target_wwn)
if self._check_tg(target_group):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/cinder/patches/06-enable-dd.patch Sat Jan 23 12:02:26 2016 -0800
@@ -0,0 +1,13 @@
+In-house supporting volume_dd_blocksize ('1M', 'G') to enable 'dd' to run on Solaris. This patch
+is Solaris-specific and not suitable for upstream.
+
+--- cinder-2014.2.2/cinder/volume/utils.py.old 2015-10-20 12:55:15.089090904 -0700
++++ cinder-2014.2.2/cinder/volume/utils.py 2015-10-20 12:55:23.640892844 -0700
+@@ -281,6 +281,7 @@
+ bs = strutils.string_to_bytes('%sB' % blocksize)
+
+ count = math.ceil(size_in_m * units.Mi / bs)
++ blocksize = int(bs)
+
+ return blocksize, int(count)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openstack/cinder/patches/09-launchpad-1414867.patch Sat Jan 23 12:02:26 2016 -0800
@@ -0,0 +1,37 @@
+This upstream patch addresses Launchpad bug 1414867. Although it's been
+addressed in Kilo, the patch below is still not yet released for Juno.
+
+commit 549144f754a8b3adb9d7fdfa8f8f9ee186a52f1e
+Author: wuyuting <email address hidden>
+Date: Tue Jan 27 02:50:28 2015 +0800
+
+ Fetch_to_volume_format calls copy_volume using wrong parameter
+
+ When creating a volume from an image, if qemu-img is not installed,
+ fetch_to_volume_format will call volume_utils.copy_volume to copy
+ image to volume. Copy_volume need the size of image in megabyte,
+ but fetch_to_volume_format call it using size in bytes.
+
+ Change-Id: Ia3b0f9168235a977a12232e27a5755ad11ec18f5
+ Closes-Bug: #1414867
+
+--- cinder-2014.2.2/cinder/image/image_utils.py.orig 2015-10-19 15:59:34.730112261 -0700
++++ cinder-2014.2.2/cinder/image/image_utils.py 2015-10-19 16:02:05.982843565 -0700
+@@ -25,6 +25,7 @@
+
+
+ import contextlib
++import math
+ import os
+ import tempfile
+
+@@ -238,7 +239,8 @@
+ LOG.debug('Copying image from %(tmp)s to volume %(dest)s - '
+ 'size: %(size)s' % {'tmp': tmp, 'dest': dest,
+ 'size': image_meta['size']})
+- volume_utils.copy_volume(tmp, dest, image_meta['size'], blocksize)
++ image_size_m = math.ceil(image_meta['size'] / units.Mi)
++ volume_utils.copy_volume(tmp, dest, image_size_m, blocksize)
+ return
+
+ data = qemu_img_info(tmp)