Difference between revisions of "Manila/Provide private data storage API for drivers"
m (Igor Malinovskiy moved page Manila/limited data API for driver to Manila/Limited share data API for drivers) |
|||
(11 intermediate revisions by 2 users not shown) | |||
Line 2: | Line 2: | ||
===Problem === | ===Problem === | ||
− | Drivers haven’t possibility to store | + | Drivers haven’t possibility to store key/value pairs in the database for shares/snapshots/etc. These values are not visible to the tenants, they're just for the drivers. |
===Use cases === | ===Use cases === | ||
Line 9: | Line 9: | ||
===Concept=== | ===Concept=== | ||
− | Provide | + | Provide private data storage (key-value) for drivers: |
− | + | ||
− | |||
<source lang="python" > | <source lang="python" > | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | class StorageDriver(object): | |
− | + | def __init__(self, backend_host): | |
+ | # Backend cannot access data stored by another backend | ||
+ | self.backend_host = backend_host | ||
− | + | def details_get(self, namespace_name, entity_id, key, default): | |
− | + | raise NotImplementedError() | |
+ | |||
+ | def details_update(self, namespace_name, entity_id, details, | ||
+ | delete_existing): | ||
+ | raise NotImplementedError() | ||
+ | |||
+ | def details_delete(self, namespace_name, entity_id, key): | ||
+ | raise NotImplementedError() | ||
+ | |||
+ | |||
+ | class SqlStorageDriver(StorageDriver): | ||
+ | pass | ||
+ | |||
+ | |||
+ | class PrivateDriverData(object): | ||
+ | |||
+ | def __init__(self, context, storage): | ||
+ | self.storage = storage | ||
+ | self.context = context | ||
+ | |||
+ | def details_get(self, entity_id, key=None, default=None): | ||
+ | return self.storage.details_get(entity_id, key, default) | ||
+ | |||
+ | def details_update(self, entity_id, details, delete_existing=False): | ||
+ | return self.storage.details_update( | ||
+ | entity_id, details, delete_existing) | ||
+ | |||
+ | def details_delete(self, entity_id, key=None): | ||
+ | return self.storage.details_delete(entity_id, key) | ||
</source> | </source> | ||
Line 35: | Line 59: | ||
def __init__(self, share_driver=None, service_name=None, *args, **kwargs): | def __init__(self, share_driver=None, service_name=None, *args, **kwargs): | ||
# … | # … | ||
− | self. | + | self.private_driver_storage = PrivateDriverData( |
+ | # … | ||
+ | ) | ||
self.driver = importutils.import_object( | self.driver = importutils.import_object( | ||
share_driver, | share_driver, | ||
− | self. | + | self.private_driver_storage, |
#... | #... | ||
) | ) | ||
Line 44: | Line 70: | ||
</source> | </source> | ||
+ | And use in drivers: | ||
− | + | <source lang="python"> | |
+ | # Get data | ||
+ | share_data = self.data_storage.details_get(share_id) # Get all data | ||
+ | volume_id = self.data_storage.details_get(share_id, 'volume_id') # Get single key | ||
− | + | # Update | |
− | + | self.data_storage.details_update(share_id, {'foo': 'bar'}) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | # Delete | |
− | + | self.data_storage.details_delete(share_id, 'foo') # Delete single key | |
− | + | self.data_storage.details_delete(share_id) # Delete all | |
</source> | </source> | ||
− | |||
− | + | This storage will allow to get/update/delete private data of any entity managed by the driver. Drivers will be able to create mappings between data in manila (Share) and backends (NAS). Also, drivers could use this storage for caching purposes - to minimize an amount of requests to the backend. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Default implementation will store data in separate table in Manila database: | |
− | + | <source lang="sql"> | |
− | + | CREATE TABLE private_drivers_data | |
− | + | ( | |
− | + | created_at DATETIME, | |
− | + | updated_at DATETIME, | |
− | + | deleted_at DATETIME, | |
+ | deleted INT, | ||
+ | host VARCHAR(255) NOT NULL, # Backend name | ||
+ | entity_id VARCHAR(36) NOT NULL, # Entity UUID | ||
+ | `key` VARCHAR(255) NOT NULL, | ||
+ | value VARCHAR(1023) NOT NULL, | ||
+ | PRIMARY KEY(host, entity_id, key) | ||
+ | ); | ||
</source> | </source> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
===DB scaling risks=== | ===DB scaling risks=== | ||
By default, all private share data will be stored in manila SQL DB and we have a risk that DB becomes a bottleneck in large deployments. This risk (in a scope of this feature) can be addressed by implementation of different storage backends for this interface. As we can see backends don’t share data, so storage can be easily horizontally scaled. We can move private share data to any distributed key-value storage. | By default, all private share data will be stored in manila SQL DB and we have a risk that DB becomes a bottleneck in large deployments. This risk (in a scope of this feature) can be addressed by implementation of different storage backends for this interface. As we can see backends don’t share data, so storage can be easily horizontally scaled. We can move private share data to any distributed key-value storage. |
Latest revision as of 10:23, 21 April 2015
Contents
Provide limited data API for drivers
Problem
Drivers haven’t possibility to store key/value pairs in the database for shares/snapshots/etc. These values are not visible to the tenants, they're just for the drivers.
Use cases
Use case #1: Generic driver should store volume id instead of renaming volume (current behaviour)
Use case #2: Some backends that can't create 32-character share names and need to maintain a mapping from the 128-bit UUID to something smaller.
Concept
Provide private data storage (key-value) for drivers:
class StorageDriver(object):
def __init__(self, backend_host):
# Backend cannot access data stored by another backend
self.backend_host = backend_host
def details_get(self, namespace_name, entity_id, key, default):
raise NotImplementedError()
def details_update(self, namespace_name, entity_id, details,
delete_existing):
raise NotImplementedError()
def details_delete(self, namespace_name, entity_id, key):
raise NotImplementedError()
class SqlStorageDriver(StorageDriver):
pass
class PrivateDriverData(object):
def __init__(self, context, storage):
self.storage = storage
self.context = context
def details_get(self, entity_id, key=None, default=None):
return self.storage.details_get(entity_id, key, default)
def details_update(self, entity_id, details, delete_existing=False):
return self.storage.details_update(
entity_id, details, delete_existing)
def details_delete(self, entity_id, key=None):
return self.storage.details_delete(entity_id, key)
Provide this storage in the manager to all drivers:
class ShareManager(manager.SchedulerDependentManager):
# …
def __init__(self, share_driver=None, service_name=None, *args, **kwargs):
# …
self.private_driver_storage = PrivateDriverData(
# …
)
self.driver = importutils.import_object(
share_driver,
self.private_driver_storage,
#...
)
# ...
And use in drivers:
# Get data
share_data = self.data_storage.details_get(share_id) # Get all data
volume_id = self.data_storage.details_get(share_id, 'volume_id') # Get single key
# Update
self.data_storage.details_update(share_id, {'foo': 'bar'})
# Delete
self.data_storage.details_delete(share_id, 'foo') # Delete single key
self.data_storage.details_delete(share_id) # Delete all
This storage will allow to get/update/delete private data of any entity managed by the driver. Drivers will be able to create mappings between data in manila (Share) and backends (NAS). Also, drivers could use this storage for caching purposes - to minimize an amount of requests to the backend.
Default implementation will store data in separate table in Manila database:
CREATE TABLE private_drivers_data
(
created_at DATETIME,
updated_at DATETIME,
deleted_at DATETIME,
deleted INT,
host VARCHAR(255) NOT NULL, # Backend name
entity_id VARCHAR(36) NOT NULL, # Entity UUID
`key` VARCHAR(255) NOT NULL,
value VARCHAR(1023) NOT NULL,
PRIMARY KEY(host, entity_id, key)
);
DB scaling risks
By default, all private share data will be stored in manila SQL DB and we have a risk that DB becomes a bottleneck in large deployments. This risk (in a scope of this feature) can be addressed by implementation of different storage backends for this interface. As we can see backends don’t share data, so storage can be easily horizontally scaled. We can move private share data to any distributed key-value storage.