text: # Copyright 2011 OpenStack Foundation
  # All Rights Reserved.
  #
  #    Licensed under the Apache License, Version 2.0 (the "License"); you may
  #    not use this file except in compliance with the License. You may obtain
  #    a copy of the License at
  #
  #         http://www.apache.org/licenses/LICENSE-2.0
  #
  #    Unless required by applicable law or agreed to in writing, software
  #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  #    License for the specific language governing permissions and limitations
  #    under the License.
  
  from oslo_log import log as logging
  import webob
  from webob import exc
  
  from jacket.api.storage import common
  from jacket.api.storage import extensions
  from jacket.api.storage.openstack import wsgi
  from jacket.api.storage.views import transfers as transfer_view
  from jacket.api.storage import xmlutil
  from jacket.storage import exception
  from jacket.storage.i18n import _, _LI
  from jacket.storage import transfer as transferAPI
  from jacket.storage import utils
  
  LOG = logging.getLogger(__name__)
  
  
  def make_transfer(elem):
      elem.set('id')
      elem.set('volume_id')
      elem.set('created_at')
      elem.set('name')
      elem.set('auth_key')
  
  
  class TransferTemplate(xmlutil.TemplateBuilder):
      def construct(self):
          root = xmlutil.TemplateElement('transfer', selector='transfer')
          make_transfer(root)
          alias = Volume_transfer.alias
          namespace = Volume_transfer.namespace
          return xmlutil.MasterTemplate(root, 1, nsmap={alias: namespace})
  
  
  class TransfersTemplate(xmlutil.TemplateBuilder):
      def construct(self):
          root = xmlutil.TemplateElement('transfers')
          elem = xmlutil.SubTemplateElement(root, 'transfer',
                                            selector='transfers')
          make_transfer(elem)
          alias = Volume_transfer.alias
          namespace = Volume_transfer.namespace
          return xmlutil.MasterTemplate(root, 1, nsmap={alias: namespace})
  
  
  class CreateDeserializer(wsgi.MetadataXMLDeserializer):
      def default(self, string):
          dom = utils.safe_minidom_parse_string(string)
          transfer = self._extract_transfer(dom)
          return {'body': {'transfer': transfer}}
  
      def _extract_transfer(self, node):
          transfer = {}
          transfer_node = self.find_first_child_named(node, 'transfer')
  
          attributes = ['volume_id', 'name']
  
          for attr in attributes:
              if transfer_node.getAttribute(attr):
                  transfer[attr] = transfer_node.getAttribute(attr)
          return transfer
  
  
  class AcceptDeserializer(wsgi.MetadataXMLDeserializer):
      def default(self, string):
          dom = utils.safe_minidom_parse_string(string)
          transfer = self._extract_transfer(dom)
          return {'body': {'accept': transfer}}
  
      def _extract_transfer(self, node):
          transfer = {}
          transfer_node = self.find_first_child_named(node, 'accept')
  
          attributes = ['auth_key']
  
          for attr in attributes:
              if transfer_node.getAttribute(attr):
                  transfer[attr] = transfer_node.getAttribute(attr)
          return transfer
  
  
  class VolumeTransferController(wsgi.Controller):
      """The Volume Transfer API controller for the OpenStack API."""
  
      _view_builder_class = transfer_view.ViewBuilder
  
      def __init__(self):
          self.transfer_api = transferAPI.API()
          super(VolumeTransferController, self).__init__()
  
      @wsgi.serializers(xml=TransferTemplate)
      def show(self, req, id):
          """Return data about active transfers."""
          context = req.environ['storage.context']
  
          try:
              transfer = self.transfer_api.get(context, transfer_id=id)
          except exception.TransferNotFound as error:
              raise exc.HTTPNotFound(explanation=error.msg)
  
          return self._view_builder.detail(req, transfer)
  
      @wsgi.serializers(xml=TransfersTemplate)
      def index(self, req):
          """Returns a summary list of transfers."""
          return self._get_transfers(req, is_detail=False)
  
      @wsgi.serializers(xml=TransfersTemplate)
      def detail(self, req):
          """Returns a detailed list of transfers."""
          return self._get_transfers(req, is_detail=True)
  
      def _get_transfers(self, req, is_detail):
          """Returns a list of transfers, transformed through view builder."""
          context = req.environ['storage.context']
          filters = req.params.copy()
          LOG.debug('Listing volume transfers')
          transfers = self.transfer_api.get_all(context, filters=filters)
          transfer_count = len(transfers)
          limited_list = common.limited(transfers, req)
  
          if is_detail:
              transfers = self._view_builder.detail_list(req, limited_list,
                                                         transfer_count)
          else:
              transfers = self._view_builder.summary_list(req, limited_list,
                                                          transfer_count)
  
          return transfers
  
      @wsgi.response(202)
      @wsgi.serializers(xml=TransferTemplate)
      @wsgi.deserializers(xml=CreateDeserializer)
      def create(self, req, body):
          """Create a new volume transfer."""
          LOG.debug('Creating new volume transfer %s', body)
          self.assert_valid_body(body, 'transfer')
  
          context = req.environ['storage.context']
          transfer = body['transfer']
  
          try:
              volume_id = transfer['volume_id']
          except KeyError:
              msg = _("Incorrect request body format")
              raise exc.HTTPBadRequest(explanation=msg)
  
          name = transfer.get('name', None)
          if name is not None:
              self.validate_string_length(name, 'Transfer name',
                                          min_length=1, max_length=255,
                                          remove_whitespaces=True)
              name = name.strip()
  
          LOG.info(_LI("Creating transfer of volume %s"),
                   volume_id,
                   context=context)
  
          try:
              new_transfer = self.transfer_api.create(context, volume_id, name)
          except exception.InvalidVolume as error:
              raise exc.HTTPBadRequest(explanation=error.msg)
          except exception.VolumeNotFound as error:
              raise exc.HTTPNotFound(explanation=error.msg)
  
          transfer = self._view_builder.create(req,
                                               dict(new_transfer))
          return transfer
  
      @wsgi.response(202)
      @wsgi.serializers(xml=TransferTemplate)
      @wsgi.deserializers(xml=AcceptDeserializer)
      def accept(self, req, id, body):
          """Accept a new volume transfer."""
          transfer_id = id
          LOG.debug('Accepting volume transfer %s', transfer_id)
          self.assert_valid_body(body, 'accept')
  
          context = req.environ['storage.context']
          accept = body['accept']
  
          try:
              auth_key = accept['auth_key']
          except KeyError:
              msg = _("Incorrect request body format")
              raise exc.HTTPBadRequest(explanation=msg)
  
          LOG.info(_LI("Accepting transfer %s"), transfer_id,
                   context=context)
  
          try:
              accepted_transfer = self.transfer_api.accept(context, transfer_id,
                                                           auth_key)
          except exception.VolumeSizeExceedsAvailableQuota as error:
              raise exc.HTTPRequestEntityTooLarge(
                  explanation=error.msg, headers={'Retry-After': '0'})
          except exception.InvalidVolume as error:
              raise exc.HTTPBadRequest(explanation=error.msg)
  
          transfer = \
              self._view_builder.summary(req,
                                         dict(accepted_transfer))
          return transfer
  
      def delete(self, req, id):
          """Delete a transfer."""
          context = req.environ['storage.context']
  
          LOG.info(_LI("Delete transfer with id: %s"), id, context=context)
  
          try:
              self.transfer_api.delete(context, transfer_id=id)
          except exception.TransferNotFound as error:
              raise exc.HTTPNotFound(explanation=error.msg)
          return webob.Response(status_int=202)
  
  
  class Volume_transfer(extensions.ExtensionDescriptor):
      """Volume transfer management support."""
  
      name = "VolumeTransfer"
      alias = "os-volume-transfer"
      namespace = "http://docs.openstack.org/volume/ext/volume-transfer/" + \
                  "api/v1.1"
      updated = "2013-05-29T00:00:00+00:00"
  
      def get_resources(self):
          resources = []
  
          res = extensions.ResourceExtension(Volume_transfer.alias,
                                             VolumeTransferController(),
                                             collection_actions={'detail':
                                                                 'GET'},
                                             member_actions={'accept': 'POST'})
          resources.append(res)
          return resources
  