Hello community,

here is the log from the commit of package openstack-cinder for 
openSUSE:Factory checked in at 2014-02-11 10:40:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openstack-cinder (Old)
 and      /work/SRC/openSUSE:Factory/.openstack-cinder.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openstack-cinder"

Changes:
--------
--- /work/SRC/openSUSE:Factory/openstack-cinder/openstack-cinder.changes        
2014-01-30 17:42:14.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.openstack-cinder.new/openstack-cinder.changes   
2014-02-11 10:40:17.000000000 +0100
@@ -1,0 +2,17 @@
+Thu Feb  6 14:48:37 UTC 2014 - [email protected]
+
+- fix typo in logrotate 
+
+-------------------------------------------------------------------
+Mon Feb  3 00:43:03 UTC 2014 - [email protected]
+
+- Update to version 2013.2.2.dev21.g240c81d:
+  + hanges I8686a1be,I4a9ea40d into stable/havan
+  + GlusterFS: Use correct base argument when deleting attached snaps
+
+-------------------------------------------------------------------
+Thu Jan 30 15:09:12 UTC 2014 - [email protected]
+
+- move lock_path to /var/run
+
+-------------------------------------------------------------------

New:
----
  openstack-cinder.conf

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ openstack-cinder-doc.spec ++++++
--- /var/tmp/diff_new_pack.NtS2Rk/_old  2014-02-11 10:40:18.000000000 +0100
+++ /var/tmp/diff_new_pack.NtS2Rk/_new  2014-02-11 10:40:18.000000000 +0100
@@ -19,7 +19,7 @@
 %define component cinder
 
 Name:           openstack-%{component}-doc
-Version:        2013.2.2.dev16.g77fade5
+Version:        2013.2.2.dev21.g240c81d
 Release:        0
 Summary:        OpenStack Block Storage (Cinder) - Documentation
 License:        Apache-2.0
@@ -62,7 +62,7 @@
 This package contains documentation files for %{name}.
 
 %prep
-%setup -q -n cinder-2013.2.2.dev16.g77fade5
+%setup -q -n cinder-2013.2.2.dev21.g240c81d
 %openstack_cleanup_prep
 
 %build

++++++ openstack-cinder.spec ++++++
--- /var/tmp/diff_new_pack.NtS2Rk/_old  2014-02-11 10:40:18.000000000 +0100
+++ /var/tmp/diff_new_pack.NtS2Rk/_new  2014-02-11 10:40:18.000000000 +0100
@@ -21,7 +21,7 @@
 %define username openstack-%{component}
 
 Name:           openstack-%{component}
-Version:        2013.2.2.dev16.g77fade5
+Version:        2013.2.2.dev21.g240c81d
 Release:        0
 Summary:        OpenStack Block Storage (Cinder)
 License:        Apache-2.0
@@ -31,6 +31,10 @@
 Source1:        %{name}.init
 Source2:        %{name}.logrotate
 Source3:        cinder-sudoers
+%if 0%{?suse_version} > 1230
+Source10:       %name.conf
+BuildRequires:  systemd
+%endif
 Patch0:         0001-Avoid-using-GREENDNS-due-to-dnspython.patch
 Patch1:         0001-Set-useful-vendor-product-id-in-Cinder-ISCSI-exports.patch
 Patch2:         0001-Robustify-skipactivation-detection.patch
@@ -188,7 +192,7 @@
 functionality of OpenStack Cinder.
 
 %prep
-%setup -q -n cinder-2013.2.2.dev16.g77fade5
+%setup -q -n cinder-2013.2.2.dev21.g240c81d
 %patch0 -p1
 %patch1 -p1
 %patch2 -p1
@@ -205,7 +209,11 @@
 
 ### directories
 install -d -m 755 %{buildroot}%{_localstatedir}/{lib,log}/%{component}
-install -d -m 750 %{buildroot}%{_localstatedir}/{lock,cache,run}/%{component}
+install -d -m 750 %{buildroot}%{_localstatedir}/cache/%{component}
+install -d -m 700 %{buildroot}%{_localstatedir}/run/%{component}
+%if 0%{?suse_version} > 1230
+install -D -m 644 %{SOURCE10} %{buildroot}/%_tmpfilesdir/%name.conf
+%endif
 install -d -m 755 %{buildroot}%{_sysconfdir}/%{component}
 
 ### configuration files
@@ -258,7 +266,7 @@
 #NOTE(saschpe): Can't hurt to set the default volume_group, only the LVM 
driver has a it otherwise:
 crudini --set %{cinder_conf} DEFAULT volume_group cinder-volumes
 crudini --set %{cinder_conf} keystone_authtoken signing_dir 
