Coverage for manila/share/drivers_private_data.py: 97%
57 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright 2015 Mirantis inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15"""
16Module provides possibility for share drivers to store private information
17related to common Manila models like Share or Snapshot.
19"""
21import abc
23from oslo_config import cfg
24from oslo_utils import importutils
25from oslo_utils import uuidutils
27from manila.db import api as db_api
28from manila.i18n import _
30private_data_opts = [
31 cfg.StrOpt(
32 'drivers_private_storage_class',
33 default='manila.share.drivers_private_data.SqlStorageDriver',
34 help='The full class name of the Private Data Driver class to use.'),
35]
37CONF = cfg.CONF
40class StorageDriver(metaclass=abc.ABCMeta):
42 def __init__(self, context, backend_host):
43 # Backend shouldn't access data stored by another backend
44 self.backend_host = backend_host
45 self.context = context
47 @abc.abstractmethod
48 def get(self, entity_id, key, default):
49 """Backend implementation for DriverPrivateData.get() method.
51 Should return all keys for given 'entity_id' if 'key' is None.
52 Otherwise should return value for provided 'key'.
53 If values for provided 'entity_id' or 'key' not found,
54 should return 'default'.
56 See DriverPrivateData.get() method for more details.
57 """
59 @abc.abstractmethod
60 def update(self, entity_id, details, delete_existing):
61 """Backend implementation for DriverPrivateData.update() method.
63 Should update details for given 'entity_id' with behaviour defined
64 by 'delete_existing' boolean flag.
66 See DriverPrivateData.update() method for more details.
67 """
69 @abc.abstractmethod
70 def delete(self, entity_id, key):
71 """Backend implementation for DriverPrivateData.delete() method.
73 Should return delete all keys if 'key' is None.
74 Otherwise should delete value for provided 'key'.
76 See DriverPrivateData.update() method for more details.
77 """
80class SqlStorageDriver(StorageDriver):
82 def update(self, entity_id, details, delete_existing):
83 return db_api.driver_private_data_update(
84 self.context, entity_id, details,
85 delete_existing
86 )
88 def get(self, entity_id, key, default):
89 return db_api.driver_private_data_get(
90 self.context, entity_id, key, default
91 )
93 def delete(self, entity_id, key):
94 return db_api.driver_private_data_delete(
95 self.context, entity_id, key
96 )
99class DriverPrivateData(object):
100 def __init__(self, storage=None, *args, **kwargs):
101 """Init method.
103 :param storage: None or inheritor of StorageDriver abstract class
104 :param config_group: Optional -- Config group used for loading settings
105 :param context: Optional -- Current context
106 :param backend_host: Optional -- Driver host
107 """
109 config_group_name = kwargs.get('config_group')
110 CONF.register_opts(private_data_opts, group=config_group_name)
112 if storage is not None:
113 self._storage = storage
114 elif 'context' in kwargs and 'backend_host' in kwargs:
115 if config_group_name: 115 ↛ 116line 115 didn't jump to line 116 because the condition on line 115 was never true
116 conf = getattr(CONF, config_group_name)
117 else:
118 conf = CONF
119 storage_class = conf.drivers_private_storage_class
120 cls = importutils.import_class(storage_class)
121 self._storage = cls(kwargs.get('context'),
122 kwargs.get('backend_host'))
123 else:
124 msg = _("You should provide 'storage' parameter or"
125 " 'context' and 'backend_host' parameters.")
126 raise ValueError(msg)
128 def get(self, entity_id, key=None, default=None):
129 """Get one, list or all key-value pairs.
131 :param entity_id: Model UUID
132 :param key: Key string or list of keys
133 :param default: Default value for case when key(s) not found
134 :returns: string or dict
135 """
136 self._validate_entity_id(entity_id)
137 return self._storage.get(entity_id, key, default)
139 def update(self, entity_id, details, delete_existing=False):
140 """Update or create specified key-value pairs.
142 :param entity_id: Model UUID
143 :param details: dict with key-value pairs data. Keys and values should
144 be strings.
145 :param delete_existing: boolean flag which determines behaviour
146 for existing key-value pairs:
147 True - remove all existing key-value pairs
148 False (default) - leave as is
149 """
150 self._validate_entity_id(entity_id)
152 if not isinstance(details, dict):
153 msg = (_("Provided details %s is not valid dict.")
154 % details)
155 raise ValueError(msg)
157 return self._storage.update(
158 entity_id, details, delete_existing)
160 def delete(self, entity_id, key=None):
161 """Delete one, list or all key-value pairs.
163 :param entity_id: Model UUID
164 :param key: Key string or list of keys
165 """
166 self._validate_entity_id(entity_id)
167 return self._storage.delete(entity_id, key)
169 @staticmethod
170 def _validate_entity_id(entity_id):
171 if not uuidutils.is_uuid_like(entity_id):
172 msg = (_("Provided entity_id %s is not valid UUID.")
173 % entity_id)
174 raise ValueError(msg)