22031461 volume attachment failed s11u3-sru
authorQiang Strony Zhang <strony.zhang@oracle.com>
Sat, 23 Jan 2016 12:02:26 -0800
branchs11u3-sru
changeset 5317 fa561e436e88
parent 5316 1312ff3232f3
child 5318 efa7f7393e63
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
components/openstack/cinder/cinder.p5m
components/openstack/cinder/files/cinder.conf
components/openstack/cinder/files/cinder.exec_attr
components/openstack/cinder/files/solaris/solarisiscsi.py
components/openstack/cinder/files/solaris/zfs.py
components/openstack/cinder/patches/06-enable-dd.patch
components/openstack/cinder/patches/09-launchpad-1414867.patch
--- 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)