/var/cache/%component/keystone-signing
-crudini --set %{cinder_conf} DEFAULT lock_path /var/lock/%component
+crudini --set %{cinder_conf} DEFAULT lock_path /var/run/%component
 
 %pre
 getent group %{groupname} >/dev/null || groupadd -r %{groupname}
@@ -309,9 +317,13 @@
 %doc LICENSE README.rst
 %dir %attr(0755, %{username}, %{groupname}) %{_localstatedir}/lib/%{component}
 %dir %attr(0750, %{username}, %{groupname}) 
%{_localstatedir}/cache/%{component}
-%dir %attr(0750, %{username}, %{groupname}) %{_localstatedir}/lock/%{component}
 %dir %attr(0750, %{username}, %{groupname}) %{_localstatedir}/log/%{component}
-%ghost %dir %attr(0750, %{username}, %{groupname}) 
%{_localstatedir}/run/%{component}
+%if 0%{?suse_version} > 1230
+%ghost %dir %attr(700,%{username},%{groupname}) 
%{_localstatedir}/run/%{component}
+%_tmpfilesdir/%name.conf
+%else
+%dir %attr(0700, %{username}, %{groupname}) %{_localstatedir}/run/%{component}
+%endif
 %dir %{_sysconfdir}/%{component}
 %dir %{_sysconfdir}/%{component}/rootwrap.d
 %config(noreplace) %{_sysconfdir}/logrotate.d/%{name}

++++++ cinder-stable-havana.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cinder-2013.2.2.dev16.g77fade5/ChangeLog 
new/cinder-2013.2.2.dev21.g240c81d/ChangeLog
--- old/cinder-2013.2.2.dev16.g77fade5/ChangeLog        2014-01-29 
21:08:23.000000000 +0100
+++ new/cinder-2013.2.2.dev21.g240c81d/ChangeLog        2014-02-02 
07:49:45.000000000 +0100
@@ -1,3 +1,21 @@
+commit 240c81d00a49f924e1b9257fee76a7d924246c57
+Merge: f02d4fe 5ef9c9b
+Author: Jenkins <[email protected]>
+Date:   Sun Feb 2 06:47:03 2014 +0000
+
+    Merge "GlusterFS: Use correct base argument when deleting attached snaps" 
into stable/havana
+
+commit f02d4fed0c5b3019449dbf8cf81fff1e64337aa1
+Merge: 77fade5 5122593
+Author: Jenkins <[email protected]>
+Date:   Sun Feb 2 05:58:45 2014 +0000
+
+    Merge changes I8686a1be,I4a9ea40d into stable/havana
+    
+    * changes:
+      GlusterFS: Complete snapshot_delete when info doesn't exist
+      GlusterFS: Ensure Cinder can write to shares
+
 commit 77fade503a4bc2ff45f43855d03125a361a43ffb
 Merge: 3d967e0 c07d60f
 Author: Jenkins <[email protected]>
@@ -42,6 +60,53 @@
     Change-Id: Ic40cd0cdc862b44b0a7d3e5b1d7c4fee8ea1b28d
     (cherry picked from commit 21ebf2898e2f5fc8127b7a3bdc9743c49933f952)
 
+commit 5ef9c9b92812b5a66218fecd5ace8515b149ea1a
+Author: Eric Harney <[email protected]>
+Date:   Wed Dec 18 19:11:44 2013 -0500
+
+    GlusterFS: Use correct base argument when deleting attached snaps
+    
+    When deleting the most recent snapshot, the 'file_to_merge' field
+    which translates into the base= field for libvirt's blockRebase
+    call in Nova must be set depending on whether other snapshots exist.
+    
+    If there are no other snapshots, base = None, which results in
+    libvirt clearing the qcow2 backing file pointer for the active
+    disk image.
+    
+    If there are other snapshots, pass the parent of the file being
+    deleted as the new base file.  The snapshot info pointer for the
+    prior base file must also be updated in this case.
+    
+    Closes-Bug: #1262880
+    
+    (cherry picked from commit 186221779a92002ff9fa13c254710c0abb3803be)
+    Conflicts:
+       cinder/tests/test_glusterfs.py
+    
+    Change-Id: If7bc8259b031d0406346caafb8f688e65a38dba6
+
+commit 5122593add816c0d20affe2f3d703a1657ceb0fc
+Author: Eric Harney <[email protected]>
+Date:   Tue Nov 19 16:25:47 2013 -0500
+
+    GlusterFS: Complete snapshot_delete when info doesn't exist
+    
+    The snapshot_delete operation will fail if the snapshot info file
+    doesn't contain a record for the snapshot, or does not exist.
+    This happens in cases such as when snapshot_create fails to commit
+    anything to disk.
+    
+    The driver should allow the manager to delete the snapshot
+    in this case, as there is no action required for the driver
+    to delete anything.
+    
+    Closes-Bug: #1252864
+    
+    (cherry picked from commit d8a11168c908fe6c6a07fbb30a5bc88a6df6e939)
+    
+    Change-Id: I8686a1be09dbb7984072538bff6c026bb84eeb52
+
 commit ec8ce6cdf236154b4ba0b392202fa7bd7c7c9b61
 Merge: 5228001 1b437d9
 Author: Jenkins <[email protected]>
