Merge "Security Group Rule enhancements."
This commit is contained in:
commit
f2c4e80fce
@ -40,7 +40,6 @@ LOG = logging.getLogger(__name__)
|
|||||||
class CreateGroup(forms.SelfHandlingForm):
|
class CreateGroup(forms.SelfHandlingForm):
|
||||||
name = forms.CharField(validators=[validators.validate_slug])
|
name = forms.CharField(validators=[validators.validate_slug])
|
||||||
description = forms.CharField()
|
description = forms.CharField()
|
||||||
tenant_id = forms.CharField(widget=forms.HiddenInput())
|
|
||||||
|
|
||||||
def handle(self, request, data):
|
def handle(self, request, data):
|
||||||
try:
|
try:
|
||||||
@ -56,13 +55,13 @@ class CreateGroup(forms.SelfHandlingForm):
|
|||||||
|
|
||||||
|
|
||||||
class AddRule(forms.SelfHandlingForm):
|
class AddRule(forms.SelfHandlingForm):
|
||||||
ip_protocol = forms.ChoiceField(label=_('IP protocol'),
|
ip_protocol = forms.ChoiceField(label=_('IP Protocol'),
|
||||||
choices=[('tcp', 'tcp'),
|
choices=[('tcp', 'TCP'),
|
||||||
('udp', 'udp'),
|
('udp', 'UDP'),
|
||||||
('icmp', 'icmp')],
|
('icmp', 'ICMP')],
|
||||||
widget=forms.Select(attrs={'class':
|
widget=forms.Select(attrs={'class':
|
||||||
'switchable'}))
|
'switchable'}))
|
||||||
from_port = forms.IntegerField(label=_("From port"),
|
from_port = forms.IntegerField(label=_("From Port"),
|
||||||
help_text=_("TCP/UDP: Enter integer value "
|
help_text=_("TCP/UDP: Enter integer value "
|
||||||
"between 1 and 65535. ICMP: "
|
"between 1 and 65535. ICMP: "
|
||||||
"enter a value for ICMP type "
|
"enter a value for ICMP type "
|
||||||
@ -71,7 +70,7 @@ class AddRule(forms.SelfHandlingForm):
|
|||||||
attrs={'data': _('From port'),
|
attrs={'data': _('From port'),
|
||||||
'data-icmp': _('Type')}),
|
'data-icmp': _('Type')}),
|
||||||
validators=[validate_port_range])
|
validators=[validate_port_range])
|
||||||
to_port = forms.IntegerField(label=_("To port"),
|
to_port = forms.IntegerField(label=_("To Port"),
|
||||||
help_text=_("TCP/UDP: Enter integer value "
|
help_text=_("TCP/UDP: Enter integer value "
|
||||||
"between 1 and 65535. ICMP: "
|
"between 1 and 65535. ICMP: "
|
||||||
"enter a value for ICMP code "
|
"enter a value for ICMP code "
|
||||||
@ -82,13 +81,14 @@ class AddRule(forms.SelfHandlingForm):
|
|||||||
validators=[validate_port_range])
|
validators=[validate_port_range])
|
||||||
|
|
||||||
source_group = forms.ChoiceField(label=_('Source Group'), required=False)
|
source_group = forms.ChoiceField(label=_('Source Group'), required=False)
|
||||||
cidr = forms.CharField(label=_("CIDR"), required=False,
|
cidr = forms.CharField(label=_("CIDR"),
|
||||||
|
required=False,
|
||||||
|
initial="0.0.0.0/0",
|
||||||
help_text=_("Classless Inter-Domain Routing "
|
help_text=_("Classless Inter-Domain Routing "
|
||||||
"(i.e. 192.168.0.0/24"),
|
"(i.e. 192.168.0.0/24"),
|
||||||
validators=[validate_ipv4_cidr])
|
validators=[validate_ipv4_cidr])
|
||||||
|
|
||||||
security_group_id = forms.IntegerField(widget=forms.HiddenInput())
|
security_group_id = forms.IntegerField(widget=forms.HiddenInput())
|
||||||
tenant_id = forms.CharField(widget=forms.HiddenInput())
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(AddRule, self).__init__(*args, **kwargs)
|
super(AddRule, self).__init__(*args, **kwargs)
|
||||||
@ -120,11 +120,16 @@ class AddRule(forms.SelfHandlingForm):
|
|||||||
'the "from" port number.')
|
'the "from" port number.')
|
||||||
raise ValidationError(msg)
|
raise ValidationError(msg)
|
||||||
|
|
||||||
if cidr and source_group:
|
if source_group and cidr != self.fields['cidr'].initial:
|
||||||
msg = _('Only either "CIDR" or "Source Group" may be specified')
|
# Specifying a source group *and* a custom CIDR is invalid.
|
||||||
|
msg = _('Either CIDR or Source Group may be specified, '
|
||||||
|
'but not both.')
|
||||||
raise ValidationError(msg)
|
raise ValidationError(msg)
|
||||||
if cidr:
|
elif source_group:
|
||||||
# if only cidr is specified, make sure source_group is cleaned
|
# If a source group is specified, clear the CIDR from its default
|
||||||
|
cleaned_data['cidr'] = None
|
||||||
|
else:
|
||||||
|
# If only cidr is specified, clear the source_group entirely
|
||||||
cleaned_data['source_group'] = None
|
cleaned_data['source_group'] = None
|
||||||
|
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
@ -59,7 +59,6 @@ class SecurityGroupsViewTests(test.TestCase):
|
|||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
formData = {'method': 'CreateGroup',
|
formData = {'method': 'CreateGroup',
|
||||||
'tenant_id': self.tenant.id,
|
|
||||||
'name': sec_group.name,
|
'name': sec_group.name,
|
||||||
'description': sec_group.description}
|
'description': sec_group.description}
|
||||||
res = self.client.post(SG_CREATE_URL, formData)
|
res = self.client.post(SG_CREATE_URL, formData)
|
||||||
@ -75,7 +74,6 @@ class SecurityGroupsViewTests(test.TestCase):
|
|||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
formData = {'method': 'CreateGroup',
|
formData = {'method': 'CreateGroup',
|
||||||
'tenant_id': self.tenant.id,
|
|
||||||
'name': sec_group.name,
|
'name': sec_group.name,
|
||||||
'description': sec_group.description}
|
'description': sec_group.description}
|
||||||
res = self.client.post(SG_CREATE_URL, formData)
|
res = self.client.post(SG_CREATE_URL, formData)
|
||||||
@ -137,7 +135,6 @@ class SecurityGroupsViewTests(test.TestCase):
|
|||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
formData = {'method': 'AddRule',
|
formData = {'method': 'AddRule',
|
||||||
'tenant_id': self.tenant.id,
|
|
||||||
'security_group_id': sec_group.id,
|
'security_group_id': sec_group.id,
|
||||||
'from_port': rule.from_port,
|
'from_port': rule.from_port,
|
||||||
'to_port': rule.to_port,
|
'to_port': rule.to_port,
|
||||||
@ -147,6 +144,32 @@ class SecurityGroupsViewTests(test.TestCase):
|
|||||||
res = self.client.post(self.edit_url, formData)
|
res = self.client.post(self.edit_url, formData)
|
||||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||||
|
|
||||||
|
def test_edit_rules_add_rule_cidr_and_source_group(self):
|
||||||
|
sec_group = self.security_groups.first()
|
||||||
|
sec_group_other = self.security_groups.get(id=2)
|
||||||
|
sec_group_list = self.security_groups.list()
|
||||||
|
rule = self.security_group_rules.first()
|
||||||
|
|
||||||
|
self.mox.StubOutWithMock(api, 'security_group_get')
|
||||||
|
self.mox.StubOutWithMock(api, 'security_group_list')
|
||||||
|
api.security_group_get(IsA(http.HttpRequest),
|
||||||
|
sec_group.id).AndReturn(sec_group)
|
||||||
|
api.security_group_list(
|
||||||
|
IsA(http.HttpRequest)).AndReturn(sec_group_list)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
formData = {'method': 'AddRule',
|
||||||
|
'security_group_id': sec_group.id,
|
||||||
|
'from_port': rule.from_port,
|
||||||
|
'to_port': rule.to_port,
|
||||||
|
'ip_protocol': rule.ip_protocol,
|
||||||
|
'cidr': "127.0.0.1/32",
|
||||||
|
'source_group': sec_group_other.id}
|
||||||
|
res = self.client.post(self.edit_url, formData)
|
||||||
|
self.assertNoMessages()
|
||||||
|
msg = 'Either CIDR or Source Group may be specified, but not both.'
|
||||||
|
self.assertFormErrors(res, count=1, message=msg)
|
||||||
|
|
||||||
def test_edit_rules_invalid_port_range(self):
|
def test_edit_rules_invalid_port_range(self):
|
||||||
sec_group = self.security_groups.first()
|
sec_group = self.security_groups.first()
|
||||||
sec_group_list = self.security_groups.list()
|
sec_group_list = self.security_groups.list()
|
||||||
@ -161,7 +184,6 @@ class SecurityGroupsViewTests(test.TestCase):
|
|||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
formData = {'method': 'AddRule',
|
formData = {'method': 'AddRule',
|
||||||
'tenant_id': self.tenant.id,
|
|
||||||
'security_group_id': sec_group.id,
|
'security_group_id': sec_group.id,
|
||||||
'from_port': rule.from_port,
|
'from_port': rule.from_port,
|
||||||
'to_port': int(rule.from_port) - 1,
|
'to_port': int(rule.from_port) - 1,
|
||||||
@ -192,7 +214,6 @@ class SecurityGroupsViewTests(test.TestCase):
|
|||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
formData = {'method': 'AddRule',
|
formData = {'method': 'AddRule',
|
||||||
'tenant_id': self.tenant.id,
|
|
||||||
'security_group_id': sec_group.id,
|
'security_group_id': sec_group.id,
|
||||||
'from_port': rule.from_port,
|
'from_port': rule.from_port,
|
||||||
'to_port': rule.to_port,
|
'to_port': rule.to_port,
|
||||||
|
@ -56,12 +56,16 @@ class EditRulesView(tables.DataTableView):
|
|||||||
return rules
|
return rules
|
||||||
|
|
||||||
def handle_form(self):
|
def handle_form(self):
|
||||||
tenant_id = self.request.user.tenant_id
|
try:
|
||||||
security_groups = [(group.id, group.name)
|
groups = api.security_group_list(self.request)
|
||||||
for group in api.security_group_list(self.request)]
|
except:
|
||||||
|
groups = []
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_("Unable to retrieve security groups."))
|
||||||
|
|
||||||
initial = {'tenant_id': tenant_id,
|
security_groups = [(group.id, group.name) for group in groups]
|
||||||
'security_group_id': self.kwargs['security_group_id'],
|
|
||||||
|
initial = {'security_group_id': self.kwargs['security_group_id'],
|
||||||
'security_group_list': security_groups}
|
'security_group_list': security_groups}
|
||||||
return AddRule.maybe_handle(self.request, initial=initial)
|
return AddRule.maybe_handle(self.request, initial=initial)
|
||||||
|
|
||||||
|
@ -84,10 +84,8 @@ class SelfHandlingForm(forms.Form):
|
|||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
return form, None
|
return form, None
|
||||||
|
|
||||||
data = form.clean()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return form, form.handle(request, data)
|
return form, form.handle(request, form.cleaned_data)
|
||||||
except:
|
except:
|
||||||
exceptions.handle(request)
|
exceptions.handle(request)
|
||||||
return form, None
|
return form, None
|
||||||
|
@ -199,7 +199,8 @@ class TestCase(django_test.TestCase):
|
|||||||
assert len(errors) == 0, \
|
assert len(errors) == 0, \
|
||||||
"Unexpected errors were found on the form: %s" % errors
|
"Unexpected errors were found on the form: %s" % errors
|
||||||
|
|
||||||
def assertFormErrors(self, response, count=0, context_name="form"):
|
def assertFormErrors(self, response, count=0, message=None,
|
||||||
|
context_name="form"):
|
||||||
"""
|
"""
|
||||||
Asserts that the response does contain a form in it's
|
Asserts that the response does contain a form in it's
|
||||||
context, and that form has errors, if count were given,
|
context, and that form has errors, if count were given,
|
||||||
@ -213,6 +214,10 @@ class TestCase(django_test.TestCase):
|
|||||||
assert len(errors) == count, \
|
assert len(errors) == count, \
|
||||||
"%d errors were found on the form, %d expected" % \
|
"%d errors were found on the form, %d expected" % \
|
||||||
(len(errors), count)
|
(len(errors), count)
|
||||||
|
if message and message not in unicode(errors):
|
||||||
|
self.fail("Expected message not found, instead found: %s"
|
||||||
|
% ["%s: %s" % (key, [e for e in field_errors]) for
|
||||||
|
(key, field_errors) in errors.items()])
|
||||||
else:
|
else:
|
||||||
assert len(errors) > 0, "No errors were found on the form"
|
assert len(errors) > 0, "No errors were found on the form"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user