Coverage for manila/db/sqlalchemy/api.py: 87%

3720 statements  

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

1# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. 

2# Copyright 2010 United States Government as represented by the 

3# Administrator of the National Aeronautics and Space Administration. 

4# Copyright (c) 2014 Mirantis, Inc. 

5# All Rights Reserved. 

6# 

7# Licensed under the Apache License, Version 2.0 (the "License"); you may 

8# not use this file except in compliance with the License. You may obtain 

9# a copy of the License at 

10# 

11# http://www.apache.org/licenses/LICENSE-2.0 

12# 

13# Unless required by applicable law or agreed to in writing, software 

14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 

15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 

16# License for the specific language governing permissions and limitations 

17# under the License. 

18 

19"""Implementation of SQLAlchemy backend.""" 

20 

21import copy 

22import datetime 

23from functools import wraps 

24import ipaddress 

25import sys 

26import warnings 

27 

28# NOTE(uglide): Required to override default oslo_db Query class 

29import manila.db.sqlalchemy.query # noqa 

30 

31from oslo_config import cfg 

32from oslo_db import api as oslo_db_api 

33from oslo_db import exception as db_exc 

34from oslo_db import exception as db_exception 

35from oslo_db import options as db_options 

36from oslo_db.sqlalchemy import enginefacade 

37from oslo_db.sqlalchemy import utils as db_utils 

38from oslo_log import log 

39from oslo_utils import excutils 

40from oslo_utils import importutils 

41from oslo_utils import strutils 

42from oslo_utils import timeutils 

43from oslo_utils import uuidutils 

44import sqlalchemy as sa 

45from sqlalchemy import and_ 

46from sqlalchemy import MetaData 

47from sqlalchemy import or_ 

48from sqlalchemy import orm 

49from sqlalchemy.sql.expression import false 

50from sqlalchemy.sql.expression import literal 

51from sqlalchemy.sql.expression import true 

52from sqlalchemy.sql import func 

53 

54from manila.common import constants 

55from manila.db.sqlalchemy import models 

56from manila.db.sqlalchemy import utils 

57from manila import exception 

58from manila.i18n import _ 

59from manila import quota 

60 

61osprofiler_sqlalchemy = importutils.try_import('osprofiler.sqlalchemy') 

62 

63CONF = cfg.CONF 

64CONF.import_group("profiler", "manila.service") 

65 

66LOG = log.getLogger(__name__) 

67QUOTAS = quota.QUOTAS 

68 

69_DEFAULT_QUOTA_NAME = 'default' 

70PER_PROJECT_QUOTAS = [] 

71 

72_DEFAULT_SQL_CONNECTION = 'sqlite://' 

73db_options.set_defaults(cfg.CONF, 

74 connection=_DEFAULT_SQL_CONNECTION) 

75 

76 

77context_manager = enginefacade.transaction_context() 

78 

79context_manager.configure() 

80 

81if ( 81 ↛ 86line 81 didn't jump to line 86 because the condition on line 81 was never true

82 osprofiler_sqlalchemy and 

83 CONF.profiler.enabled and 

84 CONF.profiler.trace_sqlalchemy 

85): 

86 context_manager.append_on_engine_create( 

87 lambda engine: osprofiler_sqlalchemy.add_tracing(sa, engine, "db")) 

88 

89 

90def get_engine(): 

91 return context_manager.writer.get_engine() 

92 

93 

94def get_backend(): 

95 """The backend is this module itself.""" 

96 

97 return sys.modules[__name__] 

98 

99 

100def is_admin_context(context): 

101 """Indicates if the request context is an administrator.""" 

102 if not context: 102 ↛ 103line 102 didn't jump to line 103 because the condition on line 102 was never true

103 warnings.warn(_('Use of empty request context is deprecated'), 

104 DeprecationWarning) 

105 raise Exception('die') 

106 return context.is_admin 

107 

108 

109def is_user_context(context): 

110 """Indicates if the request context is a normal user.""" 

111 if not context: 111 ↛ 112line 111 didn't jump to line 112 because the condition on line 111 was never true

112 return False 

113 if context.is_admin: 

114 return False 

115 if not context.user_id or not context.project_id: 

116 return False 

117 return True 

118 

119 

120def authorize_project_context(context, project_id): 

121 """Ensures a request has permission to access the given project.""" 

122 if is_user_context(context): 

123 if not context.project_id: 123 ↛ 124line 123 didn't jump to line 124 because the condition on line 123 was never true

124 raise exception.NotAuthorized() 

125 elif context.project_id != project_id: 125 ↛ 126line 125 didn't jump to line 126 because the condition on line 125 was never true

126 raise exception.NotAuthorized() 

127 

128 

129def authorize_user_context(context, user_id): 

130 """Ensures a request has permission to access the given user.""" 

131 if is_user_context(context): 

132 if not context.user_id: 

133 raise exception.NotAuthorized() 

134 elif context.user_id != user_id: 

135 raise exception.NotAuthorized() 

136 

137 

138def authorize_quota_class_context(context, class_name): 

139 """Ensures a request has permission to access the given quota class.""" 

140 if is_user_context(context): 140 ↛ 141line 140 didn't jump to line 141 because the condition on line 140 was never true

141 if not context.quota_class: 

142 raise exception.NotAuthorized() 

143 elif context.quota_class != class_name: 

144 raise exception.NotAuthorized() 

145 

146 

147def require_admin_context(f): 

148 """Decorator to require admin request context. 

149 

150 The first argument to the wrapped function must be the context. 

151 

152 """ 

153 @wraps(f) 

154 def wrapper(*args, **kwargs): 

155 if not is_admin_context(args[0]): 

156 raise exception.AdminRequired() 

157 return f(*args, **kwargs) 

158 return wrapper 

159 

160 

161def require_context(f): 

162 """Decorator to require *any* user or admin context. 

163 

164 This does no authorization for user or project access matching, see 

165 :py:func:`authorize_project_context` and 

166 :py:func:`authorize_user_context`. 

167 

168 The first argument to the wrapped function must be the context. 

169 

170 """ 

171 @wraps(f) 

172 def wrapper(*args, **kwargs): 

173 if not is_admin_context(args[0]) and not is_user_context(args[0]): 

174 raise exception.NotAuthorized() 

175 return f(*args, **kwargs) 

176 return wrapper 

177 

178 

179def require_share_exists(f): 

180 """Decorator to require the specified share to exist. 

181 

182 Requires the wrapped function to use context and share_id as 

183 their first two arguments. 

184 """ 

185 @wraps(f) 

186 def wrapper(context, share_id, *args, **kwargs): 

187 share_get(context, share_id) 

188 return f(context, share_id, *args, **kwargs) 

189 wrapper.__name__ = f.__name__ 

190 return wrapper 

191 

192 

193def require_share_snapshot_exists(f): 

194 """Decorator to require the specified share snapshot to exist. 

195 

196 Requires the wrapped function to use context and share_snapshot_id as 

197 their first two arguments. 

198 """ 

199 @wraps(f) 

200 def wrapper(context, share_snapshot_id, *args, **kwargs): 

201 share_snapshot_get(context, share_snapshot_id) 

202 return f(context, share_snapshot_id, *args, **kwargs) 

203 wrapper.__name__ = f.__name__ 

204 return wrapper 

205 

206 

207def require_share_network_subnet_exists(f): 

208 """Decorator to require the specified share network subnet to exist. 

209 

210 Requires the wrapped function to use context and share_network_subnet_id 

211 as their first two arguments. 

212 """ 

213 @wraps(f) 

214 def wrapper(context, share_network_subnet_id, *args, **kwargs): 

215 share_network_subnet_get(context, share_network_subnet_id) 

216 return f(context, share_network_subnet_id, *args, **kwargs) 

217 wrapper.__name__ = f.__name__ 

218 return wrapper 

219 

220 

221def require_share_instance_exists(f): 

222 """Decorator to require the specified share instance to exist. 

223 

224 Requires the wrapped function to use context and share_instance_id as 

225 their first two arguments. 

226 """ 

227 @wraps(f) 

228 def wrapper(context, share_instance_id, *args, **kwargs): 

229 share_instance_get(context, share_instance_id) 

230 return f(context, share_instance_id, *args, **kwargs) 

231 wrapper.__name__ = f.__name__ 

232 return wrapper 

233 

234 

235def require_availability_zone_exists(*, strict: bool): 

236 """Decorator to require the specified availability zone to exist. 

237 

238 Requires the wrapped function to use context as their first argument and 

239 values as either their second (for create) or third (for update) argument. 

240 

241 .. note:: 

242 

243 This has a side-effect of updating the provided values dict, replacing 

244 ``availability_zone`` with ``availability_zone_id`` 

245 

246 :param strict: If true, ``values`` must contain an ``availability_zone`` 

247 key 

248 """ 

249 def inner(f): 

250 @wraps(f) 

251 def wrapper(context, *args, **kwargs): 

252 values = args[0] 

253 if not isinstance(args[0], dict): 

254 values = args[1] 

255 ensure_availability_zone_exists(context, values, strict=strict) 

256 return f(context, *args, **kwargs) 

257 wrapper.__name__ = f.__name__ 

258 return wrapper 

259 return inner 

260 

261 

262def apply_sorting(model, query, sort_key, sort_dir): 

263 if sort_dir.lower() not in ('desc', 'asc'): 263 ↛ 264line 263 didn't jump to line 264 because the condition on line 263 was never true

264 msg = _("Wrong sorting data provided: sort key is '%(sort_key)s' " 

265 "and sort direction is '%(sort_dir)s'.") % { 

266 "sort_key": sort_key, "sort_dir": sort_dir} 

267 raise exception.InvalidInput(reason=msg) 

268 

269 # NOTE(maaoyu): We add the additional sort by ID in this case to 

270 # get deterministic results. Without the ordering by ID this could 

271 # lead to flapping return lists. 

272 sort_keys = [sort_key] 

273 if sort_key != 'id': 

274 sort_keys.append('id') 

275 

276 for sort_key in sort_keys: 

277 sort_attr = getattr(model, sort_key) 

278 sort_method = getattr(sort_attr, sort_dir.lower()) 

279 query = query.order_by(sort_method()) 

280 

281 return query 

282 

283 

284def handle_db_data_error(f): 

285 def wrapper(*args, **kwargs): 

286 try: 

287 return f(*args, **kwargs) 

288 except db_exc.DBDataError: 

289 msg = _('Error writing field to database.') 

290 LOG.exception(msg) 

291 raise exception.Invalid(msg) 

292 

293 return wrapper 

294 

295 

296def model_query(context, model, *args, **kwargs): 

297 """Query helper that accounts for context's `read_deleted` field. 

298 

299 :param context: context to query under 

300 :param model: model to query. Must be a subclass of ModelBase. 

301 :param read_deleted: if present, overrides context's read_deleted field. 

302 :param project_only: if present and context is user-type, then restrict 

303 query to match the context's project_id. 

304 """ 

305 assert 'session' not in kwargs 

306 assert hasattr(context, 'session') and context.session 

307 

308 read_deleted = kwargs.get('read_deleted') or context.read_deleted 

309 project_only = kwargs.get('project_only') 

310 kwargs = dict() 

311 

312 if project_only and not context.is_admin: 

313 kwargs['project_id'] = context.project_id 

314 if read_deleted in ('no', 'n', False): 

315 kwargs['deleted'] = False 

316 elif read_deleted == 'only': 

317 kwargs['deleted'] = True 

318 elif read_deleted in ('yes', 'y', True): 318 ↛ 321line 318 didn't jump to line 321 because the condition on line 318 was always true

319 pass 

320 

321 return db_utils.model_query( 

322 model=model, 

323 session=context.session, 

324 args=args, 

325 **kwargs, 

326 ) 

327 

328 

329def _process_model_like_filter(model, query, filters): 

330 """Applies regex expression filtering to a query. 

331 

332 :param model: model to apply filters to 

333 :param query: query to apply filters to 

334 :param filters: dictionary of filters with regex values 

335 :returns: the updated query. 

336 """ 

337 if query is None: 337 ↛ 338line 337 didn't jump to line 338 because the condition on line 337 was never true

338 return query 

339 

340 if filters: 

341 for key in sorted(filters): 

342 column_attr = getattr(model, key) 

343 if 'property' == type(column_attr).__name__: 343 ↛ 344line 343 didn't jump to line 344 because the condition on line 343 was never true

344 continue 

345 value = filters[key] 

346 if not (isinstance(value, (str, int))): 346 ↛ 347line 346 didn't jump to line 347 because the condition on line 346 was never true

347 continue 

348 query = query.filter( 

349 column_attr.op('LIKE')(u'%%%s%%' % value)) 

350 return query 

351 

352 

353def apply_like_filters(process_exact_filters): 

354 def _decorator(query, model, filters, legal_keys): 

355 exact_filters = filters.copy() 

356 regex_filters = {} 

357 for key, value in filters.items(): 

358 if key not in legal_keys: 

359 # Skip ones we're not filtering on 

360 continue 

361 # NOTE(haixin): For inexact match, the filter keys 

362 # are in the format of 'key~=value' 

363 if key.endswith('~'): 

364 exact_filters.pop(key) 

365 regex_filters[key.rstrip('~')] = value 

366 query = process_exact_filters(query, model, exact_filters, 

367 legal_keys) 

368 return _process_model_like_filter(model, query, regex_filters) 

369 return _decorator 

370 

371 

372@apply_like_filters 

373def exact_filter(query, model, filters, legal_keys, 

374 created_at_key='created_at'): 

375 """Applies exact match filtering to a query. 

376 

377 Returns the updated query. Modifies filters argument to remove 

378 filters consumed. 

379 

380 :param query: query to apply filters to 

381 :param model: model object the query applies to, for IN-style 

382 filtering 

383 :param filters: dictionary of filters; values that are lists, 

384 tuples, sets, or frozensets cause an 'IN' test to 

385 be performed, while exact matching ('==' operator) 

386 is used for other values 

387 :param legal_keys: list of keys to apply exact filtering to 

388 """ 

389 

390 filter_dict = {} 

391 created_at_attr = getattr(model, created_at_key, None) 

392 # Walk through all the keys 

393 for key in legal_keys: 

394 # Skip ones we're not filtering on 

395 if key not in filters: 

396 continue 

397 

398 # OK, filtering on this key; what value do we search for? 

399 value = filters.pop(key) 

400 

401 if key == 'created_since' and created_at_attr: 

402 # This is a reserved query parameter to indicate resources created 

403 # after a particular datetime 

404 value = timeutils.normalize_time(value) 

405 query = query.filter(created_at_attr.op('>=')(value)) 

406 elif key == 'created_before' and created_at_attr: 

407 # This is a reserved query parameter to indicate resources created 

408 # before a particular datetime 

409 value = timeutils.normalize_time(value) 

410 query = query.filter(created_at_attr.op('<=')(value)) 

411 elif isinstance(value, (list, tuple, set, frozenset)): 

412 # Looking for values in a list; apply to query directly 

413 column_attr = getattr(model, key) 

414 query = query.filter(column_attr.in_(value)) 

415 else: 

416 # OK, simple exact match; save for later 

417 filter_dict[key] = value 

418 

419 # Apply simple exact matches 

420 if filter_dict: 

421 query = query.filter_by(**filter_dict) 

422 

423 return query 

424 

425 

426def ensure_model_dict_has_id(model_dict): 

427 if not model_dict.get('id'): 

428 model_dict['id'] = uuidutils.generate_uuid() 

429 return model_dict 

430 

431 

432def _sync_shares(context, project_id, user_id, share_type_id=None): 

433 shares, _ = _share_data_get_for_project( 

434 context, project_id, user_id, share_type_id=share_type_id, 

435 ) 

436 return {'shares': shares} 

437 

438 

439def _sync_snapshots(context, project_id, user_id, share_type_id=None): 

440 snapshots, _ = _snapshot_data_get_for_project( 

441 context, project_id, user_id, share_type_id=share_type_id, 

442 ) 

443 return {'snapshots': snapshots} 

444 

445 

446def _sync_gigabytes(context, project_id, user_id, share_type_id=None): 

447 _, share_gigs = _share_data_get_for_project( 

448 context, project_id, user_id, share_type_id=share_type_id, 

449 ) 

450 return {'gigabytes': share_gigs} 

451 

452 

453def _sync_snapshot_gigabytes(context, project_id, user_id, share_type_id=None): 

454 _, snapshot_gigs = _snapshot_data_get_for_project( 

455 context, project_id, user_id, share_type_id=share_type_id, 

456 ) 

457 return {'snapshot_gigabytes': snapshot_gigs} 

458 

459 

460def _sync_share_networks(context, project_id, user_id, share_type_id=None): 

461 share_networks_count = _count_share_networks( 

462 context, project_id, user_id, share_type_id=share_type_id, 

463 ) 

464 return {'share_networks': share_networks_count} 

465 

466 

467def _sync_share_groups(context, project_id, user_id, share_type_id=None): 

468 share_groups_count = _count_share_groups( 

469 context, project_id, user_id, share_type_id=share_type_id, 

470 ) 

471 return {'share_groups': share_groups_count} 

472 

473 

474def _sync_backups(context, project_id, user_id, share_type_id=None): 

475 backups, _ = _backup_data_get_for_project(context, project_id, user_id) 

476 return {'backups': backups} 

477 

478 

479def _sync_backup_gigabytes(context, project_id, user_id, share_type_id=None): 

480 _, backup_gigs = _backup_data_get_for_project(context, project_id, user_id) 

481 return {'backup_gigabytes': backup_gigs} 

482 

483 

484def _sync_share_group_snapshots( 

485 context, project_id, user_id, share_type_id=None, 

486): 

487 share_group_snapshots_count = _count_share_group_snapshots( 

488 context, project_id, user_id, share_type_id=share_type_id, 

489 ) 

490 return {'share_group_snapshots': share_group_snapshots_count} 

491 

492 

493def _sync_share_replicas(context, project_id, user_id, share_type_id=None): 

494 share_replicas_count, _ = _share_replica_data_get_for_project( 

495 context, project_id, user_id, share_type_id=share_type_id, 

496 ) 

497 return {'share_replicas': share_replicas_count} 

498 

499 

500def _sync_replica_gigabytes(context, project_id, user_id, share_type_id=None): 

501 _, replica_gigs = _share_replica_data_get_for_project( 

502 context, project_id, user_id, share_type_id=share_type_id, 

503 ) 

504 return {'replica_gigabytes': replica_gigs} 

505 

506 

507def _sync_encryption_keys(context, project_id, user_id, share_type_id=None): 

508 encryption_keys = _count_encryption_keys_for_project( 

509 context, project_id, user_id 

510 ) 

511 return {'encryption_keys': encryption_keys} 

512 

513 

514QUOTA_SYNC_FUNCTIONS = { 

515 '_sync_shares': _sync_shares, 

516 '_sync_snapshots': _sync_snapshots, 

517 '_sync_gigabytes': _sync_gigabytes, 

518 '_sync_snapshot_gigabytes': _sync_snapshot_gigabytes, 

519 '_sync_share_networks': _sync_share_networks, 

520 '_sync_share_groups': _sync_share_groups, 

521 '_sync_share_group_snapshots': _sync_share_group_snapshots, 

522 '_sync_share_replicas': _sync_share_replicas, 

523 '_sync_replica_gigabytes': _sync_replica_gigabytes, 

524 '_sync_backups': _sync_backups, 

525 '_sync_backup_gigabytes': _sync_backup_gigabytes, 

526 '_sync_encryption_keys': _sync_encryption_keys, 

527} 

528 

529 

530################### 

531 

532@require_admin_context 

533@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

534@context_manager.writer 

535def share_resources_host_update(context, current_host, new_host): 

536 """Updates the 'host' attribute of resources""" 

537 

538 resources = { 

539 'instances': models.ShareInstance, 

540 'servers': models.ShareServer, 

541 'groups': models.ShareGroup, 

542 } 

543 result = {} 

544 

545 for res_name, res_model in resources.items(): 

546 host_field = res_model.host 

547 query = model_query( 

548 context, res_model, read_deleted="no", 

549 ).filter(host_field.like('{}%'.format(current_host))) 

550 count = query.update( 

551 {host_field: func.replace(host_field, current_host, new_host)}, 

552 synchronize_session=False, 

553 ) 

554 result.update({res_name: count}) 

555 return result 

556 

557 

558################### 

559 

560 

561@require_admin_context 

562@context_manager.writer 

563def service_destroy(context, service_id): 

564 service_ref = _service_get(context, service_id) 

565 service_ref.soft_delete(context.session) 

566 

567 

568@require_admin_context 

569def _service_get(context, service_id): 

570 result = ( 

571 model_query( 

572 context, 

573 models.Service, 

574 ).filter_by( 

575 id=service_id, 

576 ).first() 

577 ) 

578 if not result: 578 ↛ 579line 578 didn't jump to line 579 because the condition on line 578 was never true

579 raise exception.ServiceNotFound(service_id=service_id) 

580 

581 return result 

582 

583 

584@require_admin_context 

585@context_manager.reader 

586def service_get(context, service_id): 

587 return _service_get(context, service_id) 

588 

589 

590@require_admin_context 

591@context_manager.reader 

592def service_get_all(context, disabled=None): 

593 query = model_query(context, models.Service) 

594 

595 if disabled is not None: 

596 query = query.filter_by(disabled=disabled) 

597 

598 return query.all() 

599 

600 

601@require_admin_context 

602@context_manager.reader 

603def service_get_all_by_topic(context, topic, consider_disabled=False): 

604 query = model_query( 

605 context, models.Service, read_deleted="no") 

606 

607 if not consider_disabled: 607 ↛ 610line 607 didn't jump to line 610 because the condition on line 607 was always true

608 query = query.filter_by(disabled=False) 

609 

610 return query.filter_by(topic=topic).all() 

611 

612 

613@require_admin_context 

614@context_manager.reader 

615def service_get_by_host_and_topic(context, host, topic): 

616 result = (model_query( 

617 context, models.Service, read_deleted="no"). 

618 filter_by(disabled=False). 

619 filter_by(host=host). 

620 filter_by(topic=topic). 

621 first()) 

622 if not result: 622 ↛ 624line 622 didn't jump to line 624 because the condition on line 622 was always true

623 raise exception.ServiceNotFound(service_id=host) 

624 return result 

625 

626 

627@require_admin_context 

628def _service_get_all_topic_subquery(context, topic, subq, label): 

629 sort_value = getattr(subq.c, label) 

630 return ( 

631 model_query( 

632 context, models.Service, 

633 func.coalesce(sort_value, 0), 

634 read_deleted="no", 

635 ).filter_by( 

636 topic=topic, 

637 ).filter_by( 

638 disabled=False, 

639 ).outerjoin( 

640 (subq, models.Service.host == subq.c.host) 

641 ).order_by( 

642 sort_value 

643 ).all() 

644 ) 

645 

646 

647@require_admin_context 

648@context_manager.reader 

649def service_get_all_share_sorted(context): 

650 topic = CONF.share_topic 

651 label = 'share_gigabytes' 

652 subq = ( 

653 model_query( 

654 context, 

655 models.Share, 

656 func.sum(models.Share.size).label(label), 

657 read_deleted="no", 

658 ).join( 

659 models.ShareInstance, 

660 models.ShareInstance.share_id == models.Share.id, 

661 ).group_by( 

662 models.ShareInstance.host 

663 ).subquery() 

664 ) 

665 return _service_get_all_topic_subquery( 

666 context, 

667 topic, 

668 subq, 

669 label, 

670 ) 

671 

672 

673@require_admin_context 

674@context_manager.reader 

675def service_get_by_args(context, host, binary): 

676 result = (model_query(context, models.Service). 

677 filter_by(host=host). 

678 filter_by(binary=binary). 

679 first()) 

680 

681 if not result: 681 ↛ 684line 681 didn't jump to line 684 because the condition on line 681 was always true

682 raise exception.HostBinaryNotFound(host=host, binary=binary) 

683 

684 return result 

685 

686 

687@require_admin_context 

688@require_availability_zone_exists(strict=True) 

689@context_manager.writer 

690def service_create(context, values): 

691 service_ref = models.Service() 

692 service_ref.update(values) 

693 if not CONF.enable_new_services: 

694 service_ref.disabled = True 

695 

696 service_ref.save(context.session) 

697 return service_ref 

698 

699 

700@require_admin_context 

701@require_availability_zone_exists(strict=False) 

702@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

703@context_manager.writer 

704def service_update(context, service_id, values): 

705 service_ref = _service_get(context, service_id) 

706 service_ref.update(values) 

707 service_ref.save(context.session) 

708 

709 

710################### 

711 

712 

713@require_context 

714@context_manager.reader.independent 

715def quota_get_all_by_project_and_user(context, project_id, user_id): 

716 authorize_project_context(context, project_id) 

717 user_quotas = model_query( 

718 context, models.ProjectUserQuota, 

719 models.ProjectUserQuota.resource, 

720 models.ProjectUserQuota.hard_limit, 

721 ).filter_by( 

722 project_id=project_id, 

723 ).filter_by( 

724 user_id=user_id, 

725 ).all() 

726 

727 result = {'project_id': project_id, 'user_id': user_id} 

728 for u_quota in user_quotas: 

729 result[u_quota.resource] = u_quota.hard_limit 

730 return result 

731 

732 

733@require_context 

734@context_manager.reader.independent 

735def quota_get_all_by_project_and_share_type( 

736 context, project_id, share_type_id, 

737): 

738 authorize_project_context(context, project_id) 

739 share_type_quotas = model_query( 

740 context, models.ProjectShareTypeQuota, 

741 models.ProjectShareTypeQuota.resource, 

742 models.ProjectShareTypeQuota.hard_limit, 

743 ).filter_by( 

744 project_id=project_id, 

745 ).filter_by( 

746 share_type_id=share_type_id, 

747 ).all() 

748 

749 result = { 

750 'project_id': project_id, 

751 'share_type_id': share_type_id, 

752 } 

753 for st_quota in share_type_quotas: 

754 result[st_quota.resource] = st_quota.hard_limit 

755 return result 

756 

757 

758@require_context 

759@context_manager.reader.independent 

760def quota_get_all_by_project(context, project_id): 

761 authorize_project_context(context, project_id) 

762 project_quotas = model_query( 

763 context, models.Quota, read_deleted="no", 

764 ).filter_by( 

765 project_id=project_id, 

766 ).all() 

767 

768 result = {'project_id': project_id} 

769 for p_quota in project_quotas: 

770 result[p_quota.resource] = p_quota.hard_limit 

771 return result 

772 

773 

774@require_context 

775@context_manager.reader.independent 

776def quota_get_all(context, project_id): 

777 authorize_project_context(context, project_id) 

778 

779 result = (model_query(context, models.ProjectUserQuota). 

780 filter_by(project_id=project_id). 

781 all()) 

782 

783 return result 

784 

785 

786@require_admin_context 

787@context_manager.writer.independent 

788def quota_create( 

789 context, 

790 project_id, 

791 resource, 

792 limit, 

793 user_id=None, 

794 share_type_id=None, 

795): 

796 per_user = user_id and resource not in PER_PROJECT_QUOTAS 

797 

798 if per_user: 

799 check = model_query(context, models.ProjectUserQuota).filter( 

800 models.ProjectUserQuota.project_id == project_id, 

801 models.ProjectUserQuota.user_id == user_id, 

802 models.ProjectUserQuota.resource == resource, 

803 ).all() 

804 quota_ref = models.ProjectUserQuota() 

805 quota_ref.user_id = user_id 

806 elif share_type_id: 

807 check = model_query(context, models.ProjectShareTypeQuota).filter( 

808 models.ProjectShareTypeQuota.project_id == project_id, 

809 models.ProjectShareTypeQuota.share_type_id == share_type_id, 

810 models.ProjectShareTypeQuota.resource == resource, 

811 ).all() 

812 quota_ref = models.ProjectShareTypeQuota() 

813 quota_ref.share_type_id = share_type_id 

814 else: 

815 check = model_query(context, models.Quota).filter( 

816 models.Quota.project_id == project_id, 

817 models.Quota.resource == resource, 

818 ).all() 

819 quota_ref = models.Quota() 

820 if check: 820 ↛ 821line 820 didn't jump to line 821 because the condition on line 820 was never true

821 raise exception.QuotaExists(project_id=project_id, resource=resource) 

822 

823 quota_ref.project_id = project_id 

824 quota_ref.resource = resource 

825 quota_ref.hard_limit = limit 

826 try: 

827 quota_ref.save(context.session) 

828 except Exception as e: 

829 if "out of range" in str(e).lower(): 

830 msg = _("Quota limit should not exceed 2147483647") 

831 raise exception.InvalidInput(reason=msg) 

832 raise 

833 return quota_ref 

834 

835 

836@require_admin_context 

837@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

838@context_manager.writer.independent 

839def quota_update( 

840 context, 

841 project_id, 

842 resource, 

843 limit, 

844 user_id=None, 

845 share_type_id=None, 

846): 

847 per_user = user_id and resource not in PER_PROJECT_QUOTAS 

848 if per_user: 

849 query = model_query(context, models.ProjectUserQuota).filter( 

850 models.ProjectUserQuota.project_id == project_id, 

851 models.ProjectUserQuota.user_id == user_id, 

852 models.ProjectUserQuota.resource == resource, 

853 ) 

854 elif share_type_id: 

855 query = model_query(context, models.ProjectShareTypeQuota).filter( 

856 models.ProjectShareTypeQuota.project_id == project_id, 

857 models.ProjectShareTypeQuota.share_type_id == share_type_id, 

858 models.ProjectShareTypeQuota.resource == resource, 

859 ) 

860 else: 

861 query = model_query(context, models.Quota).filter( 

862 models.Quota.project_id == project_id, 

863 models.Quota.resource == resource, 

864 ) 

865 

866 result = query.update({'hard_limit': limit}) 

867 if not result: 

868 if per_user: 

869 raise exception.ProjectUserQuotaNotFound( 

870 project_id=project_id, user_id=user_id) 

871 elif share_type_id: 

872 raise exception.ProjectShareTypeQuotaNotFound( 

873 project_id=project_id, share_type=share_type_id) 

874 raise exception.ProjectQuotaNotFound(project_id=project_id) 

875 

876 

877################### 

878 

879 

880@require_context 

881@context_manager.reader 

882def quota_class_get(context, class_name, resource): 

883 result = ( 

884 model_query( 

885 context, 

886 models.QuotaClass, 

887 read_deleted="no", 

888 ).filter_by( 

889 class_name=class_name 

890 ).filter_by( 

891 resource=resource 

892 ).first() 

893 ) 

894 

895 if not result: 

896 raise exception.QuotaClassNotFound(class_name=class_name) 

897 

898 return result 

899 

900 

901@require_context 

902@context_manager.reader 

903def quota_class_get_default(context): 

904 rows = (model_query(context, models.QuotaClass, read_deleted="no"). 

905 filter_by(class_name=_DEFAULT_QUOTA_NAME). 

906 all()) 

907 

908 result = {'class_name': _DEFAULT_QUOTA_NAME} 

909 for row in rows: 909 ↛ 910line 909 didn't jump to line 910 because the loop on line 909 never started

910 result[row.resource] = row.hard_limit 

911 

912 return result 

913 

914 

915@require_context 

916@context_manager.reader 

917def quota_class_get_all_by_name(context, class_name): 

918 authorize_quota_class_context(context, class_name) 

919 

920 rows = (model_query(context, models.QuotaClass, read_deleted="no"). 

921 filter_by(class_name=class_name). 

922 all()) 

923 

924 result = {'class_name': class_name} 

925 for row in rows: 

926 result[row.resource] = row.hard_limit 

927 

928 return result 

929 

930 

931@require_admin_context 

932@context_manager.writer 

933def quota_class_create(context, class_name, resource, limit): 

934 quota_class_ref = models.QuotaClass() 

935 quota_class_ref.class_name = class_name 

936 quota_class_ref.resource = resource 

937 quota_class_ref.hard_limit = limit 

938 quota_class_ref.save(context.session) 

939 return quota_class_ref 

940 

941 

942@require_admin_context 

943@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

944@context_manager.writer 

945def quota_class_update(context, class_name, resource, limit): 

946 result = (model_query(context, models.QuotaClass, read_deleted="no"). 

947 filter_by(class_name=class_name). 

948 filter_by(resource=resource). 

949 update({'hard_limit': limit})) 

950 

951 if not result: 951 ↛ exitline 951 didn't return from function 'quota_class_update' because the condition on line 951 was always true

952 raise exception.QuotaClassNotFound(class_name=class_name) 

953 

954 

955################### 

956 

957 

958@require_context 

959@context_manager.reader 

960def quota_usage_get(context, project_id, resource, user_id=None, 

961 share_type_id=None): 

962 query = (model_query(context, models.QuotaUsage, read_deleted="no"). 

963 filter_by(project_id=project_id). 

964 filter_by(resource=resource)) 

965 if user_id: 965 ↛ 966line 965 didn't jump to line 966 because the condition on line 965 was never true

966 if resource not in PER_PROJECT_QUOTAS: 

967 result = query.filter_by(user_id=user_id).first() 

968 else: 

969 result = query.filter_by(user_id=None).first() 

970 elif share_type_id: 970 ↛ 971line 970 didn't jump to line 971 because the condition on line 970 was never true

971 result = query.filter_by(queryshare_type_id=share_type_id).first() 

972 else: 

973 result = query.first() 

974 

975 if not result: 

976 raise exception.QuotaUsageNotFound(project_id=project_id) 

977 

978 return result 

979 

980 

981def _quota_usage_get_all(context, project_id, user_id=None, 

982 share_type_id=None): 

983 authorize_project_context(context, project_id) 

984 query = (model_query(context, models.QuotaUsage, read_deleted="no"). 

985 filter_by(project_id=project_id)) 

986 result = {'project_id': project_id} 

987 if user_id: 

988 query = query.filter(or_(models.QuotaUsage.user_id == user_id, 

989 models.QuotaUsage.user_id is None)) 

990 result['user_id'] = user_id 

991 elif share_type_id: 

992 query = query.filter_by(share_type_id=share_type_id) 

993 result['share_type_id'] = share_type_id 

994 else: 

995 query = query.filter_by(share_type_id=None) 

996 

997 rows = query.all() 

998 for row in rows: 

999 if row.resource in result: 999 ↛ 1000line 999 didn't jump to line 1000 because the condition on line 999 was never true

1000 result[row.resource]['in_use'] += row.in_use 

1001 result[row.resource]['reserved'] += row.reserved 

1002 else: 

1003 result[row.resource] = dict(in_use=row.in_use, 

1004 reserved=row.reserved) 

1005 

1006 return result 

1007 

1008 

1009@require_context 

1010@context_manager.reader 

1011def quota_usage_get_all_by_project(context, project_id): 

1012 return _quota_usage_get_all(context, project_id) 

1013 

1014 

1015@require_context 

1016@context_manager.reader 

1017def quota_usage_get_all_by_project_and_user(context, project_id, user_id): 

1018 return _quota_usage_get_all(context, project_id, user_id=user_id) 

1019 

1020 

1021@require_context 

1022@context_manager.reader 

1023def quota_usage_get_all_by_project_and_share_type(context, project_id, 

1024 share_type_id): 

1025 return _quota_usage_get_all( 

1026 context, project_id, share_type_id=share_type_id) 

1027 

1028 

1029def _quota_usage_create(context, project_id, user_id, resource, in_use, 

1030 reserved, until_refresh, share_type_id=None): 

1031 quota_usage_ref = models.QuotaUsage() 

1032 if share_type_id: 

1033 quota_usage_ref.share_type_id = share_type_id 

1034 else: 

1035 quota_usage_ref.user_id = user_id 

1036 quota_usage_ref.project_id = project_id 

