Coverage for manila/api/v2/share_accesses.py: 85%
110 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 2018 Huawei Corporation.
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.
16"""The share accesses api."""
18import ast
20import webob
22from manila.api import common
23from manila.api.openstack import wsgi
24from manila.api.views import share_accesses as share_access_views
25from manila.common import constants
26from manila import exception
27from manila.i18n import _
28from manila.lock import api as resource_locks
29from manila import share
32class ShareAccessesController(wsgi.Controller, wsgi.AdminActionsMixin):
33 """The Share accesses API V2 controller for the OpenStack API."""
35 resource_name = 'share_access_rule'
36 _view_builder_class = share_access_views.ViewBuilder
38 def __init__(self):
39 super(ShareAccessesController, self).__init__()
40 self.share_api = share.API()
41 self.resource_locks_api = resource_locks.API()
43 @wsgi.Controller.api_version('2.45')
44 @wsgi.Controller.authorize('get')
45 def show(self, req, id):
46 """Return data about the given share access rule."""
47 context = req.environ['manila.context']
48 share_access = self._get_share_access(context, id)
49 restricted = self._is_rule_restricted(context, id)
50 if restricted:
51 share_access['restricted'] = True
52 return self._view_builder.view(req, share_access)
54 def _is_rule_restricted(self, context, id):
55 search_opts = {
56 'resource_id': id,
57 'resource_action': constants.RESOURCE_ACTION_SHOW,
58 'resource_type': 'access_rule',
59 'all_projects': True,
60 }
61 locks, count = self.resource_locks_api.get_all(
62 context.elevated(), search_opts, show_count=True)
64 if count:
65 return self.resource_locks_api.access_is_restricted(context,
66 locks[0])
67 return False
69 def _get_share_access(self, context, share_access_id):
70 try:
71 return self.share_api.access_get(context, share_access_id)
72 except exception.NotFound:
73 msg = _("Share access rule %s not found.") % share_access_id
74 raise webob.exc.HTTPNotFound(explanation=msg)
76 def _validate_search_opts(self, req, search_opts):
77 """Check if search opts parameters are valid."""
78 access_type = search_opts.get('access_type', None)
79 access_to = search_opts.get('access_to', None)
81 if access_type and access_type not in ['ip', 'user', 'cert', 'cephx']: 81 ↛ 82line 81 didn't jump to line 82 because the condition on line 81 was never true
82 raise exception.InvalidShareAccessType(type=access_type)
84 # If access_to is present but access type is not, it gets tricky to
85 # validate its content
86 if access_to and not access_type: 86 ↛ 87line 86 didn't jump to line 87 because the condition on line 86 was never true
87 msg = _("'access_type' parameter must be provided when specifying "
88 "'access_to'.")
89 raise exception.InvalidInput(reason=msg)
91 if access_type and access_to: 91 ↛ 92line 91 didn't jump to line 92 because the condition on line 91 was never true
92 common.validate_access(access_type=access_type,
93 access_to=access_to,
94 enable_ceph=True,
95 enable_ipv6=True)
97 access_level = search_opts.get('access_level', None)
98 if access_level and access_level not in constants.ACCESS_LEVELS: 98 ↛ 99line 98 didn't jump to line 99 because the condition on line 98 was never true
99 raise exception.InvalidShareAccessLevel(level=access_level)
101 @wsgi.Controller.authorize('index')
102 def _index(self, req, support_for_access_filters=False):
103 """Returns the list of access rules for a given share."""
104 context = req.environ['manila.context']
105 search_opts = {}
106 search_opts.update(req.GET)
107 if 'share_id' not in search_opts:
108 msg = _("The field 'share_id' has to be specified.")
109 raise webob.exc.HTTPBadRequest(explanation=msg)
110 share_id = search_opts.pop('share_id', None)
112 if 'metadata' in search_opts:
113 search_opts['metadata'] = ast.literal_eval(
114 search_opts['metadata'])
115 if support_for_access_filters:
116 try:
117 self._validate_search_opts(req, search_opts)
118 except (exception.InvalidShareAccessLevel,
119 exception.InvalidShareAccessType) as e:
120 raise webob.exc.HTTPBadRequest(explanation=e.msg)
121 try:
122 share = self.share_api.get(context, share_id)
123 except exception.NotFound:
124 msg = _("Share %s not found.") % share_id
125 raise webob.exc.HTTPBadRequest(explanation=msg)
126 access_rules = self.share_api.access_get_all(
127 context, share, search_opts)
128 rule_list = []
129 for rule in access_rules:
130 restricted = self._is_rule_restricted(context, rule['id'])
131 rule['restricted'] = restricted
132 if (('access_to' in search_opts or 'access_key' in search_opts) 132 ↛ 134line 132 didn't jump to line 134 because the condition on line 132 was never true
133 and restricted):
134 continue
135 rule_list.append(rule)
137 return self._view_builder.list_view(req, rule_list)
139 @wsgi.Controller.api_version('2.45', '2.81')
140 def index(self, req):
141 return self._index(req)
143 @wsgi.Controller.api_version('2.82')
144 def index(self, req): # pylint: disable=function-redefined # noqa F811
145 return self._index(req, support_for_access_filters=True)
147 @wsgi.Controller.api_version('2.88')
148 @wsgi.Controller.authorize('update')
149 def update(self, req, id, body):
150 """Update access_level about the given share access rule."""
151 context = req.environ['manila.context']
152 if not self.is_valid_body(body, 'update_access'):
153 raise webob.exc.HTTPBadRequest()
155 access_data = body['update_access']
156 access_level = access_data.get('access_level', None)
157 if not access_level: 157 ↛ 158line 157 didn't jump to line 158 because the condition on line 157 was never true
158 msg = _("Invalid input. Missing 'access_level' in "
159 "update request.")
160 raise webob.exc.HTTPBadRequest(explanation=msg)
162 if access_level not in constants.ACCESS_LEVELS: 162 ↛ 163line 162 didn't jump to line 163 because the condition on line 162 was never true
163 msg = _("Invalid or unsupported share access "
164 "level: %s.") % access_level
165 raise webob.exc.HTTPBadRequest(explanation=msg)
167 share_access = self._get_share_access(context, id)
168 if access_level == share_access.access_level: 168 ↛ 169line 168 didn't jump to line 169 because the condition on line 168 was never true
169 return self._view_builder.view(req, share_access)
171 share = self.share_api.get(context, share_access.share_id)
172 values = {
173 'access_level': access_level,
174 }
175 access = self.share_api.update_access(
176 context, share, share_access, values)
177 return self._view_builder.view(req, access)
180def create_resource():
181 return wsgi.Resource(ShareAccessesController())