"Fossies" - the Fresh Open Source Software Archive

Member "glance-20.0.1/glance/api/authorization.py" (12 Aug 2020, 31826 Bytes) of package /linux/misc/openstack/glance-20.0.1.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 "authorization.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20.0.0_vs_20.0.1.

    1 # Copyright 2012 OpenStack Foundation
    2 # Copyright 2013 IBM Corp.
    3 # All Rights Reserved.
    4 #
    5 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    6 #    not use this file except in compliance with the License. You may obtain
    7 #    a copy of the License at
    8 #
    9 #         http://www.apache.org/licenses/LICENSE-2.0
   10 #
   11 #    Unless required by applicable law or agreed to in writing, software
   12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   14 #    License for the specific language governing permissions and limitations
   15 #    under the License.
   16 
   17 import copy
   18 import functools
   19 
   20 from oslo_config import cfg
   21 from oslo_log import log as logging
   22 
   23 from glance.common import exception
   24 from glance.common import store_utils
   25 import glance.domain.proxy
   26 from glance.i18n import _
   27 
   28 CONF = cfg.CONF
   29 LOG = logging.getLogger(__name__)
   30 
   31 
   32 def lazy_update_store_info(func):
   33     """Update store information in location metadata"""
   34     @functools.wraps(func)
   35     def wrapped(context, image, image_repo, **kwargs):
   36         if CONF.enabled_backends:
   37             store_utils.update_store_in_locations(
   38                 image, image_repo)
   39 
   40         return func(context, image, image_repo, **kwargs)
   41 
   42     return wrapped
   43 
   44 
   45 def is_image_mutable(context, image):
   46     """Return True if the image is mutable in this context."""
   47     if context.is_admin:
   48         return True
   49 
   50     if image.owner is None or context.owner is None:
   51         return False
   52 
   53     return image.owner == context.owner
   54 
   55 
   56 @lazy_update_store_info
   57 def proxy_image(context, image, image_repo):
   58     if is_image_mutable(context, image):
   59         return ImageProxy(image, context)
   60     else:
   61         return ImmutableImageProxy(image, context)
   62 
   63 
   64 def is_member_mutable(context, member):
   65     """Return True if the image is mutable in this context."""
   66     if context.is_admin:
   67         return True
   68 
   69     if context.owner is None:
   70         return False
   71 
   72     return member.member_id == context.owner
   73 
   74 
   75 def proxy_member(context, member):
   76     if is_member_mutable(context, member):
   77         return member
   78     else:
   79         return ImmutableMemberProxy(member)
   80 
   81 
   82 def is_task_mutable(context, task):
   83     """Return True if the task is mutable in this context."""
   84     if context.is_admin:
   85         return True
   86 
   87     if context.owner is None:
   88         return False
   89 
   90     return task.owner == context.owner
   91 
   92 
   93 def is_task_stub_mutable(context, task_stub):
   94     """Return True if the task stub is mutable in this context."""
   95     if context.is_admin:
   96         return True
   97 
   98     if context.owner is None:
   99         return False
  100 
  101     return task_stub.owner == context.owner
  102 
  103 
  104 def proxy_task(context, task):
  105     if is_task_mutable(context, task):
  106         return task
  107     else:
  108         return ImmutableTaskProxy(task)
  109 
  110 
  111 def proxy_task_stub(context, task_stub):
  112     if is_task_stub_mutable(context, task_stub):
  113         return task_stub
  114     else:
  115         return ImmutableTaskStubProxy(task_stub)
  116 
  117 
  118 class ImageRepoProxy(glance.domain.proxy.Repo):
  119 
  120     def __init__(self, image_repo, context):
  121         self.context = context
  122         self.image_repo = image_repo
  123         proxy_kwargs = {'context': self.context}
  124         super(ImageRepoProxy, self).__init__(image_repo,
  125                                              item_proxy_class=ImageProxy,
  126                                              item_proxy_kwargs=proxy_kwargs)
  127 
  128     def get(self, image_id):
  129         image = self.image_repo.get(image_id)
  130         return proxy_image(self.context, image, self.image_repo)
  131 
  132     def list(self, *args, **kwargs):
  133         images = self.image_repo.list(*args, **kwargs)
  134         return [proxy_image(self.context, i, self.image_repo) for i in images]
  135 
  136 
  137 def _validate_image_accepts_members(visibility):
  138     if visibility != 'shared':
  139         message = _("Only shared images have members.")
  140         raise exception.Forbidden(message)
  141 
  142 
  143 class ImageMemberRepoProxy(glance.domain.proxy.MemberRepo):
  144 
  145     def __init__(self, member_repo, image, context):
  146         self.member_repo = member_repo
  147         self.image = image
  148         self.context = context
  149         proxy_kwargs = {'context': self.context}
  150         super(ImageMemberRepoProxy, self).__init__(
  151             image,
  152             member_repo,
  153             member_proxy_class=ImageMemberProxy,
  154             member_proxy_kwargs=proxy_kwargs)
  155         _validate_image_accepts_members(self.image.visibility)
  156 
  157     def get(self, member_id):
  158         if (self.context.is_admin or
  159                 self.context.owner in (self.image.owner, member_id)):
  160             member = self.member_repo.get(member_id)
  161             return proxy_member(self.context, member)
  162         else:
  163             message = _("You cannot get image member for %s")
  164             raise exception.Forbidden(message % member_id)
  165 
  166     def list(self, *args, **kwargs):
  167         members = self.member_repo.list(*args, **kwargs)
  168         if (self.context.is_admin or
  169                 self.context.owner == self.image.owner):
  170             return [proxy_member(self.context, m) for m in members]
  171         for member in members:
  172             if member.member_id == self.context.owner:
  173                 return [proxy_member(self.context, member)]
  174         message = _("You cannot get image member for %s")
  175         raise exception.Forbidden(message % self.image.image_id)
  176 
  177     def remove(self, image_member):
  178         if (self.image.owner == self.context.owner or
  179                 self.context.is_admin):
  180             self.member_repo.remove(image_member)
  181         else:
  182             message = _("You cannot delete image member for %s")
  183             raise exception.Forbidden(message
  184                                       % self.image.image_id)
  185 
  186     def add(self, image_member):
  187         if (self.image.owner == self.context.owner or
  188                 self.context.is_admin):
  189             self.member_repo.add(image_member)
  190         else:
  191             message = _("You cannot add image member for %s")
  192             raise exception.Forbidden(message
  193                                       % self.image.image_id)
  194 
  195     def save(self, image_member, from_state=None):
  196         if (self.context.is_admin or
  197                 self.context.owner == image_member.member_id):
  198             self.member_repo.save(image_member, from_state=from_state)
  199         else:
  200             message = _("You cannot update image member %s")
  201             raise exception.Forbidden(message % image_member.member_id)
  202 
  203 
  204 class ImageFactoryProxy(glance.domain.proxy.ImageFactory):
  205 
  206     def __init__(self, image_factory, context):
  207         self.image_factory = image_factory
  208         self.context = context
  209         kwargs = {'context': self.context}
  210         super(ImageFactoryProxy, self).__init__(image_factory,
  211                                                 proxy_class=ImageProxy,
  212                                                 proxy_kwargs=kwargs)
  213 
  214     def new_image(self, **kwargs):
  215         owner = kwargs.pop('owner', self.context.owner)
  216 
  217         if not self.context.is_admin:
  218             if owner is None or owner != self.context.owner:
  219                 message = _("You are not permitted to create images "
  220                             "owned by '%s'.")
  221                 raise exception.Forbidden(message % owner)
  222 
  223         return super(ImageFactoryProxy, self).new_image(owner=owner, **kwargs)
  224 
  225 
  226 class ImageMemberFactoryProxy(glance.domain.proxy.ImageMembershipFactory):
  227 
  228     def __init__(self, image_member_factory, context):
  229         self.image_member_factory = image_member_factory
  230         self.context = context
  231         kwargs = {'context': self.context}
  232         super(ImageMemberFactoryProxy, self).__init__(
  233             image_member_factory,
  234             proxy_class=ImageMemberProxy,
  235             proxy_kwargs=kwargs)
  236 
  237     def new_image_member(self, image, member_id):
  238         owner = image.owner
  239 
  240         if not self.context.is_admin:
  241             if owner is None or owner != self.context.owner:
  242                 message = _("You are not permitted to create image members "
  243                             "for the image.")
  244                 raise exception.Forbidden(message)
  245 
  246         _validate_image_accepts_members(image.visibility)
  247 
  248         return self.image_member_factory.new_image_member(image, member_id)
  249 
  250 
  251 def _immutable_attr(target, attr, proxy=None):
  252 
  253     def get_attr(self):
  254         value = getattr(getattr(self, target), attr)
  255         if proxy is not None:
  256             value = proxy(value)
  257         return value
  258 
  259     def forbidden(self, *args, **kwargs):
  260         resource = getattr(self, 'resource_name', 'resource')
  261         message = _("You are not permitted to modify '%(attr)s' on this "
  262                     "%(resource)s.")
  263         raise exception.Forbidden(message % {'attr': attr,
  264                                              'resource': resource})
  265 
  266     return property(get_attr, forbidden, forbidden)
  267 
  268 
  269 class ImmutableLocations(list):
  270     def forbidden(self, *args, **kwargs):
  271         message = _("You are not permitted to modify locations "
  272                     "for this image.")
  273         raise exception.Forbidden(message)
  274 
  275     def __deepcopy__(self, memo):
  276         return ImmutableLocations(copy.deepcopy(list(self), memo))
  277 
  278     append = forbidden
  279     extend = forbidden
  280     insert = forbidden
  281     pop = forbidden
  282     remove = forbidden
  283     reverse = forbidden
  284     sort = forbidden
  285     __delitem__ = forbidden
  286     __delslice__ = forbidden
  287     __iadd__ = forbidden
  288     __imul__ = forbidden
  289     __setitem__ = forbidden
  290     __setslice__ = forbidden
  291 
  292 
  293 class ImmutableProperties(dict):
  294     def forbidden_key(self, key, *args, **kwargs):
  295         message = _("You are not permitted to modify '%s' on this image.")
  296         raise exception.Forbidden(message % key)
  297 
  298     def forbidden(self, *args, **kwargs):
  299         message = _("You are not permitted to modify this image.")
  300         raise exception.Forbidden(message)
  301 
  302     __delitem__ = forbidden_key
  303     __setitem__ = forbidden_key
  304     pop = forbidden
  305     popitem = forbidden
  306     setdefault = forbidden
  307     update = forbidden
  308 
  309 
  310 class ImmutableTags(set):
  311     def forbidden(self, *args, **kwargs):
  312         message = _("You are not permitted to modify tags on this image.")
  313         raise exception.Forbidden(message)
  314 
  315     add = forbidden
  316     clear = forbidden
  317     difference_update = forbidden
  318     intersection_update = forbidden
  319     pop = forbidden
  320     remove = forbidden
  321     symmetric_difference_update = forbidden
  322     update = forbidden
  323 
  324 
  325 class ImmutableImageProxy(object):
  326     def __init__(self, base, context):
  327         self.base = base
  328         self.context = context
  329         self.resource_name = 'image'
  330 
  331     name = _immutable_attr('base', 'name')
  332     image_id = _immutable_attr('base', 'image_id')
  333     status = _immutable_attr('base', 'status')
  334     created_at = _immutable_attr('base', 'created_at')
  335     updated_at = _immutable_attr('base', 'updated_at')
  336     visibility = _immutable_attr('base', 'visibility')
  337     min_disk = _immutable_attr('base', 'min_disk')
  338     min_ram = _immutable_attr('base', 'min_ram')
  339     protected = _immutable_attr('base', 'protected')
  340     os_hash_algo = _immutable_attr('base', 'os_hash_algo')
  341     os_hash_value = _immutable_attr('base', 'os_hash_value')
  342     os_hidden = _immutable_attr('base', 'os_hidden')
  343     locations = _immutable_attr('base', 'locations', proxy=ImmutableLocations)
  344     checksum = _immutable_attr('base', 'checksum')
  345     owner = _immutable_attr('base', 'owner')
  346     disk_format = _immutable_attr('base', 'disk_format')
  347     container_format = _immutable_attr('base', 'container_format')
  348     size = _immutable_attr('base', 'size')
  349     virtual_size = _immutable_attr('base', 'virtual_size')
  350     extra_properties = _immutable_attr('base', 'extra_properties',
  351                                        proxy=ImmutableProperties)
  352     tags = _immutable_attr('base', 'tags', proxy=ImmutableTags)
  353 
  354     def delete(self):
  355         message = _("You are not permitted to delete this image.")
  356         raise exception.Forbidden(message)
  357 
  358     def get_data(self, *args, **kwargs):
  359         return self.base.get_data(*args, **kwargs)
  360 
  361     def set_data(self, *args, **kwargs):
  362         message = _("You are not permitted to upload data for this image.")
  363         raise exception.Forbidden(message)
  364 
  365     def deactivate(self, *args, **kwargs):
  366         message = _("You are not permitted to deactivate this image.")
  367         raise exception.Forbidden(message)
  368 
  369     def reactivate(self, *args, **kwargs):
  370         message = _("You are not permitted to reactivate this image.")
  371         raise exception.Forbidden(message)
  372 
  373 
  374 class ImmutableMemberProxy(object):
  375     def __init__(self, base):
  376         self.base = base
  377         self.resource_name = 'image member'
  378 
  379     id = _immutable_attr('base', 'id')
  380     image_id = _immutable_attr('base', 'image_id')
  381     member_id = _immutable_attr('base', 'member_id')
  382     status = _immutable_attr('base', 'status')
  383     created_at = _immutable_attr('base', 'created_at')
  384     updated_at = _immutable_attr('base', 'updated_at')
  385 
  386 
  387 class ImmutableTaskProxy(object):
  388     def __init__(self, base):
  389         self.base = base
  390         self.resource_name = 'task'
  391 
  392     task_id = _immutable_attr('base', 'task_id')
  393     type = _immutable_attr('base', 'type')
  394     status = _immutable_attr('base', 'status')
  395     owner = _immutable_attr('base', 'owner')
  396     expires_at = _immutable_attr('base', 'expires_at')
  397     created_at = _immutable_attr('base', 'created_at')
  398     updated_at = _immutable_attr('base', 'updated_at')
  399     input = _immutable_attr('base', 'input')
  400     message = _immutable_attr('base', 'message')
  401     result = _immutable_attr('base', 'result')
  402 
  403     def run(self, executor):
  404         self.base.run(executor)
  405 
  406     def begin_processing(self):
  407         message = _("You are not permitted to set status on this task.")
  408         raise exception.Forbidden(message)
  409 
  410     def succeed(self, result):
  411         message = _("You are not permitted to set status on this task.")
  412         raise exception.Forbidden(message)
  413 
  414     def fail(self, message):
  415         message = _("You are not permitted to set status on this task.")
  416         raise exception.Forbidden(message)
  417 
  418 
  419 class ImmutableTaskStubProxy(object):
  420     def __init__(self, base):
  421         self.base = base
  422         self.resource_name = 'task stub'
  423 
  424     task_id = _immutable_attr('base', 'task_id')
  425     type = _immutable_attr('base', 'type')
  426     status = _immutable_attr('base', 'status')
  427     owner = _immutable_attr('base', 'owner')
  428     expires_at = _immutable_attr('base', 'expires_at')
  429     created_at = _immutable_attr('base', 'created_at')
  430     updated_at = _immutable_attr('base', 'updated_at')
  431 
  432 
  433 class ImageProxy(glance.domain.proxy.Image):
  434 
  435     def __init__(self, image, context):
  436         self.image = image
  437         self.context = context
  438         super(ImageProxy, self).__init__(image)
  439 
  440 
  441 class ImageMemberProxy(glance.domain.proxy.ImageMember):
  442 
  443     def __init__(self, image_member, context):
  444         self.image_member = image_member
  445         self.context = context
  446         super(ImageMemberProxy, self).__init__(image_member)
  447 
  448 
  449 class TaskProxy(glance.domain.proxy.Task):
  450 
  451     def __init__(self, task):
  452         self.task = task
  453         super(TaskProxy, self).__init__(task)
  454 
  455 
  456 class TaskFactoryProxy(glance.domain.proxy.TaskFactory):
  457 
  458     def __init__(self, task_factory, context):
  459         self.task_factory = task_factory
  460         self.context = context
  461         super(TaskFactoryProxy, self).__init__(
  462             task_factory,
  463             task_proxy_class=TaskProxy)
  464 
  465     def new_task(self, **kwargs):
  466         owner = kwargs.get('owner', self.context.owner)
  467 
  468         # NOTE(nikhil): Unlike Images, Tasks are expected to have owner.
  469         # We currently do not allow even admins to set the owner to None.
  470         if owner is not None and (owner == self.context.owner
  471                                   or self.context.is_admin):
  472             return super(TaskFactoryProxy, self).new_task(**kwargs)
  473         else:
  474             message = _("You are not permitted to create this task with "
  475                         "owner as: %s")
  476             raise exception.Forbidden(message % owner)
  477 
  478 
  479 class TaskRepoProxy(glance.domain.proxy.TaskRepo):
  480 
  481     def __init__(self, task_repo, context):
  482         self.task_repo = task_repo
  483         self.context = context
  484         super(TaskRepoProxy, self).__init__(task_repo)
  485 
  486     def get(self, task_id):
  487         task = self.task_repo.get(task_id)
  488         return proxy_task(self.context, task)
  489 
  490 
  491 class TaskStubRepoProxy(glance.domain.proxy.TaskStubRepo):
  492 
  493     def __init__(self, task_stub_repo, context):
  494         self.task_stub_repo = task_stub_repo
  495         self.context = context
  496         super(TaskStubRepoProxy, self).__init__(task_stub_repo)
  497 
  498     def list(self, *args, **kwargs):
  499         task_stubs = self.task_stub_repo.list(*args, **kwargs)
  500         return [proxy_task_stub(self.context, t) for t in task_stubs]
  501 
  502 
  503 # Metadef Namespace classes
  504 def is_namespace_mutable(context, namespace):
  505     """Return True if the namespace is mutable in this context."""
  506     if context.is_admin:
  507         return True
  508 
  509     if context.owner is None:
  510         return False
  511 
  512     return namespace.owner == context.owner
  513 
  514 
  515 def proxy_namespace(context, namespace):
  516     if is_namespace_mutable(context, namespace):
  517         return namespace
  518     else:
  519         return ImmutableMetadefNamespaceProxy(namespace)
  520 
  521 
  522 class ImmutableMetadefNamespaceProxy(object):
  523 
  524     def __init__(self, base):
  525         self.base = base
  526         self.resource_name = 'namespace'
  527 
  528     namespace_id = _immutable_attr('base', 'namespace_id')
  529     namespace = _immutable_attr('base', 'namespace')
  530     display_name = _immutable_attr('base', 'display_name')
  531     description = _immutable_attr('base', 'description')
  532     owner = _immutable_attr('base', 'owner')
  533     visibility = _immutable_attr('base', 'visibility')
  534     protected = _immutable_attr('base', 'protected')
  535     created_at = _immutable_attr('base', 'created_at')
  536     updated_at = _immutable_attr('base', 'updated_at')
  537 
  538     def delete(self):
  539         message = _("You are not permitted to delete this namespace.")
  540         raise exception.Forbidden(message)
  541 
  542     def save(self):
  543         message = _("You are not permitted to update this namespace.")
  544         raise exception.Forbidden(message)
  545 
  546 
  547 class MetadefNamespaceProxy(glance.domain.proxy.MetadefNamespace):
  548 
  549     def __init__(self, namespace):
  550         self.namespace_input = namespace
  551         super(MetadefNamespaceProxy, self).__init__(namespace)
  552 
  553 
  554 class MetadefNamespaceFactoryProxy(
  555         glance.domain.proxy.MetadefNamespaceFactory):
  556 
  557     def __init__(self, meta_namespace_factory, context):
  558         self.meta_namespace_factory = meta_namespace_factory
  559         self.context = context
  560         super(MetadefNamespaceFactoryProxy, self).__init__(
  561             meta_namespace_factory,
  562             meta_namespace_proxy_class=MetadefNamespaceProxy)
  563 
  564     def new_namespace(self, **kwargs):
  565         owner = kwargs.pop('owner', self.context.owner)
  566 
  567         if not self.context.is_admin:
  568             if owner is None or owner != self.context.owner:
  569                 message = _("You are not permitted to create namespace "
  570                             "owned by '%s'")
  571                 raise exception.Forbidden(message % (owner))
  572 
  573         return super(MetadefNamespaceFactoryProxy, self).new_namespace(
  574             owner=owner, **kwargs)
  575 
  576 
  577 class MetadefNamespaceRepoProxy(glance.domain.proxy.MetadefNamespaceRepo):
  578 
  579     def __init__(self, namespace_repo, context):
  580         self.namespace_repo = namespace_repo
  581         self.context = context
  582         super(MetadefNamespaceRepoProxy, self).__init__(namespace_repo)
  583 
  584     def get(self, namespace):
  585         namespace_obj = self.namespace_repo.get(namespace)
  586         return proxy_namespace(self.context, namespace_obj)
  587 
  588     def list(self, *args, **kwargs):
  589         namespaces = self.namespace_repo.list(*args, **kwargs)
  590         return [proxy_namespace(self.context, namespace) for
  591                 namespace in namespaces]
  592 
  593 
  594 # Metadef Object classes
  595 def is_object_mutable(context, object):
  596     """Return True if the object is mutable in this context."""
  597     if context.is_admin:
  598         return True
  599 
  600     if context.owner is None:
  601         return False
  602 
  603     return object.namespace.owner == context.owner
  604 
  605 
  606 def proxy_object(context, object):
  607     if is_object_mutable(context, object):
  608         return object
  609     else:
  610         return ImmutableMetadefObjectProxy(object)
  611 
  612 
  613 class ImmutableMetadefObjectProxy(object):
  614 
  615     def __init__(self, base):
  616         self.base = base
  617         self.resource_name = 'object'
  618 
  619     object_id = _immutable_attr('base', 'object_id')
  620     name = _immutable_attr('base', 'name')
  621     required = _immutable_attr('base', 'required')
  622     description = _immutable_attr('base', 'description')
  623     properties = _immutable_attr('base', 'properties')
  624     created_at = _immutable_attr('base', 'created_at')
  625     updated_at = _immutable_attr('base', 'updated_at')
  626 
  627     def delete(self):
  628         message = _("You are not permitted to delete this object.")
  629         raise exception.Forbidden(message)
  630 
  631     def save(self):
  632         message = _("You are not permitted to update this object.")
  633         raise exception.Forbidden(message)
  634 
  635 
  636 class MetadefObjectProxy(glance.domain.proxy.MetadefObject):
  637 
  638     def __init__(self, meta_object):
  639         self.meta_object = meta_object
  640         super(MetadefObjectProxy, self).__init__(meta_object)
  641 
  642 
  643 class MetadefObjectFactoryProxy(glance.domain.proxy.MetadefObjectFactory):
  644 
  645     def __init__(self, meta_object_factory, context):
  646         self.meta_object_factory = meta_object_factory
  647         self.context = context
  648         super(MetadefObjectFactoryProxy, self).__init__(
  649             meta_object_factory,
  650             meta_object_proxy_class=MetadefObjectProxy)
  651 
  652     def new_object(self, **kwargs):
  653         owner = kwargs.pop('owner', self.context.owner)
  654 
  655         if not self.context.is_admin:
  656             if owner is None or owner != self.context.owner:
  657                 message = _("You are not permitted to create object "
  658                             "owned by '%s'")
  659                 raise exception.Forbidden(message % (owner))
  660 
  661         return super(MetadefObjectFactoryProxy, self).new_object(**kwargs)
  662 
  663 
  664 class MetadefObjectRepoProxy(glance.domain.proxy.MetadefObjectRepo):
  665 
  666     def __init__(self, object_repo, context):
  667         self.object_repo = object_repo
  668         self.context = context
  669         super(MetadefObjectRepoProxy, self).__init__(object_repo)
  670 
  671     def get(self, namespace, object_name):
  672         meta_object = self.object_repo.get(namespace, object_name)
  673         return proxy_object(self.context, meta_object)
  674 
  675     def list(self, *args, **kwargs):
  676         objects = self.object_repo.list(*args, **kwargs)
  677         return [proxy_object(self.context, meta_object) for
  678                 meta_object in objects]
  679 
  680 
  681 # Metadef ResourceType classes
  682 def is_meta_resource_type_mutable(context, meta_resource_type):
  683     """Return True if the meta_resource_type is mutable in this context."""
  684     if context.is_admin:
  685         return True
  686 
  687     if context.owner is None:
  688         return False
  689 
  690     # (lakshmiS): resource type can exist without an association with
  691     # namespace and resource type cannot be created/update/deleted directly(
  692     # they have to be associated/de-associated from namespace)
  693     if meta_resource_type.namespace:
  694         return meta_resource_type.namespace.owner == context.owner
  695     else:
  696         return False
  697 
  698 
  699 def proxy_meta_resource_type(context, meta_resource_type):
  700     if is_meta_resource_type_mutable(context, meta_resource_type):
  701         return meta_resource_type
  702     else:
  703         return ImmutableMetadefResourceTypeProxy(meta_resource_type)
  704 
  705 
  706 class ImmutableMetadefResourceTypeProxy(object):
  707 
  708     def __init__(self, base):
  709         self.base = base
  710         self.resource_name = 'meta_resource_type'
  711 
  712     namespace = _immutable_attr('base', 'namespace')
  713     name = _immutable_attr('base', 'name')
  714     prefix = _immutable_attr('base', 'prefix')
  715     properties_target = _immutable_attr('base', 'properties_target')
  716     created_at = _immutable_attr('base', 'created_at')
  717     updated_at = _immutable_attr('base', 'updated_at')
  718 
  719     def delete(self):
  720         message = _("You are not permitted to delete this meta_resource_type.")
  721         raise exception.Forbidden(message)
  722 
  723 
  724 class MetadefResourceTypeProxy(glance.domain.proxy.MetadefResourceType):
  725 
  726     def __init__(self, meta_resource_type):
  727         self.meta_resource_type = meta_resource_type
  728         super(MetadefResourceTypeProxy, self).__init__(meta_resource_type)
  729 
  730 
  731 class MetadefResourceTypeFactoryProxy(
  732         glance.domain.proxy.MetadefResourceTypeFactory):
  733 
  734     def __init__(self, resource_type_factory, context):
  735         self.meta_resource_type_factory = resource_type_factory
  736         self.context = context
  737         super(MetadefResourceTypeFactoryProxy, self).__init__(
  738             resource_type_factory,
  739             resource_type_proxy_class=MetadefResourceTypeProxy)
  740 
  741     def new_resource_type(self, **kwargs):
  742         owner = kwargs.pop('owner', self.context.owner)
  743 
  744         if not self.context.is_admin:
  745             if owner is None or owner != self.context.owner:
  746                 message = _("You are not permitted to create resource_type "
  747                             "owned by '%s'")
  748                 raise exception.Forbidden(message % (owner))
  749 
  750         return super(MetadefResourceTypeFactoryProxy, self).new_resource_type(
  751             **kwargs)
  752 
  753 
  754 class MetadefResourceTypeRepoProxy(
  755         glance.domain.proxy.MetadefResourceTypeRepo):
  756 
  757     def __init__(self, meta_resource_type_repo, context):
  758         self.meta_resource_type_repo = meta_resource_type_repo
  759         self.context = context
  760         super(MetadefResourceTypeRepoProxy, self).__init__(
  761             meta_resource_type_repo)
  762 
  763     def list(self, *args, **kwargs):
  764         meta_resource_types = self.meta_resource_type_repo.list(
  765             *args, **kwargs)
  766         return [proxy_meta_resource_type(self.context, meta_resource_type) for
  767                 meta_resource_type in meta_resource_types]
  768 
  769     def get(self, *args, **kwargs):
  770         meta_resource_type = self.meta_resource_type_repo.get(*args, **kwargs)
  771         return proxy_meta_resource_type(self.context, meta_resource_type)
  772 
  773 
  774 # Metadef namespace properties classes
  775 def is_namespace_property_mutable(context, namespace_property):
  776     """Return True if the object is mutable in this context."""
  777     if context.is_admin:
  778         return True
  779 
  780     if context.owner is None:
  781         return False
  782 
  783     return namespace_property.namespace.owner == context.owner
  784 
  785 
  786 def proxy_namespace_property(context, namespace_property):
  787     if is_namespace_property_mutable(context, namespace_property):
  788         return namespace_property
  789     else:
  790         return ImmutableMetadefPropertyProxy(namespace_property)
  791 
  792 
  793 class ImmutableMetadefPropertyProxy(object):
  794 
  795     def __init__(self, base):
  796         self.base = base
  797         self.resource_name = 'namespace_property'
  798 
  799     property_id = _immutable_attr('base', 'property_id')
  800     name = _immutable_attr('base', 'name')
  801     schema = _immutable_attr('base', 'schema')
  802 
  803     def delete(self):
  804         message = _("You are not permitted to delete this property.")
  805         raise exception.Forbidden(message)
  806 
  807     def save(self):
  808         message = _("You are not permitted to update this property.")
  809         raise exception.Forbidden(message)
  810 
  811 
  812 class MetadefPropertyProxy(glance.domain.proxy.MetadefProperty):
  813 
  814     def __init__(self, namespace_property):
  815         self.meta_object = namespace_property
  816         super(MetadefPropertyProxy, self).__init__(namespace_property)
  817 
  818 
  819 class MetadefPropertyFactoryProxy(glance.domain.proxy.MetadefPropertyFactory):
  820 
  821     def __init__(self, namespace_property_factory, context):
  822         self.meta_object_factory = namespace_property_factory
  823         self.context = context
  824         super(MetadefPropertyFactoryProxy, self).__init__(
  825             namespace_property_factory,
  826             property_proxy_class=MetadefPropertyProxy)
  827 
  828     def new_namespace_property(self, **kwargs):
  829         owner = kwargs.pop('owner', self.context.owner)
  830 
  831         if not self.context.is_admin:
  832             if owner is None or owner != self.context.owner:
  833                 message = _("You are not permitted to create property "
  834                             "owned by '%s'")
  835                 raise exception.Forbidden(message % (owner))
  836 
  837         return super(MetadefPropertyFactoryProxy, self).new_namespace_property(
  838             **kwargs)
  839 
  840 
  841 class MetadefPropertyRepoProxy(glance.domain.proxy.MetadefPropertyRepo):
  842 
  843     def __init__(self, namespace_property_repo, context):
  844         self.namespace_property_repo = namespace_property_repo
  845         self.context = context
  846         super(MetadefPropertyRepoProxy, self).__init__(namespace_property_repo)
  847 
  848     def get(self, namespace, object_name):
  849         namespace_property = self.namespace_property_repo.get(namespace,
  850                                                               object_name)
  851         return proxy_namespace_property(self.context, namespace_property)
  852 
  853     def list(self, *args, **kwargs):
  854         namespace_properties = self.namespace_property_repo.list(
  855             *args, **kwargs)
  856         return [proxy_namespace_property(self.context, namespace_property) for
  857                 namespace_property in namespace_properties]
  858 
  859 
  860 # Metadef Tag classes
  861 def is_tag_mutable(context, tag):
  862     """Return True if the tag is mutable in this context."""
  863     if context.is_admin:
  864         return True
  865 
  866     if context.owner is None:
  867         return False
  868 
  869     return tag.namespace.owner == context.owner
  870 
  871 
  872 def proxy_tag(context, tag):
  873     if is_tag_mutable(context, tag):
  874         return tag
  875     else:
  876         return ImmutableMetadefTagProxy(tag)
  877 
  878 
  879 class ImmutableMetadefTagProxy(object):
  880 
  881     def __init__(self, base):
  882         self.base = base
  883         self.resource_name = 'tag'
  884 
  885     tag_id = _immutable_attr('base', 'tag_id')
  886     name = _immutable_attr('base', 'name')
  887     created_at = _immutable_attr('base', 'created_at')
  888     updated_at = _immutable_attr('base', 'updated_at')
  889 
  890     def delete(self):
  891         message = _("You are not permitted to delete this tag.")
  892         raise exception.Forbidden(message)
  893 
  894     def save(self):
  895         message = _("You are not permitted to update this tag.")
  896         raise exception.Forbidden(message)
  897 
  898 
  899 class MetadefTagProxy(glance.domain.proxy.MetadefTag):
  900     pass
  901 
  902 
  903 class MetadefTagFactoryProxy(glance.domain.proxy.MetadefTagFactory):
  904 
  905     def __init__(self, meta_tag_factory, context):
  906         self.meta_tag_factory = meta_tag_factory
  907         self.context = context
  908         super(MetadefTagFactoryProxy, self).__init__(
  909             meta_tag_factory,
  910             meta_tag_proxy_class=MetadefTagProxy)
  911 
  912     def new_tag(self, **kwargs):
  913         owner = kwargs.pop('owner', self.context.owner)
  914         if not self.context.is_admin:
  915             if owner is None:
  916                 message = _("Owner must be specified to create a tag.")
  917                 raise exception.Forbidden(message)
  918             elif owner != self.context.owner:
  919                 message = _("You are not permitted to create a tag"
  920                             " in the namespace owned by '%s'")
  921                 raise exception.Forbidden(message % (owner))
  922 
  923         return super(MetadefTagFactoryProxy, self).new_tag(**kwargs)
  924 
  925 
  926 class MetadefTagRepoProxy(glance.domain.proxy.MetadefTagRepo):
  927 
  928     def __init__(self, tag_repo, context):
  929         self.tag_repo = tag_repo
  930         self.context = context
  931         super(MetadefTagRepoProxy, self).__init__(tag_repo)
  932 
  933     def get(self, namespace, tag_name):
  934         meta_tag = self.tag_repo.get(namespace, tag_name)
  935         return proxy_tag(self.context, meta_tag)
  936 
  937     def list(self, *args, **kwargs):
  938         tags = self.tag_repo.list(*args, **kwargs)
  939         return [proxy_tag(self.context, meta_tag) for
  940                 meta_tag in tags]