1037 quota_usage_ref.resource = resource 

1038 quota_usage_ref.in_use = in_use 

1039 quota_usage_ref.reserved = reserved 

1040 quota_usage_ref.until_refresh = until_refresh 

1041 # updated_at is needed for judgement of max_age 

1042 quota_usage_ref.updated_at = timeutils.utcnow() 

1043 

1044 quota_usage_ref.save(session=context.session) 

1045 

1046 return quota_usage_ref 

1047 

1048 

1049@require_admin_context 

1050@context_manager.writer 

1051def quota_usage_create(context, project_id, user_id, resource, in_use, 

1052 reserved, until_refresh, share_type_id=None): 

1053 return _quota_usage_create( 

1054 context, 

1055 project_id, 

1056 user_id, 

1057 resource, 

1058 in_use, 

1059 reserved, 

1060 until_refresh, 

1061 share_type_id=share_type_id, 

1062 ) 

1063 

1064 

1065@require_admin_context 

1066@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

1067@context_manager.writer.independent 

1068def quota_usage_update(context, project_id, user_id, resource, 

1069 share_type_id=None, **kwargs): 

1070 updates = {} 

1071 for key in ('in_use', 'reserved', 'until_refresh'): 

1072 if key in kwargs: 

1073 updates[key] = kwargs[key] 

1074 

1075 query = model_query( 

1076 context, models.QuotaUsage, read_deleted="no", 

1077 ).filter_by(project_id=project_id).filter_by(resource=resource) 

1078 if share_type_id: 

1079 query = query.filter_by(share_type_id=share_type_id) 

1080 else: 

1081 query = query.filter(or_(models.QuotaUsage.user_id == user_id, 

1082 models.QuotaUsage.user_id is None)) 

1083 result = query.update(updates) 

1084 

1085 if not result: 

1086 raise exception.QuotaUsageNotFound(project_id=project_id) 

1087 

1088 

1089################### 

1090 

1091 

1092def _reservation_create(context, uuid, usage, project_id, user_id, resource, 

1093 delta, expire, share_type_id=None): 

1094 reservation_ref = models.Reservation() 

1095 reservation_ref.uuid = uuid 

1096 reservation_ref.usage_id = usage['id'] 

1097 reservation_ref.project_id = project_id 

1098 if share_type_id: 

1099 reservation_ref.share_type_id = share_type_id 

1100 else: 

1101 reservation_ref.user_id = user_id 

1102 reservation_ref.resource = resource 

1103 reservation_ref.delta = delta 

1104 reservation_ref.expire = expire 

1105 reservation_ref.save(session=context.session) 

1106 return reservation_ref 

1107 

1108 

1109################### 

1110 

1111 

1112# NOTE(johannes): The quota code uses SQL locking to ensure races don't 

1113# cause under or over counting of resources. To avoid deadlocks, this 

1114# code always acquires the lock on quota_usages before acquiring the lock 

1115# on reservations. 

1116 

1117def _get_share_type_quota_usages(context, project_id, share_type_id): 

1118 rows = model_query( 

1119 context, models.QuotaUsage, read_deleted="no", 

1120 ).filter( 

1121 models.QuotaUsage.project_id == project_id, 

1122 models.QuotaUsage.share_type_id == share_type_id, 

1123 ).with_for_update().all() 

1124 return {row.resource: row for row in rows} 

1125 

1126 

1127def _get_user_quota_usages(context, project_id, user_id): 

1128 # Broken out for testability 

1129 rows = model_query( 

1130 context, models.QuotaUsage, read_deleted="no", 

1131 ).filter_by( 

1132 project_id=project_id, 

1133 ).filter( 

1134 or_( 

1135 models.QuotaUsage.user_id == user_id, 

1136 models.QuotaUsage.user_id is None, 

1137 ) 

1138 ).with_for_update().all() 

1139 return {row.resource: row for row in rows} 

1140 

1141 

1142def _get_project_quota_usages(context, project_id): 

1143 rows = model_query( 

1144 context, models.QuotaUsage, read_deleted="no", 

1145 ).filter_by( 

1146 project_id=project_id, 

1147 ).filter( 

1148 models.QuotaUsage.share_type_id is None, 

1149 ).with_for_update().all() 

1150 result = dict() 

1151 # Get the total count of in_use,reserved 

1152 for row in rows: 1152 ↛ 1153line 1152 didn't jump to line 1153 because the loop on line 1152 never started

1153 if row.resource in result: 

1154 result[row.resource]['in_use'] += row.in_use 

1155 result[row.resource]['reserved'] += row.reserved 

1156 result[row.resource]['total'] += (row.in_use + row.reserved) 

1157 else: 

1158 result[row.resource] = dict( 

1159 in_use=row.in_use, 

1160 reserved=row.reserved, 

1161 total=row.in_use + row.reserved, 

1162 ) 

1163 return result 

1164 

1165 

1166# NOTE(stephenfin): We intentionally don't wrap the outer function here since 

1167# we call the innter function multiple times and want each call to be in a 

1168# separate transaction 

1169@require_context 

1170def quota_reserve(context, resources, project_quotas, user_quotas, 

1171 share_type_quotas, deltas, expire, until_refresh, 

1172 max_age, project_id=None, user_id=None, share_type_id=None, 

1173 overquota_allowed=False): 

1174 user_reservations = _quota_reserve( 

1175 context, resources, project_quotas, user_quotas, 

1176 deltas, expire, until_refresh, max_age, project_id, user_id=user_id, 

1177 overquota_allowed=overquota_allowed) 

1178 if share_type_id: 

1179 try: 

1180 st_reservations = _quota_reserve( 

1181 context, resources, project_quotas, share_type_quotas, 

1182 deltas, expire, until_refresh, max_age, project_id, 

1183 share_type_id=share_type_id, 

1184 overquota_allowed=overquota_allowed) 

1185 except exception.OverQuota: 

1186 # rollback previous reservations 

1187 with excutils.save_and_reraise_exception(): 

1188 # We call a public method since we haven't wrapped this, the 

1189 # caller, and we want to run in a different transaction 

1190 reservation_rollback( 

1191 context, user_reservations, 

1192 project_id=project_id, user_id=user_id) 

1193 return user_reservations + st_reservations 

1194 return user_reservations 

1195 

1196 

1197# NOTE(stephenfin): Per above, we wrap the inner method here 

1198@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

1199@context_manager.writer.independent 

1200def _quota_reserve(context, resources, project_quotas, user_or_st_quotas, 

1201 deltas, expire, until_refresh, 

1202 max_age, project_id=None, user_id=None, share_type_id=None, 

1203 overquota_allowed=False): 

1204 elevated = context.elevated() 

1205 

1206 if project_id is None: 

1207 project_id = context.project_id 

1208 if share_type_id: 

1209 user_or_st_usages = _get_share_type_quota_usages( 

1210 context, project_id, share_type_id, 

1211 ) 

1212 else: 

1213 user_id = user_id if user_id else context.user_id 

1214 user_or_st_usages = _get_user_quota_usages( 

1215 context, project_id, user_id, 

1216 ) 

1217 

1218 # Get the current usages 

1219 project_usages = _get_project_quota_usages(context, project_id) 

1220 

1221 # Handle usage refresh 

1222 work = set(deltas.keys()) 

1223 while work: 

1224 resource = work.pop() 

1225 

1226 # Do we need to refresh the usage? 

1227 refresh = False 

1228 if ((resource not in PER_PROJECT_QUOTAS) and 1228 ↛ 1240line 1228 didn't jump to line 1240 because the condition on line 1228 was always true

1229 (resource not in user_or_st_usages)): 

1230 user_or_st_usages[resource] = _quota_usage_create( 

1231 elevated, 

1232 project_id, 

1233 user_id, 

1234 resource, 

1235 0, 0, 

1236 until_refresh or None, 

1237 share_type_id=share_type_id, 

1238 ) 

1239 refresh = True 

1240 elif ((resource in PER_PROJECT_QUOTAS) and 

1241 (resource not in user_or_st_usages)): 

1242 user_or_st_usages[resource] = _quota_usage_create( 

1243 elevated, 

1244 project_id, 

1245 None, 

1246 resource, 

1247 0, 0, 

1248 until_refresh or None, 

1249 share_type_id=share_type_id, 

1250 ) 

1251 refresh = True 

1252 elif user_or_st_usages[resource].in_use < 0: 

1253 # Negative in_use count indicates a desync, so try to 

1254 # heal from that... 

1255 refresh = True 

1256 elif user_or_st_usages[resource].until_refresh is not None: 

1257 user_or_st_usages[resource].until_refresh -= 1 

1258 if user_or_st_usages[resource].until_refresh <= 0: 

1259 refresh = True 

1260 elif max_age and (user_or_st_usages[resource].updated_at - 

1261 timeutils.utcnow()).seconds >= max_age: 

1262 refresh = True 

1263 

1264 # OK, refresh the usage 

1265 if refresh: 1265 ↛ 1223line 1265 didn't jump to line 1223 because the condition on line 1265 was always true

1266 # Grab the sync routine 

1267 sync = QUOTA_SYNC_FUNCTIONS[resources[resource].sync] 

1268 

1269 updates = sync( 

1270 elevated, 

1271 project_id, 

1272 user_id, 

1273 share_type_id=share_type_id, 

1274 ) 

1275 for res, in_use in updates.items(): 

1276 # Make sure we have a destination for the usage! 

1277 if ((res not in PER_PROJECT_QUOTAS) and 1277 ↛ 1279line 1277 didn't jump to line 1279 because the condition on line 1277 was never true

1278 (res not in user_or_st_usages)): 

1279 user_or_st_usages[res] = _quota_usage_create( 

1280 elevated, 

1281 project_id, 

1282 user_id, 

1283 res, 

1284 0, 0, 

1285 until_refresh or None, 

1286 share_type_id=share_type_id, 

1287 ) 

1288 if ((res in PER_PROJECT_QUOTAS) and 1288 ↛ 1290line 1288 didn't jump to line 1290 because the condition on line 1288 was never true

1289 (res not in user_or_st_usages)): 

1290 user_or_st_usages[res] = _quota_usage_create( 

1291 elevated, 

1292 project_id, 

1293 None, 

1294 res, 

1295 0, 0, 

1296 until_refresh or None, 

1297 share_type_id=share_type_id, 

1298 ) 

1299 

1300 if user_or_st_usages[res].in_use != in_use: 

1301 LOG.debug( 

1302 'quota_usages out of sync, updating. ' 

1303 'project_id: %(project_id)s, ' 

1304 'user_id: %(user_id)s, ' 

1305 'share_type_id: %(share_type_id)s, ' 

1306 'resource: %(res)s, ' 

1307 'tracked usage: %(tracked_use)s, ' 

1308 'actual usage: %(in_use)s', 

1309 {'project_id': project_id, 

1310 'user_id': user_id, 

1311 'share_type_id': share_type_id, 

1312 'res': res, 

1313 'tracked_use': user_or_st_usages[res].in_use, 

1314 'in_use': in_use}) 

1315 

1316 # Update the usage 

1317 user_or_st_usages[res].in_use = in_use 

1318 user_or_st_usages[res].until_refresh = ( 

1319 until_refresh or None) 

1320 

1321 # Because more than one resource may be refreshed 

1322 # by the call to the sync routine, and we don't 

1323 # want to double-sync, we make sure all refreshed 

1324 # resources are dropped from the work set. 

1325 work.discard(res) 

1326 

1327 # NOTE(Vek): We make the assumption that the sync 

1328 # routine actually refreshes the 

1329 # resources that it is the sync routine 

1330 # for. We don't check, because this is 

1331 # a best-effort mechanism. 

1332 

1333 # Check for deltas that would go negative 

1334 unders = [res for res, delta in deltas.items() 

1335 if delta < 0 and 

1336 delta + user_or_st_usages[res].in_use < 0] 

1337 

1338 # Now, let's check the quotas 

1339 # NOTE(Vek): We're only concerned about positive increments. 

1340 # If a project has gone over quota, we want them to 

1341 # be able to reduce their usage without any 

1342 # problems. 

1343 for key, value in user_or_st_usages.items(): 

1344 if key not in project_usages: 1344 ↛ 1343line 1344 didn't jump to line 1343 because the condition on line 1344 was always true

1345 project_usages[key] = value 

1346 overs = [res for res, delta in deltas.items() 

1347 if user_or_st_quotas[res] >= 0 and delta >= 0 and 

1348 (0 <= project_quotas[res] < delta + 

1349 project_usages[res]['total'] or 

1350 user_or_st_quotas[res] < delta + 

1351 user_or_st_usages[res].total)] 

1352 

1353 # NOTE(carloss): If OverQuota is allowed, there is no problem to exceed 

1354 # the quotas, so we reset the overs list and LOG it. 

1355 if overs and overquota_allowed: 1355 ↛ 1356line 1355 didn't jump to line 1356 because the condition on line 1355 was never true

1356 msg = _("The service has identified one or more exceeded " 

1357 "quotas. Please check the quotas for project " 

1358 "%(project_id)s, user %(user_id)s and share type " 

1359 "%(share_type_id)s, and adjust them if " 

1360 "necessary.") % { 

1361 "project_id": project_id, 

1362 "user_id": user_id, 

1363 "share_type_id": share_type_id 

1364 } 

1365 LOG.warning(msg) 

1366 overs = [] 

1367 

1368 # NOTE(Vek): The quota check needs to be in the transaction, 

1369 # but the transaction doesn't fail just because 

1370 # we're over quota, so the OverQuota raise is 

1371 # outside the transaction. If we did the raise 

1372 # here, our usage updates would be discarded, but 

1373 # they're not invalidated by being over-quota. 

1374 

1375 # Create the reservations 

1376 if not overs: 1376 ↛ 1406line 1376 didn't jump to line 1406 because the condition on line 1376 was always true

1377 reservations = [] 

1378 for res, delta in deltas.items(): 

1379 reservation = _reservation_create( 

1380 elevated, 

1381 uuidutils.generate_uuid(), 

1382 user_or_st_usages[res], 

1383 project_id, 

1384 user_id, 

1385 res, delta, expire, 

1386 share_type_id=share_type_id, 

1387 ) 

1388 reservations.append(reservation.uuid) 

1389 

1390 # Also update the reserved quantity 

1391 # NOTE(Vek): Again, we are only concerned here about 

1392 # positive increments. Here, though, we're 

1393 # worried about the following scenario: 

1394 # 

1395 # 1) User initiates resize down. 

1396 # 2) User allocates a new instance. 

1397 # 3) Resize down fails or is reverted. 

1398 # 4) User is now over quota. 

1399 # 

1400 # To prevent this, we only update the 

1401 # reserved value if the delta is positive. 

1402 if delta > 0: 

1403 user_or_st_usages[res].reserved += delta 

1404 

1405 # Apply updates to the usages table 

1406 for usage_ref in user_or_st_usages.values(): 

1407 context.session.add(usage_ref) 

1408 

1409 # NOTE(stephenfin): commit changes before we raise any exceptions 

1410 

1411 context.session.commit() 

1412 context.session.begin() 

1413 

1414 if unders: 

1415 LOG.warning("Change will make usage less than 0 for the following " 

1416 "resources: %s", unders) 

1417 if overs: 1417 ↛ 1418line 1417 didn't jump to line 1418 because the condition on line 1417 was never true

1418 if project_quotas == user_or_st_quotas: 

1419 usages = project_usages 

1420 else: 

1421 usages = user_or_st_usages 

1422 usages = {k: dict(in_use=v['in_use'], reserved=v['reserved']) 

1423 for k, v in usages.items()} 

1424 raise exception.OverQuota( 

1425 overs=sorted(overs), quotas=user_or_st_quotas, usages=usages) 

1426 

1427 return reservations 

1428 

1429 

1430def _quota_reservations_query(context, reservations): 

1431 """Return the relevant reservations.""" 

1432 return model_query( 

1433 context, models.Reservation, 

1434 read_deleted="no", 

1435 ).filter( 

1436 models.Reservation.uuid.in_(reservations), 

1437 ).with_for_update() 

1438 

1439 

1440@require_context 

1441@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

1442@context_manager.writer.independent 

1443def reservation_commit(context, reservations, project_id=None, user_id=None, 

1444 share_type_id=None): 

1445 if share_type_id: 

1446 st_usages = _get_share_type_quota_usages( 

1447 context, project_id, share_type_id, 

1448 ) 

1449 else: 

1450 st_usages = {} 

1451 user_usages = _get_user_quota_usages(context, project_id, user_id) 

1452 

1453 reservation_query = _quota_reservations_query(context, reservations) 

1454 for reservation in reservation_query.all(): 

1455 if reservation['share_type_id']: 

1456 usages = st_usages 

1457 else: 

1458 usages = user_usages 

1459 usage = usages[reservation.resource] 

1460 if reservation.delta >= 0: 

1461 usage.reserved -= reservation.delta 

1462 usage.in_use += reservation.delta 

1463 reservation_query.soft_delete(synchronize_session=False) 

1464 

1465 

1466@require_context 

1467@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

1468@context_manager.writer.independent 

1469def reservation_rollback(context, reservations, project_id=None, user_id=None, 

1470 share_type_id=None): 

1471 if share_type_id: 1471 ↛ 1472line 1471 didn't jump to line 1472 because the condition on line 1471 was never true

1472 st_usages = _get_share_type_quota_usages( 

1473 context, project_id, share_type_id, 

1474 ) 

1475 else: 

1476 st_usages = {} 

1477 user_usages = _get_user_quota_usages(context, project_id, user_id) 

1478 

1479 reservation_query = _quota_reservations_query(context, reservations) 

1480 for reservation in reservation_query.all(): 

1481 if reservation['share_type_id']: 1481 ↛ 1482line 1481 didn't jump to line 1482 because the condition on line 1481 was never true

1482 usages = st_usages 

1483 else: 

1484 usages = user_usages 

1485 usage = usages[reservation.resource] 

1486 if reservation.delta >= 0: 1486 ↛ 1480line 1486 didn't jump to line 1480 because the condition on line 1486 was always true

1487 usage.reserved -= reservation.delta 

1488 reservation_query.soft_delete(synchronize_session=False) 

1489 

1490 

1491@require_admin_context 

1492@context_manager.writer.independent 

1493def quota_destroy_all_by_project_and_user(context, project_id, user_id): 

1494 model_query( 

1495 context, models.ProjectUserQuota, read_deleted="no", 

1496 ).filter_by( 

1497 project_id=project_id, 

1498 ).filter_by(user_id=user_id).soft_delete(synchronize_session=False) 

1499 

1500 model_query( 

1501 context, models.QuotaUsage, read_deleted="no", 

1502 ).filter_by( 

1503 project_id=project_id, 

1504 ).filter_by(user_id=user_id).soft_delete(synchronize_session=False) 

1505 

1506 model_query( 

1507 context, models.Reservation, read_deleted="no", 

1508 ).filter_by( 

1509 project_id=project_id, 

1510 ).filter_by(user_id=user_id).soft_delete(synchronize_session=False) 

1511 

1512 

1513@require_admin_context 

1514@context_manager.writer.independent 

1515def quota_destroy_all_by_share_type(context, share_type_id, project_id=None): 

1516 return _quota_destroy_all_by_share_type( 

1517 context, share_type_id, project_id=project_id, 

1518 ) 

1519 

1520 

1521@require_admin_context 

1522def _quota_destroy_all_by_share_type(context, share_type_id, project_id=None): 

1523 """Soft deletes all quotas, usages and reservations. 

1524 

1525 :param context: request context for queries, updates and logging 

1526 :param share_type_id: ID of the share type to filter the quotas, usages 

1527 and reservations under. 

1528 :param project_id: ID of the project to filter the quotas, usages and 

1529 reservations under. If not provided, share type quotas for all 

1530 projects will be acted upon. 

1531 """ 

1532 share_type_quotas = model_query( 

1533 context, models.ProjectShareTypeQuota, 

1534 read_deleted="no", 

1535 ).filter_by(share_type_id=share_type_id) 

1536 

1537 share_type_quota_usages = model_query( 

1538 context, models.QuotaUsage, read_deleted="no", 

1539 ).filter_by(share_type_id=share_type_id) 

1540 

1541 share_type_quota_reservations = model_query( 

1542 context, models.Reservation, read_deleted="no", 

1543 ).filter_by(share_type_id=share_type_id) 

1544 

1545 if project_id is not None: 1545 ↛ 1546line 1545 didn't jump to line 1546 because the condition on line 1545 was never true

1546 share_type_quotas = share_type_quotas.filter_by( 

1547 project_id=project_id, 

1548 ) 

1549 share_type_quota_usages = share_type_quota_usages.filter_by( 

1550 project_id=project_id, 

1551 ) 

1552 share_type_quota_reservations = ( 

1553 share_type_quota_reservations.filter_by(project_id=project_id) 

1554 ) 

1555 

1556 share_type_quotas.soft_delete(synchronize_session=False) 

1557 share_type_quota_usages.soft_delete(synchronize_session=False) 

1558 share_type_quota_reservations.soft_delete(synchronize_session=False) 

1559 

1560 

1561@require_admin_context 

1562@context_manager.writer.independent 

1563def quota_destroy_all_by_project(context, project_id): 

1564 model_query( 

1565 context, models.Quota, read_deleted="no", 

1566 ).filter_by( 

1567 project_id=project_id, 

1568 ).soft_delete(synchronize_session=False) 

1569 

1570 model_query( 

1571 context, models.ProjectUserQuota, read_deleted="no", 

1572 ).filter_by( 

1573 project_id=project_id, 

1574 ).soft_delete(synchronize_session=False) 

1575 

1576 model_query( 

1577 context, models.QuotaUsage, read_deleted="no", 

1578 ).filter_by( 

1579 project_id=project_id, 

1580 ).soft_delete(synchronize_session=False) 

1581 

1582 model_query( 

1583 context, models.Reservation, read_deleted="no", 

1584 ).filter_by( 

1585 project_id=project_id, 

1586 ).soft_delete(synchronize_session=False) 

1587 

1588 

1589@require_admin_context 

1590@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

1591@context_manager.writer 

1592def reservation_expire(context): 

1593 current_time = timeutils.utcnow() 

1594 reservation_query = model_query( 

1595 context, models.Reservation, 

1596 read_deleted="no" 

1597 ).filter(models.Reservation.expire < current_time) 

1598 

1599 for reservation in reservation_query.all(): 

1600 if reservation.delta >= 0: 1600 ↛ 1599line 1600 didn't jump to line 1599 because the condition on line 1600 was always true

1601 quota_usage = model_query( 

1602 context, models.QuotaUsage, read_deleted="no", 

1603 ).filter( 

1604 models.QuotaUsage.id == reservation.usage_id, 

1605 ).first() 

1606 quota_usage.reserved -= reservation.delta 

1607 context.session.add(quota_usage) 

1608 

1609 reservation_query.soft_delete(synchronize_session=False) 

1610 

1611 

1612################ 

1613 

1614def _extract_subdict_by_fields(source_dict, fields): 

1615 dict_to_extract_from = copy.deepcopy(source_dict) 

1616 sub_dict = {} 

1617 for field in fields: 

1618 field_value = dict_to_extract_from.pop(field, None) 

1619 if field_value: 

1620 sub_dict.update({field: field_value}) 

1621 

1622 return sub_dict, dict_to_extract_from 

1623 

1624 

1625def _extract_share_instance_values(values): 

1626 share_instance_model_fields = [ 

1627 'status', 'host', 'scheduled_at', 'launched_at', 'terminated_at', 

1628 'share_server_id', 'share_network_id', 'availability_zone_id', 

1629 'replica_state', 'share_type_id', 'share_type', 'access_rules_status', 

1630 'mount_point_name', 'encryption_key_ref', 

1631 ] 

1632 share_instance_values, share_values = ( 

1633 _extract_subdict_by_fields(values, share_instance_model_fields) 

1634 ) 

1635 return share_instance_values, share_values 

1636 

1637 

1638def _change_size_to_instance_size(snap_instance_values): 

1639 if 'size' in snap_instance_values: 

1640 snap_instance_values['instance_size'] = snap_instance_values['size'] 

1641 snap_instance_values.pop('size') 

1642 

1643 

1644def _extract_snapshot_instance_values(values): 

1645 fields = ['status', 'progress', 'provider_location'] 

1646 snapshot_instance_values, snapshot_values = ( 

1647 _extract_subdict_by_fields(values, fields) 

1648 ) 

1649 return snapshot_instance_values, snapshot_values 

1650 

1651 

1652################ 

1653 

1654 

1655@require_context 

1656@context_manager.writer 

1657def share_instance_create(context, share_id, values): 

1658 return _share_instance_create(context, share_id, values) 

1659 

1660 

1661def _share_instance_create(context, share_id, values): 

1662 if not values.get('id'): 

1663 values['id'] = uuidutils.generate_uuid() 

1664 values.update({'share_id': share_id}) 

1665 

1666 share_instance_ref = models.ShareInstance() 

1667 share_instance_ref.update(values) 

1668 share_instance_ref.save(session=context.session) 

1669 

1670 return _share_instance_get(context, share_instance_ref['id']) 

1671 

1672 

1673@require_context 

1674@require_availability_zone_exists(strict=False) 

1675@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

1676@context_manager.writer 

1677def share_instance_update(context, share_instance_id, values, 

1678 with_share_data=False): 

1679 instance_ref = _share_instance_update( 

1680 context, share_instance_id, values, 

1681 ) 

1682 if with_share_data: 

1683 parent_share = _share_get(context, instance_ref['share_id']) 

1684 instance_ref.set_share_data(parent_share) 

1685 

1686 return instance_ref 

1687 

1688 

1689def _share_instance_update( 

1690 context, share_instance_id, values, with_share_data=False 

1691): 

1692 share_instance_ref = _share_instance_get( 

1693 context, share_instance_id, 

1694 with_share_data=with_share_data) 

1695 share_instance_ref.update(values) 

1696 share_instance_ref.save(session=context.session) 

1697 return share_instance_ref 

1698 

1699 

1700@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

1701@context_manager.writer 

1702def share_and_snapshot_instances_status_update( 

1703 context, values, share_instance_ids=None, snapshot_instance_ids=None, 

1704 current_expected_status=None, 

1705): 

1706 updated_share_instances = None 

1707 updated_snapshot_instances = None 

1708 

1709 if current_expected_status and share_instance_ids: 

1710 filters = {'instance_ids': share_instance_ids} 

1711 share_instances = _share_instance_get_all(context, filters=filters) 

1712 all_instances_are_compliant = all( 

1713 instance['status'] == current_expected_status 

1714 for instance in share_instances) 

1715 

1716 if not all_instances_are_compliant: 

1717 msg = _('At least one of the shares is not in the %(status)s ' 

1718 'status.') % { 

1719 'status': current_expected_status 

1720 } 

1721 raise exception.InvalidShareInstance(reason=msg) 

1722 

1723 if current_expected_status and snapshot_instance_ids: 

1724 filters = {'instance_ids': snapshot_instance_ids} 

1725 snapshot_instances = _share_snapshot_instance_get_all_with_filters( 

1726 context, filters, 

1727 ) 

1728 all_snap_instances_are_compliant = all( 

1729 snap_instance['status'] == current_expected_status 

1730 for snap_instance in snapshot_instances) 

1731 if not all_snap_instances_are_compliant: 1731 ↛ 1738line 1731 didn't jump to line 1738 because the condition on line 1731 was always true

1732 msg = _('At least one of the snapshots is not in the ' 

1733 '%(status)s status.') % { 

1734 'status': current_expected_status 

1735 } 

1736 raise exception.InvalidShareSnapshotInstance(reason=msg) 

1737 

1738 if share_instance_ids: 1738 ↛ 1743line 1738 didn't jump to line 1743 because the condition on line 1738 was always true

1739 updated_share_instances = _share_instance_status_update( 

1740 context, share_instance_ids, values, 

1741 ) 

1742 

1743 if snapshot_instance_ids: 1743 ↛ 1748line 1743 didn't jump to line 1748 because the condition on line 1743 was always true

1744 updated_snapshot_instances = _share_snapshot_instances_status_update( 

1745 context, snapshot_instance_ids, values, 

1746 ) 

1747 

1748 return updated_share_instances, updated_snapshot_instances 

1749 

1750 

1751@require_context 

1752@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

1753@context_manager.writer 

1754def share_instance_status_update(context, share_instance_ids, values): 

1755 return _share_instance_status_update(context, share_instance_ids, values) 

1756 

1757 

1758def _share_instance_status_update(context, share_instance_ids, values): 

1759 result = model_query( 

1760 context, models.ShareInstance, read_deleted="no", 

1761 ).filter( 

1762 models.ShareInstance.id.in_(share_instance_ids) 

1763 ).update( 

1764 values, synchronize_session=False, 

1765 ) 

1766 return result 

1767 

1768 

1769@require_context 

1770@context_manager.reader 

1771def share_instance_get(context, share_instance_id, with_share_data=False): 

1772 return _share_instance_get( 

1773 context, share_instance_id, 

1774 with_share_data=with_share_data, 

1775 ) 

1776 

1777 

1778def _share_instance_get(context, share_instance_id, with_share_data=False): 

1779 result = model_query( 

1780 context, models.ShareInstance, 

1781 ).filter_by( 

1782 id=share_instance_id, 

1783 ).options( 

1784 orm.joinedload( 

1785 models.ShareInstance.export_locations 

1786 ).joinedload(models.ShareInstanceExportLocations._el_metadata_bare), 

1787 orm.joinedload(models.ShareInstance.share_type), 

1788 ).first() 

1789 if result is None: 

1790 raise exception.NotFound() 

1791 

1792 if with_share_data: 

1793 parent_share = _share_get(context, result['share_id']) 

1794 result.set_share_data(parent_share) 

1795 

1796 return result 

1797 

1798 

1799@require_admin_context 

1800@context_manager.reader 

1801def share_instance_get_all(context, filters=None): 

1802 return _share_instance_get_all(context, filters=filters) 

1803 

1804 

1805@require_admin_context 

1806def _share_instance_get_all(context, filters=None): 

1807 query = model_query( 

1808 context, models.ShareInstance, read_deleted="no", 

1809 ).options( 

1810 orm.joinedload(models.ShareInstance.export_locations), 

1811 ) 

1812 

1813 filters = filters or {} 

1814 

1815 export_location_id = filters.get('export_location_id') 

1816 export_location_path = filters.get('export_location_path') 

1817 if export_location_id or export_location_path: 

1818 query = query.join( 

1819 models.ShareInstanceExportLocations, 

1820 models.ShareInstanceExportLocations.share_instance_id == 

1821 models.ShareInstance.id) 

1822 if export_location_path: 

1823 query = query.filter( 

1824 models.ShareInstanceExportLocations.path == 

1825 export_location_path) 

1826 if export_location_id: 

1827 query = query.filter( 

1828 models.ShareInstanceExportLocations.uuid == 

1829 export_location_id) 

1830 

1831 query = query.join( 

1832 models.Share, 

1833 models.Share.id == models.ShareInstance.share_id, 

1834 ) 

1835 is_soft_deleted = filters.get('is_soft_deleted') 

1836 if is_soft_deleted: 

1837 query = query.filter(models.Share.is_soft_deleted == true()) 

1838 else: 

1839 query = query.filter(models.Share.is_soft_deleted == false()) 

1840 

1841 instance_ids = filters.get('instance_ids') 

1842 if instance_ids: 

1843 query = query.filter(models.ShareInstance.id.in_(instance_ids)) 

1844 

1845 # TODO(gouthamr): This DB API method needs to be generalized for all 

1846 # share instance fields. 

1847 host = filters.get('host') 

1848 if host: 

1849 query = query.filter( 

1850 or_(models.ShareInstance.host == host, 

1851 models.ShareInstance.host.like("{0}#%".format(host))) 

1852 ) 

1853 share_server_id = filters.get('share_server_id') 

1854 if share_server_id: 1854 ↛ 1855line 1854 didn't jump to line 1855 because the condition on line 1854 was never true

1855 query = query.filter( 

1856 models.ShareInstance.share_server_id == share_server_id) 

1857 

1858 status = filters.get('status') 

1859 if status: 

1860 query = query.filter(models.ShareInstance.status == status) 

1861 

1862 encryption_key_ref = filters.get('encryption_key_ref') 

1863 if encryption_key_ref: 1863 ↛ 1864line 1863 didn't jump to line 1864 because the condition on line 1863 was never true

1864 query = query.filter( 

1865 models.ShareInstance.encryption_key_ref == encryption_key_ref) 

1866 

1867 # Returns list of share instances that satisfy filters. 

1868 query = query.all() 

1869 return query 

1870 

1871 

1872@require_context 

1873def _update_share_instance_usages(context, share, instance_ref, 

1874 is_replica=False, 

1875 deferred_delete=False): 

1876 deltas = {} 

1877 # if share is expected to be deferred_deleted, we drop its quotas 

1878 # whether or not it has additional share instances 

1879 no_instances_remain = deferred_delete or len(share.instances) == 0 

1880 share_usages_to_release = {"shares": -1, "gigabytes": -share['size']} 

1881 replica_usages_to_release = {"share_replicas": -1, 

1882 "replica_gigabytes": -share['size']} 

1883 

1884 if is_replica and no_instances_remain: 

1885 # A share that had a replication_type is being deleted, so there's 

1886 # need to update the share replica quotas and the share quotas 

1887 deltas.update(replica_usages_to_release) 

1888 deltas.update(share_usages_to_release) 

1889 elif is_replica: 

1890 # The user is deleting a share replica 

1891 deltas.update(replica_usages_to_release) 

1892 else: 

1893 # A share with no replication_type is being deleted 

1894 deltas.update(share_usages_to_release) 

1895 

1896 reservations = None 

1897 try: 

1898 # we give the user_id of the share, to update 

1899 # the quota usage for the user, who created the share 

1900 reservations = QUOTAS.reserve( 

1901 context, 

1902 project_id=share['project_id'], 

1903 user_id=share['user_id'], 

1904 share_type_id=instance_ref['share_type_id'], 

1905 **deltas) 

1906 QUOTAS.commit( 

1907 context, reservations, project_id=share['project_id'], 

1908 user_id=share['user_id'], 

1909 share_type_id=instance_ref['share_type_id']) 

1910 except Exception: 

1911 resource_name = ( 

1912 'share replica' if is_replica else 'share') 

1913 resource_id = instance_ref['id'] if is_replica else share['id'] 

1914 msg = (_("Failed to update usages deleting %(resource_name)s " 

1915 "'%(id)s'.") % {'id': resource_id, 

1916 "resource_name": resource_name}) 

1917 LOG.exception(msg) 

1918 if reservations: 

1919 QUOTAS.rollback( 

1920 context, reservations, 

1921 share_type_id=instance_ref['share_type_id']) 

1922 

1923 

1924@require_context 

1925@context_manager.writer 

1926def share_instance_delete(context, instance_id, need_to_update_usages=False): 

1927 _share_instance_delete( 

1928 context, instance_id, 

1929 need_to_update_usages=need_to_update_usages, 

1930 ) 

1931 

1932 

1933def _share_instance_delete(context, instance_id, 

1934 need_to_update_usages=False): 

1935 

1936 export_locations_update(context, instance_id, [], delete=True) 

1937 instance_ref = _share_instance_get(context, instance_id) 

1938 is_replica = instance_ref['replica_state'] is not None 

1939 instance_ref.soft_delete(session=context.session, update_status=True) 

1940 

1941 share = _share_get(context, instance_ref['share_id']) 

1942 if len(share.instances) == 0: 

1943 

1944 # NOTE(zzzeek) currently this potentially is required for current 

1945 # tempest runs to pass 

1946 with context_manager.writer.independent.using(context) as oob_session: 

