Skip to content

Commit

Permalink
Add update method of security group name and description
Browse files Browse the repository at this point in the history
make it possible to edit the name and description of
common security groups, we can not rename the default.

Fixes: bug #918393

Change-Id: I62ec1edc310fd5b3ffc2ad232e64c7090c1d38e4
  • Loading branch information
niuzhenguo committed Aug 28, 2013
1 parent 48e60c0 commit e6606c1
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 2 deletions.
4 changes: 4 additions & 0 deletions openstack_dashboard/api/network.py
Expand Up @@ -103,6 +103,10 @@ def security_group_delete(request, sg_id):
return NetworkClient(request).secgroups.delete(sg_id)


def security_group_update(request, sg_id, name, desc):
return NetworkClient(request).secgroups.update(sg_id, name, desc)


def security_group_rule_create(request, parent_group_id,
direction, ethertype,
ip_protocol, from_port, to_port,
Expand Down
6 changes: 6 additions & 0 deletions openstack_dashboard/api/neutron.py
Expand Up @@ -213,6 +213,12 @@ def create(self, name, desc):
secgroup = self.client.create_security_group(body)
return SecurityGroup(secgroup.get('security_group'))

def update(self, sg_id, name, desc):
body = {'security_group': {'name': name,
'description': desc}}
secgroup = self.client.update_security_group(sg_id, body)
return SecurityGroup(secgroup.get('security_group'))

def delete(self, sg_id):
self.client.delete_security_group(sg_id)

Expand Down
4 changes: 4 additions & 0 deletions openstack_dashboard/api/nova.py
Expand Up @@ -199,6 +199,10 @@ def get(self, sg_id):
def create(self, name, desc):
return SecurityGroup(self.client.security_groups.create(name, desc))

def update(self, sg_id, name, desc):
return SecurityGroup(self.client.security_groups.update(sg_id,
name, desc))

def delete(self, security_group_id):
self.client.security_groups.delete(security_group_id)

Expand Down
Expand Up @@ -66,6 +66,33 @@ def handle(self, request, data):
redirect=redirect)


class UpdateGroup(forms.SelfHandlingForm):
id = forms.CharField(widget=forms.HiddenInput())
name = forms.CharField(label=_("Name"),
error_messages={
'required': _('This field is required.'),
'invalid': _("The string may only contain"
" ASCII characters and numbers.")},
validators=[validators.validate_slug])
description = forms.CharField(label=_("Description"))

def handle(self, request, data):
try:
sg = api.network.security_group_update(request,
data['id'],
data['name'],
data['description'])
messages.success(request,
_('Successfully updated security group: %s')
% data['name'])
return sg
except Exception:
redirect = reverse("horizon:project:access_and_security:index")
exceptions.handle(request,
_('Unable to update security group.'),
redirect=redirect)


class AddRule(forms.SelfHandlingForm):
id = forms.CharField(widget=forms.HiddenInput())
rule_menu = forms.ChoiceField(label=_('Rule'),
Expand Down
Expand Up @@ -49,6 +49,18 @@ class CreateGroup(tables.LinkAction):
classes = ("ajax-modal", "btn-create")


class EditGroup(tables.LinkAction):
name = "edit"
verbose_name = _("Edit Security Group")
url = "horizon:project:access_and_security:security_groups:update"
classes = ("ajax-modal", "btn-edit")

def allowed(self, request, security_group=None):
if not security_group:
return True
return security_group.name != 'default'


class EditRules(tables.LinkAction):
name = "edit_rules"
verbose_name = _("Edit Rules")
Expand All @@ -67,7 +79,7 @@ class Meta:
name = "security_groups"
verbose_name = _("Security Groups")
table_actions = (CreateGroup, DeleteGroup)
row_actions = (EditRules, DeleteGroup)
row_actions = (EditRules, EditGroup, DeleteGroup)


class CreateRule(tables.LinkAction):
Expand Down
Expand Up @@ -55,6 +55,45 @@ def setUp(self):
'security_groups:add_rule',
args=[sec_group.id])

@test.create_stubs({api.network: ('security_group_get',)})
def test_update_security_groups_get(self):
sec_group = self.security_groups.first()
api.network.security_group_get(IsA(http.HttpRequest),
sec_group.id).AndReturn(sec_group)
self.mox.ReplayAll()

res = self.client.get(reverse('horizon:project:access_and_security:'
'security_groups:update',
args=[sec_group.id]))
self.assertTemplateUsed(res,
'project/access_and_security/security_groups/_update.html')
self.assertEqual(res.context['security_group'].name,
sec_group.name)

