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
« 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.
16from http import client as http_client
17from oslo_log import log
18import webob
19from webob import exc
21from oslo_config import cfg
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
32LOG = log.getLogger(__name__)
33CONF = cfg.CONF
36class ShareMetadataController(object):
37 """The share metadata API controller for the OpenStack API."""
39 def __init__(self):
40 self.share_api = share.API()
41 super(ShareMetadataController, self).__init__()
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
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)}
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)
65 context = req.environ['manila.context']
67 new_metadata = self._update_share_metadata(context,
68 share_id,
69 metadata,
70 delete=False)
71 return {'metadata': new_metadata}
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)
80 if id not in meta_item:
81 expl = _('Request body and URI mismatch')
82 raise exc.HTTPBadRequest(explanation=expl)
84 if len(meta_item) > 1:
85 expl = _('Request body contains too many items')
86 raise exc.HTTPBadRequest(explanation=expl)
88 context = req.environ['manila.context']
89 self._update_share_metadata(context,
90 share_id,
91 meta_item,
92 delete=False)
94 return {'meta': meta_item}
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)
103 context = req.environ['manila.context']
105 new_metadata = self._update_share_metadata(
106 context, share_id, metadata, delete=True)
107 return {'metadata': new_metadata}
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 = []
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)
139 api_common.check_metadata_properties(_metadata)
140 db.share_metadata_update(context, share['id'],
141 _metadata, delete)
143 return _metadata
144 except exception.NotFound:
145 msg = _('share does not exist')
146 raise exc.HTTPNotFound(explanation=msg)
148 except (ValueError, AttributeError):
149 msg = _("Malformed request body")
150 raise exc.HTTPBadRequest(explanation=msg)
152 except exception.InvalidMetadata as error:
153 raise exc.HTTPBadRequest(explanation=error.msg)
155 except exception.InvalidMetadataSize as error:
156 raise exc.HTTPBadRequest(explanation=error.msg)
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)
163 try:
164 return {'meta': {id: data[id]}}
165 except KeyError:
166 msg = _("Metadata item was not found")
167 raise exc.HTTPNotFound(explanation=msg)
169 def delete(self, req, share_id, id):
170 """Deletes an existing metadata."""
171 context = req.environ['manila.context']
173 metadata = self._get_metadata(context, share_id)
175 if id not in metadata:
176 msg = _("Metadata item was not found")
177 raise exc.HTTPNotFound(explanation=msg)
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)
198def create_resource():
199 return wsgi.Resource(ShareMetadataController())