1947 oob_session.query(models.ShareAccessMapping).filter_by( 

1948 share_id=share['id'] 

1949 ).soft_delete() 

1950 

1951 context.session.query(models.ShareMetadata).filter_by( 

1952 share_id=share['id'], 

1953 ).soft_delete() 

1954 share.soft_delete(session=context.session) 

1955 

1956 if need_to_update_usages: 

1957 _update_share_instance_usages(context, share, instance_ref, 

1958 is_replica=is_replica, 

1959 deferred_delete=False) 

1960 

1961 

1962@require_context 

1963@context_manager.writer 

1964def update_share_instance_quota_usages(context, instance_id): 

1965 # This method is specifically written for deferred deletion share 

1966 # instance usage. 

1967 instance_ref = _share_instance_get(context, instance_id) 

1968 is_replica = instance_ref['replica_state'] is not None 

1969 share = _share_get(context, instance_ref['share_id']) 

1970 _update_share_instance_usages(context, share, instance_ref, 

1971 is_replica=is_replica, 

1972 deferred_delete=True) 

1973 

1974 

1975def _set_instances_share_data(instances): 

1976 instances = instances.options( 

1977 orm.joinedload(models.ShareInstance.share)).all() 

1978 instances = [s for s in instances if s.share] 

1979 for s in instances: 

1980 s.set_share_data(s.share) 

1981 

1982 return instances 

1983 

1984 

1985@require_admin_context 

1986@context_manager.reader 

1987def share_instance_get_all_by_host(context, host, with_share_data=False, 

1988 status=None): 

1989 """Retrieves all share instances hosted on a host.""" 

1990 instances = ( 

1991 model_query(context, models.ShareInstance).filter( 

1992 or_( 

1993 models.ShareInstance.host == host, 

1994 models.ShareInstance.host.like("{0}#%".format(host)) 

1995 ) 

1996 ) 

1997 ) 

1998 if status is not None: 

1999 instances = instances.filter(models.ShareInstance.status == status) 

2000 if with_share_data: 

2001 instances = _set_instances_share_data(instances) 

2002 else: 

2003 # Returns list of all instances that satisfy filters. 

2004 instances = instances.all() 

2005 return instances 

2006 

2007 

2008@require_context 

2009@context_manager.reader 

2010def share_instance_sizes_sum_by_host(context, host): 

2011 result = model_query( 

2012 context, models.Share, func.sum(models.Share.size), 

2013 ).join( 

2014 models.ShareInstance.share, 

2015 ).filter(or_( 

2016 models.ShareInstance.host == host, 

2017 models.ShareInstance.host.like("{0}#%".format(host)), 

2018 )).first() 

2019 return int(result[0] or 0) 

2020 

2021 

2022@require_context 

2023@context_manager.reader 

2024def share_instance_get_all_by_share_network(context, share_network_id): 

2025 """Returns list of share instances that belong to given share network.""" 

2026 result = ( 

2027 model_query(context, models.ShareInstance).filter( 

2028 models.ShareInstance.share_network_id == share_network_id, 

2029 ).all() 

2030 ) 

2031 return result 

2032 

2033 

2034@require_context 

2035@context_manager.reader 

2036def share_instance_get_all_by_share_server(context, share_server_id, 

2037 with_share_data=False): 

2038 """Returns list of share instance with given share server.""" 

2039 result = ( 

2040 model_query(context, models.ShareInstance).filter( 

2041 models.ShareInstance.share_server_id == share_server_id, 

2042 ) 

2043 ) 

2044 

2045 if with_share_data: 2045 ↛ 2046line 2045 didn't jump to line 2046 because the condition on line 2045 was never true

2046 result = _set_instances_share_data(result) 

2047 else: 

2048 result = result.all() 

2049 

2050 return result 

2051 

2052 

2053@require_context 

2054@context_manager.reader 

2055def share_instance_get_all_by_share(context, share_id): 

2056 """Returns list of share instances that belong to given share.""" 

2057 result = ( 

2058 model_query(context, models.ShareInstance).filter( 

2059 models.ShareInstance.share_id == share_id, 

2060 ).all() 

2061 ) 

2062 return result 

2063 

2064 

2065@require_context 

2066@context_manager.reader 

2067def share_instance_get_all_by_share_group_id(context, share_group_id): 

2068 """Returns list of share instances that belong to given share group.""" 

2069 result = ( 

2070 model_query(context, models.Share).filter( 

2071 models.Share.share_group_id == share_group_id, 

2072 ).all() 

2073 ) 

2074 instances = [] 

2075 for share in result: 

2076 instance = share.instance 

2077 instance.set_share_data(share) 

2078 instances.append(instance) 

2079 

2080 return instances 

2081 

2082 

2083################ 

2084 

2085def _share_replica_get_with_filters(context, share_id=None, replica_id=None, 

2086 replica_state=None, status=None, 

2087 with_share_server=True): 

2088 

2089 query = model_query(context, models.ShareInstance, read_deleted="no") 

2090 

2091 if not context.is_admin: 

2092 query = query.join( 

2093 models.Share, 

2094 models.ShareInstance.share_id == models.Share.id 

2095 ).filter( 

2096 models.Share.project_id == context.project_id, 

2097 ) 

2098 

2099 if share_id is not None: 

2100 query = query.filter(models.ShareInstance.share_id == share_id) 

2101 

2102 if replica_id is not None: 

2103 query = query.filter(models.ShareInstance.id == replica_id) 

2104 

2105 if replica_state is not None: 

2106 query = query.filter( 

2107 models.ShareInstance.replica_state == replica_state) 

2108 else: 

2109 query = query.filter(models.ShareInstance.replica_state.isnot(None)) 

2110 

2111 if status is not None: 

2112 query = query.filter(models.ShareInstance.status == status) 

2113 

2114 if with_share_server: 

2115 query = query.options( 

2116 orm.joinedload(models.ShareInstance.share_server), 

2117 ) 

2118 

2119 return query 

2120 

2121 

2122@require_context 

2123@context_manager.reader 

2124def share_replicas_get_all(context, with_share_data=False, 

2125 with_share_server=True): 

2126 """Returns replica instances for all available replicated shares.""" 

2127 result = _share_replica_get_with_filters( 

2128 context, with_share_server=with_share_server, 

2129 ) 

2130 

2131 if with_share_data: 

2132 result = _set_instances_share_data(result) 

2133 else: 

2134 result = result.all() 

2135 

2136 return result 

2137 

2138 

2139@require_context 

2140@context_manager.reader 

2141def share_replicas_get_all_by_share(context, share_id, 

2142 with_share_data=False, 

2143 with_share_server=False,): 

2144 """Returns replica instances for a given share.""" 

2145 result = _share_replica_get_with_filters( 

2146 context, with_share_server=with_share_server, 

2147 share_id=share_id, 

2148 ) 

2149 

2150 if with_share_data: 

2151 result = _set_instances_share_data(result) 

2152 else: 

2153 result = result.all() 

2154 

2155 return result 

2156 

2157 

2158@require_context 

2159@context_manager.reader 

2160def share_replicas_get_available_active_replica(context, share_id, 

2161 with_share_data=False, 

2162 with_share_server=False): 

2163 """Returns an 'active' replica instance that is 'available'.""" 

2164 result = _share_replica_get_with_filters( 

2165 context, with_share_server=with_share_server, share_id=share_id, 

2166 replica_state=constants.REPLICA_STATE_ACTIVE, 

2167 status=constants.STATUS_AVAILABLE, 

2168 ) 

2169 

2170 if result.first() and with_share_data: 

2171 result = _set_instances_share_data(result)[0] 

2172 else: 

2173 result = result.first() 

2174 

2175 return result 

2176 

2177 

2178@require_context 

2179@context_manager.reader 

2180def share_replica_get(context, replica_id, with_share_data=False, 

2181 with_share_server=False): 

2182 """Returns summary of requested replica if available.""" 

2183 result = _share_replica_get_with_filters( 

2184 context, 

2185 with_share_server=with_share_server, 

2186 replica_id=replica_id, 

2187 ) 

2188 

2189 if result.first() and with_share_data: 

2190 result = _set_instances_share_data(result)[0] 

2191 else: 

2192 result = result.first() 

2193 

2194 if result is None: 

2195 raise exception.ShareReplicaNotFound(replica_id=replica_id) 

2196 

2197 return result 

2198 

2199 

2200@require_context 

2201@require_availability_zone_exists(strict=False) 

2202@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

2203@context_manager.writer 

2204def share_replica_update(context, share_replica_id, values, 

2205 with_share_data=False): 

2206 """Updates a share replica with specified values.""" 

2207 updated_share_replica = _share_instance_update( 

2208 context, share_replica_id, values, 

2209 with_share_data=with_share_data 

2210 ) 

2211 

2212 return updated_share_replica 

2213 

2214 

2215@require_context 

2216@context_manager.writer 

2217def share_replica_delete( 

2218 context, replica_id, need_to_update_usages=True, 

2219): 

2220 """Deletes a share replica.""" 

2221 

2222 _share_instance_delete( 

2223 context, replica_id, 

2224 need_to_update_usages=need_to_update_usages, 

2225 ) 

2226 

2227 

2228################ 

2229 

2230 

2231def _process_share_filters(query, filters, project_id=None, is_public=False): 

2232 if filters is None: 2232 ↛ 2233line 2232 didn't jump to line 2233 because the condition on line 2232 was never true

2233 filters = {} 

2234 

2235 share_filter_keys = ['share_group_id', 'snapshot_id', 

2236 'is_soft_deleted', 'source_backup_id'] 

2237 instance_filter_keys = ['share_server_id', 'status', 'share_type_id', 

2238 'host', 'share_network_id', 'mount_point_name', 

2239 'encryption_key_ref'] 

2240 share_filters = {} 

2241 instance_filters = {} 

2242 

2243 for k, v in filters.items(): 

2244 share_filters.update({k: v}) if k in share_filter_keys else None 

2245 instance_filters.update({k: v}) if k in instance_filter_keys else None 

2246 

2247 no_key = 'key_is_absent' 

2248 

2249 def _filter_data(query, model, desired_filters): 

2250 for key, value in desired_filters.items(): 

2251 filter_attr = getattr(model, key, no_key) 

2252 if filter_attr == no_key: 2252 ↛ 2253line 2252 didn't jump to line 2253 because the condition on line 2252 was never true

2253 pass 

2254 query = query.filter(filter_attr == value) 

2255 return query 

2256 

2257 if share_filters: 2257 ↛ 2259line 2257 didn't jump to line 2259 because the condition on line 2257 was always true

2258 query = _filter_data(query, models.Share, share_filters) 

2259 if instance_filters: 

2260 query = _filter_data(query, models.ShareInstance, instance_filters) 

2261 

2262 if project_id: 

2263 if is_public: 2263 ↛ 2264line 2263 didn't jump to line 2264 because the condition on line 2263 was never true

2264 query = query.filter(or_(models.Share.project_id == project_id, 

2265 models.Share.is_public)) 

2266 else: 

2267 query = query.filter(models.Share.project_id == project_id) 

2268 

2269 safe_regex_filter, db_regexp_op = _get_regexp_ops(CONF.database.connection) 

2270 display_name = filters.get('display_name') 

2271 if display_name: 

2272 query = query.filter( 

2273 models.Share.display_name == display_name) 

2274 else: 

2275 display_name = filters.get('display_name~') 

2276 if display_name: 

2277 query = query.filter( 

2278 models.Share.display_name.op(db_regexp_op)( 

2279 _get_filter_value_by_op( 

2280 db_regexp_op, display_name, safe_regex_filter))) 

2281 

2282 display_description = filters.get('display_description') 

2283 if display_description: 

2284 query = query.filter( 

2285 models.Share.display_description == display_description) 

2286 else: 

2287 display_description = filters.get('display_description~') 

2288 if display_description: 

2289 query = query.filter( 

2290 models.Share.display_description.op(db_regexp_op)( 

2291 _get_filter_value_by_op( 

2292 db_regexp_op, display_description, safe_regex_filter))) 

2293 

2294 export_location_id = filters.pop('export_location_id', None) 

2295 export_location_path = filters.pop('export_location_path', None) 

2296 if export_location_id or export_location_path: 

2297 query = query.join( 

2298 models.ShareInstanceExportLocations, 

2299 models.ShareInstanceExportLocations.share_instance_id == 

2300 models.ShareInstance.id, 

2301 ) 

2302 if export_location_path: 

2303 query = query.filter( 

2304 models.ShareInstanceExportLocations.path == 

2305 export_location_path) 

2306 if export_location_id: 

2307 query = query.filter( 

2308 models.ShareInstanceExportLocations.uuid == 

2309 export_location_id) 

2310 

2311 if 'metadata' in filters: 2311 ↛ 2312line 2311 didn't jump to line 2312 because the condition on line 2311 was never true

2312 for k, v in filters['metadata'].items(): 

2313 # pylint: disable=no-member 

2314 query = query.filter( 

2315 or_(models.Share.share_metadata.any( 

2316 key=k, value=v))) 

2317 if 'extra_specs' in filters: 2317 ↛ 2318line 2317 didn't jump to line 2318 because the condition on line 2317 was never true

2318 query = query.join( 

2319 models.ShareTypeExtraSpecs, 

2320 models.ShareTypeExtraSpecs.share_type_id == 

2321 models.ShareInstance.share_type_id, 

2322 ) 

2323 for k, v in filters['extra_specs'].items(): 

2324 query = query.filter(and_(models.ShareTypeExtraSpecs.key == k, 

2325 models.ShareTypeExtraSpecs.value == v)) 

2326 

2327 if not filters.get('list_deferred_delete'): 

2328 query = query.filter(and_( 

2329 models.ShareInstance.status != ( 

2330 constants.STATUS_DEFERRED_DELETING), 

2331 models.ShareInstance.status != ( 

2332 constants.STATUS_ERROR_DEFERRED_DELETING))) 

2333 return query 

2334 

2335 

2336def _get_filter_value_by_op(op, filter_value, safe_regex_filter): 

2337 if op == 'LIKE': 2337 ↛ 2338line 2337 didn't jump to line 2338 because the condition on line 2337 was never true

2338 return u'%' + filter_value + u'%' 

2339 else: 

2340 return safe_regex_filter(filter_value) 

2341 

2342 

2343def _safe_regex_mysql(raw_string): 

2344 """Make regex safe to mysql. 

2345 

2346 Certain items like '|' are interpreted raw by mysql REGEX. If you 

2347 search for a single | then you trigger an error because it's 

2348 expecting content on either side. 

2349 

2350 For consistency sake we escape all '|'. This does mean we wouldn't 

2351 support something like foo|bar to match completely different 

2352 things, however, one can argue putting such complicated regex into 

2353 name search probably means you are doing this wrong. 

2354 """ 

2355 return raw_string.replace('|', '\\|') 

2356 

2357 

2358def _get_regexp_ops(connection): 

2359 """Return safety filter and db opts for regex.""" 

2360 regexp_op_map = { 

2361 'postgresql': '~', 

2362 'mysql': 'REGEXP', 

2363 'sqlite': 'REGEXP' 

2364 } 

2365 regex_safe_filters = { 

2366 'mysql': _safe_regex_mysql 

2367 } 

2368 db_type = _db_connection_type(connection) 

2369 

2370 return (regex_safe_filters.get(db_type, lambda x: x), 

2371 regexp_op_map.get(db_type, 'LIKE')) 

2372 

2373 

2374def _db_connection_type(db_connection): 

2375 """Returns a lowercase symbol for the db type. 

2376 

2377 This is useful when we need to change what we are doing per DB 

2378 (like handling regexes). In a CellsV2 world it probably needs to 

2379 do something better than use the database configuration string. 

2380 """ 

2381 

2382 db_string = db_connection.split(':')[0].split('+')[0] 

2383 return db_string.lower() 

2384 

2385 

2386def _metadata_refs(metadata_dict, meta_class): 

2387 metadata_refs = [] 

2388 if metadata_dict: 

2389 for k, v in metadata_dict.items(): 

2390 value = str(v) if isinstance(v, bool) else v 

2391 

2392 metadata_ref = meta_class() 

2393 metadata_ref['key'] = k 

2394 metadata_ref['value'] = value 

2395 metadata_refs.append(metadata_ref) 

2396 return metadata_refs 

2397 

2398 

2399@require_context 

2400@require_availability_zone_exists(strict=False) 

2401@context_manager.writer 

2402def share_create(context, share_values, create_share_instance=True): 

2403 values = copy.deepcopy(share_values) 

2404 values = ensure_model_dict_has_id(values) 

2405 values['share_metadata'] = _metadata_refs(values.get('metadata'), 

2406 models.ShareMetadata) 

2407 share_ref = models.Share() 

2408 share_instance_values, share_values = _extract_share_instance_values( 

2409 values) 

2410 share_ref.update(share_values) 

2411 share_ref.save(session=context.session) 

2412 

2413 if create_share_instance: 

2414 _share_instance_create(context, share_ref['id'], 

2415 share_instance_values) 

2416 

2417 # NOTE(u_glide): Do so to prevent errors with relationships 

2418 return _share_get(context, share_ref['id']) 

2419 

2420 

2421@require_admin_context 

2422def _share_data_get_for_project( 

2423 context, project_id, user_id, share_type_id=None, 

2424): 

2425 query = model_query( 

2426 context, models.Share, 

2427 func.count(models.Share.id), 

2428 func.sum(models.Share.size), 

2429 read_deleted="no", 

2430 ).filter_by(project_id=project_id) 

2431 if share_type_id: 

2432 query = query.join( 

2433 models.Share.instances, 

2434 ).filter_by(share_type_id=share_type_id) 

2435 elif user_id: 2435 ↛ 2437line 2435 didn't jump to line 2437 because the condition on line 2435 was always true

2436 query = query.filter_by(user_id=user_id) 

2437 result = query.first() 

2438 return (result[0] or 0, result[1] or 0) 

2439 

2440 

2441@require_context 

2442@require_availability_zone_exists(strict=False) 

2443@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

2444@context_manager.writer 

2445def share_update(context, share_id, update_values): 

2446 return _share_update(context, share_id, update_values) 

2447 

2448 

2449@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

2450def _share_update(context, share_id, update_values): 

2451 values = copy.deepcopy(update_values) 

2452 

2453 share_instance_values, share_values = _extract_share_instance_values( 

2454 values) 

2455 

2456 share_ref = _share_get(context, share_id) 

2457 

2458 _share_instance_update( 

2459 context, share_ref.instance['id'], share_instance_values, 

2460 ) 

2461 

2462 share_ref.update(share_values) 

2463 share_ref.save(session=context.session) 

2464 return share_ref 

2465 

2466 

2467@require_context 

2468@context_manager.reader 

2469def share_get(context, share_id, **kwargs): 

2470 return _share_get(context, share_id, **kwargs) 

2471 

2472 

2473def _share_get(context, share_id, **kwargs): 

2474 result = model_query( 

2475 context, models.Share, **kwargs, 

2476 ).options( 

2477 orm.joinedload(models.Share.share_metadata), 

2478 ).filter_by(id=share_id).first() 

2479 

2480 if result is None: 

2481 raise exception.NotFound() 

2482 

2483 return result 

2484 

2485 

2486def _share_get_all_with_filters(context, project_id=None, share_server_id=None, 

2487 share_group_id=None, filters=None, 

2488 is_public=False, sort_key=None, 

2489 sort_dir=None, show_count=False): 

2490 """Returns sorted list of shares that satisfies filters. 

2491 

2492 :param context: context to query under 

2493 :param project_id: project id that owns shares 

2494 :param share_server_id: share server that hosts shares 

2495 :param filters: dict of filters to specify share selection 

2496 :param is_public: public shares from other projects will be added 

2497 to result if True 

2498 :param sort_key: key of models.Share to be used for sorting 

2499 :param sort_dir: desired direction of sorting, can be 'asc' and 'desc' 

2500 :returns: list -- models.Share 

2501 :raises: exception.InvalidInput 

2502 """ 

2503 if filters is None: 

2504 filters = {} 

2505 

2506 if not sort_key: 

2507 sort_key = 'created_at' 

2508 if not sort_dir: 

2509 sort_dir = 'desc' 

2510 

2511 query = model_query( 

2512 context, models.Share, 

2513 ).options( 

2514 orm.joinedload(models.Share.share_metadata), 

2515 ).join( 

2516 models.ShareInstance, 

2517 models.ShareInstance.share_id == models.Share.id 

2518 ) 

2519 

2520 if share_group_id: 

2521 filters['share_group_id'] = share_group_id 

2522 if share_server_id: 

2523 filters['share_server_id'] = share_server_id 

2524 

2525 # if not specified is_soft_deleted filter, default is False, to get 

2526 # shares not in recycle bin. 

2527 if 'is_soft_deleted' not in filters: 

2528 filters['is_soft_deleted'] = False 

2529 

2530 query = _process_share_filters( 

2531 query, filters, project_id, is_public=is_public) 

2532 

2533 try: 

2534 query = apply_sorting(models.Share, query, sort_key, sort_dir) 

2535 except AttributeError: 

2536 try: 

2537 query = apply_sorting( 

2538 models.ShareInstance, query, sort_key, sort_dir) 

2539 except AttributeError: 

2540 msg = _("Wrong sorting key provided - '%s'.") % sort_key 

2541 raise exception.InvalidInput(reason=msg) 

2542 

2543 count = None 

2544 # NOTE(carloss): Count must be calculated before limit and offset are 

2545 # applied into the query. 

2546 if show_count: 

2547 count = query.order_by(models.Share.id).distinct().count() 

2548 

2549 if 'limit' in filters: 

2550 offset = filters.get('offset', 0) 

2551 query = query.limit(filters['limit']).offset(offset) 

2552 

2553 # Returns list of shares that satisfy filters. 

2554 query = query.all() 

2555 

2556 if show_count: 

2557 return count, query 

2558 

2559 return query 

2560 

2561 

2562@require_admin_context 

2563@context_manager.reader 

2564def share_get_all_expired(context): 

2565 query = model_query( 

2566 context, models.Share, 

2567 ).options( 

2568 orm.joinedload(models.Share.share_metadata), 

2569 ).join( 

2570 models.ShareInstance, 

2571 models.ShareInstance.share_id == models.Share.id, 

2572 ) 

2573 filters = {"is_soft_deleted": True} 

2574 query = _process_share_filters(query, filters=filters) 

2575 scheduled_deleted_attr = getattr(models.Share, 

2576 'scheduled_to_be_deleted_at', None) 

2577 now_time = timeutils.utcnow() 

2578 query = query.filter(scheduled_deleted_attr.op('<=')(now_time)) 

2579 result = query.all() 

2580 

2581 return result 

2582 

2583 

2584@require_admin_context 

2585@context_manager.reader 

2586def share_get_all(context, filters=None, sort_key=None, sort_dir=None): 

2587 project_id = filters.pop('project_id', None) if filters else None 

2588 query = _share_get_all_with_filters( 

2589 context, 

2590 project_id=project_id, 

2591 filters=filters, sort_key=sort_key, sort_dir=sort_dir) 

2592 return query 

2593 

2594 

2595@require_admin_context 

2596@context_manager.reader 

2597def share_get_all_with_count(context, filters=None, sort_key=None, 

2598 sort_dir=None): 

2599 count, query = _share_get_all_with_filters( 

2600 context, 

2601 filters=filters, sort_key=sort_key, sort_dir=sort_dir, 

2602 show_count=True) 

2603 return count, query 

2604 

2605 

2606@require_context 

2607@context_manager.reader 

2608def share_get_all_by_project(context, project_id, filters=None, 

2609 is_public=False, sort_key=None, sort_dir=None): 

2610 """Returns list of shares with given project ID.""" 

2611 query = _share_get_all_with_filters( 

2612 context, project_id=project_id, filters=filters, is_public=is_public, 

2613 sort_key=sort_key, sort_dir=sort_dir) 

2614 return query 

2615 

2616 

2617@require_context 

2618@context_manager.reader 

2619def share_get_all_by_project_with_count( 

2620 context, project_id, filters=None, is_public=False, sort_key=None, 

2621 sort_dir=None): 

2622 """Returns list of shares with given project ID.""" 

2623 count, query = _share_get_all_with_filters( 

2624 context, project_id=project_id, filters=filters, is_public=is_public, 

2625 sort_key=sort_key, sort_dir=sort_dir, show_count=True) 

2626 return count, query 

2627 

2628 

2629@require_context 

2630@context_manager.reader 

2631def share_get_all_by_share_group_id(context, share_group_id, 

2632 filters=None, sort_key=None, 

2633 sort_dir=None): 

2634 """Returns list of shares with given group ID.""" 

2635 query = _share_get_all_with_filters( 

2636 context, share_group_id=share_group_id, 

2637 filters=filters, sort_key=sort_key, sort_dir=sort_dir) 

2638 return query 

2639 

2640 

2641@require_context 

2642@context_manager.reader 

2643def share_get_all_by_share_group_id_with_count(context, share_group_id, 

2644 filters=None, sort_key=None, 

2645 sort_dir=None): 

2646 """Returns list of shares with given share group ID.""" 

2647 count, query = _share_get_all_with_filters( 

2648 context, share_group_id=share_group_id, 

2649 filters=filters, sort_key=sort_key, sort_dir=sort_dir, show_count=True) 

2650 return count, query 

2651 

2652 

2653@require_context 

2654@context_manager.reader 

2655def share_get_all_by_share_server(context, share_server_id, filters=None, 

2656 sort_key=None, sort_dir=None): 

2657 """Returns list of shares with given share server.""" 

2658 query = _share_get_all_with_filters( 

2659 context, share_server_id=share_server_id, filters=filters, 

2660 sort_key=sort_key, sort_dir=sort_dir) 

2661 return query 

2662 

2663 

2664@require_context 

2665@context_manager.reader 

2666def share_get_all_soft_deleted( 

2667 context, share_server_id, filters=None, sort_key=None, sort_dir=None): 

2668 """Returns list of shares in recycle bin with given share server.""" 

2669 if filters is None: 2669 ↛ 2671line 2669 didn't jump to line 2671 because the condition on line 2669 was always true

2670 filters = {} 

2671 filters["is_soft_deleted"] = True 

2672 query = _share_get_all_with_filters( 

2673 context, share_server_id=share_server_id, filters=filters, 

2674 sort_key=sort_key, sort_dir=sort_dir) 

2675 return query 

2676 

2677 

2678@require_context 

2679@context_manager.reader 

2680def share_get_all_by_share_server_with_count( 

2681 context, share_server_id, filters=None, sort_key=None, sort_dir=None): 

2682 """Returns list of shares with given share server.""" 

2683 count, query = _share_get_all_with_filters( 

2684 context, share_server_id=share_server_id, filters=filters, 

2685 sort_key=sort_key, sort_dir=sort_dir, show_count=True) 

2686 return count, query 

2687 

2688 

2689@require_context 

2690@context_manager.reader 

2691def share_get_all_soft_deleted_by_network( 

2692 context, share_network_id, filters=None, sort_key=None, sort_dir=None): 

2693 """Returns list of shares in recycle bin with given share network.""" 

2694 if filters is None: 2694 ↛ 2696line 2694 didn't jump to line 2696 because the condition on line 2694 was always true

2695 filters = {} 

2696 filters["share_network_id"] = share_network_id 

2697 filters["is_soft_deleted"] = True 

2698 query = _share_get_all_with_filters(context, filters=filters, 

2699 sort_key=sort_key, sort_dir=sort_dir) 

2700 return query 

2701 

2702 

2703@require_context 

2704@context_manager.writer 

2705def share_delete(context, share_id): 

2706 share_ref = _share_get(context, share_id) 

2707 

2708 if len(share_ref.instances) > 0: 2708 ↛ 2709line 2708 didn't jump to line 2709 because the condition on line 2708 was never true

2709 msg = _("Share %(id)s has %(count)s share instances.") % { 

2710 'id': share_id, 'count': len(share_ref.instances)} 

2711 raise exception.InvalidShare(msg) 

2712 

2713 share_ref.soft_delete(session=context.session) 

2714 

2715 context.session.query(models.ShareMetadata).filter_by( 

2716 share_id=share_id, 

2717 ).soft_delete() 

2718 

2719 

2720@require_context 

2721@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

2722@context_manager.writer 

2723def share_soft_delete(context, share_id): 

2724 now_time = timeutils.utcnow() 

2725 time_delta = datetime.timedelta( 

2726 seconds=CONF.soft_deleted_share_retention_time) 

2727 scheduled_to_be_deleted_at = now_time + time_delta 

2728 update_values = { 

2729 'is_soft_deleted': True, 

2730 'scheduled_to_be_deleted_at': scheduled_to_be_deleted_at 

2731 } 

2732 

2733 share_ref = _share_get(context, share_id) 

2734 share_ref.update(update_values) 

2735 share_ref.save(session=context.session) 

2736 

2737 

2738@require_context 

2739@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

2740@context_manager.writer 

2741def share_restore(context, share_id): 

2742 update_values = { 

2743 'is_soft_deleted': False, 

2744 'scheduled_to_be_deleted_at': None 

2745 } 

2746 

2747 share_ref = _share_get(context, share_id) 

2748 share_ref.update(update_values) 

2749 share_ref.save(session=context.session) 

2750 

2751 

2752################### 

2753 

2754 

2755def _transfer_get( 

2756 context, transfer_id, resource_type='share', read_deleted=False, 

2757): 

2758 """resource_type can be share or network(TODO network transfer)""" 

2759 query = model_query( 

2760 context, models.Transfer, read_deleted=read_deleted, 

2761 ).filter_by(id=transfer_id) 

2762 

2763 if not is_admin_context(context): 

2764 if resource_type == 'share': 2764 ↛ 2771line 2764 didn't jump to line 2771 because the condition on line 2764 was always true

2765 share = models.Share 

2766 query = query.filter( 

2767 models.Transfer.resource_id == share.id, 

2768 share.project_id == context.project_id, 

2769 ) 

2770 

2771 result = query.first() 

2772 if not result: 

2773 raise exception.TransferNotFound(transfer_id=transfer_id) 

2774 

2775 return result 

2776 

2777 

2778@context_manager.reader 

2779def transfer_get(context, transfer_id, read_deleted=False): 

2780 return _transfer_get(context, transfer_id, read_deleted=read_deleted) 

2781 

2782 

2783def _transfer_get_all(context, limit=None, sort_key=None, 

2784 sort_dir=None, filters=None, offset=None): 

2785 sort_key = sort_key or 'created_at' 

2786 sort_dir = sort_dir or 'desc' 

2787 

2788 query = model_query(context, models.Transfer) 

2789 

2790 if filters: 

2791 legal_filter_keys = ( 

2792 'display_name', 'display_name~', 

2793 'id', 'resource_type', 'resource_id', 

2794 'source_project_id', 'destination_project_id', 

2795 ) 

2796 query = exact_filter( 

2797 query, models.Transfer, filters, legal_filter_keys, 

2798 ) 

2799 query = utils.paginate_query( 

2800 query, models.Transfer, limit, 

2801 sort_key=sort_key, 

2802 sort_dir=sort_dir, 

2803 offset=offset, 

2804 ) 

2805 return query.all() 

2806 

2807 

2808@require_admin_context 

2809@context_manager.reader 

2810def transfer_get_all(context, limit=None, sort_key=None, 

2811 sort_dir=None, filters=None, offset=None): 

2812 return _transfer_get_all(context, limit=limit, 

2813 sort_key=sort_key, sort_dir=sort_dir, 

2814 filters=filters, offset=offset) 

2815 

2816 

2817@require_context 

2818@context_manager.reader 

2819def transfer_get_all_by_project(context, project_id, 

2820 limit=None, sort_key=None, 

2821 sort_dir=None, filters=None, offset=None): 

2822 filters = filters.copy() if filters else {} 

2823 filters['source_project_id'] = project_id 

2824 return _transfer_get_all(context, limit=limit, 

2825 sort_key=sort_key, sort_dir=sort_dir, 

2826 filters=filters, offset=offset) 

2827 

2828 

2829@require_admin_context 

2830@context_manager.reader 

2831def transfer_get_all_expired(context): 

2832 query = model_query(context, models.Transfer) 

2833 expires_at_attr = getattr(models.Transfer, 'expires_at', None) 

2834 now_time = timeutils.utcnow() 

2835 query = query.filter(expires_at_attr.op('<=')(now_time)) 

2836 result = query.all() 

2837 

2838 return result 

2839 

2840 

2841@require_context 

2842@handle_db_data_error 

2843@context_manager.writer 

2844def transfer_create(context, values): 

2845 if not values.get('id'): 2845 ↛ 2848line 2845 didn't jump to line 2848 because the condition on line 2845 was always true

2846 values['id'] = uuidutils.generate_uuid() 

2847 

2848 resource_id = values['resource_id'] 

2849 now_time = timeutils.utcnow() 

2850 time_delta = datetime.timedelta(seconds=CONF.transfer_retention_time) 

2851 transfer_timeout = now_time + time_delta 

2852 values['expires_at'] = transfer_timeout 

2853 

2854 transfer = models.Transfer() 

2855 transfer.update(values) 

2856 transfer.save(session=context.session) 

2857 update = {'status': constants.STATUS_AWAITING_TRANSFER} 

2858 if values['resource_type'] == 'share': 2858 ↛ 2860line 2858 didn't jump to line 2860 because the condition on line 2858 was always true

2859 _share_update(context, resource_id, update) 

2860 return transfer 

2861 

2862 

2863@require_context 

2864@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

2865@context_manager.writer 

2866def transfer_destroy(context, transfer_id, update_share_status=True): 

2867 update = {'status': constants.STATUS_AVAILABLE} 

2868 transfer = _transfer_get(context, transfer_id) 

2869 if transfer['resource_type'] == 'share': 2869 ↛ 2873line 2869 didn't jump to line 2873 because the condition on line 2869 was always true

2870 if update_share_status: 2870 ↛ 2873line 2870 didn't jump to line 2873 because the condition on line 2870 was always true

2871 _share_update(context, transfer['resource_id'], update) 

2872 

2873 transfer_query = model_query( 

2874 context, models.Transfer, 

2875 ).filter_by( 

2876 id=transfer_id, 

2877 ) 

2878 transfer_query.soft_delete() 

2879 

2880 

2881@require_context 

2882@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

2883@context_manager.writer 

2884def transfer_accept( 

2885 context, transfer_id, user_id, project_id, accept_snapshots=False, 

2886): 

2887 share_id = _transfer_get(context, transfer_id)['resource_id'] 

2888 update = { 

2889 'status': constants.STATUS_AVAILABLE, 

2890 'user_id': user_id, 

2891 'project_id': project_id, 

2892 'updated_at': timeutils.utcnow(), 

2893 } 

2894 _share_update(context, share_id, update) 

2895 

2896 # Update snapshots for transfer snapshots with share. 

2897 if accept_snapshots: 2897 ↛ 2898line 2897 didn't jump to line 2898 because the condition on line 2897 was never true

2898 snapshots = _share_snapshot_get_all_for_share(context, share_id) 

2899 for snapshot in snapshots: 

2900 LOG.debug('Begin to transfer snapshot: %s', snapshot['id']) 

2901 update = { 

2902 'user_id': user_id, 

2903 'project_id': project_id, 

2904 'updated_at': timeutils.utcnow(), 

2905 } 

2906 _share_snapshot_update(context, snapshot['id'], update) 

2907 query = context.session.query(models.Transfer).filter_by(id=transfer_id) 

2908 query.update( 

2909 { 

2910 'deleted': True, 

2911 'deleted_at': timeutils.utcnow(), 

2912 'updated_at': timeutils.utcnow(), 

2913 'destination_project_id': project_id, 

2914 'accepted': True, 

2915 } 

2916 ) 

2917 

2918 

2919@require_context 

2920@context_manager.writer 

