Default SG rules for the Security Group "Default"
Added in the API os-security-group-default-rules This allows create, delete, list, and get (of individual rules) for rules that will be pre-populated into the Security Group "default" that is populated in all projects on creation. These rules will not be applied retroactively, as it is designed to allow the creation of a "reasonable" base-line set of sg rules. The new rules live in a separate table that mirrors the relevant structures of the security_group_rules table. Added unit tests/API samples for the new API calls Related to bp default-rules-for-default-security-group DocImpact Change-Id: I7ab51e68aff562bb869538197a0eca158fc3220c
This commit is contained in:
parent
30c2a8f66e
commit
59aaf1dff9
@ -384,6 +384,14 @@
|
|||||||
"namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1",
|
"namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1",
|
||||||
"updated": "2011-08-18T00:00:00+00:00"
|
"updated": "2011-08-18T00:00:00+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"alias": "os-security-group-default-rules",
|
||||||
|
"description": "Default rules for security group support.",
|
||||||
|
"links": [],
|
||||||
|
"name": "SecurityGroupDefaultRules",
|
||||||
|
"namespace": "http://docs.openstack.org/compute/ext/securitygroupdefaultrules/api/v1.1",
|
||||||
|
"updated": "2013-02-05T00:00:00+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"alias": "os-security-groups",
|
"alias": "os-security-groups",
|
||||||
"description": "Security group support.",
|
"description": "Security group support.",
|
||||||
|
@ -162,6 +162,9 @@
|
|||||||
<extension alias="os-rescue" updated="2011-08-18T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue">
|
<extension alias="os-rescue" updated="2011-08-18T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue">
|
||||||
<description>Instance rescue mode.</description>
|
<description>Instance rescue mode.</description>
|
||||||
</extension>
|
</extension>
|
||||||
|
<extension alias="os-security-group-default-rules" updated="2013-02-05T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/securitygroupdefaultrules/api/v1.1" name="SecurityGroupDefaultRules">
|
||||||
|
<description>Default rules for security group support.</description>
|
||||||
|
</extension>
|
||||||
<extension alias="os-security-groups" updated="2011-07-21T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/securitygroups/api/v1.1" name="SecurityGroups">
|
<extension alias="os-security-groups" updated="2011-07-21T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/securitygroups/api/v1.1" name="SecurityGroups">
|
||||||
<description>Security group support.</description>
|
<description>Security group support.</description>
|
||||||
</extension>
|
</extension>
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"from_port": "80",
|
||||||
|
"to_port": "80",
|
||||||
|
"cidr": "10.10.12.0/24"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<security_group_default_rule>
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<from_port>80</from_port>
|
||||||
|
<to_port>80</to_port>
|
||||||
|
<cidr>10.10.12.0/24</cidr>
|
||||||
|
</security_group_default_rule>
|
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"from_port": 80,
|
||||||
|
"id": 1,
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"ip_range":{
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
},
|
||||||
|
"to_port": 80
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<security_group_default_rule xmlns="http://docs.openstack.org/compute/api/v1.1" id="1">
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<from_port>80</from_port>
|
||||||
|
<to_port>80</to_port>
|
||||||
|
<ip_range>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</ip_range>
|
||||||
|
</security_group_default_rule>
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"security_group_default_rules": [
|
||||||
|
{
|
||||||
|
"from_port": 80,
|
||||||
|
"id": 1,
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"ip_range": {
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
},
|
||||||
|
"to_port": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<security_group_default_rules xmlns="http://docs.openstack.org/compute/api/v1.1">
|
||||||
|
<security_group_default_rule id="1">
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<from_port>80</from_port>
|
||||||
|
<to_port>80</to_port>
|
||||||
|
<ip_range>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</ip_range>
|
||||||
|
</security_group_default_rule>
|
||||||
|
</security_group_default_rules>
|
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"id": 1,
|
||||||
|
"from_port": 80,
|
||||||
|
"to_port": 80,
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"ip_range": {
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<security_group_default_rule xmlns="http://docs.openstack.org/compute/api/v1.1" id="1">
|
||||||
|
<from_port>80</from_port>
|
||||||
|
<to_port>80</to_port>
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<ip_range>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</ip_range>
|
||||||
|
</security_group_default_rule>
|
@ -78,6 +78,7 @@
|
|||||||
"compute_extension:quotas:update": "rule:admin_api",
|
"compute_extension:quotas:update": "rule:admin_api",
|
||||||
"compute_extension:quota_classes": "",
|
"compute_extension:quota_classes": "",
|
||||||
"compute_extension:rescue": "",
|
"compute_extension:rescue": "",
|
||||||
|
"compute_extension:security_group_default_rules": "rule:admin_api",
|
||||||
"compute_extension:security_groups": "",
|
"compute_extension:security_groups": "",
|
||||||
"compute_extension:server_diagnostics": "rule:admin_api",
|
"compute_extension:server_diagnostics": "rule:admin_api",
|
||||||
"compute_extension:server_password": "",
|
"compute_extension:server_password": "",
|
||||||
|
@ -0,0 +1,210 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2013 Metacloud Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from xml.dom import minidom
|
||||||
|
|
||||||
|
import webob
|
||||||
|
from webob import exc
|
||||||
|
|
||||||
|
from nova.api.openstack.compute.contrib import security_groups as sg
|
||||||
|
from nova.api.openstack import extensions
|
||||||
|
from nova.api.openstack import wsgi
|
||||||
|
from nova.api.openstack import xmlutil
|
||||||
|
from nova import exception
|
||||||
|
from nova.openstack.common import log as logging
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
authorize = extensions.extension_authorizer('compute',
|
||||||
|
'security_group_default_rules')
|
||||||
|
|
||||||
|
sg_nsmap = {None: wsgi.XMLNS_V11}
|
||||||
|
|
||||||
|
|
||||||
|
def make_default_rule(elem):
|
||||||
|
elem.set('id')
|
||||||
|
|
||||||
|
proto = xmlutil.SubTemplateElement(elem, 'ip_protocol')
|
||||||
|
proto.text = 'ip_protocol'
|
||||||
|
|
||||||
|
from_port = xmlutil.SubTemplateElement(elem, 'from_port')
|
||||||
|
from_port.text = 'from_port'
|
||||||
|
|
||||||
|
to_port = xmlutil.SubTemplateElement(elem, 'to_port')
|
||||||
|
to_port.text = 'to_port'
|
||||||
|
|
||||||
|
ip_range = xmlutil.SubTemplateElement(elem, 'ip_range',
|
||||||
|
selector='ip_range')
|
||||||
|
cidr = xmlutil.SubTemplateElement(ip_range, 'cidr')
|
||||||
|
cidr.text = 'cidr'
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityGroupDefaultRulesTemplate(xmlutil.TemplateBuilder):
|
||||||
|
def construct(self):
|
||||||
|
root = xmlutil.TemplateElement('security_group_default_rules')
|
||||||
|
elem = xmlutil.SubTemplateElement(root, 'security_group_default_rule',
|
||||||
|
selector='security_group_default_rules')
|
||||||
|
|
||||||
|
make_default_rule(elem)
|
||||||
|
return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityGroupDefaultRuleTemplate(xmlutil.TemplateBuilder):
|
||||||
|
def construct(self):
|
||||||
|
root = xmlutil.TemplateElement('security_group_default_rule',
|
||||||
|
selector='security_group_default_rule')
|
||||||
|
make_default_rule(root)
|
||||||
|
return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityGroupDefaultRulesXMLDeserializer(wsgi.MetadataXMLDeserializer):
|
||||||
|
def default(self, string):
|
||||||
|
dom = minidom.parseString(string)
|
||||||
|
security_group_rule = self._extract_security_group_default_rule(dom)
|
||||||
|
return {'body': {'security_group_default_rule': security_group_rule}}
|
||||||
|
|
||||||
|
def _extract_security_group_default_rule(self, node):
|
||||||
|
sg_rule = {}
|
||||||
|
sg_rule_node = self.find_first_child_named(node,
|
||||||
|
'security_group_default_rule')
|
||||||
|
if sg_rule_node is not None:
|
||||||
|
ip_protocol_node = self.find_first_child_named(sg_rule_node,
|
||||||
|
"ip_protocol")
|
||||||
|
if ip_protocol_node is not None:
|
||||||
|
sg_rule['ip_protocol'] = self.extract_text(ip_protocol_node)
|
||||||
|
|
||||||
|
from_port_node = self.find_first_child_named(sg_rule_node,
|
||||||
|
"from_port")
|
||||||
|
if from_port_node is not None:
|
||||||
|
sg_rule['from_port'] = self.extract_text(from_port_node)
|
||||||
|
|
||||||
|
to_port_node = self.find_first_child_named(sg_rule_node, "to_port")
|
||||||
|
if to_port_node is not None:
|
||||||
|
sg_rule['to_port'] = self.extract_text(to_port_node)
|
||||||
|
|
||||||
|
cidr_node = self.find_first_child_named(sg_rule_node, "cidr")
|
||||||
|
if cidr_node is not None:
|
||||||
|
sg_rule['cidr'] = self.extract_text(cidr_node)
|
||||||
|
|
||||||
|
return sg_rule
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityGroupDefaultRulesController(sg.SecurityGroupControllerBase):
|
||||||
|
|
||||||
|
@wsgi.serializers(xml=SecurityGroupDefaultRuleTemplate)
|
||||||
|
@wsgi.deserializers(xml=SecurityGroupDefaultRulesXMLDeserializer)
|
||||||
|
def create(self, req, body):
|
||||||
|
context = self._authorize_context(req)
|
||||||
|
authorize(context)
|
||||||
|
|
||||||
|
sg_rule = self._from_body(body, 'security_group_default_rule')
|
||||||
|
|
||||||
|
try:
|
||||||
|
values = self._rule_args_to_dict(to_port=sg_rule.get('to_port'),
|
||||||
|
from_port=sg_rule.get('from_port'),
|
||||||
|
ip_protocol=sg_rule.get('ip_protocol'),
|
||||||
|
cidr=sg_rule.get('cidr'))
|
||||||
|
except Exception as exp:
|
||||||
|
raise exc.HTTPBadRequest(explanation=unicode(exp))
|
||||||
|
|
||||||
|
if values is None:
|
||||||
|
msg = _('Not enough parameters to build a valid rule.')
|
||||||
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
if self.security_group_api.default_rule_exists(context, values):
|
||||||
|
msg = _('This default rule already exists.')
|
||||||
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
security_group_rule = self.security_group_api.add_default_rules(
|
||||||
|
context, [values])[0]
|
||||||
|
fmt_rule = self._format_security_group_default_rule(
|
||||||
|
security_group_rule)
|
||||||
|
return {'security_group_default_rule': fmt_rule}
|
||||||
|
|
||||||
|
def _rule_args_to_dict(self, to_port=None, from_port=None,
|
||||||
|
ip_protocol=None, cidr=None):
|
||||||
|
cidr = self.security_group_api.parse_cidr(cidr)
|
||||||
|
return self.security_group_api.new_cidr_ingress_rule(
|
||||||
|
cidr, ip_protocol, from_port, to_port)
|
||||||
|
|
||||||
|
@wsgi.serializers(xml=SecurityGroupDefaultRuleTemplate)
|
||||||
|
def show(self, req, id):
|
||||||
|
context = self._authorize_context(req)
|
||||||
|
authorize(context)
|
||||||
|
|
||||||
|
id = self._validate_id(id)
|
||||||
|
LOG.debug(_("Showing security_group_default_rule with id %s") % id)
|
||||||
|
try:
|
||||||
|
rule = self.security_group_api.get_default_rule(context, id)
|
||||||
|
except exception.SecurityGroupDefaultRuleNotFound:
|
||||||
|
raise exc.HTTPNotFound(_("security group default rule not found"))
|
||||||
|
|
||||||
|
fmt_rule = self._format_security_group_default_rule(rule)
|
||||||
|
return {"security_group_default_rule": fmt_rule}
|
||||||
|
|
||||||
|
def delete(self, req, id):
|
||||||
|
context = self._authorize_context(req)
|
||||||
|
authorize(context)
|
||||||
|
|
||||||
|
id = self._validate_id(id)
|
||||||
|
|
||||||
|
rule = self.security_group_api.get_default_rule(context, id)
|
||||||
|
|
||||||
|
self.security_group_api.remove_default_rules(context, [rule['id']])
|
||||||
|
|
||||||
|
return webob.Response(status_int=204)
|
||||||
|
|
||||||
|
@wsgi.serializers(xml=SecurityGroupDefaultRulesTemplate)
|
||||||
|
def index(self, req):
|
||||||
|
|
||||||
|
context = self._authorize_context(req)
|
||||||
|
authorize(context)
|
||||||
|
|
||||||
|
ret = {'security_group_default_rules': []}
|
||||||
|
for rule in self.security_group_api.get_all_default_rules(context):
|
||||||
|
rule_fmt = self._format_security_group_default_rule(rule)
|
||||||
|
ret['security_group_default_rules'].append(rule_fmt)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def _format_security_group_default_rule(self, rule):
|
||||||
|
sg_rule = {}
|
||||||
|
sg_rule['id'] = rule['id']
|
||||||
|
sg_rule['ip_protocol'] = rule['protocol']
|
||||||
|
sg_rule['from_port'] = rule['from_port']
|
||||||
|
sg_rule['to_port'] = rule['to_port']
|
||||||
|
sg_rule['ip_range'] = {}
|
||||||
|
sg_rule['ip_range'] = {'cidr': rule['cidr']}
|
||||||
|
return sg_rule
|
||||||
|
|
||||||
|
|
||||||
|
class Security_group_default_rules(extensions.ExtensionDescriptor):
|
||||||
|
"""Default rules for security group support."""
|
||||||
|
name = "SecurityGroupDefaultRules"
|
||||||
|
alias = "os-security-group-default-rules"
|
||||||
|
namespace = ("http://docs.openstack.org/compute/ext/"
|
||||||
|
"securitygroupdefaultrules/api/v1.1")
|
||||||
|
updated = "2013-02-05T00:00:00+00:00"
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
resources = [
|
||||||
|
extensions.ResourceExtension('os-security-group-default-rules',
|
||||||
|
SecurityGroupDefaultRulesController(),
|
||||||
|
collection_actions={'create': 'POST',
|
||||||
|
'delete': 'DELETE',
|
||||||
|
'index': 'GET'},
|
||||||
|
member_actions={'show': 'GET'})]
|
||||||
|
|
||||||
|
return resources
|
@ -3128,6 +3128,46 @@ class SecurityGroupAPI(base.Base):
|
|||||||
self.trigger_rules_refresh(context, id=security_group['id'])
|
self.trigger_rules_refresh(context, id=security_group['id'])
|
||||||
self.trigger_handler('security_group_rule_destroy', context, rule_ids)
|
self.trigger_handler('security_group_rule_destroy', context, rule_ids)
|
||||||
|
|
||||||
|
def remove_default_rules(self, context, rule_ids):
|
||||||
|
for rule_id in rule_ids:
|
||||||
|
self.db.security_group_default_rule_destroy(context, rule_id)
|
||||||
|
|
||||||
|
def add_default_rules(self, context, vals):
|
||||||
|
rules = [self.db.security_group_default_rule_create(context, v)
|
||||||
|
for v in vals]
|
||||||
|
return rules
|
||||||
|
|
||||||
|
def default_rule_exists(self, context, values):
|
||||||
|
"""Indicates whether the specified rule values are already
|
||||||
|
defined in the default security group rules.
|
||||||
|
"""
|
||||||
|
for rule in self.db.security_group_default_rule_list(context):
|
||||||
|
is_duplicate = True
|
||||||
|
keys = ('cidr', 'from_port', 'to_port', 'protocol')
|
||||||
|
for key in keys:
|
||||||
|
if rule.get(key) != values.get(key):
|
||||||
|
is_duplicate = False
|
||||||
|
break
|
||||||
|
if is_duplicate:
|
||||||
|
return rule.get('id') or True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_all_default_rules(self, context):
|
||||||
|
try:
|
||||||
|
rules = self.db.security_group_default_rule_list(context)
|
||||||
|
except Exception:
|
||||||
|
msg = 'cannot get default security group rules'
|
||||||
|
raise exception.SecurityGroupDefaultRuleNotFound(msg)
|
||||||
|
|
||||||
|
return rules
|
||||||
|
|
||||||
|
def get_default_rule(self, context, id):
|
||||||
|
try:
|
||||||
|
return self.db.security_group_default_rule_get(context, id)
|
||||||
|
except exception.NotFound:
|
||||||
|
msg = _("Rule (%s) not found") % id
|
||||||
|
self.raise_not_found(msg)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def raise_invalid_property(msg):
|
def raise_invalid_property(msg):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -1206,6 +1206,28 @@ def security_group_rule_count_by_group(context, security_group_id):
|
|||||||
###################
|
###################
|
||||||
|
|
||||||
|
|
||||||
|
def security_group_default_rule_get(context, security_group_rule_default_id):
|
||||||
|
return IMPL.security_group_default_rule_get(context,
|
||||||
|
security_group_rule_default_id)
|
||||||
|
|
||||||
|
|
||||||
|
def security_group_default_rule_destroy(context,
|
||||||
|
security_group_rule_default_id):
|
||||||
|
return IMPL.security_group_default_rule_destroy(
|
||||||
|
context, security_group_rule_default_id)
|
||||||
|
|
||||||
|
|
||||||
|
def security_group_default_rule_create(context, values):
|
||||||
|
return IMPL.security_group_default_rule_create(context, values)
|
||||||
|
|
||||||
|
|
||||||
|
def security_group_default_rule_list(context):
|
||||||
|
return IMPL.security_group_default_rule_list(context)
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
|
||||||
|
|
||||||
def provider_fw_rule_create(context, rule):
|
def provider_fw_rule_create(context, rule):
|
||||||
"""Add a firewall rule at the provider level (all hosts & instances)."""
|
"""Add a firewall rule at the provider level (all hosts & instances)."""
|
||||||
return IMPL.provider_fw_rule_create(context, rule)
|
return IMPL.provider_fw_rule_create(context, rule)
|
||||||
|
@ -3180,6 +3180,16 @@ def security_group_ensure_default(context, session=None):
|
|||||||
'project_id': context.project_id}
|
'project_id': context.project_id}
|
||||||
default_group = security_group_create(context, values,
|
default_group = security_group_create(context, values,
|
||||||
session=session)
|
session=session)
|
||||||
|
for default_rule in security_group_default_rule_list(context):
|
||||||
|
# This is suboptimal, it should be programmatic to know
|
||||||
|
# the values of the default_rule
|
||||||
|
rule_values = {'protocol': default_rule.protocol,
|
||||||
|
'from_port': default_rule.from_port,
|
||||||
|
'to_port': default_rule.to_port,
|
||||||
|
'cidr': default_rule.cidr,
|
||||||
|
'parent_group_id': default_group.id,
|
||||||
|
}
|
||||||
|
security_group_rule_create(context, rule_values)
|
||||||
return (False, default_group)
|
return (False, default_group)
|
||||||
|
|
||||||
|
|
||||||
@ -3280,6 +3290,56 @@ def security_group_rule_count_by_group(context, security_group_id):
|
|||||||
###################
|
###################
|
||||||
|
|
||||||
|
|
||||||
|
def _security_group_rule_get_default_query(context, session=None):
|
||||||
|
return model_query(context, models.SecurityGroupIngressDefaultRule,
|
||||||
|
session=session)
|
||||||
|
|
||||||
|
|
||||||
|
@require_context
|
||||||
|
def security_group_default_rule_get(context, security_group_rule_default_id,
|
||||||
|
session=None):
|
||||||
|
result = _security_group_rule_get_default_query(context, session=session).\
|
||||||
|
filter_by(id=security_group_rule_default_id).\
|
||||||
|
first()
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
raise exception.SecurityGroupDefaultRuleNotFound(
|
||||||
|
rule_id=security_group_rule_default_id)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@require_admin_context
|
||||||
|
def security_group_default_rule_destroy(context,
|
||||||
|
security_group_rule_default_id):
|
||||||
|
session = get_session()
|
||||||
|
with session.begin():
|
||||||
|
count = _security_group_rule_get_default_query(context,
|
||||||
|
session=session).\
|
||||||
|
filter_by(id=security_group_rule_default_id).\
|
||||||
|
soft_delete()
|
||||||
|
if count == 0:
|
||||||
|
raise exception.SecurityGroupDefaultRuleNotFound(
|
||||||
|
rule_id=security_group_rule_default_id)
|
||||||
|
|
||||||
|
|
||||||
|
@require_admin_context
|
||||||
|
def security_group_default_rule_create(context, values):
|
||||||
|
security_group_default_rule_ref = models.SecurityGroupIngressDefaultRule()
|
||||||
|
security_group_default_rule_ref.update(values)
|
||||||
|
security_group_default_rule_ref.save()
|
||||||
|
return security_group_default_rule_ref
|
||||||
|
|
||||||
|
|
||||||
|
@require_context
|
||||||
|
def security_group_default_rule_list(context, session=None):
|
||||||
|
return _security_group_rule_get_default_query(context, session=session).\
|
||||||
|
all()
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
|
||||||
|
|
||||||
@require_admin_context
|
@require_admin_context
|
||||||
def provider_fw_rule_create(context, rule):
|
def provider_fw_rule_create(context, rule):
|
||||||
fw_rule_ref = models.ProviderFirewallRule()
|
fw_rule_ref = models.ProviderFirewallRule()
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from sqlalchemy import Column, DateTime, Integer, MetaData, String, Table
|
||||||
|
from nova.db.sqlalchemy import types
|
||||||
|
|
||||||
|
from nova.openstack.common import log as logging
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
security_group_default_rules = Table('security_group_default_rules', meta,
|
||||||
|
Column('created_at', DateTime),
|
||||||
|
Column('updated_at', DateTime),
|
||||||
|
Column('deleted_at', DateTime),
|
||||||
|
Column('deleted', Integer, default=0),
|
||||||
|
Column('id', Integer, primary_key=True, nullable=False),
|
||||||
|
Column('protocol', String(length=5)),
|
||||||
|
Column('from_port', Integer),
|
||||||
|
Column('to_port', Integer),
|
||||||
|
Column('cidr', types.CIDR()),
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
mysql_charset='utf8',
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
security_group_default_rules.create()
|
||||||
|
except Exception:
|
||||||
|
msg = "Exception while creating table 'security_group_default_rules"
|
||||||
|
LOG.exception(msg)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migrate_engine):
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
security_group_default_rules = Table('security_group_default_rules',
|
||||||
|
meta,
|
||||||
|
autoload=True)
|
||||||
|
try:
|
||||||
|
security_group_default_rules.drop()
|
||||||
|
except Exception:
|
||||||
|
msg = "Exception while droppping table 'security_group_default_rules'"
|
||||||
|
LOG.exception(msg)
|
||||||
|
raise
|
@ -541,6 +541,15 @@ class SecurityGroupIngressRule(BASE, NovaBase):
|
|||||||
'SecurityGroupIngressRule.deleted == 0)')
|
'SecurityGroupIngressRule.deleted == 0)')
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityGroupIngressDefaultRule(BASE, NovaBase):
|
||||||
|
__tablename__ = 'security_group_default_rules'
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
protocol = Column(String(5)) # "tcp", "udp" or "icmp"
|
||||||
|
from_port = Column(Integer)
|
||||||
|
to_port = Column(Integer)
|
||||||
|
cidr = Column(types.CIDR())
|
||||||
|
|
||||||
|
|
||||||
class ProviderFirewallRule(BASE, NovaBase):
|
class ProviderFirewallRule(BASE, NovaBase):
|
||||||
"""Represents a rule in a security group."""
|
"""Represents a rule in a security group."""
|
||||||
__tablename__ = 'provider_fw_rules'
|
__tablename__ = 'provider_fw_rules'
|
||||||
|
@ -732,6 +732,10 @@ class SecurityGroupNotExistsForInstance(Invalid):
|
|||||||
" the instance %(instance_id)s")
|
" the instance %(instance_id)s")
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityGroupDefaultRuleNotFound(Invalid):
|
||||||
|
message = _("Security group default rule (%rule_id)s not found.")
|
||||||
|
|
||||||
|
|
||||||
class MigrationNotFound(NotFound):
|
class MigrationNotFound(NotFound):
|
||||||
message = _("Migration %(migration_id)s could not be found.")
|
message = _("Migration %(migration_id)s could not be found.")
|
||||||
|
|
||||||
|
@ -0,0 +1,467 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2013 Metacloud, Inc
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from lxml import etree
|
||||||
|
import webob
|
||||||
|
|
||||||
|
from nova.api.openstack.compute.contrib import security_group_default_rules
|
||||||
|
from nova.api.openstack import wsgi
|
||||||
|
from nova import context
|
||||||
|
import nova.db
|
||||||
|
from nova.openstack.common import cfg
|
||||||
|
from nova import test
|
||||||
|
from nova.tests.api.openstack import fakes
|
||||||
|
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class AttrDict(dict):
|
||||||
|
def __getattr__(self, k):
|
||||||
|
return self[k]
|
||||||
|
|
||||||
|
|
||||||
|
def security_group_default_rule_template(**kwargs):
|
||||||
|
rule = kwargs.copy()
|
||||||
|
rule.setdefault('ip_protocol', 'TCP')
|
||||||
|
rule.setdefault('from_port', 22)
|
||||||
|
rule.setdefault('to_port', 22)
|
||||||
|
rule.setdefault('cidr', '10.10.10.0/24')
|
||||||
|
return rule
|
||||||
|
|
||||||
|
|
||||||
|
def security_group_default_rule_db(security_group_default_rule, id=None):
|
||||||
|
attrs = security_group_default_rule.copy()
|
||||||
|
if id is not None:
|
||||||
|
attrs['id'] = id
|
||||||
|
return AttrDict(attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSecurityGroupDefaultRules(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestSecurityGroupDefaultRules, self).setUp()
|
||||||
|
self.controller = \
|
||||||
|
security_group_default_rules.SecurityGroupDefaultRulesController()
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule(self):
|
||||||
|
sgr = security_group_default_rule_template()
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
sgr_dict = dict(security_group_default_rule=sgr)
|
||||||
|
res_dict = self.controller.create(req, sgr_dict)
|
||||||
|
security_group_default_rule = res_dict['security_group_default_rule']
|
||||||
|
self.assertEqual(security_group_default_rule['ip_protocol'],
|
||||||
|
sgr['ip_protocol'])
|
||||||
|
self.assertEqual(security_group_default_rule['from_port'],
|
||||||
|
sgr['from_port'])
|
||||||
|
self.assertEqual(security_group_default_rule['to_port'],
|
||||||
|
sgr['to_port'])
|
||||||
|
self.assertEqual(security_group_default_rule['ip_range']['cidr'],
|
||||||
|
sgr['cidr'])
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_with_no_to_port(self):
|
||||||
|
sgr = security_group_default_rule_template()
|
||||||
|
del sgr['to_port']
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_with_no_from_port(self):
|
||||||
|
sgr = security_group_default_rule_template()
|
||||||
|
del sgr['from_port']
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_with_no_ip_protocol(self):
|
||||||
|
sgr = security_group_default_rule_template()
|
||||||
|
del sgr['ip_protocol']
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_with_no_cidr(self):
|
||||||
|
sgr = security_group_default_rule_template()
|
||||||
|
del sgr['cidr']
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
res_dict = self.controller.create(req,
|
||||||
|
{'security_group_default_rule': sgr})
|
||||||
|
security_group_default_rule = res_dict['security_group_default_rule']
|
||||||
|
self.assertNotEquals(security_group_default_rule['id'], 0)
|
||||||
|
self.assertEquals(security_group_default_rule['ip_range']['cidr'],
|
||||||
|
'0.0.0.0/0')
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_with_blank_to_port(self):
|
||||||
|
sgr = security_group_default_rule_template(to_port='')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_with_blank_from_port(self):
|
||||||
|
sgr = security_group_default_rule_template(from_port='')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_with_blank_ip_protocol(self):
|
||||||
|
sgr = security_group_default_rule_template(ip_protocol='')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_with_blank_cidr(self):
|
||||||
|
sgr = security_group_default_rule_template(cidr='')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
res_dict = self.controller.create(req,
|
||||||
|
{'security_group_default_rule': sgr})
|
||||||
|
security_group_default_rule = res_dict['security_group_default_rule']
|
||||||
|
self.assertNotEquals(security_group_default_rule['id'], 0)
|
||||||
|
self.assertEquals(security_group_default_rule['ip_range']['cidr'],
|
||||||
|
'0.0.0.0/0')
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_non_numerical_to_port(self):
|
||||||
|
sgr = security_group_default_rule_template(to_port='invalid')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_non_numerical_from_port(self):
|
||||||
|
sgr = security_group_default_rule_template(from_port='invalid')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_invalid_ip_protocol(self):
|
||||||
|
sgr = security_group_default_rule_template(ip_protocol='invalid')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_invalid_cidr(self):
|
||||||
|
sgr = security_group_default_rule_template(cidr='10.10.2222.0/24')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_invalid_to_port(self):
|
||||||
|
sgr = security_group_default_rule_template(to_port='666666')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_invalid_from_port(self):
|
||||||
|
sgr = security_group_default_rule_template(from_port='666666')
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_create_security_group_default_rule_with_no_body(self):
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
|
||||||
|
self.controller.create, req, None)
|
||||||
|
|
||||||
|
def test_create_duplicate_security_group_default_rule(self):
|
||||||
|
sgr = security_group_default_rule_template()
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.controller.create(req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
||||||
|
req, {'security_group_default_rule': sgr})
|
||||||
|
|
||||||
|
def test_security_group_default_rules_list(self):
|
||||||
|
self.test_create_security_group_default_rule()
|
||||||
|
rules = [dict(id=1,
|
||||||
|
ip_protocol='TCP',
|
||||||
|
from_port=22,
|
||||||
|
to_port=22,
|
||||||
|
ip_range=dict(cidr='10.10.10.0/24'))]
|
||||||
|
expected = {'security_group_default_rules': rules}
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
res_dict = self.controller.index(req)
|
||||||
|
self.assertEqual(res_dict, expected)
|
||||||
|
|
||||||
|
def test_default_security_group_default_rule_show(self):
|
||||||
|
sgr = security_group_default_rule_template(id=1)
|
||||||
|
|
||||||
|
self.test_create_security_group_default_rule()
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
res_dict = self.controller.show(req, '1')
|
||||||
|
|
||||||
|
security_group_default_rule = res_dict['security_group_default_rule']
|
||||||
|
|
||||||
|
self.assertEqual(security_group_default_rule['ip_protocol'],
|
||||||
|
sgr['ip_protocol'])
|
||||||
|
self.assertEqual(security_group_default_rule['to_port'],
|
||||||
|
sgr['to_port'])
|
||||||
|
self.assertEqual(security_group_default_rule['from_port'],
|
||||||
|
sgr['from_port'])
|
||||||
|
self.assertEqual(security_group_default_rule['ip_range']['cidr'],
|
||||||
|
sgr['cidr'])
|
||||||
|
|
||||||
|
def test_delete_security_group_default_rule(self):
|
||||||
|
sgr = security_group_default_rule_template(id=1)
|
||||||
|
|
||||||
|
self.test_create_security_group_default_rule()
|
||||||
|
|
||||||
|
self.called = False
|
||||||
|
|
||||||
|
def security_group_default_rule_destroy(context, id):
|
||||||
|
self.called = True
|
||||||
|
|
||||||
|
def return_security_group_default_rule(context, id):
|
||||||
|
self.assertEquals(sgr['id'], id)
|
||||||
|
return security_group_default_rule_db(sgr)
|
||||||
|
|
||||||
|
self.stubs.Set(nova.db, 'security_group_default_rule_destroy',
|
||||||
|
security_group_default_rule_destroy)
|
||||||
|
self.stubs.Set(nova.db, 'security_group_default_rule_get',
|
||||||
|
return_security_group_default_rule)
|
||||||
|
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/v2/fake/os-security-group-default-rules', use_admin_context=True)
|
||||||
|
self.controller.delete(req, '1')
|
||||||
|
|
||||||
|
self.assertTrue(self.called)
|
||||||
|
|
||||||
|
def test_security_group_ensure_default(self):
|
||||||
|
sgr = security_group_default_rule_template(id=1)
|
||||||
|
self.test_create_security_group_default_rule()
|
||||||
|
|
||||||
|
ctxt = context.get_admin_context()
|
||||||
|
|
||||||
|
setattr(ctxt, 'project_id', 'new_project_id')
|
||||||
|
|
||||||
|
_, sg = nova.db.security_group_ensure_default(ctxt)
|
||||||
|
rules = nova.db.security_group_rule_get_by_security_group(ctxt, sg.id)
|
||||||
|
security_group_rule = rules[0]
|
||||||
|
self.assertEqual(sgr['id'], security_group_rule.id)
|
||||||
|
self.assertEqual(sgr['ip_protocol'], security_group_rule.protocol)
|
||||||
|
self.assertEqual(sgr['from_port'], security_group_rule.from_port)
|
||||||
|
self.assertEqual(sgr['to_port'], security_group_rule.to_port)
|
||||||
|
self.assertEqual(sgr['cidr'], security_group_rule.cidr)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSecurityGroupDefaultRulesXMLDeserializer(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestSecurityGroupDefaultRulesXMLDeserializer, self).setUp()
|
||||||
|
deserializer = security_group_default_rules.\
|
||||||
|
SecurityGroupDefaultRulesXMLDeserializer()
|
||||||
|
self.deserializer = deserializer
|
||||||
|
|
||||||
|
def test_create_request(self):
|
||||||
|
serial_request = """
|
||||||
|
<security_group_default_rule>
|
||||||
|
<from_port>22</from_port>
|
||||||
|
<to_port>22</to_port>
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</security_group_default_rule>"""
|
||||||
|
request = self.deserializer.deserialize(serial_request)
|
||||||
|
expected = {
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"from_port": "22",
|
||||||
|
"to_port": "22",
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(request['body'], expected)
|
||||||
|
|
||||||
|
def test_create_no_to_port_request(self):
|
||||||
|
serial_request = """
|
||||||
|
<security_group_default_rule>
|
||||||
|
<from_port>22</from_port>
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</security_group_default_rule>"""
|
||||||
|
request = self.deserializer.deserialize(serial_request)
|
||||||
|
expected = {
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"from_port": "22",
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(request['body'], expected)
|
||||||
|
|
||||||
|
def test_create_no_from_port_request(self):
|
||||||
|
serial_request = """
|
||||||
|
<security_group_default_rule>
|
||||||
|
<to_port>22</to_port>
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</security_group_default_rule>"""
|
||||||
|
request = self.deserializer.deserialize(serial_request)
|
||||||
|
expected = {
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"to_port": "22",
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(request['body'], expected)
|
||||||
|
|
||||||
|
def test_create_no_ip_protocol_request(self):
|
||||||
|
serial_request = """
|
||||||
|
<security_group_default_rule>
|
||||||
|
<from_port>22</from_port>
|
||||||
|
<to_port>22</to_port>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</security_group_default_rule>"""
|
||||||
|
request = self.deserializer.deserialize(serial_request)
|
||||||
|
expected = {
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"from_port": "22",
|
||||||
|
"to_port": "22",
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(request['body'], expected)
|
||||||
|
|
||||||
|
def test_create_no_cidr_request(self):
|
||||||
|
serial_request = """
|
||||||
|
<security_group_default_rule>
|
||||||
|
<from_port>22</from_port>
|
||||||
|
<to_port>22</to_port>
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
</security_group_default_rule>"""
|
||||||
|
request = self.deserializer.deserialize(serial_request)
|
||||||
|
expected = {
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"from_port": "22",
|
||||||
|
"to_port": "22",
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
self.assertEqual(request['body'], expected)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSecurityGroupDefaultRuleXMLSerializer(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestSecurityGroupDefaultRuleXMLSerializer, self).setUp()
|
||||||
|
self.namespace = wsgi.XMLNS_V11
|
||||||
|
self.rule_serializer =\
|
||||||
|
security_group_default_rules.SecurityGroupDefaultRuleTemplate()
|
||||||
|
self.index_serializer =\
|
||||||
|
security_group_default_rules.SecurityGroupDefaultRulesTemplate()
|
||||||
|
|
||||||
|
def _tag(self, elem):
|
||||||
|
tagname = elem.tag
|
||||||
|
self.assertEqual(tagname[0], '{')
|
||||||
|
tmp = tagname.partition('}')
|
||||||
|
namespace = tmp[0][1:]
|
||||||
|
self.assertEqual(namespace, self.namespace)
|
||||||
|
return tmp[2]
|
||||||
|
|
||||||
|
def _verify_security_group_default_rule(self, raw_rule, tree):
|
||||||
|
self.assertEqual(raw_rule['id'], tree.get('id'))
|
||||||
|
|
||||||
|
seen = set()
|
||||||
|
expected = set(['ip_protocol', 'from_port', 'to_port', 'ip_range',
|
||||||
|
'ip_range/cidr'])
|
||||||
|
|
||||||
|
for child in tree:
|
||||||
|
child_tag = self._tag(child)
|
||||||
|
seen.add(child_tag)
|
||||||
|
if child_tag == 'ip_range':
|
||||||
|
for gr_child in child:
|
||||||
|
gr_child_tag = self._tag(gr_child)
|
||||||
|
self.assertTrue(gr_child_tag in raw_rule[child_tag])
|
||||||
|
seen.add('%s/%s' % (child_tag, gr_child_tag))
|
||||||
|
self.assertEqual(gr_child.text,
|
||||||
|
raw_rule[child_tag][gr_child_tag])
|
||||||
|
else:
|
||||||
|
self.assertEqual(child.text, raw_rule[child_tag])
|
||||||
|
self.assertEqual(seen, expected)
|
||||||
|
|
||||||
|
def test_rule_serializer(self):
|
||||||
|
raw_rule = dict(id='123',
|
||||||
|
ip_protocol='TCP',
|
||||||
|
from_port='22',
|
||||||
|
to_port='22',
|
||||||
|
ip_range=dict(cidr='10.10.10.0/24'))
|
||||||
|
rule = dict(security_group_default_rule=raw_rule)
|
||||||
|
text = self.rule_serializer.serialize(rule)
|
||||||
|
|
||||||
|
tree = etree.fromstring(text)
|
||||||
|
|
||||||
|
self.assertEqual('security_group_default_rule', self._tag(tree))
|
||||||
|
self._verify_security_group_default_rule(raw_rule, tree)
|
||||||
|
|
||||||
|
def test_index_serializer(self):
|
||||||
|
rules = [dict(id='123',
|
||||||
|
ip_protocol='TCP',
|
||||||
|
from_port='22',
|
||||||
|
to_port='22',
|
||||||
|
ip_range=dict(cidr='10.10.10.0/24')),
|
||||||
|
dict(id='234',
|
||||||
|
ip_protocol='UDP',
|
||||||
|
from_port='23456',
|
||||||
|
to_port='234567',
|
||||||
|
ip_range=dict(cidr='10.12.0.0/18')),
|
||||||
|
dict(id='345',
|
||||||
|
ip_protocol='tcp',
|
||||||
|
from_port='3456',
|
||||||
|
to_port='4567',
|
||||||
|
ip_range=dict(cidr='192.168.1.0/32'))]
|
||||||
|
|
||||||
|
rules_dict = dict(security_group_default_rules=rules)
|
||||||
|
|
||||||
|
text = self.index_serializer.serialize(rules_dict)
|
||||||
|
|
||||||
|
tree = etree.fromstring(text)
|
||||||
|
self.assertEqual('security_group_default_rules', self._tag(tree))
|
||||||
|
self.assertEqual(len(rules), len(tree))
|
||||||
|
for idx, child in enumerate(tree):
|
||||||
|
self._verify_security_group_default_rule(rules[idx], child)
|
@ -193,6 +193,7 @@ class ExtensionControllerTest(ExtensionTestCase):
|
|||||||
"Quotas",
|
"Quotas",
|
||||||
"Rescue",
|
"Rescue",
|
||||||
"SchedulerHints",
|
"SchedulerHints",
|
||||||
|
"SecurityGroupDefaultRules",
|
||||||
"SecurityGroups",
|
"SecurityGroups",
|
||||||
"ServerDiagnostics",
|
"ServerDiagnostics",
|
||||||
"ServerPassword",
|
"ServerPassword",
|
||||||
|
@ -156,6 +156,7 @@ policy_data = """
|
|||||||
"compute_extension:quotas:update": "",
|
"compute_extension:quotas:update": "",
|
||||||
"compute_extension:quota_classes": "",
|
"compute_extension:quota_classes": "",
|
||||||
"compute_extension:rescue": "",
|
"compute_extension:rescue": "",
|
||||||
|
"compute_extension:security_group_default_rules": "",
|
||||||
"compute_extension:security_groups": "",
|
"compute_extension:security_groups": "",
|
||||||
"compute_extension:server_diagnostics": "",
|
"compute_extension:server_diagnostics": "",
|
||||||
"compute_extension:server_password": "",
|
"compute_extension:server_password": "",
|
||||||
|
@ -392,6 +392,14 @@
|
|||||||
"namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1",
|
"namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1",
|
||||||
"updated": "%(timestamp)s"
|
"updated": "%(timestamp)s"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"alias": "os-security-group-default-rules",
|
||||||
|
"description": "%(text)s",
|
||||||
|
"links": [],
|
||||||
|
"name": "SecurityGroupDefaultRules",
|
||||||
|
"namespace": "http://docs.openstack.org/compute/ext/securitygroupdefaultrules/api/v1.1",
|
||||||
|
"updated": "%(timestamp)s"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"alias": "os-security-groups",
|
"alias": "os-security-groups",
|
||||||
"description": "%(text)s",
|
"description": "%(text)s",
|
||||||
|
@ -147,6 +147,9 @@
|
|||||||
<extension alias="os-rescue" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue">
|
<extension alias="os-rescue" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue">
|
||||||
<description>%(text)s</description>
|
<description>%(text)s</description>
|
||||||
</extension>
|
</extension>
|
||||||
|
<extension alias="os-security-group-default-rules" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/securitygroupdefaultrules/api/v1.1" name="SecurityGroupDefaultRules">
|
||||||
|
<description>%(text)s</description>
|
||||||
|
</extension>
|
||||||
<extension alias="os-security-groups" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/securitygroups/api/v1.1" name="SecurityGroups">
|
<extension alias="os-security-groups" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/securitygroups/api/v1.1" name="SecurityGroups">
|
||||||
<description>%(text)s</description>
|
<description>%(text)s</description>
|
||||||
</extension>
|
</extension>
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"from_port": "80",
|
||||||
|
"to_port": "80",
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<security_group_default_rule>
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<from_port>80</from_port>
|
||||||
|
<to_port>80</to_port>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</security_group_default_rule>
|
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"from_port": 80,
|
||||||
|
"id": 1,
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"ip_range":{
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
},
|
||||||
|
"to_port": 80
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<security_group_default_rule xmlns="http://docs.openstack.org/compute/api/v1.1" id="1">
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<from_port>80</from_port>
|
||||||
|
<to_port>80</to_port>
|
||||||
|
<ip_range>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</ip_range>
|
||||||
|
</security_group_default_rule>
|
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"security_group_default_rules": [
|
||||||
|
{
|
||||||
|
"from_port": 80,
|
||||||
|
"id": 1,
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"ip_range": {
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
},
|
||||||
|
"to_port": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<security_group_default_rules xmlns="http://docs.openstack.org/compute/api/v1.1">
|
||||||
|
<security_group_default_rule id="1">
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<from_port>80</from_port>
|
||||||
|
<to_port>80</to_port>
|
||||||
|
<ip_range>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</ip_range>
|
||||||
|
</security_group_default_rule>
|
||||||
|
</security_group_default_rules>
|
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"id": 1,
|
||||||
|
"from_port": 80,
|
||||||
|
"to_port": 80,
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"ip_range": {
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<security_group_default_rule xmlns="http://docs.openstack.org/compute/api/v1.1" id="1">
|
||||||
|
<from_port>80</from_port>
|
||||||
|
<to_port>80</to_port>
|
||||||
|
<ip_protocol>TCP</ip_protocol>
|
||||||
|
<ip_range>
|
||||||
|
<cidr>10.10.10.0/24</cidr>
|
||||||
|
</ip_range>
|
||||||
|
</security_group_default_rule>
|
@ -1127,7 +1127,39 @@ class SecurityGroupsSampleJsonTest(ServersSampleBase):
|
|||||||
subs, response)
|
subs, response)
|
||||||
|
|
||||||
|
|
||||||
class SecurityGroupsSampleXmlTest(SecurityGroupsSampleJsonTest):
|
class SecurityGroupsSampleXmlTest(ApiSampleTestBase):
|
||||||
|
ctype = 'xml'
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityGroupDefaultRulesSampleJsonTest(ServersSampleBase):
|
||||||
|
extension_name = ('nova.api.openstack.compute.contrib'
|
||||||
|
'.security_group_default_rules'
|
||||||
|
'.Security_group_default_rules')
|
||||||
|
|
||||||
|
def test_security_group_default_rules_create(self):
|
||||||
|
response = self._do_post('os-security-group-default-rules',
|
||||||
|
'security-group-default-rules-create-req',
|
||||||
|
{})
|
||||||
|
self.assertEqual(response.status, 200)
|
||||||
|
return self._verify_response(
|
||||||
|
'security-group-default-rules-create-resp', {}, response)
|
||||||
|
|
||||||
|
def test_security_group_default_rules_list(self):
|
||||||
|
self.test_security_group_default_rules_create()
|
||||||
|
response = self._do_get('os-security-group-default-rules')
|
||||||
|
return self._verify_response('security-group-default-rules-list-resp',
|
||||||
|
{}, response)
|
||||||
|
|
||||||
|
def test_security_group_default_rules_show(self):
|
||||||
|
self.test_security_group_default_rules_create()
|
||||||
|
rule_id = '1'
|
||||||
|
response = self._do_get('os-security-group-default-rules/%s' % rule_id)
|
||||||
|
return self._verify_response('security-group-default-rules-show-resp',
|
||||||
|
{}, response)
|
||||||
|
|
||||||
|
|
||||||
|
class SecurityGroupDefaultRulesSampleXmlTest(
|
||||||
|
SecurityGroupDefaultRulesSampleJsonTest):
|
||||||
ctype = 'xml'
|
ctype = 'xml'
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user