"Fossies" - the Fresh Open Source Software Archive

Member "manila-8.1.4/manila/db/sqlalchemy/api.py" (19 Nov 2020, 179746 Bytes) of package /linux/misc/openstack/manila-8.1.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "api.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 8.1.3_vs_8.1.4.

    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 
   21 import copy
   22 import datetime
   23 from functools import wraps
   24 import ipaddress
   25 import sys
   26 import warnings
   27 
   28 # NOTE(uglide): Required to override default oslo_db Query class
   29 import manila.db.sqlalchemy.query  # noqa
   30 
   31 from oslo_config import cfg
   32 from oslo_db import api as oslo_db_api
   33 from oslo_db import exception as db_exc
   34 from oslo_db import exception as db_exception
   35 from oslo_db import options as db_options
   36 from oslo_db.sqlalchemy import session
   37 from oslo_db.sqlalchemy import utils as db_utils
   38 from oslo_log import log
   39 from oslo_utils import excutils
   40 from oslo_utils import timeutils
   41 from oslo_utils import uuidutils
   42 import six
   43 from sqlalchemy import MetaData
   44 from sqlalchemy import or_
   45 from sqlalchemy.orm import joinedload
   46 from sqlalchemy.sql.expression import literal
   47 from sqlalchemy.sql.expression import true
   48 from sqlalchemy.sql import func
   49 
   50 from manila.common import constants
   51 from manila.db.sqlalchemy import models
   52 from manila import exception
   53 from manila.i18n import _
   54 from manila import quota
   55 
   56 CONF = cfg.CONF
   57 
   58 LOG = log.getLogger(__name__)
   59 QUOTAS = quota.QUOTAS
   60 
   61 _DEFAULT_QUOTA_NAME = 'default'
   62 PER_PROJECT_QUOTAS = []
   63 
   64 _FACADE = None
   65 
   66 _DEFAULT_SQL_CONNECTION = 'sqlite://'
   67 db_options.set_defaults(cfg.CONF,
   68                         connection=_DEFAULT_SQL_CONNECTION)
   69 
   70 
   71 def _create_facade_lazily():
   72     global _FACADE
   73     if _FACADE is None:
   74         _FACADE = session.EngineFacade.from_config(cfg.CONF)
   75     return _FACADE
   76 
   77 
   78 def get_engine():
   79     facade = _create_facade_lazily()
   80     return facade.get_engine()
   81 
   82 
   83 def get_session(**kwargs):
   84     facade = _create_facade_lazily()
   85     return facade.get_session(**kwargs)
   86 
   87 
   88 def get_backend():
   89     """The backend is this module itself."""
   90 
   91     return sys.modules[__name__]
   92 
   93 
   94 def is_admin_context(context):
   95     """Indicates if the request context is an administrator."""
   96     if not context:
   97         warnings.warn(_('Use of empty request context is deprecated'),
   98                       DeprecationWarning)
   99         raise Exception('die')
  100     return context.is_admin
  101 
  102 
  103 def is_user_context(context):
  104     """Indicates if the request context is a normal user."""
  105     if not context:
  106         return False
  107     if context.is_admin:
  108         return False
  109     if not context.user_id or not context.project_id:
  110         return False
  111     return True
  112 
  113 
  114 def authorize_project_context(context, project_id):
  115     """Ensures a request has permission to access the given project."""
  116     if is_user_context(context):
  117         if not context.project_id:
  118             raise exception.NotAuthorized()
  119         elif context.project_id != project_id:
  120             raise exception.NotAuthorized()
  121 
  122 
  123 def authorize_user_context(context, user_id):
  124     """Ensures a request has permission to access the given user."""
  125     if is_user_context(context):
  126         if not context.user_id:
  127             raise exception.NotAuthorized()
  128         elif context.user_id != user_id:
  129             raise exception.NotAuthorized()
  130 
  131 
  132 def authorize_quota_class_context(context, class_name):
  133     """Ensures a request has permission to access the given quota class."""
  134     if is_user_context(context):
  135         if not context.quota_class:
  136             raise exception.NotAuthorized()
  137         elif context.quota_class != class_name:
  138             raise exception.NotAuthorized()
  139 
  140 
  141 def require_admin_context(f):
  142     """Decorator to require admin request context.
  143 
  144     The first argument to the wrapped function must be the context.
  145 
  146     """
  147     @wraps(f)
  148     def wrapper(*args, **kwargs):
  149         if not is_admin_context(args[0]):
  150             raise exception.AdminRequired()
  151         return f(*args, **kwargs)
  152     return wrapper
  153 
  154 
  155 def require_context(f):
  156     """Decorator to require *any* user or admin context.
  157 
  158     This does no authorization for user or project access matching, see
  159     :py:func:`authorize_project_context` and
  160     :py:func:`authorize_user_context`.
  161 
  162     The first argument to the wrapped function must be the context.
  163 
  164     """
  165     @wraps(f)
  166     def wrapper(*args, **kwargs):
  167         if not is_admin_context(args[0]) and not is_user_context(args[0]):
  168             raise exception.NotAuthorized()
  169         return f(*args, **kwargs)
  170     return wrapper
  171 
  172 
  173 def require_share_exists(f):
  174     """Decorator to require the specified share to exist.
  175 
  176     Requires the wrapped function to use context and share_id as
  177     their first two arguments.
  178     """
  179     @wraps(f)
  180     def wrapper(context, share_id, *args, **kwargs):
  181         share_get(context, share_id)
  182         return f(context, share_id, *args, **kwargs)
  183     wrapper.__name__ = f.__name__
  184     return wrapper
  185 
  186 
  187 def require_share_instance_exists(f):
  188     """Decorator to require the specified share instance to exist.
  189 
  190     Requires the wrapped function to use context and share_instance_id as
  191     their first two arguments.
  192     """
  193     @wraps(f)
  194     def wrapper(context, share_instance_id, *args, **kwargs):
  195         share_instance_get(context, share_instance_id)
  196         return f(context, share_instance_id, *args, **kwargs)
  197     wrapper.__name__ = f.__name__
  198     return wrapper
  199 
  200 
  201 def apply_sorting(model, query, sort_key, sort_dir):
  202     if sort_dir.lower() not in ('desc', 'asc'):
  203         msg = _("Wrong sorting data provided: sort key is '%(sort_key)s' "
  204                 "and sort direction is '%(sort_dir)s'.") % {
  205                     "sort_key": sort_key, "sort_dir": sort_dir}
  206         raise exception.InvalidInput(reason=msg)
  207 
  208     sort_attr = getattr(model, sort_key)
  209     sort_method = getattr(sort_attr, sort_dir.lower())
  210     return query.order_by(sort_method())
  211 
  212 
  213 def model_query(context, model, *args, **kwargs):
  214     """Query helper that accounts for context's `read_deleted` field.
  215 
  216     :param context: context to query under
  217     :param model: model to query. Must be a subclass of ModelBase.
  218     :param session: if present, the session to use
  219     :param read_deleted: if present, overrides context's read_deleted field.
  220     :param project_only: if present and context is user-type, then restrict
  221             query to match the context's project_id.
  222     """
  223     session = kwargs.get('session') or get_session()
  224     read_deleted = kwargs.get('read_deleted') or context.read_deleted
  225     project_only = kwargs.get('project_only')
  226     kwargs = dict()
  227 
  228     if project_only and not context.is_admin:
  229         kwargs['project_id'] = context.project_id
  230     if read_deleted in ('no', 'n', False):
  231         kwargs['deleted'] = False
  232     elif read_deleted in ('yes', 'y', True):
  233         kwargs['deleted'] = True
  234 
  235     return db_utils.model_query(
  236         model=model, session=session, args=args, **kwargs)
  237 
  238 
  239 def exact_filter(query, model, filters, legal_keys):
  240     """Applies exact match filtering to a query.
  241 
  242     Returns the updated query.  Modifies filters argument to remove
  243     filters consumed.
  244 
  245     :param query: query to apply filters to
  246     :param model: model object the query applies to, for IN-style
  247                   filtering
  248     :param filters: dictionary of filters; values that are lists,
  249                     tuples, sets, or frozensets cause an 'IN' test to
  250                     be performed, while exact matching ('==' operator)
  251                     is used for other values
  252     :param legal_keys: list of keys to apply exact filtering to
  253     """
  254 
  255     filter_dict = {}
  256 
  257     # Walk through all the keys
  258     for key in legal_keys:
  259         # Skip ones we're not filtering on
  260         if key not in filters:
  261             continue
  262 
  263         # OK, filtering on this key; what value do we search for?
  264         value = filters.pop(key)
  265 
  266         if isinstance(value, (list, tuple, set, frozenset)):
  267             # Looking for values in a list; apply to query directly
  268             column_attr = getattr(model, key)
  269             query = query.filter(column_attr.in_(value))
  270         else:
  271             # OK, simple exact match; save for later
  272             filter_dict[key] = value
  273 
  274     # Apply simple exact matches
  275     if filter_dict:
  276         query = query.filter_by(**filter_dict)
  277 
  278     return query
  279 
  280 
  281 def ensure_model_dict_has_id(model_dict):
  282     if not model_dict.get('id'):
  283         model_dict['id'] = uuidutils.generate_uuid()
  284     return model_dict
  285 
  286 
  287 def _sync_shares(context, project_id, user_id, session, share_type_id=None):
  288     (shares, gigs) = share_data_get_for_project(
  289         context, project_id, user_id, share_type_id=share_type_id,
  290         session=session)
  291     return {'shares': shares}
  292 
  293 
  294 def _sync_snapshots(context, project_id, user_id, session, share_type_id=None):
  295     (snapshots, gigs) = snapshot_data_get_for_project(
  296         context, project_id, user_id, share_type_id=share_type_id,
  297         session=session)
  298     return {'snapshots': snapshots}
  299 
  300 
  301 def _sync_gigabytes(context, project_id, user_id, session, share_type_id=None):
  302     _junk, share_gigs = share_data_get_for_project(
  303         context, project_id, user_id, share_type_id=share_type_id,
  304         session=session)
  305     return {"gigabytes": share_gigs}
  306 
  307 
  308 def _sync_snapshot_gigabytes(context, project_id, user_id, session,
  309                              share_type_id=None):
  310     _junk, snapshot_gigs = snapshot_data_get_for_project(
  311         context, project_id, user_id, share_type_id=share_type_id,
  312         session=session)
  313     return {"snapshot_gigabytes": snapshot_gigs}
  314 
  315 
  316 def _sync_share_networks(context, project_id, user_id, session,
  317                          share_type_id=None):
  318     share_networks_count = count_share_networks(
  319         context, project_id, user_id, share_type_id=share_type_id,
  320         session=session)
  321     return {'share_networks': share_networks_count}
  322 
  323 
  324 def _sync_share_groups(context, project_id, user_id, session,
  325                        share_type_id=None):
  326     share_groups_count = count_share_groups(
  327         context, project_id, user_id, share_type_id=share_type_id,
  328         session=session)
  329     return {'share_groups': share_groups_count}
  330 
  331 
  332 def _sync_share_group_snapshots(context, project_id, user_id, session,
  333                                 share_type_id=None):
  334     share_group_snapshots_count = count_share_group_snapshots(
  335         context, project_id, user_id, share_type_id=share_type_id,
  336         session=session)
  337     return {'share_group_snapshots': share_group_snapshots_count}
  338 
  339 
  340 QUOTA_SYNC_FUNCTIONS = {
  341     '_sync_shares': _sync_shares,
  342     '_sync_snapshots': _sync_snapshots,
  343     '_sync_gigabytes': _sync_gigabytes,
  344     '_sync_snapshot_gigabytes': _sync_snapshot_gigabytes,
  345     '_sync_share_networks': _sync_share_networks,
  346     '_sync_share_groups': _sync_share_groups,
  347     '_sync_share_group_snapshots': _sync_share_group_snapshots,
  348 }
  349 
  350 
  351 ###################
  352 
  353 
  354 @require_admin_context
  355 def service_destroy(context, service_id):
  356     session = get_session()
  357     with session.begin():
  358         service_ref = service_get(context, service_id, session=session)
  359         service_ref.soft_delete(session)
  360 
  361 
  362 @require_admin_context
  363 def service_get(context, service_id, session=None):
  364     result = (model_query(
  365         context,
  366         models.Service,
  367         session=session).
  368         filter_by(id=service_id).
  369         first())
  370     if not result:
  371         raise exception.ServiceNotFound(service_id=service_id)
  372 
  373     return result
  374 
  375 
  376 @require_admin_context
  377 def service_get_all(context, disabled=None):
  378     query = model_query(context, models.Service)
  379 
  380     if disabled is not None:
  381         query = query.filter_by(disabled=disabled)
  382 
  383     return query.all()
  384 
  385 
  386 @require_admin_context
  387 def service_get_all_by_topic(context, topic):
  388     return (model_query(
  389         context, models.Service, read_deleted="no").
  390         filter_by(disabled=False).
  391         filter_by(topic=topic).
  392         all())
  393 
  394 
  395 @require_admin_context
  396 def service_get_by_host_and_topic(context, host, topic):
  397     result = (model_query(
  398         context, models.Service, read_deleted="no").
  399         filter_by(disabled=False).
  400         filter_by(host=host).
  401         filter_by(topic=topic).
  402         first())
  403     if not result:
  404         raise exception.ServiceNotFound(service_id=host)
  405     return result
  406 
  407 
  408 @require_admin_context
  409 def _service_get_all_topic_subquery(context, session, topic, subq, label):
  410     sort_value = getattr(subq.c, label)
  411     return (model_query(context, models.Service,
  412                         func.coalesce(sort_value, 0),
  413                         session=session, read_deleted="no").
  414             filter_by(topic=topic).
  415             filter_by(disabled=False).
  416             outerjoin((subq, models.Service.host == subq.c.host)).
  417             order_by(sort_value).
  418             all())
  419 
  420 
  421 @require_admin_context
  422 def service_get_all_share_sorted(context):
  423     session = get_session()
  424     with session.begin():
  425         topic = CONF.share_topic
  426         label = 'share_gigabytes'
  427         subq = (model_query(context, models.Share,
  428                             func.sum(models.Share.size).label(label),
  429                             session=session, read_deleted="no").
  430                 join(models.ShareInstance,
  431                      models.ShareInstance.share_id == models.Share.id).
  432                 group_by(models.ShareInstance.host).
  433                 subquery())
  434         return _service_get_all_topic_subquery(context,
  435                                                session,
  436                                                topic,
  437                                                subq,
  438                                                label)
  439 
  440 
  441 @require_admin_context
  442 def service_get_by_args(context, host, binary):
  443     result = (model_query(context, models.Service).
  444               filter_by(host=host).
  445               filter_by(binary=binary).
  446               first())
  447 
  448     if not result:
  449         raise exception.HostBinaryNotFound(host=host, binary=binary)
  450 
  451     return result
  452 
  453 
  454 @require_admin_context
  455 def service_create(context, values):
  456     session = get_session()
  457 
  458     _ensure_availability_zone_exists(context, values, session)
  459 
  460     service_ref = models.Service()
  461     service_ref.update(values)
  462     if not CONF.enable_new_services:
  463         service_ref.disabled = True
  464 
  465     with session.begin():
  466         service_ref.save(session)
  467         return service_ref
  468 
  469 
  470 @require_admin_context
  471 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
  472 def service_update(context, service_id, values):
  473     session = get_session()
  474 
  475     _ensure_availability_zone_exists(context, values, session, strict=False)
  476 
  477     with session.begin():
  478         service_ref = service_get(context, service_id, session=session)
  479         service_ref.update(values)
  480         service_ref.save(session=session)
  481 
  482 
  483 ###################
  484 
  485 
  486 @require_context
  487 def quota_get_all_by_project_and_user(context, project_id, user_id):
  488     authorize_project_context(context, project_id)
  489     user_quotas = model_query(
  490         context, models.ProjectUserQuota,
  491         models.ProjectUserQuota.resource,
  492         models.ProjectUserQuota.hard_limit,
  493     ).filter_by(
  494         project_id=project_id,
  495     ).filter_by(
  496         user_id=user_id,
  497     ).all()
  498 
  499     result = {'project_id': project_id, 'user_id': user_id}
  500     for u_quota in user_quotas:
  501         result[u_quota.resource] = u_quota.hard_limit
  502     return result
  503 
  504 
  505 @require_context
  506 def quota_get_all_by_project_and_share_type(context, project_id,
  507                                             share_type_id):
  508     authorize_project_context(context, project_id)
  509     share_type_quotas = model_query(
  510         context, models.ProjectShareTypeQuota,
  511         models.ProjectShareTypeQuota.resource,
  512         models.ProjectShareTypeQuota.hard_limit,
  513     ).filter_by(
  514         project_id=project_id,
  515     ).filter_by(
  516         share_type_id=share_type_id,
  517     ).all()
  518 
  519     result = {
  520         'project_id': project_id,
  521         'share_type_id': share_type_id,
  522     }
  523     for st_quota in share_type_quotas:
  524         result[st_quota.resource] = st_quota.hard_limit
  525     return result
  526 
  527 
  528 @require_context
  529 def quota_get_all_by_project(context, project_id):
  530     authorize_project_context(context, project_id)
  531     project_quotas = model_query(
  532         context, models.Quota, read_deleted="no",
  533     ).filter_by(
  534         project_id=project_id,
  535     ).all()
  536 
  537     result = {'project_id': project_id}
  538     for p_quota in project_quotas:
  539         result[p_quota.resource] = p_quota.hard_limit
  540     return result
  541 
  542 
  543 @require_context
  544 def quota_get_all(context, project_id):
  545     authorize_project_context(context, project_id)
  546 
  547     result = (model_query(context, models.ProjectUserQuota).
  548               filter_by(project_id=project_id).
  549               all())
  550 
  551     return result
  552 
  553 
  554 @require_admin_context
  555 def quota_create(context, project_id, resource, limit, user_id=None,
  556                  share_type_id=None):
  557     per_user = user_id and resource not in PER_PROJECT_QUOTAS
  558 
  559     if per_user:
  560         check = model_query(context, models.ProjectUserQuota).filter(
  561             models.ProjectUserQuota.project_id == project_id,
  562             models.ProjectUserQuota.user_id == user_id,
  563             models.ProjectUserQuota.resource == resource,
  564         ).all()
  565         quota_ref = models.ProjectUserQuota()
  566         quota_ref.user_id = user_id
  567     elif share_type_id:
  568         check = model_query(context, models.ProjectShareTypeQuota).filter(
  569             models.ProjectShareTypeQuota.project_id == project_id,
  570             models.ProjectShareTypeQuota.share_type_id == share_type_id,
  571             models.ProjectShareTypeQuota.resource == resource,
  572         ).all()
  573         quota_ref = models.ProjectShareTypeQuota()
  574         quota_ref.share_type_id = share_type_id
  575     else:
  576         check = model_query(context, models.Quota).filter(
  577             models.Quota.project_id == project_id,
  578             models.Quota.resource == resource,
  579         ).all()
  580         quota_ref = models.Quota()
  581     if check:
  582         raise exception.QuotaExists(project_id=project_id, resource=resource)
  583 
  584     quota_ref.project_id = project_id
  585     quota_ref.resource = resource
  586     quota_ref.hard_limit = limit
  587     session = get_session()
  588     with session.begin():
  589         quota_ref.save(session)
  590     return quota_ref
  591 
  592 
  593 @require_admin_context
  594 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
  595 def quota_update(context, project_id, resource, limit, user_id=None,
  596                  share_type_id=None):
  597     per_user = user_id and resource not in PER_PROJECT_QUOTAS
  598     if per_user:
  599         query = model_query(context, models.ProjectUserQuota).filter(
  600             models.ProjectUserQuota.project_id == project_id,
  601             models.ProjectUserQuota.user_id == user_id,
  602             models.ProjectUserQuota.resource == resource,
  603         )
  604     elif share_type_id:
  605         query = model_query(context, models.ProjectShareTypeQuota).filter(
  606             models.ProjectShareTypeQuota.project_id == project_id,
  607             models.ProjectShareTypeQuota.share_type_id == share_type_id,
  608             models.ProjectShareTypeQuota.resource == resource,
  609         )
  610     else:
  611         query = model_query(context, models.Quota).filter(
  612             models.Quota.project_id == project_id,
  613             models.Quota.resource == resource,
  614         )
  615 
  616     result = query.update({'hard_limit': limit})
  617     if not result:
  618         if per_user:
  619             raise exception.ProjectUserQuotaNotFound(
  620                 project_id=project_id, user_id=user_id)
  621         elif share_type_id:
  622             raise exception.ProjectShareTypeQuotaNotFound(
  623                 project_id=project_id, share_type=share_type_id)
  624         raise exception.ProjectQuotaNotFound(project_id=project_id)
  625 
  626 
  627 ###################
  628 
  629 
  630 @require_context
  631 def quota_class_get(context, class_name, resource, session=None):
  632     result = (model_query(context, models.QuotaClass, session=session,
  633                           read_deleted="no").
  634               filter_by(class_name=class_name).
  635               filter_by(resource=resource).
  636               first())
  637 
  638     if not result:
  639         raise exception.QuotaClassNotFound(class_name=class_name)
  640 
  641     return result
  642 
  643 
  644 @require_context
  645 def quota_class_get_default(context):
  646     rows = (model_query(context, models.QuotaClass, read_deleted="no").
  647             filter_by(class_name=_DEFAULT_QUOTA_NAME).
  648             all())
  649 
  650     result = {'class_name': _DEFAULT_QUOTA_NAME}
  651     for row in rows:
  652         result[row.resource] = row.hard_limit
  653 
  654     return result
  655 
  656 
  657 @require_context
  658 def quota_class_get_all_by_name(context, class_name):
  659     authorize_quota_class_context(context, class_name)
  660 
  661     rows = (model_query(context, models.QuotaClass, read_deleted="no").
  662             filter_by(class_name=class_name).
  663             all())
  664 
  665     result = {'class_name': class_name}
  666     for row in rows:
  667         result[row.resource] = row.hard_limit
  668 
  669     return result
  670 
  671 
  672 @require_admin_context
  673 def quota_class_create(context, class_name, resource, limit):
  674     quota_class_ref = models.QuotaClass()
  675     quota_class_ref.class_name = class_name
  676     quota_class_ref.resource = resource
  677     quota_class_ref.hard_limit = limit
  678     session = get_session()
  679     with session.begin():
  680         quota_class_ref.save(session)
  681     return quota_class_ref
  682 
  683 
  684 @require_admin_context
  685 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
  686 def quota_class_update(context, class_name, resource, limit):
  687     result = (model_query(context, models.QuotaClass, read_deleted="no").
  688               filter_by(class_name=class_name).
  689               filter_by(resource=resource).
  690               update({'hard_limit': limit}))
  691 
  692     if not result:
  693         raise exception.QuotaClassNotFound(class_name=class_name)
  694 
  695 
  696 ###################
  697 
  698 
  699 @require_context
  700 def quota_usage_get(context, project_id, resource, user_id=None,
  701                     share_type_id=None):
  702     query = (model_query(context, models.QuotaUsage, read_deleted="no").
  703              filter_by(project_id=project_id).
  704              filter_by(resource=resource))
  705     if user_id:
  706         if resource not in PER_PROJECT_QUOTAS:
  707             result = query.filter_by(user_id=user_id).first()
  708         else:
  709             result = query.filter_by(user_id=None).first()
  710     elif share_type_id:
  711         result = query.filter_by(queryshare_type_id=share_type_id).first()
  712     else:
  713         result = query.first()
  714 
  715     if not result:
  716         raise exception.QuotaUsageNotFound(project_id=project_id)
  717 
  718     return result
  719 
  720 
  721 def _quota_usage_get_all(context, project_id, user_id=None,
  722                          share_type_id=None):
  723     authorize_project_context(context, project_id)
  724     query = (model_query(context, models.QuotaUsage, read_deleted="no").
  725              filter_by(project_id=project_id))
  726     result = {'project_id': project_id}
  727     if user_id:
  728         query = query.filter(or_(models.QuotaUsage.user_id == user_id,
  729                                  models.QuotaUsage.user_id is None))
  730         result['user_id'] = user_id
  731     elif share_type_id:
  732         query = query.filter_by(share_type_id=share_type_id)
  733         result['share_type_id'] = share_type_id
  734     else:
  735         query = query.filter_by(share_type_id=None)
  736 
  737     rows = query.all()
  738     for row in rows:
  739         if row.resource in result:
  740             result[row.resource]['in_use'] += row.in_use
  741             result[row.resource]['reserved'] += row.reserved
  742         else:
  743             result[row.resource] = dict(in_use=row.in_use,
  744                                         reserved=row.reserved)
  745 
  746     return result
  747 
  748 
  749 @require_context
  750 def quota_usage_get_all_by_project(context, project_id):
  751     return _quota_usage_get_all(context, project_id)
  752 
  753 
  754 @require_context
  755 def quota_usage_get_all_by_project_and_user(context, project_id, user_id):
  756     return _quota_usage_get_all(context, project_id, user_id=user_id)
  757 
  758 
  759 @require_context
  760 def quota_usage_get_all_by_project_and_share_type(context, project_id,
  761                                                   share_type_id):
  762     return _quota_usage_get_all(
  763         context, project_id, share_type_id=share_type_id)
  764 
  765 
  766 def _quota_usage_create(context, project_id, user_id, resource, in_use,
  767                         reserved, until_refresh, share_type_id=None,
  768                         session=None):
  769     quota_usage_ref = models.QuotaUsage()
  770     if share_type_id:
  771         quota_usage_ref.share_type_id = share_type_id
  772     else:
  773         quota_usage_ref.user_id = user_id
  774     quota_usage_ref.project_id = project_id
  775     quota_usage_ref.resource = resource
  776     quota_usage_ref.in_use = in_use
  777     quota_usage_ref.reserved = reserved
  778     quota_usage_ref.until_refresh = until_refresh
  779     # updated_at is needed for judgement of max_age
  780     quota_usage_ref.updated_at = timeutils.utcnow()
  781 
  782     quota_usage_ref.save(session=session)
  783 
  784     return quota_usage_ref
  785 
  786 
  787 @require_admin_context
  788 def quota_usage_create(context, project_id, user_id, resource, in_use,
  789                        reserved, until_refresh, share_type_id=None):
  790     session = get_session()
  791     return _quota_usage_create(
  792         context, project_id, user_id, resource, in_use, reserved,
  793         until_refresh, share_type_id=share_type_id, session=session)
  794 
  795 
  796 @require_admin_context
  797 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
  798 def quota_usage_update(context, project_id, user_id, resource,
  799                        share_type_id=None, **kwargs):
  800     updates = {}
  801     for key in ('in_use', 'reserved', 'until_refresh'):
  802         if key in kwargs:
  803             updates[key] = kwargs[key]
  804 
  805     query = model_query(
  806         context, models.QuotaUsage, read_deleted="no",
  807     ).filter_by(project_id=project_id).filter_by(resource=resource)
  808     if share_type_id:
  809         query = query.filter_by(share_type_id=share_type_id)
  810     else:
  811         query = query.filter(or_(models.QuotaUsage.user_id == user_id,
  812                                  models.QuotaUsage.user_id is None))
  813     result = query.update(updates)
  814 
  815     if not result:
  816         raise exception.QuotaUsageNotFound(project_id=project_id)
  817 
  818 
  819 ###################
  820 
  821 
  822 def _reservation_create(context, uuid, usage, project_id, user_id, resource,
  823                         delta, expire, share_type_id=None, session=None):
  824     reservation_ref = models.Reservation()
  825     reservation_ref.uuid = uuid
  826     reservation_ref.usage_id = usage['id']
  827     reservation_ref.project_id = project_id
  828     if share_type_id:
  829         reservation_ref.share_type_id = share_type_id
  830     else:
  831         reservation_ref.user_id = user_id
  832     reservation_ref.resource = resource
  833     reservation_ref.delta = delta
  834     reservation_ref.expire = expire
  835     reservation_ref.save(session=session)
  836     return reservation_ref
  837 
  838 
  839 ###################
  840 
  841 
  842 # NOTE(johannes): The quota code uses SQL locking to ensure races don't
  843 # cause under or over counting of resources. To avoid deadlocks, this
  844 # code always acquires the lock on quota_usages before acquiring the lock
  845 # on reservations.
  846 
  847 def _get_share_type_quota_usages(context, session, project_id, share_type_id):
  848     rows = model_query(
  849         context, models.QuotaUsage, read_deleted="no", session=session,
  850     ).filter(
  851         models.QuotaUsage.project_id == project_id,
  852         models.QuotaUsage.share_type_id == share_type_id,
  853     ).with_lockmode('update').all()
  854     return {row.resource: row for row in rows}
  855 
  856 
  857 def _get_user_quota_usages(context, session, project_id, user_id):
  858     # Broken out for testability
  859     rows = (model_query(context, models.QuotaUsage,
  860                         read_deleted="no",
  861                         session=session).
  862             filter_by(project_id=project_id).
  863             filter(or_(models.QuotaUsage.user_id == user_id,
  864                        models.QuotaUsage.user_id is None)).
  865             with_lockmode('update').
  866             all())
  867     return {row.resource: row for row in rows}
  868 
  869 
  870 def _get_project_quota_usages(context, session, project_id):
  871     rows = (model_query(context, models.QuotaUsage,
  872                         read_deleted="no",
  873                         session=session).
  874             filter_by(project_id=project_id).
  875             filter(models.QuotaUsage.share_type_id is None).
  876             with_lockmode('update').
  877             all())
  878     result = dict()
  879     # Get the total count of in_use,reserved
  880     for row in rows:
  881         if row.resource in result:
  882             result[row.resource]['in_use'] += row.in_use
  883             result[row.resource]['reserved'] += row.reserved
  884             result[row.resource]['total'] += (row.in_use + row.reserved)
  885         else:
  886             result[row.resource] = dict(in_use=row.in_use,
  887                                         reserved=row.reserved,
  888                                         total=row.in_use + row.reserved)
  889     return result
  890 
  891 
  892 @require_context
  893 def quota_reserve(context, resources, project_quotas, user_quotas,
  894                   share_type_quotas, deltas, expire, until_refresh,
  895                   max_age, project_id=None, user_id=None, share_type_id=None):
  896     user_reservations = _quota_reserve(
  897         context, resources, project_quotas, user_quotas,
  898         deltas, expire, until_refresh, max_age, project_id, user_id=user_id)
  899     if share_type_id:
  900         try:
  901             st_reservations = _quota_reserve(
  902                 context, resources, project_quotas, share_type_quotas,
  903                 deltas, expire, until_refresh, max_age, project_id,
  904                 share_type_id=share_type_id)
  905         except exception.OverQuota:
  906             with excutils.save_and_reraise_exception():
  907                 # rollback previous reservations
  908                 reservation_rollback(
  909                     context, user_reservations,
  910                     project_id=project_id, user_id=user_id)
  911         return user_reservations + st_reservations
  912     return user_reservations
  913 
  914 
  915 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
  916 def _quota_reserve(context, resources, project_quotas, user_or_st_quotas,
  917                    deltas, expire, until_refresh,
  918                    max_age, project_id=None, user_id=None, share_type_id=None):
  919     elevated = context.elevated()
  920     session = get_session()
  921     with session.begin():
  922 
  923         if project_id is None:
  924             project_id = context.project_id
  925         if share_type_id:
  926             user_or_st_usages = _get_share_type_quota_usages(
  927                 context, session, project_id, share_type_id)
  928         else:
  929             user_id = user_id if user_id else context.user_id
  930             user_or_st_usages = _get_user_quota_usages(
  931                 context, session, project_id, user_id)
  932 
  933         # Get the current usages
  934         project_usages = _get_project_quota_usages(
  935             context, session, project_id)
  936 
  937         # Handle usage refresh
  938         work = set(deltas.keys())
  939         while work:
  940             resource = work.pop()
  941 
  942             # Do we need to refresh the usage?
  943             refresh = False
  944             if ((resource not in PER_PROJECT_QUOTAS) and
  945                     (resource not in user_or_st_usages)):
  946                 user_or_st_usages[resource] = _quota_usage_create(
  947                     elevated,
  948                     project_id,
  949                     user_id,
  950                     resource,
  951                     0, 0,
  952                     until_refresh or None,
  953                     share_type_id=share_type_id,
  954                     session=session)
  955                 refresh = True
  956             elif ((resource in PER_PROJECT_QUOTAS) and
  957                     (resource not in user_or_st_usages)):
  958                 user_or_st_usages[resource] = _quota_usage_create(
  959                     elevated,
  960                     project_id,
  961                     None,
  962                     resource,
  963                     0, 0,
  964                     until_refresh or None,
  965                     share_type_id=share_type_id,
  966                     session=session)
  967                 refresh = True
  968             elif user_or_st_usages[resource].in_use < 0:
  969                 # Negative in_use count indicates a desync, so try to
  970                 # heal from that...
  971                 refresh = True
  972             elif user_or_st_usages[resource].until_refresh is not None:
  973                 user_or_st_usages[resource].until_refresh -= 1
  974                 if user_or_st_usages[resource].until_refresh <= 0:
  975                     refresh = True
  976             elif max_age and (user_or_st_usages[resource].updated_at -
  977                               timeutils.utcnow()).seconds >= max_age:
  978                 refresh = True
  979 
  980             # OK, refresh the usage
  981             if refresh:
  982                 # Grab the sync routine
  983                 sync = QUOTA_SYNC_FUNCTIONS[resources[resource].sync]
  984 
  985                 updates = sync(
  986                     elevated, project_id, user_id,
  987                     share_type_id=share_type_id, session=session)
  988                 for res, in_use in updates.items():
  989                     # Make sure we have a destination for the usage!
  990                     if ((res not in PER_PROJECT_QUOTAS) and
  991                             (res not in user_or_st_usages)):
  992                         user_or_st_usages[res] = _quota_usage_create(
  993                             elevated,
  994                             project_id,
  995                             user_id,
  996                             res,
  997                             0, 0,
  998                             until_refresh or None,
  999                             share_type_id=share_type_id,
 1000                             session=session)
 1001                     if ((res in PER_PROJECT_QUOTAS) and
 1002                             (res not in user_or_st_usages)):
 1003                         user_or_st_usages[res] = _quota_usage_create(
 1004                             elevated,
 1005                             project_id,
 1006                             None,
 1007                             res,
 1008                             0, 0,
 1009                             until_refresh or None,
 1010                             share_type_id=share_type_id,
 1011                             session=session)
 1012 
 1013                     if user_or_st_usages[res].in_use != in_use:
 1014                         LOG.debug(
 1015                             'quota_usages out of sync, updating. '
 1016                             'project_id: %(project_id)s, '
 1017                             'user_id: %(user_id)s, '
 1018                             'share_type_id: %(share_type_id)s, '
 1019                             'resource: %(res)s, '
 1020                             'tracked usage: %(tracked_use)s, '
 1021                             'actual usage: %(in_use)s',
 1022                             {'project_id': project_id,
 1023                              'user_id': user_id,
 1024                              'share_type_id': share_type_id,
 1025                              'res': res,
 1026                              'tracked_use': user_or_st_usages[res].in_use,
 1027                              'in_use': in_use})
 1028 
 1029                     # Update the usage
 1030                     user_or_st_usages[res].in_use = in_use
 1031                     user_or_st_usages[res].until_refresh = (
 1032                         until_refresh or None)
 1033 
 1034                     # Because more than one resource may be refreshed
 1035                     # by the call to the sync routine, and we don't
 1036                     # want to double-sync, we make sure all refreshed
 1037                     # resources are dropped from the work set.
 1038                     work.discard(res)
 1039 
 1040                     # NOTE(Vek): We make the assumption that the sync
 1041                     #            routine actually refreshes the
 1042                     #            resources that it is the sync routine
 1043                     #            for.  We don't check, because this is
 1044                     #            a best-effort mechanism.
 1045 
 1046         # Check for deltas that would go negative
 1047         unders = [res for res, delta in deltas.items()
 1048                   if delta < 0 and
 1049                   delta + user_or_st_usages[res].in_use < 0]
 1050 
 1051         # Now, let's check the quotas
 1052         # NOTE(Vek): We're only concerned about positive increments.
 1053         #            If a project has gone over quota, we want them to
 1054         #            be able to reduce their usage without any
 1055         #            problems.
 1056         for key, value in user_or_st_usages.items():
 1057             if key not in project_usages:
 1058                 project_usages[key] = value
 1059         overs = [res for res, delta in deltas.items()
 1060                  if user_or_st_quotas[res] >= 0 and delta >= 0 and
 1061                  (0 <= project_quotas[res] < delta +
 1062                   project_usages[res]['total'] or
 1063                   user_or_st_quotas[res] < delta +
 1064                   user_or_st_usages[res].total)]
 1065 
 1066         # NOTE(Vek): The quota check needs to be in the transaction,
 1067         #            but the transaction doesn't fail just because
 1068         #            we're over quota, so the OverQuota raise is
 1069         #            outside the transaction.  If we did the raise
 1070         #            here, our usage updates would be discarded, but
 1071         #            they're not invalidated by being over-quota.
 1072 
 1073         # Create the reservations
 1074         if not overs:
 1075             reservations = []
 1076             for res, delta in deltas.items():
 1077                 reservation = _reservation_create(elevated,
 1078                                                   uuidutils.generate_uuid(),
 1079                                                   user_or_st_usages[res],
 1080                                                   project_id,
 1081                                                   user_id,
 1082                                                   res, delta, expire,
 1083                                                   share_type_id=share_type_id,
 1084                                                   session=session)
 1085                 reservations.append(reservation.uuid)
 1086 
 1087                 # Also update the reserved quantity
 1088                 # NOTE(Vek): Again, we are only concerned here about
 1089                 #            positive increments.  Here, though, we're
 1090                 #            worried about the following scenario:
 1091                 #
 1092                 #            1) User initiates resize down.
 1093                 #            2) User allocates a new instance.
 1094                 #            3) Resize down fails or is reverted.
 1095                 #            4) User is now over quota.
 1096                 #
 1097                 #            To prevent this, we only update the
 1098                 #            reserved value if the delta is positive.
 1099                 if delta > 0:
 1100                     user_or_st_usages[res].reserved += delta
 1101 
 1102         # Apply updates to the usages table
 1103         for usage_ref in user_or_st_usages.values():
 1104             session.add(usage_ref)
 1105 
 1106     if unders:
 1107         LOG.warning("Change will make usage less than 0 for the following "
 1108                     "resources: %s", unders)
 1109     if overs:
 1110         if project_quotas == user_or_st_quotas:
 1111             usages = project_usages
 1112         else:
 1113             usages = user_or_st_usages
 1114         usages = {k: dict(in_use=v['in_use'], reserved=v['reserved'])
 1115                   for k, v in usages.items()}
 1116         raise exception.OverQuota(
 1117             overs=sorted(overs), quotas=user_or_st_quotas, usages=usages)
 1118 
 1119     return reservations
 1120 
 1121 
 1122 def _quota_reservations_query(session, context, reservations):
 1123     """Return the relevant reservations."""
 1124 
 1125     # Get the listed reservations
 1126     return (model_query(context, models.Reservation,
 1127                         read_deleted="no",
 1128                         session=session).
 1129             filter(models.Reservation.uuid.in_(reservations)).
 1130             with_lockmode('update'))
 1131 
 1132 
 1133 @require_context
 1134 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 1135 def reservation_commit(context, reservations, project_id=None, user_id=None,
 1136                        share_type_id=None):
 1137     session = get_session()
 1138     with session.begin():
 1139         if share_type_id:
 1140             st_usages = _get_share_type_quota_usages(
 1141                 context, session, project_id, share_type_id)
 1142         else:
 1143             st_usages = {}
 1144         user_usages = _get_user_quota_usages(
 1145             context, session, project_id, user_id)
 1146 
 1147         reservation_query = _quota_reservations_query(
 1148             session, context, reservations)
 1149         for reservation in reservation_query.all():
 1150             if reservation['share_type_id']:
 1151                 usages = st_usages
 1152             else:
 1153                 usages = user_usages
 1154             usage = usages[reservation.resource]
 1155             if reservation.delta >= 0:
 1156                 usage.reserved -= reservation.delta
 1157             usage.in_use += reservation.delta
 1158         reservation_query.soft_delete(synchronize_session=False)
 1159 
 1160 
 1161 @require_context
 1162 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 1163 def reservation_rollback(context, reservations, project_id=None, user_id=None,
 1164                          share_type_id=None):
 1165     session = get_session()
 1166     with session.begin():
 1167         if share_type_id:
 1168             st_usages = _get_share_type_quota_usages(
 1169                 context, session, project_id, share_type_id)
 1170         else:
 1171             st_usages = {}
 1172         user_usages = _get_user_quota_usages(
 1173             context, session, project_id, user_id)
 1174 
 1175         reservation_query = _quota_reservations_query(
 1176             session, context, reservations)
 1177         for reservation in reservation_query.all():
 1178             if reservation['share_type_id']:
 1179                 usages = st_usages
 1180             else:
 1181                 usages = user_usages
 1182             usage = usages[reservation.resource]
 1183             if reservation.delta >= 0:
 1184                 usage.reserved -= reservation.delta
 1185         reservation_query.soft_delete(synchronize_session=False)
 1186 
 1187 
 1188 @require_admin_context
 1189 def quota_destroy_all_by_project_and_user(context, project_id, user_id):
 1190     session = get_session()
 1191     with session.begin():
 1192         (model_query(context, models.ProjectUserQuota, session=session,
 1193                      read_deleted="no").
 1194          filter_by(project_id=project_id).
 1195          filter_by(user_id=user_id).soft_delete(synchronize_session=False))
 1196 
 1197         (model_query(context, models.QuotaUsage,
 1198                      session=session, read_deleted="no").
 1199          filter_by(project_id=project_id).
 1200          filter_by(user_id=user_id).soft_delete(synchronize_session=False))
 1201 
 1202         (model_query(context, models.Reservation,
 1203                      session=session, read_deleted="no").
 1204          filter_by(project_id=project_id).
 1205          filter_by(user_id=user_id).soft_delete(synchronize_session=False))
 1206 
 1207 
 1208 @require_admin_context
 1209 def quota_destroy_all_by_share_type(context, share_type_id, project_id=None):
 1210     """Soft deletes all quotas, usages and reservations.
 1211 
 1212     :param context: request context for queries, updates and logging
 1213     :param share_type_id: ID of the share type to filter the quotas, usages
 1214         and reservations under.
 1215     :param project_id: ID of the project to filter the quotas, usages and
 1216         reservations under. If not provided, share type quotas for all
 1217         projects will be acted upon.
 1218     """
 1219     session = get_session()
 1220     with session.begin():
 1221         share_type_quotas = model_query(
 1222             context, models.ProjectShareTypeQuota, session=session,
 1223             read_deleted="no",
 1224         ).filter_by(share_type_id=share_type_id)
 1225 
 1226         share_type_quota_usages = model_query(
 1227             context, models.QuotaUsage, session=session, read_deleted="no",
 1228         ).filter_by(share_type_id=share_type_id)
 1229 
 1230         share_type_quota_reservations = model_query(
 1231             context, models.Reservation, session=session, read_deleted="no",
 1232         ).filter_by(share_type_id=share_type_id)
 1233 
 1234         if project_id is not None:
 1235             share_type_quotas = share_type_quotas.filter_by(
 1236                 project_id=project_id)
 1237             share_type_quota_usages = share_type_quota_usages.filter_by(
 1238                 project_id=project_id)
 1239             share_type_quota_reservations = (
 1240                 share_type_quota_reservations.filter_by(project_id=project_id))
 1241 
 1242         share_type_quotas.soft_delete(synchronize_session=False)
 1243         share_type_quota_usages.soft_delete(synchronize_session=False)
 1244         share_type_quota_reservations.soft_delete(synchronize_session=False)
 1245 
 1246 
 1247 @require_admin_context
 1248 def quota_destroy_all_by_project(context, project_id):
 1249     session = get_session()
 1250     with session.begin():
 1251         (model_query(context, models.Quota, session=session,
 1252                      read_deleted="no").
 1253          filter_by(project_id=project_id).
 1254          soft_delete(synchronize_session=False))
 1255 
 1256         (model_query(context, models.ProjectUserQuota, session=session,
 1257                      read_deleted="no").
 1258          filter_by(project_id=project_id).
 1259          soft_delete(synchronize_session=False))
 1260 
 1261         (model_query(context, models.QuotaUsage,
 1262                      session=session, read_deleted="no").
 1263          filter_by(project_id=project_id).
 1264          soft_delete(synchronize_session=False))
 1265 
 1266         (model_query(context, models.Reservation,
 1267                      session=session, read_deleted="no").
 1268          filter_by(project_id=project_id).
 1269          soft_delete(synchronize_session=False))
 1270 
 1271 
 1272 @require_admin_context
 1273 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 1274 def reservation_expire(context):
 1275     session = get_session()
 1276     with session.begin():
 1277         current_time = timeutils.utcnow()
 1278         reservation_query = (model_query(
 1279             context, models.Reservation,
 1280             session=session, read_deleted="no").
 1281             filter(models.Reservation.expire < current_time))
 1282 
 1283         for reservation in reservation_query.all():
 1284             if reservation.delta >= 0:
 1285                 quota_usage = model_query(context, models.QuotaUsage,
 1286                                           session=session,
 1287                                           read_deleted="no").filter(
 1288                     models.QuotaUsage.id == reservation.usage_id).first()
 1289                 quota_usage.reserved -= reservation.delta
 1290                 session.add(quota_usage)
 1291 
 1292         reservation_query.soft_delete(synchronize_session=False)
 1293 
 1294 
 1295 ################
 1296 
 1297 def _extract_subdict_by_fields(source_dict, fields):
 1298     dict_to_extract_from = copy.deepcopy(source_dict)
 1299     sub_dict = {}
 1300     for field in fields:
 1301         field_value = dict_to_extract_from.pop(field, None)
 1302         if field_value:
 1303             sub_dict.update({field: field_value})
 1304 
 1305     return sub_dict, dict_to_extract_from
 1306 
 1307 
 1308 def _extract_share_instance_values(values):
 1309     share_instance_model_fields = [
 1310         'status', 'host', 'scheduled_at', 'launched_at', 'terminated_at',
 1311         'share_server_id', 'share_network_id', 'availability_zone',
 1312         'replica_state', 'share_type_id', 'share_type', 'access_rules_status',
 1313     ]
 1314     share_instance_values, share_values = (
 1315         _extract_subdict_by_fields(values, share_instance_model_fields)
 1316     )
 1317     return share_instance_values, share_values
 1318 
 1319 
 1320 def _change_size_to_instance_size(snap_instance_values):
 1321     if 'size' in snap_instance_values:
 1322         snap_instance_values['instance_size'] = snap_instance_values['size']
 1323         snap_instance_values.pop('size')
 1324 
 1325 
 1326 def _extract_snapshot_instance_values(values):
 1327     fields = ['status', 'progress', 'provider_location']
 1328     snapshot_instance_values, snapshot_values = (
 1329         _extract_subdict_by_fields(values, fields)
 1330     )
 1331     return snapshot_instance_values, snapshot_values
 1332 
 1333 
 1334 ################
 1335 
 1336 
 1337 @require_context
 1338 def share_instance_create(context, share_id, values):
 1339     session = get_session()
 1340     with session.begin():
 1341         return _share_instance_create(context, share_id, values, session)
 1342 
 1343 
 1344 def _share_instance_create(context, share_id, values, session):
 1345     if not values.get('id'):
 1346         values['id'] = uuidutils.generate_uuid()
 1347     values.update({'share_id': share_id})
 1348 
 1349     share_instance_ref = models.ShareInstance()
 1350     share_instance_ref.update(values)
 1351     share_instance_ref.save(session=session)
 1352 
 1353     return share_instance_get(context, share_instance_ref['id'],
 1354                               session=session)
 1355 
 1356 
 1357 @require_admin_context
 1358 def share_instances_host_update(context, current_host, new_host):
 1359     session = get_session()
 1360     host_field = models.ShareInstance.host
 1361     with session.begin():
 1362         query = model_query(
 1363             context, models.ShareInstance, session=session, read_deleted="no",
 1364         ).filter(host_field.like('{}%'.format(current_host)))
 1365         result = query.update(
 1366             {host_field: func.replace(host_field, current_host, new_host)},
 1367             synchronize_session=False)
 1368     return result
 1369 
 1370 
 1371 @require_context
 1372 def share_instance_update(context, share_instance_id, values,
 1373                           with_share_data=False):
 1374     session = get_session()
 1375     _ensure_availability_zone_exists(context, values, session, strict=False)
 1376     with session.begin():
 1377         instance_ref = _share_instance_update(
 1378             context, share_instance_id, values, session
 1379         )
 1380         if with_share_data:
 1381             parent_share = share_get(context, instance_ref['share_id'],
 1382                                      session=session)
 1383             instance_ref.set_share_data(parent_share)
 1384         return instance_ref
 1385 
 1386 
 1387 def _share_instance_update(context, share_instance_id, values, session):
 1388     share_instance_ref = share_instance_get(context, share_instance_id,
 1389                                             session=session)
 1390     share_instance_ref.update(values)
 1391     share_instance_ref.save(session=session)
 1392     return share_instance_ref
 1393 
 1394 
 1395 @require_context
 1396 def share_instance_get(context, share_instance_id, session=None,
 1397                        with_share_data=False):
 1398     if session is None:
 1399         session = get_session()
 1400     result = model_query(
 1401         context, models.ShareInstance, session=session,
 1402     ).filter_by(
 1403         id=share_instance_id,
 1404     ).options(
 1405         joinedload('export_locations'),
 1406         joinedload('share_type'),
 1407     ).first()
 1408     if result is None:
 1409         raise exception.NotFound()
 1410 
 1411     if with_share_data:
 1412         parent_share = share_get(context, result['share_id'], session=session)
 1413         result.set_share_data(parent_share)
 1414 
 1415     return result
 1416 
 1417 
 1418 @require_admin_context
 1419 def share_instances_get_all(context, filters=None):
 1420     session = get_session()
 1421     query = model_query(
 1422         context, models.ShareInstance, session=session, read_deleted="no",
 1423     ).options(
 1424         joinedload('export_locations'),
 1425     )
 1426 
 1427     filters = filters or {}
 1428 
 1429     export_location_id = filters.get('export_location_id')
 1430     export_location_path = filters.get('export_location_path')
 1431     if export_location_id or export_location_path:
 1432         query = query.join(
 1433             models.ShareInstanceExportLocations,
 1434             models.ShareInstanceExportLocations.share_instance_id ==
 1435             models.ShareInstance.id)
 1436         if export_location_path:
 1437             query = query.filter(
 1438                 models.ShareInstanceExportLocations.path ==
 1439                 export_location_path)
 1440         if export_location_id:
 1441             query = query.filter(
 1442                 models.ShareInstanceExportLocations.uuid ==
 1443                 export_location_id)
 1444 
 1445     # Returns list of share instances that satisfy filters.
 1446     query = query.all()
 1447     return query
 1448 
 1449 
 1450 @require_context
 1451 def share_instance_delete(context, instance_id, session=None,
 1452                           need_to_update_usages=False):
 1453     if session is None:
 1454         session = get_session()
 1455 
 1456     with session.begin():
 1457         share_export_locations_update(context, instance_id, [], delete=True)
 1458         instance_ref = share_instance_get(context, instance_id,
 1459                                           session=session)
 1460         instance_ref.soft_delete(session=session, update_status=True)
 1461         share = share_get(context, instance_ref['share_id'], session=session)
 1462         if len(share.instances) == 0:
 1463             share_access_delete_all_by_share(context, share['id'])
 1464             session.query(models.ShareMetadata).filter_by(
 1465                 share_id=share['id']).soft_delete()
 1466             share.soft_delete(session=session)
 1467 
 1468             if need_to_update_usages:
 1469                 reservations = None
 1470                 try:
 1471                     # we give the user_id of the share, to update
 1472                     # the quota usage for the user, who created the share
 1473                     reservations = QUOTAS.reserve(
 1474                         context,
 1475                         project_id=share['project_id'],
 1476                         shares=-1,
 1477                         gigabytes=-share['size'],
 1478                         user_id=share['user_id'],
 1479                         share_type_id=instance_ref['share_type_id'])
 1480                     QUOTAS.commit(
 1481                         context, reservations, project_id=share['project_id'],
 1482                         user_id=share['user_id'],
 1483                         share_type_id=instance_ref['share_type_id'])
 1484                 except Exception:
 1485                     LOG.exception(
 1486                         "Failed to update usages deleting share '%s'.",
 1487                         share["id"])
 1488                     if reservations:
 1489                         QUOTAS.rollback(
 1490                             context, reservations,
 1491                             share_type_id=instance_ref['share_type_id'])
 1492 
 1493 
 1494 def _set_instances_share_data(context, instances, session):
 1495     if instances and not isinstance(instances, list):
 1496         instances = [instances]
 1497 
 1498     instances_with_share_data = []
 1499     for instance in instances:
 1500         try:
 1501             parent_share = share_get(context, instance['share_id'],
 1502                                      session=session)
 1503         except exception.NotFound:
 1504             continue
 1505         instance.set_share_data(parent_share)
 1506         instances_with_share_data.append(instance)
 1507     return instances_with_share_data
 1508 
 1509 
 1510 @require_admin_context
 1511 def share_instances_get_all_by_host(context, host, with_share_data=False,
 1512                                     session=None):
 1513     """Retrieves all share instances hosted on a host."""
 1514     session = session or get_session()
 1515     instances = (
 1516         model_query(context, models.ShareInstance).filter(
 1517             or_(
 1518                 models.ShareInstance.host == host,
 1519                 models.ShareInstance.host.like("{0}#%".format(host))
 1520             )
 1521         ).all()
 1522     )
 1523 
 1524     if with_share_data:
 1525         instances = _set_instances_share_data(context, instances, session)
 1526     return instances
 1527 
 1528 
 1529 @require_context
 1530 def share_instances_get_all_by_share_network(context, share_network_id):
 1531     """Returns list of share instances that belong to given share network."""
 1532     result = (
 1533         model_query(context, models.ShareInstance).filter(
 1534             models.ShareInstance.share_network_id == share_network_id,
 1535         ).all()
 1536     )
 1537     return result
 1538 
 1539 
 1540 @require_context
 1541 def share_instances_get_all_by_share_server(context, share_server_id):
 1542     """Returns list of share instance with given share server."""
 1543     result = (
 1544         model_query(context, models.ShareInstance).filter(
 1545             models.ShareInstance.share_server_id == share_server_id,
 1546         ).all()
 1547     )
 1548     return result
 1549 
 1550 
 1551 @require_context
 1552 def share_instances_get_all_by_share(context, share_id):
 1553     """Returns list of share instances that belong to given share."""
 1554     result = (
 1555         model_query(context, models.ShareInstance).filter(
 1556             models.ShareInstance.share_id == share_id,
 1557         ).all()
 1558     )
 1559     return result
 1560 
 1561 
 1562 @require_context
 1563 def share_instances_get_all_by_share_group_id(context, share_group_id):
 1564     """Returns list of share instances that belong to given share group."""
 1565     result = (
 1566         model_query(context, models.Share).filter(
 1567             models.Share.share_group_id == share_group_id,
 1568         ).all()
 1569     )
 1570     instances = []
 1571     for share in result:
 1572         instance = share.instance
 1573         instance.set_share_data(share)
 1574         instances.append(instance)
 1575 
 1576     return instances
 1577 
 1578 
 1579 ################
 1580 
 1581 def _share_replica_get_with_filters(context, share_id=None, replica_id=None,
 1582                                     replica_state=None, status=None,
 1583                                     with_share_server=True, session=None):
 1584 
 1585     query = model_query(context, models.ShareInstance, session=session,
 1586                         read_deleted="no")
 1587 
 1588     if share_id is not None:
 1589         query = query.filter(models.ShareInstance.share_id == share_id)
 1590 
 1591     if replica_id is not None:
 1592         query = query.filter(models.ShareInstance.id == replica_id)
 1593 
 1594     if replica_state is not None:
 1595         query = query.filter(
 1596             models.ShareInstance.replica_state == replica_state)
 1597     else:
 1598         query = query.filter(models.ShareInstance.replica_state.isnot(None))
 1599 
 1600     if status is not None:
 1601         query = query.filter(models.ShareInstance.status == status)
 1602 
 1603     if with_share_server:
 1604         query = query.options(joinedload('share_server'))
 1605 
 1606     return query
 1607 
 1608 
 1609 def _set_replica_share_data(context, replicas, session):
 1610     if replicas and not isinstance(replicas, list):
 1611         replicas = [replicas]
 1612 
 1613     for replica in replicas:
 1614         parent_share = share_get(context, replica['share_id'], session=session)
 1615         replica.set_share_data(parent_share)
 1616 
 1617     return replicas
 1618 
 1619 
 1620 @require_context
 1621 def share_replicas_get_all(context, with_share_data=False,
 1622                            with_share_server=True, session=None):
 1623     """Returns replica instances for all available replicated shares."""
 1624     session = session or get_session()
 1625 
 1626     result = _share_replica_get_with_filters(
 1627         context, with_share_server=with_share_server, session=session).all()
 1628 
 1629     if with_share_data:
 1630         result = _set_replica_share_data(context, result, session)
 1631 
 1632     return result
 1633 
 1634 
 1635 @require_context
 1636 def share_replicas_get_all_by_share(context, share_id,
 1637                                     with_share_data=False,
 1638                                     with_share_server=False, session=None):
 1639     """Returns replica instances for a given share."""
 1640     session = session or get_session()
 1641 
 1642     result = _share_replica_get_with_filters(
 1643         context, with_share_server=with_share_server,
 1644         share_id=share_id, session=session).all()
 1645 
 1646     if with_share_data:
 1647         result = _set_replica_share_data(context, result, session)
 1648 
 1649     return result
 1650 
 1651 
 1652 @require_context
 1653 def share_replicas_get_available_active_replica(context, share_id,
 1654                                                 with_share_data=False,
 1655                                                 with_share_server=False,
 1656                                                 session=None):
 1657     """Returns an 'active' replica instance that is 'available'."""
 1658     session = session or get_session()
 1659 
 1660     result = _share_replica_get_with_filters(
 1661         context, with_share_server=with_share_server, share_id=share_id,
 1662         replica_state=constants.REPLICA_STATE_ACTIVE,
 1663         status=constants.STATUS_AVAILABLE, session=session).first()
 1664 
 1665     if result and with_share_data:
 1666         result = _set_replica_share_data(context, result, session)[0]
 1667 
 1668     return result
 1669 
 1670 
 1671 @require_context
 1672 def share_replica_get(context, replica_id, with_share_data=False,
 1673                       with_share_server=False, session=None):
 1674     """Returns summary of requested replica if available."""
 1675     session = session or get_session()
 1676 
 1677     result = _share_replica_get_with_filters(
 1678         context, with_share_server=with_share_server,
 1679         replica_id=replica_id, session=session).first()
 1680 
 1681     if result is None:
 1682         raise exception.ShareReplicaNotFound(replica_id=replica_id)
 1683 
 1684     if with_share_data:
 1685         result = _set_replica_share_data(context, result, session)[0]
 1686 
 1687     return result
 1688 
 1689 
 1690 @require_context
 1691 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 1692 def share_replica_update(context, share_replica_id, values,
 1693                          with_share_data=False, session=None):
 1694     """Updates a share replica with specified values."""
 1695     session = session or get_session()
 1696 
 1697     with session.begin():
 1698         _ensure_availability_zone_exists(context, values, session,
 1699                                          strict=False)
 1700         updated_share_replica = _share_instance_update(
 1701             context, share_replica_id, values, session=session)
 1702 
 1703         if with_share_data:
 1704             updated_share_replica = _set_replica_share_data(
 1705                 context, updated_share_replica, session)[0]
 1706 
 1707     return updated_share_replica
 1708 
 1709 
 1710 @require_context
 1711 def share_replica_delete(context, share_replica_id, session=None):
 1712     """Deletes a share replica."""
 1713     session = session or get_session()
 1714 
 1715     share_instance_delete(context, share_replica_id, session=session)
 1716 
 1717 
 1718 ################
 1719 
 1720 
 1721 def _share_get_query(context, session=None):
 1722     if session is None:
 1723         session = get_session()
 1724     return (model_query(context, models.Share, session=session).
 1725             options(joinedload('share_metadata')))
 1726 
 1727 
 1728 def _metadata_refs(metadata_dict, meta_class):
 1729     metadata_refs = []
 1730     if metadata_dict:
 1731         for k, v in metadata_dict.items():
 1732             value = six.text_type(v) if isinstance(v, bool) else v
 1733 
 1734             metadata_ref = meta_class()
 1735             metadata_ref['key'] = k
 1736             metadata_ref['value'] = value
 1737             metadata_refs.append(metadata_ref)
 1738     return metadata_refs
 1739 
 1740 
 1741 @require_context
 1742 def share_create(context, share_values, create_share_instance=True):
 1743     values = copy.deepcopy(share_values)
 1744     values = ensure_model_dict_has_id(values)
 1745     values['share_metadata'] = _metadata_refs(values.get('metadata'),
 1746                                               models.ShareMetadata)
 1747     session = get_session()
 1748     share_ref = models.Share()
 1749     share_instance_values, share_values = _extract_share_instance_values(
 1750         values)
 1751     _ensure_availability_zone_exists(context, share_instance_values, session,
 1752                                      strict=False)
 1753     share_ref.update(share_values)
 1754 
 1755     with session.begin():
 1756         share_ref.save(session=session)
 1757 
 1758         if create_share_instance:
 1759             _share_instance_create(context, share_ref['id'],
 1760                                    share_instance_values, session=session)
 1761 
 1762         # NOTE(u_glide): Do so to prevent errors with relationships
 1763         return share_get(context, share_ref['id'], session=session)
 1764 
 1765 
 1766 @require_admin_context
 1767 def share_data_get_for_project(context, project_id, user_id,
 1768                                share_type_id=None, session=None):
 1769     query = (model_query(context, models.Share,
 1770                          func.count(models.Share.id),
 1771                          func.sum(models.Share.size),
 1772                          read_deleted="no",
 1773                          session=session).
 1774              filter_by(project_id=project_id))
 1775     if share_type_id:
 1776         query = query.join("instances").filter_by(share_type_id=share_type_id)
 1777     elif user_id:
 1778         query = query.filter_by(user_id=user_id)
 1779     result = query.first()
 1780     return (result[0] or 0, result[1] or 0)
 1781 
 1782 
 1783 @require_context
 1784 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 1785 def share_update(context, share_id, update_values):
 1786     session = get_session()
 1787     values = copy.deepcopy(update_values)
 1788 
 1789     share_instance_values, share_values = _extract_share_instance_values(
 1790         values)
 1791     _ensure_availability_zone_exists(context, share_instance_values, session,
 1792                                      strict=False)
 1793 
 1794     with session.begin():
 1795         share_ref = share_get(context, share_id, session=session)
 1796 
 1797         _share_instance_update(context, share_ref.instance['id'],
 1798                                share_instance_values, session=session)
 1799 
 1800         share_ref.update(share_values)
 1801         share_ref.save(session=session)
 1802         return share_ref
 1803 
 1804 
 1805 @require_context
 1806 def share_get(context, share_id, session=None):
 1807     result = _share_get_query(context, session).filter_by(id=share_id).first()
 1808 
 1809     if result is None:
 1810         raise exception.NotFound()
 1811 
 1812     return result
 1813 
 1814 
 1815 def _share_get_all_with_filters(context, project_id=None, share_server_id=None,
 1816                                 share_group_id=None, filters=None,
 1817                                 is_public=False, sort_key=None,
 1818                                 sort_dir=None):
 1819     """Returns sorted list of shares that satisfies filters.
 1820 
 1821     :param context: context to query under
 1822     :param project_id: project id that owns shares
 1823     :param share_server_id: share server that hosts shares
 1824     :param filters: dict of filters to specify share selection
 1825     :param is_public: public shares from other projects will be added
 1826                       to result if True
 1827     :param sort_key: key of models.Share to be used for sorting
 1828     :param sort_dir: desired direction of sorting, can be 'asc' and 'desc'
 1829     :returns: list -- models.Share
 1830     :raises: exception.InvalidInput
 1831     """
 1832     if not sort_key:
 1833         sort_key = 'created_at'
 1834     if not sort_dir:
 1835         sort_dir = 'desc'
 1836     query = (
 1837         _share_get_query(context).join(
 1838             models.ShareInstance,
 1839             models.ShareInstance.share_id == models.Share.id
 1840         )
 1841     )
 1842 
 1843     if project_id:
 1844         if is_public:
 1845             query = query.filter(or_(models.Share.project_id == project_id,
 1846                                      models.Share.is_public))
 1847         else:
 1848             query = query.filter(models.Share.project_id == project_id)
 1849     if share_server_id:
 1850         query = query.filter(
 1851             models.ShareInstance.share_server_id == share_server_id)
 1852 
 1853     if share_group_id:
 1854         query = query.filter(
 1855             models.Share.share_group_id == share_group_id)
 1856 
 1857     # Apply filters
 1858     if not filters:
 1859         filters = {}
 1860 
 1861     export_location_id = filters.get('export_location_id')
 1862     export_location_path = filters.get('export_location_path')
 1863     if export_location_id or export_location_path:
 1864         query = query.join(
 1865             models.ShareInstanceExportLocations,
 1866             models.ShareInstanceExportLocations.share_instance_id ==
 1867             models.ShareInstance.id)
 1868         if export_location_path:
 1869             query = query.filter(
 1870                 models.ShareInstanceExportLocations.path ==
 1871                 export_location_path)
 1872         if export_location_id:
 1873             query = query.filter(
 1874                 models.ShareInstanceExportLocations.uuid ==
 1875                 export_location_id)
 1876 
 1877     if 'metadata' in filters:
 1878         for k, v in filters['metadata'].items():
 1879             # pylint: disable=no-member
 1880             query = query.filter(
 1881                 or_(models.Share.share_metadata.any(
 1882                     key=k, value=v)))
 1883     if 'extra_specs' in filters:
 1884         query = query.join(
 1885             models.ShareTypeExtraSpecs,
 1886             models.ShareTypeExtraSpecs.share_type_id ==
 1887             models.ShareInstance.share_type_id)
 1888         for k, v in filters['extra_specs'].items():
 1889             query = query.filter(or_(models.ShareTypeExtraSpecs.key == k,
 1890                                      models.ShareTypeExtraSpecs.value == v))
 1891 
 1892     try:
 1893         query = apply_sorting(models.Share, query, sort_key, sort_dir)
 1894     except AttributeError:
 1895         try:
 1896             query = apply_sorting(
 1897                 models.ShareInstance, query, sort_key, sort_dir)
 1898         except AttributeError:
 1899             msg = _("Wrong sorting key provided - '%s'.") % sort_key
 1900             raise exception.InvalidInput(reason=msg)
 1901 
 1902     if 'limit' in filters:
 1903         offset = filters.get('offset', 0)
 1904         query = query.limit(filters['limit']).offset(offset)
 1905 
 1906     # Returns list of shares that satisfy filters.
 1907     query = query.all()
 1908     return query
 1909 
 1910 
 1911 @require_admin_context
 1912 def share_get_all(context, filters=None, sort_key=None, sort_dir=None):
 1913     query = _share_get_all_with_filters(
 1914         context, filters=filters, sort_key=sort_key, sort_dir=sort_dir)
 1915     return query
 1916 
 1917 
 1918 @require_context
 1919 def share_get_all_by_project(context, project_id, filters=None,
 1920                              is_public=False, sort_key=None, sort_dir=None):
 1921     """Returns list of shares with given project ID."""
 1922     query = _share_get_all_with_filters(
 1923         context, project_id=project_id, filters=filters, is_public=is_public,
 1924         sort_key=sort_key, sort_dir=sort_dir,
 1925     )
 1926     return query
 1927 
 1928 
 1929 @require_context
 1930 def share_get_all_by_share_group_id(context, share_group_id,
 1931                                     filters=None, sort_key=None,
 1932                                     sort_dir=None):
 1933     """Returns list of shares with given group ID."""
 1934     query = _share_get_all_with_filters(
 1935         context, share_group_id=share_group_id,
 1936         filters=filters, sort_key=sort_key, sort_dir=sort_dir,
 1937     )
 1938     return query
 1939 
 1940 
 1941 @require_context
 1942 def share_get_all_by_share_server(context, share_server_id, filters=None,
 1943                                   sort_key=None, sort_dir=None):
 1944     """Returns list of shares with given share server."""
 1945     query = _share_get_all_with_filters(
 1946         context, share_server_id=share_server_id, filters=filters,
 1947         sort_key=sort_key, sort_dir=sort_dir,
 1948     )
 1949     return query
 1950 
 1951 
 1952 @require_context
 1953 def share_delete(context, share_id):
 1954     session = get_session()
 1955 
 1956     with session.begin():
 1957         share_ref = share_get(context, share_id, session)
 1958 
 1959         if len(share_ref.instances) > 0:
 1960             msg = _("Share %(id)s has %(count)s share instances.") % {
 1961                 'id': share_id, 'count': len(share_ref.instances)}
 1962             raise exception.InvalidShare(msg)
 1963 
 1964         share_ref.soft_delete(session=session)
 1965 
 1966         (session.query(models.ShareMetadata).
 1967             filter_by(share_id=share_id).soft_delete())
 1968 
 1969 
 1970 ###################
 1971 
 1972 
 1973 def _share_access_get_query(context, session, values, read_deleted='no'):
 1974     """Get access record."""
 1975     query = (model_query(
 1976         context, models.ShareAccessMapping, session=session,
 1977         read_deleted=read_deleted).options(
 1978             joinedload('share_access_rules_metadata')))
 1979     return query.filter_by(**values)
 1980 
 1981 
 1982 def _share_instance_access_query(context, session, access_id=None,
 1983                                  instance_id=None):
 1984     filters = {'deleted': 'False'}
 1985 
 1986     if access_id is not None:
 1987         filters.update({'access_id': access_id})
 1988 
 1989     if instance_id is not None:
 1990         filters.update({'share_instance_id': instance_id})
 1991 
 1992     return model_query(context, models.ShareInstanceAccessMapping,
 1993                        session=session).filter_by(**filters)
 1994 
 1995 
 1996 def _share_access_metadata_get_item(context, access_id, key, session=None):
 1997     result = (_share_access_metadata_get_query(
 1998         context, access_id, session=session).filter_by(key=key).first())
 1999     if not result:
 2000         raise exception.ShareAccessMetadataNotFound(
 2001             metadata_key=key, access_id=access_id)
 2002     return result
 2003 
 2004 
 2005 def _share_access_metadata_get_query(context, access_id, session=None):
 2006     return (model_query(
 2007         context, models.ShareAccessRulesMetadata, session=session,
 2008         read_deleted="no").
 2009         filter_by(access_id=access_id).
 2010         options(joinedload('access')))
 2011 
 2012 
 2013 @require_context
 2014 def share_access_metadata_update(context, access_id, metadata):
 2015     session = get_session()
 2016 
 2017     with session.begin():
 2018         # Now update all existing items with new values, or create new meta
 2019         # objects
 2020         for meta_key, meta_value in metadata.items():
 2021 
 2022             # update the value whether it exists or not
 2023             item = {"value": meta_value}
 2024             try:
 2025                 meta_ref = _share_access_metadata_get_item(
 2026                     context, access_id, meta_key, session=session)
 2027             except exception.ShareAccessMetadataNotFound:
 2028                 meta_ref = models.ShareAccessRulesMetadata()
 2029                 item.update({"key": meta_key, "access_id": access_id})
 2030 
 2031             meta_ref.update(item)
 2032             meta_ref.save(session=session)
 2033 
 2034         return metadata
 2035 
 2036 
 2037 @require_context
 2038 def share_access_metadata_delete(context, access_id, key):
 2039     session = get_session()
 2040     with session.begin():
 2041         metadata = _share_access_metadata_get_item(
 2042             context, access_id, key, session=session)
 2043 
 2044         metadata.soft_delete(session)
 2045 
 2046 
 2047 @require_context
 2048 def share_access_create(context, values):
 2049     values = ensure_model_dict_has_id(values)
 2050     session = get_session()
 2051     with session.begin():
 2052         values['share_access_rules_metadata'] = (
 2053             _metadata_refs(values.get('metadata'),
 2054                            models.ShareAccessRulesMetadata))
 2055 
 2056         access_ref = models.ShareAccessMapping()
 2057         access_ref.update(values)
 2058         access_ref.save(session=session)
 2059 
 2060         parent_share = share_get(context, values['share_id'], session=session)
 2061 
 2062         for instance in parent_share.instances:
 2063             vals = {
 2064                 'share_instance_id': instance['id'],
 2065                 'access_id': access_ref['id'],
 2066             }
 2067 
 2068             _share_instance_access_create(vals, session)
 2069 
 2070     return share_access_get(context, access_ref['id'])
 2071 
 2072 
 2073 @require_context
 2074 def share_instance_access_create(context, values, share_instance_id):
 2075     values = ensure_model_dict_has_id(values)
 2076     session = get_session()
 2077     with session.begin():
 2078         access_list = _share_access_get_query(
 2079             context, session, {
 2080                 'share_id': values['share_id'],
 2081                 'access_type': values['access_type'],
 2082                 'access_to': values['access_to'],
 2083             }).all()
 2084         if len(access_list) > 0:
 2085             access_ref = access_list[0]
 2086         else:
 2087             access_ref = models.ShareAccessMapping()
 2088         access_ref.update(values)
 2089         access_ref.save(session=session)
 2090 
 2091         vals = {
 2092             'share_instance_id': share_instance_id,
 2093             'access_id': access_ref['id'],
 2094         }
 2095 
 2096         _share_instance_access_create(vals, session)
 2097 
 2098     return share_access_get(context, access_ref['id'])
 2099 
 2100 
 2101 @require_context
 2102 def share_instance_access_copy(context, share_id, instance_id, session=None):
 2103     """Copy access rules from share to share instance."""
 2104     session = session or get_session()
 2105 
 2106     share_access_rules = _share_access_get_query(
 2107         context, session, {'share_id': share_id}).all()
 2108 
 2109     for access_rule in share_access_rules:
 2110         values = {
 2111             'share_instance_id': instance_id,
 2112             'access_id': access_rule['id'],
 2113         }
 2114 
 2115         _share_instance_access_create(values, session)
 2116 
 2117     return share_access_rules
 2118 
 2119 
 2120 def _share_instance_access_create(values, session):
 2121     access_ref = models.ShareInstanceAccessMapping()
 2122     access_ref.update(ensure_model_dict_has_id(values))
 2123     access_ref.save(session=session)
 2124     return access_ref
 2125 
 2126 
 2127 @require_context
 2128 def share_access_get(context, access_id, session=None):
 2129     """Get access record."""
 2130     session = session or get_session()
 2131 
 2132     access = _share_access_get_query(
 2133         context, session, {'id': access_id}).first()
 2134     if access:
 2135         return access
 2136     else:
 2137         raise exception.NotFound()
 2138 
 2139 
 2140 @require_context
 2141 def share_instance_access_get(context, access_id, instance_id,
 2142                               with_share_access_data=True):
 2143     """Get access record."""
 2144     session = get_session()
 2145 
 2146     access = _share_instance_access_query(context, session, access_id,
 2147                                           instance_id).first()
 2148     if access is None:
 2149         raise exception.NotFound()
 2150 
 2151     if with_share_access_data:
 2152         access = _set_instances_share_access_data(context, access, session)[0]
 2153 
 2154     return access
 2155 
 2156 
 2157 @require_context
 2158 def share_access_get_all_for_share(context, share_id, filters=None,
 2159                                    session=None):
 2160     filters = filters or {}
 2161     session = session or get_session()
 2162     query = (_share_access_get_query(
 2163         context, session, {'share_id': share_id}).filter(
 2164         models.ShareAccessMapping.instance_mappings.any()))
 2165 
 2166     if 'metadata' in filters:
 2167         for k, v in filters['metadata'].items():
 2168             query = query.filter(
 2169                 or_(models.ShareAccessMapping.
 2170                     share_access_rules_metadata.any(key=k, value=v)))
 2171 
 2172     return query.all()
 2173 
 2174 
 2175 @require_context
 2176 def share_access_get_all_for_instance(context, instance_id, filters=None,
 2177                                       with_share_access_data=True,
 2178                                       session=None):
 2179     """Get all access rules related to a certain share instance."""
 2180     session = session or get_session()
 2181     filters = copy.deepcopy(filters) if filters else {}
 2182     filters.update({'share_instance_id': instance_id})
 2183     legal_filter_keys = ('id', 'share_instance_id', 'access_id', 'state')
 2184     query = _share_instance_access_query(context, session)
 2185 
 2186     query = exact_filter(
 2187         query, models.ShareInstanceAccessMapping, filters, legal_filter_keys)
 2188 
 2189     instance_accesses = query.all()
 2190 
 2191     if with_share_access_data:
 2192         instance_accesses = _set_instances_share_access_data(
 2193             context, instance_accesses, session)
 2194 
 2195     return instance_accesses
 2196 
 2197 
 2198 def _set_instances_share_access_data(context, instance_accesses, session):
 2199     if instance_accesses and not isinstance(instance_accesses, list):
 2200         instance_accesses = [instance_accesses]
 2201 
 2202     for instance_access in instance_accesses:
 2203         share_access = share_access_get(
 2204             context, instance_access['access_id'], session=session)
 2205         instance_access.set_share_access_data(share_access)
 2206 
 2207     return instance_accesses
 2208 
 2209 
 2210 def _set_instances_snapshot_access_data(context, instance_accesses, session):
 2211     if instance_accesses and not isinstance(instance_accesses, list):
 2212         instance_accesses = [instance_accesses]
 2213 
 2214     for instance_access in instance_accesses:
 2215         snapshot_access = share_snapshot_access_get(
 2216             context, instance_access['access_id'], session=session)
 2217         instance_access.set_snapshot_access_data(snapshot_access)
 2218 
 2219     return instance_accesses
 2220 
 2221 
 2222 @require_context
 2223 def share_access_get_all_by_type_and_access(context, share_id, access_type,
 2224                                             access):
 2225     session = get_session()
 2226     return _share_access_get_query(context, session,
 2227                                    {'share_id': share_id,
 2228                                     'access_type': access_type,
 2229                                     'access_to': access}).all()
 2230 
 2231 
 2232 @require_context
 2233 def share_access_check_for_existing_access(context, share_id, access_type,
 2234                                            access_to):
 2235     return _check_for_existing_access(
 2236         context, 'share', share_id, access_type, access_to)
 2237 
 2238 
 2239 def _check_for_existing_access(context, resource, resource_id, access_type,
 2240                                access_to):
 2241 
 2242     session = get_session()
 2243     if resource == 'share':
 2244         query_method = _share_access_get_query
 2245         access_to_field = models.ShareAccessMapping.access_to
 2246     else:
 2247         query_method = _share_snapshot_access_get_query
 2248         access_to_field = models.ShareSnapshotAccessMapping.access_to
 2249 
 2250     with session.begin():
 2251         if access_type == 'ip':
 2252             rules = query_method(
 2253                 context, session, {'%s_id' % resource: resource_id,
 2254                                    'access_type': access_type}).filter(
 2255                 access_to_field.startswith(access_to.split('/')[0])).all()
 2256 
 2257             matching_rules = [
 2258                 rule for rule in rules if
 2259                 ipaddress.ip_network(six.text_type(access_to)) ==
 2260                 ipaddress.ip_network(six.text_type(rule['access_to']))
 2261             ]
 2262             return len(matching_rules) > 0
 2263         else:
 2264             return query_method(
 2265                 context, session, {'%s_id' % resource: resource_id,
 2266                                    'access_type': access_type,
 2267                                    'access_to': access_to}).count() > 0
 2268 
 2269 
 2270 @require_context
 2271 def share_access_delete_all_by_share(context, share_id):
 2272     session = get_session()
 2273     with session.begin():
 2274         (session.query(models.ShareAccessMapping).
 2275             filter_by(share_id=share_id).soft_delete())
 2276 
 2277 
 2278 @require_context
 2279 def share_instance_access_delete(context, mapping_id):
 2280     session = get_session()
 2281     with session.begin():
 2282 
 2283         mapping = (session.query(models.ShareInstanceAccessMapping).
 2284                    filter_by(id=mapping_id).first())
 2285 
 2286         if not mapping:
 2287             exception.NotFound()
 2288 
 2289         mapping.soft_delete(session, update_status=True,
 2290                             status_field_name='state')
 2291 
 2292         other_mappings = _share_instance_access_query(
 2293             context, session, mapping['access_id']).all()
 2294 
 2295         # NOTE(u_glide): Remove access rule if all mappings were removed.
 2296         if len(other_mappings) == 0:
 2297             (session.query(models.ShareAccessRulesMetadata).filter_by(
 2298                 access_id=mapping['access_id']).soft_delete())
 2299 
 2300             (session.query(models.ShareAccessMapping).filter_by(
 2301                 id=mapping['access_id']).soft_delete())
 2302 
 2303 
 2304 @require_context
 2305 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 2306 def share_instance_access_update(context, access_id, instance_id, updates):
 2307     session = get_session()
 2308     share_access_fields = ('access_type', 'access_to', 'access_key',
 2309                            'access_level')
 2310 
 2311     share_access_map_updates, share_instance_access_map_updates = (
 2312         _extract_subdict_by_fields(updates, share_access_fields)
 2313     )
 2314 
 2315     with session.begin():
 2316         share_access = _share_access_get_query(
 2317             context, session, {'id': access_id}).first()
 2318         share_access.update(share_access_map_updates)
 2319         share_access.save(session=session)
 2320 
 2321         access = _share_instance_access_query(
 2322             context, session, access_id, instance_id).first()
 2323         access.update(share_instance_access_map_updates)
 2324         access.save(session=session)
 2325 
 2326         return access
 2327 
 2328 ###################
 2329 
 2330 
 2331 @require_context
 2332 def share_snapshot_instance_create(context, snapshot_id, values, session=None):
 2333     session = session or get_session()
 2334     values = copy.deepcopy(values)
 2335 
 2336     _change_size_to_instance_size(values)
 2337 
 2338     if not values.get('id'):
 2339         values['id'] = uuidutils.generate_uuid()
 2340     values.update({'snapshot_id': snapshot_id})
 2341 
 2342     instance_ref = models.ShareSnapshotInstance()
 2343     instance_ref.update(values)
 2344     instance_ref.save(session=session)
 2345 
 2346     return share_snapshot_instance_get(context, instance_ref['id'],
 2347                                        session=session)
 2348 
 2349 
 2350 @require_context
 2351 def share_snapshot_instance_update(context, instance_id, values):
 2352     session = get_session()
 2353     instance_ref = share_snapshot_instance_get(context, instance_id,
 2354                                                session=session)
 2355     _change_size_to_instance_size(values)
 2356 
 2357     # NOTE(u_glide): Ignore updates to custom properties
 2358     for extra_key in models.ShareSnapshotInstance._extra_keys:
 2359         if extra_key in values:
 2360             values.pop(extra_key)
 2361 
 2362     instance_ref.update(values)
 2363     instance_ref.save(session=session)
 2364     return instance_ref
 2365 
 2366 
 2367 @require_context
 2368 def share_snapshot_instance_delete(context, snapshot_instance_id,
 2369                                    session=None):
 2370     session = session or get_session()
 2371 
 2372     with session.begin():
 2373 
 2374         snapshot_instance_ref = share_snapshot_instance_get(
 2375             context, snapshot_instance_id, session=session)
 2376 
 2377         access_rules = share_snapshot_access_get_all_for_snapshot_instance(
 2378             context, snapshot_instance_id, session=session)
 2379         for rule in access_rules:
 2380             share_snapshot_instance_access_delete(
 2381                 context, rule['access_id'], snapshot_instance_id)
 2382 
 2383         for el in snapshot_instance_ref.export_locations:
 2384             share_snapshot_instance_export_location_delete(context, el['id'])
 2385 
 2386         snapshot_instance_ref.soft_delete(
 2387             session=session, update_status=True)
 2388         snapshot = share_snapshot_get(
 2389             context, snapshot_instance_ref['snapshot_id'], session=session)
 2390         if len(snapshot.instances) == 0:
 2391             snapshot.soft_delete(session=session)
 2392 
 2393 
 2394 @require_context
 2395 def share_snapshot_instance_get(context, snapshot_instance_id, session=None,
 2396                                 with_share_data=False):
 2397 
 2398     session = session or get_session()
 2399 
 2400     result = _share_snapshot_instance_get_with_filters(
 2401         context, instance_ids=[snapshot_instance_id], session=session).first()
 2402 
 2403     if result is None:
 2404         raise exception.ShareSnapshotInstanceNotFound(
 2405             instance_id=snapshot_instance_id)
 2406 
 2407     if with_share_data:
 2408         result = _set_share_snapshot_instance_data(context, result, session)[0]
 2409 
 2410     return result
 2411 
 2412 
 2413 @require_context
 2414 def share_snapshot_instance_get_all_with_filters(context, search_filters,
 2415                                                  with_share_data=False,
 2416                                                  session=None):
 2417     """Get snapshot instances filtered by known attrs, ignore unknown attrs.
 2418 
 2419     All filters accept list/tuples to filter on, along with simple values.
 2420     """
 2421     def listify(values):
 2422         if values:
 2423             if not isinstance(values, (list, tuple, set)):
 2424                 return values,
 2425             else:
 2426                 return values
 2427 
 2428     session = session or get_session()
 2429     _known_filters = ('instance_ids', 'snapshot_ids', 'share_instance_ids',
 2430                       'statuses')
 2431 
 2432     filters = {k: listify(search_filters.get(k)) for k in _known_filters}
 2433 
 2434     result = _share_snapshot_instance_get_with_filters(
 2435         context, session=session, **filters).all()
 2436 
 2437     if with_share_data:
 2438         result = _set_share_snapshot_instance_data(context, result, session)
 2439 
 2440     return result
 2441 
 2442 
 2443 def _share_snapshot_instance_get_with_filters(context, instance_ids=None,
 2444                                               snapshot_ids=None, statuses=None,
 2445                                               share_instance_ids=None,
 2446                                               session=None):
 2447 
 2448     query = model_query(context, models.ShareSnapshotInstance, session=session,
 2449                         read_deleted="no")
 2450 
 2451     if instance_ids is not None:
 2452         query = query.filter(
 2453             models.ShareSnapshotInstance.id.in_(instance_ids))
 2454 
 2455     if snapshot_ids is not None:
 2456         query = query.filter(
 2457             models.ShareSnapshotInstance.snapshot_id.in_(snapshot_ids))
 2458 
 2459     if share_instance_ids is not None:
 2460         query = query.filter(models.ShareSnapshotInstance.share_instance_id
 2461                              .in_(share_instance_ids))
 2462 
 2463     if statuses is not None:
 2464         query = query.filter(models.ShareSnapshotInstance.status.in_(statuses))
 2465 
 2466     query = query.options(joinedload('share_group_snapshot'))
 2467     return query
 2468 
 2469 
 2470 def _set_share_snapshot_instance_data(context, snapshot_instances, session):
 2471     if snapshot_instances and not isinstance(snapshot_instances, list):
 2472         snapshot_instances = [snapshot_instances]
 2473 
 2474     for snapshot_instance in snapshot_instances:
 2475         share_instance = share_instance_get(
 2476             context, snapshot_instance['share_instance_id'], session=session,
 2477             with_share_data=True)
 2478         snapshot_instance['share'] = share_instance
 2479 
 2480     return snapshot_instances
 2481 
 2482 
 2483 ###################
 2484 
 2485 
 2486 @require_context
 2487 def share_snapshot_create(context, create_values,
 2488                           create_snapshot_instance=True):
 2489     values = copy.deepcopy(create_values)
 2490     values = ensure_model_dict_has_id(values)
 2491 
 2492     snapshot_ref = models.ShareSnapshot()
 2493     snapshot_instance_values, snapshot_values = (
 2494         _extract_snapshot_instance_values(values)
 2495     )
 2496     share_ref = share_get(context, snapshot_values.get('share_id'))
 2497     snapshot_instance_values.update(
 2498         {'share_instance_id': share_ref.instance.id}
 2499     )
 2500 
 2501     snapshot_ref.update(snapshot_values)
 2502     session = get_session()
 2503     with session.begin():
 2504         snapshot_ref.save(session=session)
 2505 
 2506         if create_snapshot_instance:
 2507             share_snapshot_instance_create(
 2508                 context,
 2509                 snapshot_ref['id'],
 2510                 snapshot_instance_values,
 2511                 session=session
 2512             )
 2513         return share_snapshot_get(
 2514             context, snapshot_values['id'], session=session)
 2515 
 2516 
 2517 @require_admin_context
 2518 def snapshot_data_get_for_project(context, project_id, user_id,
 2519                                   share_type_id=None, session=None):
 2520     query = (model_query(context, models.ShareSnapshot,
 2521                          func.count(models.ShareSnapshot.id),
 2522                          func.sum(models.ShareSnapshot.size),
 2523                          read_deleted="no",
 2524                          session=session).
 2525              filter_by(project_id=project_id))
 2526 
 2527     if share_type_id:
 2528         query = query.join(
 2529             models.ShareInstance,
 2530             models.ShareInstance.share_id == models.ShareSnapshot.share_id,
 2531         ).filter_by(share_type_id=share_type_id)
 2532     elif user_id:
 2533         query = query.filter_by(user_id=user_id)
 2534     result = query.first()
 2535 
 2536     return (result[0] or 0, result[1] or 0)
 2537 
 2538 
 2539 @require_context
 2540 def share_snapshot_get(context, snapshot_id, session=None):
 2541     result = (model_query(context, models.ShareSnapshot, session=session,
 2542                           project_only=True).
 2543               filter_by(id=snapshot_id).
 2544               options(joinedload('share')).
 2545               options(joinedload('instances')).
 2546               first())
 2547 
 2548     if not result:
 2549         raise exception.ShareSnapshotNotFound(snapshot_id=snapshot_id)
 2550 
 2551     return result
 2552 
 2553 
 2554 def _share_snapshot_get_all_with_filters(context, project_id=None,
 2555                                          share_id=None, filters=None,
 2556                                          sort_key=None, sort_dir=None):
 2557     # Init data
 2558     sort_key = sort_key or 'share_id'
 2559     sort_dir = sort_dir or 'desc'
 2560     filters = filters or {}
 2561     query = model_query(context, models.ShareSnapshot)
 2562 
 2563     if project_id:
 2564         query = query.filter_by(project_id=project_id)
 2565     if share_id:
 2566         query = query.filter_by(share_id=share_id)
 2567     query = query.options(joinedload('share'))
 2568     query = query.options(joinedload('instances'))
 2569 
 2570     # Apply filters
 2571     if 'usage' in filters:
 2572         usage_filter_keys = ['any', 'used', 'unused']
 2573         if filters['usage'] == 'any':
 2574             pass
 2575         elif filters['usage'] == 'used':
 2576             query = query.filter(or_(models.Share.snapshot_id == (
 2577                 models.ShareSnapshot.id)))
 2578         elif filters['usage'] == 'unused':
 2579             query = query.filter(or_(models.Share.snapshot_id != (
 2580                 models.ShareSnapshot.id)))
 2581         else:
 2582             msg = _("Wrong 'usage' key provided - '%(key)s'. "
 2583                     "Expected keys are '%(ek)s'.") % {
 2584                         'key': filters['usage'],
 2585                         'ek': six.text_type(usage_filter_keys)}
 2586             raise exception.InvalidInput(reason=msg)
 2587 
 2588     # Apply sorting
 2589     try:
 2590         attr = getattr(models.ShareSnapshot, sort_key)
 2591     except AttributeError:
 2592         msg = _("Wrong sorting key provided - '%s'.") % sort_key
 2593         raise exception.InvalidInput(reason=msg)
 2594     if sort_dir.lower() == 'desc':
 2595         query = query.order_by(attr.desc())
 2596     elif sort_dir.lower() == 'asc':
 2597         query = query.order_by(attr.asc())
 2598     else:
 2599         msg = _("Wrong sorting data provided: sort key is '%(sort_key)s' "
 2600                 "and sort direction is '%(sort_dir)s'.") % {
 2601                     "sort_key": sort_key, "sort_dir": sort_dir}
 2602         raise exception.InvalidInput(reason=msg)
 2603 
 2604     # Returns list of shares that satisfy filters
 2605     return query.all()
 2606 
 2607 
 2608 @require_admin_context
 2609 def share_snapshot_get_all(context, filters=None, sort_key=None,
 2610                            sort_dir=None):
 2611     return _share_snapshot_get_all_with_filters(
 2612         context, filters=filters, sort_key=sort_key, sort_dir=sort_dir,
 2613     )
 2614 
 2615 
 2616 @require_context
 2617 def share_snapshot_get_all_by_project(context, project_id, filters=None,
 2618                                       sort_key=None, sort_dir=None):
 2619     authorize_project_context(context, project_id)
 2620     return _share_snapshot_get_all_with_filters(
 2621         context, project_id=project_id,
 2622         filters=filters, sort_key=sort_key, sort_dir=sort_dir,
 2623     )
 2624 
 2625 
 2626 @require_context
 2627 def share_snapshot_get_all_for_share(context, share_id, filters=None,
 2628                                      sort_key=None, sort_dir=None):
 2629     return _share_snapshot_get_all_with_filters(
 2630         context, share_id=share_id,
 2631         filters=filters, sort_key=sort_key, sort_dir=sort_dir,
 2632     )
 2633 
 2634 
 2635 @require_context
 2636 def share_snapshot_get_latest_for_share(context, share_id):
 2637 
 2638     snapshots = _share_snapshot_get_all_with_filters(
 2639         context, share_id=share_id, sort_key='created_at', sort_dir='desc')
 2640     return snapshots[0] if snapshots else None
 2641 
 2642 
 2643 @require_context
 2644 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 2645 def share_snapshot_update(context, snapshot_id, values):
 2646     session = get_session()
 2647     with session.begin():
 2648         snapshot_ref = share_snapshot_get(context, snapshot_id,
 2649                                           session=session)
 2650 
 2651         instance_values, snapshot_values = (
 2652             _extract_snapshot_instance_values(values)
 2653         )
 2654 
 2655         if snapshot_values:
 2656             snapshot_ref.update(snapshot_values)
 2657             snapshot_ref.save(session=session)
 2658 
 2659         if instance_values:
 2660             snapshot_ref.instance.update(instance_values)
 2661             snapshot_ref.instance.save(session=session)
 2662 
 2663         return snapshot_ref
 2664 
 2665 #################################
 2666 
 2667 
 2668 @require_context
 2669 def share_snapshot_access_create(context, values):
 2670     values = ensure_model_dict_has_id(values)
 2671     session = get_session()
 2672     with session.begin():
 2673         access_ref = models.ShareSnapshotAccessMapping()
 2674         access_ref.update(values)
 2675         access_ref.save(session=session)
 2676 
 2677         snapshot = share_snapshot_get(context, values['share_snapshot_id'],
 2678                                       session=session)
 2679 
 2680         for instance in snapshot.instances:
 2681             vals = {
 2682                 'share_snapshot_instance_id': instance['id'],
 2683                 'access_id': access_ref['id'],
 2684             }
 2685 
 2686             _share_snapshot_instance_access_create(vals, session)
 2687 
 2688     return share_snapshot_access_get(context, access_ref['id'])
 2689 
 2690 
 2691 def _share_snapshot_access_get_query(context, session, filters,
 2692                                      read_deleted='no'):
 2693 
 2694     query = model_query(context, models.ShareSnapshotAccessMapping,
 2695                         session=session, read_deleted=read_deleted)
 2696     return query.filter_by(**filters)
 2697 
 2698 
 2699 def _share_snapshot_instance_access_get_query(context, session,
 2700                                               access_id=None,
 2701                                               share_snapshot_instance_id=None):
 2702     filters = {'deleted': 'False'}
 2703 
 2704     if access_id is not None:
 2705         filters.update({'access_id': access_id})
 2706 
 2707     if share_snapshot_instance_id is not None:
 2708         filters.update(
 2709             {'share_snapshot_instance_id': share_snapshot_instance_id})
 2710 
 2711     return model_query(context, models.ShareSnapshotInstanceAccessMapping,
 2712                        session=session).filter_by(**filters)
 2713 
 2714 
 2715 @require_context
 2716 def share_snapshot_instance_access_get_all(context, access_id, session):
 2717     rules = _share_snapshot_instance_access_get_query(
 2718         context, session, access_id=access_id).all()
 2719     return rules
 2720 
 2721 
 2722 @require_context
 2723 def share_snapshot_access_get(context, access_id, session=None):
 2724     session = session or get_session()
 2725 
 2726     access = _share_snapshot_access_get_query(
 2727         context, session, {'id': access_id}).first()
 2728 
 2729     if access:
 2730         return access
 2731     else:
 2732         raise exception.NotFound()
 2733 
 2734 
 2735 def _share_snapshot_instance_access_create(values, session):
 2736     access_ref = models.ShareSnapshotInstanceAccessMapping()
 2737     access_ref.update(ensure_model_dict_has_id(values))
 2738     access_ref.save(session=session)
 2739     return access_ref
 2740 
 2741 
 2742 @require_context
 2743 def share_snapshot_access_get_all_for_share_snapshot(context,
 2744                                                      share_snapshot_id,
 2745                                                      filters):
 2746     session = get_session()
 2747     filters['share_snapshot_id'] = share_snapshot_id
 2748     access_list = _share_snapshot_access_get_query(
 2749         context, session, filters).all()
 2750 
 2751     return access_list
 2752 
 2753 
 2754 @require_context
 2755 def share_snapshot_check_for_existing_access(context, share_snapshot_id,
 2756                                              access_type, access_to):
 2757     return _check_for_existing_access(
 2758         context, 'share_snapshot', share_snapshot_id, access_type, access_to)
 2759 
 2760 
 2761 @require_context
 2762 def share_snapshot_access_get_all_for_snapshot_instance(
 2763         context, snapshot_instance_id, filters=None,
 2764         with_snapshot_access_data=True, session=None):
 2765     """Get all access rules related to a certain snapshot instance."""
 2766     session = session or get_session()
 2767     filters = copy.deepcopy(filters) if filters else {}
 2768     filters.update({'share_snapshot_instance_id': snapshot_instance_id})
 2769 
 2770     query = _share_snapshot_instance_access_get_query(context, session)
 2771 
 2772     legal_filter_keys = (
 2773         'id', 'share_snapshot_instance_id', 'access_id', 'state')
 2774 
 2775     query = exact_filter(
 2776         query, models.ShareSnapshotInstanceAccessMapping, filters,
 2777         legal_filter_keys)
 2778 
 2779     instance_accesses = query.all()
 2780 
 2781     if with_snapshot_access_data:
 2782         instance_accesses = _set_instances_snapshot_access_data(
 2783             context, instance_accesses, session)
 2784 
 2785     return instance_accesses
 2786 
 2787 
 2788 @require_context
 2789 def share_snapshot_instance_access_update(
 2790         context, access_id, instance_id, updates):
 2791 
 2792     snapshot_access_fields = ('access_type', 'access_to')
 2793     snapshot_access_map_updates, share_instance_access_map_updates = (
 2794         _extract_subdict_by_fields(updates, snapshot_access_fields)
 2795     )
 2796 
 2797     session = get_session()
 2798     with session.begin():
 2799 
 2800         snapshot_access = _share_snapshot_access_get_query(
 2801             context, session, {'id': access_id}).first()
 2802         if not snapshot_access:
 2803             raise exception.NotFound()
 2804         snapshot_access.update(snapshot_access_map_updates)
 2805         snapshot_access.save(session=session)
 2806 
 2807         access = _share_snapshot_instance_access_get_query(
 2808             context, session, access_id=access_id,
 2809             share_snapshot_instance_id=instance_id).first()
 2810         if not access:
 2811             raise exception.NotFound()
 2812         access.update(share_instance_access_map_updates)
 2813         access.save(session=session)
 2814 
 2815         return access
 2816 
 2817 
 2818 @require_context
 2819 def share_snapshot_instance_access_get(
 2820         context, access_id, share_snapshot_instance_id,
 2821         with_snapshot_access_data=True):
 2822 
 2823     session = get_session()
 2824 
 2825     with session.begin():
 2826         access = _share_snapshot_instance_access_get_query(
 2827             context, session, access_id=access_id,
 2828             share_snapshot_instance_id=share_snapshot_instance_id).first()
 2829 
 2830         if access is None:
 2831             raise exception.NotFound()
 2832 
 2833         if with_snapshot_access_data:
 2834             return _set_instances_snapshot_access_data(
 2835                 context, access, session)[0]
 2836         else:
 2837             return access
 2838 
 2839 
 2840 @require_context
 2841 def share_snapshot_instance_access_delete(
 2842         context, access_id, snapshot_instance_id):
 2843     session = get_session()
 2844     with session.begin():
 2845 
 2846         rule = _share_snapshot_instance_access_get_query(
 2847             context, session, access_id=access_id,
 2848             share_snapshot_instance_id=snapshot_instance_id).first()
 2849 
 2850         if not rule:
 2851             exception.NotFound()
 2852 
 2853         rule.soft_delete(session, update_status=True,
 2854                          status_field_name='state')
 2855 
 2856         other_mappings = share_snapshot_instance_access_get_all(
 2857             context, rule['access_id'], session)
 2858 
 2859         if len(other_mappings) == 0:
 2860             (
 2861                 session.query(models.ShareSnapshotAccessMapping)
 2862                 .filter_by(id=rule['access_id'])
 2863                 .soft_delete(update_status=True, status_field_name='state')
 2864             )
 2865 
 2866 
 2867 @require_context
 2868 def share_snapshot_instance_export_location_create(context, values):
 2869 
 2870     values = ensure_model_dict_has_id(values)
 2871     session = get_session()
 2872     with session.begin():
 2873         ssiel = models.ShareSnapshotInstanceExportLocation()
 2874         ssiel.update(values)
 2875         ssiel.save(session=session)
 2876 
 2877         return ssiel
 2878 
 2879 
 2880 def _share_snapshot_instance_export_locations_get_query(context, session,
 2881                                                         values):
 2882     query = model_query(context, models.ShareSnapshotInstanceExportLocation,
 2883                         session=session)
 2884     return query.filter_by(**values)
 2885 
 2886 
 2887 @require_context
 2888 def share_snapshot_export_locations_get(context, snapshot_id):
 2889     session = get_session()
 2890     snapshot = share_snapshot_get(context, snapshot_id, session=session)
 2891     ins_ids = [ins['id'] for ins in snapshot.instances]
 2892     export_locations = _share_snapshot_instance_export_locations_get_query(
 2893         context, session, {}).filter(
 2894         models.ShareSnapshotInstanceExportLocation.
 2895             share_snapshot_instance_id.in_(ins_ids)).all()
 2896     return export_locations
 2897 
 2898 
 2899 @require_context
 2900 def share_snapshot_instance_export_locations_get_all(
 2901         context, share_snapshot_instance_id):
 2902 
 2903     session = get_session()
 2904     export_locations = _share_snapshot_instance_export_locations_get_query(
 2905         context, session,
 2906         {'share_snapshot_instance_id': share_snapshot_instance_id}).all()
 2907     return export_locations
 2908 
 2909 
 2910 @require_context
 2911 def share_snapshot_instance_export_location_get(context, el_id):
 2912     session = get_session()
 2913 
 2914     export_location = _share_snapshot_instance_export_locations_get_query(
 2915         context, session, {'id': el_id}).first()
 2916 
 2917     if export_location:
 2918         return export_location
 2919     else:
 2920         raise exception.NotFound()
 2921 
 2922 
 2923 @require_context
 2924 def share_snapshot_instance_export_location_delete(context, el_id):
 2925     session = get_session()
 2926     with session.begin():
 2927 
 2928         el = _share_snapshot_instance_export_locations_get_query(
 2929             context, session, {'id': el_id}).first()
 2930 
 2931         if not el:
 2932             exception.NotFound()
 2933 
 2934         el.soft_delete(session=session)
 2935 
 2936 #################################
 2937 
 2938 
 2939 @require_context
 2940 @require_share_exists
 2941 def share_metadata_get(context, share_id):
 2942     return _share_metadata_get(context, share_id)
 2943 
 2944 
 2945 @require_context
 2946 @require_share_exists
 2947 def share_metadata_delete(context, share_id, key):
 2948     (_share_metadata_get_query(context, share_id).
 2949         filter_by(key=key).soft_delete())
 2950 
 2951 
 2952 @require_context
 2953 @require_share_exists
 2954 def share_metadata_update(context, share_id, metadata, delete):
 2955     return _share_metadata_update(context, share_id, metadata, delete)
 2956 
 2957 
 2958 def _share_metadata_get_query(context, share_id, session=None):
 2959     return (model_query(context, models.ShareMetadata, session=session,
 2960                         read_deleted="no").
 2961             filter_by(share_id=share_id).
 2962             options(joinedload('share')))
 2963 
 2964 
 2965 def _share_metadata_get(context, share_id, session=None):
 2966     rows = _share_metadata_get_query(context, share_id,
 2967                                      session=session).all()
 2968     result = {}
 2969     for row in rows:
 2970         result[row['key']] = row['value']
 2971 
 2972     return result
 2973 
 2974 
 2975 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 2976 def _share_metadata_update(context, share_id, metadata, delete, session=None):
 2977     if not session:
 2978         session = get_session()
 2979 
 2980     with session.begin():
 2981         # Set existing metadata to deleted if delete argument is True
 2982         if delete:
 2983             original_metadata = _share_metadata_get(context, share_id,
 2984                                                     session=session)
 2985             for meta_key, meta_value in original_metadata.items():
 2986                 if meta_key not in metadata:
 2987                     meta_ref = _share_metadata_get_item(context, share_id,
 2988                                                         meta_key,
 2989                                                         session=session)
 2990                     meta_ref.soft_delete(session=session)
 2991 
 2992         meta_ref = None
 2993 
 2994         # Now update all existing items with new values, or create new meta
 2995         # objects
 2996         for meta_key, meta_value in metadata.items():
 2997 
 2998             # update the value whether it exists or not
 2999             item = {"value": meta_value}
 3000 
 3001             try:
 3002                 meta_ref = _share_metadata_get_item(context, share_id,
 3003                                                     meta_key,
 3004                                                     session=session)
 3005             except exception.ShareMetadataNotFound:
 3006                 meta_ref = models.ShareMetadata()
 3007                 item.update({"key": meta_key, "share_id": share_id})
 3008 
 3009             meta_ref.update(item)
 3010             meta_ref.save(session=session)
 3011 
 3012         return metadata
 3013 
 3014 
 3015 def _share_metadata_get_item(context, share_id, key, session=None):
 3016     result = (_share_metadata_get_query(context, share_id, session=session).
 3017               filter_by(key=key).
 3018               first())
 3019 
 3020     if not result:
 3021         raise exception.ShareMetadataNotFound(metadata_key=key,
 3022                                               share_id=share_id)
 3023     return result
 3024 
 3025 
 3026 ############################
 3027 # Export locations functions
 3028 ############################
 3029 
 3030 def _share_export_locations_get(context, share_instance_ids,
 3031                                 include_admin_only=True,
 3032                                 ignore_secondary_replicas=False, session=None):
 3033     session = session or get_session()
 3034 
 3035     if not isinstance(share_instance_ids, (set, list, tuple)):
 3036         share_instance_ids = (share_instance_ids, )
 3037 
 3038     query = model_query(
 3039         context,
 3040         models.ShareInstanceExportLocations,
 3041         session=session,
 3042         read_deleted="no",
 3043     ).filter(
 3044         models.ShareInstanceExportLocations.share_instance_id.in_(
 3045             share_instance_ids),
 3046     ).order_by(
 3047         "updated_at",
 3048     ).options(
 3049         joinedload("_el_metadata_bare"),
 3050     )
 3051 
 3052     if not include_admin_only:
 3053         query = query.filter_by(is_admin_only=False)
 3054 
 3055     if ignore_secondary_replicas:
 3056         replica_state_attr = models.ShareInstance.replica_state
 3057         query = query.join("share_instance").filter(
 3058             or_(replica_state_attr == None,  # noqa
 3059                 replica_state_attr == constants.REPLICA_STATE_ACTIVE))
 3060 
 3061     return query.all()
 3062 
 3063 
 3064 @require_context
 3065 @require_share_exists
 3066 def share_export_locations_get_by_share_id(context, share_id,
 3067                                            include_admin_only=True,
 3068                                            ignore_migration_destination=False,
 3069                                            ignore_secondary_replicas=False):
 3070     share = share_get(context, share_id)
 3071     if ignore_migration_destination:
 3072         ids = [instance.id for instance in share.instances
 3073                if instance['status'] != constants.STATUS_MIGRATING_TO]
 3074     else:
 3075         ids = [instance.id for instance in share.instances]
 3076     rows = _share_export_locations_get(
 3077         context, ids, include_admin_only=include_admin_only,
 3078         ignore_secondary_replicas=ignore_secondary_replicas)
 3079     return rows
 3080 
 3081 
 3082 @require_context
 3083 @require_share_instance_exists
 3084 def share_export_locations_get_by_share_instance_id(context,
 3085                                                     share_instance_id,
 3086                                                     include_admin_only=True):
 3087     rows = _share_export_locations_get(
 3088         context, [share_instance_id], include_admin_only=include_admin_only)
 3089     return rows
 3090 
 3091 
 3092 @require_context
 3093 @require_share_exists
 3094 def share_export_locations_get(context, share_id):
 3095     # NOTE(vponomaryov): this method is kept for compatibility with
 3096     # old approach. New one uses 'share_export_locations_get_by_share_id'.
 3097     # Which returns list of dicts instead of list of strings, as this one does.
 3098     share = share_get(context, share_id)
 3099     rows = _share_export_locations_get(
 3100         context, share.instance.id, context.is_admin)
 3101 
 3102     return [location['path'] for location in rows]
 3103 
 3104 
 3105 @require_context
 3106 def share_export_location_get_by_uuid(context, export_location_uuid,
 3107                                       ignore_secondary_replicas=False,
 3108                                       session=None):
 3109     session = session or get_session()
 3110 
 3111     query = model_query(
 3112         context,
 3113         models.ShareInstanceExportLocations,
 3114         session=session,
 3115         read_deleted="no",
 3116     ).filter_by(
 3117         uuid=export_location_uuid,
 3118     ).options(
 3119         joinedload("_el_metadata_bare"),
 3120     )
 3121 
 3122     if ignore_secondary_replicas:
 3123         replica_state_attr = models.ShareInstance.replica_state
 3124         query = query.join("share_instance").filter(
 3125             or_(replica_state_attr == None,  # noqa
 3126                 replica_state_attr == constants.REPLICA_STATE_ACTIVE))
 3127 
 3128     result = query.first()
 3129     if not result:
 3130         raise exception.ExportLocationNotFound(uuid=export_location_uuid)
 3131     return result
 3132 
 3133 
 3134 @require_context
 3135 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 3136 def share_export_locations_update(context, share_instance_id, export_locations,
 3137                                   delete):
 3138     # NOTE(u_glide):
 3139     # Backward compatibility code for drivers,
 3140     # which return single export_location as string
 3141     if not isinstance(export_locations, (list, tuple, set)):
 3142         export_locations = (export_locations, )
 3143     export_locations_as_dicts = []
 3144     for el in export_locations:
 3145         # NOTE(vponomaryov): transform old export locations view to new one
 3146         export_location = el
 3147         if isinstance(el, six.string_types):
 3148             export_location = {
 3149                 "path": el,
 3150                 "is_admin_only": False,
 3151                 "metadata": {},
 3152             }
 3153         elif isinstance(export_location, dict):
 3154             if 'metadata' not in export_location:
 3155                 export_location['metadata'] = {}
 3156         else:
 3157             raise exception.ManilaException(
 3158                 _("Wrong export location type '%s'.") % type(export_location))
 3159         export_locations_as_dicts.append(export_location)
 3160     export_locations = export_locations_as_dicts
 3161 
 3162     export_locations_paths = [el['path'] for el in export_locations]
 3163 
 3164     session = get_session()
 3165 
 3166     current_el_rows = _share_export_locations_get(
 3167         context, share_instance_id, session=session)
 3168 
 3169     def get_path_list_from_rows(rows):
 3170         return set([l['path'] for l in rows])
 3171 
 3172     current_el_paths = get_path_list_from_rows(current_el_rows)
 3173 
 3174     def create_indexed_time_dict(key_list):
 3175         base = timeutils.utcnow()
 3176         return {
 3177             # NOTE(u_glide): Incrementing timestamp by microseconds to make
 3178             # timestamp order match index order.
 3179             key: base + datetime.timedelta(microseconds=index)
 3180             for index, key in enumerate(key_list)
 3181         }
 3182 
 3183     indexed_update_time = create_indexed_time_dict(export_locations_paths)
 3184 
 3185     for el in current_el_rows:
 3186         if delete and el['path'] not in export_locations_paths:
 3187             export_location_metadata_delete(context, el['uuid'])
 3188             el.soft_delete(session)
 3189         else:
 3190             updated_at = indexed_update_time[el['path']]
 3191             el.update({
 3192                 'updated_at': updated_at,
 3193                 'deleted': 0,
 3194             })
 3195             el.save(session=session)
 3196             if el['el_metadata']:
 3197                 export_location_metadata_update(
 3198                     context, el['uuid'], el['el_metadata'], session=session)
 3199 
 3200     # Now add new export locations
 3201     for el in export_locations:
 3202         if el['path'] in current_el_paths:
 3203             # Already updated
 3204             continue
 3205 
 3206         location_ref = models.ShareInstanceExportLocations()
 3207         location_ref.update({
 3208             'uuid': uuidutils.generate_uuid(),
 3209             'path': el['path'],
 3210             'share_instance_id': share_instance_id,
 3211             'updated_at': indexed_update_time[el['path']],
 3212             'deleted': 0,
 3213             'is_admin_only': el.get('is_admin_only', False),
 3214         })
 3215         location_ref.save(session=session)
 3216         if not el.get('metadata'):
 3217             continue
 3218         export_location_metadata_update(
 3219             context, location_ref['uuid'], el.get('metadata'), session=session)
 3220 
 3221     return get_path_list_from_rows(_share_export_locations_get(
 3222         context, share_instance_id, session=session))
 3223 
 3224 
 3225 #####################################
 3226 # Export locations metadata functions
 3227 #####################################
 3228 
 3229 def _export_location_metadata_get_query(context, export_location_uuid,
 3230                                         session=None):
 3231     session = session or get_session()
 3232     export_location_id = share_export_location_get_by_uuid(
 3233         context, export_location_uuid).id
 3234 
 3235     return model_query(
 3236         context, models.ShareInstanceExportLocationsMetadata, session=session,
 3237         read_deleted="no",
 3238     ).filter_by(
 3239         export_location_id=export_location_id,
 3240     )
 3241 
 3242 
 3243 @require_context
 3244 def export_location_metadata_get(context, export_location_uuid, session=None):
 3245     rows = _export_location_metadata_get_query(
 3246         context, export_location_uuid, session=session).all()
 3247     result = {}
 3248     for row in rows:
 3249         result[row["key"]] = row["value"]
 3250     return result
 3251 
 3252 
 3253 @require_context
 3254 def export_location_metadata_delete(context, export_location_uuid, keys=None):
 3255     session = get_session()
 3256     metadata = _export_location_metadata_get_query(
 3257         context, export_location_uuid, session=session,
 3258     )
 3259     # NOTE(vponomaryov): if keys is None then we delete all metadata.
 3260     if keys is not None:
 3261         keys = keys if isinstance(keys, (list, set, tuple)) else (keys, )
 3262         metadata = metadata.filter(
 3263             models.ShareInstanceExportLocationsMetadata.key.in_(keys))
 3264     metadata = metadata.all()
 3265     for meta_ref in metadata:
 3266         meta_ref.soft_delete(session=session)
 3267 
 3268 
 3269 @require_context
 3270 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 3271 def export_location_metadata_update(context, export_location_uuid, metadata,
 3272                                     delete=False, session=None):
 3273     session = session or get_session()
 3274     if delete:
 3275         original_metadata = export_location_metadata_get(
 3276             context, export_location_uuid, session=session)
 3277         keys_for_deletion = set(original_metadata).difference(metadata)
 3278         if keys_for_deletion:
 3279             export_location_metadata_delete(
 3280                 context, export_location_uuid, keys=keys_for_deletion)
 3281 
 3282     el = share_export_location_get_by_uuid(context, export_location_uuid)
 3283     for meta_key, meta_value in metadata.items():
 3284         # NOTE(vponomaryov): we should use separate session
 3285         # for each meta_ref because of autoincrement of integer primary key
 3286         # that will not take effect using one session and we will rewrite,
 3287         # in that case, single record - first one added with this call.
 3288         session = get_session()
 3289 
 3290         if meta_value is None:
 3291             LOG.warning("%s should be properly defined in the driver.",
 3292                         meta_key)
 3293 
 3294         item = {"value": meta_value, "updated_at": timeutils.utcnow()}
 3295 
 3296         meta_ref = _export_location_metadata_get_query(
 3297             context, export_location_uuid, session=session,
 3298         ).filter_by(
 3299             key=meta_key,
 3300         ).first()
 3301 
 3302         if not meta_ref:
 3303             meta_ref = models.ShareInstanceExportLocationsMetadata()
 3304             item.update({
 3305                 "key": meta_key,
 3306                 "export_location_id": el.id,
 3307             })
 3308 
 3309         meta_ref.update(item)
 3310         meta_ref.save(session=session)
 3311 
 3312     return metadata
 3313 
 3314 
 3315 ###################################
 3316 
 3317 
 3318 @require_context
 3319 def security_service_create(context, values):
 3320     values = ensure_model_dict_has_id(values)
 3321 
 3322     security_service_ref = models.SecurityService()
 3323     security_service_ref.update(values)
 3324     session = get_session()
 3325 
 3326     with session.begin():
 3327         security_service_ref.save(session=session)
 3328 
 3329     return security_service_ref
 3330 
 3331 
 3332 @require_context
 3333 def security_service_delete(context, id):
 3334     session = get_session()
 3335     with session.begin():
 3336         security_service_ref = security_service_get(context,
 3337                                                     id,
 3338                                                     session=session)
 3339         security_service_ref.soft_delete(session)
 3340 
 3341 
 3342 @require_context
 3343 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 3344 def security_service_update(context, id, values):
 3345     session = get_session()
 3346     with session.begin():
 3347         security_service_ref = security_service_get(context,
 3348                                                     id,
 3349                                                     session=session)
 3350         security_service_ref.update(values)
 3351         security_service_ref.save(session=session)
 3352         return security_service_ref
 3353 
 3354 
 3355 @require_context
 3356 def security_service_get(context, id, session=None):
 3357     result = (_security_service_get_query(context, session=session).
 3358               filter_by(id=id).first())
 3359 
 3360     if result is None:
 3361         raise exception.SecurityServiceNotFound(security_service_id=id)
 3362     return result
 3363 
 3364 
 3365 @require_context
 3366 def security_service_get_all(context):
 3367     return _security_service_get_query(context).all()
 3368 
 3369 
 3370 @require_context
 3371 def security_service_get_all_by_project(context, project_id):
 3372     return (_security_service_get_query(context).
 3373             filter_by(project_id=project_id).all())
 3374 
 3375 
 3376 def _security_service_get_query(context, session=None):
 3377     if session is None:
 3378         session = get_session()
 3379     return model_query(context, models.SecurityService, session=session)
 3380 
 3381 
 3382 ###################
 3383 
 3384 
 3385 def _network_get_query(context, session=None):
 3386     if session is None:
 3387         session = get_session()
 3388     return (model_query(context, models.ShareNetwork, session=session,
 3389                         project_only=True).
 3390             options(joinedload('share_instances'),
 3391                     joinedload('security_services'),
 3392                     joinedload('share_servers')))
 3393 
 3394 
 3395 @require_context
 3396 def share_network_create(context, values):
 3397     values = ensure_model_dict_has_id(values)
 3398 
 3399     network_ref = models.ShareNetwork()
 3400     network_ref.update(values)
 3401     session = get_session()
 3402     with session.begin():
 3403         network_ref.save(session=session)
 3404     return share_network_get(context, values['id'], session)
 3405 
 3406 
 3407 @require_context
 3408 def share_network_delete(context, id):
 3409     session = get_session()
 3410     with session.begin():
 3411         network_ref = share_network_get(context, id, session=session)
 3412         network_ref.soft_delete(session)
 3413 
 3414 
 3415 @require_context
 3416 def share_network_update(context, id, values):
 3417     session = get_session()
 3418     with session.begin():
 3419         network_ref = share_network_get(context, id, session=session)
 3420         network_ref.update(values)
 3421         network_ref.save(session=session)
 3422         return network_ref
 3423 
 3424 
 3425 @require_context
 3426 def share_network_get(context, id, session=None):
 3427     result = _network_get_query(context, session).filter_by(id=id).first()
 3428     if result is None:
 3429         raise exception.ShareNetworkNotFound(share_network_id=id)
 3430     return result
 3431 
 3432 
 3433 @require_context
 3434 def share_network_get_all(context):
 3435     return _network_get_query(context).all()
 3436 
 3437 
 3438 @require_context
 3439 def share_network_get_all_by_project(context, project_id):
 3440     return _network_get_query(context).filter_by(project_id=project_id).all()
 3441 
 3442 
 3443 @require_context
 3444 def share_network_get_all_by_security_service(context, security_service_id):
 3445     session = get_session()
 3446     return (model_query(context, models.ShareNetwork, session=session).
 3447             join(models.ShareNetworkSecurityServiceAssociation,
 3448             models.ShareNetwork.id ==
 3449             models.ShareNetworkSecurityServiceAssociation.share_network_id).
 3450             filter_by(security_service_id=security_service_id, deleted=0).
 3451             options(joinedload('share_servers')).all())
 3452 
 3453 
 3454 @require_context
 3455 def share_network_add_security_service(context, id, security_service_id):
 3456     session = get_session()
 3457 
 3458     with session.begin():
 3459         assoc_ref = (model_query(
 3460                      context,
 3461                      models.ShareNetworkSecurityServiceAssociation,
 3462                      session=session).
 3463                      filter_by(share_network_id=id).
 3464                      filter_by(
 3465                      security_service_id=security_service_id).first())
 3466 
 3467         if assoc_ref:
 3468             msg = "Already associated"
 3469             raise exception.ShareNetworkSecurityServiceAssociationError(
 3470                 share_network_id=id,
 3471                 security_service_id=security_service_id,
 3472                 reason=msg)
 3473 
 3474         share_nw_ref = share_network_get(context, id, session=session)
 3475         security_service_ref = security_service_get(context,
 3476                                                     security_service_id,
 3477                                                     session=session)
 3478         share_nw_ref.security_services += [security_service_ref]
 3479         share_nw_ref.save(session=session)
 3480 
 3481     return share_nw_ref
 3482 
 3483 
 3484 @require_context
 3485 def share_network_remove_security_service(context, id, security_service_id):
 3486     session = get_session()
 3487 
 3488     with session.begin():
 3489         share_nw_ref = share_network_get(context, id, session=session)
 3490         security_service_get(context, security_service_id, session=session)
 3491 
 3492         assoc_ref = (model_query(
 3493             context,
 3494             models.ShareNetworkSecurityServiceAssociation,
 3495             session=session).
 3496             filter_by(share_network_id=id).
 3497             filter_by(security_service_id=security_service_id).first())
 3498 
 3499         if assoc_ref:
 3500             assoc_ref.soft_delete(session)
 3501         else:
 3502             msg = "No association defined"
 3503             raise exception.ShareNetworkSecurityServiceDissociationError(
 3504                 share_network_id=id,
 3505                 security_service_id=security_service_id,
 3506                 reason=msg)
 3507 
 3508     return share_nw_ref
 3509 
 3510 
 3511 @require_context
 3512 def count_share_networks(context, project_id, user_id=None,
 3513                          share_type_id=None, session=None):
 3514     query = model_query(
 3515         context, models.ShareNetwork,
 3516         func.count(models.ShareNetwork.id),
 3517         read_deleted="no",
 3518         session=session).filter_by(project_id=project_id)
 3519     if share_type_id:
 3520         query = query.join("share_instances").filter_by(
 3521             share_type_id=share_type_id)
 3522     elif user_id is not None:
 3523         query = query.filter_by(user_id=user_id)
 3524     return query.first()[0]
 3525 
 3526 
 3527 ###################
 3528 
 3529 
 3530 def _server_get_query(context, session=None):
 3531     if session is None:
 3532         session = get_session()
 3533     return (model_query(context, models.ShareServer, session=session).
 3534             options(joinedload('share_instances'),
 3535                     joinedload('network_allocations'),
 3536                     joinedload('share_network')))
 3537 
 3538 
 3539 @require_context
 3540 def share_server_create(context, values):
 3541     values = ensure_model_dict_has_id(values)
 3542 
 3543     server_ref = models.ShareServer()
 3544     server_ref.update(values)
 3545     session = get_session()
 3546     with session.begin():
 3547         server_ref.save(session=session)
 3548         # NOTE(u_glide): Do so to prevent errors with relationships
 3549         return share_server_get(context, server_ref['id'], session=session)
 3550 
 3551 
 3552 @require_context
 3553 def share_server_delete(context, id):
 3554     session = get_session()
 3555     with session.begin():
 3556         server_ref = share_server_get(context, id, session=session)
 3557         share_server_backend_details_delete(context, id, session=session)
 3558         server_ref.soft_delete(session=session, update_status=True)
 3559 
 3560 
 3561 @require_context
 3562 def share_server_update(context, id, values):
 3563     session = get_session()
 3564     with session.begin():
 3565         server_ref = share_server_get(context, id, session=session)
 3566         server_ref.update(values)
 3567         server_ref.save(session=session)
 3568         return server_ref
 3569 
 3570 
 3571 @require_context
 3572 def share_server_get(context, server_id, session=None):
 3573     result = (_server_get_query(context, session).filter_by(id=server_id)
 3574               .first())
 3575     if result is None:
 3576         raise exception.ShareServerNotFound(share_server_id=server_id)
 3577     return result
 3578 
 3579 
 3580 @require_context
 3581 def share_server_search_by_identifier(context, identifier, session=None):
 3582 
 3583     identifier_field = models.ShareServer.identifier
 3584 
 3585     # try if given identifier is a substring of existing entry's identifier
 3586     result = (_server_get_query(context, session).filter(
 3587         identifier_field.like('%{}%'.format(identifier))).all())
 3588 
 3589     if not result:
 3590         # repeat it with underscores instead of hyphens
 3591         result = (_server_get_query(context, session).filter(
 3592             identifier_field.like('%{}%'.format(
 3593                 identifier.replace("-", "_")))).all())
 3594 
 3595     if not result:
 3596         # repeat it with hypens instead of underscores
 3597         result = (_server_get_query(context, session).filter(
 3598             identifier_field.like('%{}%'.format(
 3599                 identifier.replace("_", "-")))).all())
 3600 
 3601     if not result:
 3602         # try if an existing identifier is a substring of given identifier
 3603         result = (_server_get_query(context, session).filter(
 3604             literal(identifier).contains(identifier_field)).all())
 3605 
 3606     if not result:
 3607         # repeat it with underscores instead of hyphens
 3608         result = (_server_get_query(context, session).filter(
 3609             literal(identifier.replace("-", "_")).contains(
 3610                 identifier_field)).all())
 3611 
 3612     if not result:
 3613         # repeat it with hypens instead of underscores
 3614         result = (_server_get_query(context, session).filter(
 3615             literal(identifier.replace("_", "-")).contains(
 3616                 identifier_field)).all())
 3617 
 3618     if not result:
 3619         raise exception.ShareServerNotFound(share_server_id=identifier)
 3620 
 3621     return result
 3622 
 3623 
 3624 @require_context
 3625 def share_server_get_all_by_host_and_share_net_valid(context, host,
 3626                                                      share_net_id,
 3627                                                      session=None):
 3628     result = (_server_get_query(context, session).filter_by(host=host)
 3629               .filter_by(share_network_id=share_net_id)
 3630               .filter(models.ShareServer.status.in_(
 3631                       (constants.STATUS_CREATING,
 3632                        constants.STATUS_ACTIVE))).all())
 3633     if not result:
 3634         filters_description = ('share_network_id is "%(share_net_id)s",'
 3635                                ' host is "%(host)s" and status in'
 3636                                ' "%(status_cr)s" or "%(status_act)s"') % {
 3637             'share_net_id': share_net_id,
 3638             'host': host,
 3639             'status_cr': constants.STATUS_CREATING,
 3640             'status_act': constants.STATUS_ACTIVE,
 3641         }
 3642         raise exception.ShareServerNotFoundByFilters(
 3643             filters_description=filters_description)
 3644     return result
 3645 
 3646 
 3647 @require_context
 3648 def share_server_get_all(context):
 3649     return _server_get_query(context).all()
 3650 
 3651 
 3652 @require_context
 3653 def share_server_get_all_by_host(context, host):
 3654     return _server_get_query(context).filter_by(host=host).all()
 3655 
 3656 
 3657 @require_context
 3658 def share_server_get_all_unused_deletable(context, host, updated_before):
 3659     valid_server_status = (
 3660         constants.STATUS_INACTIVE,
 3661         constants.STATUS_ACTIVE,
 3662         constants.STATUS_ERROR,
 3663     )
 3664     result = (_server_get_query(context)
 3665               .filter_by(is_auto_deletable=True)
 3666               .filter_by(host=host)
 3667               .filter(~models.ShareServer.share_groups.any())
 3668               .filter(~models.ShareServer.share_instances.any())
 3669               .filter(models.ShareServer.status.in_(valid_server_status))
 3670               .filter(models.ShareServer.updated_at < updated_before).all())
 3671     return result
 3672 
 3673 
 3674 @require_context
 3675 def share_server_backend_details_set(context, share_server_id, server_details):
 3676     share_server_get(context, share_server_id)
 3677 
 3678     for meta_key, meta_value in server_details.items():
 3679         meta_ref = models.ShareServerBackendDetails()
 3680         meta_ref.update({
 3681             'key': meta_key,
 3682             'value': meta_value,
 3683             'share_server_id': share_server_id
 3684         })
 3685         session = get_session()
 3686         with session.begin():
 3687             meta_ref.save(session)
 3688     return server_details
 3689 
 3690 
 3691 @require_context
 3692 def share_server_backend_details_delete(context, share_server_id,
 3693                                         session=None):
 3694     if not session:
 3695         session = get_session()
 3696     share_server_details = (model_query(context,
 3697                                         models.ShareServerBackendDetails,
 3698                                         session=session)
 3699                             .filter_by(share_server_id=share_server_id).all())
 3700     for item in share_server_details:
 3701         item.soft_delete(session)
 3702 
 3703 
 3704 ###################
 3705 
 3706 def _driver_private_data_query(session, context, entity_id, key=None,
 3707                                read_deleted=False):
 3708     query = model_query(
 3709         context, models.DriverPrivateData, session=session,
 3710         read_deleted=read_deleted,
 3711     ).filter_by(
 3712         entity_uuid=entity_id,
 3713     )
 3714 
 3715     if isinstance(key, list):
 3716         return query.filter(models.DriverPrivateData.key.in_(key))
 3717     elif key is not None:
 3718         return query.filter_by(key=key)
 3719 
 3720     return query
 3721 
 3722 
 3723 @require_context
 3724 def driver_private_data_get(context, entity_id, key=None,
 3725                             default=None, session=None):
 3726     if not session:
 3727         session = get_session()
 3728 
 3729     query = _driver_private_data_query(session, context, entity_id, key)
 3730 
 3731     if key is None or isinstance(key, list):
 3732         return {item.key: item.value for item in query.all()}
 3733     else:
 3734         result = query.first()
 3735         return result["value"] if result is not None else default
 3736 
 3737 
 3738 @require_context
 3739 def driver_private_data_update(context, entity_id, details,
 3740                                delete_existing=False, session=None):
 3741     # NOTE(u_glide): following code modifies details dict, that's why we should
 3742     # copy it
 3743     new_details = copy.deepcopy(details)
 3744 
 3745     if not session:
 3746         session = get_session()
 3747 
 3748     with session.begin():
 3749         # Process existing data
 3750         original_data = session.query(models.DriverPrivateData).filter_by(
 3751             entity_uuid=entity_id).all()
 3752 
 3753         for data_ref in original_data:
 3754             in_new_details = data_ref['key'] in new_details
 3755 
 3756             if in_new_details:
 3757                 new_value = six.text_type(new_details.pop(data_ref['key']))
 3758                 data_ref.update({
 3759                     "value": new_value,
 3760                     "deleted": 0,
 3761                     "deleted_at": None
 3762                 })
 3763                 data_ref.save(session=session)
 3764             elif delete_existing and data_ref['deleted'] != 1:
 3765                 data_ref.update({
 3766                     "deleted": 1, "deleted_at": timeutils.utcnow()
 3767                 })
 3768                 data_ref.save(session=session)
 3769 
 3770         # Add new data
 3771         for key, value in new_details.items():
 3772             data_ref = models.DriverPrivateData()
 3773             data_ref.update({
 3774                 "entity_uuid": entity_id,
 3775                 "key": key,
 3776                 "value": six.text_type(value)
 3777             })
 3778             data_ref.save(session=session)
 3779 
 3780         return details
 3781 
 3782 
 3783 @require_context
 3784 def driver_private_data_delete(context, entity_id, key=None,
 3785                                session=None):
 3786     if not session:
 3787         session = get_session()
 3788 
 3789     with session.begin():
 3790         query = _driver_private_data_query(session, context,
 3791                                            entity_id, key)
 3792         query.update({"deleted": 1, "deleted_at": timeutils.utcnow()})
 3793 
 3794 
 3795 ###################
 3796 
 3797 
 3798 @require_context
 3799 def network_allocation_create(context, values):
 3800     values = ensure_model_dict_has_id(values)
 3801     alloc_ref = models.NetworkAllocation()
 3802     alloc_ref.update(values)
 3803     session = get_session()
 3804     with session.begin():
 3805         alloc_ref.save(session=session)
 3806     return alloc_ref
 3807 
 3808 
 3809 @require_context
 3810 def network_allocation_delete(context, id):
 3811     session = get_session()
 3812     with session.begin():
 3813         alloc_ref = network_allocation_get(context, id, session=session)
 3814         alloc_ref.soft_delete(session)
 3815 
 3816 
 3817 @require_context
 3818 def network_allocation_get(context, id, session=None, read_deleted="no"):
 3819     if session is None:
 3820         session = get_session()
 3821     result = (model_query(context, models.NetworkAllocation, session=session,
 3822                           read_deleted=read_deleted).
 3823               filter_by(id=id).first())
 3824     if result is None:
 3825         raise exception.NotFound()
 3826     return result
 3827 
 3828 
 3829 @require_context
 3830 def network_allocations_get_by_ip_address(context, ip_address):
 3831     session = get_session()
 3832     result = (model_query(context, models.NetworkAllocation, session=session).
 3833               filter_by(ip_address=ip_address).all())
 3834     return result or []
 3835 
 3836 
 3837 @require_context
 3838 def network_allocations_get_for_share_server(context, share_server_id,
 3839                                              session=None, label=None):
 3840     if session is None:
 3841         session = get_session()
 3842 
 3843     query = model_query(
 3844         context, models.NetworkAllocation, session=session,
 3845     ).filter_by(
 3846         share_server_id=share_server_id,
 3847     )
 3848     if label:
 3849         if label != 'admin':
 3850             query = query.filter(or_(
 3851                 # NOTE(vponomaryov): we treat None as alias for 'user'.
 3852                 models.NetworkAllocation.label == None,  # noqa
 3853                 models.NetworkAllocation.label == label,
 3854             ))
 3855         else:
 3856             query = query.filter(models.NetworkAllocation.label == label)
 3857 
 3858     result = query.all()
 3859     return result
 3860 
 3861 
 3862 @require_context
 3863 def network_allocation_update(context, id, values, read_deleted=None):
 3864     session = get_session()
 3865     with session.begin():
 3866         alloc_ref = network_allocation_get(context, id, session=session,
 3867                                            read_deleted=read_deleted)
 3868         alloc_ref.update(values)
 3869         alloc_ref.save(session=session)
 3870         return alloc_ref
 3871 
 3872 
 3873 ###################
 3874 
 3875 
 3876 def _dict_with_specs(inst_type_query, specs_key='extra_specs'):
 3877     """Convert type query result to dict with extra_spec and rate_limit.
 3878 
 3879     Takes a share [group] type query returned by sqlalchemy and returns it
 3880     as a dictionary, converting the extra/group specs entry from a list
 3881     of dicts:
 3882 
 3883     'extra_specs' : [{'key': 'k1', 'value': 'v1', ...}, ...]
 3884     'group_specs' : [{'key': 'k1', 'value': 'v1', ...}, ...]
 3885     to a single dict:
 3886     'extra_specs' : {'k1': 'v1'}
 3887     'group_specs' : {'k1': 'v1'}
 3888     """
 3889     inst_type_dict = dict(inst_type_query)
 3890     specs = {x['key']: x['value'] for x in inst_type_query[specs_key]}
 3891     inst_type_dict[specs_key] = specs
 3892     return inst_type_dict
 3893 
 3894 
 3895 @require_admin_context
 3896 def share_type_create(context, values, projects=None):
 3897     """Create a new share type.
 3898 
 3899     In order to pass in extra specs, the values dict should contain a
 3900     'extra_specs' key/value pair:
 3901     {'extra_specs' : {'k1': 'v1', 'k2': 'v2', ...}}
 3902     """
 3903     values = ensure_model_dict_has_id(values)
 3904 
 3905     projects = projects or []
 3906 
 3907     session = get_session()
 3908     with session.begin():
 3909         try:
 3910             values['extra_specs'] = _metadata_refs(values.get('extra_specs'),
 3911                                                    models.ShareTypeExtraSpecs)
 3912             share_type_ref = models.ShareTypes()
 3913             share_type_ref.update(values)
 3914             share_type_ref.save(session=session)
 3915         except db_exception.DBDuplicateEntry:
 3916             raise exception.ShareTypeExists(id=values['name'])
 3917         except Exception as e:
 3918             raise db_exception.DBError(e)
 3919 
 3920         for project in set(projects):
 3921             access_ref = models.ShareTypeProjects()
 3922             access_ref.update({"share_type_id": share_type_ref.id,
 3923                                "project_id": project})
 3924             access_ref.save(session=session)
 3925 
 3926         return share_type_ref
 3927 
 3928 
 3929 def _share_type_get_query(context, session=None, read_deleted=None,
 3930                           expected_fields=None):
 3931     expected_fields = expected_fields or []
 3932     query = (model_query(context,
 3933                          models.ShareTypes,
 3934                          session=session,
 3935                          read_deleted=read_deleted).
 3936              options(joinedload('extra_specs')))
 3937 
 3938     if 'projects' in expected_fields:
 3939         query = query.options(joinedload('projects'))
 3940 
 3941     if not context.is_admin:
 3942         the_filter = [models.ShareTypes.is_public == true()]
 3943         projects_attr = getattr(models.ShareTypes, 'projects')
 3944         the_filter.extend([
 3945             projects_attr.any(project_id=context.project_id)
 3946         ])
 3947         query = query.filter(or_(*the_filter))
 3948 
 3949     return query
 3950 
 3951 
 3952 @require_context
 3953 def share_type_get_all(context, inactive=False, filters=None):
 3954     """Returns a dict describing all share_types with name as key."""
 3955     filters = filters or {}
 3956 
 3957     read_deleted = "yes" if inactive else "no"
 3958 
 3959     query = _share_type_get_query(context, read_deleted=read_deleted)
 3960 
 3961     if 'is_public' in filters and filters['is_public'] is not None:
 3962         the_filter = [models. ShareTypes.is_public == filters['is_public']]
 3963         if filters['is_public'] and context.project_id is not None:
 3964             projects_attr = getattr(models. ShareTypes, 'projects')
 3965             the_filter.extend([
 3966                 projects_attr.any(
 3967                     project_id=context.project_id, deleted=0)
 3968             ])
 3969         if len(the_filter) > 1:
 3970             query = query.filter(or_(*the_filter))
 3971         else:
 3972             query = query.filter(the_filter[0])
 3973 
 3974     rows = query.order_by("name").all()
 3975 
 3976     result = {}
 3977     for row in rows:
 3978         result[row['name']] = _dict_with_specs(row)
 3979 
 3980     return result
 3981 
 3982 
 3983 def _share_type_get_id_from_share_type_query(context, id, session=None):
 3984     return (model_query(
 3985             context, models.ShareTypes, read_deleted="no", session=session).
 3986             filter_by(id=id))
 3987 
 3988 
 3989 def _share_type_get_id_from_share_type(context, id, session=None):
 3990     result = _share_type_get_id_from_share_type_query(
 3991         context, id, session=session).first()
 3992     if not result:
 3993         raise exception.ShareTypeNotFound(share_type_id=id)
 3994     return result['id']
 3995 
 3996 
 3997 def _share_type_get(context, id, session=None, inactive=False,
 3998                     expected_fields=None):
 3999     expected_fields = expected_fields or []
 4000     read_deleted = "yes" if inactive else "no"
 4001     result = (_share_type_get_query(
 4002               context, session, read_deleted, expected_fields).
 4003               filter_by(id=id).
 4004               first())
 4005 
 4006     if not result:
 4007         # The only way that id could be None is if the default share type is
 4008         # not configured and no other share type was specified.
 4009         if id is None:
 4010             raise exception.DefaultShareTypeNotConfigured()
 4011         raise exception.ShareTypeNotFound(share_type_id=id)
 4012 
 4013     share_type = _dict_with_specs(result)
 4014 
 4015     if 'projects' in expected_fields:
 4016         share_type['projects'] = [p['project_id'] for p in result['projects']]
 4017 
 4018     return share_type
 4019 
 4020 
 4021 @require_context
 4022 def share_type_get(context, id, inactive=False, expected_fields=None):
 4023     """Return a dict describing specific share_type."""
 4024     return _share_type_get(context, id,
 4025                            session=None,
 4026                            inactive=inactive,
 4027                            expected_fields=expected_fields)
 4028 
 4029 
 4030 def _share_type_get_by_name(context, name, session=None):
 4031     result = (_share_type_get_query(context, session=session).
 4032               filter_by(name=name).
 4033               first())
 4034 
 4035     if not result:
 4036         raise exception.ShareTypeNotFoundByName(share_type_name=name)
 4037 
 4038     return _dict_with_specs(result)
 4039 
 4040 
 4041 @require_context
 4042 def share_type_get_by_name(context, name):
 4043     """Return a dict describing specific share_type."""
 4044     return _share_type_get_by_name(context, name)
 4045 
 4046 
 4047 @require_context
 4048 def share_type_get_by_name_or_id(context, name_or_id):
 4049     """Return a dict describing specific share_type using its name or ID.
 4050 
 4051     :returns: ShareType object or None if not found
 4052     """
 4053     try:
 4054         return _share_type_get(context, name_or_id)
 4055     except exception.ShareTypeNotFound:
 4056         try:
 4057             return _share_type_get_by_name(context, name_or_id)
 4058         except exception.ShareTypeNotFoundByName:
 4059             return None
 4060 
 4061 
 4062 @require_admin_context
 4063 def share_type_destroy(context, id):
 4064     session = get_session()
 4065     with session.begin():
 4066         _share_type_get(context, id, session)
 4067         shares_count = model_query(
 4068             context,
 4069             models.ShareInstance,
 4070             read_deleted="no",
 4071             session=session,
 4072         ).filter_by(share_type_id=id).count()
 4073         share_group_types_count = model_query(
 4074             context,
 4075             models.ShareGroupTypeShareTypeMapping,
 4076             read_deleted="no",
 4077             session=session,
 4078         ).filter_by(share_type_id=id).count()
 4079         if shares_count or share_group_types_count:
 4080             msg = ("Deletion of share type %(stype)s failed; it in use by "
 4081                    "%(shares)d shares and %(gtypes)d share group types")
 4082             msg_args = {'stype': id,
 4083                         'shares': shares_count,
 4084                         'gtypes': share_group_types_count}
 4085             LOG.error(msg, msg_args)
 4086             raise exception.ShareTypeInUse(share_type_id=id)
 4087 
 4088         model_query(
 4089             context, models.ShareTypeExtraSpecs, session=session
 4090         ).filter_by(
 4091             share_type_id=id
 4092         ).soft_delete()
 4093         model_query(
 4094             context, models.ShareTypeProjects, session=session
 4095         ).filter_by(
 4096             share_type_id=id,
 4097         ).soft_delete()
 4098         model_query(
 4099             context, models.ShareTypes, session=session
 4100         ).filter_by(
 4101             id=id
 4102         ).soft_delete()
 4103 
 4104     # Destroy any quotas, usages and reservations for the share type:
 4105     quota_destroy_all_by_share_type(context, id)
 4106 
 4107 
 4108 def _share_type_access_query(context, session=None):
 4109     return model_query(context, models.ShareTypeProjects, session=session,
 4110                        read_deleted="no")
 4111 
 4112 
 4113 @require_admin_context
 4114 def share_type_access_get_all(context, type_id):
 4115     share_type_id = _share_type_get_id_from_share_type(context, type_id)
 4116     return (_share_type_access_query(context).
 4117             filter_by(share_type_id=share_type_id).all())
 4118 
 4119 
 4120 @require_admin_context
 4121 def share_type_access_add(context, type_id, project_id):
 4122     """Add given tenant to the share type access list."""
 4123     share_type_id = _share_type_get_id_from_share_type(context, type_id)
 4124 
 4125     access_ref = models.ShareTypeProjects()
 4126     access_ref.update({"share_type_id": share_type_id,
 4127                        "project_id": project_id})
 4128 
 4129     session = get_session()
 4130     with session.begin():
 4131         try:
 4132             access_ref.save(session=session)
 4133         except db_exception.DBDuplicateEntry:
 4134             raise exception.ShareTypeAccessExists(share_type_id=type_id,
 4135                                                   project_id=project_id)
 4136         return access_ref
 4137 
 4138 
 4139 @require_admin_context
 4140 def share_type_access_remove(context, type_id, project_id):
 4141     """Remove given tenant from the share type access list."""
 4142     share_type_id = _share_type_get_id_from_share_type(context, type_id)
 4143 
 4144     count = (_share_type_access_query(context).
 4145              filter_by(share_type_id=share_type_id).
 4146              filter_by(project_id=project_id).
 4147              soft_delete(synchronize_session=False))
 4148     if count == 0:
 4149         raise exception.ShareTypeAccessNotFound(
 4150             share_type_id=type_id, project_id=project_id)
 4151 
 4152 ####################
 4153 
 4154 
 4155 def _share_type_extra_specs_query(context, share_type_id, session=None):
 4156     return (model_query(context, models.ShareTypeExtraSpecs, session=session,
 4157                         read_deleted="no").
 4158             filter_by(share_type_id=share_type_id).
 4159             options(joinedload('share_type')))
 4160 
 4161 
 4162 @require_context
 4163 def share_type_extra_specs_get(context, share_type_id):
 4164     rows = (_share_type_extra_specs_query(context, share_type_id).
 4165             all())
 4166 
 4167     result = {}
 4168     for row in rows:
 4169         result[row['key']] = row['value']
 4170 
 4171     return result
 4172 
 4173 
 4174 @require_context
 4175 def share_type_extra_specs_delete(context, share_type_id, key):
 4176     session = get_session()
 4177     with session.begin():
 4178         _share_type_extra_specs_get_item(context, share_type_id, key, session)
 4179         (_share_type_extra_specs_query(context, share_type_id, session).
 4180             filter_by(key=key).soft_delete())
 4181 
 4182 
 4183 def _share_type_extra_specs_get_item(context, share_type_id, key,
 4184                                      session=None):
 4185     result = _share_type_extra_specs_query(
 4186         context, share_type_id, session=session
 4187     ).filter_by(key=key).options(joinedload('share_type')).first()
 4188 
 4189     if not result:
 4190         raise exception.ShareTypeExtraSpecsNotFound(
 4191             extra_specs_key=key,
 4192             share_type_id=share_type_id)
 4193 
 4194     return result
 4195 
 4196 
 4197 @require_context
 4198 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 4199 def share_type_extra_specs_update_or_create(context, share_type_id, specs):
 4200     session = get_session()
 4201     with session.begin():
 4202         spec_ref = None
 4203         for key, value in specs.items():
 4204             try:
 4205                 spec_ref = _share_type_extra_specs_get_item(
 4206                     context, share_type_id, key, session)
 4207             except exception.ShareTypeExtraSpecsNotFound:
 4208                 spec_ref = models.ShareTypeExtraSpecs()
 4209             spec_ref.update({"key": key, "value": value,
 4210                              "share_type_id": share_type_id,
 4211                              "deleted": 0})
 4212             spec_ref.save(session=session)
 4213 
 4214         return specs
 4215 
 4216 
 4217 def _ensure_availability_zone_exists(context, values, session, strict=True):
 4218     az_name = values.pop('availability_zone', None)
 4219 
 4220     if strict and not az_name:
 4221         msg = _("Values dict should have 'availability_zone' field.")
 4222         raise ValueError(msg)
 4223     elif not az_name:
 4224         return
 4225 
 4226     if uuidutils.is_uuid_like(az_name):
 4227         az_ref = availability_zone_get(context, az_name, session=session)
 4228     else:
 4229         az_ref = availability_zone_create_if_not_exist(
 4230             context, az_name, session=session)
 4231 
 4232     values.update({'availability_zone_id': az_ref['id']})
 4233 
 4234 
 4235 @require_context
 4236 def availability_zone_get(context, id_or_name, session=None):
 4237     if session is None:
 4238         session = get_session()
 4239 
 4240     query = model_query(context, models.AvailabilityZone, session=session)
 4241 
 4242     if uuidutils.is_uuid_like(id_or_name):
 4243         query = query.filter_by(id=id_or_name)
 4244     else:
 4245         query = query.filter_by(name=id_or_name)
 4246 
 4247     result = query.first()
 4248 
 4249     if not result:
 4250         raise exception.AvailabilityZoneNotFound(id=id_or_name)
 4251 
 4252     return result
 4253 
 4254 
 4255 @require_context
 4256 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 4257 def availability_zone_create_if_not_exist(context, name, session=None):
 4258     if session is None:
 4259         session = get_session()
 4260 
 4261     az = models.AvailabilityZone()
 4262     az.update({'id': uuidutils.generate_uuid(), 'name': name})
 4263     try:
 4264         with session.begin():
 4265             az.save(session)
 4266     # NOTE(u_glide): Do not catch specific exception here, because it depends
 4267     # on concrete backend used by SqlAlchemy
 4268     except Exception:
 4269         return availability_zone_get(context, name, session=session)
 4270     return az
 4271 
 4272 
 4273 @require_context
 4274 def availability_zone_get_all(context):
 4275     session = get_session()
 4276 
 4277     enabled_services = model_query(
 4278         context, models.Service,
 4279         models.Service.availability_zone_id,
 4280         session=session,
 4281         read_deleted="no"
 4282     ).filter_by(disabled=False).distinct()
 4283 
 4284     return model_query(context, models.AvailabilityZone, session=session,
 4285                        read_deleted="no").filter(
 4286         models.AvailabilityZone.id.in_(enabled_services)
 4287     ).all()
 4288 
 4289 
 4290 @require_admin_context
 4291 def purge_deleted_records(context, age_in_days):
 4292     """Purge soft-deleted records older than(and equal) age from tables."""
 4293 
 4294     if age_in_days < 0:
 4295         msg = _('Must supply a non-negative value for "age_in_days".')
 4296         LOG.error(msg)
 4297         raise exception.InvalidParameterValue(msg)
 4298 
 4299     metadata = MetaData()
 4300     metadata.reflect(get_engine())
 4301     session = get_session()
 4302     session.begin()
 4303     deleted_age = timeutils.utcnow() - datetime.timedelta(days=age_in_days)
 4304 
 4305     for table in reversed(metadata.sorted_tables):
 4306         if 'deleted' in table.columns.keys():
 4307             try:
 4308                 mds = [m for m in models.__dict__.values() if
 4309                        (hasattr(m, '__tablename__') and
 4310                         m.__tablename__ == six.text_type(table))]
 4311                 if len(mds) > 0:
 4312                     # collect all soft-deleted records
 4313                     with session.begin_nested():
 4314                         model = mds[0]
 4315                         s_deleted_records = session.query(model).filter(
 4316                             model.deleted_at <= deleted_age)
 4317                     deleted_count = 0
 4318                     # delete records one by one,
 4319                     # skip the records which has FK constraints
 4320                     for record in s_deleted_records:
 4321                         try:
 4322                             with session.begin_nested():
 4323                                 session.delete(record)
 4324                                 deleted_count += 1
 4325                         except db_exc.DBError:
 4326                             LOG.warning(
 4327                                 ("Deleting soft-deleted resource %s "
 4328                                  "failed, skipping."), record)
 4329                     if deleted_count != 0:
 4330                         LOG.info("Deleted %(count)s records in "
 4331                                  "table %(table)s.",
 4332                                  {'count': deleted_count, 'table': table})
 4333             except db_exc.DBError:
 4334                 LOG.warning("Querying table %s's soft-deleted records "
 4335                             "failed, skipping.", table)
 4336     session.commit()
 4337 
 4338 
 4339 ####################
 4340 
 4341 
 4342 def _share_group_get(context, share_group_id, session=None):
 4343     session = session or get_session()
 4344     result = (model_query(context, models.ShareGroup,
 4345                           session=session,
 4346                           project_only=True,
 4347                           read_deleted='no').
 4348               filter_by(id=share_group_id).
 4349               options(joinedload('share_types')).
 4350               first())
 4351 
 4352     if not result:
 4353         raise exception.ShareGroupNotFound(share_group_id=share_group_id)
 4354 
 4355     return result
 4356 
 4357 
 4358 @require_context
 4359 def share_group_get(context, share_group_id, session=None):
 4360     return _share_group_get(context, share_group_id, session=session)
 4361 
 4362 
 4363 def _share_group_get_all(context, project_id=None, share_server_id=None,
 4364                          host=None, detailed=True, filters=None,
 4365                          sort_key=None, sort_dir=None, session=None):
 4366     session = session or get_session()
 4367     sort_key = sort_key or 'created_at'
 4368     sort_dir = sort_dir or 'desc'
 4369 
 4370     query = model_query(
 4371         context, models.ShareGroup, session=session, read_deleted='no')
 4372 
 4373     # Apply filters
 4374     if not filters:
 4375         filters = {}
 4376     no_key = 'key_is_absent'
 4377     for k, v in filters.items():
 4378         temp_k = k.rstrip('~') if k in constants.LIKE_FILTER else k
 4379         filter_attr = getattr(models.ShareGroup, temp_k, no_key)
 4380 
 4381         if filter_attr == no_key:
 4382             msg = _("Share groups cannot be filtered using '%s' key.")
 4383             raise exception.InvalidInput(reason=msg % k)
 4384 
 4385         if k in constants.LIKE_FILTER:
 4386             query = query.filter(filter_attr.op('LIKE')(u'%' + v + u'%'))
 4387         else:
 4388             query = query.filter(filter_attr == v)
 4389 
 4390     if project_id:
 4391         query = query.filter(
 4392             models.ShareGroup.project_id == project_id)
 4393     if host:
 4394         query = query.filter(
 4395             models.ShareGroup.host == host)
 4396     if share_server_id:
 4397         query = query.filter(
 4398             models.ShareGroup.share_server_id == share_server_id)
 4399 
 4400     try:
 4401         query = apply_sorting(models.ShareGroup, query, sort_key, sort_dir)
 4402     except AttributeError:
 4403         msg = _("Wrong sorting key provided - '%s'.") % sort_key
 4404         raise exception.InvalidInput(reason=msg)
 4405 
 4406     if detailed:
 4407         return query.options(joinedload('share_types')).all()
 4408     else:
 4409         query = query.with_entities(
 4410             models.ShareGroup.id, models.ShareGroup.name)
 4411         values = []
 4412         for sg_id, sg_name in query.all():
 4413             values.append({"id": sg_id, "name": sg_name})
 4414         return values
 4415 
 4416 
 4417 @require_admin_context
 4418 def share_group_get_all(context, detailed=True, filters=None, sort_key=None,
 4419                         sort_dir=None):
 4420     return _share_group_get_all(
 4421         context, detailed=detailed, filters=filters,
 4422         sort_key=sort_key, sort_dir=sort_dir)
 4423 
 4424 
 4425 @require_admin_context
 4426 def share_group_get_all_by_host(context, host, detailed=True):
 4427     return _share_group_get_all(context, host=host, detailed=detailed)
 4428 
 4429 
 4430 @require_context
 4431 def share_group_get_all_by_project(context, project_id, detailed=True,
 4432                                    filters=None, sort_key=None, sort_dir=None):
 4433     authorize_project_context(context, project_id)
 4434     return _share_group_get_all(
 4435         context, project_id=project_id, detailed=detailed, filters=filters,
 4436         sort_key=sort_key, sort_dir=sort_dir)
 4437 
 4438 
 4439 @require_context
 4440 def share_group_get_all_by_share_server(context, share_server_id, filters=None,
 4441                                         sort_key=None, sort_dir=None):
 4442     return _share_group_get_all(
 4443         context, share_server_id=share_server_id, filters=filters,
 4444         sort_key=sort_key, sort_dir=sort_dir)
 4445 
 4446 
 4447 @require_context
 4448 def share_group_create(context, values):
 4449     share_group = models.ShareGroup()
 4450     if not values.get('id'):
 4451         values['id'] = six.text_type(uuidutils.generate_uuid())
 4452 
 4453     mappings = []
 4454     for item in values.get('share_types') or []:
 4455         mapping = models.ShareGroupShareTypeMapping()
 4456         mapping['id'] = six.text_type(uuidutils.generate_uuid())
 4457         mapping['share_type_id'] = item
 4458         mapping['share_group_id'] = values['id']
 4459         mappings.append(mapping)
 4460 
 4461     values['share_types'] = mappings
 4462 
 4463     session = get_session()
 4464     with session.begin():
 4465         share_group.update(values)
 4466         session.add(share_group)
 4467 
 4468         return _share_group_get(context, values['id'], session=session)
 4469 
 4470 
 4471 @require_context
 4472 def share_group_update(context, share_group_id, values):
 4473     session = get_session()
 4474     with session.begin():
 4475         share_group_ref = _share_group_get(
 4476             context, share_group_id, session=session)
 4477         share_group_ref.update(values)
 4478         share_group_ref.save(session=session)
 4479         return share_group_ref
 4480 
 4481 
 4482 @require_admin_context
 4483 def share_group_destroy(context, share_group_id):
 4484     session = get_session()
 4485     with session.begin():
 4486         share_group_ref = _share_group_get(
 4487             context, share_group_id, session=session)
 4488         share_group_ref.soft_delete(session)
 4489         session.query(models.ShareGroupShareTypeMapping).filter_by(
 4490             share_group_id=share_group_ref['id']).soft_delete()
 4491 
 4492 
 4493 @require_context
 4494 def count_shares_in_share_group(context, share_group_id, session=None):
 4495     session = session or get_session()
 4496     return (model_query(context, models.Share, session=session,
 4497                         project_only=True, read_deleted="no").
 4498             filter_by(share_group_id=share_group_id).
 4499             count())
 4500 
 4501 
 4502 @require_context
 4503 def get_all_shares_by_share_group(context, share_group_id, session=None):
 4504     session = session or get_session()
 4505     return (model_query(
 4506             context, models.Share, session=session,
 4507             project_only=True, read_deleted="no").
 4508             filter_by(share_group_id=share_group_id).
 4509             all())
 4510 
 4511 
 4512 @require_context
 4513 def count_share_groups(context, project_id, user_id=None,
 4514                        share_type_id=None, session=None):
 4515     query = model_query(
 4516         context, models.ShareGroup,
 4517         func.count(models.ShareGroup.id),
 4518         read_deleted="no",
 4519         session=session).filter_by(project_id=project_id)
 4520     if share_type_id:
 4521         query = query.join("share_group_share_type_mappings").filter_by(
 4522             share_type_id=share_type_id)
 4523     elif user_id is not None:
 4524         query = query.filter_by(user_id=user_id)
 4525     return query.first()[0]
 4526 
 4527 
 4528 @require_context
 4529 def count_share_group_snapshots(context, project_id, user_id=None,
 4530                                 share_type_id=None, session=None):
 4531     query = model_query(
 4532         context, models.ShareGroupSnapshot,
 4533         func.count(models.ShareGroupSnapshot.id),
 4534         read_deleted="no",
 4535         session=session).filter_by(project_id=project_id)
 4536     if share_type_id:
 4537         query = query.join(
 4538             "share_group"
 4539         ).join(
 4540             "share_group_share_type_mappings"
 4541         ).filter_by(share_type_id=share_type_id)
 4542     elif user_id is not None:
 4543         query = query.filter_by(user_id=user_id)
 4544     return query.first()[0]
 4545 
 4546 
 4547 @require_context
 4548 def count_share_group_snapshots_in_share_group(context, share_group_id,
 4549                                                session=None):
 4550     session = session or get_session()
 4551     return model_query(
 4552         context, models.ShareGroupSnapshot, session=session,
 4553         project_only=True, read_deleted="no",
 4554     ).filter_by(
 4555         share_group_id=share_group_id,
 4556     ).count()
 4557 
 4558 
 4559 @require_context
 4560 def count_share_groups_in_share_network(context, share_network_id,
 4561                                         session=None):
 4562     session = session or get_session()
 4563     return (model_query(
 4564             context, models.ShareGroup, session=session,
 4565             project_only=True, read_deleted="no").
 4566             filter_by(share_network_id=share_network_id).
 4567             count())
 4568 
 4569 
 4570 @require_context
 4571 def count_share_group_snapshot_members_in_share(context, share_id,
 4572                                                 session=None):
 4573     session = session or get_session()
 4574     return model_query(
 4575         context, models.ShareSnapshotInstance, session=session,
 4576         project_only=True, read_deleted="no",
 4577     ).join(
 4578         models.ShareInstance,
 4579         models.ShareInstance.id == (
 4580             models.ShareSnapshotInstance.share_instance_id),
 4581     ).filter(
 4582         models.ShareInstance.share_id == share_id,
 4583     ).count()
 4584 
 4585 
 4586 @require_context
 4587 def _share_group_snapshot_get(context, share_group_snapshot_id, session=None):
 4588     session = session or get_session()
 4589     result = model_query(
 4590         context, models.ShareGroupSnapshot, session=session,
 4591         project_only=True, read_deleted='no',
 4592     ).options(
 4593         joinedload('share_group'),
 4594         joinedload('share_group_snapshot_members'),
 4595     ).filter_by(
 4596         id=share_group_snapshot_id,
 4597     ).first()
 4598 
 4599     if not result:
 4600         raise exception.ShareGroupSnapshotNotFound(
 4601             share_group_snapshot_id=share_group_snapshot_id)
 4602 
 4603     return result
 4604 
 4605 
 4606 def _share_group_snapshot_get_all(
 4607         context, project_id=None, detailed=True, filters=None,
 4608         sort_key=None, sort_dir=None, session=None):
 4609     session = session or get_session()
 4610     if not sort_key:
 4611         sort_key = 'created_at'
 4612     if not sort_dir:
 4613         sort_dir = 'desc'
 4614 
 4615     query = model_query(
 4616         context, models.ShareGroupSnapshot, session=session, read_deleted='no',
 4617     ).options(
 4618         joinedload('share_group'),
 4619         joinedload('share_group_snapshot_members'),
 4620     )
 4621 
 4622     # Apply filters
 4623     if not filters:
 4624         filters = {}
 4625     no_key = 'key_is_absent'
 4626     for k, v in filters.items():
 4627         filter_attr = getattr(models.ShareGroupSnapshot, k, no_key)
 4628         if filter_attr == no_key:
 4629             msg = _("Share group snapshots cannot be filtered using '%s' key.")
 4630             raise exception.InvalidInput(reason=msg % k)
 4631         query = query.filter(filter_attr == v)
 4632 
 4633     if project_id:
 4634         query = query.filter(
 4635             models.ShareGroupSnapshot.project_id == project_id)
 4636 
 4637     try:
 4638         query = apply_sorting(
 4639             models.ShareGroupSnapshot, query, sort_key, sort_dir)
 4640     except AttributeError:
 4641         msg = _("Wrong sorting key provided - '%s'.") % sort_key
 4642         raise exception.InvalidInput(reason=msg)
 4643 
 4644     if detailed:
 4645         return query.all()
 4646     else:
 4647         query = query.with_entities(models.ShareGroupSnapshot.id,
 4648                                     models.ShareGroupSnapshot.name)
 4649         values = []
 4650         for sgs_id, sgs_name in query.all():
 4651             values.append({"id": sgs_id, "name": sgs_name})
 4652         return values
 4653 
 4654 
 4655 @require_context
 4656 def share_group_snapshot_get(context, share_group_snapshot_id, session=None):
 4657     session = session or get_session()
 4658     return _share_group_snapshot_get(
 4659         context, share_group_snapshot_id, session=session)
 4660 
 4661 
 4662 @require_admin_context
 4663 def share_group_snapshot_get_all(
 4664         context, detailed=True, filters=None, sort_key=None, sort_dir=None):
 4665     return _share_group_snapshot_get_all(
 4666         context, filters=filters, detailed=detailed,
 4667         sort_key=sort_key, sort_dir=sort_dir)
 4668 
 4669 
 4670 @require_context
 4671 def share_group_snapshot_get_all_by_project(
 4672         context, project_id, detailed=True, filters=None,
 4673         sort_key=None, sort_dir=None):
 4674     authorize_project_context(context, project_id)
 4675     return _share_group_snapshot_get_all(
 4676         context, project_id=project_id, filters=filters, detailed=detailed,
 4677         sort_key=sort_key, sort_dir=sort_dir,
 4678     )
 4679 
 4680 
 4681 @require_context
 4682 def share_group_snapshot_create(context, values):
 4683     share_group_snapshot = models.ShareGroupSnapshot()
 4684     if not values.get('id'):
 4685         values['id'] = six.text_type(uuidutils.generate_uuid())
 4686 
 4687     session = get_session()
 4688     with session.begin():
 4689         share_group_snapshot.update(values)
 4690         session.add(share_group_snapshot)
 4691 
 4692         return _share_group_snapshot_get(
 4693             context, values['id'], session=session)
 4694 
 4695 
 4696 @require_context
 4697 def share_group_snapshot_update(context, share_group_snapshot_id, values):
 4698     session = get_session()
 4699     with session.begin():
 4700         share_group_ref = _share_group_snapshot_get(
 4701             context, share_group_snapshot_id, session=session)
 4702         share_group_ref.update(values)
 4703         share_group_ref.save(session=session)
 4704         return share_group_ref
 4705 
 4706 
 4707 @require_admin_context
 4708 def share_group_snapshot_destroy(context, share_group_snapshot_id):
 4709     session = get_session()
 4710     with session.begin():
 4711         share_group_snap_ref = _share_group_snapshot_get(
 4712             context, share_group_snapshot_id, session=session)
 4713         share_group_snap_ref.soft_delete(session)
 4714         session.query(models.ShareSnapshotInstance).filter_by(
 4715             share_group_snapshot_id=share_group_snapshot_id).soft_delete()
 4716 
 4717 
 4718 @require_context
 4719 def share_group_snapshot_members_get_all(context, share_group_snapshot_id,
 4720                                          session=None):
 4721     session = session or get_session()
 4722     query = model_query(
 4723         context, models.ShareSnapshotInstance, session=session,
 4724         read_deleted='no',
 4725     ).filter_by(share_group_snapshot_id=share_group_snapshot_id)
 4726     return query.all()
 4727 
 4728 
 4729 @require_context
 4730 def share_group_snapshot_member_get(context, member_id, session=None):
 4731     result = model_query(
 4732         context, models.ShareSnapshotInstance, session=session,
 4733         project_only=True, read_deleted='no',
 4734     ).filter_by(id=member_id).first()
 4735     if not result:
 4736         raise exception.ShareGroupSnapshotMemberNotFound(member_id=member_id)
 4737     return result
 4738 
 4739 
 4740 @require_context
 4741 def share_group_snapshot_member_create(context, values):
 4742     member = models.ShareSnapshotInstance()
 4743     if not values.get('id'):
 4744         values['id'] = six.text_type(uuidutils.generate_uuid())
 4745 
 4746     _change_size_to_instance_size(values)
 4747 
 4748     session = get_session()
 4749     with session.begin():
 4750         member.update(values)
 4751         session.add(member)
 4752 
 4753         return share_group_snapshot_member_get(
 4754             context, values['id'], session=session)
 4755 
 4756 
 4757 @require_context
 4758 def share_group_snapshot_member_update(context, member_id, values):
 4759     session = get_session()
 4760     _change_size_to_instance_size(values)
 4761     with session.begin():
 4762         member = share_group_snapshot_member_get(
 4763             context, member_id, session=session)
 4764         member.update(values)
 4765         session.add(member)
 4766         return share_group_snapshot_member_get(
 4767             context, member_id, session=session)
 4768 
 4769 
 4770 ####################
 4771 
 4772 
 4773 @require_admin_context
 4774 def share_group_type_create(context, values, projects=None):
 4775     """Create a new share group type.
 4776 
 4777     In order to pass in group specs, the values dict should contain a
 4778     'group_specs' key/value pair:
 4779     {'group_specs' : {'k1': 'v1', 'k2': 'v2', ...}}
 4780     """
 4781     values = ensure_model_dict_has_id(values)
 4782 
 4783     projects = projects or []
 4784 
 4785     session = get_session()
 4786     with session.begin():
 4787         try:
 4788             values['group_specs'] = _metadata_refs(
 4789                 values.get('group_specs'), models.ShareGroupTypeSpecs)
 4790             mappings = []
 4791             for item in values.get('share_types', []):
 4792                 share_type = share_type_get_by_name_or_id(context, item)
 4793                 if not share_type:
 4794                     raise exception.ShareTypeDoesNotExist(share_type=item)
 4795                 mapping = models.ShareGroupTypeShareTypeMapping()
 4796                 mapping['id'] = six.text_type(uuidutils.generate_uuid())
 4797                 mapping['share_type_id'] = share_type['id']
 4798                 mapping['share_group_type_id'] = values['id']
 4799                 mappings.append(mapping)
 4800 
 4801             values['share_types'] = mappings
 4802             share_group_type_ref = models.ShareGroupTypes()
 4803             share_group_type_ref.update(values)
 4804             share_group_type_ref.save(session=session)
 4805         except db_exception.DBDuplicateEntry:
 4806             raise exception.ShareGroupTypeExists(type_id=values['name'])
 4807         except exception.ShareTypeDoesNotExist:
 4808             raise
 4809         except Exception as e:
 4810             raise db_exception.DBError(e)
 4811 
 4812         for project in set(projects):
 4813             access_ref = models.ShareGroupTypeProjects()
 4814             access_ref.update({"share_group_type_id": share_group_type_ref.id,
 4815                                "project_id": project})
 4816             access_ref.save(session=session)
 4817 
 4818         return share_group_type_ref
 4819 
 4820 
 4821 def _share_group_type_get_query(context, session=None, read_deleted=None,
 4822                                 expected_fields=None):
 4823     expected_fields = expected_fields or []
 4824     query = model_query(
 4825         context, models.ShareGroupTypes, session=session,
 4826         read_deleted=read_deleted
 4827     ).options(
 4828         joinedload('group_specs'),
 4829         joinedload('share_types'),
 4830     )
 4831 
 4832     if 'projects' in expected_fields:
 4833         query = query.options(joinedload('projects'))
 4834 
 4835     if not context.is_admin:
 4836         the_filter = [models.ShareGroupTypes.is_public == true()]
 4837         projects_attr = getattr(models.ShareGroupTypes, 'projects')
 4838         the_filter.extend([
 4839             projects_attr.any(project_id=context.project_id)
 4840         ])
 4841         query = query.filter(or_(*the_filter))
 4842 
 4843     return query
 4844 
 4845 
 4846 @require_context
 4847 def share_group_type_get_all(context, inactive=False, filters=None):
 4848     """Returns a dict describing all share group types with name as key."""
 4849     filters = filters or {}
 4850     read_deleted = "yes" if inactive else "no"
 4851     query = _share_group_type_get_query(context, read_deleted=read_deleted)
 4852 
 4853     if 'is_public' in filters and filters['is_public'] is not None:
 4854         the_filter = [models.ShareGroupTypes.is_public == filters['is_public']]
 4855         if filters['is_public'] and context.project_id is not None:
 4856             projects_attr = getattr(models. ShareGroupTypes, 'projects')
 4857             the_filter.extend([
 4858                 projects_attr.any(
 4859                     project_id=context.project_id, deleted=0)
 4860             ])
 4861         if len(the_filter) > 1:
 4862             query = query.filter(or_(*the_filter))
 4863         else:
 4864             query = query.filter(the_filter[0])
 4865 
 4866     rows = query.order_by("name").all()
 4867 
 4868     result = {}
 4869     for row in rows:
 4870         result[row['name']] = _dict_with_specs(row, 'group_specs')
 4871 
 4872     return result
 4873 
 4874 
 4875 def _share_group_type_get_id_from_share_group_type_query(context, type_id,
 4876                                                          session=None):
 4877     return model_query(
 4878         context, models.ShareGroupTypes, read_deleted="no", session=session,
 4879     ).filter_by(id=type_id)
 4880 
 4881 
 4882 def _share_group_type_get_id_from_share_group_type(context, type_id,
 4883                                                    session=None):
 4884     result = _share_group_type_get_id_from_share_group_type_query(
 4885         context, type_id, session=session).first()
 4886     if not result:
 4887         raise exception.ShareGroupTypeNotFound(type_id=type_id)
 4888     return result['id']
 4889 
 4890 
 4891 @require_context
 4892 def _share_group_type_get(context, type_id, session=None, inactive=False,
 4893                           expected_fields=None):
 4894     expected_fields = expected_fields or []
 4895     read_deleted = "yes" if inactive else "no"
 4896     result = _share_group_type_get_query(
 4897         context, session, read_deleted, expected_fields,
 4898     ).filter_by(id=type_id).first()
 4899 
 4900     if not result:
 4901         raise exception.ShareGroupTypeNotFound(type_id=type_id)
 4902 
 4903     share_group_type = _dict_with_specs(result, 'group_specs')
 4904 
 4905     if 'projects' in expected_fields:
 4906         share_group_type['projects'] = [
 4907             p['project_id'] for p in result['projects']]
 4908 
 4909     return share_group_type
 4910 
 4911 
 4912 @require_context
 4913 def share_group_type_get(context, type_id, inactive=False,
 4914                          expected_fields=None):
 4915     """Return a dict describing specific share group type."""
 4916     return _share_group_type_get(
 4917         context, type_id, session=None, inactive=inactive,
 4918         expected_fields=expected_fields)
 4919 
 4920 
 4921 @require_context
 4922 def _share_group_type_get_by_name(context, name, session=None):
 4923     result = model_query(
 4924         context, models.ShareGroupTypes, session=session,
 4925     ).options(
 4926         joinedload('group_specs'),
 4927         joinedload('share_types'),
 4928     ).filter_by(
 4929         name=name,
 4930     ).first()
 4931     if not result:
 4932         raise exception.ShareGroupTypeNotFoundByName(type_name=name)
 4933     return _dict_with_specs(result, 'group_specs')
 4934 
 4935 
 4936 @require_context
 4937 def share_group_type_get_by_name(context, name):
 4938     """Return a dict describing specific share group type."""
 4939     return _share_group_type_get_by_name(context, name)
 4940 
 4941 
 4942 @require_admin_context
 4943 def share_group_type_destroy(context, type_id):
 4944     session = get_session()
 4945     with session.begin():
 4946         _share_group_type_get(context, type_id, session)
 4947         results = model_query(
 4948             context, models.ShareGroup, session=session, read_deleted="no",
 4949         ).filter_by(
 4950             share_group_type_id=type_id,
 4951         ).count()
 4952         if results:
 4953             LOG.error('Share group type %s deletion failed, it in use.',
 4954                       type_id)
 4955             raise exception.ShareGroupTypeInUse(type_id=type_id)
 4956         model_query(
 4957             context, models.ShareGroupTypeSpecs, session=session,
 4958         ).filter_by(
 4959             share_group_type_id=type_id,
 4960         ).soft_delete()
 4961         model_query(
 4962             context, models.ShareGroupTypeShareTypeMapping, session=session
 4963         ).filter_by(
 4964             share_group_type_id=type_id,
 4965         ).soft_delete()
 4966         model_query(
 4967             context, models.ShareGroupTypeProjects, session=session
 4968         ).filter_by(
 4969             share_group_type_id=type_id,
 4970         ).soft_delete()
 4971         model_query(
 4972             context, models.ShareGroupTypes, session=session
 4973         ).filter_by(
 4974             id=type_id,
 4975         ).soft_delete()
 4976 
 4977 
 4978 def _share_group_type_access_query(context, session=None):
 4979     return model_query(context, models.ShareGroupTypeProjects, session=session,
 4980                        read_deleted="no")
 4981 
 4982 
 4983 @require_admin_context
 4984 def share_group_type_access_get_all(context, type_id):
 4985     share_group_type_id = _share_group_type_get_id_from_share_group_type(
 4986         context, type_id)
 4987     return _share_group_type_access_query(context).filter_by(
 4988         share_group_type_id=share_group_type_id,
 4989     ).all()
 4990 
 4991 
 4992 @require_admin_context
 4993 def share_group_type_access_add(context, type_id, project_id):
 4994     """Add given tenant to the share group type  access list."""
 4995     share_group_type_id = _share_group_type_get_id_from_share_group_type(
 4996         context, type_id)
 4997     access_ref = models.ShareGroupTypeProjects()
 4998     access_ref.update({"share_group_type_id": share_group_type_id,
 4999                        "project_id": project_id})
 5000     session = get_session()
 5001     with session.begin():
 5002         try:
 5003             access_ref.save(session=session)
 5004         except db_exception.DBDuplicateEntry:
 5005             raise exception.ShareGroupTypeAccessExists(
 5006                 type_id=share_group_type_id, project_id=project_id)
 5007         return access_ref
 5008 
 5009 
 5010 @require_admin_context
 5011 def share_group_type_access_remove(context, type_id, project_id):
 5012     """Remove given tenant from the share group type access list."""
 5013     share_group_type_id = _share_group_type_get_id_from_share_group_type(
 5014         context, type_id)
 5015     count = _share_group_type_access_query(context).filter_by(
 5016         share_group_type_id=share_group_type_id,
 5017     ).filter_by(
 5018         project_id=project_id,
 5019     ).soft_delete(
 5020         synchronize_session=False,
 5021     )
 5022     if count == 0:
 5023         raise exception.ShareGroupTypeAccessNotFound(
 5024             type_id=share_group_type_id, project_id=project_id)
 5025 
 5026 
 5027 def _share_group_type_specs_query(context, type_id, session=None):
 5028     return model_query(
 5029         context, models.ShareGroupTypeSpecs, session=session, read_deleted="no"
 5030     ).filter_by(
 5031         share_group_type_id=type_id,
 5032     ).options(
 5033         joinedload('share_group_type'),
 5034     )
 5035 
 5036 
 5037 @require_context
 5038 def share_group_type_specs_get(context, type_id):
 5039     rows = _share_group_type_specs_query(context, type_id).all()
 5040     result = {}
 5041     for row in rows:
 5042         result[row['key']] = row['value']
 5043     return result
 5044 
 5045 
 5046 @require_context
 5047 def share_group_type_specs_delete(context, type_id, key):
 5048     session = get_session()
 5049     with session.begin():
 5050         _share_group_type_specs_get_item(context, type_id, key, session)
 5051         _share_group_type_specs_query(
 5052             context, type_id, session,
 5053         ).filter_by(
 5054             key=key,
 5055         ).soft_delete()
 5056 
 5057 
 5058 @require_context
 5059 def _share_group_type_specs_get_item(context, type_id, key, session=None):
 5060     result = _share_group_type_specs_query(
 5061         context, type_id, session=session,
 5062     ).filter_by(
 5063         key=key,
 5064     ).options(
 5065         joinedload('share_group_type'),
 5066     ).first()
 5067 
 5068     if not result:
 5069         raise exception.ShareGroupTypeSpecsNotFound(
 5070             specs_key=key, type_id=type_id)
 5071 
 5072     return result
 5073 
 5074 
 5075 @require_context
 5076 @oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
 5077 def share_group_type_specs_update_or_create(context, type_id, specs):
 5078     session = get_session()
 5079     with session.begin():
 5080         spec_ref = None
 5081         for key, value in specs.items():
 5082             try:
 5083                 spec_ref = _share_group_type_specs_get_item(
 5084                     context, type_id, key, session)
 5085             except exception.ShareGroupTypeSpecsNotFound:
 5086                 spec_ref = models.ShareGroupTypeSpecs()
 5087             spec_ref.update({"key": key, "value": value,
 5088                              "share_group_type_id": type_id, "deleted": 0})
 5089             spec_ref.save(session=session)
 5090 
 5091         return specs
 5092 
 5093 
 5094 ###############################
 5095 
 5096 
 5097 @require_context
 5098 def message_get(context, message_id):
 5099     query = model_query(context,
 5100                         models.Message,
 5101                         read_deleted="no",
 5102                         project_only="yes")
 5103     result = query.filter_by(id=message_id).first()
 5104     if not result:
 5105         raise exception.MessageNotFound(message_id=message_id)
 5106     return result
 5107 
 5108 
 5109 @require_context
 5110 def message_get_all(context, filters=None, sort_key='created_at',
 5111                     sort_dir='asc'):
 5112     messages = models.Message
 5113     query = model_query(context,
 5114                         messages,
 5115                         read_deleted="no",
 5116                         project_only="yes")
 5117 
 5118     legal_filter_keys = ('request_id', 'resource_type', 'resource_id',
 5119                          'action_id', 'detail_id', 'message_level')
 5120 
 5121     if not filters:
 5122         filters = {}
 5123 
 5124     query = exact_filter(query, messages, filters, legal_filter_keys)
 5125     try:
 5126         query = apply_sorting(messages, query, sort_key, sort_dir)
 5127     except AttributeError:
 5128         msg = _("Wrong sorting key provided - '%s'.") % sort_key
 5129         raise exception.InvalidInput(reason=msg)
 5130 
 5131     return query.all()
 5132 
 5133 
 5134 @require_context
 5135 def message_create(context, message_values):
 5136     values = copy.deepcopy(message_values)
 5137     message_ref = models.Message()
 5138     if not values.get('id'):
 5139         values['id'] = uuidutils.generate_uuid()
 5140     message_ref.update(values)
 5141 
 5142     session = get_session()
 5143     with session.begin():
 5144         session.add(message_ref)
 5145 
 5146     return message_get(context, message_ref['id'])
 5147 
 5148 
 5149 @require_context
 5150 def message_destroy(context, message):
 5151     session = get_session()
 5152     with session.begin():
 5153         (model_query(context, models.Message, session=session).
 5154             filter_by(id=message.get('id')).soft_delete())
 5155 
 5156 
 5157 @require_admin_context
 5158 def cleanup_expired_messages(context):
 5159     session = get_session()
 5160     now = timeutils.utcnow()
 5161     with session.begin():
 5162         return session.query(models.Message).filter(
 5163             models.Message.expires_at < now).delete()
 5164 
 5165 
 5166 @require_context
 5167 def backend_info_get(context, host):
 5168     """Get hash info for given host."""
 5169     session = get_session()
 5170 
 5171     result = _backend_info_query(session, context, host)
 5172 
 5173     return result
 5174 
 5175 
 5176 @require_context
 5177 def backend_info_create(context, host, value):
 5178     session = get_session()
 5179     with session.begin():
 5180         info_ref = models.BackendInfo()
 5181         info_ref.update({"host": host,
 5182                          "info_hash": value})
 5183         info_ref.save(session)
 5184         return info_ref
 5185 
 5186 
 5187 @require_context
 5188 def backend_info_update(context, host, value=None, delete_existing=False):
 5189     """Remove backend info for host name."""
 5190     session = get_session()
 5191 
 5192     with session.begin():
 5193         info_ref = _backend_info_query(session, context, host)
 5194         if info_ref:
 5195             if value:
 5196                 info_ref.update({"info_hash": value})
 5197             elif delete_existing and info_ref['deleted'] != 1:
 5198                 info_ref.update({"deleted": 1,
 5199                                  "deleted_at": timeutils.utcnow()})
 5200         else:
 5201             info_ref = models.BackendInfo()
 5202             info_ref.update({"host": host,
 5203                              "info_hash": value})
 5204         info_ref.save(session)
 5205         return info_ref
 5206 
 5207 
 5208 def _backend_info_query(session, context, host, read_deleted=False):
 5209     result = model_query(
 5210         context, models.BackendInfo, session=session,
 5211         read_deleted=read_deleted,
 5212     ).filter_by(
 5213         host=host,
 5214     ).first()
 5215 
 5216     return result