2921def transfer_accept_rollback( 

2922 context, transfer_id, user_id, project_id, rollback_snap=False, 

2923): 

2924 share_id = _transfer_get( 

2925 context, transfer_id, read_deleted=True, 

2926 )['resource_id'] 

2927 update = { 

2928 'status': constants.STATUS_AWAITING_TRANSFER, 

2929 'user_id': user_id, 

2930 'project_id': project_id, 

2931 'updated_at': timeutils.utcnow(), 

2932 } 

2933 _share_update(context, share_id, update) 

2934 

2935 # rollback snapshots for transfer snapshots with share. 

2936 if rollback_snap: 2936 ↛ 2937line 2936 didn't jump to line 2937 because the condition on line 2936 was never true

2937 snapshots = _share_snapshot_get_all_for_share(context, share_id) 

2938 for snapshot in snapshots: 

2939 LOG.debug('Begin to rollback snapshot: %s', snapshot['id']) 

2940 update = { 

2941 'user_id': user_id, 

2942 'project_id': project_id, 

2943 'updated_at': timeutils.utcnow(), 

2944 } 

2945 _share_snapshot_update(context, snapshot['id'], update) 

2946 

2947 query = context.session.query(models.Transfer).filter_by(id=transfer_id) 

2948 query.update( 

2949 { 

2950 'deleted': 'False', 

2951 'deleted_at': None, 

2952 'updated_at': timeutils.utcnow(), 

2953 'destination_project_id': None, 

2954 'accepted': 0, 

2955 } 

2956 ) 

2957 

2958 

2959################### 

2960 

2961 

2962def _share_access_get_query(context, values, read_deleted='no'): 

2963 """Get access record.""" 

2964 query = model_query( 

2965 context, models.ShareAccessMapping, 

2966 read_deleted=read_deleted 

2967 ).options( 

2968 orm.joinedload(models.ShareAccessMapping.share_access_rules_metadata), 

2969 ) 

2970 return query.filter_by(**values) 

2971 

2972 

2973def _share_instance_access_query(context, access_id=None, instance_id=None): 

2974 filters = {'deleted': 'False'} 

2975 

2976 if access_id is not None: 

2977 filters.update({'access_id': access_id}) 

2978 

2979 if instance_id is not None: 

2980 filters.update({'share_instance_id': instance_id}) 

2981 

2982 return model_query( 

2983 context, models.ShareInstanceAccessMapping, 

2984 ).filter_by(**filters) 

2985 

2986 

2987def _share_access_metadata_get_item(context, access_id, key): 

2988 result = _share_access_metadata_get_query( 

2989 context, access_id, 

2990 ).filter_by(key=key).first() 

2991 if not result: 

2992 raise exception.ShareAccessMetadataNotFound( 

2993 metadata_key=key, access_id=access_id) 

2994 return result 

2995 

2996 

2997def _share_access_metadata_get_query(context, access_id): 

2998 return model_query( 

2999 context, models.ShareAccessRulesMetadata, read_deleted="no", 

3000 ).filter_by( 

3001 access_id=access_id, 

3002 ).options(orm.joinedload(models.ShareAccessRulesMetadata.access)) 

3003 

3004 

3005@require_context 

3006@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

3007@context_manager.writer 

3008def share_access_metadata_update(context, access_id, metadata): 

3009 # Now update all existing items with new values, or create new meta 

3010 # objects 

3011 for meta_key, meta_value in metadata.items(): 

3012 

3013 # update the value whether it exists or not 

3014 item = {"value": meta_value} 

3015 try: 

3016 meta_ref = _share_access_metadata_get_item( 

3017 context, access_id, meta_key, 

3018 ) 

3019 except exception.ShareAccessMetadataNotFound: 

3020 meta_ref = models.ShareAccessRulesMetadata() 

3021 item.update({"key": meta_key, "access_id": access_id}) 

3022 

3023 meta_ref.update(item) 

3024 meta_ref.save(session=context.session) 

3025 

3026 return metadata 

3027 

3028 

3029@require_context 

3030@context_manager.writer 

3031def share_access_metadata_delete(context, access_id, key): 

3032 metadata = _share_access_metadata_get_item( 

3033 context, access_id, key, 

3034 ) 

3035 metadata.soft_delete(session=context.session) 

3036 

3037 

3038@require_context 

3039@context_manager.writer 

3040def share_access_create(context, values): 

3041 values = ensure_model_dict_has_id(values) 

3042 values['share_access_rules_metadata'] = _metadata_refs( 

3043 values.get('metadata'), models.ShareAccessRulesMetadata 

3044 ) 

3045 

3046 access_ref = models.ShareAccessMapping() 

3047 access_ref.update(values) 

3048 access_ref.save(session=context.session) 

3049 

3050 parent_share = _share_get(context, values['share_id']) 

3051 

3052 for instance in parent_share.instances: 

3053 values = { 

3054 'share_instance_id': instance['id'], 

3055 'access_id': access_ref['id'], 

3056 } 

3057 

3058 instance_access_ref = models.ShareInstanceAccessMapping() 

3059 instance_access_ref.update(ensure_model_dict_has_id(values)) 

3060 instance_access_ref.save(session=context.session) 

3061 

3062 return _share_access_get(context, access_ref['id']) 

3063 

3064 

3065@require_context 

3066@context_manager.writer 

3067def share_access_update(context, access_id, values): 

3068 access_ref = _share_access_get(context, access_id) 

3069 access_ref.update(values) 

3070 access_ref.save(session=context.session) 

3071 return access_ref 

3072 

3073 

3074@require_context 

3075@context_manager.writer 

3076def share_instance_access_create(context, values, share_instance_id): 

3077 values = ensure_model_dict_has_id(values) 

3078 access_list = _share_access_get_query( 

3079 context, 

3080 { 

3081 'share_id': values['share_id'], 

3082 'access_type': values['access_type'], 

3083 'access_to': values['access_to'], 

3084 } 

3085 ).all() 

3086 if len(access_list) > 0: 

3087 access_ref = access_list[0] 

3088 else: 

3089 access_ref = models.ShareAccessMapping() 

3090 access_ref.update(values) 

3091 access_ref.save(session=context.session) 

3092 

3093 values = { 

3094 'share_instance_id': share_instance_id, 

3095 'access_id': access_ref['id'], 

3096 } 

3097 

3098 instance_access_ref = models.ShareInstanceAccessMapping() 

3099 instance_access_ref.update(ensure_model_dict_has_id(values)) 

3100 instance_access_ref.save(session=context.session) 

3101 

3102 return _share_access_get(context, access_ref['id']) 

3103 

3104 

3105@require_context 

3106@context_manager.writer 

3107def share_instance_access_copy(context, share_id, instance_id): 

3108 """Copy access rules from share to share instance.""" 

3109 share_access_rules = _share_access_get_query( 

3110 context, {'share_id': share_id} 

3111 ).all() 

3112 

3113 for access_rule in share_access_rules: 

3114 values = { 

3115 'share_instance_id': instance_id, 

3116 'access_id': access_rule['id'], 

3117 } 

3118 

3119 instance_access_ref = models.ShareInstanceAccessMapping() 

3120 instance_access_ref.update(ensure_model_dict_has_id(values)) 

3121 instance_access_ref.save(session=context.session) 

3122 

3123 return share_access_rules 

3124 

3125 

3126@require_context 

3127@context_manager.reader 

3128def share_access_get(context, access_id): 

3129 return _share_access_get(context, access_id) 

3130 

3131 

3132def _share_access_get(context, access_id): 

3133 """Get access record.""" 

3134 access = _share_access_get_query(context, {'id': access_id}).first() 

3135 if access: 

3136 return access 

3137 else: 

3138 raise exception.NotFound() 

3139 

3140 

3141@require_context 

3142@context_manager.reader 

3143def share_access_get_with_context(context, access_id): 

3144 """Get access record.""" 

3145 access = _share_access_get_query( 

3146 context, {'id': access_id} 

3147 ).options(orm.joinedload(models.ShareAccessMapping.share)).first() 

3148 if access: 

3149 access['project_id'] = access['share']['project_id'] 

3150 return access 

3151 else: 

3152 raise exception.NotFound() 

3153 

3154 

3155@require_context 

3156@context_manager.reader 

3157def share_instance_access_get(context, access_id, instance_id, 

3158 with_share_access_data=True): 

3159 """Get access record.""" 

3160 access = _share_instance_access_query( 

3161 context, access_id, instance_id 

3162 ).first() 

3163 if access is None: 

3164 raise exception.NotFound() 

3165 

3166 if with_share_access_data: 

3167 access = _set_instances_share_access_data(context, access)[0] 

3168 

3169 return access 

3170 

3171 

3172@require_context 

3173@context_manager.reader 

3174def share_access_get_all_for_share(context, share_id, filters=None): 

3175 filters = filters or {} 

3176 share_access_mapping = models.ShareAccessMapping 

3177 query = _share_access_get_query( 

3178 context, {'share_id': share_id} 

3179 ).filter( 

3180 models.ShareAccessMapping.instance_mappings.any() 

3181 ) 

3182 

3183 legal_filter_keys = ('id', 'access_type', 'access_key', 

3184 'access_to', 'access_level') 

3185 

3186 if 'metadata' in filters: 

3187 for k, v in filters['metadata'].items(): 

3188 query = query.filter( 

3189 or_( 

3190 models.ShareAccessMapping. 

3191 share_access_rules_metadata.any(key=k, value=v) 

3192 ) 

3193 ) 

3194 

3195 query = exact_filter( 

3196 query, share_access_mapping, filters, legal_filter_keys) 

3197 

3198 return query.all() 

3199 

3200 

3201@require_context 

3202@context_manager.reader 

3203def share_access_get_all_for_instance(context, instance_id, filters=None, 

3204 with_share_access_data=True): 

3205 """Get all access rules related to a certain share instance.""" 

3206 filters = copy.deepcopy(filters) if filters else {} 

3207 filters.update({'share_instance_id': instance_id}) 

3208 legal_filter_keys = ('id', 'share_instance_id', 'access_id', 'state') 

3209 query = _share_instance_access_query(context) 

3210 

3211 query = exact_filter( 

3212 query, models.ShareInstanceAccessMapping, filters, legal_filter_keys) 

3213 

3214 instance_accesses = query.all() 

3215 

3216 if with_share_access_data: 

3217 instance_accesses = _set_instances_share_access_data( 

3218 context, instance_accesses 

3219 ) 

3220 

3221 return instance_accesses 

3222 

3223 

3224def _set_instances_share_access_data(context, instance_accesses): 

3225 if instance_accesses and not isinstance(instance_accesses, list): 

3226 instance_accesses = [instance_accesses] 

3227 

3228 for instance_access in instance_accesses: 

3229 share_access = _share_access_get( 

3230 context, instance_access['access_id'] 

3231 ) 

3232 instance_access.set_share_access_data(share_access) 

3233 

3234 return instance_accesses 

3235 

3236 

3237def _set_instances_snapshot_access_data(context, instance_accesses): 

3238 if instance_accesses and not isinstance(instance_accesses, list): 

3239 instance_accesses = [instance_accesses] 

3240 

3241 for instance_access in instance_accesses: 

3242 snapshot_access = _share_snapshot_access_get( 

3243 context, instance_access['access_id'] 

3244 ) 

3245 instance_access.set_snapshot_access_data(snapshot_access) 

3246 

3247 return instance_accesses 

3248 

3249 

3250@require_context 

3251@context_manager.reader 

3252def share_access_get_all_by_type_and_access(context, share_id, access_type, 

3253 access): 

3254 return _share_access_get_query(context, 

3255 {'share_id': share_id, 

3256 'access_type': access_type, 

3257 'access_to': access}).all() 

3258 

3259 

3260@require_context 

3261@context_manager.reader 

3262def share_access_check_for_existing_access(context, share_id, access_type, 

3263 access_to): 

3264 return _check_for_existing_access( 

3265 context, 'share', share_id, access_type, access_to) 

3266 

3267 

3268def _check_for_existing_access(context, resource, resource_id, access_type, 

3269 access_to): 

3270 if resource == 'share': 

3271 query_method = _share_access_get_query 

3272 access_to_field = models.ShareAccessMapping.access_to 

3273 else: 

3274 query_method = _share_snapshot_access_get_query 

3275 access_to_field = models.ShareSnapshotAccessMapping.access_to 

3276 

3277 if access_type == 'ip': 

3278 rules = query_method( 

3279 context, 

3280 {'%s_id' % resource: resource_id, 'access_type': access_type} 

3281 ).filter(access_to_field.startswith(access_to.split('/')[0])).all() 

3282 

3283 matching_rules = [ 

3284 rule for rule in rules if 

3285 ipaddress.ip_network(str(access_to)) == 

3286 ipaddress.ip_network(str(rule['access_to'])) 

3287 ] 

3288 return len(matching_rules) > 0 

3289 

3290 return query_method( 

3291 context, 

3292 { 

3293 '%s_id' % resource: resource_id, 

3294 'access_type': access_type, 

3295 'access_to': access_to 

3296 } 

3297 ).count() > 0 

3298 

3299 

3300@require_context 

3301@context_manager.writer 

3302def share_instance_access_delete(context, mapping_id): 

3303 mapping = context.session.query( 

3304 models.ShareInstanceAccessMapping 

3305 ).filter_by(id=mapping_id).first() 

3306 

3307 if not mapping: 3307 ↛ 3308line 3307 didn't jump to line 3308 because the condition on line 3307 was never true

3308 exception.NotFound() 

3309 

3310 filters = { 

3311 'resource_id': mapping['access_id'], 

3312 'all_projects': True 

3313 } 

3314 locks, _ = resource_lock_get_all( 

3315 context.elevated(), filters=filters 

3316 ) 

3317 if locks: 

3318 for lock in locks: 

3319 if lock['resource_action'] == constants.RESOURCE_ACTION_DELETE: 3319 ↛ 3336line 3319 didn't jump to line 3336 because the condition on line 3319 was always true

3320 lock_reason = ( 

3321 constants.SHARE_LOCKED_BY_ACCESS_LOCK_REASON % { 

3322 'lock_id': lock['id'] 

3323 } 

3324 ) 

3325 share_filters = { 

3326 'all_projects': True, 

3327 'lock_reason': lock_reason 

3328 } 

3329 share_locks, _ = resource_lock_get_all( 

3330 context.elevated(), filters=share_filters 

3331 ) or [] 

3332 for share_lock in share_locks: 

3333 resource_lock_delete( 

3334 context.elevated(), share_lock['id'] 

3335 ) 

3336 resource_lock_delete( 

3337 context.elevated(), lock['id'] 

3338 ) 

3339 

3340 mapping.soft_delete( 

3341 session=context.session, update_status=True, 

3342 status_field_name='state' 

3343 ) 

3344 

3345 other_mappings = _share_instance_access_query( 

3346 context, mapping['access_id'] 

3347 ).all() 

3348 

3349 # NOTE(u_glide): Remove access rule if all mappings were removed. 

3350 if len(other_mappings) == 0: 3350 ↛ exitline 3350 didn't return from function 'share_instance_access_delete' because the condition on line 3350 was always true

3351 context.session.query(models.ShareAccessRulesMetadata).filter_by( 

3352 access_id=mapping['access_id'] 

3353 ).soft_delete() 

3354 context.session.query(models.ShareAccessMapping).filter_by( 

3355 id=mapping['access_id'] 

3356 ).soft_delete() 

3357 

3358 

3359@require_context 

3360@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

3361@context_manager.writer 

3362def share_instance_access_update(context, access_id, instance_id, updates): 

3363 share_access_fields = ('access_type', 'access_to', 'access_key', 

3364 'access_level') 

3365 

3366 share_access_map_updates, share_instance_access_map_updates = ( 

3367 _extract_subdict_by_fields(updates, share_access_fields) 

3368 ) 

3369 updated_at = timeutils.utcnow() 

3370 share_access_map_updates['updated_at'] = updated_at 

3371 share_instance_access_map_updates['updated_at'] = updated_at 

3372 

3373 access_ref = _share_access_get_query(context, {'id': access_id}).first() 

3374 access_ref.update(share_access_map_updates) 

3375 access_ref.save(session=context.session) 

3376 

3377 instance_access_ref = _share_instance_access_query( 

3378 context, access_id, instance_id).first() 

3379 instance_access_ref.update(share_instance_access_map_updates) 

3380 instance_access_ref.save(session=context.session) 

3381 

3382 return instance_access_ref 

3383 

3384################### 

3385 

3386 

3387@require_context 

3388@context_manager.writer 

3389def share_snapshot_instance_create(context, snapshot_id, values): 

3390 return _share_snapshot_instance_create(context, snapshot_id, values) 

3391 

3392 

3393def _share_snapshot_instance_create(context, snapshot_id, values): 

3394 values = copy.deepcopy(values) 

3395 values['share_snapshot_metadata'] = _metadata_refs( 

3396 values.get('metadata'), models.ShareSnapshotMetadata) 

3397 

3398 _change_size_to_instance_size(values) 

3399 

3400 if not values.get('id'): 

3401 values['id'] = uuidutils.generate_uuid() 

3402 values.update({'snapshot_id': snapshot_id}) 

3403 

3404 instance_ref = models.ShareSnapshotInstance() 

3405 instance_ref.update(values) 

3406 instance_ref.save(session=context.session) 

3407 

3408 return _share_snapshot_instance_get(context, instance_ref['id']) 

3409 

3410 

3411@require_context 

3412@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

3413@context_manager.writer 

3414def share_snapshot_instance_update(context, instance_id, values): 

3415 instance_ref = _share_snapshot_instance_get(context, instance_id) 

3416 _change_size_to_instance_size(values) 

3417 

3418 # NOTE(u_glide): Ignore updates to custom properties 

3419 for extra_key in models.ShareSnapshotInstance._extra_keys: 

3420 if extra_key in values: 3420 ↛ 3421line 3420 didn't jump to line 3421 because the condition on line 3420 was never true

3421 values.pop(extra_key) 

3422 

3423 instance_ref.update(values) 

3424 instance_ref.save(session=context.session) 

3425 return instance_ref 

3426 

3427 

3428@require_context 

3429@context_manager.writer 

3430def share_snapshot_instance_delete(context, snapshot_instance_id): 

3431 snapshot_instance_ref = _share_snapshot_instance_get( 

3432 context, snapshot_instance_id 

3433 ) 

3434 

3435 access_rules = _share_snapshot_access_get_all_for_snapshot_instance( 

3436 context, snapshot_instance_id 

3437 ) 

3438 for rule in access_rules: 3438 ↛ 3439line 3438 didn't jump to line 3439 because the loop on line 3438 never started

3439 _share_snapshot_instance_access_delete( 

3440 context, rule['access_id'], snapshot_instance_id, 

3441 ) 

3442 

3443 for el in snapshot_instance_ref.export_locations: 3443 ↛ 3444line 3443 didn't jump to line 3444 because the loop on line 3443 never started

3444 _share_snapshot_instance_export_location_delete(context, el['id']) 

3445 

3446 snapshot_instance_ref.soft_delete( 

3447 session=context.session, update_status=True) 

3448 snapshot = _share_snapshot_get( 

3449 context, snapshot_instance_ref['snapshot_id']) 

3450 if len(snapshot.instances) == 0: 

3451 context.session.query(models.ShareSnapshotMetadata).filter_by( 

3452 share_snapshot_id=snapshot['id'], 

3453 ).soft_delete() 

3454 snapshot.soft_delete(session=context.session) 

3455 

3456 

3457@require_context 

3458@context_manager.reader 

3459def share_snapshot_instance_get(context, snapshot_instance_id, 

3460 with_share_data=False): 

3461 return _share_snapshot_instance_get( 

3462 context, snapshot_instance_id, with_share_data=with_share_data, 

3463 ) 

3464 

3465 

3466def _share_snapshot_instance_get( 

3467 context, snapshot_instance_id, with_share_data=False, 

3468): 

3469 result = _share_snapshot_instance_get_with_filters( 

3470 context, instance_ids=[snapshot_instance_id], 

3471 ).first() 

3472 

3473 if result is None: 3473 ↛ 3474line 3473 didn't jump to line 3474 because the condition on line 3473 was never true

3474 raise exception.ShareSnapshotInstanceNotFound( 

3475 instance_id=snapshot_instance_id) 

3476 

3477 if with_share_data: 

3478 result = _set_share_snapshot_instance_data(context, result)[0] 

3479 

3480 return result 

3481 

3482 

3483@require_context 

3484@context_manager.reader 

3485def share_snapshot_instance_get_all_with_filters( 

3486 context, search_filters, with_share_data=False, 

3487): 

3488 """Get snapshot instances filtered by known attrs, ignore unknown attrs. 

3489 

3490 All filters accept list/tuples to filter on, along with simple values. 

3491 """ 

3492 return _share_snapshot_instance_get_all_with_filters( 

3493 context, search_filters, with_share_data=with_share_data, 

3494 ) 

3495 

3496 

3497def _share_snapshot_instance_get_all_with_filters( 

3498 context, search_filters, with_share_data=False, 

3499): 

3500 def listify(values): 

3501 if values: 

3502 if not isinstance(values, (list, tuple, set)): 

3503 return values, 

3504 else: 

3505 return values 

3506 

3507 _known_filters = ('instance_ids', 'snapshot_ids', 'share_instance_ids', 

3508 'statuses') 

3509 

3510 filters = {k: listify(search_filters.get(k)) for k in _known_filters} 

3511 

3512 result = _share_snapshot_instance_get_with_filters( 

3513 context, **filters, 

3514 ).all() 

3515 

3516 if with_share_data: 

3517 result = _set_share_snapshot_instance_data(context, result) 

3518 

3519 return result 

3520 

3521 

3522def _share_snapshot_instance_get_with_filters(context, instance_ids=None, 

3523 snapshot_ids=None, statuses=None, 

3524 share_instance_ids=None): 

3525 query = model_query(context, models.ShareSnapshotInstance, 

3526 read_deleted="no") 

3527 

3528 if instance_ids is not None: 

3529 query = query.filter( 

3530 models.ShareSnapshotInstance.id.in_(instance_ids)) 

3531 

3532 if snapshot_ids is not None: 

3533 query = query.filter( 

3534 models.ShareSnapshotInstance.snapshot_id.in_(snapshot_ids)) 

3535 

3536 if share_instance_ids is not None: 

3537 query = query.filter(models.ShareSnapshotInstance.share_instance_id 

3538 .in_(share_instance_ids)) 

3539 

3540 if statuses is not None: 

3541 query = query.filter(models.ShareSnapshotInstance.status.in_(statuses)) 

3542 

3543 query = query.options( 

3544 orm.joinedload(models.ShareSnapshotInstance.share_group_snapshot), 

3545 ) 

3546 return query 

3547 

3548 

3549def _set_share_snapshot_instance_data(context, snapshot_instances): 

3550 if snapshot_instances and not isinstance(snapshot_instances, list): 

3551 snapshot_instances = [snapshot_instances] 

3552 

3553 for snapshot_instance in snapshot_instances: 

3554 share_instance = _share_instance_get( 

3555 context, snapshot_instance['share_instance_id'], 

3556 with_share_data=True) 

3557 snapshot_instance['share'] = share_instance 

3558 

3559 return snapshot_instances 

3560 

3561 

3562################### 

3563 

3564 

3565@require_context 

3566@context_manager.writer 

3567def share_snapshot_create(context, create_values, 

3568 create_snapshot_instance=True): 

3569 values = copy.deepcopy(create_values) 

3570 values = ensure_model_dict_has_id(values) 

3571 values['share_snapshot_metadata'] = _metadata_refs( 

3572 values.pop('metadata', {}), models.ShareSnapshotMetadata) 

3573 

3574 snapshot_ref = models.ShareSnapshot() 

3575 snapshot_instance_values, snapshot_values = ( 

3576 _extract_snapshot_instance_values(values) 

3577 ) 

3578 snapshot_ref.update(snapshot_values) 

3579 

3580 share_ref = _share_get( 

3581 context, 

3582 snapshot_values.get('share_id'), 

3583 ) 

3584 snapshot_instance_values.update( 

3585 {'share_instance_id': share_ref.instance.id} 

3586 ) 

3587 

3588 snapshot_ref.save(session=context.session) 

3589 

3590 if create_snapshot_instance: 

3591 _share_snapshot_instance_create( 

3592 context, 

3593 snapshot_ref['id'], 

3594 snapshot_instance_values, 

3595 ) 

3596 return _share_snapshot_get(context, snapshot_values['id']) 

3597 

3598 

3599@require_admin_context 

3600def _snapshot_data_get_for_project( 

3601 context, project_id, user_id, share_type_id=None, 

3602): 

3603 query = model_query( 

3604 context, models.ShareSnapshot, 

3605 func.count(models.ShareSnapshot.id), 

3606 func.sum(models.ShareSnapshot.size), 

3607 read_deleted="no", 

3608 ).filter_by(project_id=project_id) 

3609 if share_type_id: 

3610 query = query.join( 

3611 models.ShareInstance, 

3612 models.ShareInstance.share_id == models.ShareSnapshot.share_id, 

3613 ).filter_by(share_type_id=share_type_id) 

3614 elif user_id: 

3615 query = query.filter_by(user_id=user_id) 

3616 result = query.first() 

3617 

3618 return result[0] or 0, result[1] or 0 

3619 

3620 

3621@require_context 

3622@context_manager.reader 

3623def share_snapshot_get(context, snapshot_id, project_only=True): 

3624 return _share_snapshot_get(context, snapshot_id, project_only=project_only) 

3625 

3626 

3627def _share_snapshot_get(context, snapshot_id, project_only=True): 

3628 result = model_query( 

3629 context, models.ShareSnapshot, project_only=project_only, 

3630 ).filter_by( 

3631 id=snapshot_id, 

3632 ).options( 

3633 orm.joinedload(models.ShareSnapshot.share), 

3634 orm.joinedload(models.ShareSnapshot.instances), 

3635 orm.joinedload(models.ShareSnapshot.share_snapshot_metadata), 

3636 ).first() 

3637 

3638 if not result: 

3639 raise exception.ShareSnapshotNotFound(snapshot_id=snapshot_id) 

3640 

3641 return result 

3642 

3643 

3644def _share_snapshot_get_all_with_filters(context, project_id=None, 

3645 share_id=None, filters=None, 

3646 limit=None, offset=None, 

3647 sort_key=None, sort_dir=None, 

3648 show_count=False): 

3649 """Retrieves all snapshots. 

3650 

3651 If no sorting parameters are specified then returned snapshots are sorted 

3652 by the 'created_at' key and desc order. 

3653 

3654 :param context: context to query under 

3655 :param filters: dictionary of filters 

3656 :param limit: maximum number of items to return 

3657 :param sort_key: attribute by which results should be sorted,default is 

3658 created_at 

3659 :param sort_dir: direction in which results should be sorted 

3660 :returns: list of matching snapshots 

3661 """ 

3662 # Init data 

3663 sort_key = sort_key or 'created_at' 

3664 sort_dir = sort_dir or 'desc' 

3665 filters = copy.deepcopy(filters) if filters else {} 

3666 query = model_query(context, models.ShareSnapshot) 

3667 

3668 if project_id: 3668 ↛ 3669line 3668 didn't jump to line 3669 because the condition on line 3668 was never true

3669 query = query.filter_by(project_id=project_id) 

3670 

3671 if share_id: 

3672 query = query.filter_by(share_id=share_id) 

3673 

3674 query = query.options( 

3675 orm.joinedload(models.ShareSnapshot.share), 

3676 orm.joinedload(models.ShareSnapshot.instances), 

3677 orm.joinedload(models.ShareSnapshot.share_snapshot_metadata), 

3678 ) 

3679 

3680 # Snapshots with no instances are filtered out. 

3681 query = query.filter( 

3682 models.ShareSnapshot.id == models.ShareSnapshotInstance.snapshot_id) 

3683 

3684 # Apply filters 

3685 if 'usage' in filters: 3685 ↛ 3686line 3685 didn't jump to line 3686 because the condition on line 3685 was never true

3686 usage_filter_keys = ['any', 'used', 'unused'] 

3687 if filters['usage'] == 'any': 

3688 pass 

3689 elif filters['usage'] == 'used': 

3690 query = query.filter(models.Share.snapshot_id == ( 

3691 models.ShareSnapshot.id)) 

3692 elif filters['usage'] == 'unused': 

3693 query = query.filter(models.Share.snapshot_id != ( 

3694 models.ShareSnapshot.id)) 

3695 else: 

3696 msg = _("Wrong 'usage' key provided - '%(key)s'. " 

3697 "Expected keys are '%(ek)s'.") % { 

3698 'key': filters['usage'], 

3699 'ek': usage_filter_keys} 

3700 raise exception.InvalidInput(reason=msg) 

3701 filters.pop('usage') 

3702 

3703 if 'status' in filters: 

3704 query = query.filter(models.ShareSnapshotInstance.status == ( 

3705 filters['status'])) 

3706 filters.pop('status') 

3707 

3708 if 'metadata' in filters: 

3709 for k, v in filters['metadata'].items(): 

3710 # pylint: disable=no-member 

3711 query = query.filter( 

3712 or_(models.ShareSnapshot.share_snapshot_metadata.any( 

3713 key=k, value=v))) 

3714 filters.pop('metadata') 

3715 

3716 legal_filter_keys = ('display_name', 'display_name~', 

3717 'display_description', 'display_description~', 

3718 'id', 'user_id', 'project_id', 'share_id', 

3719 'share_proto', 'size', 'share_size') 

3720 query = exact_filter(query, models.ShareSnapshot, 

3721 filters, legal_filter_keys) 

3722 

3723 if not filters.get('list_deferred_delete'): 3723 ↛ 3730line 3723 didn't jump to line 3730 because the condition on line 3723 was always true

3724 query = query.filter(and_( 

3725 models.ShareSnapshotInstance.status != ( 

3726 constants.STATUS_DEFERRED_DELETING), 

3727 models.ShareSnapshotInstance.status != ( 

3728 constants.STATUS_ERROR_DEFERRED_DELETING))) 

3729 

3730 query = apply_sorting(models.ShareSnapshot, query, sort_key, sort_dir) 

3731 

3732 count = None 

3733 if show_count: 

3734 count = query.order_by(models.ShareSnapshot.id).distinct().count() 

3735 

3736 if limit is not None: 

3737 query = query.limit(limit) 

3738 

3739 if offset: 3739 ↛ 3740line 3739 didn't jump to line 3740 because the condition on line 3739 was never true

3740 query = query.offset(offset) 

3741 

3742 # Returns list of share snapshots that satisfy filters 

3743 query = query.all() 

3744 

3745 if show_count: 

3746 return count, query 

3747 

3748 return query 

3749 

3750 

3751@require_admin_context 

3752@context_manager.reader 

3753def share_snapshot_get_all(context, filters=None, limit=None, offset=None, 

3754 sort_key=None, sort_dir=None): 

3755 return _share_snapshot_get_all_with_filters( 

3756 context, filters=filters, limit=limit, 

3757 offset=offset, sort_key=sort_key, sort_dir=sort_dir) 

3758 

3759 

3760@require_admin_context 

3761@context_manager.reader 

3762def share_snapshot_get_all_with_count(context, filters=None, limit=None, 

3763 offset=None, sort_key=None, 

3764 sort_dir=None): 

3765 count, query = _share_snapshot_get_all_with_filters( 

3766 context, filters=filters, limit=limit, 

3767 offset=offset, sort_key=sort_key, sort_dir=sort_dir, 

3768 show_count=True) 

3769 return count, query 

3770 

3771 

3772@require_context 

3773@context_manager.reader 

3774def share_snapshot_get_all_by_project(context, project_id, filters=None, 

3775 limit=None, offset=None, 

3776 sort_key=None, sort_dir=None): 

3777 authorize_project_context(context, project_id) 

3778 return _share_snapshot_get_all_with_filters( 

3779 context, project_id=project_id, filters=filters, limit=limit, 

3780 offset=offset, sort_key=sort_key, sort_dir=sort_dir) 

3781 

3782 

3783@require_context 

3784@context_manager.reader 

3785def share_snapshot_get_all_by_project_with_count(context, project_id, 

3786 filters=None, limit=None, 

3787 offset=None, sort_key=None, 

3788 sort_dir=None): 

3789 authorize_project_context(context, project_id) 

3790 count, query = _share_snapshot_get_all_with_filters( 

3791 context, project_id=project_id, filters=filters, limit=limit, 

3792 offset=offset, sort_key=sort_key, sort_dir=sort_dir, 

3793 show_count=True) 

3794 return count, query 

3795 

3796 

3797@require_context 

3798@context_manager.reader 

3799def share_snapshot_get_all_for_share( 

3800 context, share_id, filters=None, sort_key=None, sort_dir=None, 

3801): 

3802 return _share_snapshot_get_all_for_share( 

3803 context, share_id, filters=None, sort_key=None, sort_dir=None, 

3804 ) 

3805 

3806 

3807def _share_snapshot_get_all_for_share( 

3808 context, share_id, filters=None, sort_key=None, sort_dir=None, 

3809): 

3810 return _share_snapshot_get_all_with_filters( 

3811 context, share_id=share_id, 

3812 filters=filters, sort_key=sort_key, sort_dir=sort_dir, 

3813 ) 

3814 

3815 

3816@require_context 

3817@context_manager.reader 

3818def share_snapshot_get_latest_for_share(context, share_id): 

3819 snapshots = _share_snapshot_get_all_with_filters( 

3820 context, share_id=share_id, sort_key='created_at', sort_dir='desc') 

3821 return snapshots[0] if snapshots else None 

3822 

3823 

3824@require_context 

3825@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

3826@context_manager.writer 

3827def share_snapshot_update(context, snapshot_id, values): 

3828 return _share_snapshot_update(context, snapshot_id, values) 

3829 

3830 

3831def _share_snapshot_update(context, snapshot_id, values): 

3832 snapshot_ref = _share_snapshot_get(context, snapshot_id) 

3833 

3834 instance_values, snapshot_values = ( 

3835 _extract_snapshot_instance_values(values) 

3836 ) 

3837 

3838 if snapshot_values: 

3839 snapshot_ref.update(snapshot_values) 

3840 snapshot_ref.save(session=context.session) 

3841 

3842 if instance_values: 3842 ↛ 3846line 3842 didn't jump to line 3846 because the condition on line 3842 was always true

3843 snapshot_ref.instance.update(instance_values) 

3844 snapshot_ref.instance.save(session=context.session) 

3845 

3846 return snapshot_ref 

3847 

3848 

3849@require_context 

3850@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

3851@context_manager.writer 

3852def share_snapshot_instances_status_update( 

3853 context, snapshot_instance_ids, values, 

3854): 

3855 return _share_snapshot_instances_status_update( 

3856 context, snapshot_instance_ids, values, 

3857 ) 

3858 

3859 

3860def _share_snapshot_instances_status_update( 

3861 context, snapshot_instance_ids, values, 

3862): 

3863 result = model_query( 

3864 context, models.ShareSnapshotInstance, 

3865 read_deleted="no", 

3866 ).filter( 

3867 models.ShareSnapshotInstance.id.in_(snapshot_instance_ids) 

3868 ).update(values, synchronize_session=False) 

3869 

3870 return result 

3871 

3872 

3873################################### 

3874# Share Snapshot Metadata functions 

3875################################### 

3876 

3877@require_context 

3878@require_share_snapshot_exists 

3879@context_manager.writer 

3880def share_snapshot_metadata_get(context, share_snapshot_id): 

3881 return _share_snapshot_metadata_get(context, share_snapshot_id) 

3882 

3883 

3884@require_context 

3885@require_share_snapshot_exists 

3886@context_manager.writer 

3887def share_snapshot_metadata_delete(context, share_snapshot_id, key): 