@@ -258,6 +323,23 @@
 
     Merge "GlusterFS: Synchronize operations that manipulate qcow2 data" into 
stable/havana
 
+commit d39b2d2d808a79280201f6dc00aa93f576d70acd
+Author: Eric Harney <[email protected]>
+Date:   Tue Nov 19 18:01:55 2013 -0500
+
+    GlusterFS: Ensure Cinder can write to shares
+    
+    Ensure the Cinder user can write to the GlusterFS share.  This
+    is required for snapshot functionality, and means the admin
+    does not have to set this permission manually.
+    
+    Conflicts:
+       cinder/tests/test_glusterfs.py
+    
+    Closes-Bug: #1236966
+    Change-Id: I4a9ea40df9681ca6931ad6b390aa21b09d6cfec9
+    (cherry picked from commit 371fa540600b20b97eae389e1f976145866cadae)
+
 commit 9e2ba7b5274c07cba5275d9d65ed8c73810f21f8
 Author: Eric Harney <[email protected]>
 Date:   Mon Nov 18 13:42:37 2013 -0500
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cinder-2013.2.2.dev16.g77fade5/PKG-INFO 
new/cinder-2013.2.2.dev21.g240c81d/PKG-INFO
--- old/cinder-2013.2.2.dev16.g77fade5/PKG-INFO 2014-01-29 21:08:24.000000000 
+0100
+++ new/cinder-2013.2.2.dev21.g240c81d/PKG-INFO 2014-02-02 07:49:46.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cinder
-Version: 2013.2.2.dev16.g77fade5
+Version: 2013.2.2.dev21.g240c81d
 Summary: OpenStack Block Storage
 Home-page: http://www.openstack.org/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/cinder-2013.2.2.dev16.g77fade5/cinder/tests/test_glusterfs.py 
new/cinder-2013.2.2.dev21.g240c81d/cinder/tests/test_glusterfs.py
--- old/cinder-2013.2.2.dev16.g77fade5/cinder/tests/test_glusterfs.py   
2014-01-29 21:06:39.000000000 +0100
+++ new/cinder-2013.2.2.dev21.g240c81d/cinder/tests/test_glusterfs.py   
2014-02-02 07:47:48.000000000 +0100
@@ -19,6 +19,7 @@
 import errno
 import json
 import os
+import tempfile
 
 import mox as mox_lib
 from mox import IgnoreArg
@@ -34,6 +35,7 @@
 from cinder import test
 from cinder.tests.compute import test_nova
 from cinder import units
+from cinder import utils
 from cinder.volume import configuration as conf
 from cinder.volume.drivers import glusterfs
 
@@ -311,6 +313,11 @@
         mox = self._mox
         drv = self._driver
 
+        mox.StubOutWithMock(utils, 'get_file_mode')
+        mox.StubOutWithMock(utils, 'get_file_gid')
+        mox.StubOutWithMock(drv, '_execute')
+        mox.StubOutWithMock(drv, '_ensure_share_writable')
+
         mox.StubOutWithMock(drv, '_get_mount_point_for_share')
         drv._get_mount_point_for_share(self.TEST_EXPORT1).\
             AndReturn(self.TEST_MNT_POINT)
@@ -319,6 +326,15 @@
         drv._mount_glusterfs(self.TEST_EXPORT1, self.TEST_MNT_POINT,
                              ensure=True)
 
+        utils.get_file_gid(self.TEST_MNT_POINT).AndReturn(333333)
+
+        utils.get_file_mode(self.TEST_MNT_POINT).AndReturn(0o777)
+
+        drv._ensure_share_writable(self.TEST_MNT_POINT)
+
+        drv._execute('chgrp', IgnoreArg(), self.TEST_MNT_POINT,
+                     run_as_root=True)
+
         mox.ReplayAll()
 
         drv._ensure_share_mounted(self.TEST_EXPORT1)
@@ -399,6 +415,52 @@
 
         mox.VerifyAll()
 
