From 2488c85b5b4a4be509c0d7365dfffd3ba28258a8 Mon Sep 17 00:00:00 2001 From: Sergey Otpuschennikov Date: Mon, 7 Jul 2014 11:33:14 +0400 Subject: [PATCH] Build from master Change-Id: Ib3370c25d038003e75ca06f7f39bc8e518ab0422 --- debian/changelog | 130 +- debian/cinder-common.install | 2 +- debian/cinder-common.postinst | 7 +- debian/cinder-volume.install | 1 - debian/cinder_sudoers | 2 +- debian/control | 73 +- ...-clone-non-raw-images-in-rbd-backend.patch | 496 ------- debian/patches/fix-babel-requirements.patch | 17 - .../patches/fix-sqlalchemy-requirements.patch | 12 - debian/patches/series | 3 - debian/rules | 2 +- ...-t-access-the-net-when-building-docs.patch | 22 - ...time-dep-on-python-pbr-python-d2to1.patch} | 6 +- ...002-Revert-Switch-over-to-oslosphinx.patch | 34 + ...llel-install-versions-of-epel-packag.patch | 96 -- ...sphinx-and-remove-local-copy-of-doc-.patch | 1237 ----------------- ...-clone-non-raw-images-in-rbd-backend.patch | 496 ------- rpm/SOURCES/cinder-dist.conf | 3 +- rpm/SOURCES/cinder-tgt.conf | 6 +- rpm/SOURCES/openstack-cinder-api.upstart | 8 - rpm/SOURCES/openstack-cinder-backup.upstart | 8 - .../openstack-cinder-scheduler.upstart | 8 - rpm/SOURCES/openstack-cinder-volume.upstart | 8 - rpm/SPECS/openstack-cinder.spec | 246 ++-- 24 files changed, 369 insertions(+), 2554 deletions(-) delete mode 100755 debian/patches/MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch delete mode 100644 debian/patches/fix-babel-requirements.patch delete mode 100644 debian/patches/fix-sqlalchemy-requirements.patch delete mode 100644 debian/patches/series delete mode 100644 rpm/SOURCES/0001-Ensure-we-don-t-access-the-net-when-building-docs.patch rename rpm/SOURCES/{0003-Remove-runtime-dep-on-python-pbr-python-d2to1.patch => 0001-Remove-runtime-dep-on-python-pbr-python-d2to1.patch} (90%) create mode 100644 rpm/SOURCES/0002-Revert-Switch-over-to-oslosphinx.patch delete mode 100644 rpm/SOURCES/0002-Use-updated-parallel-install-versions-of-epel-packag.patch delete mode 100644 rpm/SOURCES/0004-Revert-Use-oslo.sphinx-and-remove-local-copy-of-doc-.patch delete mode 100755 rpm/SOURCES/MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch delete mode 100644 rpm/SOURCES/openstack-cinder-api.upstart delete mode 100644 rpm/SOURCES/openstack-cinder-backup.upstart delete mode 100644 rpm/SOURCES/openstack-cinder-scheduler.upstart delete mode 100644 rpm/SOURCES/openstack-cinder-volume.upstart diff --git a/debian/changelog b/debian/changelog index 14d1ad611..584a238fe 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,132 @@ -cinder (1:2013.2-0ubuntu1~cloud0) precise-havana; urgency=low +cinder (1:2014.2~b2-0ubuntu1) utopic; urgency=medium - * New upstream release for the Ubuntu Cloud Archive. + * New upstream release. + * Clean up dependencies: + - debian/control: Dropped python-d2to1, python-hp3parclient, + python-hplefthandclient, python-lockfile, python-amqplib + - debian/control: Add python-oslosphinx, python-requests, + python-hacking, python-oslo.db. + * debian/patches/fix-requirements.patch: Refreshed. + + -- Chuck Short Thu, 24 Jul 2014 13:44:04 -0400 + +cinder (1:2014.2~b1-0ubuntu2) utopic; urgency=medium + + * SECURITY UPDATE: specify /etc/nova/rootwrap.conf for use with + nova-rootwrap + - CVE-2013-1068 (LP: #1185019) + + -- Chuck Short Wed, 18 Jun 2014 11:37:45 -0400 + +cinder (1:2014.2~b1-0ubuntu1) utopic; urgency=medium + + * New upstream release. + * debian/control: Open up juno release + * debian/patches/fix-requirements.patch: Refreshed. + + -- Chuck Short Thu, 12 Jun 2014 10:35:06 -0400 + +cinder (1:2014.1-0ubuntu1) trusty; urgency=medium + + * New upstream release (LP: #1299055). + + -- Corey Bryant Wed, 16 Apr 2014 13:06:37 -0400 + +cinder (1:2014.1~rc3-0ubuntu1) trusty; urgency=medium + + * New release candidate (LP: #1299010). + + -- Chuck Short Tue, 15 Apr 2014 09:02:40 -0400 + +cinder (1:2014.1~rc2-0ubuntu1) trusty; urgency=medium + + * New upstream release (LP: #1299010). + + -- Chuck Short Mon, 07 Apr 2014 11:18:57 -0400 + +cinder (1:2014.1~rc1-0ubuntu1) trusty; urgency=medium + + * New upstream release (LP: #1299010). + * debian/patches/fixup-rbd-str-handling.patch: Dropped no longer needed. + * debian/patches/fix-requirements.patch: Rediffed. + * debian/control: Add python-oslo.messaging. + + -- Chuck Short Fri, 28 Mar 2014 09:48:21 -0400 + +cinder (1:2014.1~b3-0ubuntu3) trusty; urgency=medium + + * d/p/fixup-rbd-str-handling.patch: Cherry pick fix from upstream + Gerrit to resolve issue deleting Ceph volumes and snapshots + (LP: #1292433). + * d/control,rules: Use upstream run_tests.sh wrapper to execute unit tests, + add subunit to BD's to ensure output is correctly formatted. + + -- James Page Fri, 14 Mar 2014 11:19:16 +0000 + +cinder (1:2014.1~b3-0ubuntu2) trusty; urgency=medium + + * d/cinder-common.postinst: Correct use of getent (LP: #1224275). + * d/cinder-common.postinst: Tidy detection of local sqlite database use + for db sync operations (LP: #1290423). + + -- James Page Thu, 13 Mar 2014 10:11:20 +0000 + +cinder (1:2014.1~b3-0ubuntu1) trusty; urgency=medium + + [ Chuck Short ] + * debian/patches/fix-requirements.patch: Refreshed. + * debian/control: Bump python-keystoneclient to 0.4.2. + * debian/patches/skip-tests.patch: Temporarily skip + testlefthand tests since the needed python library hasnt been + packaged yet. + + [ James Page ] + * d/p/fix-requirements.patch: Refreshed. + * d/control,d/p/series/skip-tests.patch: Add BD on python-hplefthandclient, + bump version requirement on python-hp3parclient to >= 3.0.0 and drop + patch that skips hplefthandclient tests. + + [ Corey Bryant ] + * New upstream release. + + -- Corey Bryant Thu, 06 Mar 2014 13:16:02 -0500 + +cinder (1:2014.1~b2-0ubuntu1) trusty; urgency=low + + [ James Page ] + * d/control: Add versioned dependency python-six >= 1.4.1 (LP: #1259203). + * d/p/*: Refreshed. + + [Chuck Short] + * New upstream release. + * debian/control: Add python-taskflow as a dependency. + * debian/control: Add python-oslo.rootwrap as a dependency. + + -- Chuck Short Thu, 23 Jan 2014 12:41:54 -0500 + +cinder (1:2014.1~b1-0ubuntu1) trusty; urgency=low + + [ Chuck Short ] + * New upstream release. + * debian/control: + - Open icehouse release. + - Add python-rtslib as a dependency. + * debian/patches/fix-sqlalchemy-requirements.patch: Dropped no longer needed. + * debian/patches/fix-babel-requirements.patch: Dropped no longer needed. + * debian/paches/fix-requirements.patch: Fixed up requirements.txt for + dependencies we have in Ubuntu. + * debian/cinder-common.install: Add "cinder-rtstool". + + [ James Page ] + * debian/patches/*: Refresh. + + -- Chuck Short Thu, 05 Dec 2013 21:30:40 -0500 + +cinder (1:2013.2-0ubuntu1) saucy; urgency=low + + * New upstream release (LP: #1236462). - -- James Page Wed, 16 Oct 2013 11:27:06 +0100 + -- Chuck Short Thu, 17 Oct 2013 10:00:43 -0400 cinder (1:2013.2~rc3-0ubuntu1) saucy; urgency=low diff --git a/debian/cinder-common.install b/debian/cinder-common.install index 3d068db3d..0269adf17 100644 --- a/debian/cinder-common.install +++ b/debian/cinder-common.install @@ -6,4 +6,4 @@ etc/cinder/policy.json etc/cinder etc/cinder/rootwrap.conf etc/cinder usr/bin/cinder-manage usr/bin/cinder-rootwrap -usr/bin/cinder-rpc-zmq-receiver +usr/bin/cinder-rtstool diff --git a/debian/cinder-common.postinst b/debian/cinder-common.postinst index 3443c56fa..8045dbffb 100644 --- a/debian/cinder-common.postinst +++ b/debian/cinder-common.postinst @@ -1,11 +1,11 @@ #!/bin/sh -e if [ "$1" = "configure" ]; then - if ! getenv group cinder > /dev/null 2>&1; then + if ! getent group cinder > /dev/null 2>&1; then addgroup --system cinder >/dev/null fi - if ! getenv passwd cinder > /dev/null 2>&1; then + if ! getent passwd cinder > /dev/null 2>&1; then adduser --system --home /var/lib/cinder --ingroup cinder --no-create-home \ --shell /bin/false cinder fi @@ -19,7 +19,8 @@ if [ "$1" = "configure" ]; then chmod 0755 /etc/cinder/rootwrap.d chown root:root /etc/cinder/rootwrap.conf - if ! grep -q sql_connection /etc/cinder/cinder.conf + if ! grep -qE "^(sql_)?connection.*" /etc/cinder/cinder.conf || \ + grep -qE "^(sql_)?connection.*sqlite.*" /etc/cinder/cinder.conf then su -s /bin/sh -c 'cinder-manage db sync' cinder fi diff --git a/debian/cinder-volume.install b/debian/cinder-volume.install index 6ae49b0cb..bbaf426b3 100644 --- a/debian/cinder-volume.install +++ b/debian/cinder-volume.install @@ -1,5 +1,4 @@ debian/cinder_tgt.conf etc/tgt/conf.d etc/cinder/rootwrap.d/volume.filters /etc/cinder/rootwrap.d -usr/bin/cinder-clear-rabbit-queues usr/bin/cinder-volume usr/bin/cinder-volume-usage-audit diff --git a/debian/cinder_sudoers b/debian/cinder_sudoers index 73142ab4e..d38575d4d 100644 --- a/debian/cinder_sudoers +++ b/debian/cinder_sudoers @@ -1,3 +1,3 @@ Defaults:cinder !requiretty -cinder ALL = (root) NOPASSWD: /usr/bin/cinder-rootwrap +cinder ALL = (root) NOPASSWD: /usr/bin/cinder-rootwrap /etc/cinder/rootwrap.conf diff --git a/debian/control b/debian/control index 1f20f0fb8..1be8693f3 100644 --- a/debian/control +++ b/debian/control @@ -4,47 +4,52 @@ Priority: extra Maintainer: Chuck Short Build-Depends: debhelper (>= 8.0.0), python-all (>= 2.6) Build-Depends-Indep: - python-amqplib (>= 0.6.1), python-anyjson (>= 0.3.3), - python-babel, + python-babel (>= 1.3), python-coverage, - python-d2to1, python-eventlet (>= 0.13.0), python-fixtures (>= 0.3.14), python-glanceclient (>= 1:0.9.0), python-greenlet (>= 0.3.2), - python-hp3parclient (>= 2.0.0), + python-hacking, python-iso8601, - python-keystoneclient (>= 1:0.3.0), + python-keystoneclient (>= 1:0.4.2), + python-keystonemiddleware (>= 1.0.0), python-kombu (>= 2.5.12), - python-lockfile, python-lxml (>= 2.3), - python-migrate, + python-migrate (>= 0.9.1), python-mock, python-mox, - python-mysqldb, + python-mysqldb , python-netaddr, - python-novaclient (>= 1:2.15.0), - python-oslo.config (>= 1:1.1.0), - python-paramiko (>= 1.8), + python-novaclient (>= 2.17.0), + python-oslo.config (>= 1.2.1), + python-oslo.db, + python-oslo.rootwrap, + python-oslo.messaging, + python-oslosphinx, + python-paramiko (>= 1.13), python-paste, - python-pastedeploy, - python-pbr (>= 0.5.21), + python-pastedeploy (>= 1.5), + python-requests, + python-pbr (>= 0.6), python-pbr (<< 0.7) | python-pbr (>> 0.7), python-pbr (<< 1.0), python-routes, python-setuptools, - python-six, + python-six (>= 1.7.0), python-sphinx, - python-sqlalchemy (>= 0.8.2), - python-stevedore (>= 0.10), + python-sqlalchemy (>= 0.8.4), python-sqlalchemy (<< 0.9.5) | python-sqlalchemy (>> 0.9.5), python-sqlalchemy (<= 0.9.99), + python-stevedore (>= 0.14), python-suds, - python-swiftclient (>= 1:1.5), + python-swiftclient (>= 2.0.2), + python-taskflow, python-testtools (>= 0.9.32), python-webob (>= 1.2.3), + subunit, testrepository (>= 0.0.17) Standards-Version: 3.9.4 Homepage: http://launchpad.net/cinder -Vcs-Browser: http://bazaar.launchpad.net/~ubuntu-server-dev/cinder/havana/files -Vcs-Bzr: https://code.launchpad.net/~ubuntu-server-dev/cinder/havana +Vcs-Browser: http://bazaar.launchpad.net/~ubuntu-server-dev/cinder/juno/files +Vcs-Bzr: https://code.launchpad.net/~ubuntu-server-dev/cinder/juno XS-Testsuite: autopkgtest Package: python-cinder @@ -53,30 +58,32 @@ Architecture: all Depends: python-amqplib (>= 0.6.1), python-anyjson (>= 0.3.3), - python-babel, + python-babel (>= 1.3), python-eventlet (>= 0.13.0), python-glanceclient (>= 1:0.9.0), python-greenlet (>= 0.3.2), - python-importlib, - python-iso8601, + python-iso8601 (>= 0.1.9) , python-keystoneclient (>= 1:0.3.0), + python-keystonemiddleware (>= 1.0.0), python-kombu (>= 2.5.12), python-lockfile, python-lxml (>= 2.3), - python-migrate, - python-mysqldb, - python-netaddr, + python-migrate (>= 0.9.1), + python-netaddr (>= 0.7.6), python-novaclient (>= 1:2.12.0), - python-oslo.config (>= 1:1.1.0), - python-paramiko (>= 1.8), + python-oslo.config (>= 1:1.2.1), + python-oslo.messaging, + python-paramiko (>= 1.13), python-paste, - python-pastedeploy, - python-routes, - python-six, - python-sqlalchemy (>= 0.8.2), - python-stevedore (>= 0.10), + python-pastedeploy (>= 1.5), + python-routes (>= 1.12.3), python-routes (<< 2.0) | python-routes (> 2.0), + python-six (>= 1.7.0), + python-sqlalchemy (>= 0.8.4), python-sqlalchemy (<< 0.9.5) | python-sqlalchemy (>> 0.9.5), python-sqlalchemy (<= 0.9.99), + python-stevedore (>= 0.14), python-suds, - python-swiftclient (>= 1:1.5), + python-swiftclient (>= 2.0.2), + python-taskflow, + python-rtslib-fb (>= 2.1.39), python-webob (>= 1.2.3), ${misc:Depends}, ${python:Depends} diff --git a/debian/patches/MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch b/debian/patches/MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch deleted file mode 100755 index 0b1f0850b..000000000 --- a/debian/patches/MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch +++ /dev/null @@ -1,496 +0,0 @@ -From fd7e9dd59ffa346bed5a11e5312f4bb1bf114ab4 Mon Sep 17 00:00:00 2001 -From: Dmitry Borodaenko -Date: Wed, 27 Nov 2013 14:33:00 -0800 -Subject: [PATCH] Do not clone non-raw images in rbd backend - -RBD backend only supports booting from images in raw format. A volume -that was cloned from an image in any other format is not bootable. The -RBD driver will consider non-raw images to be uncloneable to trigger -automatic conversion to raw format. - -Includes conversion of the corresponding unit test to use mock (instead -of mox) and expanded comments and error messages from patchset #58893 by -Edward Hope-Morley. - -Change-Id: I5725d2f7576bc1b3e9b874ba944ad17d33a6e2cb -Closes-Bug: #1246219 -Closes-Bug: #1247998 ---- - cinder/tests/test_gpfs.py | 6 +- - cinder/tests/test_netapp_nfs.py | 12 +- - cinder/tests/test_rbd.py | 168 +++++++++++++++++--------- - cinder/tests/test_volume.py | 2 +- - cinder/volume/driver.py | 7 +- - cinder/volume/drivers/gpfs.py | 2 +- - cinder/volume/drivers/lvm.py | 2 +- - cinder/volume/drivers/netapp/nfs.py | 2 +- - cinder/volume/drivers/rbd.py | 14 ++- - cinder/volume/drivers/scality.py | 2 +- - cinder/volume/flows/create_volume/__init__.py | 2 +- - 11 files changed, 144 insertions(+), 75 deletions(-) - -diff --git a/cinder/tests/test_gpfs.py b/cinder/tests/test_gpfs.py -index 4fdb788..1f47c6b 100644 ---- a/cinder/tests/test_gpfs.py -+++ b/cinder/tests/test_gpfs.py -@@ -288,7 +288,8 @@ class GPFSDriverTestCase(test.TestCase): - CONF.gpfs_images_share_mode = 'copy_on_write' - self.driver.clone_image(volume, - None, -- self.image_id) -+ self.image_id, -+ {}) - - self.assertTrue(os.path.exists(volumepath)) - self.volume.delete_volume(self.context, volume['id']) -@@ -309,7 +310,8 @@ class GPFSDriverTestCase(test.TestCase): - CONF.gpfs_images_share_mode = 'copy' - self.driver.clone_image(volume, - None, -- self.image_id) -+ self.image_id, -+ {}) - - self.assertTrue(os.path.exists(volumepath)) - self.volume.delete_volume(self.context, volume['id']) -diff --git a/cinder/tests/test_netapp_nfs.py b/cinder/tests/test_netapp_nfs.py -index 950efc8..042280e 100644 ---- a/cinder/tests/test_netapp_nfs.py -+++ b/cinder/tests/test_netapp_nfs.py -@@ -469,7 +469,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - drv._post_clone_image(volume) - - mox.ReplayAll() -- drv. clone_image(volume, ('image_location', None), 'image_id') -+ drv.clone_image(volume, ('image_location', None), 'image_id', {}) - mox.VerifyAll() - - def get_img_info(self, format): -@@ -493,7 +493,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - (prop, cloned) = drv. clone_image( -- volume, ('nfs://127.0.0.1:/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1:/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - if not cloned and not prop['provider_location']: - pass -@@ -529,7 +529,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - drv. clone_image( -- volume, ('nfs://127.0.0.1:/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1:/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - - def test_clone_image_cloneableshare_notraw(self): -@@ -566,7 +566,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - drv. clone_image( -- volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - - def test_clone_image_file_not_discovered(self): -@@ -605,7 +605,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - vol_dict, result = drv. clone_image( -- volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - self.assertFalse(result) - self.assertFalse(vol_dict['bootable']) -@@ -652,7 +652,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - vol_dict, result = drv. clone_image( -- volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - self.assertFalse(result) - self.assertFalse(vol_dict['bootable']) -diff --git a/cinder/tests/test_rbd.py b/cinder/tests/test_rbd.py -index 60de09b..054bbb5 100644 ---- a/cinder/tests/test_rbd.py -+++ b/cinder/tests/test_rbd.py -@@ -34,6 +34,7 @@ from cinder.tests.test_volume import DriverTestCase - from cinder import units - from cinder.volume import configuration as conf - import cinder.volume.drivers.rbd as driver -+from cinder.volume.flows import create_volume - - - LOG = logging.getLogger(__name__) -@@ -247,7 +248,8 @@ class RBDTestCase(test.TestCase): - self.assertRaises(exception.ImageUnacceptable, - self.driver._parse_location, - loc) -- self.assertFalse(self.driver._is_cloneable(loc)) -+ self.assertFalse( -+ self.driver._is_cloneable(loc, {'disk_format': 'raw'})) - - def test_cloneable(self): - self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') -@@ -264,12 +266,14 @@ class RBDTestCase(test.TestCase): - - self.mox.ReplayAll() - -- self.assertTrue(self.driver._is_cloneable(location)) -+ self.assertTrue( -+ self.driver._is_cloneable(location, {'disk_format': 'raw'})) - - def test_uncloneable_different_fsid(self): - self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') - location = 'rbd://def/pool/image/snap' -- self.assertFalse(self.driver._is_cloneable(location)) -+ self.assertFalse( -+ self.driver._is_cloneable(location, {'disk_format': 'raw'})) - - def test_uncloneable_unreadable(self): - self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') -@@ -284,7 +288,16 @@ class RBDTestCase(test.TestCase): - - self.mox.ReplayAll() - -- self.assertFalse(self.driver._is_cloneable(location)) -+ self.assertFalse( -+ self.driver._is_cloneable(location, {'disk_format': 'raw'})) -+ -+ def test_uncloneable_bad_format(self): -+ self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') -+ location = 'rbd://abc/pool/image/snap' -+ formats = ['qcow2', 'vmdk', 'vdi'] -+ for f in formats: -+ self.assertFalse( -+ self.driver._is_cloneable(location, {'disk_format': f})) - - def _copy_image(self): - @contextlib.contextmanager -@@ -504,26 +517,37 @@ class ManagedRBDTestCase(DriverTestCase): - super(ManagedRBDTestCase, self).setUp() - fake_image.stub_out_image_service(self.stubs) - self.volume.driver.set_initialized() -+ self.called = [] - -- def _clone_volume_from_image(self, expected_status, -- clone_works=True): -+ def _create_volume_from_image(self, expected_status, raw=False, -+ clone_error=False): - """Try to clone a volume from an image, and check the status - afterwards. -+ -+ NOTE: if clone_error is True we force the image type to raw otherwise -+ clone_image is not called - """ -- def fake_clone_image(volume, image_location, image_id): -- return {'provider_location': None}, True -+ def mock_clone_image(volume, image_location, image_id, image_meta): -+ self.called.append('clone_image') -+ if clone_error: -+ raise exception.CinderException() -+ else: -+ return {'provider_location': None}, True - -- def fake_clone_error(volume, image_location, image_id): -- raise exception.CinderException() -+ if clone_error: -+ raw = True - -- self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True) -- if clone_works: -- self.stubs.Set(self.volume.driver, 'clone_image', fake_clone_image) -+ # See tests.image.fake for image types. -+ if raw: -+ expected_calls = ['clone_image'] -+ image_id = '155d900f-4e14-4e4c-a73d-069cbf4541e6' - else: -- self.stubs.Set(self.volume.driver, 'clone_image', fake_clone_error) -+ expected_calls = ['clone_image', 'create_volume', -+ 'copy_image_to_volume'] -+ image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77' - -- image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77' - volume_id = 1 -+ - # creating volume testdata - db.volume_create(self.context, - {'id': volume_id, -@@ -533,58 +557,88 @@ class ManagedRBDTestCase(DriverTestCase): - 'status': 'creating', - 'instance_uuid': None, - 'host': 'dummy'}) -- try: -- if clone_works: -- self.volume.create_volume(self.context, -- volume_id, -- image_id=image_id) -- else: -- self.assertRaises(exception.CinderException, -- self.volume.create_volume, -- self.context, -- volume_id, -- image_id=image_id) -- -- volume = db.volume_get(self.context, volume_id) -- self.assertEqual(volume['status'], expected_status) -- finally: -- # cleanup -- db.volume_destroy(self.context, volume_id) -+ -+ with mock.patch.object(self.volume.driver, 'create_volume') as \ -+ mock_create_volume: -+ with mock.patch.object(self.volume.driver, 'clone_image', -+ mock_clone_image): -+ with mock.patch.object(create_volume.CreateVolumeFromSpecTask, -+ '_copy_image_to_volume') as \ -+ mock_copy_image_to_volume: -+ self.volume.driver._is_cloneable = mock.Mock() -+ self.volume.driver._is_cloneable.return_value = True -+ -+ try: -+ if not clone_error: -+ self.volume.create_volume(self.context, -+ volume_id, -+ image_id=image_id) -+ else: -+ self.assertRaises(exception.CinderException, -+ self.volume.create_volume, -+ self.context, -+ volume_id, -+ image_id=image_id) -+ -+ volume = db.volume_get(self.context, volume_id) -+ self.assertEqual(volume['status'], expected_status) -+ finally: -+ # cleanup -+ db.volume_destroy(self.context, volume_id) -+ -+ if raw: -+ self.assertEquals(self.called, ['clone_image']) -+ -+ mock_create_volume.assert_called() -+ mock_copy_image_to_volume.assert_called() - - def test_create_vol_from_image_status_available(self): -- """Verify that before cloning, an image is in the available state.""" -- self._clone_volume_from_image('available', True) -+ """Clone raw image then verify volume is in available state.""" -+ self._create_volume_from_image('available', raw=True) -+ -+ def test_create_vol_from_non_raw_image_status_available(self): -+ """Clone non-raw image then verify volume is in available state.""" -+ self._create_volume_from_image('available', raw=False) - - def test_create_vol_from_image_status_error(self): -- """Verify that before cloning, an image is in the available state.""" -- self._clone_volume_from_image('error', False) -+ """Clone raw image with failure then verify volume is in error -+ state. -+ """ -+ self._create_volume_from_image('error', raw=True, clone_error=True) - - def test_clone_image(self): -- # Test Failure Case(s) -- expected = ({}, False) -+ driver = self.volume.driver - -- self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: False) -- image_loc = (object(), object()) -- actual = self.volume.driver.clone_image(object(), image_loc, object()) -- self.assertEqual(expected, actual) -+ # Test uncloneable case(s) -+ with mock.patch.object(driver, '_is_cloneable', -+ lambda *args: False) as mock_is_cloneable: -+ image_loc = (mock.Mock(), mock.Mock()) -+ actual = driver.clone_image(mock.Mock(), image_loc, -+ mock.Mock(), {}) -+ self.assertEqual(({}, False), actual) - -- self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True) -- self.assertEqual(expected, -- self.volume.driver.clone_image(object(), None, None)) -+ self.assertEqual(({}, False), -+ driver.clone_image(object(), None, None, {})) - -- # Test Success Case(s) -+ # Test success case(s) - expected = ({'provider_location': None}, True) -- -- self.stubs.Set(self.volume.driver, '_parse_location', -- lambda x: ('a', 'b', 'c', 'd')) -- -- self.stubs.Set(self.volume.driver, '_clone', lambda *args: None) -- self.stubs.Set(self.volume.driver, '_resize', lambda *args: None) -- actual = self.volume.driver.clone_image(object(), image_loc, object()) -- self.assertEqual(expected, actual) -+ mpo = mock.patch.object -+ with mpo(driver, '_is_cloneable', lambda *args: True): -+ with mpo(driver, '_parse_location', -+ lambda x: ('a', 'b', 'c', 'd')): -+ with mpo(driver, '_clone') as mock_clone: -+ with mpo(driver, '_resize') as mock_resize: -+ actual = driver.clone_image(mock.Mock(), image_loc, -+ mock.Mock(), -+ {'disk_format': 'raw'}) -+ self.assertEqual(expected, actual) -+ mock_clone.assert_called() -+ mock_resize.assert_called() - - def test_clone_success(self): -- self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True) -- self.stubs.Set(self.volume.driver, 'clone_image', lambda a, b, c: True) -+ self.stubs.Set(self.volume.driver, '_is_cloneable', lambda *args: True) -+ self.stubs.Set(self.volume.driver, 'clone_image', -+ lambda a, b, c, d: True) - image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77' -- self.assertTrue(self.volume.driver.clone_image({}, image_id, image_id)) -+ self.assertTrue(self.volume.driver.clone_image({}, -+ image_id, image_id, {})) -diff --git a/cinder/tests/test_volume.py b/cinder/tests/test_volume.py -index 4a0d475..928799f 100644 ---- a/cinder/tests/test_volume.py -+++ b/cinder/tests/test_volume.py -@@ -1216,7 +1216,7 @@ class VolumeTestCase(BaseVolumeTestCase): - def fake_fetch_to_raw(ctx, image_service, image_id, path, size=None): - pass - -- def fake_clone_image(volume_ref, image_location, image_id): -+ def fake_clone_image(volume_ref, image_location, image_id, image_meta): - return {'provider_location': None}, True - - dst_fd, dst_path = tempfile.mkstemp() -diff --git a/cinder/volume/driver.py b/cinder/volume/driver.py -index 21dd12b..dd2be3c 100644 ---- a/cinder/volume/driver.py -+++ b/cinder/volume/driver.py -@@ -396,7 +396,7 @@ class VolumeDriver(object): - connector.disconnect_volume(attach_info['conn']['data'], - attach_info['device']) - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - """Create a volume efficiently from an existing image. - - image_location is a string whose format depends on the -@@ -407,6 +407,11 @@ class VolumeDriver(object): - It can be used by the driver to introspect internal - stores or registry to do an efficient image clone. - -+ image_meta is a dictionary that includes 'disk_format' (e.g. -+ raw, qcow2) and other image attributes that allow drivers to -+ decide whether they can clone the image without first requiring -+ conversion. -+ - Returns a dict of volume properties eg. provider_location, - boolean indicating whether cloning occurred - """ -diff --git a/cinder/volume/drivers/gpfs.py b/cinder/volume/drivers/gpfs.py -index 9a1a397..8792ad8 100644 ---- a/cinder/volume/drivers/gpfs.py -+++ b/cinder/volume/drivers/gpfs.py -@@ -463,7 +463,7 @@ class GPFSDriver(driver.VolumeDriver): - return '100M' - return '%sG' % size_in_g - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - return self._clone_image(volume, image_location, image_id) - - def _is_cloneable(self, image_id): -diff --git a/cinder/volume/drivers/lvm.py b/cinder/volume/drivers/lvm.py -index 094436f..c6023eb 100644 ---- a/cinder/volume/drivers/lvm.py -+++ b/cinder/volume/drivers/lvm.py -@@ -322,7 +322,7 @@ class LVMVolumeDriver(driver.VolumeDriver): - finally: - self.delete_snapshot(temp_snapshot) - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - return None, False - - def backup_volume(self, context, backup, backup_service): -diff --git a/cinder/volume/drivers/netapp/nfs.py b/cinder/volume/drivers/netapp/nfs.py -index 602a1dc..9463137 100644 ---- a/cinder/volume/drivers/netapp/nfs.py -+++ b/cinder/volume/drivers/netapp/nfs.py -@@ -374,7 +374,7 @@ class NetAppNFSDriver(nfs.NfsDriver): - LOG.warning(_('Exception during deleting %s'), ex.__str__()) - return False - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - """Create a volume efficiently from an existing image. - - image_location is a string whose format depends on the -diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py -index 775ab16..7ed59d0 100644 ---- a/cinder/volume/drivers/rbd.py -+++ b/cinder/volume/drivers/rbd.py -@@ -706,7 +706,7 @@ class RBDDriver(driver.VolumeDriver): - with RADOSClient(self) as client: - return client.cluster.get_fsid() - -- def _is_cloneable(self, image_location): -+ def _is_cloneable(self, image_location, image_meta): - try: - fsid, pool, image, snapshot = self._parse_location(image_location) - except exception.ImageUnacceptable as e: -@@ -718,6 +718,13 @@ class RBDDriver(driver.VolumeDriver): - LOG.debug(reason) - return False - -+ if image_meta['disk_format'] != 'raw': -+ reason = _("rbd image clone requires image format to be " -+ "'raw' but image {0} is '{1}'").format( -+ image_location, image_meta['disk_format']) -+ LOG.debug(reason) -+ return False -+ - # check that we can read the image - try: - with RBDVolumeProxy(self, image, -@@ -730,9 +737,10 @@ class RBDDriver(driver.VolumeDriver): - dict(loc=image_location, err=e)) - return False - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - image_location = image_location[0] if image_location else None -- if image_location is None or not self._is_cloneable(image_location): -+ if image_location is None or not self._is_cloneable( -+ image_location, image_meta): - return ({}, False) - prefix, pool, image, snapshot = self._parse_location(image_location) - self._clone(volume, pool, image, snapshot) -diff --git a/cinder/volume/drivers/scality.py b/cinder/volume/drivers/scality.py -index 4cf49c6..abd6c29 100644 ---- a/cinder/volume/drivers/scality.py -+++ b/cinder/volume/drivers/scality.py -@@ -250,7 +250,7 @@ class ScalityDriver(driver.VolumeDriver): - image_meta, - self.local_path(volume)) - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - """Create a volume efficiently from an existing image. - - image_location is a string whose format depends on the -diff --git a/cinder/volume/flows/create_volume/__init__.py b/cinder/volume/flows/create_volume/__init__.py -index bb7acd3..e5aa371 100644 ---- a/cinder/volume/flows/create_volume/__init__.py -+++ b/cinder/volume/flows/create_volume/__init__.py -@@ -1438,7 +1438,7 @@ class CreateVolumeFromSpecTask(base.CinderTask): - # dict containing provider_location for cloned volume - # and clone status. - model_update, cloned = self.driver.clone_image( -- volume_ref, image_location, image_id) -+ volume_ref, image_location, image_id, image_meta) - if not cloned: - # TODO(harlowja): what needs to be rolled back in the clone if this - # volume create fails?? Likely this should be a subflow or broken --- -1.8.5.1 - diff --git a/debian/patches/fix-babel-requirements.patch b/debian/patches/fix-babel-requirements.patch deleted file mode 100644 index 675cc9067..000000000 --- a/debian/patches/fix-babel-requirements.patch +++ /dev/null @@ -1,17 +0,0 @@ -Author: Revert new babel requirements. -Author: Chuck Short -Forwarded: No, https://review.openstack.org/#/c/48739/ -diff --git a/requirements.txt b/requirements.txt -index 219962d..01ec2e6 100644 ---- a/requirements.txt -+++ b/requirements.txt -@@ -2,7 +2,7 @@ pbr>=0.5.21,<1.0 - amqplib>=0.6.1 - anyjson>=0.3.3 - argparse --Babel>=1.3 -+Babel>=0.9.6 - eventlet>=0.13.0 - greenlet>=0.3.2 - iso8601>=0.1.8 - diff --git a/debian/patches/fix-sqlalchemy-requirements.patch b/debian/patches/fix-sqlalchemy-requirements.patch deleted file mode 100644 index c4217c67b..000000000 --- a/debian/patches/fix-sqlalchemy-requirements.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Naurp cinder-2013.2.rc1.orig/requirements.txt cinder-2013.2.rc1/requirements.txt ---- cinder-2013.2.rc1.orig/requirements.txt 2013-10-04 05:11:50.000000000 -0400 -+++ cinder-2013.2.rc1/requirements.txt 2013-10-04 08:33:32.072164528 -0400 -@@ -20,7 +20,7 @@ python-novaclient>=2.15.0 - python-swiftclient>=1.5 - Routes>=1.12.3 - six>=1.4.1 --SQLAlchemy>=0.7.8,<=0.7.99 -+SQLAlchemy>=0.7.8,<=0.8.99 - sqlalchemy-migrate>=0.7.2 - stevedore>=0.10 - suds>=0.4 diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index be203b8c7..000000000 --- a/debian/patches/series +++ /dev/null @@ -1,3 +0,0 @@ -fix-sqlalchemy-requirements.patch -fix-babel-requirements.patch -MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch diff --git a/debian/rules b/debian/rules index d4ef58857..f38a7dc14 100755 --- a/debian/rules +++ b/debian/rules @@ -11,7 +11,7 @@ get-orig-source: ifeq (,$(findstring nocheck, $(DEB_BUILD_OPTIONS))) override_dh_auto_test: - testr init && testr run + ./run_tests.sh -N -P endif override_dh_install: diff --git a/rpm/SOURCES/0001-Ensure-we-don-t-access-the-net-when-building-docs.patch b/rpm/SOURCES/0001-Ensure-we-don-t-access-the-net-when-building-docs.patch deleted file mode 100644 index 865d8afeb..000000000 --- a/rpm/SOURCES/0001-Ensure-we-don-t-access-the-net-when-building-docs.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 9904118c6d3d130624eaec31878649e41efd1bc2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?P=C3=A1draig=20Brady?= -Date: Fri, 21 Sep 2012 13:33:26 +0100 -Subject: [PATCH] Ensure we don't access the net when building docs - -(Note, this has not been sent upstream) ---- - doc/source/conf.py | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/doc/source/conf.py b/doc/source/conf.py -index e27d458..7a2bf1a 100644 ---- a/doc/source/conf.py -+++ b/doc/source/conf.py -@@ -29,7 +29,6 @@ sys.path.insert(0, os.path.abspath('./')) - # or your custom ones. - - extensions = ['sphinx.ext.autodoc', -- 'sphinx.ext.intersphinx', - 'ext.cinder_todo', - 'sphinx.ext.coverage', - 'sphinx.ext.pngmath', diff --git a/rpm/SOURCES/0003-Remove-runtime-dep-on-python-pbr-python-d2to1.patch b/rpm/SOURCES/0001-Remove-runtime-dep-on-python-pbr-python-d2to1.patch similarity index 90% rename from rpm/SOURCES/0003-Remove-runtime-dep-on-python-pbr-python-d2to1.patch rename to rpm/SOURCES/0001-Remove-runtime-dep-on-python-pbr-python-d2to1.patch index 5fd94c95b..a056afbd2 100644 --- a/rpm/SOURCES/0003-Remove-runtime-dep-on-python-pbr-python-d2to1.patch +++ b/rpm/SOURCES/0001-Remove-runtime-dep-on-python-pbr-python-d2to1.patch @@ -1,4 +1,4 @@ -From 6ed6db76f6e6b1a579d07c3db63283d444385c14 Mon Sep 17 00:00:00 2001 +From 302c285b0193bcae47aaaaec49f51340b4fbe6e7 Mon Sep 17 00:00:00 2001 From: Eric Harney Date: Thu, 13 Jun 2013 17:50:12 -0400 Subject: [PATCH] Remove runtime dep on python-pbr, python-d2to1 @@ -9,10 +9,10 @@ Requires RPM spec to fill in REDHATCINDERVERSION. 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/cinder/version.py b/cinder/version.py -index ad1ebc0..b4f6fd8 100644 +index e3dbd70..ab8f888 100644 --- a/cinder/version.py +++ b/cinder/version.py -@@ -14,12 +14,22 @@ +@@ -12,12 +12,22 @@ # License for the specific language governing permissions and limitations # under the License. diff --git a/rpm/SOURCES/0002-Revert-Switch-over-to-oslosphinx.patch b/rpm/SOURCES/0002-Revert-Switch-over-to-oslosphinx.patch new file mode 100644 index 000000000..f4437c125 --- /dev/null +++ b/rpm/SOURCES/0002-Revert-Switch-over-to-oslosphinx.patch @@ -0,0 +1,34 @@ +From 15cc208adf811d9a83e8f820fb4be775c5db9a00 Mon Sep 17 00:00:00 2001 +From: Eric Harney +Date: Thu, 27 Mar 2014 14:24:57 -0400 +Subject: [PATCH] Revert "Switch over to oslosphinx" + +This reverts commit ea7d4a599224b5d0c7674d03993bbe72c49f0d51. +--- + doc/source/conf.py | 2 +- + test-requirements.txt | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/doc/source/conf.py b/doc/source/conf.py +index ac2eadc..238a922 100644 +--- a/doc/source/conf.py ++++ b/doc/source/conf.py +@@ -34,7 +34,7 @@ extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.pngmath', + 'sphinx.ext.ifconfig', + 'sphinx.ext.graphviz', +- 'oslosphinx', ++ 'oslo.sphinx', + ] + + # autodoc generation is a bit aggressive and a nuisance +diff --git a/test-requirements.txt b/test-requirements.txt +index 56746da..15308b9 100644 +--- a/test-requirements.txt ++++ b/test-requirements.txt +@@ -13,4 +13,4 @@ sphinx>=1.1.2,<1.2 + python-subunit>=0.0.18 + testtools>=0.9.34 + testrepository>=0.0.18 +-oslosphinx ++oslo.sphinx diff --git a/rpm/SOURCES/0002-Use-updated-parallel-install-versions-of-epel-packag.patch b/rpm/SOURCES/0002-Use-updated-parallel-install-versions-of-epel-packag.patch deleted file mode 100644 index 6f2d7415e..000000000 --- a/rpm/SOURCES/0002-Use-updated-parallel-install-versions-of-epel-packag.patch +++ /dev/null @@ -1,96 +0,0 @@ -From c8b9384ccf0e9c69f35978f3abbb5e5d5638d859 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?P=C3=A1draig=20Brady?= -Date: Wed, 24 Oct 2012 13:44:37 +0100 -Subject: [PATCH] Use updated parallel install versions of epel package - -Use sqlalchemy >= 0.6.3 WebOb >= 1.2 Routes >= 1.12.3 PasteDeploy >= 1.5.0 -and depend on the parallel installable -versions of these packages to satisfy those requirements. - -Delve into pkg_resources a little to get it to modify sys.path, -so that our parallel installed egg takes precedence over the -system default module versions. ---- - bin/cinder-manage | 4 +++- - cinder/__init__.py | 30 ++++++++++++++++++++++++++++++ - cinder/db/sqlalchemy/migration.py | 7 ++++++- - 3 files changed, 39 insertions(+), 2 deletions(-) - -diff --git a/bin/cinder-manage b/bin/cinder-manage -index 3c05d77..9474e2e 100755 ---- a/bin/cinder-manage -+++ b/bin/cinder-manage -@@ -62,7 +62,6 @@ import sys - - from oslo.config import cfg - -- - # If ../cinder/__init__.py exists, add ../ to Python search path, so that - # it will override what happens to be installed in /usr/(local/)lib/python... - POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), -@@ -84,6 +83,9 @@ from cinder.openstack.common import uuidutils - from cinder import utils - from cinder import version - -+from sqlalchemy import create_engine, MetaData, Table -+from sqlalchemy.ext.declarative import declarative_base -+from sqlalchemy.orm import sessionmaker - - CONF = cfg.CONF - -diff --git a/cinder/__init__.py b/cinder/__init__.py -index d765b08..720320e 100644 ---- a/cinder/__init__.py -+++ b/cinder/__init__.py -@@ -30,3 +30,33 @@ - .. moduleauthor:: Manish Singh - .. moduleauthor:: Andy Smith - """ -+ -+import sys -+import pkg_resources -+ -+# If there is a conflicting non egg module, -+# i.e. an older standard system module installed, -+# then replace it with this requirement -+def replace_dist(requirement): -+ try: -+ return pkg_resources.require(requirement) -+ except pkg_resources.VersionConflict: -+ e = sys.exc_info()[1] -+ dist=e.args[0] -+ req=e.args[1] -+ if dist.key == req.key and not dist.location.endswith('.egg'): -+ del pkg_resources.working_set.by_key[dist.key] -+ # We assume there is no need to adjust sys.path -+ # and the associated pkg_resources.working_set.entries -+ return pkg_resources.require(requirement) -+ -+replace_dist("WebOb >= 1.2") -+replace_dist("SQLAlchemy >= 0.6.3") -+replace_dist("Routes >= 1.12.3") -+ -+replace_dist("PasteDeploy >= 1.5.0") -+# This hack is needed because replace_dist() results in -+# the standard paste module path being at the start of __path__. -+# TODO: See can we get pkg_resources to do the right thing directly -+import paste -+paste.__path__.insert(0, paste.__path__.pop(-1)) -diff --git a/cinder/db/sqlalchemy/migration.py b/cinder/db/sqlalchemy/migration.py -index e2463bc..9ba7b73 100644 ---- a/cinder/db/sqlalchemy/migration.py -+++ b/cinder/db/sqlalchemy/migration.py -@@ -56,7 +56,12 @@ if (not hasattr(migrate, '__version__') or - - - # NOTE(jkoelker) Delay importing migrate until we are patched --from migrate import exceptions as versioning_exceptions -+try: -+ # Try the more specific path first (migrate <= 0.6) -+ from migrate.versioning import exceptions as versioning_exceptions -+except ImportError: -+ # Use the newer path (migrate >= 0.7) -+ from migrate import exceptions as versioning_exceptions - from migrate.versioning import api as versioning_api - from migrate.versioning.repository import Repository - diff --git a/rpm/SOURCES/0004-Revert-Use-oslo.sphinx-and-remove-local-copy-of-doc-.patch b/rpm/SOURCES/0004-Revert-Use-oslo.sphinx-and-remove-local-copy-of-doc-.patch deleted file mode 100644 index f9609a750..000000000 --- a/rpm/SOURCES/0004-Revert-Use-oslo.sphinx-and-remove-local-copy-of-doc-.patch +++ /dev/null @@ -1,1237 +0,0 @@ -From bd1bfd86fbeacd893ff5d9abb969c7b0c994fbf4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?P=C3=A1draig=20Brady?= -Date: Mon, 22 Jul 2013 03:14:27 +0100 -Subject: [PATCH] Revert "Use oslo.sphinx and remove local copy of doc theme" - -This reverts commit 8b1ae18ba95f04fedc04592b419401d75d448543. - -Conflicts: - - test-requirements.txt ---- - doc/source/_static/.gitignore | 0 - doc/source/_static/.placeholder | 0 - doc/source/_static/basic.css | 416 +++++++++++++++++++++++++++++++++++++ - doc/source/_static/default.css | 230 ++++++++++++++++++++ - doc/source/_static/jquery.tweet.js | 154 ++++++++++++++ - doc/source/_static/tweaks.css | 218 +++++++++++++++++++ - doc/source/_templates/.gitignore | 0 - doc/source/_templates/.placeholder | 0 - doc/source/_theme/layout.html | 95 +++++++++ - doc/source/_theme/theme.conf | 5 + - doc/source/conf.py | 8 +- - test-requirements.txt | 1 - - 12 files changed, 1121 insertions(+), 6 deletions(-) - create mode 100644 doc/source/_static/.gitignore - create mode 100644 doc/source/_static/.placeholder - create mode 100644 doc/source/_static/basic.css - create mode 100644 doc/source/_static/default.css - create mode 100644 doc/source/_static/jquery.tweet.js - create mode 100644 doc/source/_static/tweaks.css - create mode 100644 doc/source/_templates/.gitignore - create mode 100644 doc/source/_templates/.placeholder - create mode 100644 doc/source/_theme/layout.html - create mode 100644 doc/source/_theme/theme.conf - -diff --git a/doc/source/_static/.gitignore b/doc/source/_static/.gitignore -new file mode 100644 -index 0000000..e69de29 -diff --git a/doc/source/_static/.placeholder b/doc/source/_static/.placeholder -new file mode 100644 -index 0000000..e69de29 -diff --git a/doc/source/_static/basic.css b/doc/source/_static/basic.css -new file mode 100644 -index 0000000..d909ce3 ---- /dev/null -+++ b/doc/source/_static/basic.css -@@ -0,0 +1,416 @@ -+/** -+ * Sphinx stylesheet -- basic theme -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ */ -+ -+/* -- main layout ----------------------------------------------------------- */ -+ -+div.clearer { -+ clear: both; -+} -+ -+/* -- relbar ---------------------------------------------------------------- */ -+ -+div.related { -+ width: 100%; -+ font-size: 90%; -+} -+ -+div.related h3 { -+ display: none; -+} -+ -+div.related ul { -+ margin: 0; -+ padding: 0 0 0 10px; -+ list-style: none; -+} -+ -+div.related li { -+ display: inline; -+} -+ -+div.related li.right { -+ float: right; -+ margin-right: 5px; -+} -+ -+/* -- sidebar --------------------------------------------------------------- */ -+ -+div.sphinxsidebarwrapper { -+ padding: 10px 5px 0 10px; -+} -+ -+div.sphinxsidebar { -+ float: left; -+ width: 230px; -+ margin-left: -100%; -+ font-size: 90%; -+} -+ -+div.sphinxsidebar ul { -+ list-style: none; -+} -+ -+div.sphinxsidebar ul ul, -+div.sphinxsidebar ul.want-points { -+ margin-left: 20px; -+ list-style: square; -+} -+ -+div.sphinxsidebar ul ul { -+ margin-top: 0; -+ margin-bottom: 0; -+} -+ -+div.sphinxsidebar form { -+ margin-top: 10px; -+} -+ -+div.sphinxsidebar input { -+ border: 1px solid #98dbcc; -+ font-family: sans-serif; -+ font-size: 1em; -+} -+ -+img { -+ border: 0; -+} -+ -+/* -- search page ----------------------------------------------------------- */ -+ -+ul.search { -+ margin: 10px 0 0 20px; -+ padding: 0; -+} -+ -+ul.search li { -+ padding: 5px 0 5px 20px; -+ background-image: url(file.png); -+ background-repeat: no-repeat; -+ background-position: 0 7px; -+} -+ -+ul.search li a { -+ font-weight: bold; -+} -+ -+ul.search li div.context { -+ color: #888; -+ margin: 2px 0 0 30px; -+ text-align: left; -+} -+ -+ul.keywordmatches li.goodmatch a { -+ font-weight: bold; -+} -+ -+/* -- index page ------------------------------------------------------------ */ -+ -+table.contentstable { -+ width: 90%; -+} -+ -+table.contentstable p.biglink { -+ line-height: 150%; -+} -+ -+a.biglink { -+ font-size: 1.3em; -+} -+ -+span.linkdescr { -+ font-style: italic; -+ padding-top: 5px; -+ font-size: 90%; -+} -+ -+/* -- general index --------------------------------------------------------- */ -+ -+table.indextable td { -+ text-align: left; -+ vertical-align: top; -+} -+ -+table.indextable dl, table.indextable dd { -+ margin-top: 0; -+ margin-bottom: 0; -+} -+ -+table.indextable tr.pcap { -+ height: 10px; -+} -+ -+table.indextable tr.cap { -+ margin-top: 10px; -+ background-color: #f2f2f2; -+} -+ -+img.toggler { -+ margin-right: 3px; -+ margin-top: 3px; -+ cursor: pointer; -+} -+ -+/* -- general body styles --------------------------------------------------- */ -+ -+a.headerlink { -+ visibility: hidden; -+} -+ -+h1:hover > a.headerlink, -+h2:hover > a.headerlink, -+h3:hover > a.headerlink, -+h4:hover > a.headerlink, -+h5:hover > a.headerlink, -+h6:hover > a.headerlink, -+dt:hover > a.headerlink { -+ visibility: visible; -+} -+ -+div.body p.caption { -+ text-align: inherit; -+} -+ -+div.body td { -+ text-align: left; -+} -+ -+.field-list ul { -+ padding-left: 1em; -+} -+ -+.first { -+} -+ -+p.rubric { -+ margin-top: 30px; -+ font-weight: bold; -+} -+ -+/* -- sidebars -------------------------------------------------------------- */ -+ -+div.sidebar { -+ margin: 0 0 0.5em 1em; -+ border: 1px solid #ddb; -+ padding: 7px 7px 0 7px; -+ background-color: #ffe; -+ width: 40%; -+ float: right; -+} -+ -+p.sidebar-title { -+ font-weight: bold; -+} -+ -+/* -- topics ---------------------------------------------------------------- */ -+ -+div.topic { -+ border: 1px solid #ccc; -+ padding: 7px 7px 0 7px; -+ margin: 10px 0 10px 0; -+} -+ -+p.topic-title { -+ font-size: 1.1em; -+ font-weight: bold; -+ margin-top: 10px; -+} -+ -+/* -- admonitions ----------------------------------------------------------- */ -+ -+div.admonition { -+ margin-top: 10px; -+ margin-bottom: 10px; -+ padding: 7px; -+} -+ -+div.admonition dt { -+ font-weight: bold; -+} -+ -+div.admonition dl { -+ margin-bottom: 0; -+} -+ -+p.admonition-title { -+ margin: 0px 10px 5px 0px; -+ font-weight: bold; -+} -+ -+div.body p.centered { -+ text-align: center; -+ margin-top: 25px; -+} -+ -+/* -- tables ---------------------------------------------------------------- */ -+ -+table.docutils { -+ border: 0; -+ border-collapse: collapse; -+} -+ -+table.docutils td, table.docutils th { -+ padding: 1px 8px 1px 0; -+ border-top: 0; -+ border-left: 0; -+ border-right: 0; -+ border-bottom: 1px solid #aaa; -+} -+ -+table.field-list td, table.field-list th { -+ border: 0 !important; -+} -+ -+table.footnote td, table.footnote th { -+ border: 0 !important; -+} -+ -+th { -+ text-align: left; -+ padding-right: 5px; -+} -+ -+/* -- other body styles ----------------------------------------------------- */ -+ -+dl { -+ margin-bottom: 15px; -+} -+ -+dd p { -+ margin-top: 0px; -+} -+ -+dd ul, dd table { -+ margin-bottom: 10px; -+} -+ -+dd { -+ margin-top: 3px; -+ margin-bottom: 10px; -+ margin-left: 30px; -+} -+ -+dt:target, .highlight { -+ background-color: #fbe54e; -+} -+ -+dl.glossary dt { -+ font-weight: bold; -+ font-size: 1.1em; -+} -+ -+.field-list ul { -+ margin: 0; -+ padding-left: 1em; -+} -+ -+.field-list p { -+ margin: 0; -+} -+ -+.refcount { -+ color: #060; -+} -+ -+.optional { -+ font-size: 1.3em; -+} -+ -+.versionmodified { -+ font-style: italic; -+} -+ -+.system-message { -+ background-color: #fda; -+ padding: 5px; -+ border: 3px solid red; -+} -+ -+.footnote:target { -+ background-color: #ffa -+} -+ -+.line-block { -+ display: block; -+ margin-top: 1em; -+ margin-bottom: 1em; -+} -+ -+.line-block .line-block { -+ margin-top: 0; -+ margin-bottom: 0; -+ margin-left: 1.5em; -+} -+ -+/* -- code displays --------------------------------------------------------- */ -+ -+pre { -+ overflow: auto; -+} -+ -+td.linenos pre { -+ padding: 5px 0px; -+ border: 0; -+ background-color: transparent; -+ color: #aaa; -+} -+ -+table.highlighttable { -+ margin-left: 0.5em; -+} -+ -+table.highlighttable td { -+ padding: 0 0.5em 0 0.5em; -+} -+ -+tt.descname { -+ background-color: transparent; -+ font-weight: bold; -+ font-size: 1.2em; -+} -+ -+tt.descclassname { -+ background-color: transparent; -+} -+ -+tt.xref, a tt { -+ background-color: transparent; -+ font-weight: bold; -+} -+ -+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { -+ background-color: transparent; -+} -+ -+/* -- math display ---------------------------------------------------------- */ -+ -+img.math { -+ vertical-align: middle; -+} -+ -+div.body div.math p { -+ text-align: center; -+} -+ -+span.eqno { -+ float: right; -+} -+ -+/* -- printout stylesheet --------------------------------------------------- */ -+ -+@media print { -+ div.document, -+ div.documentwrapper, -+ div.bodywrapper { -+ margin: 0 !important; -+ width: 100%; -+ } -+ -+ div.sphinxsidebar, -+ div.related, -+ div.footer, -+ #top-link { -+ display: none; -+ } -+} -diff --git a/doc/source/_static/default.css b/doc/source/_static/default.css -new file mode 100644 -index 0000000..c8091ec ---- /dev/null -+++ b/doc/source/_static/default.css -@@ -0,0 +1,230 @@ -+/** -+ * Sphinx stylesheet -- default theme -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ */ -+ -+@import url("basic.css"); -+ -+/* -- page layout ----------------------------------------------------------- */ -+ -+body { -+ font-family: sans-serif; -+ font-size: 100%; -+ background-color: #11303d; -+ color: #000; -+ margin: 0; -+ padding: 0; -+} -+ -+div.document { -+ background-color: #1c4e63; -+} -+ -+div.documentwrapper { -+ float: left; -+ width: 100%; -+} -+ -+div.bodywrapper { -+ margin: 0 0 0 230px; -+} -+ -+div.body { -+ background-color: #ffffff; -+ color: #000000; -+ padding: 0 20px 30px 20px; -+} -+ -+div.footer { -+ color: #ffffff; -+ width: 100%; -+ padding: 9px 0 9px 0; -+ text-align: center; -+ font-size: 75%; -+} -+ -+div.footer a { -+ color: #ffffff; -+ text-decoration: underline; -+} -+ -+div.related { -+ background-color: #133f52; -+ line-height: 30px; -+ color: #ffffff; -+} -+ -+div.related a { -+ color: #ffffff; -+} -+ -+div.sphinxsidebar { -+} -+ -+div.sphinxsidebar h3 { -+ font-family: 'Trebuchet MS', sans-serif; -+ color: #ffffff; -+ font-size: 1.4em; -+ font-weight: normal; -+ margin: 0; -+ padding: 0; -+} -+ -+div.sphinxsidebar h3 a { -+ color: #ffffff; -+} -+ -+div.sphinxsidebar h4 { -+ font-family: 'Trebuchet MS', sans-serif; -+ color: #ffffff; -+ font-size: 1.3em; -+ font-weight: normal; -+ margin: 5px 0 0 0; -+ padding: 0; -+} -+ -+div.sphinxsidebar p { -+ color: #ffffff; -+} -+ -+div.sphinxsidebar p.topless { -+ margin: 5px 10px 10px 10px; -+} -+ -+div.sphinxsidebar ul { -+ margin: 10px; -+ padding: 0; -+ color: #ffffff; -+} -+ -+div.sphinxsidebar a { -+ color: #98dbcc; -+} -+ -+div.sphinxsidebar input { -+ border: 1px solid #98dbcc; -+ font-family: sans-serif; -+ font-size: 1em; -+} -+ -+/* -- body styles ----------------------------------------------------------- */ -+ -+a { -+ color: #355f7c; -+ text-decoration: none; -+} -+ -+a:hover { -+ text-decoration: underline; -+} -+ -+div.body p, div.body dd, div.body li { -+ text-align: left; -+ line-height: 130%; -+} -+ -+div.body h1, -+div.body h2, -+div.body h3, -+div.body h4, -+div.body h5, -+div.body h6 { -+ font-family: 'Trebuchet MS', sans-serif; -+ background-color: #f2f2f2; -+ font-weight: normal; -+ color: #20435c; -+ border-bottom: 1px solid #ccc; -+ margin: 20px -20px 10px -20px; -+ padding: 3px 0 3px 10px; -+} -+ -+div.body h1 { margin-top: 0; font-size: 200%; } -+div.body h2 { font-size: 160%; } -+div.body h3 { font-size: 140%; } -+div.body h4 { font-size: 120%; } -+div.body h5 { font-size: 110%; } -+div.body h6 { font-size: 100%; } -+ -+a.headerlink { -+ color: #c60f0f; -+ font-size: 0.8em; -+ padding: 0 4px 0 4px; -+ text-decoration: none; -+} -+ -+a.headerlink:hover { -+ background-color: #c60f0f; -+ color: white; -+} -+ -+div.body p, div.body dd, div.body li { -+ text-align: left; -+ line-height: 130%; -+} -+ -+div.admonition p.admonition-title + p { -+ display: inline; -+} -+ -+div.admonition p { -+ margin-bottom: 5px; -+} -+ -+div.admonition pre { -+ margin-bottom: 5px; -+} -+ -+div.admonition ul, div.admonition ol { -+ margin-bottom: 5px; -+} -+ -+div.note { -+ background-color: #eee; -+ border: 1px solid #ccc; -+} -+ -+div.seealso { -+ background-color: #ffc; -+ border: 1px solid #ff6; -+} -+ -+div.topic { -+ background-color: #eee; -+} -+ -+div.warning { -+ background-color: #ffe4e4; -+ border: 1px solid #f66; -+} -+ -+p.admonition-title { -+ display: inline; -+} -+ -+p.admonition-title:after { -+ content: ":"; -+} -+ -+pre { -+ padding: 5px; -+ background-color: #eeffcc; -+ color: #333333; -+ line-height: 120%; -+ border: 1px solid #ac9; -+ border-left: none; -+ border-right: none; -+} -+ -+tt { -+ background-color: #ecf0f3; -+ padding: 0 1px 0 1px; -+ font-size: 0.95em; -+} -+ -+.warning tt { -+ background: #efc2c2; -+} -+ -+.note tt { -+ background: #d6d6d6; -+} -diff --git a/doc/source/_static/jquery.tweet.js b/doc/source/_static/jquery.tweet.js -new file mode 100644 -index 0000000..79bf0bd ---- /dev/null -+++ b/doc/source/_static/jquery.tweet.js -@@ -0,0 +1,154 @@ -+(function($) { -+ -+ $.fn.tweet = function(o){ -+ var s = { -+ username: ["seaofclouds"], // [string] required, unless you want to display our tweets. :) it can be an array, just do ["username1","username2","etc"] -+ list: null, //[string] optional name of list belonging to username -+ avatar_size: null, // [integer] height and width of avatar if displayed (48px max) -+ count: 3, // [integer] how many tweets to display? -+ intro_text: null, // [string] do you want text BEFORE your your tweets? -+ outro_text: null, // [string] do you want text AFTER your tweets? -+ join_text: null, // [string] optional text in between date and tweet, try setting to "auto" -+ auto_join_text_default: "i said,", // [string] auto text for non verb: "i said" bullocks -+ auto_join_text_ed: "i", // [string] auto text for past tense: "i" surfed -+ auto_join_text_ing: "i am", // [string] auto tense for present tense: "i was" surfing -+ auto_join_text_reply: "i replied to", // [string] auto tense for replies: "i replied to" @someone "with" -+ auto_join_text_url: "i was looking at", // [string] auto tense for urls: "i was looking at" http:... -+ loading_text: null, // [string] optional loading text, displayed while tweets load -+ query: null // [string] optional search query -+ }; -+ -+ if(o) $.extend(s, o); -+ -+ $.fn.extend({ -+ linkUrl: function() { -+ var returning = []; -+ var regexp = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi; -+ this.each(function() { -+ returning.push(this.replace(regexp,"$1")); -+ }); -+ return $(returning); -+ }, -+ linkUser: function() { -+ var returning = []; -+ var regexp = /[\@]+([A-Za-z0-9-_]+)/gi; -+ this.each(function() { -+ returning.push(this.replace(regexp,"@$1")); -+ }); -+ return $(returning); -+ }, -+ linkHash: function() { -+ var returning = []; -+ var regexp = / [\#]+([A-Za-z0-9-_]+)/gi; -+ this.each(function() { -+ returning.push(this.replace(regexp, ' #$1')); -+ }); -+ return $(returning); -+ }, -+ capAwesome: function() { -+ var returning = []; -+ this.each(function() { -+ returning.push(this.replace(/\b(awesome)\b/gi, '$1')); -+ }); -+ return $(returning); -+ }, -+ capEpic: function() { -+ var returning = []; -+ this.each(function() { -+ returning.push(this.replace(/\b(epic)\b/gi, '$1')); -+ }); -+ return $(returning); -+ }, -+ makeHeart: function() { -+ var returning = []; -+ this.each(function() { -+ returning.push(this.replace(/(<)+[3]/gi, "")); -+ }); -+ return $(returning); -+ } -+ }); -+ -+ function relative_time(time_value) { -+ var parsed_date = Date.parse(time_value); -+ var relative_to = (arguments.length > 1) ? arguments[1] : new Date(); -+ var delta = parseInt((relative_to.getTime() - parsed_date) / 1000); -+ var pluralize = function (singular, n) { -+ return '' + n + ' ' + singular + (n == 1 ? '' : 's'); -+ }; -+ if(delta < 60) { -+ return 'less than a minute ago'; -+ } else if(delta < (45*60)) { -+ return 'about ' + pluralize("minute", parseInt(delta / 60)) + ' ago'; -+ } else if(delta < (24*60*60)) { -+ return 'about ' + pluralize("hour", parseInt(delta / 3600)) + ' ago'; -+ } else { -+ return 'about ' + pluralize("day", parseInt(delta / 86400)) + ' ago'; -+ } -+ } -+ -+ function build_url() { -+ var proto = ('https:' == document.location.protocol ? 'https:' : 'http:'); -+ if (s.list) { -+ return proto+"//api.twitter.com/1/"+s.username[0]+"/lists/"+s.list+"/statuses.json?per_page="+s.count+"&callback=?"; -+ } else if (s.query == null && s.username.length == 1) { -+ return proto+'//twitter.com/status/user_timeline/'+s.username[0]+'.json?count='+s.count+'&callback=?'; -+ } else { -+ var query = (s.query || 'from:'+s.username.join('%20OR%20from:')); -+ return proto+'//search.twitter.com/search.json?&q='+query+'&rpp='+s.count+'&callback=?'; -+ } -+ } -+ -+ return this.each(function(){ -+ var list = $('
    ').appendTo(this); -+ var intro = '

    '+s.intro_text+'

    '; -+ var outro = '

    '+s.outro_text+'

    '; -+ var loading = $('

    '+s.loading_text+'

    '); -+ -+ if(typeof(s.username) == "string"){ -+ s.username = [s.username]; -+ } -+ -+ if (s.loading_text) $(this).append(loading); -+ $.getJSON(build_url(), function(data){ -+ if (s.loading_text) loading.remove(); -+ if (s.intro_text) list.before(intro); -+ $.each((data.results || data), function(i,item){ -+ // auto join text based on verb tense and content -+ if (s.join_text == "auto") { -+ if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) { -+ var join_text = s.auto_join_text_reply; -+ } else if (item.text.match(/(^\w+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+) .*/i)) { -+ var join_text = s.auto_join_text_url; -+ } else if (item.text.match(/^((\w+ed)|just) .*/im)) { -+ var join_text = s.auto_join_text_ed; -+ } else if (item.text.match(/^(\w*ing) .*/i)) { -+ var join_text = s.auto_join_text_ing; -+ } else { -+ var join_text = s.auto_join_text_default; -+ } -+ } else { -+ var join_text = s.join_text; -+ }; -+ -+ var from_user = item.from_user || item.user.screen_name; -+ var profile_image_url = item.profile_image_url || item.user.profile_image_url; -+ var join_template = ' '+join_text+' '; -+ var join = ((s.join_text) ? join_template : ' '); -+ var avatar_template = ''+from_user+'\'s avatar'; -+ var avatar = (s.avatar_size ? avatar_template : ''); -+ var date = ''+relative_time(item.created_at)+''; -+ var text = '' +$([item.text]).linkUrl().linkUser().linkHash().makeHeart().capAwesome().capEpic()[0]+ ''; -+ -+ // until we create a template option, arrange the items below to alter a tweet's display. -+ list.append('
  • ' + avatar + date + join + text + '
  • '); -+ -+ list.children('li:first').addClass('tweet_first'); -+ list.children('li:odd').addClass('tweet_even'); -+ list.children('li:even').addClass('tweet_odd'); -+ }); -+ if (s.outro_text) list.after(outro); -+ }); -+ -+ }); -+ }; -+})(jQuery); -\ No newline at end of file -diff --git a/doc/source/_static/tweaks.css b/doc/source/_static/tweaks.css -new file mode 100644 -index 0000000..046ead8 ---- /dev/null -+++ b/doc/source/_static/tweaks.css -@@ -0,0 +1,218 @@ -+ul.todo_list { -+ list-style-type: none; -+ margin: 0; -+ padding: 0; -+} -+ -+ul.todo_list li { -+ display: block; -+ margin: 0; -+ padding: 7px 0; -+ border-top: 1px solid #eee; -+} -+ -+ul.todo_list li p { -+ display: inline; -+} -+ -+ul.todo_list li p.link { -+ font-weight: bold; -+} -+ -+ul.todo_list li p.details { -+ font-style: italic; -+} -+ -+ul.todo_list li { -+} -+ -+div.admonition { -+ border: 1px solid #8F1000; -+} -+ -+div.admonition p.admonition-title { -+ background-color: #8F1000; -+ border-bottom: 1px solid #8E8E8E; -+} -+ -+a { -+ color: #CF2F19; -+} -+ -+div.related ul li a { -+ color: #CF2F19; -+} -+ -+div.sphinxsidebar h4 { -+ background-color:#8E8E8E; -+ border:1px solid #255E6E; -+ color:white; -+ font-size:1em; -+ margin:1em 0 0.5em; -+ padding:0.1em 0 0.1em 0.5em; -+} -+ -+em { -+ font-style: normal; -+} -+ -+table.docutils { -+ font-size: 11px; -+} -+ -+.tweet_list li { -+ font-size: 0.9em; -+ border-bottom: 1px solid #eee; -+ padding: 5px 0; -+} -+ -+.tweet_list li .tweet_avatar { -+ float: left; -+} -+ -+/* ------------------------------------------ -+PURE CSS SPEECH BUBBLES -+by Nicolas Gallagher -+- http://nicolasgallagher.com/pure-css-speech-bubbles/ -+ -+http://nicolasgallagher.com -+http://twitter.com/necolas -+ -+Created: 02 March 2010 -+Version: 1.1 (21 October 2010) -+ -+Dual licensed under MIT and GNU GPLv2 © Nicolas Gallagher -+------------------------------------------ */ -+/* THE SPEECH BUBBLE -+------------------------------------------------------------------------------------------------------------------------------- */ -+ -+/* THE SPEECH BUBBLE -+------------------------------------------------------------------------------------------------------------------------------- */ -+ -+.triangle-border { -+ position:relative; -+ padding:15px; -+ margin:1em 0 3em; -+ border:5px solid #BC1518; -+ color:#333; -+ background:#fff; -+ -+ /* css3 */ -+ -moz-border-radius:10px; -+ -webkit-border-radius:10px; -+ border-radius:10px; -+} -+ -+/* Variant : for left positioned triangle -+------------------------------------------ */ -+ -+.triangle-border.left { -+ margin-left:30px; -+} -+ -+/* Variant : for right positioned triangle -+------------------------------------------ */ -+ -+.triangle-border.right { -+ margin-right:30px; -+} -+ -+/* THE TRIANGLE -+------------------------------------------------------------------------------------------------------------------------------- */ -+ -+.triangle-border:before { -+ content:""; -+ display:block; /* reduce the damage in FF3.0 */ -+ position:absolute; -+ bottom:-40px; /* value = - border-top-width - border-bottom-width */ -+ left:40px; /* controls horizontal position */ -+ width:0; -+ height:0; -+ border:20px solid transparent; -+ border-top-color:#BC1518; -+} -+ -+/* creates the smaller triangle */ -+.triangle-border:after { -+ content:""; -+ display:block; /* reduce the damage in FF3.0 */ -+ position:absolute; -+ bottom:-26px; /* value = - border-top-width - border-bottom-width */ -+ left:47px; /* value = (:before left) + (:before border-left) - (:after border-left) */ -+ width:0; -+ height:0; -+ border:13px solid transparent; -+ border-top-color:#fff; -+} -+ -+/* Variant : top -+------------------------------------------ */ -+ -+/* creates the larger triangle */ -+.triangle-border.top:before { -+ top:-40px; /* value = - border-top-width - border-bottom-width */ -+ right:40px; /* controls horizontal position */ -+ bottom:auto; -+ left:auto; -+ border:20px solid transparent; -+ border-bottom-color:#BC1518; -+} -+ -+/* creates the smaller triangle */ -+.triangle-border.top:after { -+ top:-26px; /* value = - border-top-width - border-bottom-width */ -+ right:47px; /* value = (:before right) + (:before border-right) - (:after border-right) */ -+ bottom:auto; -+ left:auto; -+ border:13px solid transparent; -+ border-bottom-color:#fff; -+} -+ -+/* Variant : left -+------------------------------------------ */ -+ -+/* creates the larger triangle */ -+.triangle-border.left:before { -+ top:10px; /* controls vertical position */ -+ left:-30px; /* value = - border-left-width - border-right-width */ -+ bottom:auto; -+ border-width:15px 30px 15px 0; -+ border-style:solid; -+ border-color:transparent #BC1518; -+} -+ -+/* creates the smaller triangle */ -+.triangle-border.left:after { -+ top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */ -+ left:-21px; /* value = - border-left-width - border-right-width */ -+ bottom:auto; -+ border-width:9px 21px 9px 0; -+ border-style:solid; -+ border-color:transparent #fff; -+} -+ -+/* Variant : right -+------------------------------------------ */ -+ -+/* creates the larger triangle */ -+.triangle-border.right:before { -+ top:10px; /* controls vertical position */ -+ right:-30px; /* value = - border-left-width - border-right-width */ -+ bottom:auto; -+ left:auto; -+ border-width:15px 0 15px 30px; -+ border-style:solid; -+ border-color:transparent #BC1518; -+} -+ -+/* creates the smaller triangle */ -+.triangle-border.right:after { -+ top:16px; /* value = (:before top) + (:before border-top) - (:after border-top) */ -+ right:-21px; /* value = - border-left-width - border-right-width */ -+ bottom:auto; -+ left:auto; -+ border-width:9px 0 9px 21px; -+ border-style:solid; -+ border-color:transparent #fff; -+} -+ -diff --git a/doc/source/_templates/.gitignore b/doc/source/_templates/.gitignore -new file mode 100644 -index 0000000..e69de29 -diff --git a/doc/source/_templates/.placeholder b/doc/source/_templates/.placeholder -new file mode 100644 -index 0000000..e69de29 -diff --git a/doc/source/_theme/layout.html b/doc/source/_theme/layout.html -new file mode 100644 -index 0000000..f5b388c ---- /dev/null -+++ b/doc/source/_theme/layout.html -@@ -0,0 +1,95 @@ -+{% extends "sphinxdoc/layout.html" %} -+{% set css_files = css_files + ['_static/tweaks.css'] %} -+{% set script_files = script_files + ['_static/jquery.tweet.js'] %} -+{% block extrahead %} -+ -+{% endblock %} -+ -+{%- macro sidebar() %} -+ {%- if not embedded %}{% if not theme_nosidebar|tobool %} -+
    -+
    -+ {%- block sidebarlogo %} -+ {%- if logo %} -+ -+ {%- endif %} -+ {%- endblock %} -+ {%- block sidebartoc %} -+ {%- if display_toc %} -+

    {{ _('Table Of Contents') }}

    -+ {{ toc }} -+ {%- endif %} -+ {%- endblock %} -+ {%- block sidebarrel %} -+ {%- if prev %} -+

    {{ _('Previous topic') }}

    -+

    {{ prev.title }}

    -+ {%- endif %} -+ {%- if next %} -+

    {{ _('Next topic') }}

    -+

    {{ next.title }}

    -+ {%- endif %} -+ {%- endblock %} -+ {%- block sidebarsourcelink %} -+ {%- if show_source and has_source and sourcename %} -+

    {{ _('This Page') }}

    -+ -+ {%- endif %} -+ {%- endblock %} -+ {%- if customsidebar %} -+ {% include customsidebar %} -+ {%- endif %} -+ {%- block sidebarsearch %} -+ {%- if pagename != "search" %} -+ -+ -+ -+

    -+ Psst... hey. You're reading the latest content, but it's for the Block Storage project only. You can read all OpenStack docs too. -+

    -+ -+ {%- endif %} -+ -+ {%- if pagename == "index" %} -+ -+ -+

    {{ _('Twitter Feed') }}

    -+ -+ {%- endif %} -+ -+ -+ -+ -+ {%- endblock %} -+
    -+
    -+ {%- endif %}{% endif %} -+{%- endmacro %} -diff --git a/doc/source/_theme/theme.conf b/doc/source/_theme/theme.conf -new file mode 100644 -index 0000000..e039fe0 ---- /dev/null -+++ b/doc/source/_theme/theme.conf -@@ -0,0 +1,5 @@ -+[theme] -+inherit = sphinxdoc -+stylesheet = sphinxdoc.css -+pygments_style = friendly -+ -diff --git a/doc/source/conf.py b/doc/source/conf.py -index 7a2bf1a..01bd3b4 100644 ---- a/doc/source/conf.py -+++ b/doc/source/conf.py -@@ -33,9 +33,7 @@ extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.coverage', - 'sphinx.ext.pngmath', - 'sphinx.ext.ifconfig', -- 'sphinx.ext.graphviz', -- 'oslo.sphinx', -- ] -+ 'sphinx.ext.graphviz'] - - # autodoc generation is a bit aggressive and a nuisance - # when doing heavy text edit cycles. Execute "export SPHINX_DEBUG=1" -@@ -133,8 +131,8 @@ man_pages = [ - - # The theme to use for HTML and HTML Help pages. Major themes that come with - # Sphinx are currently 'default' and 'sphinxdoc'. --# html_theme_path = ["."] --# html_theme = '_theme' -+html_theme_path = ["."] -+html_theme = '_theme' - - # Theme options are theme-specific and customize the look and feel of a theme - # further. For a list of options available for each theme, see the -diff --git a/test-requirements.txt b/test-requirements.txt -index 3d8e9bf..f83b20b 100644 ---- a/test-requirements.txt -+++ b/test-requirements.txt -@@ -12,4 +12,3 @@ sphinx>=1.1.2 - python-subunit - testtools>=0.9.32 - testrepository>=0.0.17 --oslo.sphinx diff --git a/rpm/SOURCES/MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch b/rpm/SOURCES/MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch deleted file mode 100755 index 0b1f0850b..000000000 --- a/rpm/SOURCES/MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch +++ /dev/null @@ -1,496 +0,0 @@ -From fd7e9dd59ffa346bed5a11e5312f4bb1bf114ab4 Mon Sep 17 00:00:00 2001 -From: Dmitry Borodaenko -Date: Wed, 27 Nov 2013 14:33:00 -0800 -Subject: [PATCH] Do not clone non-raw images in rbd backend - -RBD backend only supports booting from images in raw format. A volume -that was cloned from an image in any other format is not bootable. The -RBD driver will consider non-raw images to be uncloneable to trigger -automatic conversion to raw format. - -Includes conversion of the corresponding unit test to use mock (instead -of mox) and expanded comments and error messages from patchset #58893 by -Edward Hope-Morley. - -Change-Id: I5725d2f7576bc1b3e9b874ba944ad17d33a6e2cb -Closes-Bug: #1246219 -Closes-Bug: #1247998 ---- - cinder/tests/test_gpfs.py | 6 +- - cinder/tests/test_netapp_nfs.py | 12 +- - cinder/tests/test_rbd.py | 168 +++++++++++++++++--------- - cinder/tests/test_volume.py | 2 +- - cinder/volume/driver.py | 7 +- - cinder/volume/drivers/gpfs.py | 2 +- - cinder/volume/drivers/lvm.py | 2 +- - cinder/volume/drivers/netapp/nfs.py | 2 +- - cinder/volume/drivers/rbd.py | 14 ++- - cinder/volume/drivers/scality.py | 2 +- - cinder/volume/flows/create_volume/__init__.py | 2 +- - 11 files changed, 144 insertions(+), 75 deletions(-) - -diff --git a/cinder/tests/test_gpfs.py b/cinder/tests/test_gpfs.py -index 4fdb788..1f47c6b 100644 ---- a/cinder/tests/test_gpfs.py -+++ b/cinder/tests/test_gpfs.py -@@ -288,7 +288,8 @@ class GPFSDriverTestCase(test.TestCase): - CONF.gpfs_images_share_mode = 'copy_on_write' - self.driver.clone_image(volume, - None, -- self.image_id) -+ self.image_id, -+ {}) - - self.assertTrue(os.path.exists(volumepath)) - self.volume.delete_volume(self.context, volume['id']) -@@ -309,7 +310,8 @@ class GPFSDriverTestCase(test.TestCase): - CONF.gpfs_images_share_mode = 'copy' - self.driver.clone_image(volume, - None, -- self.image_id) -+ self.image_id, -+ {}) - - self.assertTrue(os.path.exists(volumepath)) - self.volume.delete_volume(self.context, volume['id']) -diff --git a/cinder/tests/test_netapp_nfs.py b/cinder/tests/test_netapp_nfs.py -index 950efc8..042280e 100644 ---- a/cinder/tests/test_netapp_nfs.py -+++ b/cinder/tests/test_netapp_nfs.py -@@ -469,7 +469,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - drv._post_clone_image(volume) - - mox.ReplayAll() -- drv. clone_image(volume, ('image_location', None), 'image_id') -+ drv.clone_image(volume, ('image_location', None), 'image_id', {}) - mox.VerifyAll() - - def get_img_info(self, format): -@@ -493,7 +493,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - (prop, cloned) = drv. clone_image( -- volume, ('nfs://127.0.0.1:/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1:/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - if not cloned and not prop['provider_location']: - pass -@@ -529,7 +529,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - drv. clone_image( -- volume, ('nfs://127.0.0.1:/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1:/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - - def test_clone_image_cloneableshare_notraw(self): -@@ -566,7 +566,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - drv. clone_image( -- volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - - def test_clone_image_file_not_discovered(self): -@@ -605,7 +605,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - vol_dict, result = drv. clone_image( -- volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - self.assertFalse(result) - self.assertFalse(vol_dict['bootable']) -@@ -652,7 +652,7 @@ class NetappDirectCmodeNfsDriverTestCase(test.TestCase): - - mox.ReplayAll() - vol_dict, result = drv. clone_image( -- volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id') -+ volume, ('nfs://127.0.0.1/share/img-id', None), 'image_id', {}) - mox.VerifyAll() - self.assertFalse(result) - self.assertFalse(vol_dict['bootable']) -diff --git a/cinder/tests/test_rbd.py b/cinder/tests/test_rbd.py -index 60de09b..054bbb5 100644 ---- a/cinder/tests/test_rbd.py -+++ b/cinder/tests/test_rbd.py -@@ -34,6 +34,7 @@ from cinder.tests.test_volume import DriverTestCase - from cinder import units - from cinder.volume import configuration as conf - import cinder.volume.drivers.rbd as driver -+from cinder.volume.flows import create_volume - - - LOG = logging.getLogger(__name__) -@@ -247,7 +248,8 @@ class RBDTestCase(test.TestCase): - self.assertRaises(exception.ImageUnacceptable, - self.driver._parse_location, - loc) -- self.assertFalse(self.driver._is_cloneable(loc)) -+ self.assertFalse( -+ self.driver._is_cloneable(loc, {'disk_format': 'raw'})) - - def test_cloneable(self): - self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') -@@ -264,12 +266,14 @@ class RBDTestCase(test.TestCase): - - self.mox.ReplayAll() - -- self.assertTrue(self.driver._is_cloneable(location)) -+ self.assertTrue( -+ self.driver._is_cloneable(location, {'disk_format': 'raw'})) - - def test_uncloneable_different_fsid(self): - self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') - location = 'rbd://def/pool/image/snap' -- self.assertFalse(self.driver._is_cloneable(location)) -+ self.assertFalse( -+ self.driver._is_cloneable(location, {'disk_format': 'raw'})) - - def test_uncloneable_unreadable(self): - self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') -@@ -284,7 +288,16 @@ class RBDTestCase(test.TestCase): - - self.mox.ReplayAll() - -- self.assertFalse(self.driver._is_cloneable(location)) -+ self.assertFalse( -+ self.driver._is_cloneable(location, {'disk_format': 'raw'})) -+ -+ def test_uncloneable_bad_format(self): -+ self.stubs.Set(self.driver, '_get_fsid', lambda: 'abc') -+ location = 'rbd://abc/pool/image/snap' -+ formats = ['qcow2', 'vmdk', 'vdi'] -+ for f in formats: -+ self.assertFalse( -+ self.driver._is_cloneable(location, {'disk_format': f})) - - def _copy_image(self): - @contextlib.contextmanager -@@ -504,26 +517,37 @@ class ManagedRBDTestCase(DriverTestCase): - super(ManagedRBDTestCase, self).setUp() - fake_image.stub_out_image_service(self.stubs) - self.volume.driver.set_initialized() -+ self.called = [] - -- def _clone_volume_from_image(self, expected_status, -- clone_works=True): -+ def _create_volume_from_image(self, expected_status, raw=False, -+ clone_error=False): - """Try to clone a volume from an image, and check the status - afterwards. -+ -+ NOTE: if clone_error is True we force the image type to raw otherwise -+ clone_image is not called - """ -- def fake_clone_image(volume, image_location, image_id): -- return {'provider_location': None}, True -+ def mock_clone_image(volume, image_location, image_id, image_meta): -+ self.called.append('clone_image') -+ if clone_error: -+ raise exception.CinderException() -+ else: -+ return {'provider_location': None}, True - -- def fake_clone_error(volume, image_location, image_id): -- raise exception.CinderException() -+ if clone_error: -+ raw = True - -- self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True) -- if clone_works: -- self.stubs.Set(self.volume.driver, 'clone_image', fake_clone_image) -+ # See tests.image.fake for image types. -+ if raw: -+ expected_calls = ['clone_image'] -+ image_id = '155d900f-4e14-4e4c-a73d-069cbf4541e6' - else: -- self.stubs.Set(self.volume.driver, 'clone_image', fake_clone_error) -+ expected_calls = ['clone_image', 'create_volume', -+ 'copy_image_to_volume'] -+ image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77' - -- image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77' - volume_id = 1 -+ - # creating volume testdata - db.volume_create(self.context, - {'id': volume_id, -@@ -533,58 +557,88 @@ class ManagedRBDTestCase(DriverTestCase): - 'status': 'creating', - 'instance_uuid': None, - 'host': 'dummy'}) -- try: -- if clone_works: -- self.volume.create_volume(self.context, -- volume_id, -- image_id=image_id) -- else: -- self.assertRaises(exception.CinderException, -- self.volume.create_volume, -- self.context, -- volume_id, -- image_id=image_id) -- -- volume = db.volume_get(self.context, volume_id) -- self.assertEqual(volume['status'], expected_status) -- finally: -- # cleanup -- db.volume_destroy(self.context, volume_id) -+ -+ with mock.patch.object(self.volume.driver, 'create_volume') as \ -+ mock_create_volume: -+ with mock.patch.object(self.volume.driver, 'clone_image', -+ mock_clone_image): -+ with mock.patch.object(create_volume.CreateVolumeFromSpecTask, -+ '_copy_image_to_volume') as \ -+ mock_copy_image_to_volume: -+ self.volume.driver._is_cloneable = mock.Mock() -+ self.volume.driver._is_cloneable.return_value = True -+ -+ try: -+ if not clone_error: -+ self.volume.create_volume(self.context, -+ volume_id, -+ image_id=image_id) -+ else: -+ self.assertRaises(exception.CinderException, -+ self.volume.create_volume, -+ self.context, -+ volume_id, -+ image_id=image_id) -+ -+ volume = db.volume_get(self.context, volume_id) -+ self.assertEqual(volume['status'], expected_status) -+ finally: -+ # cleanup -+ db.volume_destroy(self.context, volume_id) -+ -+ if raw: -+ self.assertEquals(self.called, ['clone_image']) -+ -+ mock_create_volume.assert_called() -+ mock_copy_image_to_volume.assert_called() - - def test_create_vol_from_image_status_available(self): -- """Verify that before cloning, an image is in the available state.""" -- self._clone_volume_from_image('available', True) -+ """Clone raw image then verify volume is in available state.""" -+ self._create_volume_from_image('available', raw=True) -+ -+ def test_create_vol_from_non_raw_image_status_available(self): -+ """Clone non-raw image then verify volume is in available state.""" -+ self._create_volume_from_image('available', raw=False) - - def test_create_vol_from_image_status_error(self): -- """Verify that before cloning, an image is in the available state.""" -- self._clone_volume_from_image('error', False) -+ """Clone raw image with failure then verify volume is in error -+ state. -+ """ -+ self._create_volume_from_image('error', raw=True, clone_error=True) - - def test_clone_image(self): -- # Test Failure Case(s) -- expected = ({}, False) -+ driver = self.volume.driver - -- self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: False) -- image_loc = (object(), object()) -- actual = self.volume.driver.clone_image(object(), image_loc, object()) -- self.assertEqual(expected, actual) -+ # Test uncloneable case(s) -+ with mock.patch.object(driver, '_is_cloneable', -+ lambda *args: False) as mock_is_cloneable: -+ image_loc = (mock.Mock(), mock.Mock()) -+ actual = driver.clone_image(mock.Mock(), image_loc, -+ mock.Mock(), {}) -+ self.assertEqual(({}, False), actual) - -- self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True) -- self.assertEqual(expected, -- self.volume.driver.clone_image(object(), None, None)) -+ self.assertEqual(({}, False), -+ driver.clone_image(object(), None, None, {})) - -- # Test Success Case(s) -+ # Test success case(s) - expected = ({'provider_location': None}, True) -- -- self.stubs.Set(self.volume.driver, '_parse_location', -- lambda x: ('a', 'b', 'c', 'd')) -- -- self.stubs.Set(self.volume.driver, '_clone', lambda *args: None) -- self.stubs.Set(self.volume.driver, '_resize', lambda *args: None) -- actual = self.volume.driver.clone_image(object(), image_loc, object()) -- self.assertEqual(expected, actual) -+ mpo = mock.patch.object -+ with mpo(driver, '_is_cloneable', lambda *args: True): -+ with mpo(driver, '_parse_location', -+ lambda x: ('a', 'b', 'c', 'd')): -+ with mpo(driver, '_clone') as mock_clone: -+ with mpo(driver, '_resize') as mock_resize: -+ actual = driver.clone_image(mock.Mock(), image_loc, -+ mock.Mock(), -+ {'disk_format': 'raw'}) -+ self.assertEqual(expected, actual) -+ mock_clone.assert_called() -+ mock_resize.assert_called() - - def test_clone_success(self): -- self.stubs.Set(self.volume.driver, '_is_cloneable', lambda x: True) -- self.stubs.Set(self.volume.driver, 'clone_image', lambda a, b, c: True) -+ self.stubs.Set(self.volume.driver, '_is_cloneable', lambda *args: True) -+ self.stubs.Set(self.volume.driver, 'clone_image', -+ lambda a, b, c, d: True) - image_id = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77' -- self.assertTrue(self.volume.driver.clone_image({}, image_id, image_id)) -+ self.assertTrue(self.volume.driver.clone_image({}, -+ image_id, image_id, {})) -diff --git a/cinder/tests/test_volume.py b/cinder/tests/test_volume.py -index 4a0d475..928799f 100644 ---- a/cinder/tests/test_volume.py -+++ b/cinder/tests/test_volume.py -@@ -1216,7 +1216,7 @@ class VolumeTestCase(BaseVolumeTestCase): - def fake_fetch_to_raw(ctx, image_service, image_id, path, size=None): - pass - -- def fake_clone_image(volume_ref, image_location, image_id): -+ def fake_clone_image(volume_ref, image_location, image_id, image_meta): - return {'provider_location': None}, True - - dst_fd, dst_path = tempfile.mkstemp() -diff --git a/cinder/volume/driver.py b/cinder/volume/driver.py -index 21dd12b..dd2be3c 100644 ---- a/cinder/volume/driver.py -+++ b/cinder/volume/driver.py -@@ -396,7 +396,7 @@ class VolumeDriver(object): - connector.disconnect_volume(attach_info['conn']['data'], - attach_info['device']) - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - """Create a volume efficiently from an existing image. - - image_location is a string whose format depends on the -@@ -407,6 +407,11 @@ class VolumeDriver(object): - It can be used by the driver to introspect internal - stores or registry to do an efficient image clone. - -+ image_meta is a dictionary that includes 'disk_format' (e.g. -+ raw, qcow2) and other image attributes that allow drivers to -+ decide whether they can clone the image without first requiring -+ conversion. -+ - Returns a dict of volume properties eg. provider_location, - boolean indicating whether cloning occurred - """ -diff --git a/cinder/volume/drivers/gpfs.py b/cinder/volume/drivers/gpfs.py -index 9a1a397..8792ad8 100644 ---- a/cinder/volume/drivers/gpfs.py -+++ b/cinder/volume/drivers/gpfs.py -@@ -463,7 +463,7 @@ class GPFSDriver(driver.VolumeDriver): - return '100M' - return '%sG' % size_in_g - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - return self._clone_image(volume, image_location, image_id) - - def _is_cloneable(self, image_id): -diff --git a/cinder/volume/drivers/lvm.py b/cinder/volume/drivers/lvm.py -index 094436f..c6023eb 100644 ---- a/cinder/volume/drivers/lvm.py -+++ b/cinder/volume/drivers/lvm.py -@@ -322,7 +322,7 @@ class LVMVolumeDriver(driver.VolumeDriver): - finally: - self.delete_snapshot(temp_snapshot) - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - return None, False - - def backup_volume(self, context, backup, backup_service): -diff --git a/cinder/volume/drivers/netapp/nfs.py b/cinder/volume/drivers/netapp/nfs.py -index 602a1dc..9463137 100644 ---- a/cinder/volume/drivers/netapp/nfs.py -+++ b/cinder/volume/drivers/netapp/nfs.py -@@ -374,7 +374,7 @@ class NetAppNFSDriver(nfs.NfsDriver): - LOG.warning(_('Exception during deleting %s'), ex.__str__()) - return False - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - """Create a volume efficiently from an existing image. - - image_location is a string whose format depends on the -diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py -index 775ab16..7ed59d0 100644 ---- a/cinder/volume/drivers/rbd.py -+++ b/cinder/volume/drivers/rbd.py -@@ -706,7 +706,7 @@ class RBDDriver(driver.VolumeDriver): - with RADOSClient(self) as client: - return client.cluster.get_fsid() - -- def _is_cloneable(self, image_location): -+ def _is_cloneable(self, image_location, image_meta): - try: - fsid, pool, image, snapshot = self._parse_location(image_location) - except exception.ImageUnacceptable as e: -@@ -718,6 +718,13 @@ class RBDDriver(driver.VolumeDriver): - LOG.debug(reason) - return False - -+ if image_meta['disk_format'] != 'raw': -+ reason = _("rbd image clone requires image format to be " -+ "'raw' but image {0} is '{1}'").format( -+ image_location, image_meta['disk_format']) -+ LOG.debug(reason) -+ return False -+ - # check that we can read the image - try: - with RBDVolumeProxy(self, image, -@@ -730,9 +737,10 @@ class RBDDriver(driver.VolumeDriver): - dict(loc=image_location, err=e)) - return False - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - image_location = image_location[0] if image_location else None -- if image_location is None or not self._is_cloneable(image_location): -+ if image_location is None or not self._is_cloneable( -+ image_location, image_meta): - return ({}, False) - prefix, pool, image, snapshot = self._parse_location(image_location) - self._clone(volume, pool, image, snapshot) -diff --git a/cinder/volume/drivers/scality.py b/cinder/volume/drivers/scality.py -index 4cf49c6..abd6c29 100644 ---- a/cinder/volume/drivers/scality.py -+++ b/cinder/volume/drivers/scality.py -@@ -250,7 +250,7 @@ class ScalityDriver(driver.VolumeDriver): - image_meta, - self.local_path(volume)) - -- def clone_image(self, volume, image_location, image_id): -+ def clone_image(self, volume, image_location, image_id, image_meta): - """Create a volume efficiently from an existing image. - - image_location is a string whose format depends on the -diff --git a/cinder/volume/flows/create_volume/__init__.py b/cinder/volume/flows/create_volume/__init__.py -index bb7acd3..e5aa371 100644 ---- a/cinder/volume/flows/create_volume/__init__.py -+++ b/cinder/volume/flows/create_volume/__init__.py -@@ -1438,7 +1438,7 @@ class CreateVolumeFromSpecTask(base.CinderTask): - # dict containing provider_location for cloned volume - # and clone status. - model_update, cloned = self.driver.clone_image( -- volume_ref, image_location, image_id) -+ volume_ref, image_location, image_id, image_meta) - if not cloned: - # TODO(harlowja): what needs to be rolled back in the clone if this - # volume create fails?? Likely this should be a subflow or broken --- -1.8.5.1 - diff --git a/rpm/SOURCES/cinder-dist.conf b/rpm/SOURCES/cinder-dist.conf index ccc7c3f6c..933c4a870 100644 --- a/rpm/SOURCES/cinder-dist.conf +++ b/rpm/SOURCES/cinder-dist.conf @@ -3,9 +3,8 @@ logdir = /var/log/cinder state_path = /var/lib/cinder lock_path = /var/lib/cinder/tmp volumes_dir = /etc/cinder/volumes -iscsi_helper = tgtadm +iscsi_helper = lioadm sql_connection = mysql://cinder:cinder@localhost/cinder -rpc_backend = cinder.openstack.common.rpc.impl_qpid rootwrap_config = /etc/cinder/rootwrap.conf auth_strategy = keystone diff --git a/rpm/SOURCES/cinder-tgt.conf b/rpm/SOURCES/cinder-tgt.conf index 1581c7953..b07cc4788 100644 --- a/rpm/SOURCES/cinder-tgt.conf +++ b/rpm/SOURCES/cinder-tgt.conf @@ -1,5 +1 @@ -# Note this config mode is not supported by scsi-target-utils in RHEL <= 6.4 -# include /etc/cinder/volumes/ -# So instead please add the following line (without the leading comment char) -# to the top of /etc/tgt/targets.conf -# include /etc/cinder/volumes/* +include /etc/cinder/volumes/ diff --git a/rpm/SOURCES/openstack-cinder-api.upstart b/rpm/SOURCES/openstack-cinder-api.upstart deleted file mode 100644 index 51acbc58d..000000000 --- a/rpm/SOURCES/openstack-cinder-api.upstart +++ /dev/null @@ -1,8 +0,0 @@ -description "OpenStack Cinder API Server" - -start on stopped rc RUNLEVEL=[2345] -stop on runlevel [S016] - -respawn - -exec su -s /bin/sh -c "exec /usr/bin/cinder-api --config-file /usr/share/cinder/cinder-dist.conf --config-file /etc/cinder/cinder.conf --logfile /var/log/cinder/api.log" cinder diff --git a/rpm/SOURCES/openstack-cinder-backup.upstart b/rpm/SOURCES/openstack-cinder-backup.upstart deleted file mode 100644 index 1c23c2178..000000000 --- a/rpm/SOURCES/openstack-cinder-backup.upstart +++ /dev/null @@ -1,8 +0,0 @@ -description "OpenStack Cinder Backup Server" - -start on stopped rc RUNLEVEL=[2345] -stop on runlevel [S016] - -respawn - -exec su -s /bin/sh -c "exec /usr/bin/cinder-backup --config-file /usr/share/cinder/cinder-dist.conf --config-file /etc/cinder/cinder.conf --logfile /var/log/cinder/backup.log" cinder diff --git a/rpm/SOURCES/openstack-cinder-scheduler.upstart b/rpm/SOURCES/openstack-cinder-scheduler.upstart deleted file mode 100644 index b152c1846..000000000 --- a/rpm/SOURCES/openstack-cinder-scheduler.upstart +++ /dev/null @@ -1,8 +0,0 @@ -description "OpenStack Cinder Scheduler Server" - -start on stopped rc RUNLEVEL=[2345] -stop on runlevel [S016] - -respawn - -exec su -s /bin/sh -c "exec /usr/bin/cinder-scheduler --config-file /usr/share/cinder/cinder-dist.conf --config-file /etc/cinder/cinder.conf --logfile /var/log/cinder/scheduler.log" cinder diff --git a/rpm/SOURCES/openstack-cinder-volume.upstart b/rpm/SOURCES/openstack-cinder-volume.upstart deleted file mode 100644 index 46020f48b..000000000 --- a/rpm/SOURCES/openstack-cinder-volume.upstart +++ /dev/null @@ -1,8 +0,0 @@ -description "OpenStack Cinder Volume Server" - -start on stopped rc RUNLEVEL=[2345] -stop on runlevel [S016] - -respawn - -exec su -s /bin/sh -c "exec /usr/bin/cinder-volume --config-file /usr/share/cinder/cinder-dist.conf --config-file /etc/cinder/cinder.conf --logfile /var/log/cinder/volume.log" cinder diff --git a/rpm/SPECS/openstack-cinder.spec b/rpm/SPECS/openstack-cinder.spec index e39dd511f..2c30b2deb 100644 --- a/rpm/SPECS/openstack-cinder.spec +++ b/rpm/SPECS/openstack-cinder.spec @@ -1,50 +1,39 @@ %global with_doc %{!?_without_doc:1}%{?_without_doc:0} Name: openstack-cinder -Version: 2013.2 -Release: 0.9.b3%{?dist} +Version: 2014.2 +Release: 2%{?dist} Summary: OpenStack Volume service Group: Applications/System License: ASL 2.0 URL: http://www.openstack.org/software/openstack-storage/ -Source0: https://launchpad.net/cinder/havana/havana-3/+download/cinder-%{version}.b3.tar.gz +Source0: https://launchpad.net/cinder/icehouse/2014.1/+download/cinder-%{version}.tar.gz Source1: cinder-dist.conf Source2: cinder.logrotate Source3: cinder-tgt.conf Source10: openstack-cinder-api.init -Source100: openstack-cinder-api.upstart Source11: openstack-cinder-scheduler.init -Source110: openstack-cinder-scheduler.upstart Source12: openstack-cinder-volume.init -Source120: openstack-cinder-volume.upstart Source13: openstack-cinder-backup.init -Source130: openstack-cinder-backup.upstart Source20: cinder-sudoers # -# patches_base=2013.2.b3 +# patches_base=2014.1.1 # -Patch0001: 0001-Ensure-we-don-t-access-the-net-when-building-docs.patch -Patch0002: 0002-Use-updated-parallel-install-versions-of-epel-packag.patch -Patch0003: 0003-Remove-runtime-dep-on-python-pbr-python-d2to1.patch -Patch0004: 0004-Revert-Use-oslo.sphinx-and-remove-local-copy-of-doc-.patch -Patch0005: MIRA-Do-not-clone-non-raw-images-in-rbd-backend.patch +Patch0001: 0001-Remove-runtime-dep-on-python-pbr-python-d2to1.patch +Patch0002: 0002-Revert-Switch-over-to-oslosphinx.patch BuildArch: noarch BuildRequires: intltool BuildRequires: python-d2to1 +BuildRequires: python-oslo-sphinx BuildRequires: python-pbr -BuildRequires: python-sphinx10 +BuildRequires: python-sphinx BuildRequires: python-setuptools BuildRequires: python-netaddr -BuildRequires: openstack-utils -BuildRequires: python-paste-deploy1.5 -BuildRequires: python-routes1.12 -BuildRequires: python-sqlalchemy0.7 -BuildRequires: python-webob1.2 Requires: openstack-utils Requires: python-cinder = %{version}-%{release} @@ -76,41 +65,49 @@ Requires: MySQL-python Requires: qemu-img Requires: sysfsutils -Requires: python-paramiko +Requires: python-paramiko >= 1.13.0 Requires: python-qpid Requires: python-kombu Requires: python-amqplib -Requires: python-importlib - -Requires: python-eventlet -Requires: python-greenlet -Requires: python-iso8601 -Requires: python-netaddr -Requires: python-lxml -Requires: python-anyjson -Requires: python-cheetah -Requires: python-stevedore + +Requires: python-eventlet >= 0.13.0 +Requires: python-greenlet >= 0.3.2 +Requires: python-iso8601 >= 0.1.9 +Requires: python-netaddr >= 0.7.6 +Requires: python-lxml >= 2.3 +Requires: python-anyjson >= 0.3.3 +#Requires: python-cheetah +Requires: python-stevedore >= 0.14 Requires: python-suds -Requires: python-sqlalchemy0.7 -Requires: python-migrate +Requires: python-sqlalchemy >= 0.8.4, python-sqlalchemy < 0.95, python-sqlalchemy > 0.9.5, python-sqlalchemy <= 0.9.99 +Requires: python-migrate >= 0.9.1 -Requires: python-paste-deploy1.5 -Requires: python-routes1.12 -Requires: python-webob1.2 +Requires: python-paste-deploy >= 1.5.0 +Requires: python-routes >= 1.12.3, python-routes < 2.0, python-routes > 2.0 +Requires: python-webob >= 1.2.3 Requires: python-glanceclient >= 1:0 -Requires: python-swiftclient >= 1.2 -Requires: python-keystoneclient -Requires: python-novaclient >= 2.14 +Requires: python-swiftclient >= 2.0.2 +Requires: python-keystoneclient +Requires: python-keystonemiddleware >= 1.0.0 +Requires: python-novaclient >= 1:2.17 Requires: python-oslo-config >= 1:1.2.0 -Requires: python-six +Requires: python-six >= 1.7.0 -Requires: python-babel +Requires: python-babel >= 1.3 Requires: python-lockfile +Requires: python-oslo-rootwrap +Requires: python-rtslib-fb +Requires: python-taskflow +Requires: python-oslo-messaging >= 1.3.0-0.1.a9 + +Requires: python-ceph +#Requires: iscsi-initiator-utils + %description -n python-cinder OpenStack Volume (codename Cinder) provides services to manage and access block storage volumes for use by Virtual Machine instances. @@ -128,9 +125,9 @@ BuildRequires: graphviz # Required to build module documents BuildRequires: python-eventlet -BuildRequires: python-routes1.12 -BuildRequires: python-sqlalchemy0.7 -BuildRequires: python-webob1.2 +BuildRequires: python-routes +BuildRequires: python-sqlalchemy +BuildRequires: python-webob # while not strictly required, quiets the build down when building docs. BuildRequires: python-migrate, python-iso8601 @@ -146,9 +143,6 @@ This package contains documentation files for cinder. %patch0001 -p1 %patch0002 -p1 -%patch0003 -p1 -%patch0004 -p1 -%patch0005 -p1 find . \( -name .gitignore -o -name .placeholder \) -delete @@ -166,15 +160,6 @@ sed -i s/REDHATCINDERVERSION/%{version}/ cinder/version.py sed -i s/REDHATCINDERRELEASE/%{release}/ cinder/version.py %build - -# Move authtoken configuration out of paste.ini -openstack-config --del etc/cinder/api-paste.ini filter:authtoken admin_tenant_name -openstack-config --del etc/cinder/api-paste.ini filter:authtoken admin_user -openstack-config --del etc/cinder/api-paste.ini filter:authtoken admin_password -openstack-config --del etc/cinder/api-paste.ini filter:authtoken auth_host -openstack-config --del etc/cinder/api-paste.ini filter:authtoken auth_port -openstack-config --del etc/cinder/api-paste.ini filter:authtoken auth_protocol - %{__python} setup.py build %install @@ -186,7 +171,7 @@ export PYTHONPATH="$( pwd ):$PYTHONPATH" pushd doc %if 0%{?with_doc} -SPHINX_DEBUG=1 sphinx-1.0-build -b html source build/html +SPHINX_DEBUG=1 sphinx-build -b html source build/html # Fix hidden-file-or-dir warnings rm -fr build/html/.doctrees build/html/.buildinfo %endif @@ -194,7 +179,7 @@ rm -fr build/html/.doctrees build/html/.buildinfo # Create dir link to avoid a sphinx-build exception mkdir -p build/man/.doctrees/ ln -s . build/man/.doctrees/man -SPHINX_DEBUG=1 sphinx-1.0-build -b man -c source source/man build/man +SPHINX_DEBUG=1 sphinx-build -b man -c source source/man build/man mkdir -p %{buildroot}%{_mandir}/man1 install -p -D -m 644 build/man/*.1 %{buildroot}%{_mandir}/man1/ @@ -230,13 +215,6 @@ install -p -D -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/logrotate.d/openstack # Install pid directory install -d -m 755 %{buildroot}%{_localstatedir}/run/cinder -# Install upstart jobs examples -install -d -m 755 %{buildroot}%{_datadir}/cinder -install -p -m 644 %{SOURCE100} %{buildroot}%{_datadir}/cinder/ -install -p -m 644 %{SOURCE110} %{buildroot}%{_datadir}/cinder/ -install -p -m 644 %{SOURCE120} %{buildroot}%{_datadir}/cinder/ -install -p -m 644 %{SOURCE130} %{buildroot}%{_datadir}/cinder/ - # Install rootwrap files in /usr/share/cinder/rootwrap mkdir -p %{buildroot}%{_datarootdir}/cinder/rootwrap/ install -p -D -m 644 etc/cinder/rootwrap.d/* %{buildroot}%{_datarootdir}/cinder/rootwrap/ @@ -255,16 +233,13 @@ fi exit 0 %post -if [ $1 -eq 1 ] ; then - # Initial installation - for svc in volume api scheduler; do - /sbin/chkconfig --add openstack-cinder-$svc - done -fi +for svc in volume api scheduler backup; do + /sbin/chkconfig --add openstack-cinder-$svc +done %preun if [ $1 -eq 0 ] ; then - for svc in volume api scheduler; do + for svc in volume api scheduler backup; do /sbin/service openstack-cinder-${svc} stop > /dev/null 2>&1 /sbin/chkconfig --del openstack-cinder-${svc} done @@ -273,7 +248,7 @@ fi %postun if [ $1 -ge 1 ] ; then # Package upgrade, not uninstall - for svc in volume api scheduler; do + for svc in volume api scheduler backup; do /sbin/service openstack-cinder-${svc} condrestart > /dev/null 2>&1 || : done fi @@ -315,6 +290,78 @@ fi %endif %changelog +* Wed Jun 11 2014 Eric Harney - 2014.1.1-2 +- Add dependency on iscsi-initiator-utils + +* Mon Jun 09 2014 Eric Harney - 2014.1.1-1 +- Update to Icehouse stable release 1 + +* Sat Jun 07 2014 Fedora Release Engineering - 2014.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Tue Apr 29 2014 Alan Pevec - 2014.1-3 +- drop crudini build dependency + +* Mon Apr 21 2014 Eric Harney - 2014.1-2 +- Remove qpid settings from cinder-dist.conf + +* Thu Apr 17 2014 Eric Harney - 2014.1-1 +- Update to 2014.1 (Icehouse) + +* Tue Apr 15 2014 Eric Harney - 2014.1-0.10.rc3 +- Add python-oslo-messaging requirement +- Add GlusterFS delete patch +- Add systemd patches (not used yet) + +* Tue Apr 15 2014 Eric Harney - 2014.1-0.9.rc3 +- Update to Icehouse RC3 + +* Mon Apr 07 2014 Eric Harney - 2014.1-0.8.rc2 +- Update to Icehouse RC2 +- Icehouse requires newer version of python-six + +* Thu Mar 27 2014 Eric Harney - 2014.1-0.7.rc1 +- Update to Icehouse RC1 + +* Tue Mar 25 2014 Pádraig Brady - 2014.1-0.6.b3 +- Depend on python-rtslib and targetcli rather than scsi-target-utils + +* Fri Mar 21 2014 Pádraig Brady - 2014.1-0.5.b3 +- Use lioadm iSCSI helper rather than tgtadm + +* Sun Mar 16 2014 Eric Harney - 2014.1-0.4.b3 +- Update to Icehouse milestone 3 +- Add deps on python-oslo-rootwrap, python-taskflow + +* Mon Jan 27 2014 Eric Harney - 2014.1-0.3.b2 +- Update to Icehouse milestone 2 + +* Mon Jan 06 2014 Pádraig Brady - 2014.1-0.2.b1 +- Set python-six min version to ensure updated + +* Thu Dec 19 2013 Eric Harney - 2014.1-0.1.b1 +- Update to Icehouse milestone 1 + +* Mon Oct 28 2013 Eric Harney - 2013.2-2 +- Fix GlusterFS volume driver clone operations + +* Thu Oct 17 2013 Eric Harney - 2013.2-1 +- Update to 2013.2 (Havana) +- Restart/remove cinder-backup service during upgrade/uninstallation + +* Wed Oct 16 2013 Eric Harney - 2013.2-0.13.rc3 +- Update to Havana RC3 + +* Fri Oct 11 2013 Eric Harney - 2013.2-0.12.rc2 +- Update to Havana RC2 + +* Tue Oct 08 2013 Eric Harney - 2013.2-0.11.rc1 +- Update to Havana RC1 +- Fix python-novaclient req epoch + +* Mon Sep 23 2013 Eric Harney - 2013.2-0.10.b3 +- Depend on python-novaclient 2.15 + * Wed Sep 18 2013 Eric Harney - 2013.2-0.9.b3 - Add cinder-dist.conf - Tighten permissions on /var/log/cinder @@ -323,33 +370,38 @@ fi - Update to Havana milestone 3 - Add dependency on python-novaclient -* Thu Aug 29 2013 Pádraig Brady - 2013.2-0.7.b2 +* Thu Aug 29 2013 Pádraig Brady - 2013.2-0.7.b2 - Add dependency on sysfsutils to support the fiber channel driver -* Mon Aug 26 2013 Eric Harney - 2013.2-0.5.b2 +* Mon Aug 26 2013 Eric Harney - 2013.2-0.6.b2 - Add cinder-backup service init script -* Mon Jul 22 2013 Pádraig Brady - 2013.2-0.4.b2 +* Sat Aug 03 2013 Fedora Release Engineering - 2013.2-0.5.b2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Mon Jul 22 2013 Pádraig Brady - 2013.2-0.4.b2 - Add dependency on python-suds to support the netapp driver - Add dependency on python-keystoneclient for auth token middleware - Add dependency on qemu-img for volume creation from Glance images -* Sun Jul 21 2013 Pádraig Brady - 2013.2-0.3.b2 +* Sun Jul 21 2013 Pádraig Brady - 2013.2-0.3.b2 - Update to Havana milestone 2 * Thu Jun 13 2013 Eric Harney - 2013.2-0.2.b1 - Update to Havana milestone 1 -* Fri May 10 2013 Eric Harney - 2013.1.1-1 -- Update to Grizzly stable release 1 +* Mon May 13 2013 Eric Harney - 2013.1.1-1 +- Update to Grizzly stable release 1, 2013.1.1 * Mon Apr 08 2013 Eric Harney - 2013.1-2 - Backport fix for GlusterFS driver get_volume_stats -- Adjust to support sqlalchemy-0.8.0 * Thu Apr 04 2013 Eric Harney - 2013.1-1 - Update to Grizzly final release +* Tue Apr 2 2013 Pádraig Brady - 2013.1-0.6.rc3 +- Adjust to support sqlalchemy-0.8.0 + * Wed Mar 27 2013 Eric Harney - 2013.1-0.5.rc3 - Update to Grizzly RC3 release @@ -359,26 +411,40 @@ fi * Mon Mar 18 2013 Eric Harney - 2013.1-0.5.rc1 - Update to Grizzly RC1 release -* Tue Mar 05 2013 Pádraig Brady - 2013.1-0.4.g3 +* Tue Mar 05 2013 Pádraig Brady - 2013.1-0.4.g3 - Add dependency on python-stevedore -* Wed Feb 27 2013 Eric Harney - 2013.1-0.2.g3 +* Mon Feb 25 2013 Eric Harney - 2013.1-0.3.g3 +- Fix build issues with G-3 update + +* Mon Feb 25 2013 Eric Harney - 2013.1-0.2.g3 - Update to Grizzly milestone 3 +* Thu Feb 14 2013 Fedora Release Engineering - 2013.1-0.2.g2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + * Thu Jan 10 2013 Eric Harney - 2013.1-0.1.g2 - Update to Grizzly milestone 2 -* Thu Dec 20 2012 Eric Harney - 2013.1-0.1.g1 +* Thu Nov 29 2012 Eric Harney - 2013.1-0.1.g1 - Update to Grizzly milestone 1 -* Mon Dec 03 2012 Eric Harney - 2012.2.1-1 -- Update to Folsom stable release 1 - -* Wed Nov 14 2012 Eric Harney - 2012.2-4 +* Wed Nov 14 2012 Eric Harney - 2012.2-2 - Remove unused dependency on python-daemon -* Wed Oct 31 2012 Pádraig Brady - 2012.2-3 -- Adjust to be compatible with python-migrate-0.6 +* Thu Sep 27 2012 Pádraig Brady - 2012.2-1 +- Update to Folsom final + +* Fri Sep 21 2012 Pádraig Brady - 2012.2-0.5.rc1 +- Update to Folsom RC1 + +* Fri Sep 21 2012 Pádraig Brady - 2012.2-0.4.f3 +- Fix to ensure that tgt configuration is honored + +* Mon Sep 17 2012 Pádraig Brady - 2012.2-0.3.f3 +- Move user config out of /etc/cinder/api-paste.ini +- Require python-cinderclient + +* Mon Sep 3 2012 Pádraig Brady - 2012.2-0.2.f3 +- Initial release -* Wed Oct 24 2012 Pádraig Brady - 2012.2-2 -- Initial Folsom release -- 2.32.3