3888 meta_ref = _share_snapshot_metadata_get_item( 

3889 context, share_snapshot_id, key) 

3890 meta_ref.soft_delete(session=context.session) 

3891 

3892 

3893@require_context 

3894@require_share_snapshot_exists 

3895@context_manager.writer 

3896def share_snapshot_metadata_update(context, share_snapshot_id, 

3897 metadata, delete): 

3898 return _share_snapshot_metadata_update(context, share_snapshot_id, 

3899 metadata, delete) 

3900 

3901 

3902@context_manager.writer 

3903def share_snapshot_metadata_update_item(context, share_snapshot_id, item): 

3904 return _share_snapshot_metadata_update(context, share_snapshot_id, 

3905 item, delete=False) 

3906 

3907 

3908@context_manager.reader 

3909def share_snapshot_metadata_get_item(context, share_snapshot_id, key): 

3910 

3911 row = _share_snapshot_metadata_get_item(context, share_snapshot_id, key) 

3912 result = {} 

3913 result[row['key']] = row['value'] 

3914 

3915 return result 

3916 

3917 

3918def _share_snapshot_metadata_get_query(context, share_snapshot_id): 

3919 return model_query( 

3920 context, models.ShareSnapshotMetadata, read_deleted="no", 

3921 ).filter_by( 

3922 share_snapshot_id=share_snapshot_id, 

3923 ).options(orm.joinedload(models.ShareSnapshotMetadata.share_snapshot)) 

3924 

3925 

3926def _share_snapshot_metadata_get(context, share_snapshot_id): 

3927 rows = _share_snapshot_metadata_get_query( 

3928 context, share_snapshot_id, 

3929 ).all() 

3930 

3931 result = {} 

3932 for row in rows: 

3933 result[row['key']] = row['value'] 

3934 return result 

3935 

3936 

3937def _share_snapshot_metadata_get_item(context, share_snapshot_id, key): 

3938 result = _share_snapshot_metadata_get_query( 

3939 context, share_snapshot_id).filter_by( 

3940 key=key).first() 

3941 if not result: 3941 ↛ 3942line 3941 didn't jump to line 3942 because the condition on line 3941 was never true

3942 raise exception.MetadataItemNotFound 

3943 return result 

3944 

3945 

3946@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

3947def _share_snapshot_metadata_update(context, share_snapshot_id, 

3948 metadata, delete): 

3949 delete = strutils.bool_from_string(delete) 

3950 if delete: 3950 ↛ 3951line 3950 didn't jump to line 3951 because the condition on line 3950 was never true

3951 original_metadata = _share_snapshot_metadata_get( 

3952 context, share_snapshot_id) 

3953 for meta_key, meta_value in original_metadata.items(): 

3954 if meta_key not in metadata: 

3955 meta_ref = _share_snapshot_metadata_get_item( 

3956 context, share_snapshot_id, meta_key, 

3957 ) 

3958 meta_ref.soft_delete(session=context.session) 

3959 

3960 # Now update all existing items with new values, or create new meta 

3961 # objects 

3962 meta_ref = None 

3963 for meta_key, meta_value in metadata.items(): 

3964 # update the value whether it exists or not 

3965 item = {"value": meta_value} 

3966 meta_ref = _share_snapshot_metadata_get_query( 

3967 context, share_snapshot_id, 

3968 ).filter_by(key=meta_key).first() 

3969 if not meta_ref: 

3970 meta_ref = models.ShareSnapshotMetadata() 

3971 item.update({"key": meta_key, 

3972 "share_snapshot_id": share_snapshot_id}) 

3973 meta_ref.update(item) 

3974 meta_ref.save(session=context.session) 

3975 

3976 return metadata 

3977 

3978################################# 

3979 

3980 

3981@require_context 

3982@context_manager.writer 

3983def share_snapshot_access_create(context, values): 

3984 values = ensure_model_dict_has_id(values) 

3985 access_ref = models.ShareSnapshotAccessMapping() 

3986 access_ref.update(values) 

3987 access_ref.save(session=context.session) 

3988 

3989 snapshot = _share_snapshot_get(context, values['share_snapshot_id']) 

3990 

3991 for instance in snapshot.instances: 

3992 values = { 

3993 'share_snapshot_instance_id': instance['id'], 

3994 'access_id': access_ref['id'], 

3995 } 

3996 

3997 instance_access_ref = models.ShareSnapshotInstanceAccessMapping() 

3998 instance_access_ref.update(ensure_model_dict_has_id(values)) 

3999 instance_access_ref.save(session=context.session) 

4000 

4001 return _share_snapshot_access_get(context, access_ref['id']) 

4002 

4003 

4004def _share_snapshot_access_get_query(context, filters, read_deleted='no'): 

4005 query = model_query( 

4006 context, models.ShareSnapshotAccessMapping, read_deleted=read_deleted 

4007 ) 

4008 return query.filter_by(**filters) 

4009 

4010 

4011def _share_snapshot_instance_access_get_query( 

4012 context, access_id=None, share_snapshot_instance_id=None, 

4013): 

4014 filters = {'deleted': 'False'} 

4015 

4016 if access_id is not None: 

4017 filters.update({'access_id': access_id}) 

4018 

4019 if share_snapshot_instance_id is not None: 

4020 filters.update( 

4021 {'share_snapshot_instance_id': share_snapshot_instance_id} 

4022 ) 

4023 

4024 return model_query( 

4025 context, models.ShareSnapshotInstanceAccessMapping 

4026 ).filter_by(**filters) 

4027 

4028 

4029@require_context 

4030@context_manager.reader 

4031def share_snapshot_instance_access_get_all(context, access_id): 

4032 return _share_snapshot_instance_access_get_all(context, access_id) 

4033 

4034 

4035def _share_snapshot_instance_access_get_all(context, access_id): 

4036 rules = _share_snapshot_instance_access_get_query( 

4037 context, access_id=access_id).all() 

4038 return rules 

4039 

4040 

4041@require_context 

4042@context_manager.reader 

4043def share_snapshot_access_get(context, access_id): 

4044 return _share_snapshot_access_get(context, access_id) 

4045 

4046 

4047def _share_snapshot_access_get(context, access_id): 

4048 access = _share_snapshot_access_get_query( 

4049 context, {'id': access_id}, 

4050 ).first() 

4051 

4052 if access: 4052 ↛ 4055line 4052 didn't jump to line 4055 because the condition on line 4052 was always true

4053 return access 

4054 else: 

4055 raise exception.NotFound() 

4056 

4057 

4058@require_context 

4059@context_manager.reader 

4060def share_snapshot_access_get_all_for_share_snapshot(context, 

4061 share_snapshot_id, 

4062 filters): 

4063 filters['share_snapshot_id'] = share_snapshot_id 

4064 access_list = _share_snapshot_access_get_query( 

4065 context, filters 

4066 ).all() 

4067 

4068 return access_list 

4069 

4070 

4071@require_context 

4072@context_manager.reader 

4073def share_snapshot_check_for_existing_access(context, share_snapshot_id, 

4074 access_type, access_to): 

4075 return _check_for_existing_access( 

4076 context, 'share_snapshot', share_snapshot_id, access_type, access_to) 

4077 

4078 

4079@require_context 

4080@context_manager.reader 

4081def share_snapshot_access_get_all_for_snapshot_instance( 

4082 context, snapshot_instance_id, filters=None, 

4083 with_snapshot_access_data=True, 

4084): 

4085 return _share_snapshot_access_get_all_for_snapshot_instance( 

4086 context, snapshot_instance_id, filters=filters, 

4087 with_snapshot_access_data=with_snapshot_access_data, 

4088 ) 

4089 

4090 

4091def _share_snapshot_access_get_all_for_snapshot_instance( 

4092 context, snapshot_instance_id, filters=None, 

4093 with_snapshot_access_data=True, 

4094): 

4095 """Get all access rules related to a certain snapshot instance.""" 

4096 filters = copy.deepcopy(filters) if filters else {} 

4097 filters.update({'share_snapshot_instance_id': snapshot_instance_id}) 

4098 

4099 query = _share_snapshot_instance_access_get_query(context) 

4100 

4101 legal_filter_keys = ( 

4102 'id', 'share_snapshot_instance_id', 'access_id', 'state') 

4103 

4104 query = exact_filter( 

4105 query, models.ShareSnapshotInstanceAccessMapping, filters, 

4106 legal_filter_keys) 

4107 

4108 instance_accesses = query.all() 

4109 

4110 if with_snapshot_access_data: 4110 ↛ 4115line 4110 didn't jump to line 4115 because the condition on line 4110 was always true

4111 instance_accesses = _set_instances_snapshot_access_data( 

4112 context, instance_accesses 

4113 ) 

4114 

4115 return instance_accesses 

4116 

4117 

4118@require_context 

4119@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

4120@context_manager.writer 

4121def share_snapshot_instance_access_update( 

4122 context, access_id, instance_id, updates 

4123): 

4124 snapshot_access_fields = ('access_type', 'access_to') 

4125 snapshot_access_map_updates, share_instance_access_map_updates = ( 

4126 _extract_subdict_by_fields(updates, snapshot_access_fields) 

4127 ) 

4128 

4129 updated_at = timeutils.utcnow() 

4130 snapshot_access_map_updates['updated_at'] = updated_at 

4131 share_instance_access_map_updates['updated_at'] = updated_at 

4132 

4133 snapshot_access = _share_snapshot_access_get_query( 

4134 context, {'id': access_id}).first() 

4135 if not snapshot_access: 4135 ↛ 4136line 4135 didn't jump to line 4136 because the condition on line 4135 was never true

4136 raise exception.NotFound() 

4137 snapshot_access.update(snapshot_access_map_updates) 

4138 snapshot_access.save(session=context.session) 

4139 

4140 access = _share_snapshot_instance_access_get_query( 

4141 context, access_id=access_id, 

4142 share_snapshot_instance_id=instance_id).first() 

4143 if not access: 4143 ↛ 4144line 4143 didn't jump to line 4144 because the condition on line 4143 was never true

4144 raise exception.NotFound() 

4145 access.update(share_instance_access_map_updates) 

4146 access.save(session=context.session) 

4147 

4148 return access 

4149 

4150 

4151@require_context 

4152@context_manager.writer 

4153def share_snapshot_instance_access_get( 

4154 context, access_id, share_snapshot_instance_id, 

4155 with_snapshot_access_data=True 

4156): 

4157 access = _share_snapshot_instance_access_get_query( 

4158 context, access_id=access_id, 

4159 share_snapshot_instance_id=share_snapshot_instance_id 

4160 ).first() 

4161 

4162 if access is None: 4162 ↛ 4163line 4162 didn't jump to line 4163 because the condition on line 4162 was never true

4163 raise exception.NotFound() 

4164 

4165 if with_snapshot_access_data: 4165 ↛ 4168line 4165 didn't jump to line 4168 because the condition on line 4165 was always true

4166 return _set_instances_snapshot_access_data(context, access)[0] 

4167 else: 

4168 return access 

4169 

4170 

4171@require_context 

4172@context_manager.writer 

4173def share_snapshot_instance_access_delete( 

4174 context, access_id, snapshot_instance_id 

4175): 

4176 return _share_snapshot_instance_access_delete( 

4177 context, access_id, snapshot_instance_id 

4178 ) 

4179 

4180 

4181def _share_snapshot_instance_access_delete( 

4182 context, access_id, snapshot_instance_id 

4183): 

4184 rule = _share_snapshot_instance_access_get_query( 

4185 context, access_id=access_id, 

4186 share_snapshot_instance_id=snapshot_instance_id).first() 

4187 

4188 if not rule: 4188 ↛ 4189line 4188 didn't jump to line 4189 because the condition on line 4188 was never true

4189 exception.NotFound() 

4190 

4191 rule.soft_delete( 

4192 session=context.session, update_status=True, 

4193 status_field_name='state') 

4194 

4195 other_mappings = _share_snapshot_instance_access_get_all( 

4196 context, rule['access_id']) 

4197 

4198 if len(other_mappings) == 0: 4198 ↛ 4199line 4198 didn't jump to line 4199 because the condition on line 4198 was never true

4199 context.session.query( 

4200 models.ShareSnapshotAccessMapping 

4201 ).filter_by( 

4202 id=rule['access_id'] 

4203 ).soft_delete( 

4204 update_status=True, status_field_name='state' 

4205 ) 

4206 

4207 

4208@require_context 

4209@context_manager.writer 

4210def share_snapshot_instance_export_location_create(context, values): 

4211 values = ensure_model_dict_has_id(values) 

4212 ssiel = models.ShareSnapshotInstanceExportLocation() 

4213 ssiel.update(values) 

4214 ssiel.save(session=context.session) 

4215 

4216 return ssiel 

4217 

4218 

4219def _share_snapshot_instance_export_locations_get_query(context, values): 

4220 query = model_query(context, models.ShareSnapshotInstanceExportLocation) 

4221 return query.filter_by(**values) 

4222 

4223 

4224@require_context 

4225@context_manager.reader 

4226def share_snapshot_export_locations_get(context, snapshot_id): 

4227 snapshot = _share_snapshot_get(context, snapshot_id) 

4228 ins_ids = [ins['id'] for ins in snapshot.instances] 

4229 export_locations = _share_snapshot_instance_export_locations_get_query( 

4230 context, {}).filter( 

4231 models.ShareSnapshotInstanceExportLocation. 

4232 share_snapshot_instance_id.in_(ins_ids)).all() 

4233 return export_locations 

4234 

4235 

4236@require_context 

4237@context_manager.reader 

4238def share_snapshot_instance_export_locations_get_all( 

4239 context, share_snapshot_instance_id, 

4240): 

4241 return _share_snapshot_instance_export_locations_get_all( 

4242 context, share_snapshot_instance_id, 

4243 ) 

4244 

4245 

4246def _share_snapshot_instance_export_locations_get_all( 

4247 context, share_snapshot_instance_id, 

4248): 

4249 export_locations = _share_snapshot_instance_export_locations_get_query( 

4250 context, 

4251 {'share_snapshot_instance_id': share_snapshot_instance_id}, 

4252 ).all() 

4253 return export_locations 

4254 

4255 

4256@require_context 

4257@context_manager.reader 

4258def share_snapshot_instance_export_location_get(context, el_id): 

4259 export_location = _share_snapshot_instance_export_locations_get_query( 

4260 context, {'id': el_id}, 

4261 ).first() 

4262 

4263 if export_location: 4263 ↛ 4266line 4263 didn't jump to line 4266 because the condition on line 4263 was always true

4264 return export_location 

4265 else: 

4266 raise exception.NotFound() 

4267 

4268 

4269@require_context 

4270@context_manager.writer 

4271def share_snapshot_instance_export_location_delete(context, el_id): 

4272 return _share_snapshot_instance_export_location_delete(context, el_id) 

4273 

4274 

4275def _share_snapshot_instance_export_location_delete(context, el_id): 

4276 el = _share_snapshot_instance_export_locations_get_query( 

4277 context, {'id': el_id}).first() 

4278 

4279 if not el: 

4280 exception.NotFound() 

4281 

4282 el.soft_delete(session=context.session) 

4283 

4284 

4285@require_context 

4286@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

4287@context_manager.writer 

4288def share_snapshot_instance_export_locations_update( 

4289 context, share_snapshot_instance_id, export_locations, delete, 

4290): 

4291 # NOTE(dviroel): Lets keep this backward compatibility for driver that 

4292 # may still return export_locations as string 

4293 if not isinstance(export_locations, (list, tuple, set)): 4293 ↛ 4294line 4293 didn't jump to line 4294 because the condition on line 4293 was never true

4294 export_locations = (export_locations, ) 

4295 

4296 export_locations_as_dicts = [] 

4297 for el in export_locations: 

4298 export_location = el 

4299 if isinstance(el, str): 

4300 export_location = { 

4301 "path": el, 

4302 "is_admin_only": False, 

4303 } 

4304 elif not isinstance(export_location, dict): 4304 ↛ 4307line 4304 didn't jump to line 4307 because the condition on line 4304 was always true

4305 raise exception.ManilaException( 

4306 _("Wrong export location type '%s'.") % type(export_location)) 

4307 export_locations_as_dicts.append(export_location) 

4308 

4309 export_locations = export_locations_as_dicts 

4310 export_locations_paths = [el['path'] for el in export_locations] 

4311 current_el_rows = _share_snapshot_instance_export_locations_get_all( 

4312 context, share_snapshot_instance_id, 

4313 ) 

4314 

4315 def get_path_list_from_rows(rows): 

4316 return set([row['path'] for row in rows]) 

4317 

4318 current_el_paths = get_path_list_from_rows(current_el_rows) 

4319 

4320 def create_indexed_time_dict(key_list): 

4321 base = timeutils.utcnow() 

4322 return { 

4323 # NOTE(u_glide): Incrementing timestamp by microseconds to make 

4324 # timestamp order match index order. 

4325 key: base + datetime.timedelta(microseconds=index) 

4326 for index, key in enumerate(key_list) 

4327 } 

4328 

4329 indexed_update_time = create_indexed_time_dict(export_locations_paths) 

4330 

4331 for el in current_el_rows: 

4332 if delete and el['path'] not in export_locations_paths: 

4333 el.soft_delete(session=context.session) 

4334 else: 

4335 updated_at = indexed_update_time[el['path']] 

4336 el.update({ 

4337 'updated_at': updated_at, 

4338 }) 

4339 el.save(session=context.session) 

4340 

4341 # Now add new export locations 

4342 for el in export_locations: 

4343 if el['path'] in current_el_paths: 

4344 # Already updated 

4345 continue 

4346 

4347 location_ref = models.ShareSnapshotInstanceExportLocation() 

4348 location_ref.update({ 

4349 'id': uuidutils.generate_uuid(), 

4350 'path': el['path'], 

4351 'share_snapshot_instance_id': share_snapshot_instance_id, 

4352 'updated_at': indexed_update_time[el['path']], 

4353 'is_admin_only': el.get('is_admin_only', False), 

4354 }) 

4355 location_ref.save(session=context.session) 

4356 

4357 return get_path_list_from_rows( 

4358 _share_snapshot_instance_export_locations_get_all( 

4359 context, share_snapshot_instance_id, 

4360 ) 

4361 ) 

4362 

4363################################# 

4364 

4365 

4366def _share_metadata_get_query(context, share_id): 

4367 return model_query( 

4368 context, models.ShareMetadata, read_deleted="no", 

4369 ).filter_by( 

4370 share_id=share_id, 

4371 ).options(orm.joinedload(models.ShareMetadata.share)) 

4372 

4373 

4374@require_context 

4375@require_share_exists 

4376@context_manager.reader 

4377def share_metadata_get(context, share_id): 

4378 return _share_metadata_get(context, share_id) 

4379 

4380 

4381def _share_metadata_get(context, share_id): 

4382 rows = _share_metadata_get_query(context, share_id).all() 

4383 result = {} 

4384 for row in rows: 

4385 result[row['key']] = row['value'] 

4386 

4387 return result 

4388 

4389 

4390@require_context 

4391@require_share_exists 

4392@context_manager.reader 

4393def share_metadata_get_item(context, share_id, key): 

4394 try: 

4395 row = _share_metadata_get_item(context, share_id, key) 

4396 except exception.MetadataItemNotFound: 

4397 raise exception.MetadataItemNotFound() 

4398 

4399 result = {} 

4400 result[row['key']] = row['value'] 

4401 

4402 return result 

4403 

4404 

4405@require_context 

4406@require_share_exists 

4407@context_manager.writer 

4408def share_metadata_delete(context, share_id, key): 

4409 _share_metadata_get_query( 

4410 context, share_id, 

4411 ).filter_by(key=key).soft_delete() 

4412 

4413 

4414@require_context 

4415@require_share_exists 

4416@context_manager.writer 

4417def share_metadata_update(context, share_id, metadata, delete): 

4418 return _share_metadata_update(context, share_id, metadata, delete) 

4419 

4420 

4421@require_context 

4422@require_share_exists 

4423@context_manager.writer 

4424def share_metadata_update_item(context, share_id, item): 

4425 return _share_metadata_update(context, share_id, item, delete=False) 

4426 

4427 

4428@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

4429def _share_metadata_update(context, share_id, metadata, delete): 

4430 # Set existing metadata to deleted if delete argument is True 

4431 delete = strutils.bool_from_string(delete) 

4432 if delete: 

4433 original_metadata = _share_metadata_get(context, share_id) 

4434 for meta_key, meta_value in original_metadata.items(): 

4435 if meta_key not in metadata: 

4436 meta_ref = _share_metadata_get_item( 

4437 context, share_id, meta_key, 

4438 ) 

4439 meta_ref.soft_delete(session=context.session) 

4440 

4441 meta_ref = None 

4442 

4443 # Now update all existing items with new values, or create new meta 

4444 # objects 

4445 for meta_key, meta_value in metadata.items(): 

4446 

4447 # update the value whether it exists or not 

4448 item = {"value": meta_value} 

4449 

4450 try: 

4451 meta_ref = _share_metadata_get_item( 

4452 context, share_id, meta_key, 

4453 ) 

4454 except exception.MetadataItemNotFound: 

4455 meta_ref = models.ShareMetadata() 

4456 item.update({"key": meta_key, "share_id": share_id}) 

4457 

4458 meta_ref.update(item) 

4459 meta_ref.save(session=context.session) 

4460 

4461 return metadata 

4462 

4463 

4464def _share_metadata_get_item(context, share_id, key): 

4465 result = _share_metadata_get_query( 

4466 context, share_id, 

4467 ).filter_by(key=key).first() 

4468 

4469 if not result: 

4470 raise exception.MetadataItemNotFound() 

4471 return result 

4472 

4473 

4474############################ 

4475# Export locations functions 

4476############################ 

4477 

4478def _export_location_get_all( 

4479 context, share_instance_ids, 

4480 include_admin_only=True, 

4481 ignore_secondary_replicas=False, 

4482): 

4483 if not isinstance(share_instance_ids, (set, list, tuple)): 

4484 share_instance_ids = (share_instance_ids, ) 

4485 

4486 query = model_query( 

4487 context, 

4488 models.ShareInstanceExportLocations, 

4489 read_deleted="no", 

4490 ).filter( 

4491 models.ShareInstanceExportLocations.share_instance_id.in_( 

4492 share_instance_ids), 

4493 ).order_by( 

4494 "updated_at", 

4495 ).options( 

4496 orm.joinedload(models.ShareInstanceExportLocations._el_metadata_bare), 

4497 ) 

4498 

4499 if not include_admin_only: 

4500 query = query.filter_by(is_admin_only=False) 

4501 

4502 if ignore_secondary_replicas: 

4503 replica_state_attr = models.ShareInstance.replica_state 

4504 query = query.join( 

4505 models.ShareInstanceExportLocations.share_instance, 

4506 ).filter( 

4507 or_(replica_state_attr == None, # noqa 

4508 replica_state_attr == constants.REPLICA_STATE_ACTIVE)) 

4509 

4510 return query.all() 

4511 

4512 

4513@require_context 

4514@require_share_exists 

4515@context_manager.reader 

4516def export_location_get_all_by_share_id( 

4517 context, share_id, 

4518 include_admin_only=True, 

4519 ignore_migration_destination=False, 

4520 ignore_secondary_replicas=False, 

4521): 

4522 share = _share_get(context, share_id) 

4523 if ignore_migration_destination: 

4524 ids = [instance.id for instance in share.instances 

4525 if instance['status'] != constants.STATUS_MIGRATING_TO] 

4526 else: 

4527 ids = [instance.id for instance in share.instances] 

4528 rows = _export_location_get_all( 

4529 context, ids, include_admin_only=include_admin_only, 

4530 ignore_secondary_replicas=ignore_secondary_replicas) 

4531 return rows 

4532 

4533 

4534@require_context 

4535@require_share_instance_exists 

4536@context_manager.reader 

4537def export_location_get_all_by_share_instance_id( 

4538 context, share_instance_id, include_admin_only=True, 

4539): 

4540 rows = _export_location_get_all( 

4541 context, [share_instance_id], include_admin_only=include_admin_only) 

4542 return rows 

4543 

4544 

4545@require_context 

4546@require_share_exists 

4547@context_manager.reader 

4548def export_location_get_all(context, share_id): 

4549 # NOTE(vponomaryov): this method is kept for compatibility with 

4550 # old approach. New one uses 'export_location_get_all_by_share_id'. 

4551 # Which returns list of dicts instead of list of strings, as this one does. 

4552 share = _share_get(context, share_id) 

4553 rows = _export_location_get_all( 

4554 context, share.instance.id, context.is_admin) 

4555 

4556 return [location['path'] for location in rows] 

4557 

4558 

4559@require_context 

4560@context_manager.reader 

4561def export_location_get_by_uuid( 

4562 context, export_location_uuid, ignore_secondary_replicas=False, 

4563): 

4564 return _export_location_get_by_uuid( 

4565 context, export_location_uuid, 

4566 ignore_secondary_replicas=ignore_secondary_replicas, 

4567 ) 

4568 

4569 

4570def _export_location_get_by_uuid( 

4571 context, export_location_uuid, ignore_secondary_replicas=False, 

4572): 

4573 query = model_query( 

4574 context, 

4575 models.ShareInstanceExportLocations, 

4576 read_deleted="no", 

4577 ).filter_by( 

4578 uuid=export_location_uuid, 

4579 ).options( 

4580 orm.joinedload(models.ShareInstanceExportLocations._el_metadata_bare), 

4581 ) 

4582 

4583 if ignore_secondary_replicas: 

4584 replica_state_attr = models.ShareInstance.replica_state 

4585 query = query.join( 

4586 models.ShareInstanceExportLocations.share_instance, 

4587 ).filter( 

4588 or_( 

4589 replica_state_attr == None, # noqa 

4590 replica_state_attr == constants.REPLICA_STATE_ACTIVE, 

4591 ) 

4592 ) 

4593 

4594 result = query.first() 

4595 if not result: 

4596 raise exception.ExportLocationNotFound(uuid=export_location_uuid) 

4597 return result 

4598 

4599 

4600@require_context 

4601@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

4602@context_manager.writer 

4603def export_locations_update( 

4604 context, share_instance_id, export_locations, delete, 

4605): 

4606 return _export_locations_update( 

4607 context, share_instance_id, export_locations, delete, 

4608 ) 

4609 

4610 

4611def _export_locations_update( 

4612 context, share_instance_id, export_locations, delete, 

4613): 

4614 # NOTE(u_glide): 

4615 # Backward compatibility code for drivers, 

4616 # which return single export_location as string 

4617 if not isinstance(export_locations, (list, tuple, set)): 

4618 export_locations = (export_locations, ) 

4619 

4620 export_locations_as_dicts = [] 

4621 for el in export_locations: 

4622 # NOTE(vponomaryov): transform old export locations view to new one 

4623 export_location = el 

4624 if isinstance(el, str): 

4625 export_location = { 

4626 "path": el, 

4627 "is_admin_only": False, 

4628 "metadata": {}, 

4629 } 

4630 elif isinstance(export_location, dict): 4630 ↛ 4634line 4630 didn't jump to line 4634 because the condition on line 4630 was always true

4631 if 'metadata' not in export_location: 

4632 export_location['metadata'] = {} 

4633 else: 

4634 raise exception.ManilaException( 

4635 _("Wrong export location type '%s'.") % type(export_location)) 

4636 export_locations_as_dicts.append(export_location) 

4637 export_locations = export_locations_as_dicts 

4638 

4639 export_locations_paths = [el['path'] for el in export_locations] 

4640 

4641 current_el_rows = _export_location_get_all(context, share_instance_id) 

4642 

4643 def get_path_list_from_rows(rows): 

4644 return set([row['path'] for row in rows]) 

4645 

4646 current_el_paths = get_path_list_from_rows(current_el_rows) 

4647 

4648 def create_indexed_time_dict(key_list): 

4649 base = timeutils.utcnow() 

4650 return { 

4651 # NOTE(u_glide): Incrementing timestamp by microseconds to make 

4652 # timestamp order match index order. 

4653 key: base + datetime.timedelta(microseconds=index) 

4654 for index, key in enumerate(key_list) 

4655 } 

4656 

4657 indexed_update_time = create_indexed_time_dict(export_locations_paths) 

4658 

4659 for el in current_el_rows: 

4660 if delete and el['path'] not in export_locations_paths: 

4661 _export_location_metadata_delete(context, el['uuid']) 

4662 el.soft_delete(session=context.session) 

4663 else: 

4664 updated_at = indexed_update_time[el['path']] 

4665 el.update({ 

4666 'updated_at': updated_at, 

4667 'deleted': 0, 

4668 }) 

4669 el.save(session=context.session) 

4670 

4671 new_export_metadata = next( 

4672 exl.get('metadata', {}) 

4673 for exl in export_locations 

4674 if exl['path'] == el['path'] 

4675 ) 

4676 new_export_metadata = new_export_metadata or el['el_metadata'] 

4677 

4678 if new_export_metadata: 

4679 _export_location_metadata_update( 

4680 context, el['uuid'], new_export_metadata, 

4681 ) 

4682 

4683 # Now add new export locations 

4684 for el in export_locations: 

4685 if el['path'] in current_el_paths: 

4686 # Already updated 

4687 continue 

4688 

4689 location_ref = models.ShareInstanceExportLocations() 

4690 location_ref.update({ 

4691 'uuid': uuidutils.generate_uuid(), 

4692 'path': el['path'], 

4693 'share_instance_id': share_instance_id, 

4694 'updated_at': indexed_update_time[el['path']], 

4695 'deleted': 0, 

4696 'is_admin_only': el.get('is_admin_only', False), 

4697 }) 

4698 location_ref.save(session=context.session) 

4699 if not el.get('metadata'): 

4700 continue 

4701 _export_location_metadata_update( 

4702 context, location_ref['uuid'], el.get('metadata'), 

4703 ) 

4704 

4705 return get_path_list_from_rows( 

4706 _export_location_get_all(context, share_instance_id) 

4707 ) 

4708 

4709 

4710##################################### 

4711# Export locations metadata functions 

4712##################################### 

4713 

4714def _export_location_metadata_get_query(context, export_location_uuid): 

4715 export_location_id = _export_location_get_by_uuid( 

4716 context, export_location_uuid).id 

4717 

4718 return model_query( 

4719 context, models.ShareInstanceExportLocationsMetadata, 

4720 read_deleted="no", 

4721 ).filter_by( 

4722 export_location_id=export_location_id, 

4723 ) 

4724 

4725 

4726@require_context 

4727@context_manager.reader 

4728def export_location_metadata_get(context, export_location_uuid): 

4729 return _export_location_metadata_get(context, export_location_uuid) 

4730 

4731 

4732def _export_location_metadata_get(context, export_location_uuid): 

4733 rows = _export_location_metadata_get_query( 

4734 context, export_location_uuid, 

4735 ).all() 

4736 result = {} 

4737 for row in rows: 

4738 result[row["key"]] = row["value"] 

4739 return result 

4740 

4741 

4742@require_context 

4743@context_manager.writer 

4744def export_location_metadata_delete(context, export_location_uuid, keys=None): 

4745 return _export_location_metadata_delete( 

4746 context, export_location_uuid, keys=keys, 

4747 ) 

4748 

4749 

4750def _export_location_metadata_delete(context, export_location_uuid, keys=None): 

4751 metadata = _export_location_metadata_get_query( 

4752 context, export_location_uuid, 

4753 ) 

4754 # NOTE(vponomaryov): if keys is None then we delete all metadata. 

4755 if keys is not None: 

4756 keys = keys if isinstance(keys, (list, set, tuple)) else (keys, ) 

4757 metadata = metadata.filter( 

4758 models.ShareInstanceExportLocationsMetadata.key.in_(keys), 

4759 ) 

4760 metadata = metadata.all() 

4761 for meta_ref in metadata: 

4762 meta_ref.soft_delete(session=context.session) 

4763 

4764 

4765@require_context 

4766@context_manager.writer 

4767def export_location_metadata_update( 

4768 context, export_location_uuid, metadata, delete=False, 

4769): 

4770 return _export_location_metadata_update( 

4771 context, export_location_uuid, metadata, delete=delete, 

4772 ) 

4773 

4774 

4775@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

4776def _export_location_metadata_update( 

4777 context, export_location_uuid, metadata, delete=False, 

4778): 

4779 if delete: 

4780 original_metadata = _export_location_metadata_get( 

4781 context, export_location_uuid, 

4782 ) 

4783 keys_for_deletion = set(original_metadata).difference(metadata) 

4784 if keys_for_deletion: 4784 ↛ 4789line 4784 didn't jump to line 4789 because the condition on line 4784 was always true

4785 _export_location_metadata_delete( 

4786 context, export_location_uuid, keys=keys_for_deletion, 

4787 ) 

4788 

4789 el = _export_location_get_by_uuid(context, export_location_uuid) 

4790 for meta_key, meta_value in metadata.items(): 

4791 # NOTE(vponomaryov): we should use separate session 

4792 # for each meta_ref because of autoincrement of integer primary key 

4793 # that will not take effect using one session and we will rewrite, 

4794 # in that case, single record - first one added with this call. 

4795 context.session.commit() 

4796 context.session.begin() 

4797 

4798 if meta_value is None: 4798 ↛ 4799line 4798 didn't jump to line 4799 because the condition on line 4798 was never true

4799 LOG.warning("%s should be properly defined in the driver.", 

4800 meta_key) 

4801 

4802 item = {"value": meta_value, "updated_at": timeutils.utcnow()} 

4803 

4804 meta_ref = _export_location_metadata_get_query( 

4805 context, export_location_uuid, 

4806 ).filter_by( 

4807 key=meta_key, 

4808 ).first() 

4809 

4810 if not meta_ref: 

4811 meta_ref = models.ShareInstanceExportLocationsMetadata() 

4812 item.update({ 

4813 "key": meta_key, 

4814 "export_location_id": el.id, 

4815 }) 

4816 

4817 meta_ref.update(item) 

4818 meta_ref.save(session=context.session) 

4819 

4820 return metadata 

4821 

4822 

4823@require_context 

4824@context_manager.reader 

4825def export_location_metadata_get_item(context, export_location_uuid, key): 

4826 

4827 row = _export_location_metadata_get_item( 

4828 context, export_location_uuid, key) 

4829 result = {row['key']: row['value']} 

4830 

4831 return result 

4832 

4833 

4834@require_context 

4835@context_manager.writer 

4836def export_location_metadata_update_item(context, export_location_uuid, 

4837 item): 

4838 return _export_location_metadata_update(context, export_location_uuid, 

4839 item, delete=False) 

4840 

4841 

4842def _export_location_metadata_get_item(context, export_location_uuid, key): 

4843 result = _export_location_metadata_get_query( 

4844 context, export_location_uuid, 

4845 ).filter_by(key=key).first() 

4846 if not result: 

4847 raise exception.MetadataItemNotFound() 

4848 return result 

4849 

4850################################### 

4851 

4852 

4853def _security_service_get_query(context, project_only=False): 

4854 return model_query( 

4855 context, models.SecurityService, project_only=project_only, 

4856 ) 

4857 

4858 

4859@require_context 

4860@context_manager.writer 

4861def security_service_create(context, values): 

4862 values = ensure_model_dict_has_id(values) 

4863 

4864 security_service_ref = models.SecurityService() 

4865 security_service_ref.update(values) 

4866 security_service_ref.save(session=context.session) 

4867 

4868 return security_service_ref 

4869 

4870 

4871@require_context 

4872@context_manager.writer 

4873def security_service_delete(context, id): 

4874 security_service_ref = _security_service_get(context, id) 

4875 security_service_ref.soft_delete(session=context.session) 

4876 

4877 

4878@require_context 

4879@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

4880@context_manager.writer 

4881def security_service_update(context, id, values): 

