Coverage for manila/api/v1/share_metadata.py: 97%

130 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2026-02-18 22:19 +0000

1# Copyright 2011 OpenStack Foundation 

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 

16from http import client as http_client 

17from oslo_log import log 

18import webob 

19from webob import exc 

20 

21from oslo_config import cfg 

22 

23from manila.api import common as api_common 

24from manila.api.openstack import wsgi 

25from manila import db 

26from manila import exception 

27from manila.i18n import _ 

28from manila import policy 

29from manila import share 

30 

31 

32LOG = log.getLogger(__name__) 

33CONF = cfg.CONF 

34 

35 

36class ShareMetadataController(object): 

37 """The share metadata API controller for the OpenStack API.""" 

38 

39 def __init__(self): 

40 self.share_api = share.API() 

41 super(ShareMetadataController, self).__init__() 

42 

43 def _get_metadata(self, context, share_id): 

44 try: 

45 share = self.share_api.get(context, share_id) 

46 rv = db.share_metadata_get(context, share['id']) 

47 meta = dict(rv.items()) 

48 except exception.NotFound: 

49 msg = _('share does not exist') 

50 raise exc.HTTPNotFound(explanation=msg) 

51 return meta 

52 

53 def index(self, req, share_id): 

54 """Returns the list of metadata for a given share.""" 

55 context = req.environ['manila.context'] 

56 return {'metadata': self._get_metadata(context, share_id)} 

57 

58 def create(self, req, share_id, body): 

59 try: 

60 metadata = body['metadata'] 

61 except (KeyError, TypeError): 

62 msg = _("Malformed request body") 

63 raise exc.HTTPBadRequest(explanation=msg) 

64 

65 context = req.environ['manila.context'] 

66 

67 new_metadata = self._update_share_metadata(context, 

68 share_id, 

69 metadata, 

70 delete=False) 

71 return {'metadata': new_metadata} 

72 

73 def update(self, req, share_id, id, body): 

74 try: 

75 meta_item = body['meta'] 

76 except (TypeError, KeyError): 

77 expl = _('Malformed request body') 

78 raise exc.HTTPBadRequest(explanation=expl) 

79 

80 if id not in meta_item: 

81 expl = _('Request body and URI mismatch') 

82 raise exc.HTTPBadRequest(explanation=expl) 

83 

84 if len(meta_item) > 1: 

85 expl = _('Request body contains too many items') 

86 raise exc.HTTPBadRequest(explanation=expl) 

87 

88 context = req.environ['manila.context'] 

89 self._update_share_metadata(context, 

90 share_id, 

91 meta_item, 

92 delete=False) 

93 

94 return {'meta': meta_item} 

95 

96 def update_all(self, req, share_id, body): 

97 try: 

98 metadata = body['metadata'] 

99 except (TypeError, KeyError): 

100 expl = _('Malformed request body') 

101 raise exc.HTTPBadRequest(explanation=expl) 

102 

103 context = req.environ['manila.context'] 

104 

105 new_metadata = self._update_share_metadata( 

106 context, share_id, metadata, delete=True) 

107 return {'metadata': new_metadata} 

108 

109 def _update_share_metadata(self, context, 

110 share_id, metadata, 

111 delete=False): 

112 ignore_keys = getattr(CONF, 'admin_only_metadata', []) 

113 try: 

114 share = self.share_api.get(context, share_id) 

115 if set(metadata).intersection(set(ignore_keys)): 

116 try: 

117 policy.check_policy( 

118 context, 'share', 'update_admin_only_metadata') 

119 except exception.PolicyNotAuthorized: 

120 msg = _("Cannot set or update admin only metadata.") 

121 LOG.exception(msg) 

122 raise exc.HTTPForbidden(explanation=msg) 

123 ignore_keys = [] 

124 

125 rv = db.share_metadata_get(context, share['id']) 

126 orig_meta = dict(rv.items()) 

127 if delete: 

128 _metadata = metadata 

129 for key in ignore_keys: 

130 if key in orig_meta: 130 ↛ 131line 130 didn't jump to line 131 because the condition on line 130 was never true

131 _metadata[key] = orig_meta[key] 

132 else: 

133 metadata_copy = metadata.copy() 

134 for key in ignore_keys: 

135 metadata_copy.pop(key, None) 

136 _metadata = orig_meta.copy() 

137 _metadata.update(metadata_copy) 

138 

139 api_common.check_metadata_properties(_metadata) 

140 db.share_metadata_update(context, share['id'], 

141 _metadata, delete) 

142 

143 return _metadata 

144 except exception.NotFound: 

145 msg = _('share does not exist') 

146 raise exc.HTTPNotFound(explanation=msg) 

147 

148 except (ValueError, AttributeError): 

149 msg = _("Malformed request body") 

150 raise exc.HTTPBadRequest(explanation=msg) 

151 

152 except exception.InvalidMetadata as error: 

153 raise exc.HTTPBadRequest(explanation=error.msg) 

154 

155 except exception.InvalidMetadataSize as error: 

156 raise exc.HTTPBadRequest(explanation=error.msg) 

157 

158 def show(self, req, share_id, id): 

159 """Return a single metadata item.""" 

160 context = req.environ['manila.context'] 

161 data = self._get_metadata(context, share_id) 

162 

163 try: 

164 return {'meta': {id: data[id]}} 

165 except KeyError: 

166 msg = _("Metadata item was not found") 

167 raise exc.HTTPNotFound(explanation=msg) 

168 

169 def delete(self, req, share_id, id): 

170 """Deletes an existing metadata.""" 

171 context = req.environ['manila.context'] 

172 

173 metadata = self._get_metadata(context, share_id) 

174 

175 if id not in metadata: 

176 msg = _("Metadata item was not found") 

177 raise exc.HTTPNotFound(explanation=msg) 

178 

179 try: 

180 share = self.share_api.get(context, share_id) 

181 admin_only_metadata_keys = ( 

182 getattr(CONF, 'admin_only_metadata', set()) 

183 ) 

184 if id in admin_only_metadata_keys: 

185 policy.check_policy(context, 'share', 

186 'update_admin_only_metadata') 

187 db.share_metadata_delete(context, share['id'], id) 

188 except exception.NotFound: 

189 msg = _('share does not exist') 

190 raise exc.HTTPNotFound(explanation=msg) 

191 except exception.PolicyNotAuthorized: 

192 msg = _("Cannot delete admin only metadata.") 

193 LOG.exception(msg) 

194 raise exc.HTTPForbidden(explanation=msg) 

195 return webob.Response(status_int=http_client.OK) 

196 

197 

198def create_resource(): 

199 return wsgi.Resource(ShareMetadataController())