Coverage for manila/api/v2/resource_locks.py: 91%
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# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
13"""The resource_locks API controller module.
15This module handles the following requests:
16GET /resource-locks
17GET /resource-locks/{lock_id}
18POST /resource-locks
19PUT /resource-locks/{lock_id}
20DELETE /resource-locks/{lock_id}
21"""
23from http import client as http_client
25from oslo_utils import timeutils
26from oslo_utils import uuidutils
27import webob
28from webob import exc
30from manila.api import common
31from manila.api.openstack import wsgi
32from manila.api.schemas import resource_locks as schema
33from manila.api import validation
34from manila.api.views import resource_locks as resource_locks_view
35from manila.common import constants
36from manila import exception
37from manila.i18n import _
38from manila.lock import api as resource_locks
39from manila import utils
41RESOURCE_LOCKS_MIN_API_VERSION = '2.81'
44@validation.validated
45class ResourceLocksController(wsgi.Controller):
46 """The Resource Locks API controller for the OpenStack API."""
48 _view_builder_class = resource_locks_view.ViewBuilder
49 resource_name = 'resource_lock'
51 def _check_body(self, body, lock_to_update=None):
52 if 'resource_lock' not in body:
53 raise exc.HTTPBadRequest(
54 explanation="Malformed request body.")
55 lock_data = body['resource_lock']
56 resource_type = (
57 lock_to_update['resource_type']
58 if lock_to_update
59 else lock_data.get('resource_type', constants.SHARE_RESOURCE_TYPE)
60 )
61 resource_id = lock_data.get('resource_id') or ''
62 resource_action = (lock_data.get('resource_action') or
63 constants.RESOURCE_ACTION_DELETE)
64 lock_reason = lock_data.get('lock_reason') or ''
66 if len(lock_reason) > 1023:
67 msg = _("'lock_reason' can contain a maximum of 1023 characters.")
68 raise exc.HTTPBadRequest(explanation=msg)
69 if resource_type not in constants.RESOURCE_LOCK_RESOURCE_TYPES:
70 msg = _("'resource_type' is required and must be one "
71 "of %(resource_types)s") % {
72 'resource_types': constants.RESOURCE_LOCK_RESOURCE_TYPES
73 }
74 raise exc.HTTPBadRequest(explanation=msg)
75 resource_type_lock_actions = (
76 constants.RESOURCE_LOCK_ACTIONS_MAPPING[resource_type])
77 if resource_action not in resource_type_lock_actions:
78 msg = _("'resource_action' can only be one of %(actions)s" %
79 {'actions': resource_type_lock_actions})
80 raise exc.HTTPBadRequest(explanation=msg)
82 if lock_to_update:
83 if set(lock_data.keys()) - {'resource_action', 'lock_reason'}:
84 msg = _("Only 'resource_action' and 'lock_reason' "
85 "can be updated.")
86 raise exc.HTTPBadRequest(explanation=msg)
87 else:
88 if not uuidutils.is_uuid_like(resource_id):
89 msg = _("Resource ID is required and must be in uuid format.")
90 raise exc.HTTPBadRequest(explanation=msg)
92 def __init__(self):
93 self.resource_locks_api = resource_locks.API()
94 super(ResourceLocksController, self).__init__()
96 @wsgi.Controller.api_version(RESOURCE_LOCKS_MIN_API_VERSION)
97 @wsgi.Controller.authorize('get_all')
98 @validation.request_query_schema(schema.index_request_query)
99 @validation.response_body_schema(schema.index_response_body)
100 def index(self, req):
101 """Returns a list of locks, transformed through view builder."""
102 context = req.environ['manila.context']
103 filters = req.params.copy()
105 params = common.get_pagination_params(req)
106 limit, offset = [params.pop('limit', None), params.pop('offset', None)]
107 sort_key, sort_dir = common.get_sort_params(filters)
108 for key in ('limit', 'offset'):
109 filters.pop(key, None)
111 show_count = utils.get_bool_from_api_params(
112 'with_count', {'with_count': filters.pop('with_count', False)})
114 for time_comparison_filter in ['created_since', 'created_before']:
115 if time_comparison_filter in filters: 115 ↛ 116line 115 didn't jump to line 116 because the condition on line 115 was never true
116 time_str = filters.get(time_comparison_filter)
117 try:
118 parsed_time = timeutils.parse_isotime(time_str)
119 filters[time_comparison_filter] = parsed_time
120 except ValueError:
121 msg = _('Invalid value specified for the query '
122 'key: %s') % time_comparison_filter
123 raise exc.HTTPBadRequest(explanation=msg)
125 locks, count = self.resource_locks_api.get_all(context,
126 search_opts=filters,
127 limit=limit,
128 offset=offset,
129 sort_key=sort_key,
130 sort_dir=sort_dir,
131 show_count=show_count)
133 return self._view_builder.index(req,
134 locks,
135 count=count)
137 @wsgi.Controller.api_version(RESOURCE_LOCKS_MIN_API_VERSION)
138 @wsgi.Controller.authorize('get')
139 @validation.request_query_schema(schema.show_request_query)
140 @validation.response_body_schema(schema.show_response_body)
141 def show(self, req, id):
142 """Return an existing resource lock by ID."""
143 context = req.environ['manila.context']
144 try:
145 resource_lock = self.resource_locks_api.get(context, id)
146 except exception.ResourceLockNotFound as error:
147 raise exc.HTTPNotFound(explanation=error.msg)
148 return self._view_builder.detail(req, resource_lock)
150 @wsgi.Controller.api_version(RESOURCE_LOCKS_MIN_API_VERSION)
151 @wsgi.Controller.authorize
152 @wsgi.action("delete")
153 @validation.response_body_schema(schema.delete_response_body)
154 def delete(self, req, id):
155 """Delete an existing resource lock."""
156 context = req.environ['manila.context']
157 try:
158 self.resource_locks_api.delete(context, id)
159 except exception.ResourceLockNotFound as error:
160 raise exc.HTTPNotFound(explanation=error.msg)
161 return webob.Response(status_int=http_client.NO_CONTENT)
163 @wsgi.Controller.api_version(RESOURCE_LOCKS_MIN_API_VERSION)
164 @wsgi.Controller.authorize
165 @validation.request_body_schema(schema.create_request_body)
166 @validation.response_body_schema(schema.create_response_body)
167 def create(self, req, body):
168 """Create a resource lock."""
169 context = req.environ['manila.context']
170 self._check_body(body)
171 lock_data = body['resource_lock']
172 try:
173 resource_lock = self.resource_locks_api.create(
174 context,
175 resource_id=lock_data['resource_id'],
176 resource_type=lock_data['resource_type'],
177 resource_action=(lock_data.get('resource_action') or
178 constants.RESOURCE_ACTION_DELETE),
179 lock_reason=lock_data.get('lock_reason')
180 )
181 except exception.NotFound:
182 raise exc.HTTPBadRequest(
183 explanation="No such resource found.")
184 except exception.InvalidInput as error:
185 raise exc.HTTPConflict(explanation=error.msg)
186 except exception.ResourceVisibilityLockExists:
187 raise exc.HTTPConflict(
188 "Resource's visibility is already locked by other user.")
189 return self._view_builder.detail(req, resource_lock)
191 @wsgi.Controller.api_version(RESOURCE_LOCKS_MIN_API_VERSION)
192 @wsgi.Controller.authorize
193 @validation.request_body_schema(schema.update_request_body)
194 @validation.response_body_schema(schema.update_response_body)
195 def update(self, req, id, body):
196 """Update an existing resource lock."""
197 context = req.environ['manila.context']
198 try:
199 resource_lock = self.resource_locks_api.get(context, id)
200 except exception.NotFound as e:
201 raise exc.HTTPNotFound(explanation=e.msg)
203 self._check_body(body, lock_to_update=resource_lock)
204 lock_data = body['resource_lock']
205 try:
206 resource_lock = self.resource_locks_api.update(
207 context,
208 resource_lock,
209 lock_data,
210 )
211 except exception.InvalidInput as e:
212 raise exc.HTTPBadRequest(explanation=e.msg)
213 return self._view_builder.detail(req, resource_lock)
216def create_resource():
217 return wsgi.Resource(ResourceLocksController())