4882 security_service_ref = _security_service_get(context, id) 

4883 security_service_ref.update(values) 

4884 security_service_ref.save(session=context.session) 

4885 return security_service_ref 

4886 

4887 

4888@require_context 

4889@context_manager.reader 

4890def security_service_get(context, id, **kwargs): 

4891 return _security_service_get(context, id, **kwargs) 

4892 

4893 

4894@require_context 

4895def _security_service_get(context, id, **kwargs): 

4896 result = _security_service_get_query( 

4897 context, 

4898 **kwargs, 

4899 ).filter_by(id=id).first() 

4900 if result is None: 

4901 raise exception.SecurityServiceNotFound(security_service_id=id) 

4902 return result 

4903 

4904 

4905@require_context 

4906@context_manager.reader 

4907def security_service_get_all(context): 

4908 return _security_service_get_query(context).all() 

4909 

4910 

4911@require_context 

4912@context_manager.reader 

4913def security_service_get_all_by_project(context, project_id): 

4914 return _security_service_get_query(context).filter_by( 

4915 project_id=project_id, 

4916 ).all() 

4917 

4918 

4919@require_context 

4920@context_manager.reader 

4921def security_service_get_all_by_share_network(context, share_network_id): 

4922 return model_query( 

4923 context, models.SecurityService, 

4924 ).join( 

4925 models.ShareNetworkSecurityServiceAssociation, 

4926 models.SecurityService.id == 

4927 models.ShareNetworkSecurityServiceAssociation.security_service_id, 

4928 ).filter_by( 

4929 share_network_id=share_network_id, deleted=0, 

4930 ).all() 

4931 

4932 

4933################### 

4934 

4935 

4936def _share_network_get_query(context): 

4937 return model_query( 

4938 context, models.ShareNetwork, project_only=True, 

4939 ).options( 

4940 orm.joinedload(models.ShareNetwork.share_instances), 

4941 orm.joinedload(models.ShareNetwork.security_services), 

4942 orm.subqueryload(models.ShareNetwork.share_network_subnets), 

4943 ) 

4944 

4945 

4946@require_context 

4947@context_manager.writer 

4948def share_network_create(context, values): 

4949 values = ensure_model_dict_has_id(values) 

4950 

4951 network_ref = models.ShareNetwork() 

4952 network_ref.update(values) 

4953 network_ref.save(session=context.session) 

4954 return _share_network_get(context, values['id']) 

4955 

4956 

4957@require_context 

4958@context_manager.writer 

4959def share_network_delete(context, id): 

4960 network_ref = _share_network_get(context, id) 

4961 for subnet in network_ref['share_network_subnets']: 

4962 share_network_subnet_delete(context, subnet['id']) 

4963 network_ref.soft_delete(session=context.session) 

4964 

4965 

4966@require_context 

4967@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

4968@context_manager.writer 

4969def share_network_update(context, id, values): 

4970 network_ref = _share_network_get(context, id) 

4971 network_ref.update(values) 

4972 network_ref.save(session=context.session) 

4973 return network_ref 

4974 

4975 

4976@require_context 

4977@context_manager.reader 

4978def share_network_get(context, id): 

4979 return _share_network_get(context, id) 

4980 

4981 

4982@require_context 

4983def _share_network_get(context, id): 

4984 result = _share_network_get_query(context).filter_by(id=id).first() 

4985 if result is None: 

4986 raise exception.ShareNetworkNotFound(share_network_id=id) 

4987 return result 

4988 

4989 

4990@require_context 

4991@context_manager.reader 

4992def share_network_get_all_by_filter(context, filters=None): 

4993 query = _share_network_get_query(context) 

4994 

4995 legal_filter_keys = ('project_id', 'created_since', 'created_before') 

4996 

4997 if not filters: 4997 ↛ 4998line 4997 didn't jump to line 4998 because the condition on line 4997 was never true

4998 filters = {} 

4999 

5000 query = exact_filter( 

5001 query, models.ShareNetwork, filters, legal_filter_keys, 

5002 ) 

5003 if 'security_service_id' in filters: 5003 ↛ 5004line 5003 didn't jump to line 5004 because the condition on line 5003 was never true

5004 security_service_id = filters.get('security_service_id') 

5005 query = query.join( 

5006 models.ShareNetworkSecurityServiceAssociation, 

5007 models.ShareNetwork.id == models.ShareNetworkSecurityServiceAssociation.share_network_id, # noqa: E501 

5008 ).filter_by( 

5009 security_service_id=security_service_id, 

5010 deleted=0, 

5011 ) 

5012 

5013 return query.all() 

5014 

5015 

5016@require_context 

5017@context_manager.reader 

5018def share_network_get_all(context): 

5019 return _share_network_get_query(context).all() 

5020 

5021 

5022@require_context 

5023@context_manager.reader 

5024def share_network_get_all_by_project(context, project_id): 

5025 return _share_network_get_query( 

5026 context, 

5027 ).filter_by(project_id=project_id).all() 

5028 

5029 

5030@require_context 

5031@context_manager.reader 

5032def share_network_get_all_by_security_service(context, security_service_id): 

5033 return model_query( 

5034 context, models.ShareNetwork, 

5035 ).join( 

5036 models.ShareNetworkSecurityServiceAssociation, 

5037 models.ShareNetwork.id == 

5038 models.ShareNetworkSecurityServiceAssociation.share_network_id, 

5039 ).filter_by(security_service_id=security_service_id, deleted=0).all() 

5040 

5041 

5042@require_context 

5043@context_manager.writer 

5044def share_network_add_security_service(context, id, security_service_id): 

5045 assoc_ref = model_query( 

5046 context, 

5047 models.ShareNetworkSecurityServiceAssociation, 

5048 ).filter_by( 

5049 share_network_id=id, 

5050 ).filter_by(security_service_id=security_service_id).first() 

5051 

5052 if assoc_ref: 

5053 msg = "Already associated" 

5054 raise exception.ShareNetworkSecurityServiceAssociationError( 

5055 share_network_id=id, 

5056 security_service_id=security_service_id, 

5057 reason=msg, 

5058 ) 

5059 

5060 share_nw_ref = _share_network_get(context, id) 

5061 security_service_ref = _security_service_get(context, security_service_id) 

5062 share_nw_ref.security_services += [security_service_ref] 

5063 share_nw_ref.save(session=context.session) 

5064 

5065 return share_nw_ref 

5066 

5067 

5068@require_context 

5069@context_manager.reader 

5070def share_network_security_service_association_get( 

5071 context, share_network_id, security_service_id, 

5072): 

5073 association = model_query( 

5074 context, 

5075 models.ShareNetworkSecurityServiceAssociation, 

5076 ).filter_by( 

5077 share_network_id=share_network_id, 

5078 ).filter_by( 

5079 security_service_id=security_service_id, 

5080 ).first() 

5081 return association 

5082 

5083 

5084@require_context 

5085@context_manager.writer 

5086def share_network_remove_security_service(context, id, security_service_id): 

5087 share_nw_ref = _share_network_get(context, id) 

5088 _security_service_get(context, security_service_id) 

5089 

5090 assoc_ref = model_query( 

5091 context, 

5092 models.ShareNetworkSecurityServiceAssociation, 

5093 ).filter_by( 

5094 share_network_id=id, 

5095 ).filter_by(security_service_id=security_service_id).first() 

5096 

5097 if assoc_ref: 

5098 assoc_ref.soft_delete(session=context.session) 

5099 else: 

5100 msg = "No association defined" 

5101 raise exception.ShareNetworkSecurityServiceDissociationError( 

5102 share_network_id=id, 

5103 security_service_id=security_service_id, 

5104 reason=msg, 

5105 ) 

5106 

5107 return share_nw_ref 

5108 

5109 

5110@require_context 

5111@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

5112@context_manager.writer 

5113def share_network_update_security_service( 

5114 context, id, current_security_service_id, new_security_service_id, 

5115): 

5116 share_nw_ref = _share_network_get(context, id) 

5117 # Check if the old security service exists 

5118 _security_service_get(context, current_security_service_id) 

5119 new_security_service_ref = _security_service_get( 

5120 context, new_security_service_id, 

5121 ) 

5122 

5123 assoc_ref = model_query( 

5124 context, 

5125 models.ShareNetworkSecurityServiceAssociation, 

5126 ).filter_by( 

5127 share_network_id=id, 

5128 ).filter_by( 

5129 security_service_id=current_security_service_id, 

5130 ).first() 

5131 

5132 if assoc_ref: 5132 ↛ 5135line 5132 didn't jump to line 5135 because the condition on line 5132 was always true

5133 assoc_ref.soft_delete(session=context.session) 

5134 else: 

5135 msg = "No association defined" 

5136 raise exception.ShareNetworkSecurityServiceDissociationError( 

5137 share_network_id=id, 

5138 security_service_id=current_security_service_id, 

5139 reason=msg) 

5140 

5141 # Add new association 

5142 share_nw_ref.security_services += [new_security_service_ref] 

5143 share_nw_ref.save(session=context.session) 

5144 

5145 return share_nw_ref 

5146 

5147 

5148@require_context 

5149def _count_share_networks( 

5150 context, project_id, user_id=None, share_type_id=None, 

5151): 

5152 query = model_query( 

5153 context, models.ShareNetwork, 

5154 func.count(models.ShareNetwork.id), 

5155 read_deleted="no", 

5156 ).filter_by(project_id=project_id) 

5157 if share_type_id: 5157 ↛ 5158line 5157 didn't jump to line 5158 because the condition on line 5157 was never true

5158 query = query.join( 

5159 models.ShareNetwork.share_instances, 

5160 ).filter_by(share_type_id=share_type_id) 

5161 elif user_id is not None: 5161 ↛ 5163line 5161 didn't jump to line 5163 because the condition on line 5161 was always true

5162 query = query.filter_by(user_id=user_id) 

5163 return query.first()[0] 

5164 

5165 

5166################### 

5167 

5168 

5169@require_context 

5170def _share_network_subnet_get_query(context): 

5171 return model_query( 

5172 context, models.ShareNetworkSubnet, 

5173 ).options( 

5174 orm.joinedload(models.ShareNetworkSubnet.share_servers), 

5175 orm.joinedload(models.ShareNetworkSubnet.share_network), 

5176 orm.joinedload( 

5177 models.ShareNetworkSubnet.share_network_subnet_metadata 

5178 ), 

5179 ) 

5180 

5181 

5182@require_context 

5183@context_manager.writer 

5184def share_network_subnet_create(context, values): 

5185 values = ensure_model_dict_has_id(values) 

5186 values['share_network_subnet_metadata'] = _metadata_refs( 

5187 values.pop('metadata', {}), models.ShareNetworkSubnetMetadata) 

5188 

5189 network_subnet_ref = models.ShareNetworkSubnet() 

5190 network_subnet_ref.update(values) 

5191 network_subnet_ref.save(session=context.session) 

5192 return _share_network_subnet_get( 

5193 context, network_subnet_ref['id'], 

5194 ) 

5195 

5196 

5197@require_context 

5198@context_manager.writer 

5199def share_network_subnet_delete(context, network_subnet_id): 

5200 network_subnet_ref = _share_network_subnet_get(context, network_subnet_id) 

5201 context.session.query(models.ShareNetworkSubnetMetadata).filter_by( 

5202 share_network_subnet_id=network_subnet_id, 

5203 ).soft_delete() 

5204 network_subnet_ref.soft_delete(session=context.session, update_status=True) 

5205 

5206 

5207@require_context 

5208@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

5209@context_manager.writer 

5210def share_network_subnet_update(context, network_subnet_id, values): 

5211 network_subnet_ref = _share_network_subnet_get(context, network_subnet_id) 

5212 network_subnet_ref.update(values) 

5213 network_subnet_ref.save(session=context.session) 

5214 return network_subnet_ref 

5215 

5216 

5217@require_context 

5218@context_manager.reader 

5219def share_network_subnet_get(context, network_subnet_id, parent_id=None): 

5220 return _share_network_subnet_get( 

5221 context, network_subnet_id, parent_id=parent_id, 

5222 ) 

5223 

5224 

5225@require_context 

5226def _share_network_subnet_get(context, network_subnet_id, parent_id=None): 

5227 kwargs = {'id': network_subnet_id} 

5228 if parent_id: 5228 ↛ 5229line 5228 didn't jump to line 5229 because the condition on line 5228 was never true

5229 kwargs['share_network_id'] = parent_id 

5230 result = _share_network_subnet_get_query( 

5231 context, 

5232 ).filter_by(**kwargs).first() 

5233 if result is None: 

5234 raise exception.ShareNetworkSubnetNotFound( 

5235 share_network_subnet_id=network_subnet_id, 

5236 ) 

5237 return result 

5238 

5239 

5240@require_context 

5241@context_manager.reader 

5242def share_network_subnet_get_all_with_same_az(context, network_subnet_id): 

5243 subnet = _share_network_subnet_get_query( 

5244 context, 

5245 ).filter_by(id=network_subnet_id).subquery() 

5246 result = _share_network_subnet_get_query( 

5247 context, 

5248 ).join( 

5249 subnet, 

5250 subnet.c.share_network_id == 

5251 models.ShareNetworkSubnet.share_network_id, 

5252 ).filter( 

5253 func.coalesce(subnet.c.availability_zone_id, '0') == 

5254 func.coalesce(models.ShareNetworkSubnet.availability_zone_id, '0') 

5255 ).all() 

5256 if not result: 

5257 raise exception.ShareNetworkSubnetNotFound( 

5258 share_network_subnet_id=network_subnet_id, 

5259 ) 

5260 return result 

5261 

5262 

5263@require_context 

5264@context_manager.reader 

5265def share_network_subnet_get_all(context): 

5266 return _share_network_subnet_get_query(context).all() 

5267 

5268 

5269@require_context 

5270@context_manager.reader 

5271def share_network_subnet_get_all_by_share_network(context, network_id): 

5272 return _share_network_subnet_get_query(context).filter_by( 

5273 share_network_id=network_id, 

5274 ).all() 

5275 

5276 

5277@require_context 

5278@context_manager.reader 

5279def share_network_subnets_get_all_by_availability_zone_id( 

5280 context, share_network_id, availability_zone_id, 

5281 fallback_to_default=True, 

5282): 

5283 """Get the share network subnets DB records in a given AZ. 

5284 

5285 This method returns list of subnets DB record for a given share network id 

5286 and an availability zone. If the 'availability_zone_id' is 'None', a 

5287 record may be returned and it will represent the default share network 

5288 subnets. If there is no subnet for a specific availability zone id and 

5289 "fallback_to_default" is True, this method will return the default share 

5290 network subnets, if it exists. 

5291 

5292 :param context: operation context. 

5293 :param share_network_id: the share network id to be the subnets. 

5294 :param availability_zone_id: the availability zone id to be the subnets. 

5295 :param fallback_to_default: determines in case no subnets found in the 

5296 given AZ, it will return the "default" subnets. 

5297 :return: the list of share network subnets in the AZ and share network. 

5298 """ 

5299 return _share_network_subnets_get_all_by_availability_zone_id( 

5300 context, share_network_id, availability_zone_id, 

5301 fallback_to_default=fallback_to_default, 

5302 ) 

5303 

5304 

5305@require_context 

5306def _share_network_subnets_get_all_by_availability_zone_id( 

5307 context, share_network_id, availability_zone_id, 

5308 fallback_to_default=True, 

5309): 

5310 result = _share_network_subnet_get_query(context).filter_by( 

5311 share_network_id=share_network_id, 

5312 availability_zone_id=availability_zone_id, 

5313 ).all() 

5314 # If a specific subnet wasn't found, try get the default one 

5315 if availability_zone_id and not result and fallback_to_default: 

5316 return _share_network_subnet_get_query(context).filter_by( 

5317 share_network_id=share_network_id, 

5318 availability_zone_id=None, 

5319 ).all() 

5320 return result 

5321 

5322 

5323@require_context 

5324@context_manager.reader 

5325def share_network_subnet_get_default_subnets(context, share_network_id): 

5326 return _share_network_subnets_get_all_by_availability_zone_id( 

5327 context, share_network_id, availability_zone_id=None, 

5328 ) 

5329 

5330 

5331@require_context 

5332@context_manager.reader 

5333def share_network_subnet_get_all_by_share_server_id(context, share_server_id): 

5334 result = _share_network_subnet_get_query(context).filter( 

5335 models.ShareNetworkSubnet.share_servers.any( 

5336 id=share_server_id, 

5337 ) 

5338 ).all() 

5339 if not result: 

5340 raise exception.ShareNetworkSubnetNotFoundByShareServer( 

5341 share_server_id=share_server_id, 

5342 ) 

5343 

5344 return result 

5345 

5346################### 

5347 

5348 

5349def _share_network_subnet_metadata_get_query(context, share_network_subnet_id): 

5350 return model_query( 

5351 context, models.ShareNetworkSubnetMetadata, 

5352 read_deleted="no", 

5353 ).filter_by( 

5354 share_network_subnet_id=share_network_subnet_id, 

5355 ).options( 

5356 orm.joinedload(models.ShareNetworkSubnetMetadata.share_network_subnet), 

5357 ) 

5358 

5359 

5360@require_context 

5361@require_share_network_subnet_exists 

5362@context_manager.reader 

5363def share_network_subnet_metadata_get(context, share_network_subnet_id): 

5364 return _share_network_subnet_metadata_get(context, share_network_subnet_id) 

5365 

5366 

5367@require_context 

5368def _share_network_subnet_metadata_get(context, share_network_subnet_id): 

5369 rows = _share_network_subnet_metadata_get_query( 

5370 context, share_network_subnet_id, 

5371 ).all() 

5372 

5373 result = {} 

5374 for row in rows: 

5375 result[row['key']] = row['value'] 

5376 return result 

5377 

5378 

5379@require_context 

5380@require_share_network_subnet_exists 

5381@context_manager.writer 

5382def share_network_subnet_metadata_delete( 

5383 context, share_network_subnet_id, key, 

5384): 

5385 meta_ref = _share_network_subnet_metadata_get_item( 

5386 context, share_network_subnet_id, key, 

5387 ) 

5388 meta_ref.soft_delete(session=context.session) 

5389 

5390 

5391@require_context 

5392@require_share_network_subnet_exists 

5393@context_manager.writer 

5394def share_network_subnet_metadata_update( 

5395 context, share_network_subnet_id, metadata, delete, 

5396): 

5397 return _share_network_subnet_metadata_update( 

5398 context, share_network_subnet_id, metadata, delete, 

5399 ) 

5400 

5401 

5402@require_context 

5403@context_manager.writer 

5404def share_network_subnet_metadata_update_item( 

5405 context, share_network_subnet_id, item, 

5406): 

5407 return _share_network_subnet_metadata_update( 

5408 context, share_network_subnet_id, item, delete=False, 

5409 ) 

5410 

5411 

5412@require_context 

5413@context_manager.reader 

5414def share_network_subnet_metadata_get_item( 

5415 context, share_network_subnet_id, key, 

5416): 

5417 row = _share_network_subnet_metadata_get_item( 

5418 context, share_network_subnet_id, key, 

5419 ) 

5420 result = {row['key']: row['value']} 

5421 return result 

5422 

5423 

5424def _share_network_subnet_metadata_get_item( 

5425 context, share_network_subnet_id, key, 

5426): 

5427 result = _share_network_subnet_metadata_get_query( 

5428 context, share_network_subnet_id, 

5429 ).filter_by(key=key).first() 

5430 if not result: 5430 ↛ 5431line 5430 didn't jump to line 5431 because the condition on line 5430 was never true

5431 raise exception.MetadataItemNotFound 

5432 return result 

5433 

5434 

5435@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

5436def _share_network_subnet_metadata_update( 

5437 context, share_network_subnet_id, metadata, delete, 

5438): 

5439 delete = strutils.bool_from_string(delete) 

5440 if delete: 5440 ↛ 5441line 5440 didn't jump to line 5441 because the condition on line 5440 was never true

5441 original_metadata = _share_network_subnet_metadata_get( 

5442 context, share_network_subnet_id, 

5443 ) 

5444 for meta_key, meta_value in original_metadata.items(): 

5445 if meta_key not in metadata: 

5446 meta_ref = _share_network_subnet_metadata_get_item( 

5447 context, share_network_subnet_id, meta_key, 

5448 ) 

5449 meta_ref.soft_delete(session=context.session) 

5450 meta_ref = None 

5451 # Now update all existing items with new values, or create new meta 

5452 # objects. 

5453 for meta_key, meta_value in metadata.items(): 

5454 

5455 # update the value whether it exists or not. 

5456 item = {"value": meta_value} 

5457 meta_ref = _share_network_subnet_metadata_get_query( 

5458 context, share_network_subnet_id, 

5459 ).filter_by(key=meta_key).first() 

5460 if not meta_ref: 

5461 meta_ref = models.ShareNetworkSubnetMetadata() 

5462 item.update( 

5463 { 

5464 "key": meta_key, 

5465 "share_network_subnet_id": share_network_subnet_id, 

5466 } 

5467 ) 

5468 meta_ref.update(item) 

5469 meta_ref.save(session=context.session) 

5470 

5471 return metadata 

5472 

5473################################# 

5474 

5475 

5476def _share_server_get_query(context): 

5477 return model_query( 

5478 context, models.ShareServer, 

5479 ).options( 

5480 orm.joinedload(models.ShareServer.share_instances), 

5481 orm.joinedload(models.ShareServer.network_allocations), 

5482 orm.joinedload(models.ShareServer.share_network_subnets), 

5483 ) 

5484 

5485 

5486@require_context 

5487@context_manager.writer 

5488def share_server_create(context, values): 

5489 values = ensure_model_dict_has_id(values) 

5490 

5491 server_ref = models.ShareServer() 

5492 # updated_at is needed for judgement of automatic cleanup 

5493 server_ref.updated_at = timeutils.utcnow() 

5494 server_ref.update(values) 

5495 

5496 # If encryption_key_ref is present, create associated record 

5497 encryption_key_ref = values.get('encryption_key_ref') 

5498 if encryption_key_ref: 

5499 encryption_ref = models.EncryptionRef( 

5500 id=uuidutils.generate_uuid(), 

5501 share_server_id=server_ref['id'], 

5502 encryption_key_ref=encryption_key_ref, 

5503 project_id=context.project_id, 

5504 ) 

5505 server_ref.server_encryption_ref_entry = encryption_ref 

5506 

5507 server_ref.save(session=context.session) 

5508 

5509 # NOTE(u_glide): Do so to prevent errors with relationships 

5510 return _share_server_get(context, server_ref['id']) 

5511 

5512 

5513@require_context 

5514@context_manager.writer 

5515def share_server_delete(context, id): 

5516 server_ref = _share_server_get(context, id) 

5517 model_query( 

5518 context, models.ShareServerShareNetworkSubnetMapping, 

5519 ).filter_by( 

5520 share_server_id=id, 

5521 ).soft_delete() 

5522 _share_server_backend_details_delete(context, id) 

5523 server_ref.soft_delete(session=context.session, update_status=True) 

5524 

5525 # If encryption_key_ref is present, delete associated encryption ref entry 

5526 if server_ref.server_encryption_ref_entry: 5526 ↛ 5527line 5526 didn't jump to line 5527 because the condition on line 5526 was never true

5527 server_ref.server_encryption_ref_entry.soft_delete( 

5528 session=context.session) 

5529 

5530 

5531@require_context 

5532@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

5533@context_manager.writer 

5534def share_server_update(context, id, values): 

5535 server_ref = _share_server_get(context, id) 

5536 server_ref.update(values) 

5537 server_ref.save(session=context.session) 

5538 return server_ref 

5539 

5540 

5541@require_context 

5542@context_manager.reader 

5543def share_server_get(context, server_id): 

5544 return _share_server_get(context, server_id) 

5545 

5546 

5547@require_context 

5548def _share_server_get(context, server_id): 

5549 result = _share_server_get_query(context).filter_by(id=server_id).first() 

5550 if result is None: 

5551 raise exception.ShareServerNotFound(share_server_id=server_id) 

5552 return result 

5553 

5554 

5555@require_context 

5556@context_manager.reader 

5557def share_server_search_by_identifier(context, identifier): 

5558 

5559 identifier_field = models.ShareServer.identifier 

5560 

5561 # try if given identifier is a suffix of existing entry's identifier 

5562 result = (_share_server_get_query(context).filter( 

5563 identifier_field.like('%{}'.format(identifier))).all()) 

5564 

5565 if not result: 

5566 # repeat it with underscores instead of hyphens 

5567 result = (_share_server_get_query(context).filter( 

5568 identifier_field.like('%{}'.format( 

5569 identifier.replace("-", "_")))).all()) 

5570 

5571 if not result: 

5572 # repeat it with hypens instead of underscores 

5573 result = (_share_server_get_query(context).filter( 

5574 identifier_field.like('%{}'.format( 

5575 identifier.replace("_", "-")))).all()) 

5576 

5577 if not result: 

5578 # try if an existing identifier is a substring of given identifier 

5579 result = (_share_server_get_query(context).filter( 

5580 literal(identifier).contains(identifier_field)).all()) 

5581 

5582 if not result: 

5583 # repeat it with underscores instead of hyphens 

5584 result = (_share_server_get_query(context).filter( 

5585 literal(identifier.replace("-", "_")).contains( 

5586 identifier_field)).all()) 

5587 

5588 if not result: 

5589 # repeat it with hypens instead of underscores 

5590 result = (_share_server_get_query(context).filter( 

5591 literal(identifier.replace("_", "-")).contains( 

5592 identifier_field)).all()) 

5593 

5594 if not result: 

5595 raise exception.ShareServerNotFound(share_server_id=identifier) 

5596 

5597 return result 

5598 

5599 

5600@require_context 

5601@context_manager.reader 

5602def share_server_get_all_by_host_and_share_subnet_valid( 

5603 context, host, share_subnet_id, 

5604): 

5605 result = _share_server_get_query( 

5606 context, 

5607 ).filter_by( 

5608 host=host, 

5609 ).filter( 

5610 models.ShareServer.share_network_subnets.any(id=share_subnet_id) 

5611 ).filter( 

5612 models.ShareServer.status.in_( 

5613 (constants.STATUS_CREATING, constants.STATUS_ACTIVE), 

5614 ) 

5615 ).all() 

5616 

5617 if not result: 

5618 filters_description = ('share_network_subnet_id is ' 

5619 '"%(share_subnet_id)s", host is "%(host)s" and ' 

5620 'status in "%(status_cr)s" or ' 

5621 '"%(status_act)s"') % { 

5622 'share_subnet_id': share_subnet_id, 

5623 'host': host, 

5624 'status_cr': constants.STATUS_CREATING, 

5625 'status_act': constants.STATUS_ACTIVE, 

5626 } 

5627 raise exception.ShareServerNotFoundByFilters( 

5628 filters_description=filters_description, 

5629 ) 

5630 return result 

5631 

5632 

5633@require_context 

5634@context_manager.reader 

5635def share_server_get_all_by_host_and_or_share_subnet( 

5636 context, host=None, share_subnet_id=None, 

5637): 

5638 result = _share_server_get_query(context) 

5639 if host: 5639 ↛ 5641line 5639 didn't jump to line 5641 because the condition on line 5639 was always true

5640 result = result.filter_by(host=host) 

5641 result = result.filter( 

5642 models.ShareServer.share_network_subnets.any(id=share_subnet_id) 

5643 ).all() 

5644 

5645 if not result: 

5646 filters_description = ( 

5647 'share_network_subnet_id is "%(share_subnet_id)s" and host is ' 

5648 '"%(host)s".' 

5649 ) % { 

5650 'share_subnet_id': share_subnet_id, 

5651 'host': host, 

5652 } 

5653 raise exception.ShareServerNotFoundByFilters( 

5654 filters_description=filters_description, 

5655 ) 

5656 return result 

5657 

5658 

5659@require_context 

5660@context_manager.reader 

5661def share_server_get_all(context): 

5662 return _share_server_get_query(context).all() 

5663 

5664 

5665@require_context 

5666@context_manager.reader 

5667def share_server_get_all_with_filters(context, filters): 

5668 return _share_server_get_all_with_filters(context, filters) 

5669 

5670 

5671@require_context 

5672def _share_server_get_all_with_filters(context, filters): 

5673 query = _share_server_get_query(context) 

5674 

5675 if filters.get('host'): 

5676 query = query.filter_by(host=filters.get('host')) 

5677 if filters.get('status'): 

5678 query = query.filter_by(status=filters.get('status')) 

5679 if filters.get('source_share_server_id'): 

5680 query = query.filter_by( 

5681 source_share_server_id=filters.get('source_share_server_id')) 

5682 if filters.get('encryption_key_ref'): 5682 ↛ 5683line 5682 didn't jump to line 5683 because the condition on line 5682 was never true

5683 query = query.filter_by( 

5684 encryption_key_ref=filters.get('encryption_key_ref')) 

5685 if filters.get('identifier'): 5685 ↛ 5686line 5685 didn't jump to line 5686 because the condition on line 5685 was never true

5686 query = query.filter_by(identifier=filters.get('identifier')) 

5687 if filters.get('share_network_id'): 

5688 query = query.join( 

5689 models.ShareServerShareNetworkSubnetMapping, 

5690 models.ShareServerShareNetworkSubnetMapping.share_server_id == 

5691 models.ShareServer.id 

5692 ).join( 

5693 models.ShareNetworkSubnet, 

5694 models.ShareNetworkSubnet.id == 

5695 models.ShareServerShareNetworkSubnetMapping.share_network_subnet_id 

5696 ).filter( 

5697 models.ShareNetworkSubnet.share_network_id == 

5698 filters.get('share_network_id')) 

5699 return query.all() 

5700 

5701 

5702@require_context 

5703@context_manager.reader 

5704def share_server_get_all_by_host(context, host, filters=None): 

5705 if filters: 5705 ↛ 5706line 5705 didn't jump to line 5706 because the condition on line 5705 was never true

5706 filters.update({'host': host}) 

5707 else: 

5708 filters = {'host': host} 

5709 return _share_server_get_all_with_filters(context, filters=filters) 

5710 

5711 

5712@require_context 

5713@context_manager.reader 

5714def share_server_get_all_unused_deletable(context, host, updated_before): 

5715 valid_server_status = ( 

5716 constants.STATUS_INACTIVE, 

5717 constants.STATUS_ACTIVE, 

5718 constants.STATUS_ERROR, 

5719 ) 

5720 result = (_share_server_get_query(context) 

5721 .filter_by(is_auto_deletable=True) 

5722 .filter_by(host=host) 

5723 .filter(~models.ShareServer.share_groups.any()) 

5724 .filter(~models.ShareServer.share_instances.any()) 

5725 .filter(models.ShareServer.status.in_(valid_server_status)) 

5726 .filter(models.ShareServer.updated_at < updated_before).all()) 

5727 return result 

5728 

5729 

5730def _share_server_backend_details_get_item(context, share_server_id, key): 

5731 result = _share_server_backend_details_get_query( 

5732 context, share_server_id, 

5733 ).filter_by(key=key).first() 

5734 if not result: 

5735 raise exception.ShareServerBackendDetailsNotFound() 

5736 return result 

5737 

5738 

5739def _share_server_backend_details_get_query(context, share_server_id): 

5740 return (model_query( 

5741 context, models.ShareServerBackendDetails, 

5742 read_deleted="no"). 

5743 filter_by(share_server_id=share_server_id)) 

5744 

5745 

5746@require_context 

5747@context_manager.writer 

5748def share_server_backend_details_set(context, share_server_id, server_details): 

5749 _share_server_get(context, share_server_id) 

5750 

5751 for meta_key, meta_value in server_details.items(): 

5752 

5753 # update the value whether it exists or not 

5754 item = {"value": meta_value} 

5755 try: 

5756 meta_ref = _share_server_backend_details_get_item( 

5757 context, share_server_id, meta_key) 

5758 except exception.ShareServerBackendDetailsNotFound: 

5759 meta_ref = models.ShareServerBackendDetails() 

5760 item.update({"key": meta_key, "share_server_id": share_server_id}) 

5761 

5762 meta_ref.update(item) 

5763 meta_ref.save(session=context.session) 

5764 return server_details 

5765 

5766 

5767@require_context 

5768@context_manager.reader 

5769def share_server_backend_details_get_item(context, share_server_id, meta_key): 

5770 try: 

5771 meta_ref = _share_server_backend_details_get_item( 

5772 context, share_server_id, meta_key) 

5773 except exception.ShareServerBackendDetailsNotFound: 

5774 return None 

5775 return meta_ref.get('value') 

5776 

5777 

5778@require_context 

5779@context_manager.writer 

5780def share_server_backend_details_delete(context, share_server_id): 

5781 return _share_server_backend_details_delete(context, share_server_id) 

5782 

5783 

5784@require_context 

5785def _share_server_backend_details_delete(context, share_server_id): 

5786 share_server_details = model_query( 

5787 context, 

5788 models.ShareServerBackendDetails, 

5789 ).filter_by(share_server_id=share_server_id).all() 

5790 for item in share_server_details: 

5791 item.soft_delete(session=context.session) 

5792 

5793 

5794@require_context 

5795@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

5796@context_manager.writer 

5797def share_servers_update(context, share_server_ids, values): 

5798 result = model_query( 

5799 context, models.ShareServer, read_deleted="no", 

5800 ).filter( 

5801 models.ShareServer.id.in_(share_server_ids), 

5802 ).update(values, synchronize_session=False) 

5803 return result 

5804 

5805 

5806################### 

5807 

5808def _driver_private_data_query( 

5809 context, entity_id, key=None, read_deleted=False, 

5810): 

5811 query = model_query( 

5812 context, models.DriverPrivateData, 

5813 read_deleted=read_deleted, 

5814 ).filter_by( 

5815 entity_uuid=entity_id, 

5816 ) 

5817 

5818 if isinstance(key, list): 

5819 return query.filter(models.DriverPrivateData.key.in_(key)) 

5820 elif key is not None: 

5821 return query.filter_by(key=key) 

5822 

5823 return query 

5824 

5825 

5826@require_context 

5827@context_manager.reader 

5828def driver_private_data_get(context, entity_id, key=None, default=None): 

5829 query = _driver_private_data_query(context, entity_id, key) 

5830 

5831 if key is None or isinstance(key, list): 

5832 return {item.key: item.value for item in query.all()} 

5833 else: 

5834 result = query.first() 

5835 return result["value"] if result is not None else default 

5836 

5837 

5838@require_context 

5839@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

5840@context_manager.writer 

5841def driver_private_data_update( 

5842 context, entity_id, details, delete_existing=False, 

5843): 

5844 # NOTE(u_glide): following code modifies details dict, that's why we should 

5845 # copy it 

5846 new_details = copy.deepcopy(details) 

5847 

5848 # Process existing data 

5849 original_data = context.session.query(models.DriverPrivateData).filter_by( 

5850 entity_uuid=entity_id, 

5851 ).all() 

5852 

5853 for data_ref in original_data: 

5854 in_new_details = data_ref['key'] in new_details 

5855 

5856 if in_new_details: 

5857 new_value = str(new_details.pop(data_ref['key'])) 

5858 data_ref.update({ 

5859 "value": new_value, 

5860 "deleted": 0, 

5861 "deleted_at": None 

5862 }) 

5863 data_ref.save(session=context.session) 

5864 elif delete_existing and data_ref['deleted'] != 1: 

5865 data_ref.update({ 

5866 "deleted": 1, "deleted_at": timeutils.utcnow() 

5867 }) 

5868 data_ref.save(session=context.session) 

5869 

5870 # Add new data 

5871 for key, value in new_details.items(): 

5872 data_ref = models.DriverPrivateData() 