+    def _fake_load_shares_config(self, conf):
+        self._driver.shares = {'127.7.7.7:/gluster1': None}
+
+    def _fake_NamedTemporaryFile(self, prefix=None, dir=None):
+        raise OSError('Permission denied!')
+
+    def test_setup_set_share_permissions(self):
+        mox = self._mox
+        drv = self._driver
+
+        glusterfs.CONF.glusterfs_shares_config = self.TEST_SHARES_CONFIG_FILE
+
+        self.stubs.Set(drv, '_load_shares_config',
+                       self._fake_load_shares_config)
+        self.stubs.Set(tempfile, 'NamedTemporaryFile',
+                       self._fake_NamedTemporaryFile)
+        mox.StubOutWithMock(os.path, 'exists')
+        mox.StubOutWithMock(drv, '_execute')
+        mox.StubOutWithMock(utils, 'get_file_gid')
+        mox.StubOutWithMock(utils, 'get_file_mode')
+        mox.StubOutWithMock(os, 'getegid')
+
+        drv._execute('mount.glusterfs', check_exit_code=False)
+
+        drv._execute('mkdir', '-p', mox_lib.IgnoreArg())
+
+        os.path.exists(self.TEST_SHARES_CONFIG_FILE).AndReturn(True)
+
+        drv._execute('mount', '-t', 'glusterfs', '127.7.7.7:/gluster1',
+                     mox_lib.IgnoreArg(), run_as_root=True)
+
+        utils.get_file_gid(mox_lib.IgnoreArg()).AndReturn(33333)
+        # perms not writable
+        utils.get_file_mode(mox_lib.IgnoreArg()).AndReturn(0o000)
+
+        os.getegid().AndReturn(888)
+
+        drv._execute('chgrp', 888, mox_lib.IgnoreArg(), run_as_root=True)
+        drv._execute('chmod', 'g+w', mox_lib.IgnoreArg(), run_as_root=True)
+
+        mox.ReplayAll()
+
+        drv.do_setup(IsA(context.RequestContext))
+
+        mox.VerifyAll()
+
     def test_find_share_should_throw_error_if_there_is_no_mounted_shares(self):
         """_find_share should throw error if there is no mounted shares."""
         drv = self._driver
@@ -765,6 +827,7 @@
         (mox, drv) = self._mox, self._driver
 
         hashed = drv._get_hash_str(self.TEST_EXPORT1)
+        volume_dir = os.path.join(self.TEST_MNT_POINT_BASE, hashed)
         volume_path = '%s/%s/volume-%s' % (self.TEST_MNT_POINT_BASE,
                                            hashed,
                                            self.VOLUME_UUID)
@@ -789,8 +852,11 @@
         mox.StubOutWithMock(drv, '_get_backing_chain_for_path')
         mox.StubOutWithMock(drv, '_get_matching_backing_file')
         mox.StubOutWithMock(drv, '_write_info_file')
+        mox.StubOutWithMock(drv, '_ensure_share_writable')
         mox.StubOutWithMock(image_utils, 'qemu_img_info')
 
+        drv._ensure_share_writable(volume_dir)
+
         img_info = image_utils.QemuImgInfo(qemu_img_info_output)
         image_utils.qemu_img_info(snap_path_2).AndReturn(img_info)
 
@@ -810,7 +876,8 @@
         snap_path_chain = [{self.SNAP_UUID: snap_file},
                            {'active': snap_file}]
 
-        drv._read_info_file(info_path).AndReturn(info_file_dict)
+        drv._read_info_file(info_path, empty_if_missing=True).\
+            AndReturn(info_file_dict)
 
         drv._execute('qemu-img', 'commit', snap_path_2, run_as_root=True)
 
@@ -850,6 +917,7 @@
 
         hashed = drv._get_hash_str(self.TEST_EXPORT1)
         volume_file = 'volume-%s' % self.VOLUME_UUID
+        volume_dir = os.path.join(self.TEST_MNT_POINT_BASE, hashed)
         volume_path = '%s/%s/%s' % (self.TEST_MNT_POINT_BASE,
                                     hashed,
                                     volume_file)
@@ -887,6 +955,7 @@
         mox.StubOutWithMock(drv, '_write_info_file')
         mox.StubOutWithMock(drv, '_get_backing_chain_for_path')
         mox.StubOutWithMock(drv, 'get_active_image_from_info')
+        mox.StubOutWithMock(drv, '_ensure_share_writable')
         mox.StubOutWithMock(image_utils, 'qemu_img_info')
 
         info_file_dict = {self.SNAP_UUID_2: 'volume-%s.%s' %
@@ -894,8 +963,11 @@
                           self.SNAP_UUID: 'volume-%s.%s' %
                           (self.VOLUME_UUID, self.SNAP_UUID)}
 
