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]
