"Fossies" - the Fresh Open Source Software Archive

Member "zaqar-10.0.0/zaqar/transport/wsgi/v1_0/pools.py" (13 May 2020, 7230 Bytes) of package /linux/misc/openstack/zaqar-10.0.0.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. See also the latest Fossies "Diffs" side-by-side code changes report for "pools.py": 9.0.0_vs_10.0.0.

    1 # Copyright (c) 2013 Rackspace Hosting, Inc.
    2 #
    3 # Licensed under the Apache License, Version 2.0 (the "License");
    4 # you may not use this file except in compliance with the License.
    5 # You may obtain a copy of the License at
    6 #
    7 #    http://www.apache.org/licenses/LICENSE-2.0
    8 #
    9 # Unless required by applicable law or agreed to in writing, software
   10 # distributed under the License is distributed on an "AS IS" BASIS,
   11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   12 # implied.
   13 # See the License for the specific language governing permissions and
   14 # limitations under the License.
   15 
   16 """pools: a resource to handle storage pool management
   17 
   18 A pool is added by an operator by interacting with the
   19 pooling-related endpoints. When specifying a pool, the
   20 following fields are required:
   21 
   22 ::
   23 
   24     {
   25         "name": string,
   26         "weight": integer,
   27         "uri": string::uri
   28     }
   29 
   30 Furthermore, depending on the underlying storage type of pool being
   31 registered, there is an optional field::
   32 
   33     {
   34         "options": {...}
   35     }
   36 """
   37 
   38 import falcon
   39 import jsonschema
   40 from oslo_log import log
   41 import six
   42 
   43 from zaqar.common.api.schemas import pools as schema
   44 from zaqar.common import utils as common_utils
   45 from zaqar.storage import errors
   46 from zaqar.storage import utils as storage_utils
   47 from zaqar.transport import utils as transport_utils
   48 from zaqar.transport.wsgi import errors as wsgi_errors
   49 from zaqar.transport.wsgi import utils as wsgi_utils
   50 
   51 LOG = log.getLogger(__name__)
   52 
   53 
   54 class Listing(object):
   55     """A resource to list registered pools
   56 
   57     :param pools_controller: means to interact with storage
   58     """
   59 
   60     def __init__(self, pools_controller):
   61         self._ctrl = pools_controller
   62 
   63     def on_get(self, request, response, project_id):
   64         """Returns a pool listing as objects embedded in an object:
   65 
   66         ::
   67 
   68             {
   69                 "pools": [
   70                     {"href": "", "weight": 100, "uri": ""},
   71                     ...
   72                 ],
   73                 "links": [
   74                     {"href": "", "rel": "next"}
   75                 ]
   76             }
   77 
   78         :returns: HTTP | 200
   79         """
   80 
   81         LOG.debug(u'LIST pools')
   82 
   83         store = {}
   84         request.get_param('marker', store=store)
   85         request.get_param_as_int('limit', store=store)
   86         request.get_param_as_bool('detailed', store=store)
   87 
   88         cursor = self._ctrl.list(**store)
   89 
   90         pools = list(next(cursor))
   91 
   92         results = {}
   93 
   94         if pools:
   95             store['marker'] = next(cursor)
   96 
   97             for entry in pools:
   98                 entry['href'] = request.path + '/' + entry['name']
   99 
  100         results['links'] = [
  101             {
  102                 'rel': 'next',
  103                 'href': request.path + falcon.to_query_str(store)
  104             }
  105         ]
  106         results['pools'] = pools
  107 
  108         response.content_location = request.relative_uri
  109         response.body = transport_utils.to_json(results)
  110         response.status = falcon.HTTP_200
  111 
  112 
  113 class Resource(object):
  114     """A handler for individual pool.
  115 
  116     :param pools_controller: means to interact with storage
  117     """
  118 
  119     def __init__(self, pools_controller):
  120         self._ctrl = pools_controller
  121         validator_type = jsonschema.Draft4Validator
  122         self._validators = {
  123             'weight': validator_type(schema.patch_weight),
  124             'uri': validator_type(schema.patch_uri),
  125             'options': validator_type(schema.patch_options),
  126             'create': validator_type(schema.create)
  127         }
  128 
  129     def on_get(self, request, response, project_id, pool):
  130         """Returns a JSON object for a single pool entry:
  131 
  132         ::
  133 
  134             {"weight": 100, "uri": "", options: {...}}
  135 
  136             :returns: HTTP | [200, 404]
  137         """
  138         LOG.debug(u'GET pool - name: %s', pool)
  139         data = None
  140         detailed = request.get_param_as_bool('detailed') or False
  141 
  142         try:
  143             data = self._ctrl.get(pool, detailed)
  144 
  145         except errors.PoolDoesNotExist as ex:
  146             LOG.debug(ex)
  147             raise wsgi_errors.HTTPNotFound(six.text_type(ex))
  148 
  149         data['href'] = request.path
  150 
  151         response.body = transport_utils.to_json(data)
  152         response.content_location = request.relative_uri
  153 
  154     def on_put(self, request, response, project_id, pool):
  155         """Registers a new pool. Expects the following input:
  156 
  157         ::
  158 
  159             {"weight": 100, "uri": ""}
  160 
  161         An options object may also be provided.
  162 
  163         :returns: HTTP | [201, 204]
  164         """
  165 
  166         LOG.debug(u'PUT pool - name: %s', pool)
  167 
  168         conf = self._ctrl.driver.conf
  169         data = wsgi_utils.load(request)
  170         wsgi_utils.validate(self._validators['create'], data)
  171         if not storage_utils.can_connect(data['uri'], conf=conf):
  172             raise wsgi_errors.HTTPBadRequestBody(
  173                 'cannot connect to %s' % data['uri']
  174             )
  175         try:
  176             self._ctrl.create(pool, weight=data['weight'],
  177                               uri=data['uri'],
  178                               options=data.get('options', {}))
  179             response.status = falcon.HTTP_201
  180             response.location = request.path
  181         except errors.PoolAlreadyExists as e:
  182             LOG.exception('Pool "%s" already exists', pool)
  183             raise wsgi_errors.HTTPConflict(six.text_type(e))
  184 
  185     def on_delete(self, request, response, project_id, pool):
  186         """Deregisters a pool.
  187 
  188         :returns: HTTP | 204
  189         """
  190 
  191         LOG.debug(u'DELETE pool - name: %s', pool)
  192         self._ctrl.delete(pool)
  193         response.status = falcon.HTTP_204
  194 
  195     def on_patch(self, request, response, project_id, pool):
  196         """Allows one to update a pool's weight, uri, and/or options.
  197 
  198         This method expects the user to submit a JSON object
  199         containing at least one of: 'uri', 'weight', 'options'. If
  200         none are found, the request is flagged as bad. There is also
  201         strict format checking through the use of
  202         jsonschema. Appropriate errors are returned in each case for
  203         badly formatted input.
  204 
  205         :returns: HTTP | 200,400
  206         """
  207 
  208         LOG.debug(u'PATCH pool - name: %s', pool)
  209         data = wsgi_utils.load(request)
  210 
  211         EXPECT = ('weight', 'uri', 'options')
  212         if not any([(field in data) for field in EXPECT]):
  213             LOG.debug(u'PATCH pool, bad params')
  214             raise wsgi_errors.HTTPBadRequestBody(
  215                 'One of `uri`, `weight`, or `options` needs '
  216                 'to be specified'
  217             )
  218 
  219         for field in EXPECT:
  220             wsgi_utils.validate(self._validators[field], data)
  221 
  222         conf = self._ctrl.driver.conf
  223         if 'uri' in data and not storage_utils.can_connect(data['uri'],
  224                                                            conf=conf):
  225             raise wsgi_errors.HTTPBadRequestBody(
  226                 'cannot connect to %s' % data['uri']
  227             )
  228         fields = common_utils.fields(data, EXPECT,
  229                                      pred=lambda v: v is not None)
  230 
  231         try:
  232             self._ctrl.update(pool, **fields)
  233         except errors.PoolDoesNotExist as ex:
  234             LOG.exception('Pool "%s" does not exist', pool)
  235             raise wsgi_errors.HTTPNotFound(six.text_type(ex))