5873 data_ref.update({ 

5874 "entity_uuid": entity_id, 

5875 "key": key, 

5876 "value": str(value) 

5877 }) 

5878 data_ref.save(session=context.session) 

5879 

5880 return details 

5881 

5882 

5883@require_context 

5884@context_manager.writer 

5885def driver_private_data_delete(context, entity_id, key=None): 

5886 query = _driver_private_data_query(context, entity_id, key) 

5887 query.update({"deleted": 1, "deleted_at": timeutils.utcnow()}) 

5888 

5889 

5890################### 

5891 

5892 

5893@require_context 

5894@context_manager.writer 

5895def network_allocation_create(context, values): 

5896 values = ensure_model_dict_has_id(values) 

5897 alloc_ref = models.NetworkAllocation() 

5898 alloc_ref.update(values) 

5899 alloc_ref.save(session=context.session) 

5900 return alloc_ref 

5901 

5902 

5903@require_context 

5904@context_manager.writer 

5905def network_allocation_delete(context, id): 

5906 alloc_ref = _network_allocation_get(context, id) 

5907 alloc_ref.soft_delete(session=context.session) 

5908 

5909 

5910@require_context 

5911@context_manager.reader 

5912def network_allocation_get(context, id, read_deleted="no"): 

5913 return _network_allocation_get(context, id, read_deleted=read_deleted) 

5914 

5915 

5916@require_context 

5917def _network_allocation_get(context, id, read_deleted="no"): 

5918 result = model_query( 

5919 context, models.NetworkAllocation, 

5920 read_deleted=read_deleted, 

5921 ).filter_by(id=id).first() 

5922 if result is None: 

5923 raise exception.NotFound() 

5924 return result 

5925 

5926 

5927@require_context 

5928@context_manager.reader 

5929def network_allocations_get_by_ip_address(context, ip_address): 

5930 result = model_query( 

5931 context, models.NetworkAllocation, 

5932 ).filter_by(ip_address=ip_address).all() 

5933 return result or [] 

5934 

5935 

5936@require_context 

5937@context_manager.reader 

5938def network_allocations_get_for_share_server( 

5939 context, share_server_id, label=None, subnet_id=None, 

5940): 

5941 query = model_query( 

5942 context, models.NetworkAllocation, 

5943 ).filter_by( 

5944 share_server_id=share_server_id, 

5945 ) 

5946 if label: 

5947 if label == 'user': 

5948 query = query.filter(or_( 

5949 # NOTE(vponomaryov): we treat None as alias for 'user'. 

5950 models.NetworkAllocation.label == None, # noqa 

5951 models.NetworkAllocation.label == label, 

5952 )) 

5953 else: 

5954 query = query.filter(models.NetworkAllocation.label == label) 

5955 if subnet_id: 

5956 query = query.filter( 

5957 models.NetworkAllocation.share_network_subnet_id == subnet_id) 

5958 

5959 result = query.all() 

5960 return result 

5961 

5962 

5963@require_context 

5964@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

5965@context_manager.writer 

5966def network_allocation_update(context, id, values, read_deleted=None): 

5967 alloc_ref = _network_allocation_get(context, id, read_deleted=read_deleted) 

5968 alloc_ref.update(values) 

5969 alloc_ref.save(session=context.session) 

5970 return alloc_ref 

5971 

5972 

5973################### 

5974 

5975 

5976def _dict_with_specs(inst_type_query, specs_key='extra_specs'): 

5977 """Convert type query result to dict with extra_spec and rate_limit. 

5978 

5979 Takes a share [group] type query returned by sqlalchemy and returns it 

5980 as a dictionary, converting the extra/group specs entry from a list 

5981 of dicts: 

5982 

5983 'extra_specs' : [{'key': 'k1', 'value': 'v1', ...}, ...] 

5984 'group_specs' : [{'key': 'k1', 'value': 'v1', ...}, ...] 

5985 to a single dict: 

5986 'extra_specs' : {'k1': 'v1'} 

5987 'group_specs' : {'k1': 'v1'} 

5988 """ 

5989 inst_type_dict = dict(inst_type_query) 

5990 specs = {x['key']: x['value'] for x in inst_type_query[specs_key]} 

5991 inst_type_dict[specs_key] = specs 

5992 return inst_type_dict 

5993 

5994 

5995@require_admin_context 

5996@context_manager.writer 

5997def share_type_create(context, values, projects=None): 

5998 """Create a new share type. 

5999 

6000 In order to pass in extra specs, the values dict should contain a 

6001 'extra_specs' key/value pair: 

6002 {'extra_specs' : {'k1': 'v1', 'k2': 'v2', ...}} 

6003 """ 

6004 values = ensure_model_dict_has_id(values) 

6005 

6006 projects = projects or [] 

6007 

6008 try: 

6009 values['extra_specs'] = _metadata_refs( 

6010 values.get('extra_specs'), 

6011 models.ShareTypeExtraSpecs, 

6012 ) 

6013 share_type_ref = models.ShareTypes() 

6014 share_type_ref.update(values) 

6015 share_type_ref.save(session=context.session) 

6016 except db_exception.DBDuplicateEntry: 

6017 raise exception.ShareTypeExists(id=values['name']) 

6018 except Exception as e: 

6019 raise db_exception.DBError(e) 

6020 

6021 for project in set(projects): 

6022 access_ref = models.ShareTypeProjects() 

6023 access_ref.update( 

6024 {"share_type_id": share_type_ref.id, "project_id": project}, 

6025 ) 

6026 access_ref.save(session=context.session) 

6027 

6028 return share_type_ref 

6029 

6030 

6031def _share_type_get_query(context, read_deleted=None, expected_fields=None): 

6032 expected_fields = expected_fields or [] 

6033 query = model_query( 

6034 context, 

6035 models.ShareTypes, 

6036 read_deleted=read_deleted, 

6037 ).options(orm.joinedload(models.ShareTypes.extra_specs)) 

6038 

6039 if 'projects' in expected_fields: 6039 ↛ 6040line 6039 didn't jump to line 6040 because the condition on line 6039 was never true

6040 query = query.options(orm.joinedload(models.ShareTypes.projects)) 

6041 

6042 if not context.is_admin: 

6043 the_filter = [models.ShareTypes.is_public == true()] 

6044 projects_attr = getattr(models.ShareTypes, 'projects') 

6045 the_filter.extend([ 

6046 projects_attr.any(project_id=context.project_id) 

6047 ]) 

6048 query = query.filter(or_(*the_filter)) 

6049 

6050 return query 

6051 

6052 

6053@handle_db_data_error 

6054@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

6055def _share_type_update(context, type_id, values, is_group): 

6056 

6057 if values.get('name') is None: 

6058 values.pop('name', None) 

6059 

6060 if is_group: 6060 ↛ 6061line 6060 didn't jump to line 6061 because the condition on line 6060 was never true

6061 model = models.ShareGroupTypes 

6062 exists_exc = exception.ShareGroupTypeExists 

6063 exists_args = {'type_id': values.get('name')} 

6064 else: 

6065 model = models.ShareTypes 

6066 exists_exc = exception.ShareTypeExists 

6067 exists_args = {'id': values.get('name')} 

6068 

6069 query = model_query(context, model) 

6070 

6071 try: 

6072 result = query.filter_by(id=type_id).update(values) 

6073 except db_exception.DBDuplicateEntry: 

6074 # This exception only occurs if there's a non-deleted 

6075 # share/group type which has the same name as the name being 

6076 # updated. 

6077 raise exists_exc(**exists_args) 

6078 

6079 if not result: 

6080 if is_group: 6080 ↛ 6081line 6080 didn't jump to line 6081 because the condition on line 6080 was never true

6081 raise exception.ShareGroupTypeNotFound(type_id=type_id) 

6082 else: 

6083 raise exception.ShareTypeNotFound(share_type_id=type_id) 

6084 

6085 

6086@context_manager.writer 

6087def share_type_update(context, share_type_id, values): 

6088 _share_type_update(context, share_type_id, values, is_group=False) 

6089 

6090 

6091@require_context 

6092@context_manager.reader 

6093def share_type_get_all(context, inactive=False, filters=None): 

6094 """Returns a dict describing all share_types with name as key.""" 

6095 filters = filters or {} 

6096 

6097 read_deleted = "yes" if inactive else "no" 

6098 

6099 query = _share_type_get_query(context, read_deleted=read_deleted) 

6100 

6101 if 'is_public' in filters and filters['is_public'] is not None: 

6102 the_filter = [models. ShareTypes.is_public == filters['is_public']] 

6103 if filters['is_public'] and context.project_id is not None: 

6104 projects_attr = getattr(models. ShareTypes, 'projects') 

6105 the_filter.extend([ 

6106 projects_attr.any( 

6107 project_id=context.project_id, deleted=0) 

6108 ]) 

6109 if len(the_filter) > 1: 

6110 query = query.filter(or_(*the_filter)) 

6111 else: 

6112 query = query.filter(the_filter[0]) 

6113 

6114 rows = query.order_by("name").all() 

6115 

6116 result = {} 

6117 for row in rows: 

6118 result[row['name']] = _dict_with_specs(row) 

6119 

6120 return result 

6121 

6122 

6123def _share_type_get_id_from_share_type(context, id): 

6124 result = model_query( 

6125 context, models.ShareTypes, read_deleted="no", 

6126 ).filter_by(id=id).first() 

6127 if not result: 

6128 raise exception.ShareTypeNotFound(share_type_id=id) 

6129 return result['id'] 

6130 

6131 

6132def _share_type_get(context, id, inactive=False, expected_fields=None): 

6133 expected_fields = expected_fields or [] 

6134 read_deleted = "yes" if inactive else "no" 

6135 result = _share_type_get_query( 

6136 context, read_deleted, expected_fields, 

6137 ).filter_by(id=id).first() 

6138 

6139 if not result: 

6140 # The only way that id could be None is if the default share type is 

6141 # not configured and no other share type was specified. 

6142 if id is None: 

6143 raise exception.DefaultShareTypeNotConfigured() 

6144 raise exception.ShareTypeNotFound(share_type_id=id) 

6145 

6146 share_type = _dict_with_specs(result) 

6147 

6148 if 'projects' in expected_fields: 6148 ↛ 6149line 6148 didn't jump to line 6149 because the condition on line 6148 was never true

6149 share_type['projects'] = [p['project_id'] for p in result['projects']] 

6150 

6151 return share_type 

6152 

6153 

6154@require_context 

6155@context_manager.reader 

6156def share_type_get(context, id, inactive=False, expected_fields=None): 

6157 """Return a dict describing specific share_type.""" 

6158 return _share_type_get(context, id, 

6159 inactive=inactive, 

6160 expected_fields=expected_fields) 

6161 

6162 

6163def _share_type_get_by_name(context, name): 

6164 result = _share_type_get_query(context).filter_by(name=name).first() 

6165 

6166 if not result: 

6167 raise exception.ShareTypeNotFoundByName(share_type_name=name) 

6168 

6169 return _dict_with_specs(result) 

6170 

6171 

6172@require_context 

6173@context_manager.reader 

6174def share_type_get_by_name(context, name): 

6175 """Return a dict describing specific share_type.""" 

6176 return _share_type_get_by_name(context, name) 

6177 

6178 

6179@require_context 

6180@context_manager.reader 

6181def share_type_get_by_name_or_id(context, name_or_id): 

6182 """Return a dict describing specific share_type using its name or ID. 

6183 

6184 :returns: ShareType object or None if not found 

6185 """ 

6186 try: 

6187 return _share_type_get(context, name_or_id) 

6188 except exception.ShareTypeNotFound: 

6189 try: 

6190 return _share_type_get_by_name(context, name_or_id) 

6191 except exception.ShareTypeNotFoundByName: 

6192 return None 

6193 

6194 

6195@require_admin_context 

6196@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

6197@context_manager.writer 

6198def share_type_destroy(context, id): 

6199 _share_type_get(context, id) 

6200 shares_count = model_query( 

6201 context, 

6202 models.ShareInstance, 

6203 read_deleted="no", 

6204 ).filter_by(share_type_id=id).count() 

6205 share_group_types_count = model_query( 

6206 context, 

6207 models.ShareGroupTypeShareTypeMapping, 

6208 read_deleted="no", 

6209 ).filter_by(share_type_id=id).count() 

6210 if shares_count or share_group_types_count: 

6211 msg = ("Deletion of share type %(stype)s failed; it in use by " 

6212 "%(shares)d shares and %(gtypes)d share group types") 

6213 msg_args = {'stype': id, 

6214 'shares': shares_count, 

6215 'gtypes': share_group_types_count} 

6216 LOG.error(msg, msg_args) 

6217 raise exception.ShareTypeInUse(share_type_id=id) 

6218 

6219 model_query( 

6220 context, models.ShareTypeExtraSpecs, 

6221 ).filter_by( 

6222 share_type_id=id 

6223 ).soft_delete() 

6224 model_query( 

6225 context, models.ShareTypeProjects, 

6226 ).filter_by( 

6227 share_type_id=id, 

6228 ).soft_delete() 

6229 model_query( 

6230 context, models.ShareTypes, 

6231 ).filter_by( 

6232 id=id 

6233 ).soft_delete() 

6234 

6235 # NOTE(stephenfin): commit changes before we do anything with quotas 

6236 

6237 context.session.commit() 

6238 context.session.begin() 

6239 

6240 # Destroy any quotas, usages and reservations for the share type: 

6241 _quota_destroy_all_by_share_type(context, id) 

6242 

6243 

6244def _share_type_access_query(context): 

6245 return model_query(context, models.ShareTypeProjects, read_deleted="no") 

6246 

6247 

6248@require_admin_context 

6249@context_manager.reader 

6250def share_type_access_get_all(context, type_id): 

6251 share_type_id = _share_type_get_id_from_share_type(context, type_id) 

6252 return _share_type_access_query( 

6253 context, 

6254 ).filter_by(share_type_id=share_type_id).all() 

6255 

6256 

6257@require_admin_context 

6258@context_manager.writer 

6259def share_type_access_add(context, type_id, project_id): 

6260 """Add given tenant to the share type access list.""" 

6261 share_type_id = _share_type_get_id_from_share_type(context, type_id) 

6262 

6263 access_ref = models.ShareTypeProjects() 

6264 access_ref.update( 

6265 {"share_type_id": share_type_id, "project_id": project_id}, 

6266 ) 

6267 

6268 try: 

6269 access_ref.save(session=context.session) 

6270 except db_exception.DBDuplicateEntry: 

6271 raise exception.ShareTypeAccessExists( 

6272 share_type_id=type_id, project_id=project_id, 

6273 ) 

6274 return access_ref 

6275 

6276 

6277@require_admin_context 

6278@context_manager.writer 

6279def share_type_access_remove(context, type_id, project_id): 

6280 """Remove given tenant from the share type access list.""" 

6281 share_type_id = _share_type_get_id_from_share_type(context, type_id) 

6282 

6283 count = _share_type_access_query( 

6284 context, 

6285 ).filter_by( 

6286 share_type_id=share_type_id, 

6287 ).filter_by( 

6288 project_id=project_id, 

6289 ).soft_delete(synchronize_session=False) 

6290 

6291 if count == 0: 6291 ↛ 6292line 6291 didn't jump to line 6292 because the condition on line 6291 was never true

6292 raise exception.ShareTypeAccessNotFound( 

6293 share_type_id=type_id, project_id=project_id, 

6294 ) 

6295 

6296#################### 

6297 

6298 

6299def _share_type_extra_specs_query(context, share_type_id): 

6300 return model_query( 

6301 context, models.ShareTypeExtraSpecs, read_deleted="no", 

6302 ).filter_by( 

6303 share_type_id=share_type_id, 

6304 ).options(orm.joinedload(models.ShareTypeExtraSpecs.share_type)) 

6305 

6306 

6307@require_context 

6308@context_manager.reader 

6309def share_type_extra_specs_get(context, share_type_id): 

6310 rows = _share_type_extra_specs_query(context, share_type_id).all() 

6311 result = {} 

6312 for row in rows: 6312 ↛ 6313line 6312 didn't jump to line 6313 because the loop on line 6312 never started

6313 result[row['key']] = row['value'] 

6314 

6315 return result 

6316 

6317 

6318@require_context 

6319@context_manager.writer 

6320def share_type_extra_specs_delete(context, share_type_id, key): 

6321 _share_type_extra_specs_get_item(context, share_type_id, key) 

6322 _share_type_extra_specs_query( 

6323 context, share_type_id, 

6324 ).filter_by(key=key).soft_delete() 

6325 

6326 

6327def _share_type_extra_specs_get_item(context, share_type_id, key): 

6328 result = _share_type_extra_specs_query( 

6329 context, share_type_id, 

6330 ).filter_by( 

6331 key=key, 

6332 ).options( 

6333 orm.joinedload(models.ShareTypeExtraSpecs.share_type), 

6334 ).first() 

6335 

6336 if not result: 

6337 raise exception.ShareTypeExtraSpecsNotFound( 

6338 extra_specs_key=key, 

6339 share_type_id=share_type_id, 

6340 ) 

6341 

6342 return result 

6343 

6344 

6345@require_context 

6346@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

6347@context_manager.writer 

6348def share_type_extra_specs_update_or_create(context, share_type_id, specs): 

6349 spec_ref = None 

6350 for key, value in specs.items(): 

6351 try: 

6352 spec_ref = _share_type_extra_specs_get_item( 

6353 context, share_type_id, key, 

6354 ) 

6355 except exception.ShareTypeExtraSpecsNotFound: 

6356 spec_ref = models.ShareTypeExtraSpecs() 

6357 spec_ref.update( 

6358 { 

6359 "key": key, 

6360 "value": value, 

6361 "share_type_id": share_type_id, 

6362 "deleted": 0, 

6363 } 

6364 ) 

6365 spec_ref.save(session=context.session) 

6366 

6367 return specs 

6368 

6369#################### 

6370 

6371 

6372@context_manager.writer 

6373def ensure_availability_zone_exists(context, values, *, strict=True): 

6374 az_name = values.pop('availability_zone', None) 

6375 

6376 if not az_name: 

6377 if strict: 

6378 msg = _("Values dict should have 'availability_zone' field.") 

6379 raise ValueError(msg) 

6380 return 

6381 

6382 if uuidutils.is_uuid_like(az_name): 6382 ↛ 6383line 6382 didn't jump to line 6383 because the condition on line 6382 was never true

6383 az_ref = _availability_zone_get(context, az_name) 

6384 else: 

6385 az_ref = _availability_zone_create_if_not_exist(context, az_name) 

6386 

6387 values.update({'availability_zone_id': az_ref['id']}) 

6388 

6389 

6390@require_context 

6391@context_manager.reader 

6392def availability_zone_get(context, id_or_name): 

6393 return _availability_zone_get(context, id_or_name) 

6394 

6395 

6396@require_context 

6397def _availability_zone_get(context, id_or_name): 

6398 query = model_query(context, models.AvailabilityZone) 

6399 

6400 if uuidutils.is_uuid_like(id_or_name): 

6401 query = query.filter_by(id=id_or_name) 

6402 else: 

6403 query = query.filter_by(name=id_or_name) 

6404 

6405 result = query.first() 

6406 

6407 if not result: 

6408 raise exception.AvailabilityZoneNotFound(id=id_or_name) 

6409 

6410 return result 

6411 

6412 

6413@require_context 

6414@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

6415def _availability_zone_create_if_not_exist(context, name): 

6416 try: 

6417 return _availability_zone_get(context, name) 

6418 except exception.AvailabilityZoneNotFound: 

6419 az = models.AvailabilityZone() 

6420 az.update({'id': uuidutils.generate_uuid(), 'name': name}) 

6421 az.save(context.session) 

6422 return az 

6423 

6424 

6425@require_context 

6426@context_manager.reader 

6427def availability_zone_get_all(context): 

6428 enabled_services = model_query( 

6429 context, models.Service, 

6430 models.Service.availability_zone_id, 

6431 read_deleted="no" 

6432 ).filter_by(disabled=False).distinct() 

6433 

6434 return model_query( 

6435 context, models.AvailabilityZone, read_deleted="no", 

6436 ).filter( 

6437 models.AvailabilityZone.id.in_(enabled_services) 

6438 ).all() 

6439 

6440#################### 

6441 

6442 

6443@require_admin_context 

6444@context_manager.writer 

6445def purge_deleted_records(context, age_in_days): 

6446 """Purge soft-deleted records older than(and equal) age from tables.""" 

6447 

6448 if age_in_days < 0: 

6449 msg = _('Must supply a non-negative value for "age_in_days".') 

6450 LOG.error(msg) 

6451 raise exception.InvalidParameterValue(msg) 

6452 

6453 metadata = MetaData() 

6454 metadata.reflect(get_engine()) 

6455 tables = metadata.sorted_tables 

6456 if not tables: 6456 ↛ 6457line 6456 didn't jump to line 6457 because the condition on line 6456 was never true

6457 msg = 'No tables found, check database connection' 

6458 raise exception.InvalidResults(msg) 

6459 

6460 deleted_age = timeutils.utcnow() - datetime.timedelta(days=age_in_days) 

6461 

6462 # Deleting rows in share_network_security_service_association 

6463 # related to deleted network or security service 

6464 sec_assoc_to_delete = context.session.query( 

6465 models.ShareNetworkSecurityServiceAssociation).join( 

6466 models.ShareNetwork).join(models.SecurityService).filter( 

6467 or_(models.ShareNetwork.deleted_at <= deleted_age, 

6468 models.SecurityService.deleted_at <= deleted_age)).all() 

6469 

6470 for assoc in sec_assoc_to_delete: 

6471 with context.session.begin_nested(): 

6472 context.session.delete(assoc) 

6473 

6474 for table in reversed(tables): 

6475 if 'deleted' not in table.columns.keys(): 

6476 continue 

6477 

6478 try: 

6479 mds = [m for m in models.__dict__.values() if 

6480 (hasattr(m, '__tablename__') and 

6481 m.__tablename__ == str(table))] 

6482 if len(mds) > 0: 6482 ↛ 6474line 6482 didn't jump to line 6474 because the condition on line 6482 was always true

6483 # collect all soft-deleted records 

6484 with context.session.begin_nested(): 

6485 model = mds[0] 

6486 s_deleted_records = context.session.query( 

6487 model, 

6488 ).filter(model.deleted_at <= deleted_age) 

6489 deleted_count = 0 

6490 # delete records one by one, 

6491 # skip the records which has FK constraints 

6492 for record in s_deleted_records: 

6493 try: 

6494 with context.session.begin_nested(): 

6495 context.session.delete(record) 

6496 deleted_count += 1 

6497 except db_exc.DBError: 

6498 LOG.warning( 

6499 ("Deleting soft-deleted resource %s " 

6500 "failed, skipping."), record) 

6501 if deleted_count != 0: 

6502 LOG.info("Deleted %(count)s records in " 

6503 "table %(table)s.", 

6504 {'count': deleted_count, 'table': table}) 

6505 except db_exc.DBError: 

6506 LOG.warning("Querying table %s's soft-deleted records " 

6507 "failed, skipping.", table) 

6508 

6509 

6510#################### 

6511 

6512 

6513def _share_group_get(context, share_group_id): 

6514 result = model_query( 

6515 context, models.ShareGroup, project_only=True, read_deleted='no', 

6516 ).filter_by( 

6517 id=share_group_id, 

6518 ).options(orm.joinedload(models.ShareGroup.share_types)).first() 

6519 

6520 if not result: 

6521 raise exception.ShareGroupNotFound(share_group_id=share_group_id) 

6522 

6523 return result 

6524 

6525 

6526@require_context 

6527@context_manager.reader 

6528def share_group_get(context, share_group_id): 

6529 return _share_group_get(context, share_group_id) 

6530 

6531 

6532def _share_group_get_all(context, project_id=None, share_server_id=None, 

6533 host=None, detailed=True, filters=None, 

6534 sort_key=None, sort_dir=None): 

6535 sort_key = sort_key or 'created_at' 

6536 sort_dir = sort_dir or 'desc' 

6537 

6538 query = model_query( 

6539 context, models.ShareGroup, read_deleted='no') 

6540 

6541 # Apply filters 

6542 if not filters: 

6543 filters = {} 

6544 no_key = 'key_is_absent' 

6545 for k, v in filters.items(): 

6546 temp_k = k.rstrip('~') if k in constants.LIKE_FILTER else k 

6547 filter_attr = getattr(models.ShareGroup, temp_k, no_key) 

6548 

6549 if filter_attr == no_key: 6549 ↛ 6550line 6549 didn't jump to line 6550 because the condition on line 6549 was never true

6550 msg = _("Share groups cannot be filtered using '%s' key.") 

6551 raise exception.InvalidInput(reason=msg % k) 

6552 

6553 if k in constants.LIKE_FILTER: 

6554 query = query.filter(filter_attr.op('LIKE')(u'%' + v + u'%')) 

6555 else: 

6556 query = query.filter(filter_attr == v) 

6557 

6558 if project_id: 

6559 query = query.filter( 

6560 models.ShareGroup.project_id == project_id) 

6561 if host: 

6562 query = query.filter( 

6563 models.ShareGroup.host == host) 

6564 if share_server_id: 

6565 query = query.filter( 

6566 models.ShareGroup.share_server_id == share_server_id) 

6567 

6568 try: 

6569 query = apply_sorting(models.ShareGroup, query, sort_key, sort_dir) 

6570 except AttributeError: 

6571 msg = _("Wrong sorting key provided - '%s'.") % sort_key 

6572 raise exception.InvalidInput(reason=msg) 

6573 

6574 if detailed: 

6575 return query.options( 

6576 orm.joinedload(models.ShareGroup.share_types), 

6577 ).all() 

6578 

6579 query = query.with_entities( 

6580 models.ShareGroup.id, models.ShareGroup.name) 

6581 values = [] 

6582 for sg_id, sg_name in query.all(): 

6583 values.append({"id": sg_id, "name": sg_name}) 

6584 return values 

6585 

6586 

6587@require_admin_context 

6588@context_manager.reader 

6589def share_group_get_all(context, detailed=True, filters=None, sort_key=None, 

6590 sort_dir=None): 

6591 return _share_group_get_all( 

6592 context, detailed=detailed, filters=filters, 

6593 sort_key=sort_key, sort_dir=sort_dir) 

6594 

6595 

6596@require_admin_context 

6597@context_manager.reader 

6598def share_group_get_all_by_host(context, host, detailed=True): 

6599 return _share_group_get_all(context, host=host, detailed=detailed) 

6600 

6601 

6602@require_context 

6603@context_manager.reader 

6604def share_group_get_all_by_project(context, project_id, detailed=True, 

6605 filters=None, sort_key=None, sort_dir=None): 

6606 authorize_project_context(context, project_id) 

6607 return _share_group_get_all( 

6608 context, project_id=project_id, detailed=detailed, filters=filters, 

6609 sort_key=sort_key, sort_dir=sort_dir) 

6610 

6611 

6612@require_context 

6613@context_manager.reader 

6614def share_group_get_all_by_share_server(context, share_server_id, filters=None, 

6615 sort_key=None, sort_dir=None): 

6616 return _share_group_get_all( 

6617 context, share_server_id=share_server_id, filters=filters, 

6618 sort_key=sort_key, sort_dir=sort_dir) 

6619 

6620 

6621@require_context 

6622@context_manager.writer 

6623def share_group_create(context, values): 

6624 share_group = models.ShareGroup() 

6625 if not values.get('id'): 6625 ↛ 6628line 6625 didn't jump to line 6628 because the condition on line 6625 was always true

6626 values['id'] = uuidutils.generate_uuid() 

6627 

6628 mappings = [] 

6629 for item in values.get('share_types') or []: 

6630 mapping = models.ShareGroupShareTypeMapping() 

6631 mapping['id'] = uuidutils.generate_uuid() 

6632 mapping['share_type_id'] = item 

6633 mapping['share_group_id'] = values['id'] 

6634 mappings.append(mapping) 

6635 

6636 values['share_types'] = mappings 

6637 

6638 share_group.update(values) 

6639 context.session.add(share_group) 

6640 

6641 return _share_group_get(context, values['id']) 

6642 

6643 

6644@require_context 

6645@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

6646@context_manager.writer 

6647def share_group_update(context, share_group_id, values): 

6648 share_group_ref = _share_group_get( 

6649 context, share_group_id) 

6650 share_group_ref.update(values) 

6651 share_group_ref.save(session=context.session) 

6652 return share_group_ref 

6653 

6654 

6655@require_admin_context 

6656@context_manager.writer 

6657def share_group_destroy(context, share_group_id): 

6658 share_group_ref = _share_group_get(context, share_group_id) 

6659 share_group_ref.soft_delete(context.session) 

6660 context.session.query(models.ShareGroupShareTypeMapping).filter_by( 

6661 share_group_id=share_group_ref['id']).soft_delete() 

6662 

6663 

6664@require_context 

6665@context_manager.reader 

6666def count_shares_in_share_group(context, share_group_id): 

6667 return (model_query(context, models.Share, 

6668 project_only=True, read_deleted="no"). 

6669 filter_by(share_group_id=share_group_id). 

6670 count()) 

6671 

6672 

6673@require_context 

6674@context_manager.reader 

6675def get_all_shares_by_share_group(context, share_group_id): 

6676 return (model_query( 

6677 context, models.Share, 

6678 project_only=True, read_deleted="no"). 

6679 filter_by(share_group_id=share_group_id). 

6680 all()) 

6681 

6682 

6683@require_context 

6684def _count_share_groups(context, project_id, user_id=None, share_type_id=None): 

6685 query = model_query( 

6686 context, models.ShareGroup, 

6687 func.count(models.ShareGroup.id), 

6688 read_deleted="no", 

6689 ).filter_by(project_id=project_id) 

6690 if share_type_id: 

6691 query = query.join( 

6692 # models.ShareGroupShareTypeMapping, 

6693 models.ShareGroup.share_types, 

6694 ).filter_by(share_type_id=share_type_id) 

6695 elif user_id is not None: 

6696 query = query.filter_by(user_id=user_id) 

6697 return query.first()[0] 

6698 

6699 

6700@require_context 

6701def _count_share_group_snapshots( 

6702 context, project_id, user_id=None, share_type_id=None, 

6703): 

6704 query = model_query( 

6705 context, models.ShareGroupSnapshot, 

6706 func.count(models.ShareGroupSnapshot.id), 

6707 read_deleted="no", 

6708 ).filter_by(project_id=project_id) 

6709 if share_type_id: 

6710 query = query.join( 

6711 models.ShareGroupSnapshot.share_group, 

6712 ).join( 

6713 # models.ShareGroupShareTypeMapping, 

6714 models.ShareGroup.share_types, 

6715 ).filter_by(share_type_id=share_type_id) 

6716 elif user_id is not None: 

6717 query = query.filter_by(user_id=user_id) 

6718 return query.first()[0] 

6719 

6720 

6721@require_context 

6722def _share_replica_data_get_for_project( 

6723 context, project_id, user_id=None, share_type_id=None, 

6724): 

6725 query = model_query( 

6726 context, models.ShareInstance, 

6727 func.count(models.ShareInstance.id), 

6728 func.sum(models.Share.size), 

6729 read_deleted="no", 

6730 ).join( 

6731 models.Share, 

6732 models.ShareInstance.share_id == models.Share.id 

6733 ).filter( 

6734 models.Share.project_id == project_id 

6735 ).filter( 

6736 models.ShareInstance.replica_state.isnot(None) 

6737 ) 

6738 

6739 if share_type_id: 

6740 query = query.filter( 

6741 models.ShareInstance.share_type_id == share_type_id) 

6742 elif user_id: 

6743 query = query.filter(models.Share.user_id == user_id) 

6744 

6745 result = query.first() 

6746 return result[0] or 0, result[1] or 0 

6747 

6748 

6749@require_context 

6750def _count_encryption_keys_for_project( 

6751 context, project_id, user_id=None, 

6752): 

6753 return encryption_keys_get_count( 

6754 context, filters={'project_id': project_id} 

6755 ) 

6756 

6757 

6758@require_context 

6759@context_manager.reader 

6760def count_share_group_snapshots_in_share_group(context, share_group_id): 

6761 return model_query( 

6762 context, models.ShareGroupSnapshot, 

6763 project_only=True, read_deleted="no", 

6764 ).filter_by( 

6765 share_group_id=share_group_id, 

6766 ).count() 

6767 

6768 

6769@require_context 

6770@context_manager.reader 

6771def count_share_groups_in_share_network(context, share_network_id): 

6772 return (model_query( 

6773 context, models.ShareGroup, 

6774 project_only=True, read_deleted="no"). 

6775 filter_by(share_network_id=share_network_id). 

6776 count()) 

6777 

6778 

6779@require_context 

6780@context_manager.reader 

6781def count_share_group_snapshot_members_in_share( 

6782 context, share_id, include_deferred_deleting=True 

6783): 

6784 query = model_query( 

6785 context, models.ShareSnapshotInstance, 

6786 project_only=True, read_deleted="no", 

6787 ).join( 

6788 models.ShareInstance, 

6789 models.ShareInstance.id == ( 

6790 models.ShareSnapshotInstance.share_instance_id), 

6791 ) 

6792 

6793 if include_deferred_deleting: 6793 ↛ 6799line 6793 didn't jump to line 6799 because the condition on line 6793 was always true

6794 # consider deferred deleting states in query 

6795 return query.filter( 

6796 models.ShareInstance.share_id == share_id, 

6797 ).count() 

6798 

6799 deferred_delete_states = [ 

6800 constants.STATUS_DEFERRED_DELETING, 

6801 constants.STATUS_ERROR_DEFERRED_DELETING, 

6802 ] 

6803 return query.filter( 

6804 models.ShareInstance.share_id == share_id, 

6805 and_(models.ShareSnapshotInstance.status.not_in( 

6806 deferred_delete_states)) 

6807 ).count() 

6808 

6809 

6810#################### 

6811 

6812 

6813@require_context 

6814def _share_group_snapshot_get(context, share_group_snapshot_id): 

6815 result = model_query( 

6816 context, 

6817 models.ShareGroupSnapshot, 

6818 project_only=True, 

6819 read_deleted='no', 

6820 ).options( 

6821 orm.joinedload(models.ShareGroupSnapshot.share_group), 

6822 orm.joinedload(models.ShareGroupSnapshot.share_group_snapshot_members), 

6823 ).filter_by( 

6824 id=share_group_snapshot_id, 

6825 ).first() 

6826 

6827 if not result: 

6828 raise exception.ShareGroupSnapshotNotFound( 

6829 share_group_snapshot_id=share_group_snapshot_id) 

6830 

6831 return result 

6832 

6833 

6834def _share_group_snapshot_get_all( 

6835 context, 

6836 project_id=None, 

6837 detailed=True, 

6838 filters=None, 

6839 sort_key=None, 

6840 sort_dir=None, 

6841): 

6842 if not sort_key: 6842 ↛ 6844line 6842 didn't jump to line 6844 because the condition on line 6842 was always true

6843 sort_key = 'created_at' 

6844 if not sort_dir: 6844 ↛ 6847line 6844 didn't jump to line 6847 because the condition on line 6844 was always true

6845 sort_dir = 'desc' 

6846 

6847 query = model_query(context, models.ShareGroupSnapshot, read_deleted='no') 

6848 

6849 # Apply filters 

6850 if not filters: 6850 ↛ 6852line 6850 didn't jump to line 6852 because the condition on line 6850 was always true

6851 filters = {} 

6852 no_key = 'key_is_absent' 

6853 for k, v in filters.items(): 6853 ↛ 6854line 6853 didn't jump to line 6854 because the loop on line 6853 never started

6854 filter_attr = getattr(models.ShareGroupSnapshot, k, no_key) 

6855 if filter_attr == no_key: 

