~ubuntu-branches/ubuntu/raring/nova/raring-proposed

« back to all changes in this revision

Viewing changes to nova/api/openstack/volume/contrib/volume_actions.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Adam Gandelman, Chuck Short
  • Date: 2012-11-23 09:04:58 UTC
  • mfrom: (1.1.66)
  • Revision ID: package-import@ubuntu.com-20121123090458-91565o7aev1i1h71
Tags: 2013.1~g1-0ubuntu1
[ Adam Gandelman ]
* debian/control: Ensure novaclient is upgraded with nova,
  require python-keystoneclient >= 1:2.9.0. (LP: #1073289)
* debian/patches/{ubuntu/*, rbd-security.patch}: Dropped, applied
  upstream.
* debian/control: Add python-testtools to Build-Depends.

[ Chuck Short ]
* New upstream version.
* Refreshed debian/patches/avoid_setuptools_git_dependency.patch.
* debian/rules: FTBFS if missing binaries.
* debian/nova-scheudler.install: Add missing rabbit-queues and
  nova-rpc-zmq-receiver.
* Remove nova-volume since it doesnt exist anymore, transition to cinder-*.
* debian/rules: install apport hook in the right place.
* debian/patches/ubuntu-show-tests.patch: Display test failures.
* debian/control: Add depends on genisoimage
* debian/control: Suggest guestmount.
* debian/control: Suggest websockify. (LP: #1076442)
* debian/nova.conf: Disable nova-volume service.
* debian/control: Depend on xen-system-* rather than the hypervisor.
* debian/control, debian/mans/nova-conductor.8, debian/nova-conductor.init,
  debian/nova-conductor.install, debian/nova-conductor.logrotate
  debian/nova-conductor.manpages, debian/nova-conductor.postrm
  debian/nova-conductor.upstart.in: Add nova-conductor service.
* debian/control: Add python-fixtures as a build deps.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#   Copyright 2012 OpenStack, LLC.
2
 
#
3
 
#   Licensed under the Apache License, Version 2.0 (the "License"); you may
4
 
#   not use this file except in compliance with the License. You may obtain
5
 
#   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, WITHOUT
11
 
#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
 
#   License for the specific language governing permissions and limitations
13
 
#   under the License.
14
 
 
15
 
import webob
16
 
from xml.dom import minidom
17
 
 
18
 
from nova.api.openstack import extensions
19
 
from nova.api.openstack import wsgi
20
 
from nova.api.openstack import xmlutil
21
 
from nova import exception
22
 
from nova import flags
23
 
from nova.openstack.common import log as logging
24
 
from nova.openstack.common.rpc import common as rpc_common
25
 
from nova import volume
26
 
 
27
 
 
28
 
FLAGS = flags.FLAGS
29
 
LOG = logging.getLogger(__name__)
30
 
 
31
 
 
32
 
def authorize(context, action_name):
33
 
    action = 'volume_actions:%s' % action_name
34
 
    extensions.extension_authorizer('volume', action)(context)
35
 
 
36
 
 
37
 
class VolumeToImageSerializer(xmlutil.TemplateBuilder):
38
 
    def construct(self):
39
 
        root = xmlutil.TemplateElement('os-volume_upload_image',
40
 
                                       selector='os-volume_upload_image')
41
 
        root.set('id')
42
 
        root.set('updated_at')
43
 
        root.set('status')
44
 
        root.set('display_description')
45
 
        root.set('size')
46
 
        root.set('volume_type')
47
 
        root.set('image_id')
48
 
        root.set('container_format')
49
 
        root.set('disk_format')
50
 
        root.set('image_name')
51
 
        return xmlutil.MasterTemplate(root, 1)
52
 
 
53
 
 
54
 
class VolumeToImageDeserializer(wsgi.XMLDeserializer):
55
 
    """Deserializer to handle xml-formatted requests"""
56
 
    def default(self, string):
57
 
        dom = minidom.parseString(string)
58
 
        action_node = dom.childNodes[0]
59
 
        action_name = action_node.tagName
60
 
 
61
 
        action_data = {}
62
 
        attributes = ["force", "image_name", "container_format", "disk_format"]
63
 
        for attr in attributes:
64
 
            if action_node.hasAttribute(attr):
65
 
                action_data[attr] = action_node.getAttribute(attr)
66
 
        if 'force' in action_data and action_data['force'] == 'True':
67
 
            action_data['force'] = True
68
 
        return {'body': {action_name: action_data}}
69
 
 
70
 
 
71
 
class VolumeActionsController(wsgi.Controller):
72
 
    def __init__(self, *args, **kwargs):
73
 
        super(VolumeActionsController, self).__init__(*args, **kwargs)
74
 
        self.volume_api = volume.API()
75
 
 
76
 
    @wsgi.response(202)
77
 
    @wsgi.action('os-volume_upload_image')
78
 
    @wsgi.serializers(xml=VolumeToImageSerializer)
79
 
    @wsgi.deserializers(xml=VolumeToImageDeserializer)
80
 
    def _volume_upload_image(self, req, id, body):
81
 
        """Uploads the specified volume to image service."""
82
 
        context = req.environ['nova.context']
83
 
        try:
84
 
            params = body['os-volume_upload_image']
85
 
        except (TypeError, KeyError):
86
 
            msg = _("Invalid request body")
87
 
            raise webob.exc.HTTPBadRequest(explanation=msg)
88
 
 
89
 
        if not params.get("image_name"):
90
 
            msg = _("No image_name was specified in request.")
91
 
            raise webob.exc.HTTPBadRequest(explanation=msg)
92
 
 
93
 
        force = params.get('force', False)
94
 
        try:
95
 
            volume = self.volume_api.get(context, id)
96
 
        except exception.VolumeNotFound, error:
97
 
            raise webob.exc.HTTPNotFound(explanation=unicode(error))
98
 
        authorize(context, "upload_image")
99
 
        image_metadata = {"container_format": params.get("container_format",
100
 
                                                         "bare"),
101
 
                          "disk_format": params.get("disk_format", "raw"),
102
 
                          "name": params["image_name"]}
103
 
        try:
104
 
            response = self.volume_api.copy_volume_to_image(context,
105
 
                                                            volume,
106
 
                                                            image_metadata,
107
 
                                                            force)
108
 
        except exception.InvalidVolume, error:
109
 
            raise webob.exc.HTTPBadRequest(explanation=unicode(error))
110
 
        except ValueError, error:
111
 
            raise webob.exc.HTTPBadRequest(explanation=unicode(error))
112
 
        except rpc_common.RemoteError as error:
113
 
            msg = "%(err_type)s: %(err_msg)s" % {'err_type': error.exc_type,
114
 
                                                 'err_msg': error.value}
115
 
            raise webob.exc.HTTPBadRequest(explanation=msg)
116
 
        return {'os-volume_upload_image': response}
117
 
 
118
 
 
119
 
class Volume_actions(extensions.ExtensionDescriptor):
120
 
    """Enable volume actions
121
 
    """
122
 
 
123
 
    name = "VolumeActions"
124
 
    alias = "os-volume-actions"
125
 
    namespace = "http://docs.openstack.org/volume/ext/volume-actions/api/v1.1"
126
 
    updated = "2012-05-31T00:00:00+00:00"
127
 
 
128
 
    def get_controller_extensions(self):
129
 
        controller = VolumeActionsController()
130
 
        extension = extensions.ControllerExtension(self, 'volumes', controller)
131
 
        return [extension]