Coverage for manila/api/v2/share_transfer.py: 98%
115 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 (c) 2022 China Telecom Digital Intelligence.
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 transfer api."""
18from http import client as http_client
20from oslo_log import log as logging
21from oslo_utils import strutils
22from oslo_utils import uuidutils
23import webob
24from webob import exc
26from manila.api import common
27from manila.api.openstack import wsgi
28from manila.api.views import transfers as transfer_view
29from manila import exception
30from manila.i18n import _
31from manila.transfer import api as transfer_api
33LOG = logging.getLogger(__name__)
34SHARE_TRANSFER_VERSION = "2.77"
37class ShareTransferController(wsgi.Controller):
38 """The Share Transfer API controller for the OpenStack API."""
40 resource_name = 'share_transfer'
41 _view_builder_class = transfer_view.ViewBuilder
43 def __init__(self):
44 self.transfer_api = transfer_api.API()
45 super(ShareTransferController, self).__init__()
47 @wsgi.Controller.authorize('get')
48 @wsgi.Controller.api_version(SHARE_TRANSFER_VERSION)
49 def show(self, req, id):
50 """Return data about active transfers."""
51 context = req.environ['manila.context']
53 # Not found exception will be handled at the wsgi level
54 transfer = self.transfer_api.get(context, transfer_id=id)
56 return self._view_builder.detail(req, transfer)
58 @wsgi.Controller.api_version(SHARE_TRANSFER_VERSION)
59 def index(self, req):
60 """Returns a summary list of transfers."""
61 return self._get_transfers(req, is_detail=False)
63 @wsgi.Controller.api_version(SHARE_TRANSFER_VERSION)
64 def detail(self, req):
65 """Returns a detailed list of transfers."""
66 return self._get_transfers(req, is_detail=True)
68 @wsgi.Controller.authorize('get_all')
69 def _get_transfers(self, req, is_detail):
70 """Returns a list of transfers, transformed through view builder."""
71 context = req.environ['manila.context']
72 params = req.params.copy()
73 pagination_params = common.get_pagination_params(req)
74 limit, offset = [pagination_params.pop('limit', None),
75 pagination_params.pop('offset', None)]
76 sort_key, sort_dir = common.get_sort_params(params)
78 filters = params
79 key_map = {'name': 'display_name', 'name~': 'display_name~'}
80 for k in key_map:
81 if k in filters: 81 ↛ 82line 81 didn't jump to line 82 because the condition on line 81 was never true
82 filters[key_map[k]] = filters.pop(k)
83 LOG.debug('Listing share transfers.')
85 transfers = self.transfer_api.get_all(context,
86 limit=limit,
87 sort_key=sort_key,
88 sort_dir=sort_dir,
89 filters=filters,
90 offset=offset)
92 if is_detail:
93 transfers = self._view_builder.detail_list(req, transfers)
94 else:
95 transfers = self._view_builder.summary_list(req, transfers)
97 return transfers
99 @wsgi.response(http_client.ACCEPTED)
100 @wsgi.Controller.api_version(SHARE_TRANSFER_VERSION)
101 @wsgi.Controller.authorize('create')
102 def create(self, req, body):
103 """Create a new share transfer."""
104 LOG.debug('Creating new share transfer %s', body)
105 context = req.environ['manila.context']
107 if not self.is_valid_body(body, 'transfer'):
108 msg = _("'transfer' is missing from the request body.")
109 raise exc.HTTPBadRequest(explanation=msg)
111 transfer = body.get('transfer', {})
113 share_id = transfer.get('share_id')
114 if not share_id:
115 msg = _("Must supply 'share_id' attribute.")
116 raise exc.HTTPBadRequest(explanation=msg)
117 if not uuidutils.is_uuid_like(share_id):
118 msg = _("The 'share_id' attribute must be a uuid.")
119 raise exc.HTTPBadRequest(explanation=msg)
121 transfer_name = transfer.get('name')
122 if transfer_name is not None: 122 ↛ 125line 122 didn't jump to line 125 because the condition on line 122 was always true
123 transfer_name = transfer_name.strip()
125 LOG.debug("Creating transfer of share %s", share_id)
127 try:
128 new_transfer = self.transfer_api.create(context, share_id,
129 transfer_name)
130 except exception.Invalid as error:
131 raise exc.HTTPBadRequest(explanation=error.msg)
133 transfer = self._view_builder.create(req,
134 dict(new_transfer))
135 return transfer
137 @wsgi.response(http_client.ACCEPTED)
138 @wsgi.Controller.api_version(SHARE_TRANSFER_VERSION)
139 @wsgi.Controller.authorize('accept')
140 def accept(self, req, id, body):
141 """Accept a new share transfer."""
142 transfer_id = id
143 LOG.debug('Accepting share transfer %s', transfer_id)
144 context = req.environ['manila.context']
146 if not self.is_valid_body(body, 'accept'):
147 msg = _("'accept' is missing from the request body.")
148 raise exc.HTTPBadRequest(explanation=msg)
150 accept = body.get('accept', {})
151 auth_key = accept.get('auth_key')
152 if not auth_key:
153 msg = _("Must supply 'auth_key' while accepting a "
154 "share transfer.")
155 raise exc.HTTPBadRequest(explanation=msg)
157 clear_rules = accept.get('clear_access_rules', False)
158 if clear_rules:
159 try:
160 clear_rules = strutils.bool_from_string(clear_rules,
161 strict=True)
162 except (ValueError, TypeError):
163 msg = (_('Invalid boolean clear_access_rules : %(value)s') %
164 {'value': accept['clear_access_rules']})
165 raise exc.HTTPBadRequest(explanation=msg)
167 LOG.debug("Accepting transfer %s", transfer_id)
169 try:
170 self.transfer_api.accept(
171 context, transfer_id, auth_key, clear_rules=clear_rules)
172 except (exception.ShareSizeExceedsLimit,
173 exception.ShareLimitExceeded,
174 exception.ShareSizeExceedsAvailableQuota,
175 exception.ShareReplicasLimitExceeded,
176 exception.ShareReplicaSizeExceedsAvailableQuota,
177 exception.SnapshotSizeExceedsAvailableQuota,
178 exception.SnapshotLimitExceeded) as e:
179 raise exc.HTTPRequestEntityTooLarge(explanation=e.msg,
180 headers={'Retry-After': '0'})
181 except (exception.InvalidShare,
182 exception.InvalidSnapshot,
183 exception.InvalidAuthKey,
184 exception.TransferNotFound) as error:
185 raise exc.HTTPBadRequest(explanation=error.msg)
187 @wsgi.Controller.api_version(SHARE_TRANSFER_VERSION)
188 @wsgi.Controller.authorize('delete')
189 def delete(self, req, id):
190 """Delete a transfer."""
191 context = req.environ['manila.context']
193 LOG.debug("Delete transfer with id: %s", id)
195 # Not found exception will be handled at the wsgi level
196 self.transfer_api.delete(context, transfer_id=id)
197 return webob.Response(status_int=http_client.OK)
200def create_resource():
201 return wsgi.Resource(ShareTransferController())