~ubuntu-branches/ubuntu/quantal/nova/quantal-security

« back to all changes in this revision

Viewing changes to .pc/CVE-2013-1664.patch/nova/api/openstack/compute/contrib/hosts.py

  • Committer: Package Import Robot
  • Author(s): Jamie Strandboge
  • Date: 2013-10-21 15:48:27 UTC
  • mfrom: (94.1.6 quantal-proposed)
  • Revision ID: package-import@ubuntu.com-20131021154827-2rqxw7uhjgnknxxa
Tags: 2012.2.4-0ubuntu3.1
* SECURITY UPDATE: properly honor the is_public flag
  - debian/patches/CVE-2013-2256.patch, CVE-2013-4278.patch: add enforcement
    of is_public in the db layer (LP: #1194093, LP: #1212179)
  - CVE-2013-2256, CVE-2013-4278
* SECURITY UPDATE: denial of service with network security group policy
  updates
  - debian/patches/CVE-2013-4185.patch: use cached nwinfo for secgroup rules
    (LP: #1184041)
  - CVE-2013-4185

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 extensions
23
 
from nova.api.openstack import wsgi
24
 
from nova.api.openstack import xmlutil
25
 
from nova.compute import api as compute_api
26
 
from nova import db
27
 
from nova import exception
28
 
from nova import flags
29
 
from nova.openstack.common import log as logging
30
 
 
31
 
 
32
 
LOG = logging.getLogger(__name__)
33
 
FLAGS = flags.FLAGS
34
 
authorize = extensions.extension_authorizer('compute', 'hosts')
35
 
 
36
 
 
37
 
class HostIndexTemplate(xmlutil.TemplateBuilder):
38
 
    def construct(self):
39
 
        def shimmer(obj, do_raise=False):
40
 
            # A bare list is passed in; we need to wrap it in a dict
41
 
            return dict(hosts=obj)
42
 
 
43
 
        root = xmlutil.TemplateElement('hosts', selector=shimmer)
44
 
        elem = xmlutil.SubTemplateElement(root, 'host', selector='hosts')
45
 
        elem.set('host_name')
46
 
        elem.set('service')
47
 
 
48
 
        return xmlutil.MasterTemplate(root, 1)
49
 
 
50
 
 
51
 
class HostUpdateTemplate(xmlutil.TemplateBuilder):
52
 
    def construct(self):
53
 
        root = xmlutil.TemplateElement('host')
54
 
        root.set('host')
55
 
        root.set('status')
56
 
        root.set('maintenance_mode')
57
 
 
58
 
        return xmlutil.MasterTemplate(root, 1)
59
 
 
60
 
 
61
 
class HostActionTemplate(xmlutil.TemplateBuilder):
62
 
    def construct(self):
63
 
        root = xmlutil.TemplateElement('host')
64
 
        root.set('host')
65
 
        root.set('power_action')
66
 
 
67
 
        return xmlutil.MasterTemplate(root, 1)
68
 
 
69
 
 
70
 
class HostShowTemplate(xmlutil.TemplateBuilder):
71
 
    def construct(self):
72
 
        root = xmlutil.TemplateElement('host')
73
 
        elem = xmlutil.make_flat_dict('resource', selector='host',
74
 
                                      subselector='resource')
75
 
        root.append(elem)
76
 
 
77
 
        return xmlutil.MasterTemplate(root, 1)
78
 
 
79
 
 
80
 
class HostDeserializer(wsgi.XMLDeserializer):
81
 
    def default(self, string):
82
 
        try:
83
 
            node = minidom.parseString(string)
84
 
        except expat.ExpatError:
85
 
            msg = _("cannot understand XML")
86
 
            raise exception.MalformedRequestBody(reason=msg)
87
 
 
88
 
        updates = {}
89
 
        for child in node.childNodes[0].childNodes:
90
 
            updates[child.tagName] = self.extract_text(child)
91
 
 
92
 
        return dict(body=updates)
93
 
 
94
 
 
95
 
def _list_hosts(req, service=None):
96
 
    """Returns a summary list of hosts, optionally filtering
97
 
    by service type.
98
 
    """
99
 
    context = req.environ['nova.context']
100
 
    services = db.service_get_all(context, False)
101
 
 
102
 
    hosts = []
103
 
    for host in services:
104
 
        hosts.append({"host_name": host['host'], 'service': host['topic']})
105
 
    if service:
106
 
        hosts = [host for host in hosts
107
 
                if host["service"] == service]
108
 
    return hosts
109
 
 
110
 
 
111
 
def check_host(fn):
112
 
    """Makes sure that the host exists."""
113
 
    def wrapped(self, req, id, service=None, *args, **kwargs):
114
 
        listed_hosts = _list_hosts(req, service)
115
 
        hosts = [h["host_name"] for h in listed_hosts]
116
 
        if id in hosts:
117
 
            return fn(self, req, id, *args, **kwargs)
118
 
        else:
119
 
            message = _("Host '%s' could not be found.") % id
120
 
            raise webob.exc.HTTPNotFound(explanation=message)
121
 
    return wrapped
122
 
 
123
 
 
124
 
class HostController(object):
125
 
    """The Hosts API controller for the OpenStack API."""
126
 
    def __init__(self):
127
 
        self.api = compute_api.HostAPI()
128
 
        super(HostController, self).__init__()
129
 
 
130
 
    @wsgi.serializers(xml=HostIndexTemplate)
131
 
    def index(self, req):
132
 
        authorize(req.environ['nova.context'])
133
 
        return {'hosts': _list_hosts(req)}
134
 
 
135
 
    @wsgi.serializers(xml=HostUpdateTemplate)
136
 
    @wsgi.deserializers(xml=HostDeserializer)
137
 
    @check_host
138
 
    def update(self, req, id, body):
139
 
        authorize(req.environ['nova.context'])
140
 
        update_values = {}
141
 
        for raw_key, raw_val in body.iteritems():
142
 
            key = raw_key.lower().strip()
143
 
            val = raw_val.lower().strip()
144
 
            if key == "status":
145
 
                if val in ("enable", "disable"):
146
 
                    update_values['status'] = val.startswith("enable")
147
 
                else:
148
 
                    explanation = _("Invalid status: '%s'") % raw_val
149
 
                    raise webob.exc.HTTPBadRequest(explanation=explanation)
150
 
            elif key == "maintenance_mode":
151
 
                if val not in ['enable', 'disable']:
152
 
                    explanation = _("Invalid mode: '%s'") % raw_val
153
 
                    raise webob.exc.HTTPBadRequest(explanation=explanation)
154
 
                update_values['maintenance_mode'] = val == 'enable'
155
 
            else:
156
 
                explanation = _("Invalid update setting: '%s'") % raw_key
157
 
                raise webob.exc.HTTPBadRequest(explanation=explanation)
158
 
 
159
 
        # this is for handling multiple settings at the same time:
160
 
        # the result dictionaries are merged in the first one.
161
 
        # Note: the 'host' key will always be the same so it's
162
 
        # okay that it gets overwritten.
163
 
        update_setters = {'status': self._set_enabled_status,
164
 
                          'maintenance_mode': self._set_host_maintenance}
165
 
        result = {}
166
 
        for key, value in update_values.iteritems():
167
 
            result.update(update_setters[key](req, id, value))
168
 
        return result
169
 
 
170
 
    def _set_host_maintenance(self, req, host, mode=True):
171
 
        """Start/Stop host maintenance window. On start, it triggers
172
 
        guest VMs evacuation."""
173
 
        context = req.environ['nova.context']
174
 
        LOG.audit(_("Putting host %(host)s in maintenance "
175
 
                    "mode %(mode)s.") % locals())
176
 
        result = self.api.set_host_maintenance(context, host, mode)
177
 
        if result not in ("on_maintenance", "off_maintenance"):
178
 
            raise webob.exc.HTTPBadRequest(explanation=result)
179
 
        return {"host": host, "maintenance_mode": result}
180
 
 
181
 
    def _set_enabled_status(self, req, host, enabled):
182
 
        """Sets the specified host's ability to accept new instances."""
183
 
        context = req.environ['nova.context']
184
 
        state = "enabled" if enabled else "disabled"
185
 
        LOG.audit(_("Setting host %(host)s to %(state)s.") % locals())
186
 
        result = self.api.set_host_enabled(context, host=host,
187
 
                enabled=enabled)
188
 
        if result not in ("enabled", "disabled"):
189
 
            # An error message was returned
190
 
            raise webob.exc.HTTPBadRequest(explanation=result)
191
 
        return {"host": host, "status": result}
192
 
 
193
 
    def _host_power_action(self, req, host, action):
194
 
        """Reboots, shuts down or powers up the host."""
195
 
        context = req.environ['nova.context']
196
 
        authorize(context)
197
 
        try:
198
 
            result = self.api.host_power_action(context, host=host,
199
 
                    action=action)
200
 
        except NotImplementedError as e:
201
 
            raise webob.exc.HTTPBadRequest(explanation=e.msg)
202
 
        return {"host": host, "power_action": result}
203
 
 
204
 
    @wsgi.serializers(xml=HostActionTemplate)
205
 
    def startup(self, req, id):
206
 
        return self._host_power_action(req, host=id, action="startup")
207
 
 
208
 
    @wsgi.serializers(xml=HostActionTemplate)
209
 
    def shutdown(self, req, id):
210
 
        return self._host_power_action(req, host=id, action="shutdown")
211
 
 
212
 
    @wsgi.serializers(xml=HostActionTemplate)
213
 
    def reboot(self, req, id):
214
 
        return self._host_power_action(req, host=id, action="reboot")
215
 
 
216
 
    @wsgi.serializers(xml=HostShowTemplate)
217
 
    def show(self, req, id):
218
 
        """Shows the physical/usage resource given by hosts.
219
 
 
220
 
        :param context: security context
221
 
        :param host: hostname
222
 
        :returns: expected to use HostShowTemplate.
223
 
            ex.::
224
 
 
225
 
                {'host': {'resource':D},..}
226
 
                D: {'host': 'hostname','project': 'admin',
227
 
                    'cpu': 1, 'memory_mb': 2048, 'disk_gb': 30}
228
 
        """
229
 
        host = id
230
 
        context = req.environ['nova.context']
231
 
        if not context.is_admin:
232
 
            msg = _("Describe-resource is admin only functionality")
233
 
            raise webob.exc.HTTPForbidden(explanation=msg)
234
 
 
235
 
        # Getting compute node info and related instances info
236
 
        try:
237
 
            compute_ref = db.service_get_all_compute_by_host(context, host)
238
 
            compute_ref = compute_ref[0]
239
 
        except exception.ComputeHostNotFound:
240
 
            raise webob.exc.HTTPNotFound(explanation=_("Host not found"))
241
 
        instance_refs = db.instance_get_all_by_host(context,
242
 
                                                    compute_ref['host'])
243
 
 
244
 
        # Getting total available/used resource
245
 
        compute_ref = compute_ref['compute_node'][0]
246
 
        resources = [{'resource': {'host': host, 'project': '(total)',
247
 
                      'cpu': compute_ref['vcpus'],
248
 
                      'memory_mb': compute_ref['memory_mb'],
249
 
                      'disk_gb': compute_ref['local_gb']}},
250
 
                     {'resource': {'host': host, 'project': '(used_now)',
251
 
                      'cpu': compute_ref['vcpus_used'],
252
 
                      'memory_mb': compute_ref['memory_mb_used'],
253
 
                      'disk_gb': compute_ref['local_gb_used']}}]
254
 
 
255
 
        cpu_sum = 0
256
 
        mem_sum = 0
257
 
        hdd_sum = 0
258
 
        for i in instance_refs:
259
 
            cpu_sum += i['vcpus']
260
 
            mem_sum += i['memory_mb']
261
 
            hdd_sum += i['root_gb'] + i['ephemeral_gb']
262
 
 
263
 
        resources.append({'resource': {'host': host,
264
 
                          'project': '(used_max)',
265
 
                          'cpu': cpu_sum,
266
 
                          'memory_mb': mem_sum,
267
 
                          'disk_gb': hdd_sum}})
268
 
 
269
 
        # Getting usage resource per project
270
 
        project_ids = [i['project_id'] for i in instance_refs]
271
 
        project_ids = list(set(project_ids))
272
 
        for project_id in project_ids:
273
 
            vcpus = [i['vcpus'] for i in instance_refs
274
 
                     if i['project_id'] == project_id]
275
 
 
276
 
            mem = [i['memory_mb'] for i in instance_refs
277
 
                   if i['project_id'] == project_id]
278
 
 
279
 
            disk = [i['root_gb'] + i['ephemeral_gb'] for i in instance_refs
280
 
                    if i['project_id'] == project_id]
281
 
 
282
 
            resources.append({'resource': {'host': host,
283
 
                              'project': project_id,
284
 
                              'cpu': reduce(lambda x, y: x + y, vcpus),
285
 
                              'memory_mb': reduce(lambda x, y: x + y, mem),
286
 
                              'disk_gb': reduce(lambda x, y: x + y, disk)}})
287
 
 
288
 
        return {'host': resources}
289
 
 
290
 
 
291
 
class Hosts(extensions.ExtensionDescriptor):
292
 
    """Admin-only host administration"""
293
 
 
294
 
    name = "Hosts"
295
 
    alias = "os-hosts"
296
 
    namespace = "http://docs.openstack.org/compute/ext/hosts/api/v1.1"
297
 
    updated = "2011-06-29T00:00:00+00:00"
298
 
 
299
 
    def get_resources(self):
300
 
        resources = [extensions.ResourceExtension('os-hosts',
301
 
                HostController(),
302
 
                collection_actions={'update': 'PUT'},
303
 
                member_actions={"startup": "GET", "shutdown": "GET",
304
 
                        "reboot": "GET"})]
305
 
        return resources