+        drv._ensure_share_writable(volume_dir)
+
         info_path = drv._local_path_volume(volume) + '.info'
-        drv._read_info_file(info_path).AndReturn(info_file_dict)
+        drv._read_info_file(info_path, empty_if_missing=True).\
+            AndReturn(info_file_dict)
 
         img_info = image_utils.QemuImgInfo(qemu_img_info_output_snap_1)
         image_utils.qemu_img_info(snap_path).AndReturn(img_info)
@@ -930,6 +1002,44 @@
 
         mox.VerifyAll()
 
+    def test_delete_snapshot_not_in_info(self):
+        """Snapshot not in info file / info file doesn't exist.
+
+        Snapshot creation failed so nothing is on-disk.  Driver
+        should allow operation to succeed so the manager can
+        remove the snapshot record.
+
+        (Scenario: Snapshot object created in Cinder db but not
+         on backing storage.)
+
+        """
+        (mox, drv) = self._mox, self._driver
+
+        hashed = drv._get_hash_str(self.TEST_EXPORT1)
+        volume_dir = os.path.join(self.TEST_MNT_POINT_BASE, hashed)
+        volume_filename = 'volume-%s' % self.VOLUME_UUID
+        volume_path = os.path.join(volume_dir, volume_filename)
+        info_path = '%s%s' % (volume_path, '.info')
+
+        mox.StubOutWithMock(drv, '_read_file')
+        mox.StubOutWithMock(drv, '_read_info_file')
+        mox.StubOutWithMock(drv, '_ensure_share_writable')
+
+        snap_ref = {'name': 'test snap',
+                    'volume_id': self.VOLUME_UUID,
+                    'volume': self._simple_volume(),
+                    'id': self.SNAP_UUID_2}
+
+        drv._ensure_share_writable(volume_dir)
+
+        drv._read_info_file(info_path, empty_if_missing=True).AndReturn({})
+
+        mox.ReplayAll()
+
+        drv.delete_snapshot(snap_ref)
+
+        mox.VerifyAll()
+
     def test_read_info_file(self):
         (mox, drv) = self._mox, self._driver
 
@@ -1112,7 +1222,7 @@
                           snap_ref)
 
     def test_delete_snapshot_online_1(self):
-        """Delete the newest snapshot."""
+        """Delete the newest snapshot, with only one snap present."""
         (mox, drv) = self._mox, self._driver
 
         volume = self._simple_volume()
@@ -1128,6 +1238,7 @@
 
         hashed = drv._get_hash_str(self.TEST_EXPORT1)
         volume_file = 'volume-%s' % self.VOLUME_UUID
+        volume_dir = os.path.join(self.TEST_MNT_POINT_BASE, hashed)
         volume_path = '%s/%s/%s' % (self.TEST_MNT_POINT_BASE,
                                     hashed,
                                     volume_file)
@@ -1143,11 +1254,15 @@
         mox.StubOutWithMock(os.path, 'exists')
         mox.StubOutWithMock(db, 'snapshot_get')
         mox.StubOutWithMock(image_utils, 'qemu_img_info')
+        mox.StubOutWithMock(drv, '_ensure_share_writable')
 
         snap_info = {'active': snap_file,
                      self.SNAP_UUID: snap_file}
 
-        drv._read_info_file(info_path).AndReturn(snap_info)
+        drv._ensure_share_writable(volume_dir)
+
+        drv._read_info_file(info_path, empty_if_missing=True).\
+            AndReturn(snap_info)
 
         os.path.exists(snap_path).AndReturn(True)
 
