diff --git a/glance_store/_drivers/cinder.py b/glance_store/_drivers/cinder.py index 1a612f8b..f91072c7 100644 --- a/glance_store/_drivers/cinder.py +++ b/glance_store/_drivers/cinder.py @@ -131,7 +131,7 @@ class Store(glance_store.driver.Store): """Cinder backend store adapter.""" - _CAPABILITIES = capabilities.DRIVER_REUSABLE + _CAPABILITIES = capabilities.BitMasks.DRIVER_REUSABLE OPTIONS = _CINDER_OPTS EXAMPLE_URL = "cinder://" diff --git a/glance_store/_drivers/filesystem.py b/glance_store/_drivers/filesystem.py index 7816defd..54601028 100644 --- a/glance_store/_drivers/filesystem.py +++ b/glance_store/_drivers/filesystem.py @@ -149,9 +149,9 @@ class ChunkedFile(object): class Store(glance_store.driver.Store): - _CAPABILITIES = (capabilities.READ_RANDOM | - capabilities.WRITE_ACCESS | - capabilities.DRIVER_REUSABLE) + _CAPABILITIES = (capabilities.BitMasks.READ_RANDOM | + capabilities.BitMasks.WRITE_ACCESS | + capabilities.BitMasks.DRIVER_REUSABLE) OPTIONS = _FILESYSTEM_CONFIGS READ_CHUNKSIZE = 64 * units.Ki WRITE_CHUNKSIZE = READ_CHUNKSIZE diff --git a/glance_store/_drivers/gridfs.py b/glance_store/_drivers/gridfs.py index 85496e57..bfe4e630 100644 --- a/glance_store/_drivers/gridfs.py +++ b/glance_store/_drivers/gridfs.py @@ -81,7 +81,7 @@ class StoreLocation(glance_store.location.StoreLocation): class Store(glance_store.driver.Store): """GridFS adapter""" - _CAPABILITIES = capabilities.RW_ACCESS + _CAPABILITIES = capabilities.BitMasks.RW_ACCESS OPTIONS = _GRIDFS_OPTS EXAMPLE_URL = "gridfs://" diff --git a/glance_store/_drivers/http.py b/glance_store/_drivers/http.py index 886d981a..eef578d3 100644 --- a/glance_store/_drivers/http.py +++ b/glance_store/_drivers/http.py @@ -112,8 +112,8 @@ class Store(glance_store.driver.Store): """An implementation of the HTTP(S) Backend Adapter""" - _CAPABILITIES = (capabilities.READ_ACCESS | - capabilities.DRIVER_REUSABLE) + _CAPABILITIES = (capabilities.BitMasks.READ_ACCESS | + capabilities.BitMasks.DRIVER_REUSABLE) @capabilities.check def get(self, location, offset=0, chunk_size=None, context=None): diff --git a/glance_store/_drivers/rbd.py b/glance_store/_drivers/rbd.py index 6eceb72a..0f93e275 100644 --- a/glance_store/_drivers/rbd.py +++ b/glance_store/_drivers/rbd.py @@ -176,7 +176,7 @@ class ImageIterator(object): class Store(driver.Store): """An implementation of the RBD backend adapter.""" - _CAPABILITIES = capabilities.RW_ACCESS + _CAPABILITIES = capabilities.BitMasks.RW_ACCESS OPTIONS = _RBD_OPTS EXAMPLE_URL = "rbd://///" diff --git a/glance_store/_drivers/s3.py b/glance_store/_drivers/s3.py index f74fdba3..7955f1a2 100644 --- a/glance_store/_drivers/s3.py +++ b/glance_store/_drivers/s3.py @@ -294,7 +294,7 @@ class ChunkedFile(object): class Store(glance_store.driver.Store): """An implementation of the s3 adapter.""" - _CAPABILITIES = capabilities.RW_ACCESS + _CAPABILITIES = capabilities.BitMasks.RW_ACCESS OPTIONS = _S3_OPTS EXAMPLE_URL = "s3://:@//" diff --git a/glance_store/_drivers/sheepdog.py b/glance_store/_drivers/sheepdog.py index 18863ab3..9ee9cc07 100644 --- a/glance_store/_drivers/sheepdog.py +++ b/glance_store/_drivers/sheepdog.py @@ -174,7 +174,8 @@ class ImageIterator(object): class Store(glance_store.driver.Store): """Sheepdog backend adapter.""" - _CAPABILITIES = (capabilities.RW_ACCESS | capabilities.DRIVER_REUSABLE) + _CAPABILITIES = (capabilities.BitMasks.RW_ACCESS | + capabilities.BitMasks.DRIVER_REUSABLE) OPTIONS = _SHEEPDOG_OPTS EXAMPLE_URL = "sheepdog://image" diff --git a/glance_store/_drivers/swift/store.py b/glance_store/_drivers/swift/store.py index b0549315..9f1995ce 100644 --- a/glance_store/_drivers/swift/store.py +++ b/glance_store/_drivers/swift/store.py @@ -375,7 +375,7 @@ Store.OPTIONS = _SWIFT_OPTS + sutils.swift_opts class BaseStore(driver.Store): - _CAPABILITIES = capabilities.RW_ACCESS + _CAPABILITIES = capabilities.BitMasks.RW_ACCESS CHUNKSIZE = 65536 OPTIONS = _SWIFT_OPTS + sutils.swift_opts diff --git a/glance_store/_drivers/vmware_datastore.py b/glance_store/_drivers/vmware_datastore.py index b5cec78c..9309c10b 100644 --- a/glance_store/_drivers/vmware_datastore.py +++ b/glance_store/_drivers/vmware_datastore.py @@ -221,7 +221,7 @@ class StoreLocation(location.StoreLocation): class Store(glance_store.Store): """An implementation of the VMware datastore adapter.""" - _CAPABILITIES = capabilities.RW_ACCESS + _CAPABILITIES = capabilities.BitMasks.RW_ACCESS OPTIONS = _VMWARE_OPTS WRITE_CHUNKSIZE = units.Mi # FIXME(arnaud): re-visit this code once the store API is cleaned up. diff --git a/glance_store/backend.py b/glance_store/backend.py index dac8f201..735e6039 100644 --- a/glance_store/backend.py +++ b/glance_store/backend.py @@ -231,7 +231,7 @@ def get_store_from_scheme(scheme): raise exceptions.UnknownScheme(scheme=scheme) scheme_info = location.SCHEME_TO_CLS_MAP[scheme] store = scheme_info['store'] - if not store.is_capable(capabilities.DRIVER_REUSABLE): + if not store.is_capable(capabilities.BitMasks.DRIVER_REUSABLE): # Driver instance isn't stateless so it can't # be reused safely and need recreation. store_entry = scheme_info['store_entry'] diff --git a/glance_store/capabilities.py b/glance_store/capabilities.py index 704ed5dd..a9878acc 100644 --- a/glance_store/capabilities.py +++ b/glance_store/capabilities.py @@ -19,6 +19,7 @@ import logging import threading import time +import enum from eventlet import tpool from glance_store import exceptions @@ -29,22 +30,34 @@ _STORE_CAPABILITES_UPDATE_SCHEDULING_BOOK = {} _STORE_CAPABILITES_UPDATE_SCHEDULING_LOCK = threading.Lock() LOG = logging.getLogger(__name__) -# Store capability constants -NONE = 0b00000000 -ALL = 0b11111111 -READ_ACCESS = 0b00000001 -READ_OFFSET = 0b00000011 # Included READ_ACCESS -READ_CHUNK = 0b00000101 # Included READ_ACCESS -READ_RANDOM = 0b00000111 # READ_OFFSET | READ_CHUNK -WRITE_ACCESS = 0b00001000 -WRITE_OFFSET = 0b00011000 # Included WRITE_ACCESS -WRITE_CHUNK = 0b00101000 # Included WRITE_ACCESS -WRITE_RANDOM = 0b00111000 # WRITE_OFFSET | WRITE_CHUNK -RW_ACCESS = 0b00001001 # READ_ACCESS | WRITE_ACCESS -RW_OFFSET = 0b00011011 # READ_OFFSET | WRITE_OFFSET -RW_CHUNK = 0b00101101 # READ_CHUNK | WRITE_CHUNK -RW_RANDOM = 0b00111111 # RW_OFFSET | RW_CHUNK -DRIVER_REUSABLE = 0b01000000 # driver is stateless and can be reused safely + +class BitMasks(enum.IntEnum): + NONE = 0b00000000 + ALL = 0b11111111 + READ_ACCESS = 0b00000001 + # Included READ_ACCESS + READ_OFFSET = 0b00000011 + # Included READ_ACCESS + READ_CHUNK = 0b00000101 + # READ_OFFSET | READ_CHUNK + READ_RANDOM = 0b00000111 + WRITE_ACCESS = 0b00001000 + # Included WRITE_ACCESS + WRITE_OFFSET = 0b00011000 + # Included WRITE_ACCESS + WRITE_CHUNK = 0b00101000 + # WRITE_OFFSET | WRITE_CHUNK + WRITE_RANDOM = 0b00111000 + # READ_ACCESS | WRITE_ACCESS + RW_ACCESS = 0b00001001 + # READ_OFFSET | WRITE_OFFSET + RW_OFFSET = 0b00011011 + # READ_CHUNK | WRITE_CHUNK + RW_CHUNK = 0b00101101 + # RW_OFFSET | RW_CHUNK + RW_RANDOM = 0b00111111 + # driver is stateless and can be reused safely + DRIVER_REUSABLE = 0b01000000 class StoreCapability(object): @@ -178,12 +191,16 @@ def check(store_op_fun): if store.conf.glance_store.store_capabilities_update_min_interval > 0: _schedule_capabilities_update(store) + get_capabilities = [ + BitMasks.READ_ACCESS, + BitMasks.READ_OFFSET if kwargs.get('offset') else BitMasks.NONE, + BitMasks.READ_CHUNK if kwargs.get('chunk_size') else BitMasks.NONE + ] + op_cap_map = { - 'get': [READ_ACCESS, - READ_OFFSET if kwargs.get('offset') else NONE, - READ_CHUNK if kwargs.get('chunk_size') else NONE], - 'add': [WRITE_ACCESS], - 'delete': [WRITE_ACCESS]} + 'get': get_capabilities, + 'add': [BitMasks.WRITE_ACCESS], + 'delete': [BitMasks.WRITE_ACCESS]} op_exec_map = { 'get': (exceptions.StoreRandomGetNotSupported diff --git a/glance_store/driver.py b/glance_store/driver.py index b7680a62..c7cf3a59 100644 --- a/glance_store/driver.py +++ b/glance_store/driver.py @@ -70,7 +70,7 @@ class Store(capabilities.StoreCapability): try: self.configure_add() except exceptions.BadStoreConfiguration as e: - self.unset_capabilities(capabilities.WRITE_ACCESS) + self.unset_capabilities(capabilities.BitMasks.WRITE_ACCESS) msg = (_(u"Failed to configure store correctly: %s " "Disabling add method.") % utils.exception_to_str(e)) LOG.warn(msg) diff --git a/requirements.txt b/requirements.txt index 188019f4..8ff82a69 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ oslo.serialization>=1.0.0 # Apache-2.0 oslo.utils>=1.2.0 # Apache-2.0 oslo.concurrency>=1.4.1 # Apache-2.0 stevedore>=0.12 +enum34 python-cinderclient>=1.0.6 diff --git a/tests/unit/test_s3_store.py b/tests/unit/test_s3_store.py index e1ce939d..fcf6f94f 100644 --- a/tests/unit/test_s3_store.py +++ b/tests/unit/test_s3_store.py @@ -489,7 +489,8 @@ class TestStore(base.StoreBaseTest, self.config(**conf) self.store = s3.Store(self.conf) self.store.configure() - return not self.store.is_capable(capabilities.WRITE_ACCESS) + return not self.store.is_capable( + capabilities.BitMasks.WRITE_ACCESS) except Exception: return False return False diff --git a/tests/unit/test_store_capabilities.py b/tests/unit/test_store_capabilities.py index d5a36117..1258481c 100644 --- a/tests/unit/test_store_capabilities.py +++ b/tests/unit/test_store_capabilities.py @@ -19,23 +19,24 @@ from glance_store.tests import base class FakeStoreWithStaticCapabilities(caps.StoreCapability): - _CAPABILITIES = caps.READ_RANDOM | caps.DRIVER_REUSABLE + _CAPABILITIES = caps.BitMasks.READ_RANDOM | caps.BitMasks.DRIVER_REUSABLE class FakeStoreWithDynamicCapabilities(caps.StoreCapability): def __init__(self, *cap_list): super(FakeStoreWithDynamicCapabilities, self).__init__() if not cap_list: - cap_list = [caps.READ_RANDOM, caps.DRIVER_REUSABLE] + cap_list = [caps.BitMasks.READ_RANDOM, + caps.BitMasks.DRIVER_REUSABLE] self.set_capabilities(*cap_list) class FakeStoreWithMixedCapabilities(caps.StoreCapability): - _CAPABILITIES = caps.READ_RANDOM + _CAPABILITIES = caps.BitMasks.READ_RANDOM def __init__(self): super(FakeStoreWithMixedCapabilities, self).__init__() - self.set_capabilities(caps.DRIVER_REUSABLE) + self.set_capabilities(caps.BitMasks.DRIVER_REUSABLE) class TestStoreCapabilitiesChecking(object): @@ -50,9 +51,9 @@ class TestStoreCapabilities(base.StoreBaseTest): def _verify_store_capabilities(self, store): # This function tested is_capable() as well. - self.assertTrue(store.is_capable(caps.READ_RANDOM)) - self.assertTrue(store.is_capable(caps.DRIVER_REUSABLE)) - self.assertFalse(store.is_capable(caps.WRITE_ACCESS)) + self.assertTrue(store.is_capable(caps.BitMasks.READ_RANDOM)) + self.assertTrue(store.is_capable(caps.BitMasks.DRIVER_REUSABLE)) + self.assertFalse(store.is_capable(caps.BitMasks.WRITE_ACCESS)) def test_static_capabilities_setup(self): self._verify_store_capabilities(FakeStoreWithStaticCapabilities()) @@ -65,16 +66,16 @@ class TestStoreCapabilities(base.StoreBaseTest): def test_set_unset_capabilities(self): store = FakeStoreWithStaticCapabilities() - self.assertFalse(store.is_capable(caps.WRITE_ACCESS)) + self.assertFalse(store.is_capable(caps.BitMasks.WRITE_ACCESS)) # Set and unset single capability on one time - store.set_capabilities(caps.WRITE_ACCESS) - self.assertTrue(store.is_capable(caps.WRITE_ACCESS)) - store.unset_capabilities(caps.WRITE_ACCESS) - self.assertFalse(store.is_capable(caps.WRITE_ACCESS)) + store.set_capabilities(caps.BitMasks.WRITE_ACCESS) + self.assertTrue(store.is_capable(caps.BitMasks.WRITE_ACCESS)) + store.unset_capabilities(caps.BitMasks.WRITE_ACCESS) + self.assertFalse(store.is_capable(caps.BitMasks.WRITE_ACCESS)) # Set and unset multiple capabilities on one time - cap_list = [caps.WRITE_ACCESS, caps.WRITE_OFFSET] + cap_list = [caps.BitMasks.WRITE_ACCESS, caps.BitMasks.WRITE_OFFSET] store.set_capabilities(*cap_list) self.assertTrue(store.is_capable(*cap_list)) store.unset_capabilities(*cap_list) @@ -90,54 +91,54 @@ class TestStoreCapabilities(base.StoreBaseTest): # Test read capability store = FakeStoreWithMixedCapabilities() self._verify_store_capabilities(store) - store.unset_capabilities(caps.READ_ACCESS) - cap_list = [caps.READ_ACCESS, caps.READ_OFFSET, - caps.READ_CHUNK, caps.READ_RANDOM] + store.unset_capabilities(caps.BitMasks.READ_ACCESS) + cap_list = [caps.BitMasks.READ_ACCESS, caps.BitMasks.READ_OFFSET, + caps.BitMasks.READ_CHUNK, caps.BitMasks.READ_RANDOM] for cap in cap_list: # To make sure all of them are unsetted. self.assertFalse(store.is_capable(cap)) - self.assertTrue(store.is_capable(caps.DRIVER_REUSABLE)) + self.assertTrue(store.is_capable(caps.BitMasks.DRIVER_REUSABLE)) # Test write capability - store = FakeStoreWithDynamicCapabilities(caps.WRITE_RANDOM, - caps.DRIVER_REUSABLE) - self.assertTrue(store.is_capable(caps.WRITE_RANDOM)) - self.assertTrue(store.is_capable(caps.DRIVER_REUSABLE)) - store.unset_capabilities(caps.WRITE_ACCESS) - cap_list = [caps.WRITE_ACCESS, caps.WRITE_OFFSET, - caps.WRITE_CHUNK, caps.WRITE_RANDOM] + store = FakeStoreWithDynamicCapabilities(caps.BitMasks.WRITE_RANDOM, + caps.BitMasks.DRIVER_REUSABLE) + self.assertTrue(store.is_capable(caps.BitMasks.WRITE_RANDOM)) + self.assertTrue(store.is_capable(caps.BitMasks.DRIVER_REUSABLE)) + store.unset_capabilities(caps.BitMasks.WRITE_ACCESS) + cap_list = [caps.BitMasks.WRITE_ACCESS, caps.BitMasks.WRITE_OFFSET, + caps.BitMasks.WRITE_CHUNK, caps.BitMasks.WRITE_RANDOM] for cap in cap_list: # To make sure all of them are unsetted. self.assertFalse(store.is_capable(cap)) - self.assertTrue(store.is_capable(caps.DRIVER_REUSABLE)) + self.assertTrue(store.is_capable(caps.BitMasks.DRIVER_REUSABLE)) class TestStoreCapabilityConstants(base.StoreBaseTest): def test_one_single_capability_own_one_bit(self): cap_list = [ - caps.READ_ACCESS, - caps.WRITE_ACCESS, - caps.DRIVER_REUSABLE, + caps.BitMasks.READ_ACCESS, + caps.BitMasks.WRITE_ACCESS, + caps.BitMasks.DRIVER_REUSABLE, ] for cap in cap_list: self.assertEqual(1, bin(cap).count('1')) def test_combined_capability_bits(self): check = caps.StoreCapability.contains - check(caps.READ_OFFSET, caps.READ_ACCESS) - check(caps.READ_CHUNK, caps.READ_ACCESS) - check(caps.READ_RANDOM, caps.READ_CHUNK) - check(caps.READ_RANDOM, caps.READ_OFFSET) - check(caps.WRITE_OFFSET, caps.WRITE_ACCESS) - check(caps.WRITE_CHUNK, caps.WRITE_ACCESS) - check(caps.WRITE_RANDOM, caps.WRITE_CHUNK) - check(caps.WRITE_RANDOM, caps.WRITE_OFFSET) - check(caps.RW_ACCESS, caps.READ_ACCESS) - check(caps.RW_ACCESS, caps.WRITE_ACCESS) - check(caps.RW_OFFSET, caps.READ_OFFSET) - check(caps.RW_OFFSET, caps.WRITE_OFFSET) - check(caps.RW_CHUNK, caps.READ_CHUNK) - check(caps.RW_CHUNK, caps.WRITE_CHUNK) - check(caps.RW_RANDOM, caps.READ_RANDOM) - check(caps.RW_RANDOM, caps.WRITE_RANDOM) + check(caps.BitMasks.READ_OFFSET, caps.BitMasks.READ_ACCESS) + check(caps.BitMasks.READ_CHUNK, caps.BitMasks.READ_ACCESS) + check(caps.BitMasks.READ_RANDOM, caps.BitMasks.READ_CHUNK) + check(caps.BitMasks.READ_RANDOM, caps.BitMasks.READ_OFFSET) + check(caps.BitMasks.WRITE_OFFSET, caps.BitMasks.WRITE_ACCESS) + check(caps.BitMasks.WRITE_CHUNK, caps.BitMasks.WRITE_ACCESS) + check(caps.BitMasks.WRITE_RANDOM, caps.BitMasks.WRITE_CHUNK) + check(caps.BitMasks.WRITE_RANDOM, caps.BitMasks.WRITE_OFFSET) + check(caps.BitMasks.RW_ACCESS, caps.BitMasks.READ_ACCESS) + check(caps.BitMasks.RW_ACCESS, caps.BitMasks.WRITE_ACCESS) + check(caps.BitMasks.RW_OFFSET, caps.BitMasks.READ_OFFSET) + check(caps.BitMasks.RW_OFFSET, caps.BitMasks.WRITE_OFFSET) + check(caps.BitMasks.RW_CHUNK, caps.BitMasks.READ_CHUNK) + check(caps.BitMasks.RW_CHUNK, caps.BitMasks.WRITE_CHUNK) + check(caps.BitMasks.RW_RANDOM, caps.BitMasks.READ_RANDOM) + check(caps.BitMasks.RW_RANDOM, caps.BitMasks.WRITE_RANDOM) diff --git a/tests/unit/test_swift_store.py b/tests/unit/test_swift_store.py index e5579477..253fc52b 100644 --- a/tests/unit/test_swift_store.py +++ b/tests/unit/test_swift_store.py @@ -761,7 +761,8 @@ class SwiftTests(object): try: self.config(**conf) self.store = Store(self.conf) - return not self.store.is_capable(capabilities.WRITE_ACCESS) + return not self.store.is_capable( + capabilities.BitMasks.WRITE_ACCESS) except Exception: return False return False @@ -775,7 +776,8 @@ class SwiftTests(object): 'authurl.com', 'user': '', 'key': ''}} self.store.configure() - self.assertFalse(self.store.is_capable(capabilities.WRITE_ACCESS)) + self.assertFalse(self.store.is_capable( + capabilities.BitMasks.WRITE_ACCESS)) def test_no_auth_address(self): """ @@ -786,7 +788,8 @@ class SwiftTests(object): '', 'user': 'user1', 'key': 'key1'}} self.store.configure() - self.assertFalse(self.store.is_capable(capabilities.WRITE_ACCESS)) + self.assertFalse(self.store.is_capable( + capabilities.BitMasks.WRITE_ACCESS)) def test_delete(self): """