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

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. 

18 

19""" 

20 

21import abc 

22 

23from oslo_config import cfg 

24from oslo_utils import importutils 

25from oslo_utils import uuidutils 

26 

27from manila.db import api as db_api 

28from manila.i18n import _ 

29 

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] 

36 

37CONF = cfg.CONF 

38 

39 

40class StorageDriver(metaclass=abc.ABCMeta): 

41 

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 

46 

47 @abc.abstractmethod 

48 def get(self, entity_id, key, default): 

49 """Backend implementation for DriverPrivateData.get() method. 

50 

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'. 

55 

56 See DriverPrivateData.get() method for more details. 

57 """ 

58 

59 @abc.abstractmethod 

60 def update(self, entity_id, details, delete_existing): 

61 """Backend implementation for DriverPrivateData.update() method. 

62 

63 Should update details for given 'entity_id' with behaviour defined 

64 by 'delete_existing' boolean flag. 

65 

66 See DriverPrivateData.update() method for more details. 

67 """ 

68 

69 @abc.abstractmethod 

70 def delete(self, entity_id, key): 

71 """Backend implementation for DriverPrivateData.delete() method. 

72 

73 Should return delete all keys if 'key' is None. 

74 Otherwise should delete value for provided 'key'. 

75 

76 See DriverPrivateData.update() method for more details. 

77 """ 

78 

79 

80class SqlStorageDriver(StorageDriver): 

81 

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 ) 

87 

88 def get(self, entity_id, key, default): 

89 return db_api.driver_private_data_get( 

90 self.context, entity_id, key, default 

91 ) 

92 

93 def delete(self, entity_id, key): 

94 return db_api.driver_private_data_delete( 

95 self.context, entity_id, key 

96 ) 

97 

98 

99class DriverPrivateData(object): 

100 def __init__(self, storage=None, *args, **kwargs): 

101 """Init method. 

102 

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 """ 

108 

109 config_group_name = kwargs.get('config_group') 

110 CONF.register_opts(private_data_opts, group=config_group_name) 

111 

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) 

127 

128 def get(self, entity_id, key=None, default=None): 

129 """Get one, list or all key-value pairs. 

130 

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) 

138 

139 def update(self, entity_id, details, delete_existing=False): 

140 """Update or create specified key-value pairs. 

141 

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) 

151 

152 if not isinstance(details, dict): 

153 msg = (_("Provided details %s is not valid dict.") 

154 % details) 

155 raise ValueError(msg) 

156 

157 return self._storage.update( 

158 entity_id, details, delete_existing) 

159 

160 def delete(self, entity_id, key=None): 

161 """Delete one, list or all key-value pairs. 

162 

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) 

168 

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)