@@ -1158,15 +1273,25 @@
         backing file: %s
         """ % (snap_file, volume_file)
         img_info = image_utils.QemuImgInfo(qemu_img_info_output)
+
+        vol_qemu_img_info_output = """image: %s
+        file format: raw
+        virtual size: 1.0G (1073741824 bytes)
+        disk size: 173K
+        """ % volume_file
+        volume_img_info = image_utils.QemuImgInfo(vol_qemu_img_info_output)
+
         image_utils.qemu_img_info(snap_path).AndReturn(img_info)
 
+        image_utils.qemu_img_info(volume_path).AndReturn(volume_img_info)
+
         drv._read_info_file(info_path, empty_if_missing=True).\
             AndReturn(snap_info)
 
         delete_info = {
             'type': 'qcow2',
             'merge_target_file': None,
-            'file_to_merge': volume_file,
+            'file_to_merge': None,
             'volume_id': self.VOLUME_UUID
         }
 
@@ -1197,7 +1322,7 @@
         drv.delete_snapshot(snap_ref)
 
     def test_delete_snapshot_online_2(self):
-        """Delete the middle snapshot."""
+        """Delete the middle of 3 snapshots."""
         (mox, drv) = self._mox, self._driver
 
         volume = self._simple_volume()
@@ -1213,6 +1338,7 @@
 
         hashed = drv._get_hash_str(self.TEST_EXPORT1)
         volume_file = 'volume-%s' % self.VOLUME_UUID
+        volume_dir = os.path.join(self.TEST_MNT_POINT_BASE, hashed)
         volume_path = '%s/%s/%s' % (self.TEST_MNT_POINT_BASE,
                                     hashed,
                                     volume_file)
@@ -1230,12 +1356,16 @@
         mox.StubOutWithMock(os.path, 'exists')
         mox.StubOutWithMock(db, 'snapshot_get')
         mox.StubOutWithMock(image_utils, 'qemu_img_info')
+        mox.StubOutWithMock(drv, '_ensure_share_writable')
 
         snap_info = {'active': snap_file_2,
                      self.SNAP_UUID: snap_file,
                      self.SNAP_UUID_2: snap_file_2}
 
-        drv._read_info_file(info_path).AndReturn(snap_info)
+        drv._ensure_share_writable(volume_dir)
+
+        drv._read_info_file(info_path, empty_if_missing=True).\
+            AndReturn(snap_info)
 
         os.path.exists(snap_path).AndReturn(True)
 
@@ -1247,8 +1377,17 @@
         """ % (snap_file, volume_file)
         img_info = image_utils.QemuImgInfo(qemu_img_info_output)
 
+        vol_qemu_img_info_output = """image: %s
+        file format: raw
+        virtual size: 1.0G (1073741824 bytes)
+        disk size: 173K
+        """ % volume_file
+        volume_img_info = image_utils.QemuImgInfo(vol_qemu_img_info_output)
+
         image_utils.qemu_img_info(snap_path).AndReturn(img_info)
 
+        image_utils.qemu_img_info(volume_path).AndReturn(volume_img_info)
+
         drv._read_info_file(info_path, empty_if_missing=True).\
             AndReturn(snap_info)
 
@@ -1318,7 +1457,8 @@
         snap_info = {'active': snap_file,
                      self.SNAP_UUID: snap_file}
 
-        drv._read_info_file(info_path).AndReturn(snap_info)
+        drv._read_info_file(info_path, empty_if_missing=True).\
+            AndReturn(snap_info)
 
         os.path.exists(snap_path).AndReturn(True)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/cinder-2013.2.2.dev16.g77fade5/cinder/tests/test_utils.py 
new/cinder-2013.2.2.dev21.g240c81d/cinder/tests/test_utils.py
--- old/cinder-2013.2.2.dev16.g77fade5/cinder/tests/test_utils.py       
2014-01-29 21:06:39.000000000 +0100
+++ new/cinder-2013.2.2.dev21.g240c81d/cinder/tests/test_utils.py       
2014-02-02 07:47:48.000000000 +0100
@@ -513,6 +513,57 @@
 
         self.mox.VerifyAll()
 