6856 msg = _("Share group snapshots cannot be filtered using '%s' key.") 

6857 raise exception.InvalidInput(reason=msg % k) 

6858 query = query.filter(filter_attr == v) 

6859 

6860 if project_id: 

6861 query = query.filter( 

6862 models.ShareGroupSnapshot.project_id == project_id) 

6863 

6864 try: 

6865 query = apply_sorting( 

6866 models.ShareGroupSnapshot, query, sort_key, sort_dir) 

6867 except AttributeError: 

6868 msg = _("Wrong sorting key provided - '%s'.") % sort_key 

6869 raise exception.InvalidInput(reason=msg) 

6870 

6871 if detailed: 

6872 return query.options( 

6873 orm.joinedload(models.ShareGroupSnapshot.share_group), 

6874 orm.joinedload( 

6875 models.ShareGroupSnapshot.share_group_snapshot_members 

6876 ), 

6877 ).all() 

6878 

6879 query = query.with_entities(models.ShareGroupSnapshot.id, 

6880 models.ShareGroupSnapshot.name) 

6881 values = [] 

6882 for sgs_id, sgs_name in query.all(): 

6883 values.append({"id": sgs_id, "name": sgs_name}) 

6884 return values 

6885 

6886 

6887@require_context 

6888@context_manager.reader 

6889def share_group_snapshot_get(context, share_group_snapshot_id): 

6890 return _share_group_snapshot_get(context, share_group_snapshot_id) 

6891 

6892 

6893@require_admin_context 

6894@context_manager.reader 

6895def share_group_snapshot_get_all( 

6896 context, detailed=True, filters=None, sort_key=None, sort_dir=None): 

6897 return _share_group_snapshot_get_all( 

6898 context, filters=filters, detailed=detailed, 

6899 sort_key=sort_key, sort_dir=sort_dir) 

6900 

6901 

6902@require_context 

6903@context_manager.reader 

6904def share_group_snapshot_get_all_by_project( 

6905 context, project_id, detailed=True, filters=None, 

6906 sort_key=None, sort_dir=None): 

6907 authorize_project_context(context, project_id) 

6908 return _share_group_snapshot_get_all( 

6909 context, project_id=project_id, filters=filters, detailed=detailed, 

6910 sort_key=sort_key, sort_dir=sort_dir, 

6911 ) 

6912 

6913 

6914@require_context 

6915@context_manager.writer 

6916def share_group_snapshot_create(context, values): 

6917 share_group_snapshot = models.ShareGroupSnapshot() 

6918 if not values.get('id'): 6918 ↛ 6921line 6918 didn't jump to line 6921 because the condition on line 6918 was always true

6919 values['id'] = uuidutils.generate_uuid() 

6920 

6921 share_group_snapshot.update(values) 

6922 context.session.add(share_group_snapshot) 

6923 

6924 return _share_group_snapshot_get(context, values['id']) 

6925 

6926 

6927@require_context 

6928@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

6929@context_manager.writer 

6930def share_group_snapshot_update(context, share_group_snapshot_id, values): 

6931 share_group_ref = _share_group_snapshot_get( 

6932 context, share_group_snapshot_id, 

6933 ) 

6934 share_group_ref.update(values) 

6935 share_group_ref.save(session=context.session) 

6936 return share_group_ref 

6937 

6938 

6939@require_admin_context 

6940@context_manager.writer 

6941def share_group_snapshot_destroy(context, share_group_snapshot_id): 

6942 share_group_snap_ref = _share_group_snapshot_get( 

6943 context, 

6944 share_group_snapshot_id, 

6945 ) 

6946 share_group_snap_ref.soft_delete(context.session) 

6947 context.session.query( 

6948 models.ShareSnapshotInstance 

6949 ).filter_by( 

6950 share_group_snapshot_id=share_group_snapshot_id 

6951 ).soft_delete() 

6952 

6953 

6954#################### 

6955 

6956 

6957@require_context 

6958@context_manager.reader 

6959def share_group_snapshot_members_get_all(context, share_group_snapshot_id): 

6960 query = model_query( 

6961 context, 

6962 models.ShareSnapshotInstance, 

6963 read_deleted='no', 

6964 ).filter_by(share_group_snapshot_id=share_group_snapshot_id) 

6965 return query.all() 

6966 

6967 

6968@require_context 

6969@context_manager.reader 

6970def share_group_snapshot_member_get(context, member_id): 

6971 return _share_group_snapshot_member_get(context, member_id) 

6972 

6973 

6974def _share_group_snapshot_member_get(context, member_id): 

6975 result = model_query( 

6976 context, 

6977 models.ShareSnapshotInstance, 

6978 project_only=True, 

6979 read_deleted='no', 

6980 ).filter_by(id=member_id).first() 

6981 if not result: 

6982 raise exception.ShareGroupSnapshotMemberNotFound(member_id=member_id) 

6983 return result 

6984 

6985 

6986@require_context 

6987@context_manager.writer 

6988def share_group_snapshot_member_create(context, values): 

6989 if not values.get('id'): 6989 ↛ 6992line 6989 didn't jump to line 6992 because the condition on line 6989 was always true

6990 values['id'] = uuidutils.generate_uuid() 

6991 

6992 _change_size_to_instance_size(values) 

6993 

6994 member = models.ShareSnapshotInstance() 

6995 member.update(values) 

6996 context.session.add(member) 

6997 

6998 return _share_group_snapshot_member_get(context, values['id']) 

6999 

7000 

7001@require_context 

7002@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

7003@context_manager.writer 

7004def share_group_snapshot_member_update(context, member_id, values): 

7005 _change_size_to_instance_size(values) 

7006 

7007 member = _share_group_snapshot_member_get(context, member_id) 

7008 member.update(values) 

7009 context.session.add(member) 

7010 

7011 return _share_group_snapshot_member_get(context, member_id) 

7012 

7013 

7014#################### 

7015 

7016 

7017@require_admin_context 

7018@context_manager.writer 

7019def share_group_type_create(context, values, projects=None): 

7020 """Create a new share group type. 

7021 

7022 In order to pass in group specs, the values dict should contain a 

7023 'group_specs' key/value pair: 

7024 {'group_specs' : {'k1': 'v1', 'k2': 'v2', ...}} 

7025 """ 

7026 values = ensure_model_dict_has_id(values) 

7027 

7028 projects = projects or [] 

7029 

7030 try: 

7031 values['group_specs'] = _metadata_refs( 

7032 values.get('group_specs'), models.ShareGroupTypeSpecs) 

7033 mappings = [] 

7034 for item in values.get('share_types', []): 

7035 share_type = share_type_get_by_name_or_id(context, item) 

7036 if not share_type: 

7037 raise exception.ShareTypeDoesNotExist(share_type=item) 

7038 mapping = models.ShareGroupTypeShareTypeMapping() 

7039 mapping['id'] = uuidutils.generate_uuid() 

7040 mapping['share_type_id'] = share_type['id'] 

7041 mapping['share_group_type_id'] = values['id'] 

7042 mappings.append(mapping) 

7043 

7044 values['share_types'] = mappings 

7045 share_group_type_ref = models.ShareGroupTypes() 

7046 share_group_type_ref.update(values) 

7047 share_group_type_ref.save(session=context.session) 

7048 except db_exception.DBDuplicateEntry: 

7049 raise exception.ShareGroupTypeExists(type_id=values['name']) 

7050 except exception.ShareTypeDoesNotExist: 

7051 raise 

7052 except Exception as e: 

7053 raise db_exception.DBError(e) 

7054 

7055 for project in set(projects): 

7056 access_ref = models.ShareGroupTypeProjects() 

7057 access_ref.update({"share_group_type_id": share_group_type_ref.id, 

7058 "project_id": project}) 

7059 access_ref.save(session=context.session) 

7060 

7061 return share_group_type_ref 

7062 

7063 

7064def _share_group_type_get_query( 

7065 context, 

7066 read_deleted=None, 

7067 expected_fields=None, 

7068): 

7069 expected_fields = expected_fields or [] 

7070 query = model_query( 

7071 context, 

7072 models.ShareGroupTypes, 

7073 read_deleted=read_deleted 

7074 ).options( 

7075 orm.joinedload(models.ShareGroupTypes.group_specs), 

7076 orm.joinedload(models.ShareGroupTypes.share_types), 

7077 ) 

7078 

7079 if 'projects' in expected_fields: 7079 ↛ 7080line 7079 didn't jump to line 7080 because the condition on line 7079 was never true

7080 query = query.options(orm.joinedload(models.ShareGroupTypes.projects)) 

7081 

7082 if not context.is_admin: 7082 ↛ 7083line 7082 didn't jump to line 7083 because the condition on line 7082 was never true

7083 the_filter = [models.ShareGroupTypes.is_public == true()] 

7084 projects_attr = getattr(models.ShareGroupTypes, 'projects') 

7085 the_filter.extend([ 

7086 projects_attr.any(project_id=context.project_id) 

7087 ]) 

7088 query = query.filter(or_(*the_filter)) 

7089 

7090 return query 

7091 

7092 

7093@require_context 

7094@context_manager.reader 

7095def share_group_type_get_all(context, inactive=False, filters=None): 

7096 """Returns a dict describing all share group types with name as key.""" 

7097 filters = filters or {} 

7098 read_deleted = "yes" if inactive else "no" 

7099 query = _share_group_type_get_query(context, read_deleted=read_deleted) 

7100 

7101 if 'is_public' in filters and filters['is_public'] is not None: 

7102 the_filter = [models.ShareGroupTypes.is_public == filters['is_public']] 

7103 if filters['is_public'] and context.project_id is not None: 

7104 projects_attr = getattr(models. ShareGroupTypes, 'projects') 

7105 the_filter.extend([ 

7106 projects_attr.any( 

7107 project_id=context.project_id, deleted=0) 

7108 ]) 

7109 if len(the_filter) > 1: 

7110 query = query.filter(or_(*the_filter)) 

7111 else: 

7112 query = query.filter(the_filter[0]) 

7113 

7114 rows = query.order_by("name").all() 

7115 

7116 result = {} 

7117 for row in rows: 

7118 result[row['name']] = _dict_with_specs(row, 'group_specs') 

7119 

7120 return result 

7121 

7122 

7123def _share_group_type_get_id_from_share_group_type_query(context, type_id): 

7124 return model_query( 

7125 context, 

7126 models.ShareGroupTypes, 

7127 read_deleted="no", 

7128 ).filter_by(id=type_id) 

7129 

7130 

7131def _share_group_type_get_id_from_share_group_type(context, type_id): 

7132 result = _share_group_type_get_id_from_share_group_type_query( 

7133 context, 

7134 type_id, 

7135 ).first() 

7136 if not result: 

7137 raise exception.ShareGroupTypeNotFound(type_id=type_id) 

7138 return result['id'] 

7139 

7140 

7141@require_context 

7142def _share_group_type_get( 

7143 context, 

7144 type_id, 

7145 inactive=False, 

7146 expected_fields=None, 

7147): 

7148 expected_fields = expected_fields or [] 

7149 read_deleted = "yes" if inactive else "no" 

7150 result = _share_group_type_get_query( 

7151 context, 

7152 read_deleted, 

7153 expected_fields, 

7154 ).filter_by(id=type_id).first() 

7155 

7156 if not result: 

7157 raise exception.ShareGroupTypeNotFound(type_id=type_id) 

7158 

7159 share_group_type = _dict_with_specs(result, 'group_specs') 

7160 

7161 if 'projects' in expected_fields: 7161 ↛ 7162line 7161 didn't jump to line 7162 because the condition on line 7161 was never true

7162 share_group_type['projects'] = [ 

7163 p['project_id'] for p in result['projects']] 

7164 

7165 return share_group_type 

7166 

7167 

7168@require_context 

7169@context_manager.reader 

7170def share_group_type_get(context, type_id, inactive=False, 

7171 expected_fields=None): 

7172 """Return a dict describing specific share group type.""" 

7173 return _share_group_type_get( 

7174 context, 

7175 type_id, 

7176 inactive=inactive, 

7177 expected_fields=expected_fields, 

7178 ) 

7179 

7180 

7181@require_context 

7182def _share_group_type_get_by_name(context, name): 

7183 result = model_query( 

7184 context, 

7185 models.ShareGroupTypes, 

7186 ).options( 

7187 orm.joinedload(models.ShareGroupTypes.group_specs), 

7188 orm.joinedload(models.ShareGroupTypes.share_types), 

7189 ).filter_by( 

7190 name=name, 

7191 ).first() 

7192 if not result: 

7193 raise exception.ShareGroupTypeNotFoundByName(type_name=name) 

7194 return _dict_with_specs(result, 'group_specs') 

7195 

7196 

7197@require_context 

7198@context_manager.reader 

7199def share_group_type_get_by_name(context, name): 

7200 """Return a dict describing specific share group type.""" 

7201 return _share_group_type_get_by_name(context, name) 

7202 

7203 

7204@require_admin_context 

7205@context_manager.writer 

7206def share_group_type_destroy(context, type_id): 

7207 _share_group_type_get(context, type_id) 

7208 results = model_query( 

7209 context, 

7210 models.ShareGroup, 

7211 read_deleted="no", 

7212 ).filter_by( 

7213 share_group_type_id=type_id, 

7214 ).count() 

7215 if results: 

7216 LOG.error('Share group type %s deletion failed, it in use.', 

7217 type_id) 

7218 raise exception.ShareGroupTypeInUse(type_id=type_id) 

7219 

7220 model_query( 

7221 context, 

7222 models.ShareGroupTypeSpecs, 

7223 ).filter_by( 

7224 share_group_type_id=type_id, 

7225 ).soft_delete() 

7226 

7227 model_query( 

7228 context, 

7229 models.ShareGroupTypeShareTypeMapping, 

7230 ).filter_by( 

7231 share_group_type_id=type_id, 

7232 ).soft_delete() 

7233 

7234 model_query( 

7235 context, 

7236 models.ShareGroupTypeProjects, 

7237 ).filter_by( 

7238 share_group_type_id=type_id, 

7239 ).soft_delete() 

7240 

7241 model_query( 

7242 context, 

7243 models.ShareGroupTypes, 

7244 ).filter_by( 

7245 id=type_id, 

7246 ).soft_delete() 

7247 

7248 

7249############################### 

7250 

7251 

7252def _share_group_type_access_query(context): 

7253 return model_query( 

7254 context, 

7255 models.ShareGroupTypeProjects, 

7256 read_deleted="no", 

7257 ) 

7258 

7259 

7260@require_admin_context 

7261@context_manager.reader 

7262def share_group_type_access_get_all(context, type_id): 

7263 share_group_type_id = _share_group_type_get_id_from_share_group_type( 

7264 context, type_id) 

7265 return _share_group_type_access_query(context).filter_by( 

7266 share_group_type_id=share_group_type_id, 

7267 ).all() 

7268 

7269 

7270@require_admin_context 

7271@context_manager.writer 

7272def share_group_type_access_add(context, type_id, project_id): 

7273 """Add given tenant to the share group type access list.""" 

7274 share_group_type_id = _share_group_type_get_id_from_share_group_type( 

7275 context, type_id) 

7276 access_ref = models.ShareGroupTypeProjects() 

7277 access_ref.update({"share_group_type_id": share_group_type_id, 

7278 "project_id": project_id}) 

7279 try: 

7280 access_ref.save(session=context.session) 

7281 except db_exception.DBDuplicateEntry: 

7282 raise exception.ShareGroupTypeAccessExists( 

7283 type_id=share_group_type_id, project_id=project_id) 

7284 return access_ref 

7285 

7286 

7287@require_admin_context 

7288@context_manager.writer 

7289def share_group_type_access_remove(context, type_id, project_id): 

7290 """Remove given tenant from the share group type access list.""" 

7291 share_group_type_id = _share_group_type_get_id_from_share_group_type( 

7292 context, type_id) 

7293 count = _share_group_type_access_query(context).filter_by( 

7294 share_group_type_id=share_group_type_id, 

7295 ).filter_by( 

7296 project_id=project_id, 

7297 ).soft_delete( 

7298 synchronize_session=False, 

7299 ) 

7300 if count == 0: 7300 ↛ 7301line 7300 didn't jump to line 7301 because the condition on line 7300 was never true

7301 raise exception.ShareGroupTypeAccessNotFound( 

7302 type_id=share_group_type_id, project_id=project_id) 

7303 

7304 

7305############################### 

7306 

7307 

7308def _share_group_type_specs_query(context, type_id): 

7309 return model_query( 

7310 context, 

7311 models.ShareGroupTypeSpecs, 

7312 read_deleted="no" 

7313 ).filter_by( 

7314 share_group_type_id=type_id, 

7315 ).options( 

7316 orm.joinedload(models.ShareGroupTypeSpecs.share_group_type), 

7317 ) 

7318 

7319 

7320@require_context 

7321@context_manager.reader 

7322def share_group_type_specs_get(context, type_id): 

7323 rows = _share_group_type_specs_query(context, type_id).all() 

7324 result = {} 

7325 for row in rows: 7325 ↛ 7326line 7325 didn't jump to line 7326 because the loop on line 7325 never started

7326 result[row['key']] = row['value'] 

7327 return result 

7328 

7329 

7330@require_context 

7331@context_manager.writer 

7332def share_group_type_specs_delete(context, type_id, key): 

7333 _share_group_type_specs_get_item(context, type_id, key) 

7334 _share_group_type_specs_query( 

7335 context, 

7336 type_id, 

7337 ).filter_by( 

7338 key=key, 

7339 ).soft_delete() 

7340 

7341 

7342@require_context 

7343def _share_group_type_specs_get_item(context, type_id, key): 

7344 result = _share_group_type_specs_query( 

7345 context, 

7346 type_id, 

7347 ).filter_by( 

7348 key=key, 

7349 ).options( 

7350 orm.joinedload(models.ShareGroupTypeSpecs.share_group_type), 

7351 ).first() 

7352 

7353 if not result: 

7354 raise exception.ShareGroupTypeSpecsNotFound( 

7355 specs_key=key, type_id=type_id) 

7356 

7357 return result 

7358 

7359 

7360@require_context 

7361@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

7362@context_manager.writer 

7363def share_group_type_specs_update_or_create(context, type_id, specs): 

7364 spec_ref = None 

7365 for key, value in specs.items(): 

7366 try: 

7367 spec_ref = _share_group_type_specs_get_item( 

7368 context, 

7369 type_id, 

7370 key, 

7371 ) 

7372 except exception.ShareGroupTypeSpecsNotFound: 

7373 spec_ref = models.ShareGroupTypeSpecs() 

7374 spec_ref.update({"key": key, "value": value, 

7375 "share_group_type_id": type_id, "deleted": 0}) 

7376 spec_ref.save(session=context.session) 

7377 

7378 return specs 

7379 

7380 

7381############################### 

7382 

7383 

7384@require_context 

7385def _message_get(context, message_id): 

7386 query = model_query(context, 

7387 models.Message, 

7388 read_deleted="no", 

7389 project_only="yes") 

7390 result = query.filter_by(id=message_id).first() 

7391 if not result: 

7392 raise exception.MessageNotFound(message_id=message_id) 

7393 return result 

7394 

7395 

7396@require_context 

7397@context_manager.reader 

7398def message_get(context, message_id): 

7399 return _message_get(context, message_id) 

7400 

7401 

7402@require_context 

7403@context_manager.reader 

7404def message_get_all(context, filters=None, limit=None, offset=None, 

7405 sort_key='created_at', sort_dir='desc'): 

7406 """Retrieves all messages. 

7407 

7408 If no sort parameters are specified then the returned messages are 

7409 sorted by the 'created_at' key in descending order. 

7410 

7411 :param context: context to query under 

7412 :param limit: maximum number of items to return 

7413 :param offset: the number of items to skip from the marker or from the 

7414 first element. 

7415 :param sort_key: attributes by which results should be sorted. 

7416 :param sort_dir: directions in which results should be sorted. 

7417 :param filters: dictionary of filters; values that are in lists, tuples, 

7418 or sets cause an 'IN' operation, while exact matching 

7419 is used for other values, see exact_filter function for 

7420 more information 

7421 :returns: list of matching messages 

7422 """ 

7423 messages = models.Message 

7424 

7425 query = model_query(context, 

7426 messages, 

7427 read_deleted="no", 

7428 project_only="yes") 

7429 

7430 legal_filter_keys = ('request_id', 'resource_type', 'resource_id', 

7431 'action_id', 'detail_id', 'message_level', 

7432 'created_since', 'created_before') 

7433 

7434 if not filters: 

7435 filters = {} 

7436 

7437 query = exact_filter(query, messages, filters, legal_filter_keys) 

7438 

7439 query = utils.paginate_query(query, messages, limit, 

7440 sort_key=sort_key, 

7441 sort_dir=sort_dir, 

7442 offset=offset) 

7443 

7444 return query.all() 

7445 

7446 

7447@require_context 

7448@context_manager.writer 

7449def message_create(context, message_values): 

7450 values = copy.deepcopy(message_values) 

7451 message_ref = models.Message() 

7452 if not values.get('id'): 7452 ↛ 7454line 7452 didn't jump to line 7454 because the condition on line 7452 was always true

7453 values['id'] = uuidutils.generate_uuid() 

7454 message_ref.update(values) 

7455 

7456 context.session.add(message_ref) 

7457 

7458 return _message_get(context, message_ref['id']) 

7459 

7460 

7461@require_context 

7462@context_manager.writer 

7463def message_destroy(context, message): 

7464 model_query( 

7465 context, models.Message, 

7466 ).filter_by(id=message.get('id')).soft_delete() 

7467 

7468 

7469@require_admin_context 

7470@context_manager.writer 

7471def cleanup_expired_messages(context): 

7472 now = timeutils.utcnow() 

7473 return context.session.query( 

7474 models.Message 

7475 ).filter( 

7476 models.Message.expires_at < now 

7477 ).delete() 

7478 

7479 

7480############################### 

7481 

7482 

7483@require_context 

7484@context_manager.reader 

7485def backend_info_get(context, host): 

7486 """Get hash info for given host.""" 

7487 result = _backend_info_query(context, host) 

7488 return result 

7489 

7490 

7491@require_context 

7492@context_manager.writer 

7493def backend_info_create(context, host, value): 

7494 info_ref = models.BackendInfo() 

7495 info_ref.update({"host": host, "info_hash": value}) 

7496 info_ref.save(context.session) 

7497 return info_ref 

7498 

7499 

7500@require_context 

7501@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

7502@context_manager.writer 

7503def backend_info_update(context, host, value=None, delete_existing=False): 

7504 """Remove backend info for host name.""" 

7505 info_ref = _backend_info_query(context, host) 

7506 if info_ref: 

7507 if value: 

7508 info_ref.update({"info_hash": value}) 

7509 elif delete_existing and info_ref['deleted'] != 1: 7509 ↛ 7514line 7509 didn't jump to line 7514 because the condition on line 7509 was always true

7510 info_ref.update({"deleted": 1, "deleted_at": timeutils.utcnow()}) 

7511 else: 

7512 info_ref = models.BackendInfo() 

7513 info_ref.update({"host": host, "info_hash": value}) 

7514 info_ref.save(context.session) 

7515 return info_ref 

7516 

7517 

7518def _backend_info_query(context, host, read_deleted=False): 

7519 result = model_query( 

7520 context, 

7521 models.BackendInfo, 

7522 read_deleted=read_deleted, 

7523 ).filter_by( 

7524 host=host, 

7525 ).first() 

7526 

7527 return result 

7528 

7529################### 

7530 

7531 

7532def _async_operation_data_query( 

7533 context, entity_id, key=None, read_deleted=False, 

7534): 

7535 query = model_query( 

7536 context, models.AsynchronousOperationData, 

7537 read_deleted=read_deleted, 

7538 ).filter_by( 

7539 entity_uuid=entity_id, 

7540 ) 

7541 

7542 if isinstance(key, list): 

7543 return query.filter(models.AsynchronousOperationData.key.in_(key)) 

7544 elif key is not None: 

7545 return query.filter_by(key=key) 

7546 

7547 return query 

7548 

7549 

7550@require_context 

7551@context_manager.reader 

7552def async_operation_data_get(context, entity_id, key=None, default=None): 

7553 query = _async_operation_data_query(context, entity_id, key) 

7554 

7555 if key is None or isinstance(key, list): 

7556 return {item.key: item.value for item in query.all()} 

7557 else: 

7558 result = query.first() 

7559 return result["value"] if result is not None else default 

7560 

7561 

7562@require_context 

7563@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

7564@context_manager.writer 

7565def async_operation_data_update( 

7566 context, entity_id, details, delete_existing=False, 

7567): 

7568 new_details = copy.deepcopy(details) 

7569 

7570 # Process existing data 

7571 original_data = context.session.query( 

7572 models.AsynchronousOperationData).filter_by( 

7573 entity_uuid=entity_id, 

7574 ).all() 

7575 

7576 for data_ref in original_data: 

7577 in_new_details = data_ref['key'] in new_details 

7578 

7579 if in_new_details: 

7580 new_value = str(new_details.pop(data_ref['key'])) 

7581 data_ref.update({ 

7582 "value": new_value, 

7583 "deleted": 0, 

7584 "deleted_at": None 

7585 }) 

7586 data_ref.save(session=context.session) 

7587 elif delete_existing and data_ref['deleted'] != 1: 

7588 data_ref.update({ 

7589 "deleted": 1, "deleted_at": timeutils.utcnow() 

7590 }) 

7591 data_ref.save(session=context.session) 

7592 

7593 # Add new data 

7594 for key, value in new_details.items(): 

7595 data_ref = models.AsynchronousOperationData() 

7596 data_ref.update({ 

7597 "entity_uuid": entity_id, 

7598 "key": key, 

7599 "value": str(value) 

7600 }) 

7601 data_ref.save(session=context.session) 

7602 

7603 return details 

7604 

7605 

7606@require_context 

7607@context_manager.writer 

7608def async_operation_data_delete(context, entity_id, key=None): 

7609 query = _async_operation_data_query(context, entity_id, key) 

7610 query.update({"deleted": 1, "deleted_at": timeutils.utcnow()}) 

7611 

7612 

7613@require_context 

7614@require_availability_zone_exists(strict=True) 

7615@context_manager.writer 

7616def share_backup_create(context, share_id, values): 

7617 if not values.get('id'): 

7618 values['id'] = uuidutils.generate_uuid() 

7619 values.update({'share_id': share_id}) 

7620 

7621 share_backup_ref = models.ShareBackup() 

7622 share_backup_ref.update(values) 

7623 share_backup_ref.save(session=context.session) 

7624 return share_backup_get(context, share_backup_ref['id']) 

7625 

7626 

7627@require_context 

7628@context_manager.reader 

7629def share_backup_get(context, share_backup_id): 

7630 result = model_query( 

7631 context, models.ShareBackup, project_only=True, read_deleted="no" 

7632 ).filter_by( 

7633 id=share_backup_id, 

7634 ).first() 

7635 if result is None: 

7636 raise exception.ShareBackupNotFound(backup_id=share_backup_id) 

7637 

7638 return result 

7639 

7640 

7641@require_context 

7642@context_manager.reader 

7643def share_backups_get_all(context, filters=None, 

7644 limit=None, offset=None, 

7645 sort_key=None, sort_dir=None): 

7646 project_id = filters.pop('project_id', None) if filters else None 

7647 query = _share_backups_get_with_filters( 

7648 context, 

7649 project_id=project_id, 

7650 filters=filters, limit=limit, offset=offset, 

7651 sort_key=sort_key, sort_dir=sort_dir) 

7652 

7653 return query 

7654 

7655 

7656def _share_backups_get_with_filters(context, project_id=None, filters=None, 

7657 limit=None, offset=None, 

7658 sort_key=None, sort_dir=None): 

7659 """Retrieves all backups. 

7660 

7661 If no sorting parameters are specified then returned backups are sorted 

7662 by the 'created_at' key and desc order. 

7663 

7664 :param context: context to query under 

7665 :param filters: dictionary of filters 

7666 :param limit: maximum number of items to return 

7667 :param sort_key: attribute by which results should be sorted,default is 

7668 created_at 

7669 :param sort_dir: direction in which results should be sorted 

7670 :returns: list of matching backups 

7671 """ 

7672 # Init data 

7673 sort_key = sort_key or 'created_at' 

7674 sort_dir = sort_dir or 'desc' 

7675 filters = copy.deepcopy(filters) if filters else {} 

7676 query = model_query(context, models.ShareBackup) 

7677 

7678 if project_id: 7678 ↛ 7679line 7678 didn't jump to line 7679 because the condition on line 7678 was never true

7679 query = query.filter_by(project_id=project_id) 

7680 

7681 legal_filter_keys = ('display_name', 'display_name~', 

7682 'display_description', 'display_description~', 

7683 'id', 'share_id', 'host', 'topic', 'status') 

7684 query = exact_filter(query, models.ShareBackup, 

7685 filters, legal_filter_keys) 

7686 

7687 query = apply_sorting(models.ShareBackup, query, sort_key, sort_dir) 

7688 

7689 if limit is not None: 7689 ↛ 7690line 7689 didn't jump to line 7690 because the condition on line 7689 was never true

7690 query = query.limit(limit) 

7691 

7692 if offset: 7692 ↛ 7693line 7692 didn't jump to line 7693 because the condition on line 7692 was never true

7693 query = query.offset(offset) 

7694 

7695 return query.all() 

7696 

7697 

7698@require_admin_context 

7699@context_manager.reader 

7700def _backup_data_get_for_project(context, project_id, user_id): 

7701 query = model_query(context, models.ShareBackup, 

7702 func.count(models.ShareBackup.id), 

7703 func.sum(models.ShareBackup.size), 

7704 read_deleted="no").\ 

7705 filter_by(project_id=project_id) 

7706 

7707 if user_id: 7707 ↛ 7708line 7707 didn't jump to line 7708 because the condition on line 7707 was never true

7708 result = query.filter_by(user_id=user_id).first() 

7709 else: 

7710 result = query.first() 

7711 

7712 return (result[0] or 0, result[1] or 0) 

7713 

7714 

7715@require_context 

7716@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

7717@require_availability_zone_exists(strict=False) 

7718@context_manager.writer 

7719def share_backup_update(context, backup_id, values): 

7720 backup_ref = share_backup_get(context, backup_id) 

7721 backup_ref.update(values) 

7722 backup_ref.save(session=context.session) 

7723 return backup_ref 

7724 

7725 

7726@require_context 

7727@context_manager.writer 

7728def share_backup_delete(context, backup_id): 

7729 backup_ref = share_backup_get(context, backup_id) 

7730 backup_ref.soft_delete(session=context.session, update_status=True) 

7731 

7732############################### 

7733 

7734 

7735@require_context 

7736def _resource_lock_get(context, lock_id): 

7737 query = model_query(context, 

7738 models.ResourceLock, 

7739 read_deleted="no", 

7740 project_only="yes") 

7741 result = query.filter_by(id=lock_id).first() 

7742 if not result: 

7743 raise exception.ResourceLockNotFound(lock_id=lock_id) 

7744 return result 

7745 

7746 

7747@require_context 

7748@context_manager.writer 

7749def resource_lock_create(context, kwargs): 

7750 """Create a resource lock.""" 

7751 values = copy.deepcopy(kwargs) 

7752 lock_ref = models.ResourceLock() 

7753 if not values.get('id'): 7753 ↛ 7755line 7753 didn't jump to line 7755 because the condition on line 7753 was always true

7754 values['id'] = uuidutils.generate_uuid() 

7755 lock_ref.update(values) 

7756 

7757 context.session.add(lock_ref) 

7758 

7759 return _resource_lock_get(context, lock_ref['id']) 

7760 

7761 

7762@require_context 

7763@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True) 

7764@context_manager.writer 

7765def resource_lock_update(context, lock_id, kwargs): 

7766 """Update a resource lock.""" 

7767 lock_ref = _resource_lock_get(context, lock_id) 

7768 lock_ref.update(kwargs) 

7769 lock_ref.save(session=context.session) 

7770 return lock_ref 

7771 

7772 

7773@require_context 

7774@context_manager.writer 

7775def resource_lock_delete(context, lock_id): 

7776 """Delete a resource lock.""" 

7777 lock_ref = _resource_lock_get(context, lock_id) 

7778 lock_ref.soft_delete(session=context.session) 

7779 

7780 

7781@require_context 

7782@context_manager.reader 

7783def resource_lock_get(context, lock_id): 

7784 """Retrieve a resource lock.""" 

7785 return _resource_lock_get(context, lock_id) 

7786 

7787 

7788@require_context 

7789@context_manager.reader 

7790def resource_lock_get_all(context, filters=None, limit=None, offset=None, 

7791 sort_key='created_at', sort_dir='desc', 

7792 show_count=False): 

7793 """Retrieve all resource locks. 

7794 

7795 If no sort parameters are specified then the returned locks are 

7796 sorted by the 'created_at' key in descending order. 

7797 

7798 :param context: context to query under 

7799 :param limit: maximum number of items to return 

7800 :param offset: the number of items to skip from the marker or from the 

7801 first element. 

7802 :param sort_key: attributes by which results should be sorted. 

7803 :param sort_dir: directions in which results should be sorted. 

7804 :param filters: dictionary of filters; values that are in lists, tuples, 

7805 or sets cause an 'IN' operation, while exact matching 

7806 is used for other values, see exact_filter function for 

7807 more information 

7808 :returns: list of matching resource locks 

7809 """ 

7810 locks = models.ResourceLock 

7811 

7812 # add policy check to allow: all_projects, project_id filters 

7813 filters = filters or {} 

7814 

7815 query = model_query(context, locks, read_deleted="no") 

7816 

7817 project_id = filters.get('project_id') 

7818 all_projects = filters.get('all_projects') or filters.get('all_tenants') 

7819 if project_id is None and not all_projects: 

7820 filters['project_id'] = context.project_id 

7821 

7822 legal_filter_keys = ('id', 'user_id', 'resource_id', 'resource_type', 

7823 'lock_context', 'resource_action', 'created_since', 

7824 'created_before', 'lock_reason', 'lock_reason~', 

7825 'project_id') 

7826 

7827 query = exact_filter(query, locks, filters, legal_filter_keys) 

7828 

7829 count = query.count() if show_count else None 

7830 

7831 query = utils.paginate_query(query, locks, limit, 

7832 sort_key=sort_key, 

7833 sort_dir=sort_dir, 

7834 offset=offset) 

7835 

7836 return query.all(), count 

7837 

7838############################### 

7839 

7840 

7841@require_context 

7842@context_manager.reader 

7843def encryption_keys_get_count(context, filters=None): 

7844 if filters: 

7845 project_id = filters.get('project_id') 

7846 else: 

7847 project_id = context.project_id 

7848 

7849 query = model_query( 

7850 context, models.EncryptionRef, read_deleted="no" 

7851 ).filter_by( 

7852 project_id=project_id, 

7853 ) 

7854 

7855 return query.count() 

7856 

7857 

7858@require_context 

7859@context_manager.reader 

7860def encryption_keys_get_all(context, filters=None): 

7861 if filters: 7861 ↛ 7864line 7861 didn't jump to line 7864 because the condition on line 7861 was always true

7862 project_id = filters.get('project_id') 

7863 else: 

7864 project_id = context.project_id 

7865 

7866 query = model_query( 

7867 context, models.EncryptionRef, read_deleted="no" 

7868 ).filter_by( 

7869 project_id=project_id, 

7870 ) 

7871 

7872 encryption_key_ref = filters.get('encryption_key_ref') 

7873 if encryption_key_ref: 7873 ↛ 7876line 7873 didn't jump to line 7876 because the condition on line 7873 was always true

7874 query = query.filter_by(encryption_key_ref=encryption_key_ref) 

7875 

7876 return query.all()