~ubuntu-branches/ubuntu/saucy/nova/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/CVE-2012-2101.patch/nova/api/openstack/compute/contrib/security_groups.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-05-24 13:12:53 UTC
  • mfrom: (1.1.55)
  • Revision ID: package-import@ubuntu.com-20120524131253-ommql08fg1en06ut
Tags: 2012.2~f1-0ubuntu1
* New upstream release.
* Prepare for quantal:
  - Dropped debian/patches/upstream/0006-Use-project_id-in-ec2.cloud._format_image.patch
  - Dropped debian/patches/upstream/0005-Populate-image-properties-with-project_id-again.patch
  - Dropped debian/patches/upstream/0004-Fixed-bug-962840-added-a-test-case.patch
  - Dropped debian/patches/upstream/0003-Allow-unprivileged-RADOS-users-to-access-rbd-volumes.patch
  - Dropped debian/patches/upstream/0002-Stop-libvirt-test-from-deleting-instances-dir.patch
  - Dropped debian/patches/upstream/0001-fix-bug-where-nova-ignores-glance-host-in-imageref.patch 
  - Dropped debian/patches/0001-fix-useexisting-deprecation-warnings.patch
* debian/control: Add python-keystone as a dependency. (LP: #907197)
* debian/patches/kombu_tests_timeout.patch: Refreshed.
* debian/nova.conf, debian/nova-common.postinst: Convert to new ini
  file configuration
* debian/patches/nova-manage_flagfile_location.patch: Refreshed

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2011 OpenStack LLC.
2
 
# Copyright 2012 Justin Santa Barbara
3
 
# All Rights Reserved.
4
 
#
5
 
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
6
 
#    not use this file except in compliance with the License. You may obtain
7
 
#    a copy of the License at
8
 
#
9
 
#         http://www.apache.org/licenses/LICENSE-2.0
10
 
#
11
 
#    Unless required by applicable law or agreed to in writing, software
12
 
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
 
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
 
#    License for the specific language governing permissions and limitations
15
 
#    under the License.
16
 
 
17
 
"""The security groups extension."""
18
 
 
19
 
import urllib
20
 
from xml.dom import minidom
21
 
 
22
 
from webob import exc
23
 
import webob
24
 
 
25
 
from nova.api.openstack import common
26
 
from nova.api.openstack import extensions
27
 
from nova.api.openstack import wsgi
28
 
from nova.api.openstack import xmlutil
29
 
from nova import compute
30
 
from nova import db
31
 
from nova import exception
32
 
from nova import flags
33
 
from nova import log as logging
34
 
from nova import utils
35
 
 
36
 
 
37
 
LOG = logging.getLogger(__name__)
38
 
FLAGS = flags.FLAGS
39
 
authorize = extensions.extension_authorizer('compute', 'security_groups')
40
 
 
41
 
 
42
 
def make_rule(elem):
43
 
    elem.set('id')
44
 
    elem.set('parent_group_id')
45
 
 
46
 
    proto = xmlutil.SubTemplateElement(elem, 'ip_protocol')
47
 
    proto.text = 'ip_protocol'
48
 
 
49
 
    from_port = xmlutil.SubTemplateElement(elem, 'from_port')
50
 
    from_port.text = 'from_port'
51
 
 
52
 
    to_port = xmlutil.SubTemplateElement(elem, 'to_port')
53
 
    to_port.text = 'to_port'
54
 
 
55
 
    group = xmlutil.SubTemplateElement(elem, 'group', selector='group')
56
 
    name = xmlutil.SubTemplateElement(group, 'name')
57
 
    name.text = 'name'
58
 
    tenant_id = xmlutil.SubTemplateElement(group, 'tenant_id')
59
 
    tenant_id.text = 'tenant_id'
60
 
 
61
 
    ip_range = xmlutil.SubTemplateElement(elem, 'ip_range',
62
 
                                          selector='ip_range')
63
 
    cidr = xmlutil.SubTemplateElement(ip_range, 'cidr')
64
 
    cidr.text = 'cidr'
65
 
 
66
 
 
67
 
def make_sg(elem):
68
 
    elem.set('id')
69
 
    elem.set('tenant_id')
70
 
    elem.set('name')
71
 
 
72
 
    desc = xmlutil.SubTemplateElement(elem, 'description')
73
 
    desc.text = 'description'
74
 
 
75
 
    rules = xmlutil.SubTemplateElement(elem, 'rules')
76
 
    rule = xmlutil.SubTemplateElement(rules, 'rule', selector='rules')
77
 
    make_rule(rule)
78
 
 
79
 
 
80
 
sg_nsmap = {None: wsgi.XMLNS_V11}
81
 
 
82
 
 
83
 
class SecurityGroupRuleTemplate(xmlutil.TemplateBuilder):
84
 
    def construct(self):
85
 
        root = xmlutil.TemplateElement('security_group_rule',
86
 
                                       selector='security_group_rule')
87
 
        make_rule(root)
88
 
        return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
89
 
 
90
 
 
91
 
class SecurityGroupTemplate(xmlutil.TemplateBuilder):
92
 
    def construct(self):
93
 
        root = xmlutil.TemplateElement('security_group',
94
 
                                       selector='security_group')
95
 
        make_sg(root)
96
 
        return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
97
 
 
98
 
 
99
 
class SecurityGroupsTemplate(xmlutil.TemplateBuilder):
100
 
    def construct(self):
101
 
        root = xmlutil.TemplateElement('security_groups')
102
 
        elem = xmlutil.SubTemplateElement(root, 'security_group',
103
 
                                          selector='security_groups')
104
 
        make_sg(elem)
105
 
        return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
106
 
 
107
 
 
108
 
class SecurityGroupXMLDeserializer(wsgi.MetadataXMLDeserializer):
109
 
    """
110
 
    Deserializer to handle xml-formatted security group requests.
111
 
    """
112
 
    def default(self, string):
113
 
        """Deserialize an xml-formatted security group create request"""
114
 
        dom = minidom.parseString(string)
115
 
        security_group = {}
116
 
        sg_node = self.find_first_child_named(dom,
117
 
                                               'security_group')
118
 
        if sg_node is not None:
119
 
            if sg_node.hasAttribute('name'):
120
 
                security_group['name'] = sg_node.getAttribute('name')
121
 
            desc_node = self.find_first_child_named(sg_node,
122
 
                                                     "description")
123
 
            if desc_node:
124
 
                security_group['description'] = self.extract_text(desc_node)
125
 
        return {'body': {'security_group': security_group}}
126
 
 
127
 
 
128
 
class SecurityGroupRulesXMLDeserializer(wsgi.MetadataXMLDeserializer):
129
 
    """
130
 
    Deserializer to handle xml-formatted security group requests.
131
 
    """
132
 
 
133
 
    def default(self, string):
134
 
        """Deserialize an xml-formatted security group create request"""
135
 
        dom = minidom.parseString(string)
136
 
        security_group_rule = self._extract_security_group_rule(dom)
137
 
        return {'body': {'security_group_rule': security_group_rule}}
138
 
 
139
 
    def _extract_security_group_rule(self, node):
140
 
        """Marshal the security group rule attribute of a parsed request"""
141
 
        sg_rule = {}
142
 
        sg_rule_node = self.find_first_child_named(node,
143
 
                                                   'security_group_rule')
144
 
        if sg_rule_node is not None:
145
 
            ip_protocol_node = self.find_first_child_named(sg_rule_node,
146
 
                                                           "ip_protocol")
147
 
            if ip_protocol_node is not None:
148
 
                sg_rule['ip_protocol'] = self.extract_text(ip_protocol_node)
149
 
 
150
 
            from_port_node = self.find_first_child_named(sg_rule_node,
151
 
                                                         "from_port")
152
 
            if from_port_node is not None:
153
 
                sg_rule['from_port'] = self.extract_text(from_port_node)
154
 
 
155
 
            to_port_node = self.find_first_child_named(sg_rule_node, "to_port")
156
 
            if to_port_node is not None:
157
 
                sg_rule['to_port'] = self.extract_text(to_port_node)
158
 
 
159
 
            parent_group_id_node = self.find_first_child_named(sg_rule_node,
160
 
                                                            "parent_group_id")
161
 
            if parent_group_id_node is not None:
162
 
                sg_rule['parent_group_id'] = self.extract_text(
163
 
                                                         parent_group_id_node)
164
 
 
165
 
            group_id_node = self.find_first_child_named(sg_rule_node,
166
 
                                                        "group_id")
167
 
            if group_id_node is not None:
168
 
                sg_rule['group_id'] = self.extract_text(group_id_node)
169
 
 
170
 
            cidr_node = self.find_first_child_named(sg_rule_node, "cidr")
171
 
            if cidr_node is not None:
172
 
                sg_rule['cidr'] = self.extract_text(cidr_node)
173
 
 
174
 
        return sg_rule
175
 
 
176
 
 
177
 
class SecurityGroupControllerBase(object):
178
 
    """Base class for Security Group controllers."""
179
 
 
180
 
    def __init__(self):
181
 
        self.compute_api = compute.API()
182
 
        self.sgh = utils.import_object(FLAGS.security_group_handler)
183
 
 
184
 
    def _format_security_group_rule(self, context, rule):
185
 
        sg_rule = {}
186
 
        sg_rule['id'] = rule.id
187
 
        sg_rule['parent_group_id'] = rule.parent_group_id
188
 
        sg_rule['ip_protocol'] = rule.protocol
189
 
        sg_rule['from_port'] = rule.from_port
190
 
        sg_rule['to_port'] = rule.to_port
191
 
        sg_rule['group'] = {}
192
 
        sg_rule['ip_range'] = {}
193
 
        if rule.group_id:
194
 
            source_group = db.security_group_get(context, rule.group_id)
195
 
            sg_rule['group'] = {'name': source_group.name,
196
 
                             'tenant_id': source_group.project_id}
197
 
        else:
198
 
            sg_rule['ip_range'] = {'cidr': rule.cidr}
199
 
        return sg_rule
200
 
 
201
 
    def _format_security_group(self, context, group):
202
 
        security_group = {}
203
 
        security_group['id'] = group.id
204
 
        security_group['description'] = group.description
205
 
        security_group['name'] = group.name
206
 
        security_group['tenant_id'] = group.project_id
207
 
        security_group['rules'] = []
208
 
        for rule in group.rules:
209
 
            security_group['rules'] += [self._format_security_group_rule(
210
 
                    context, rule)]
211
 
        return security_group
212
 
 
213
 
 
214
 
class SecurityGroupController(SecurityGroupControllerBase):
215
 
    """The Security group API controller for the OpenStack API."""
216
 
 
217
 
    def _get_security_group(self, context, id):
218
 
        try:
219
 
            id = int(id)
220
 
            security_group = db.security_group_get(context, id)
221
 
        except ValueError:
222
 
            msg = _("Security group id should be integer")
223
 
            raise exc.HTTPBadRequest(explanation=msg)
224
 
        except exception.NotFound as exp:
225
 
            raise exc.HTTPNotFound(explanation=unicode(exp))
226
 
        return security_group
227
 
 
228
 
    @wsgi.serializers(xml=SecurityGroupTemplate)
229
 
    def show(self, req, id):
230
 
        """Return data about the given security group."""
231
 
        context = req.environ['nova.context']
232
 
        authorize(context)
233
 
        security_group = self._get_security_group(context, id)
234
 
        return {'security_group': self._format_security_group(context,
235
 
                                                              security_group)}
236
 
 
237
 
    def delete(self, req, id):
238
 
        """Delete a security group."""
239
 
        context = req.environ['nova.context']
240
 
        authorize(context)
241
 
        security_group = self._get_security_group(context, id)
242
 
        if db.security_group_in_use(context, security_group.id):
243
 
            msg = _("Security group is still in use")
244
 
            raise exc.HTTPBadRequest(explanation=msg)
245
 
        LOG.audit(_("Delete security group %s"), id, context=context)
246
 
        db.security_group_destroy(context, security_group.id)
247
 
        self.sgh.trigger_security_group_destroy_refresh(
248
 
            context, security_group.id)
249
 
 
250
 
        return webob.Response(status_int=202)
251
 
 
252
 
    @wsgi.serializers(xml=SecurityGroupsTemplate)
253
 
    def index(self, req):
254
 
        """Returns a list of security groups"""
255
 
        context = req.environ['nova.context']
256
 
        authorize(context)
257
 
 
258
 
        self.compute_api.ensure_default_security_group(context)
259
 
        groups = db.security_group_get_by_project(context,
260
 
                                                  context.project_id)
261
 
        limited_list = common.limited(groups, req)
262
 
        result = [self._format_security_group(context, group)
263
 
                     for group in limited_list]
264
 
 
265
 
        return {'security_groups':
266
 
                list(sorted(result,
267
 
                            key=lambda k: (k['tenant_id'], k['name'])))}
268
 
 
269
 
    @wsgi.serializers(xml=SecurityGroupTemplate)
270
 
    @wsgi.deserializers(xml=SecurityGroupXMLDeserializer)
271
 
    def create(self, req, body):
272
 
        """Creates a new security group."""
273
 
        context = req.environ['nova.context']
274
 
        authorize(context)
275
 
        if not body:
276
 
            raise exc.HTTPUnprocessableEntity()
277
 
 
278
 
        security_group = body.get('security_group', None)
279
 
 
280
 
        if security_group is None:
281
 
            raise exc.HTTPUnprocessableEntity()
282
 
 
283
 
        group_name = security_group.get('name', None)
284
 
        group_description = security_group.get('description', None)
285
 
 
286
 
        self._validate_security_group_property(group_name, "name")
287
 
        self._validate_security_group_property(group_description,
288
 
                                               "description")
289
 
        group_name = group_name.strip()
290
 
        group_description = group_description.strip()
291
 
 
292
 
        LOG.audit(_("Create Security Group %s"), group_name, context=context)
293
 
        self.compute_api.ensure_default_security_group(context)
294
 
        if db.security_group_exists(context, context.project_id, group_name):
295
 
            msg = _('Security group %s already exists') % group_name
296
 
            raise exc.HTTPBadRequest(explanation=msg)
297
 
 
298
 
        group = {'user_id': context.user_id,
299
 
                 'project_id': context.project_id,
300
 
                 'name': group_name,
301
 
                 'description': group_description}
302
 
        group_ref = db.security_group_create(context, group)
303
 
        self.sgh.trigger_security_group_create_refresh(context, group)
304
 
 
305
 
        return {'security_group': self._format_security_group(context,
306
 
                                                                 group_ref)}
307
 
 
308
 
    def _validate_security_group_property(self, value, typ):
309
 
        """ typ will be either 'name' or 'description',
310
 
            depending on the caller
311
 
        """
312
 
        try:
313
 
            val = value.strip()
314
 
        except AttributeError:
315
 
            msg = _("Security group %s is not a string or unicode") % typ
316
 
            raise exc.HTTPBadRequest(explanation=msg)
317
 
        if not val:
318
 
            msg = _("Security group %s cannot be empty.") % typ
319
 
            raise exc.HTTPBadRequest(explanation=msg)
320
 
        if len(val) > 255:
321
 
            msg = _("Security group %s should not be greater "
322
 
                            "than 255 characters.") % typ
323
 
            raise exc.HTTPBadRequest(explanation=msg)
324
 
 
325
 
 
326
 
class SecurityGroupRulesController(SecurityGroupControllerBase):
327
 
 
328
 
    @wsgi.serializers(xml=SecurityGroupRuleTemplate)
329
 
    @wsgi.deserializers(xml=SecurityGroupRulesXMLDeserializer)
330
 
    def create(self, req, body):
331
 
        context = req.environ['nova.context']
332
 
        authorize(context)
333
 
 
334
 
        if not body:
335
 
            raise exc.HTTPUnprocessableEntity()
336
 
 
337
 
        if not 'security_group_rule' in body:
338
 
            raise exc.HTTPUnprocessableEntity()
339
 
 
340
 
        self.compute_api.ensure_default_security_group(context)
341
 
 
342
 
        sg_rule = body['security_group_rule']
343
 
        parent_group_id = sg_rule.get('parent_group_id', None)
344
 
        try:
345
 
            parent_group_id = int(parent_group_id)
346
 
            security_group = db.security_group_get(context, parent_group_id)
347
 
        except ValueError:
348
 
            msg = _("Parent group id is not integer")
349
 
            raise exc.HTTPBadRequest(explanation=msg)
350
 
        except exception.NotFound as exp:
351
 
            msg = _("Security group (%s) not found") % parent_group_id
352
 
            raise exc.HTTPNotFound(explanation=msg)
353
 
 
354
 
        msg = _("Authorize security group ingress %s")
355
 
        LOG.audit(msg, security_group['name'], context=context)
356
 
 
357
 
        try:
358
 
            values = self._rule_args_to_dict(context,
359
 
                              to_port=sg_rule.get('to_port'),
360
 
                              from_port=sg_rule.get('from_port'),
361
 
                              parent_group_id=sg_rule.get('parent_group_id'),
362
 
                              ip_protocol=sg_rule.get('ip_protocol'),
363
 
                              cidr=sg_rule.get('cidr'),
364
 
                              group_id=sg_rule.get('group_id'))
365
 
        except Exception as exp:
366
 
            raise exc.HTTPBadRequest(explanation=unicode(exp))
367
 
 
368
 
        if values is None:
369
 
            msg = _("Not enough parameters to build a "
370
 
                                       "valid rule.")
371
 
            raise exc.HTTPBadRequest(explanation=msg)
372
 
 
373
 
        values['parent_group_id'] = security_group.id
374
 
 
375
 
        if self._security_group_rule_exists(security_group, values):
376
 
            msg = _('This rule already exists in group %s') % parent_group_id
377
 
            raise exc.HTTPBadRequest(explanation=msg)
378
 
 
379
 
        security_group_rule = db.security_group_rule_create(context, values)
380
 
        self.sgh.trigger_security_group_rule_create_refresh(
381
 
            context, [security_group_rule['id']])
382
 
        self.compute_api.trigger_security_group_rules_refresh(context,
383
 
                                    security_group_id=security_group['id'])
384
 
 
385
 
        return {"security_group_rule": self._format_security_group_rule(
386
 
                                                        context,
387
 
                                                        security_group_rule)}
388
 
 
389
 
    def _security_group_rule_exists(self, security_group, values):
390
 
        """Indicates whether the specified rule values are already
391
 
           defined in the given security group.
392
 
        """
393
 
        for rule in security_group.rules:
394
 
            is_duplicate = True
395
 
            keys = ('group_id', 'cidr', 'from_port', 'to_port', 'protocol')
396
 
            for key in keys:
397
 
                if rule.get(key) != values.get(key):
398
 
                    is_duplicate = False
399
 
                    break
400
 
            if is_duplicate:
401
 
                return True
402
 
        return False
403
 
 
404
 
    def _rule_args_to_dict(self, context, to_port=None, from_port=None,
405
 
                                  parent_group_id=None, ip_protocol=None,
406
 
                                  cidr=None, group_id=None):
407
 
        values = {}
408
 
 
409
 
        if group_id is not None:
410
 
            try:
411
 
                parent_group_id = int(parent_group_id)
412
 
                group_id = int(group_id)
413
 
            except ValueError:
414
 
                msg = _("Parent or group id is not integer")
415
 
                raise exception.InvalidInput(reason=msg)
416
 
 
417
 
            values['group_id'] = group_id
418
 
            #check if groupId exists
419
 
            db.security_group_get(context, group_id)
420
 
        elif cidr:
421
 
            # If this fails, it throws an exception. This is what we want.
422
 
            try:
423
 
                cidr = urllib.unquote(cidr).decode()
424
 
            except Exception:
425
 
                raise exception.InvalidCidr(cidr=cidr)
426
 
 
427
 
            if not utils.is_valid_cidr(cidr):
428
 
                # Raise exception for non-valid address
429
 
                raise exception.InvalidCidr(cidr=cidr)
430
 
 
431
 
            values['cidr'] = cidr
432
 
        else:
433
 
            values['cidr'] = '0.0.0.0/0'
434
 
 
435
 
        if group_id:
436
 
            # Open everything if an explicit port range or type/code are not
437
 
            # specified, but only if a source group was specified.
438
 
            ip_proto_upper = ip_protocol.upper() if ip_protocol else ''
439
 
            if (ip_proto_upper == 'ICMP' and
440
 
                from_port is None and to_port is None):
441
 
                from_port = -1
442
 
                to_port = -1
443
 
            elif (ip_proto_upper in ['TCP', 'UDP'] and from_port is None
444
 
                  and to_port is None):
445
 
                from_port = 1
446
 
                to_port = 65535
447
 
 
448
 
        if ip_protocol and from_port is not None and to_port is not None:
449
 
 
450
 
            ip_protocol = str(ip_protocol)
451
 
            try:
452
 
                from_port = int(from_port)
453
 
                to_port = int(to_port)
454
 
            except ValueError:
455
 
                if ip_protocol.upper() == 'ICMP':
456
 
                    raise exception.InvalidInput(reason="Type and"
457
 
                         " Code must be integers for ICMP protocol type")
458
 
                else:
459
 
                    raise exception.InvalidInput(reason="To and From ports "
460
 
                          "must be integers")
461
 
 
462
 
            if ip_protocol.upper() not in ['TCP', 'UDP', 'ICMP']:
463
 
                raise exception.InvalidIpProtocol(protocol=ip_protocol)
464
 
 
465
 
            # Verify that from_port must always be less than
466
 
            # or equal to to_port
467
 
            if (ip_protocol.upper() in ['TCP', 'UDP'] and
468
 
                from_port > to_port):
469
 
                raise exception.InvalidPortRange(from_port=from_port,
470
 
                      to_port=to_port, msg="Former value cannot"
471
 
                                            " be greater than the later")
472
 
 
473
 
            # Verify valid TCP, UDP port ranges
474
 
            if (ip_protocol.upper() in ['TCP', 'UDP'] and
475
 
                (from_port < 1 or to_port > 65535)):
476
 
                raise exception.InvalidPortRange(from_port=from_port,
477
 
                      to_port=to_port, msg="Valid TCP ports should"
478
 
                                           " be between 1-65535")
479
 
 
480
 
            # Verify ICMP type and code
481
 
            if (ip_protocol.upper() == "ICMP" and
482
 
                (from_port < -1 or from_port > 255 or
483
 
                to_port < -1 or to_port > 255)):
484
 
                raise exception.InvalidPortRange(from_port=from_port,
485
 
                      to_port=to_port, msg="For ICMP, the"
486
 
                                           " type:code must be valid")
487
 
 
488
 
            values['protocol'] = ip_protocol
489
 
            values['from_port'] = from_port
490
 
            values['to_port'] = to_port
491
 
        else:
492
 
            # If cidr based filtering, protocol and ports are mandatory
493
 
            if 'cidr' in values:
494
 
                return None
495
 
 
496
 
        return values
497
 
 
498
 
    def delete(self, req, id):
499
 
        context = req.environ['nova.context']
500
 
        authorize(context)
501
 
 
502
 
        self.compute_api.ensure_default_security_group(context)
503
 
        try:
504
 
            id = int(id)
505
 
            rule = db.security_group_rule_get(context, id)
506
 
        except ValueError:
507
 
            msg = _("Rule id is not integer")
508
 
            raise exc.HTTPBadRequest(explanation=msg)
509
 
        except exception.NotFound:
510
 
            msg = _("Rule (%s) not found") % id
511
 
            raise exc.HTTPNotFound(explanation=msg)
512
 
 
513
 
        group_id = rule.parent_group_id
514
 
        self.compute_api.ensure_default_security_group(context)
515
 
        security_group = db.security_group_get(context, group_id)
516
 
 
517
 
        msg = _("Revoke security group ingress %s")
518
 
        LOG.audit(msg, security_group['name'], context=context)
519
 
 
520
 
        db.security_group_rule_destroy(context, rule['id'])
521
 
        self.sgh.trigger_security_group_rule_destroy_refresh(
522
 
            context, [rule['id']])
523
 
        self.compute_api.trigger_security_group_rules_refresh(context,
524
 
                                    security_group_id=security_group['id'])
525
 
 
526
 
        return webob.Response(status_int=202)
527
 
 
528
 
 
529
 
class ServerSecurityGroupController(SecurityGroupControllerBase):
530
 
 
531
 
    @wsgi.serializers(xml=SecurityGroupsTemplate)
532
 
    def index(self, req, server_id):
533
 
        """Returns a list of security groups for the given instance."""
534
 
        context = req.environ['nova.context']
535
 
        authorize(context)
536
 
 
537
 
        self.compute_api.ensure_default_security_group(context)
538
 
 
539
 
        try:
540
 
            instance = self.compute_api.get(context, server_id)
541
 
            groups = db.security_group_get_by_instance(context,
542
 
                                                       instance['id'])
543
 
        except exception.ApiError, e:
544
 
            raise webob.exc.HTTPBadRequest(explanation=e.message)
545
 
        except exception.NotAuthorized, e:
546
 
            raise webob.exc.HTTPUnauthorized()
547
 
 
548
 
        result = [self._format_security_group(context, group)
549
 
                    for group in groups]
550
 
 
551
 
        return {'security_groups':
552
 
                list(sorted(result,
553
 
                            key=lambda k: (k['tenant_id'], k['name'])))}
554
 
 
555
 
 
556
 
class SecurityGroupActionController(wsgi.Controller):
557
 
    def __init__(self, *args, **kwargs):
558
 
        super(SecurityGroupActionController, self).__init__(*args, **kwargs)
559
 
        self.compute_api = compute.API()
560
 
        self.sgh = utils.import_object(FLAGS.security_group_handler)
561
 
 
562
 
    @wsgi.action('addSecurityGroup')
563
 
    def _addSecurityGroup(self, req, id, body):
564
 
        context = req.environ['nova.context']
565
 
        authorize(context)
566
 
 
567
 
        try:
568
 
            body = body['addSecurityGroup']
569
 
            group_name = body['name']
570
 
        except TypeError:
571
 
            msg = _("Missing parameter dict")
572
 
            raise webob.exc.HTTPBadRequest(explanation=msg)
573
 
        except KeyError:
574
 
            msg = _("Security group not specified")
575
 
            raise webob.exc.HTTPBadRequest(explanation=msg)
576
 
 
577
 
        if not group_name or group_name.strip() == '':
578
 
            msg = _("Security group name cannot be empty")
579
 
            raise webob.exc.HTTPBadRequest(explanation=msg)
580
 
 
581
 
        try:
582
 
            instance = self.compute_api.get(context, id)
583
 
            self.compute_api.add_security_group(context, instance, group_name)
584
 
            self.sgh.trigger_instance_add_security_group_refresh(
585
 
                context, instance, group_name)
586
 
        except exception.SecurityGroupNotFound as exp:
587
 
            raise exc.HTTPNotFound(explanation=unicode(exp))
588
 
        except exception.InstanceNotFound as exp:
589
 
            raise exc.HTTPNotFound(explanation=unicode(exp))
590
 
        except exception.Invalid as exp:
591
 
            raise exc.HTTPBadRequest(explanation=unicode(exp))
592
 
 
593
 
        return webob.Response(status_int=202)
594
 
 
595
 
    @wsgi.action('removeSecurityGroup')
596
 
    def _removeSecurityGroup(self, req, id, body):
597
 
        context = req.environ['nova.context']
598
 
        authorize(context)
599
 
 
600
 
        try:
601
 
            body = body['removeSecurityGroup']
602
 
            group_name = body['name']
603
 
        except TypeError:
604
 
            msg = _("Missing parameter dict")
605
 
            raise webob.exc.HTTPBadRequest(explanation=msg)
606
 
        except KeyError:
607
 
            msg = _("Security group not specified")
608
 
            raise webob.exc.HTTPBadRequest(explanation=msg)
609
 
 
610
 
        if not group_name or group_name.strip() == '':
611
 
            msg = _("Security group name cannot be empty")
612
 
            raise webob.exc.HTTPBadRequest(explanation=msg)
613
 
 
614
 
        try:
615
 
            instance = self.compute_api.get(context, id)
616
 
            self.compute_api.remove_security_group(context, instance,
617
 
                                                   group_name)
618
 
            self.sgh.trigger_instance_remove_security_group_refresh(
619
 
                context, instance, group_name)
620
 
        except exception.SecurityGroupNotFound as exp:
621
 
            raise exc.HTTPNotFound(explanation=unicode(exp))
622
 
        except exception.InstanceNotFound as exp:
623
 
            raise exc.HTTPNotFound(explanation=unicode(exp))
624
 
        except exception.Invalid as exp:
625
 
            raise exc.HTTPBadRequest(explanation=unicode(exp))
626
 
 
627
 
        return webob.Response(status_int=202)
628
 
 
629
 
 
630
 
class Security_groups(extensions.ExtensionDescriptor):
631
 
    """Security group support"""
632
 
 
633
 
    name = "SecurityGroups"
634
 
    alias = "security_groups"
635
 
    namespace = "http://docs.openstack.org/compute/ext/securitygroups/api/v1.1"
636
 
    updated = "2011-07-21T00:00:00+00:00"
637
 
 
638
 
    def get_controller_extensions(self):
639
 
        controller = SecurityGroupActionController()
640
 
        extension = extensions.ControllerExtension(self, 'servers', controller)
641
 
        return [extension]
642
 
 
643
 
    def get_resources(self):
644
 
        resources = []
645
 
 
646
 
        res = extensions.ResourceExtension('os-security-groups',
647
 
                                controller=SecurityGroupController())
648
 
 
649
 
        resources.append(res)
650
 
 
651
 
        res = extensions.ResourceExtension('os-security-group-rules',
652
 
                                controller=SecurityGroupRulesController())
653
 
        resources.append(res)
654
 
 
655
 
        res = extensions.ResourceExtension(
656
 
            'os-security-groups',
657
 
            controller=ServerSecurityGroupController(),
658
 
            parent=dict(member_name='server', collection_name='servers'))
659
 
        resources.append(res)
660
 
 
661
 
        return resources