+    def _make_fake_stat(self, test_file, orig_os_stat):
+        """Create a fake method to stub out os.stat().
+
+           Generate a function that will return a particular
+           stat object for a given file.
+
+           :param: test_file: file to spoof stat() for
+           :param: orig_os_stat: pointer to original os.stat()
+        """
+
+        def fake_stat(path):
+            if path == test_file:
+                class stat_result:
+                    st_mode = 0o777
+                    st_gid = 33333
+                return stat_result
+            else:
+                return orig_os_stat(path)
+
+        return fake_stat
+
+    def test_get_file_mode(self):
+        test_file = '/var/tmp/made_up_file'
+
+        orig_os_stat = os.stat
+        os.stat = self._make_fake_stat(test_file, orig_os_stat)
+
+        self.mox.ReplayAll()
+
+        mode = utils.get_file_mode(test_file)
+        self.assertEqual(mode, 0o777)
+
+        self.mox.VerifyAll()
+
+        os.stat = orig_os_stat
+
+    def test_get_file_gid(self):
+        test_file = '/var/tmp/made_up_file'
+
+        orig_os_stat = os.stat
+        os.stat = self._make_fake_stat(test_file, orig_os_stat)
+
+        self.mox.ReplayAll()
+
+        gid = utils.get_file_gid(test_file)
+        self.assertEqual(gid, 33333)
+
+        self.mox.VerifyAll()
+
+        os.stat = orig_os_stat
+
 
 class MonkeyPatchTestCase(test.TestCase):
     """Unit test for utils.monkey_patch()."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cinder-2013.2.2.dev16.g77fade5/cinder/utils.py 
new/cinder-2013.2.2.dev21.g240c81d/cinder/utils.py
--- old/cinder-2013.2.2.dev16.g77fade5/cinder/utils.py  2014-01-29 
21:06:39.000000000 +0100
+++ new/cinder-2013.2.2.dev21.g240c81d/cinder/utils.py  2014-02-02 
07:47:48.000000000 +0100
@@ -30,6 +30,7 @@
 import random
 import re
 import shutil
+import stat
 import sys
 import tempfile
 import time
@@ -820,3 +821,13 @@
             raise exception.DriverNotInitialized(driver=driver_name)
         return func(self, *args, **kwargs)
     return wrapper
+
+
+def get_file_mode(path):
+    """This primarily exists to make unit testing easier."""
+    return stat.S_IMODE(os.stat(path).st_mode)
+
+
+def get_file_gid(path):
+    """This primarily exists to make unit testing easier."""
+    return os.stat(path).st_gid
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/cinder-2013.2.2.dev16.g77fade5/cinder/volume/drivers/glusterfs.py 
new/cinder-2013.2.2.dev21.g240c81d/cinder/volume/drivers/glusterfs.py
--- old/cinder-2013.2.2.dev16.g77fade5/cinder/volume/drivers/glusterfs.py       
2014-01-29 21:06:39.000000000 +0100
+++ new/cinder-2013.2.2.dev21.g240c81d/cinder/volume/drivers/glusterfs.py       
2014-02-02 07:47:48.000000000 +0100
@@ -20,6 +20,8 @@
 import json
 import os
 import re
+import stat
+import tempfile
 import time
 
 from oslo.config import cfg
@@ -108,6 +110,8 @@
             else:
                 raise
 
+        self._ensure_shares_mounted()
+
     def check_for_setup_error(self):
         """Just to override parent behavior."""
         pass
@@ -545,6 +549,10 @@
         If volume status is 'in-use', calculate what qcow2 files need to
         merge, and call to Nova to perform this operation.
 
+        :raises: InvalidVolume if status not acceptable
+        :raises: GlusterfsException(msg) if operation fails
+        :returns: None
+
         """
 
         LOG.debug(_('deleting snapshot %s') % snapshot['id'])
@@ -554,12 +562,24 @@
             msg = _('Volume status must be "available" or "in-use".')
             raise exception.InvalidVolume(msg)
 
+        self._ensure_share_writable(
+            self._local_volume_dir(snapshot['volume']))
+
         # Determine the true snapshot file for this snapshot
         #  based on the .info file
         info_path = self._local_path_volume(snapshot['volume']) + '.info'
-        snap_info = self._read_info_file(info_path)
-        snapshot_file = snap_info[snapshot['id']]
+        snap_info = self._read_info_file(info_path, empty_if_missing=True)
 
