~ubuntu-branches/ubuntu/quantal/nova/quantal-proposed

« back to all changes in this revision

Viewing changes to nova/api/openstack/v2/contrib/hosts.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-01-20 11:54:15 UTC
  • mto: This revision was merged to the branch mainline in revision 62.
  • Revision ID: package-import@ubuntu.com-20120120115415-h2ujma9o536o1ut6
Tags: upstream-2012.1~e3~20120120.12170
ImportĀ upstreamĀ versionĀ 2012.1~e3~20120120.12170

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2011 Openstack, LLC.
2
 
# All Rights Reserved.
3
 
#
4
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
 
#    not use this file except in compliance with the License. You may obtain
6
 
#    a copy of the License at
7
 
#
8
 
#         http://www.apache.org/licenses/LICENSE-2.0
9
 
#
10
 
#    Unless required by applicable law or agreed to in writing, software
11
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 
#    License for the specific language governing permissions and limitations
14
 
#    under the License.
15
 
 
16
 
"""The hosts admin extension."""
17
 
 
18
 
import webob.exc
19
 
from xml.dom import minidom
20
 
from xml.parsers import expat
21
 
 
22
 
from nova.api.openstack import wsgi
23
 
from nova.api.openstack import xmlutil
24
 
from nova.api.openstack.v2 import extensions
25
 
from nova import compute
26
 
from nova import exception
27
 
from nova import flags
28
 
from nova import log as logging
29
 
from nova.scheduler import api as scheduler_api
30
 
 
31
 
 
32
 
LOG = logging.getLogger("nova.api.openstack.v2.contrib.hosts")
33
 
FLAGS = flags.FLAGS
34
 
 
35
 
 
36
 
class HostIndexTemplate(xmlutil.TemplateBuilder):
37
 
    def construct(self):
38
 
        def shimmer(obj, do_raise=False):
39
 
            # A bare list is passed in; we need to wrap it in a dict
40
 
            return dict(hosts=obj)
41
 
 
42
 
        root = xmlutil.TemplateElement('hosts', selector=shimmer)
43
 
        elem = xmlutil.SubTemplateElement(root, 'host', selector='hosts')
44
 
        elem.set('host_name')
45
 
        elem.set('service')
46
 
 
47
 
        return xmlutil.MasterTemplate(root, 1)
48
 
 
49
 
 
50
 
class HostUpdateTemplate(xmlutil.TemplateBuilder):
51
 
    def construct(self):
52
 
        root = xmlutil.TemplateElement('host')
53
 
        root.set('host')
54
 
        root.set('status')
55
 
 
56
 
        return xmlutil.MasterTemplate(root, 1)
57
 
 
58
 
 
59
 
class HostActionTemplate(xmlutil.TemplateBuilder):
60
 
    def construct(self):
61
 
        root = xmlutil.TemplateElement('host')
62
 
        root.set('host')
63
 
        root.set('power_action')
64
 
 
65
 
        return xmlutil.MasterTemplate(root, 1)
66
 
 
67
 
 
68
 
class HostDeserializer(wsgi.XMLDeserializer):
69
 
    def default(self, string):
70
 
        try:
71
 
            node = minidom.parseString(string)
72
 
        except expat.ExpatError:
73
 
            msg = _("cannot understand XML")
74
 
            raise exception.MalformedRequestBody(reason=msg)
75
 
 
76
 
        updates = {}
77
 
        for child in node.childNodes[0].childNodes:
78
 
            updates[child.tagName] = self.extract_text(child)
79
 
 
80
 
        return dict(body=updates)
81
 
 
82
 
 
83
 
def _list_hosts(req, service=None):
84
 
    """Returns a summary list of hosts, optionally filtering
85
 
    by service type.
86
 
    """
87
 
    context = req.environ['nova.context']
88
 
    hosts = scheduler_api.get_host_list(context)
89
 
    if service:
90
 
        hosts = [host for host in hosts
91
 
                if host["service"] == service]
92
 
    return hosts
93
 
 
94
 
 
95
 
def check_host(fn):
96
 
    """Makes sure that the host exists."""
97
 
    def wrapped(self, req, id, service=None, *args, **kwargs):
98
 
        listed_hosts = _list_hosts(req, service)
