summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api_samples/all_extensions/extensions-get-resp.json8
-rw-r--r--doc/api_samples/all_extensions/extensions-get-resp.xml3
-rw-r--r--doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.json8
-rw-r--r--doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.xml7
-rw-r--r--doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.json11
-rw-r--r--doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.xml9
-rw-r--r--doc/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.json13
-rw-r--r--doc/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.xml11
-rw-r--r--doc/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.json11
-rw-r--r--doc/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.xml9
-rw-r--r--etc/nova/policy.json1
-rw-r--r--nova/api/openstack/compute/contrib/security_group_default_rules.py210
-rw-r--r--nova/compute/api.py40
-rw-r--r--nova/db/api.py22
-rw-r--r--nova/db/sqlalchemy/api.py60
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/157_add_security_group_default_rules.py61
-rw-r--r--nova/db/sqlalchemy/models.py9
-rw-r--r--nova/exception.py4
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_security_group_default_rules.py467
-rw-r--r--nova/tests/api/openstack/compute/test_extensions.py1
-rw-r--r--nova/tests/fake_policy.py1
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl8
-rw-r--r--nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl3
-rw-r--r--nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.json.tpl8
-rw-r--r--nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.xml.tpl7
-rw-r--r--nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.json.tpl11
-rw-r--r--nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.xml.tpl9
-rw-r--r--nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.json.tpl13
-rw-r--r--nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.xml.tpl11
-rw-r--r--nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.json.tpl11
-rw-r--r--nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.xml.tpl9
-rw-r--r--nova/tests/integrated/test_api_samples.py34
32 files changed, 1089 insertions, 1 deletions
diff --git a/doc/api_samples/all_extensions/extensions-get-resp.json b/doc/api_samples/all_extensions/extensions-get-resp.json
index ba5e410eb8..14e9062ca3 100644
--- a/doc/api_samples/all_extensions/extensions-get-resp.json
+++ b/doc/api_samples/all_extensions/extensions-get-resp.json
@@ -385,6 +385,14 @@
"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",
"description": "Security group support.",
"links": [],
diff --git a/doc/api_samples/all_extensions/extensions-get-resp.xml b/doc/api_samples/all_extensions/extensions-get-resp.xml
index a18e524370..133b0570ad 100644
--- a/doc/api_samples/all_extensions/extensions-get-resp.xml
+++ b/doc/api_samples/all_extensions/extensions-get-resp.xml
@@ -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">
<description>Instance rescue mode.</description>
</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">
<description>Security group support.</description>
</extension>
diff --git a/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.json b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.json
new file mode 100644
index 0000000000..8b0a901c7c
--- /dev/null
+++ b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.json
@@ -0,0 +1,8 @@
+{
+ "security_group_default_rule": {
+ "ip_protocol": "TCP",
+ "from_port": "80",
+ "to_port": "80",
+ "cidr": "10.10.12.0/24"
+ }
+} \ No newline at end of file
diff --git a/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.xml b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.xml
new file mode 100644
index 0000000000..7fa3af7d9d
--- /dev/null
+++ b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.xml
@@ -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> \ No newline at end of file
diff --git a/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.json b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.json
new file mode 100644
index 0000000000..ae6c62bfd6
--- /dev/null
+++ b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.json
@@ -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
+ }
+} \ No newline at end of file
diff --git a/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.xml b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.xml
new file mode 100644
index 0000000000..9e700969ff
--- /dev/null
+++ b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.xml
@@ -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> \ No newline at end of file
diff --git a/doc/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.json b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.json
new file mode 100644
index 0000000000..c083640c3e
--- /dev/null
+++ b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.json
@@ -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
+ }
+ ]
+} \ No newline at end of file
diff --git a/doc/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.xml b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.xml
new file mode 100644
index 0000000000..f009bf80f1
--- /dev/null
+++ b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.xml
@@ -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> \ No newline at end of file
diff --git a/doc/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.json b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.json
new file mode 100644
index 0000000000..97b5259a18
--- /dev/null
+++ b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.json
@@ -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"
+ }
+ }
+} \ No newline at end of file
diff --git a/doc/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.xml b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.xml
new file mode 100644
index 0000000000..9181abd387
--- /dev/null
+++ b/doc/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.xml
@@ -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> \ No newline at end of file
diff --git a/etc/nova/policy.json b/etc/nova/policy.json
index 2d3c4ed062..a8bc6f1414 100644
--- a/etc/nova/policy.json
+++ b/etc/nova/policy.json
@@ -78,6 +78,7 @@
"compute_extension:quotas:update": "rule:admin_api",
"compute_extension:quota_classes": "",
"compute_extension:rescue": "",
+ "compute_extension:security_group_default_rules": "rule:admin_api",
"compute_extension:security_groups": "",
"compute_extension:server_diagnostics": "rule:admin_api",
"compute_extension:server_password": "",
diff --git a/nova/api/openstack/compute/contrib/security_group_default_rules.py b/nova/api/openstack/compute/contrib/security_group_default_rules.py
new file mode 100644
index 0000000000..fed1468a81
--- /dev/null
+++ b/nova/api/openstack/compute/contrib/security_group_default_rules.py
@@ -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
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 5e160d2ef4..39d5f70500 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -3128,6 +3128,46 @@ class SecurityGroupAPI(base.Base):
self.trigger_rules_refresh(context, id=security_group['id'])
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
def raise_invalid_property(msg):
raise NotImplementedError()
diff --git a/nova/db/api.py b/nova/db/api.py
index 6ec0b3a95b..969cf494aa 100644
--- a/nova/db/api.py
+++ b/nova/db/api.py
@@ -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):
"""Add a firewall rule at the provider level (all hosts & instances)."""
return IMPL.provider_fw_rule_create(context, rule)
diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 375a3884b4..66fc243558 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -3180,6 +3180,16 @@ def security_group_ensure_default(context, session=None):
'project_id': context.project_id}
default_group = security_group_create(context, values,
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)
@@ -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
def provider_fw_rule_create(context, rule):
fw_rule_ref = models.ProviderFirewallRule()
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/157_add_security_group_default_rules.py b/nova/db/sqlalchemy/migrate_repo/versions/157_add_security_group_default_rules.py
new file mode 100644
index 0000000000..5dcfdbb90d
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/157_add_security_group_default_rules.py
@@ -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
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 28d8f08825..f0dcd33079 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -541,6 +541,15 @@ class SecurityGroupIngressRule(BASE, NovaBase):
'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):
"""Represents a rule in a security group."""
__tablename__ = 'provider_fw_rules'
diff --git a/nova/exception.py b/nova/exception.py
index 9e9e5182b4..09b01b342d 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -732,6 +732,10 @@ class SecurityGroupNotExistsForInstance(Invalid):
" the instance %(instance_id)s")
+class SecurityGroupDefaultRuleNotFound(Invalid):
+ message = _("Security group default rule (%rule_id)s not found.")
+
+
class MigrationNotFound(NotFound):
message = _("Migration %(migration_id)s could not be found.")
diff --git a/nova/tests/api/openstack/compute/contrib/test_security_group_default_rules.py b/nova/tests/api/openstack/compute/contrib/test_security_group_default_rules.py
new file mode 100644
index 0000000000..88dee2edfb
--- /dev/null
+++ b/nova/tests/api/openstack/compute/contrib/test_security_group_default_rules.py
@@ -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)
diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py
index 9c45edc08b..63a6b3c9a2 100644
--- a/nova/tests/api/openstack/compute/test_extensions.py
+++ b/nova/tests/api/openstack/compute/test_extensions.py
@@ -193,6 +193,7 @@ class ExtensionControllerTest(ExtensionTestCase):
"Quotas",
"Rescue",
"SchedulerHints",
+ "SecurityGroupDefaultRules",
"SecurityGroups",
"ServerDiagnostics",
"ServerPassword",
diff --git a/nova/tests/fake_policy.py b/nova/tests/fake_policy.py
index 3878df531d..3826679048 100644
--- a/nova/tests/fake_policy.py
+++ b/nova/tests/fake_policy.py
@@ -156,6 +156,7 @@ policy_data = """
"compute_extension:quotas:update": "",
"compute_extension:quota_classes": "",
"compute_extension:rescue": "",
+ "compute_extension:security_group_default_rules": "",
"compute_extension:security_groups": "",
"compute_extension:server_diagnostics": "",
"compute_extension:server_password": "",
diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
index 17914de426..6aeedbe56a 100644
--- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl
@@ -393,6 +393,14 @@
"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",
"description": "%(text)s",
"links": [],
diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
index 4492ed3aaa..421cc22338 100644
--- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
+++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl
@@ -147,6 +147,9 @@
<extension alias="os-rescue" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue">
<description>%(text)s</description>
</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">
<description>%(text)s</description>
</extension>
diff --git a/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.json.tpl b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.json.tpl
new file mode 100644
index 0000000000..8836d0eecc
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.json.tpl
@@ -0,0 +1,8 @@
+{
+ "security_group_default_rule": {
+ "ip_protocol": "TCP",
+ "from_port": "80",
+ "to_port": "80",
+ "cidr": "10.10.10.0/24"
+ }
+} \ No newline at end of file
diff --git a/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.xml.tpl b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.xml.tpl
new file mode 100644
index 0000000000..daee122905
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-req.xml.tpl
@@ -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> \ No newline at end of file
diff --git a/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.json.tpl b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.json.tpl
new file mode 100644
index 0000000000..ae6c62bfd6
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.json.tpl
@@ -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
+ }
+} \ No newline at end of file
diff --git a/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.xml.tpl b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.xml.tpl
new file mode 100644
index 0000000000..9e700969ff
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-create-resp.xml.tpl
@@ -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> \ No newline at end of file
diff --git a/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.json.tpl
new file mode 100644
index 0000000000..c083640c3e
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.json.tpl
@@ -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
+ }
+ ]
+} \ No newline at end of file
diff --git a/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.xml.tpl
new file mode 100644
index 0000000000..f009bf80f1
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-list-resp.xml.tpl
@@ -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> \ No newline at end of file
diff --git a/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.json.tpl b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.json.tpl
new file mode 100644
index 0000000000..97b5259a18
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.json.tpl
@@ -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"
+ }
+ }
+} \ No newline at end of file
diff --git a/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.xml.tpl b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.xml.tpl
new file mode 100644
index 0000000000..9181abd387
--- /dev/null
+++ b/nova/tests/integrated/api_samples/os-security-group-default-rules/security-group-default-rules-show-resp.xml.tpl
@@ -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> \ No newline at end of file
diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py
index ae34765d9f..6344ae45aa 100644
--- a/nova/tests/integrated/test_api_samples.py
+++ b/nova/tests/integrated/test_api_samples.py
@@ -1127,7 +1127,39 @@ class SecurityGroupsSampleJsonTest(ServersSampleBase):
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'