+        if snapshot['id'] not in snap_info:
+            # If snapshot info file is present, but snapshot record does not
+            # exist, do not attempt to delete.
+            # (This happens, for example, if snapshot_create failed due to lack
+            # of permission to write to the share.)
+            LOG.info(_('Snapshot record for %s is not present, allowing '
+                       'snapshot_delete to proceed.') % snapshot['id'])
+            return
+
+        snapshot_file = snap_info[snapshot['id']]
         LOG.debug(_('snapshot_file for this snap is %s') % snapshot_file)
 
         snapshot_path = '%s/%s' % (self._local_volume_dir(snapshot['volume']),
@@ -583,6 +603,12 @@
                 # file as base.
                 msg = _('No base file found for %s.') % snapshot_path
                 raise exception.GlusterfsException(msg)
+
+            base_path = os.path.join(
+                self._local_volume_dir(snapshot['volume']), base_file)
+            base_file_img_info = self._qemu_img_info(base_path)
+            new_base_file = base_file_img_info.backing_file
+
             base_id = None
             info_path = self._local_path_volume(snapshot['volume']) + '.info'
             snap_info = self._read_info_file(info_path)
@@ -601,7 +627,8 @@
                 'active_file': active_file,
                 'snapshot_file': snapshot_file,
                 'base_file': base_file,
-                'base_id': base_id
+                'base_id': base_id,
+                'new_base_file': new_base_file
             }
 
             return self._delete_snapshot_online(context,
@@ -711,8 +738,15 @@
             # info['base'] => snapshot_file
 
             file_to_delete = info['base_file']
+            if info['base_id'] is None:
+                # Passing base=none to blockRebase ensures that
+                # libvirt blanks out the qcow2 backing file pointer
+                new_base = None
+            else:
+                new_base = info['new_base_file']
+                snap_info[info['base_id']] = info['snapshot_file']
 
-            delete_info = {'file_to_merge': info['base_file'],
+            delete_info = {'file_to_merge': new_base,
                            'merge_target_file': None,  # current
                            'type': 'qcow2',
                            'volume_id': snapshot['volume']['id']}
@@ -981,6 +1015,26 @@
 
         LOG.debug(_('Available shares: %s') % str(self._mounted_shares))
 
+    def _ensure_share_writable(self, path):
+        """Ensure that the Cinder user can write to the share.
+
+        If not, raise an exception.
+
+        :param path: path to test
+        :raises: GlusterfsException
+        :returns: None
+        """
+
+        prefix = '.cinder-write-test-' + str(os.getpid()) + '-'
+
+        try:
+            tempfile.NamedTemporaryFile(prefix=prefix, dir=path)
+        except OSError:
+            msg = _('GlusterFS share at %(dir)s is not writable by the '
+                    'Cinder volume service. Snapshot operations will not be '
+                    'supported.') % {'dir': path}
+            raise exception.GlusterfsException(msg)
+
     def _ensure_share_mounted(self, glusterfs_share):
         """Mount GlusterFS share.
         :param glusterfs_share: string
@@ -988,6 +1042,21 @@
         mount_path = self._get_mount_point_for_share(glusterfs_share)
         self._mount_glusterfs(glusterfs_share, mount_path, ensure=True)
 
+        # Ensure we can write to this share
+        group_id = os.getegid()
+        current_group_id = utils.get_file_gid(mount_path)
+        current_mode = utils.get_file_mode(mount_path)
+
+        if group_id != current_group_id:
+            cmd = ['chgrp', group_id, mount_path]
+            self._execute(*cmd, run_as_root=True)
+
+        if not (current_mode & stat.S_IWGRP):
+            cmd = ['chmod', 'g+w', mount_path]
+            self._execute(*cmd, run_as_root=True)
+
+        self._ensure_share_writable(mount_path)
+
     def _find_share(self, volume_size_for):
         """Choose GlusterFS share among available ones for given volume size.
         Current implementation looks for greatest capacity.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/cinder-2013.2.2.dev16.g77fade5/cinder.egg-info/PKG-INFO 
new/cinder-2013.2.2.dev21.g240c81d/cinder.egg-info/PKG-INFO
--- old/cinder-2013.2.2.dev16.g77fade5/cinder.egg-info/PKG-INFO 2014-01-29 
21:08:23.000000000 +0100
+++ new/cinder-2013.2.2.dev21.g240c81d/cinder.egg-info/PKG-INFO 2014-02-02 
07:49:46.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cinder
-Version: 2013.2.2.dev16.g77fade5
+Version: 2013.2.2.dev21.g240c81d
 Summary: OpenStack Block Storage
 Home-page: http://www.openstack.org/
 Author: OpenStack
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/cinder-2013.2.2.dev16.g77fade5/etc/cinder/rootwrap.d/volume.filters 
new/cinder-2013.2.2.dev21.g240c81d/etc/cinder/rootwrap.d/volume.filters
--- old/cinder-2013.2.2.dev16.g77fade5/etc/cinder/rootwrap.d/volume.filters     
2014-01-29 21:06:39.000000000 +0100
+++ new/cinder-2013.2.2.dev21.g240c81d/etc/cinder/rootwrap.d/volume.filters     
2014-02-02 07:47:48.000000000 +0100
@@ -67,6 +67,7 @@
 
 # cinder/volume/drivers/glusterfs.py
 mv: CommandFilter, mv, root
+chgrp: CommandFilter, chgrp, root
 
 # cinder/volumes/drivers/hds/hds.py:
 hus-cmd: CommandFilter, hus-cmd, root

++++++ openstack-cinder.conf ++++++
d /var/run/openstack-cinder 0700 openstack-cinder openstack-cinder -
++++++ openstack-cinder.logrotate ++++++
--- /var/tmp/diff_new_pack.NtS2Rk/_old  2014-02-11 10:40:19.000000000 +0100
+++ /var/tmp/diff_new_pack.NtS2Rk/_new  2014-02-11 10:40:19.000000000 +0100
@@ -6,7 +6,7 @@
     weekly
     dateext
     missingok
-    notifyempty
+    notifempty
     su openstack-cinder openstack-cinder
     copytruncate
     sharedscripts

-- 
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to