99
 
        hosts = [h["host_name"] for h in listed_hosts]
100
 
        if id in hosts:
101
 
            return fn(self, req, id, *args, **kwargs)
102
 
        else:
103
 
            raise exception.HostNotFound(host=id)
104
 
    return wrapped
105
 
 
106
 
 
107
 
class HostController(object):
108
 
    """The Hosts API controller for the OpenStack API."""
109
 
    def __init__(self):
110
 
        self.compute_api = compute.API()
111
 
        super(HostController, self).__init__()
112
 
 
113
 
    @wsgi.serializers(xml=HostIndexTemplate)
114
 
    def index(self, req):
115
 
        return {'hosts': _list_hosts(req)}
116
 
 
117
 
    @wsgi.serializers(xml=HostUpdateTemplate)
118
 
    @wsgi.deserializers(xml=HostDeserializer)
119
 
    @check_host
120
 
    def update(self, req, id, body):
121
 
        for raw_key, raw_val in body.iteritems():
122
 
            key = raw_key.lower().strip()
123
 
            val = raw_val.lower().strip()
124
 
            # NOTE: (dabo) Right now only 'status' can be set, but other
125
 
            # settings may follow.
126
 
            if key == "status":
127
 
                if val[:6] in ("enable", "disabl"):
128
 
                    return self._set_enabled_status(req, id,
129
 
                            enabled=(val.startswith("enable")))
130
 
                else:
131
 
                    explanation = _("Invalid status: '%s'") % raw_val
132
 
                    raise webob.exc.HTTPBadRequest(explanation=explanation)
133
 
            else:
134
 
                explanation = _("Invalid update setting: '%s'") % raw_key
135
 
                raise webob.exc.HTTPBadRequest(explanation=explanation)
136
 
 
137
 
    def _set_enabled_status(self, req, host, enabled):
138
 
        """Sets the specified host's ability to accept new instances."""
139
 
        context = req.environ['nova.context']
140
 
        state = "enabled" if enabled else "disabled"
141
 
        LOG.audit(_("Setting host %(host)s to %(state)s.") % locals())
142
 
        result = self.compute_api.set_host_enabled(context, host=host,
143
 
                enabled=enabled)
144
 
        if result not in ("enabled", "disabled"):
145
 
            # An error message was returned
146
 
            raise webob.exc.HTTPBadRequest(explanation=result)
147
 
        return {"host": host, "status": result}
148
 
 
149
 
    def _host_power_action(self, req, host, action):
150
 
        """Reboots, shuts down or powers up the host."""
151
 
        context = req.environ['nova.context']
152
 
        try:
153
 
            result = self.compute_api.host_power_action(context, host=host,
154
 
                    action=action)
155
 
        except NotImplementedError as e:
156
 
            raise webob.exc.HTTPBadRequest(explanation=e.msg)
157
 
        return {"host": host, "power_action": result}
158
 
 
159
 
    @wsgi.serializers(xml=HostActionTemplate)
160
 
    def startup(self, req, id):
161
 
        return self._host_power_action(req, host=id, action="startup")
162
 
 
163
 
    @wsgi.serializers(xml=HostActionTemplate)
164
 
    def shutdown(self, req, id):
165
 
        return self._host_power_action(req, host=id, action="shutdown")
166
 
 
167
 
    @wsgi.serializers(xml=HostActionTemplate)
168
 
    def reboot(self, req, id):
169
 
        return self._host_power_action(req, host=id, action="reboot")
170
 
 
171
 
 
172
 
class Hosts(extensions.ExtensionDescriptor):
173
 
    """Admin-only host administration"""
174
 
 
175
 
    name = "Hosts"
176
 
    alias = "os-hosts"
177
 
    namespace = "http://docs.openstack.org/compute/ext/hosts/api/v1.1"
178
 
    updated = "2011-06-29T00:00:00+00:00"
179
 
    admin_only = True
180
 
 
181
 
    def get_resources(self):
182
 
        resources = [extensions.ResourceExtension('os-hosts',
183
 
                HostController(),
184
 
                collection_actions={'update': 'PUT'},
185
 
                member_actions={"startup": "GET", "shutdown": "GET",
186
 
                        "reboot": "GET"})]
187
 
        return resources