@test.create_stubs({api.network: ('security_group_update',
'security_group_get')})
def test_update_security_groups_post(self):
sec_group = self.security_groups.get(name="other_group")
api.network.security_group_update(IsA(http.HttpRequest),
str(sec_group.id),
sec_group.name,
sec_group.description) \
.AndReturn(sec_group)
api.network.security_group_get(IsA(http.HttpRequest),
sec_group.id).AndReturn(sec_group)
self.mox.ReplayAll()

formData = {'method': 'UpdateGroup',
'id': sec_group.id,
'name': sec_group.name,
'description': sec_group.description}

update_url = reverse('horizon:project:access_and_security:'
'security_groups:update',
args=[sec_group.id])
res = self.client.post(update_url, formData)
self.assertRedirectsNoFollow(res, INDEX_URL)

def test_create_security_groups_get(self):
res = self.client.get(SG_CREATE_URL)
self.assertTemplateUsed(res,
Expand Down
Expand Up @@ -32,5 +32,8 @@
name='detail'),
url(r'^(?P<security_group_id>[^/]+)/add_rule/$',
views.AddRuleView.as_view(),
name='add_rule')
name='add_rule'),
url(r'^(?P<security_group_id>[^/]+)/update/$',
views.UpdateView.as_view(),
name='update')
)
Expand Up @@ -68,6 +68,35 @@ def get_context_data(self, **kwargs):
return context


class UpdateView(forms.ModalFormView):
form_class = project_forms.UpdateGroup
template_name = 'project/access_and_security/security_groups/update.html'
success_url = reverse_lazy('horizon:project:access_and_security:index')

def get_object(self):
if not hasattr(self, "_object"):
sg_id = filters.get_int_or_uuid(self.kwargs['security_group_id'])
try:
self._object = api.network.security_group_get(self.request,
sg_id)
except Exception:
msg = _('Unable to retrieve security group.')
url = reverse('horizon:project:access_and_security:index')
exceptions.handle(self.request, msg, redirect=url)
return self._object

def get_context_data(self, **kwargs):
context = super(UpdateView, self).get_context_data(**kwargs)
context["security_group"] = self.get_object()
return context

def get_initial(self):
security_group = self.get_object()
return {'id': self.kwargs['security_group_id'],
'name': security_group.name,
'description': security_group.description}


class AddRuleView(forms.ModalFormView):
form_class = project_forms.AddRule
template_name = 'project/access_and_security/security_groups/add_rule.html'
Expand Down
@@ -0,0 +1,26 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% load url from future %}

{% block form_id %}update_security_group_form{% endblock %}
{% block form_action %}{% url 'horizon:project:access_and_security:security_groups:update' security_group.id%}{% endblock %}

{% block modal-header %}{% trans "Edit Security Group" %}{% endblock %}
{% block modal_id %}update_security_group_modal{% endblock %}

{% block modal-body %}
<div class="left">
<fieldset>
{% include "horizon/common/_form_fields.html" %}
</fieldset>
</div>
<div class="right">
<h3>{% trans "Description" %}:</h3>
<p>{% trans "From here you can modify name and description of a security group." %}</p>
</div>
{% endblock %}

{% block modal-footer %}
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Edit Security Group" %}" />
<a href="{% url 'horizon:project:access_and_security:index' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a>
{% endblock %}
@@ -0,0 +1,11 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Edit Security Group" %}{% endblock %}

{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Edit Security Group") %}
{% endblock page_header %}

{% block main %}
{% include 'project/access_and_security/security_groups/_update.html' %}
{% endblock %}
17 changes: 17 additions & 0 deletions openstack_dashboard/test/api_tests/network_tests.py
Expand Up @@ -232,6 +232,23 @@ def test_security_group_create(self):
secgroup['description'])
self._cmp_sg(secgroup, ret)

def test_security_group_update(self):
secgroup = self.api_q_secgroups.list()[1]
secgroup = copy.deepcopy(secgroup)
secgroup['name'] = 'newname'
secgroup['description'] = 'new description'
body = {'security_group':
{'name': secgroup['name'],
'description': secgroup['description']}}
self.qclient.update_security_group(secgroup['id'], body) \
.AndReturn({'security_group': secgroup})
self.mox.ReplayAll()
ret = api.network.security_group_update(self.request,
secgroup['id'],
secgroup['name'],
secgroup['description'])
self._cmp_sg(secgroup, ret)

def test_security_group_delete(self):
secgroup = self.api_q_secgroups.first()
self.qclient.delete_security_group(secgroup['id'])
Expand Down

0 comments on commit e6606c1

Please sign in to comment.