Commit 651a6105 by Kálmán Viktor

dashboard: open and close ports

parent d798a61b
...@@ -194,3 +194,17 @@ body { ...@@ -194,3 +194,17 @@ body {
border-radius: 3px; border-radius: 3px;
} }
/* --- */ /* --- */
.vm-details-remove-port:hover {
text-decoration: none;
}
/* arrow in port add table */
#ipv4 tbody td:nth-child(2), #ipv6 tbody td:nth-child(2) {
width: 60px;
}
/* port add buttons */
.vm-details-network-port-add .input-group-addon, .vm-details-network-port-add .input-group-btn {
width: inherit ;
}
...@@ -75,8 +75,39 @@ $(function() { ...@@ -75,8 +75,39 @@ $(function() {
}); });
return false; return false;
}); });
/* remove port */
$('.vm-details-remove-port').click(function() {
addModalConfirmation(removePort,
{
'url': $(this).prop("href"),
'data': [],
'rule': $(this).data("rule")
});
return false;
});
}); });
function removePort(data) {
$.ajax({
type: 'POST',
url: data['url'],
headers: {"X-CSRFToken": getCookie('csrftoken')},
success: function(re, textStatus, xhr) {
$("a[data-rule=" + data['rule'] + "]").each(function() {
$(this).closest("tr").fadeOut(500, function() {
$(this).remove();
});
});
addMessage(re['message'], "success");
},
error: function(xhr, textStatus, error) {
}
});
}
function checkNewActivity() { function checkNewActivity() {
var latest = $('.activity:first').data('activity-id'); var latest = $('.activity:first').data('activity-id');
var latest_sub = $('div[data-activity-id="' + latest + '"] .sub-timeline .sub-activity:first').data('activity-id'); var latest_sub = $('div[data-activity-id="' + latest + '"] .sub-timeline .sub-activity:first').data('activity-id');
......
...@@ -3,9 +3,13 @@ ...@@ -3,9 +3,13 @@
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-body"> <div class="modal-body">
{% if text %}
{{ text }}
{% else %}
{%blocktrans with object=object%} {%blocktrans with object=object%}
Are you sure you want to delete <strong>{{ object }}</strong>? Are you sure you want to delete <strong>{{ object }}</strong>?
{%endblocktrans%} {%endblocktrans%}
{% endif %}
<br /> <br />
<div class="pull-right" style="margin-top: 15px;"> <div class="pull-right" style="margin-top: 15px;">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
......
...@@ -6,13 +6,21 @@ ...@@ -6,13 +6,21 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="no-margin"> <h3 class="no-margin">
Delete confirmation {% if title %}
{{ title }}
{% else %}
Delete confirmation
{% endif %}
</h3> </h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
{%blocktrans with object=object%} {% if text %}
Are you sure you want to delete <strong>{{ object }}</strong>? {{ text }}
{%endblocktrans%} {% else %}
{%blocktrans with object=object%}
Are you sure you want to delete <strong>{{ object }}</strong>?
{%endblocktrans%}
{% endif %}
<div class="pull-right"> <div class="pull-right">
<form action="" method="POST"> <form action="" method="POST">
{% csrf_token %} {% csrf_token %}
......
<tfoot> {% load i18n %}
<tr> <div class="vm-details-network-port-add pull-right">
<td style="vertical-align: middle;"> <form action="" method="POST">
<i class="icon-plus"></i> <i class="icon-long-arrow-right"></i> {% csrf_token %}
</td> <input type="hidden" name="host_pk" value="{{ i.host.pk }}"/>
<td colspan="2"> <div class="input-group input-group-sm">
<div class="input-group input-group-sm"> <span class="input-group-addon">
<input type="text" class="form-control" size="5" /> <i class="icon-plus"></i> <i class="icon-long-arrow-right"></i>
<span class="input-group-addon">/</span> </span>
<select class="form-control"><option>tcp</option><option>udp</option></select> <input type="text" class="form-control" size="5" style="width: 80px;" name="port"/>
</div> <span class="input-group-addon">/</span>
</td> <select class="form-control" name="proto" style="width: 70px;"><option>tcp</option><option>udp</option></select>
<td> <div class="input-group-btn">
<button type="submit" class="btn btn-success btn-sm">Add</button> <button type="submit" class="btn btn-success btn-sm">{% trans "Add" %}</button>
</td> </div>
</tr> </div>
</tfoot> </form>
</div>
...@@ -44,31 +44,27 @@ Interfaces</h2> ...@@ -44,31 +44,27 @@ Interfaces</h2>
</th></tr> </th></tr>
</thead> </thead>
<tbody> <tbody>
<!-- inline td width shall be replaced -->
{% for l in i.host.list_ports %} {% for l in i.host.list_ports %}
{% if l.ipv4 %} {% if l.ipv4 %}
<tr> <tr>
<td> <td>
{{ l.ipv4.host }}:{{ l.ipv4.port }} {{ l.ipv4.host }}:{{ l.ipv4.port }}
</td> </td>
<td style="width: 61px;"><i class="icon-long-arrow-right"></i></td> <td><i class="icon-long-arrow-right"></i></td>
<td style="width: 111px;"> <td>
{{ l.private }}/{{ l.proto }} {{ l.private }}/{{ l.proto }}
</td> </td>
<td> <td>
<a href="#" class="btn btn-link btn-xs" title="{% trans "Remove" %}"><i class="icon-remove"><span class="sr-only">{% trans "Remove" %}</span></i></a> <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="icon-remove"><span class="sr-only">{% trans "Remove" %}</span></i></a>
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<tr><td>vm.ik.bme.hu:22620</td><td><i class="icon-long-arrow-right"></i></td><td><abbr title="ssh">22</abbr>/tcp</td><td><a href="#" class="btn btn-link btn-xs" title="remove"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a></td></tr>
<tr><td>vm.ik.bme.hu:22620</td><td><i class="icon-long-arrow-right"></i></td><td>12344/tcp</td><td><a href="#" class="btn btn-link btn-xs" title="remove"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a></td></tr>
<tr><td>vm.ik.bme.hu:22620</td><td><i class="icon-long-arrow-right"></i></td><td><abbr title="http-alt">8080</abbr>/tcp</td><td><a href="#" class="btn btn-link btn-xs" title="remove"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a></td></tr>
</tbody> </tbody>
{% include "dashboard/vm-detail-network-port-add.html" %}
</table> </table>
</div> <!-- /ipv4 --> </div> <!-- /ipv4 -->
<div class="tab-pane" id="ipv6"> <div class="tab-pane" id="ipv6">
{% if i.host.ipv6 %}
<table class="table table-striped rule-table"> <table class="table table-striped rule-table">
<thead> <thead>
<tr><th> <tr><th>
...@@ -80,30 +76,29 @@ Interfaces</h2> ...@@ -80,30 +76,29 @@ Interfaces</h2>
</th></tr> </th></tr>
</thead> </thead>
<tbody> <tbody>
<!-- inline td width TODO not do it -->
{% for l in i.host.list_ports %} {% for l in i.host.list_ports %}
{% if l.ipv6 %} {% if l.ipv6 %}
<tr> <tr>
<td> <td>
{{ l.ipv6.host }}:{{ l.ipv6.port }} {{ l.ipv6.host }}:{{ l.ipv6.port }}
</td> </td>
<td style="width: 61px;"><i class="icon-long-arrow-right"></i></td> <td><i class="icon-long-arrow-right"></i></td>
<td style="width: 111px;"> <td>
{{ l.private }}/{{ l.proto }} {{ l.private }}/{{ l.proto }}
</td> </td>
<td> <td>
<a href="#" class="btn btn-link btn-xs" title="{% trans "Remove" %}"><i class="icon-remove"><span class="sr-only">{% trans "Remove" %}</span></i></a> <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="icon-remove"><span class="sr-only">{% trans "Remove" %}</span></i></a>
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<tr><td>550.vm.ik.bme.hu:22</td><td><i class="icon-long-arrow-right"></i></td><td><abbr title="ssh">22</abbr>/tcp</td><td><a href="#" class="btn btn-link btn-xs" title="remove"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a></td></tr>
<tr><td>550.vm.ik.bme.hu:12344</td><td><i class="icon-long-arrow-right"></i></td><td>12344/tcp</td><td><a href="#" class="btn btn-link btn-xs" title="remove"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a></td></tr>
<tr><td>550.vm.ik.bme.hu:8080</td><td><i class="icon-long-arrow-right"></i></td><td><abbr title="http-alt">8080</abbr>/tcp</td><td><a href="#" class="btn btn-link btn-xs" title="remove"><i class="icon-remove"><span class="sr-only">{% trans "remove" %}</span></i></a></td></tr>
</tbody> </tbody>
{% include "dashboard/vm-detail-network-port-add.html" %}
</table> </table>
</div> {% else %}
<h4>{% trans "This VM doesn't have an IPv6 address!" %}</h4>
{% endif %}
</div><!-- /ipv6 -->
{% include "dashboard/vm-detail-network-port-add.html" %}
</div> </div>
</div> </div>
</div> </div>
......
...@@ -3,7 +3,7 @@ from django.conf.urls import patterns, url ...@@ -3,7 +3,7 @@ from django.conf.urls import patterns, url
from vm.models import Instance from vm.models import Instance
from .views import ( from .views import (
IndexView, VmDetailView, VmList, VmCreate, TemplateDetail, AclUpdateView, IndexView, VmDetailView, VmList, VmCreate, TemplateDetail, AclUpdateView,
VmDelete, VmMassDelete, vm_activity, NodeList, NodeDetailView, VmDelete, VmMassDelete, vm_activity, NodeList, NodeDetailView, PortDelete,
TransferOwnershipView, TransferOwnershipConfirmView TransferOwnershipView, TransferOwnershipConfirmView
) )
...@@ -12,6 +12,8 @@ urlpatterns = patterns( ...@@ -12,6 +12,8 @@ urlpatterns = patterns(
url(r'^$', IndexView.as_view(), name="dashboard.index"), url(r'^$', IndexView.as_view(), name="dashboard.index"),
url(r'^template/(?P<pk>\d+)/$', TemplateDetail.as_view(), url(r'^template/(?P<pk>\d+)/$', TemplateDetail.as_view(),
name='dashboard.views.template-detail'), name='dashboard.views.template-detail'),
url(r'^vm/(?P<pk>\d+)/remove_port/(?P<rule>\d+)/$', PortDelete.as_view(),
name='dashboard.views.remove-port'),
url(r'^vm/(?P<pk>\d+)/$', VmDetailView.as_view(), url(r'^vm/(?P<pk>\d+)/$', VmDetailView.as_view(),
name='dashboard.views.detail'), name='dashboard.views.detail'),
url(r'^vm/(?P<pk>\d+)/acl/$', AclUpdateView.as_view(model=Instance), url(r'^vm/(?P<pk>\d+)/acl/$', AclUpdateView.as_view(model=Instance),
......
...@@ -22,7 +22,7 @@ from braces.views import LoginRequiredMixin ...@@ -22,7 +22,7 @@ from braces.views import LoginRequiredMixin
from .tables import (VmListTable, NodeListTable) from .tables import (VmListTable, NodeListTable)
from vm.models import (Instance, InstanceTemplate, InterfaceTemplate, from vm.models import (Instance, InstanceTemplate, InterfaceTemplate,
InstanceActivity, Node, instance_activity) InstanceActivity, Node, instance_activity)
from firewall.models import Vlan from firewall.models import Vlan, Host, Rule
from storage.models import Disk from storage.models import Disk
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -120,6 +120,9 @@ class VmDetailView(CheckedDetailView): ...@@ -120,6 +120,9 @@ class VmDetailView(CheckedDetailView):
if request.POST.get("to_remove") is not None: if request.POST.get("to_remove") is not None:
return self.__remove_tag(request) return self.__remove_tag(request)
if request.POST.get("port") is not None:
return self.__add_port(request)
def __set_resources(self, request): def __set_resources(self, request):
self.object = self.get_object() self.object = self.get_object()
if not self.object.has_level(request.user, 'owner'): if not self.object.has_level(request.user, 'owner'):
...@@ -201,6 +204,31 @@ class VmDetailView(CheckedDetailView): ...@@ -201,6 +204,31 @@ class VmDetailView(CheckedDetailView):
content_type="application=json" content_type="application=json"
) )
def __add_port(self, request):
object = self.get_object()
if not object.has_level(request.user, 'owner'):
raise PermissionDenied()
port = request.POST.get("port")
proto = request.POST.get("proto")
try:
error = None
host = Host.objects.get(pk=request.POST.get("host_pk"))
host.add_port(proto, private=port)
except Host.DoesNotExist:
error = _("Host not found!")
except Exception, e:
error = u', '.join(e.messages)
if request.is_ajax():
pass
else:
if error:
messages.error(request, error)
return redirect(reverse_lazy("dashboard.views.detail",
kwargs={'pk': self.get_object().pk}))
class NodeDetailView(DetailView): class NodeDetailView(DetailView):
template_name = "dashboard/node-detail.html" template_name = "dashboard/node-detail.html"
...@@ -389,6 +417,7 @@ class VmDelete(DeleteView): ...@@ -389,6 +417,7 @@ class VmDelete(DeleteView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
# this is redundant now, but if we wanna add more to print # this is redundant now, but if we wanna add more to print
# we'll need this # we'll need this
print kwargs
context = super(VmDelete, self).get_context_data(**kwargs) context = super(VmDelete, self).get_context_data(**kwargs)
return context return context
...@@ -421,6 +450,52 @@ class VmDelete(DeleteView): ...@@ -421,6 +450,52 @@ class VmDelete(DeleteView):
return reverse_lazy('dashboard.index') return reverse_lazy('dashboard.index')
class PortDelete(DeleteView):
model = Rule
pk_url_kwarg = 'rule'
def get_template_names(self):
if self.request.is_ajax():
return ['dashboard/confirm/ajax-delete.html']
else:
return ['dashboard/confirm/base-delete.html']
def get_context_data(self, **kwargs):
context = super(PortDelete, self).get_context_data(**kwargs)
rule = kwargs.get('object')
instance = rule.host.interface_set.get().instance
context['title'] = _("Port delete confirmation")
context['text'] = _("Are you sure you want to close %(port)d/"
"%(proto)s on %(vm)s?" % {'port': rule.dport,
'proto': rule.proto,
'vm': instance})
return context
def delete(self, request, *args, **kwargs):
rule = Rule.objects.get(pk=kwargs.get("rule"))
instance = rule.host.interface_set.get().instance
if not instance.has_level(request.user, 'owner'):
raise PermissionDenied()
super(PortDelete, self).delete(request, *args, **kwargs)
success_url = self.get_success_url()
success_message = _("Port successfully removed!")
if request.is_ajax():
return HttpResponse(
json.dumps({'message': success_message}),
content_type="application/json",
)
else:
messages.success(request, success_message)
return HttpResponseRedirect("%s#network" % success_url)
def get_success_url(self):
return reverse_lazy('dashboard.views.detail',
kwargs={'pk': self.kwargs.get("pk")})
class VmMassDelete(View): class VmMassDelete(View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
vms = request.GET.getlist('v[]') vms = request.GET.getlist('v[]')
......
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