Commit 5816bf02 by Bach Dániel

dashboard: add RemovePortOperation

parent 77d7975a
......@@ -40,7 +40,7 @@ from django.contrib.auth.forms import UserCreationForm as OrgUserCreationForm
from django.forms.widgets import TextInput, HiddenInput
from django.template import Context
from django.template.loader import render_to_string
from django.utils.html import escape
from django.utils.html import escape, format_html
from django.utils.translation import ugettext_lazy as _
from sizefield.widgets import FileSizeWidget
from django.core.urlresolvers import reverse_lazy
......@@ -935,6 +935,35 @@ class VmDeployForm(OperationForm):
"(blank allows scheduling automatically).")))
class VmPortRemoveForm(OperationForm):
def __init__(self, *args, **kwargs):
choices = kwargs.pop('choices')
self.rule = kwargs.pop('default')
super(VmPortRemoveForm, self).__init__(*args, **kwargs)
self.fields.insert(0, 'rule', forms.ModelChoiceField(
queryset=choices, initial=self.rule, required=True,
empty_label=None, label=_('Port')))
if self.rule:
self.fields['rule'].widget = HiddenInput()
@property
def helper(self):
helper = super(VmPortRemoveForm, self).helper
if self.rule:
helper.layout = Layout(
AnyTag(
"div",
HTML(format_html(_("<label>Port:</label> {0}/{1}"),
escape(self.rule.dport), escape(self.rule.proto))),
css_class="form-group",
),
Field("rule"),
)
return helper
class CircleAuthenticationForm(AuthenticationForm):
# fields: username, password
......
......@@ -78,7 +78,7 @@
{{ l.private }}/{{ l.proto }}
</td>
<td>
<a href="{% url "dashboard.views.remove-port" pk=instance.pk rule=l.ipv4.pk %}" class="btn btn-link btn-xs vm-details-remove-port" data-rule="{{ l.ipv4.pk }}" title="{% trans "Remove" %}"><i class="fa fa-times"><span class="sr-only">{% trans "Remove" %}</span></i></a>
<a href="{{ op.remove_port.get_url }}?rule={{ l.ipv4.pk }}" class="btn btn-link btn-xs vm-details-remove-port" data-rule="{{ l.ipv4.pk }}" title="{% trans "Remove" %}"><i class="fa fa-times"><span class="sr-only">{% trans "Remove" %}</span></i></a>
</td>
</tr>
{% endif %}
......@@ -110,7 +110,7 @@
{{ l.private }}/{{ l.proto }}
</td>
<td>
<a href="{% url "dashboard.views.remove-port" pk=instance.pk rule=l.ipv4.pk %}" class="btn btn-link btn-xs vm-details-remove-port" data-rule="{{ l.ipv6.pk }}" title="{% trans "Remove" %}"><i class="fa fa-times"><span class="sr-only">{% trans "Remove" %}</span></i></a>
<a href="{{ op.remove_port.get_url }}?rule={{ l.ipv4.pk }}" class="btn btn-link btn-xs vm-details-remove-port" data-rule="{{ l.ipv6.pk }}" title="{% trans "Remove" %}"><i class="fa fa-times"><span class="sr-only">{% trans "Remove" %}</span></i></a>
</td>
</tr>
{% endif %}
......
......@@ -62,6 +62,7 @@ from ..forms import (
VmRenewForm, VmStateChangeForm, VmListSearchForm, VmCustomizeForm,
TransferOwnershipForm, VmDiskResizeForm, RedeployForm, VmDiskRemoveForm,
VmMigrateForm, VmDeployForm,
VmPortRemoveForm,
)
from ..models import Favourite, Profile
......@@ -450,6 +451,33 @@ class VmMigrateView(FormOperationMixin, VmOperationView):
return val
class VmPortRemoveView(FormOperationMixin, VmOperationView):
op = 'remove_port'
show_in_toolbar = False
with_reload = True
icon = 'times'
effect = "danger"
form_class = VmPortRemoveForm
def get_form_kwargs(self):
instance = self.get_op().instance
choices = Rule.portforwards().filter(
host__interface__instance=instance)
rule_pk = self.request.GET.get('rule')
if rule_pk:
try:
default = choices.get(pk=rule_pk)
except (ValueError, Rule.DoesNotExist):
raise Http404()
else:
default = None
val = super(VmPortRemoveView, self).get_form_kwargs()
val.update({'choices': choices, 'default': default})
return val
class VmSaveView(FormOperationMixin, VmOperationView):
op = 'save_as_template'
......@@ -683,6 +711,7 @@ vm_ops = OrderedDict([
op='remove_disk', form_class=VmDiskRemoveForm,
icon='times', effect="danger")),
('add_interface', VmAddInterfaceView),
('remove_port', VmPortRemoveView),
('renew', VmRenewView),
('resources_change', VmResourcesChangeView),
('password_reset', VmOperationView.factory(
......
......@@ -243,6 +243,13 @@ class Rule(models.Model):
return retval
@classmethod
def portforwards(cls, host=None):
qs = cls.objects.filter(dport__isnull=False, direction='in')
if host is not None:
qs = qs.filter(host=host)
return qs
class Meta:
verbose_name = _("rule")
verbose_name_plural = _("rules")
......@@ -762,7 +769,7 @@ class Host(models.Model):
Return a list of ports with forwarding rules set.
"""
retval = []
for rule in self.rules.filter(dport__isnull=False, direction='in'):
for rule in Rule.portforwards(host=self):
forward = {
'proto': rule.proto,
'private': rule.dport,
......
......@@ -606,6 +606,25 @@ class RemoveInterfaceOperation(InstanceOperation):
@register_operation
class RemovePortOperation(InstanceOperation):
id = 'remove_port'
name = _("close port")
description = _("Close the specified port.")
concurrency_check = False
required_perms = ()
accept_states = ()
def _operation(self, activity, rule):
interface = rule.host.interface_set.get()
if interface.instance != self.instance:
raise PermissionDenied()
activity.readable_name = create_readable(
ugettext_noop("close %(proto)s/%(port)d on %(host)s"),
proto=rule.proto, port=rule.dport, host=rule.host)
rule.delete()
@register_operation
class RemoveDiskOperation(InstanceOperation):
id = 'remove_disk'
name = _("remove disk")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment