~yolanda.robla/nova/precise-security

« back to all changes in this revision

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

  • Committer: yolanda.robla at canonical
  • Date: 2013-04-24 12:24:03 UTC
  • mfrom: (1.1.58)
  • Revision ID: yolanda.robla@canonical.com-20130424122403-m2v1wv4fz672e480
New upstream release.

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