Commit 883d6de6 by Őry Máté

Merge branch 'master' into acl

Conflicts:
	circle/circle/settings/base.py
parents e1b8a82b 97b69b04
"""Common settings and globals."""
from datetime import timedelta
from os import environ
from os.path import abspath, basename, dirname, join, normpath
from json import loads
# from socket import SOCK_STREAM
from sys import path
# Normally you should not import ANYTHING from Django directly
# into your settings, but ImproperlyConfigured is an exception.
from django.core.exceptions import ImproperlyConfigured
......@@ -311,3 +312,11 @@ AUTHENTICATION_BACKENDS = (
'guardian.backends.ObjectPermissionBackend',
)
ANONYMOUS_USER_ID = -1
# Set up periodic firewall tasks
CELERYBEAT_SCHEDULE = {
'blabla': {
'task': 'firewall.tasks.local_tasks.periodic_task',
'schedule': timedelta(seconds=5),
},
}
from django_tables2 import Table, A
from django_tables2.columns import Column, LinkColumn, TemplateColumn
from django_tables2.columns import LinkColumn, TemplateColumn
from vm.models import Instance
from django.utils.translation import ugettext_lazy as _
class VmListTable(Table):
name = LinkColumn('dashboard.views.detail', args=[A('pk')])
admin = TemplateColumn(template_name='dashboard/vm-list/column-admin.html')
details = TemplateColumn(template_name=
'dashboard/vm-list/column-details.html')
actions = TemplateColumn(template_name=
'dashboard/vm-list/column-actions.html')
pk = TemplateColumn(
template_name='dashboard/vm-list/column-id.html',
verbose_name="ID",
attrs={'th': {'class': 'vm-list-table-thin'}},
)
name = LinkColumn(
'dashboard.views.detail',
args=[A('pk')],
attrs={'class': 'real-link'}
)
admin = TemplateColumn(
template_name='dashboard/vm-list/column-admin.html',
attrs={'th': {'class': 'vm-list-table-admin'}},
)
details = TemplateColumn(
template_name='dashboard/vm-list/column-details.html',
attrs={'th': {'class': 'vm-list-table-thin'}},
)
actions = TemplateColumn(
template_name='dashboard/vm-list/column-actions.html',
attrs={'th': {'class': 'vm-list-table-thin'}},
)
time_of_suspend = TemplateColumn(
'{{ record.time_of_suspend|timesince }}',
'{{ record.time_of_suspend|timeuntil }}',
verbose_name=_("Suspend in"))
time_of_delete = Column(verbose_name=_("Delete in"))
time_of_delete = TemplateColumn(
'{{ record.time_of_delete|timeuntil }}',
verbose_name=_("Delete in"))
class Meta:
model = Instance
......
......@@ -3,7 +3,8 @@
<label for="cpu-priority-slider"><i class="icon-trophy"></i> CPU priority</label>
</div>
<div class="col-sm-9">
<input type="text" data-slider="true" data-slider-highlight="true" data-slider-snap="true" id="cpu-priority-slider" value="0.25">
<input type="text" data-slider="true" data-slider-highlight="true"
data-slider-snap="true" data-slider-range="0,100" data-slider-step="1" id="cpu-priority-slider" value="{{ instance.priority }}">
</div>
</p>
......@@ -13,7 +14,7 @@
<label for="cpu-count-slider"><i class="icon-cogs"></i> CPU count</label>
</div>
<div class="col-sm-9">
<input type="text" value="1" data-slider="true" data-slider-highlight="true" data-slider-range="0,8" data-slider-snap="true" data-slider-step="1" id="cpu-count-slider">
<input type="text" value="{{ instance.num_cores }}" data-slider="true" data-slider-highlight="true" data-slider-range="0,8" data-slider-snap="true" data-slider-step="1" id="cpu-count-slider">
</div>
</p>
......@@ -23,7 +24,7 @@
<label for="ram-slider"><i class="icon-ticket"></i> RAM amount</label>
</div>
<div class="col-sm-9">
<input type="text" data-slider="true" data-slider-highlight="true" id="ram-slider" data-slider-range="128,4096" data-slider-snap="true" data-slider-step="128"> MiB
<input type="text" data-slider="true" data-slider-highlight="true" id="ram-slider" data-slider-range="128,4096" data-slider-snap="true" data-slider-step="128" value="{{ instance.ram_size }}"> MiB
</div>
</p>
......@@ -9,7 +9,7 @@
<div class="row">
<div class="col-md-4" id="vm-info-pane">
<div class="big">
<span class="label label-success ">RUNNING</span>
<span class="label label-success">{{ instance.state }}</span>
<div class="btn-group">
<button type="button" class="btn btn-warning dropdown-toggle" data-toggle="dropdown">Action <i class="icon-caret-down"></i></button>
<ul class="dropdown-menu" role="menu">
......
......@@ -4,7 +4,11 @@
{% block content %}
<div class="alert alert-info">
Tip of the day: you can select multiple vm instances while holding down the <strong>CTRL</strong> button!
Tip #1: you can select multiple vm instances while holding down the <strong>CTRL</strong> key!
</div>
<div class="alert alert-info">
Tip #2: if you want to select multiple instances by one click select an instance then hold down <strong>SHIFT</strong> key and select another one!
</div>
<div class="row">
......@@ -13,6 +17,16 @@
<div class="panel-heading">
<h3 class="no-margin"><i class="icon-desktop"></i> Your virtual machines</h3>
</div>
<div class="panel-body vm-list-group-control">
<p>
<strong>Group actions</strong>
<button class="btn btn-info btn-xs" disabled>Select all</button>
<a class="btn btn-default btn-xs" id="vm-list-group-migrate" disabled><i class="icon-truck"></i> Migrate</a>
<a disabled href="#" class="btn btn-default btn-xs"><i class="icon-refresh"></i> Reboot</a>
<a disabled href="#" class="btn btn-default btn-xs"><i class="icon-off"></i> Shutdown</a>
<a disabled href="#" class="btn btn-danger btn-xs"><i class="icon-remove"></i> Discard</a>
</p>
</div>
<div class="panel-body">
<table class="table table-bordered table-striped table-hover vm-list-table">
<thead>
......@@ -71,27 +85,79 @@
.vm-list-selected td:first-child {
font-weight: bold;
}
.vm-list-table-thin {
width: 10px;
}
.vm-list-table-admin {
width: 130px;
}
</style>
{% endblock %}
{% block extra_js %}
$(function() {
var ctrlDown = false;
var ctrlDown, shiftDown = false;
var ctrlKey = 17;
var shiftKey = 16;
var selected = [];
$(document).keydown(function(e) {
if (e.keyCode == ctrlKey) ctrlDown = true;
if (e.keyCode == shiftKey) shiftDown = true;
}).keyup(function(e) {
if (e.keyCode == ctrlKey) ctrlDown = false;
if (e.keyCode == shiftKey) shiftDown = false;
});
$('.vm-list-table').find('tr').click(function() {
$('.vm-list-table tbody').find('tr').mousedown(function() {
if (ctrlDown) {
setRowColor($(this));
if(!$(this).hasClass('vm-list-selected')) {
selected.splice(selected.indexOf($(this).index()), 1);
} else {
selected.push($(this).index());
}
} else if(shiftDown) {
if(selected.length > 0) {
start = selected[selected.length - 1] + 1;
end = $(this).index();
if(start > end) {
var tmp = start - 1; start = end; end = tmp - 1;
}
for(var i = start; i <= end; i++) {
if(selected.indexOf(i) < 0) {
selected.push(i);
setRowColor($('.vm-list-table tbody tr').eq(i));
}
}
}
} else {
$('.vm-list-selected').removeClass('vm-list-selected');
$(this).addClass('vm-list-selected');
selected = [$(this).index()];
}
// reset btn disables
$('.vm-list-table tbody tr .btn').attr('disabled', false);
// show/hide group controls
if(selected.length > 1) {
$('.vm-list-group-control .btn').attr('disabled', false);
for(var i = 0; i < selected.length; i++) {
$('.vm-list-table tbody tr').eq(selected[i]).find('.btn').attr('disabled', true);
}
} else {
$('.vm-list-group-control .btn').attr('disabled', true);
}
return false;
});
$('#vm-list-group-migrate').click(function() {
console.log(collectIds(selected));
});
$('.vm-list-details').popover({
......@@ -106,25 +172,28 @@ $(function() {
'trigger': 'click'
});
/*
$('#check_all').click(function() {
var checked = $(this).prop('checked');
$('.vm-checkbox').each(function() {
// reverse
// $(this).prop('checked', !$(this).prop('checked'));
// set
$(this).prop('checked', checked);
setRowColor($(this))
})
});
$('tbody a').mousedown(function(e) {
// parent tr doesn't get selected when clicked
e.stopPropagation();
});
$('.vm-checkbox').click(function() {
setRowColor($(this));
$('tbody a').click(function(e) {
// browser doesn't jump to top when clicked the buttons
if(!$(this).hasClass('real-link')) {
return false;
}
});
*/
});
function collectIds(rows) {
var ids = [];
for(var i = 0; i < rows.length; i++) {
var div = $('td:first-child div', $('.vm-list-table tbody tr').eq(rows[i]));
ids.push(div.prop('id').replace('vm-', ''));
}
return ids;
}
function setRowColor(row) {
if(!row.hasClass('vm-list-selected')) {
......
sziahello
<div class="btn-group">
<button type="button" class="btn btn-xs btn-warning dropdown-toggle" data-toggle="dropdown">Action <i class="icon-caret-down"></i></button>
<ul class="dropdown-menu" role="menu">
<li><a href="#"><i class="icon-refresh"></i> Reboot</a></li>
<li><a href="#"><i class="icon-off"></i> Shutdown</a></li>
<li><a href="#"><i class="icon-remove"></i> Discard</a></li>
</ul>
</div>
admin
<a class="btn btn-default btn-xs" title data-original-title="Migrate">
<i class="icon-truck"></i>
</a>
<a class="btn btn-default btn-xs" title data-original-title="Rename">
<i class="icon-pencil"></i>
</a>
<a href="#" class="btn btn-default btn-xs vm-list-connect" data-toggle="popover"
data-content='
Belépés: <input style="width: 300px;" type="text" class="form-control" value="ssh cloud@vm.ik.bme.hu -p22312"/>
Jelszó: <input style="width: 300px;" type="text" class="form-control" value="asdfkicsiasdfkocsi"/>
'>Connect</a>
detail
<a class="btn btn-info btn-xs vm-list-details" href="#" data-toggle="popover"
data-content='
<h4>Quick details</h4>
<dl class="dl-horizontal">
<dt>Number of cores:</dt><dd>{{ record.num_cores }}</dd>
<dt>Memory:</dt> <dd>{{ record.ram_size }} Mebibytes</dd>
<dt>Architecture:</td><dd>{{ record.arch }}</dd>
</dl>
<dl>
<dt>IPv4 address:</dt><dd>{{ record.ipv4 }}10.9.8.7</dd>
<dt>IPv6 address:</dt><dd> 2001:2001:2001:2001:2001:2001::</dd>
<dt>DNS name:</dt><dd>1825.vm.ik.bme.hu</dd>
</ul>
'>Details</a>
<div id="vm-{{ record.pk }}">{{ record.pk }}</div>
<tr>
<!--<td><input type="checkbox"/ class="vm-checkbox" id="vm-1825{{ c }}"></td>-->
<td>182{{ c }}</td>
<td><a href="">network-devenv</a></td>
<td>
<div id="vm-1{{ c }}">1{{ c }}</div>
</td>
<td><a href="" class="real-link">network-devenv</a></td>
<td>running</td>
<td>10 days</td>
<td>1 month</td>
<td>
<span class="btn btn-default btn-xs" title data-original-title="Migrate">
<a class="btn btn-default btn-xs" title data-original-title="Migrate">
<i class="icon-truck"></i>
</span>
<span class="btn btn-default btn-xs" title data-original-title="Rename">
</a>
<a class="btn btn-default btn-xs" title data-original-title="Rename">
<i class="icon-pencil"></i>
</span>
</a>
<a href="#" class="btn btn-default btn-xs vm-list-connect" data-toggle="popover"
data-content='
Belépés: <input style="width: 300px;" type="text" class="form-control" value="ssh cloud@vm.ik.bme.hu -p22312"/>
......
......@@ -74,3 +74,4 @@ class VmList(SingleTableView):
template_name = "dashboard/vm-list.html"
model = Instance
table_class = VmListTable
table_pagination = False
......@@ -49,7 +49,7 @@ class RuleAdmin(admin.ModelAdmin):
list_display = ('r_type', 'color_desc', 'owner', 'extra', 'direction',
'accept', 'proto', 'sport', 'dport', 'nat',
'nat_dport', 'used_in')
list_filter = ('r_type', 'vlan', 'owner', 'direction', 'accept',
list_filter = ('vlan', 'owner', 'direction', 'accept',
'proto', 'nat')
def color_desc(self, instance):
......
......@@ -64,7 +64,7 @@ class IPNetworkField(models.Field):
description = _('IP Network object')
__metaclass__ = models.SubfieldBase
def __init__(self, version=4, *args, **kwargs):
def __init__(self, version=4, serialize=True, *args, **kwargs):
kwargs['max_length'] = 100
self.version = version
super(IPNetworkField, self).__init__(*args, **kwargs)
......@@ -98,7 +98,7 @@ class IPNetworkField(models.Field):
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_prep_value(value)
return str(self.get_prep_value(value))
def clean(self, value, model_instance):
value = super(IPNetworkField, self).clean(value, model_instance)
......
from firewall import models
import django.conf
import subprocess
import re
from datetime import datetime, timedelta
from django.db.models import Q
......@@ -12,14 +10,6 @@ settings = django.conf.settings.FIREWALL_SETTINGS
class Firewall:
IPV6 = False
RULES = None
RULES_NAT = []
vlans = None
pub = None
hosts = None
fw = None
def dportsport(self, rule, repl=True):
retval = ' '
if rule.proto == 'tcp' or rule.proto == 'udp':
......@@ -46,7 +36,7 @@ class Firewall:
if not rule.foreign_network:
return
if self.IPV6 and host.ipv6:
if self.proto == 6 and host.ipv6:
ipaddr = host.ipv6 + '/112'
else:
ipaddr = host.ipv4
......@@ -156,10 +146,6 @@ class Firewall:
'-j ACCEPT')
def postrun(self):
self.iptables('-A PUB_OUT -s 152.66.243.160/27 -p tcp --dport 25 '
'-j LOG_ACC')
self.iptables('-A PUB_OUT -s 152.66.243.160/27 -p tcp --dport 445 '
'-j LOG_ACC')
self.iptables('-A PUB_OUT -p tcp --dport 25 -j LOG_DROP')
self.iptables('-A PUB_OUT -p tcp --dport 445 -j LOG_DROP')
self.iptables('-A PUB_OUT -p udp --dport 445 -j LOG_DROP')
......@@ -206,15 +192,6 @@ class Firewall:
(str(s_vlan.network4), d_vlan.interface,
s_vlan.snat_ip))
# hard-wired rules
self.iptablesnat('-A POSTROUTING -s 10.5.0.0/16 -o vlan0003 -j SNAT '
'--to-source 10.3.255.254') # man elerheto legyen
self.iptablesnat('-A POSTROUTING -o vlan0008 -j SNAT '
'--to-source 10.0.0.247') # wolf network for printing
self.iptablesnat('-A POSTROUTING -s 10.3.0.0/16 -p udp --dport 53 '
'-o vlan0002 -j SNAT ''--to-source %s' %
self.pub.ipv4) # kulonben nem megy a dns man-ban
self.iptablesnat('COMMIT')
def ipt_filter(self):
......@@ -258,45 +235,29 @@ class Firewall:
# post-run stuff
self.postrun()
if self.IPV6:
if self.proto == 6:
self.RULES = [x for x in self.RULES if not ipv4_re.search(x)]
self.RULES = [x.replace('icmp', 'icmpv6') for x in self.RULES]
def __init__(self, IPV6=False):
def __init__(self, proto=4):
self.RULES = []
self.RULES_NAT = []
self.IPV6 = IPV6
self.proto = proto
self.vlans = models.Vlan.objects.all()
self.hosts = models.Host.objects.all()
self.pub = models.Vlan.objects.get(name='PUB')
self.fw = models.Firewall.objects.all()
self.ipt_filter()
if not self.IPV6:
if self.proto != 6:
self.ipt_nat()
def reload(self):
if self.IPV6:
process = subprocess.Popen(['/usr/bin/ssh', 'fw2',
'/usr/bin/sudo',
'/sbin/ip6tables-restore', '-c'],
shell=False, stdin=subprocess.PIPE)
process.communicate('\n'.join(self.RULES) + '\n')
else:
process = subprocess.Popen(['/usr/bin/ssh', 'fw2',
'/usr/bin/sudo',
'/sbin/iptables-restore', '-c'],
shell=False, stdin=subprocess.PIPE)
process.communicate('\n'.join(self.RULES) + '\n' +
'\n'.join(self.RULES_NAT) + '\n')
def get(self):
if self.IPV6:
if self.proto == 6:
return {'filter': self.RULES, }
else:
return {'filter': self.RULES, 'nat': self.RULES_NAT}
def show(self):
if self.IPV6:
if self.proto == 6:
return '\n'.join(self.RULES) + '\n'
else:
return ('\n'.join(self.RULES) + '\n' +
......@@ -413,11 +374,6 @@ def dns():
DNS.append("^%s:%s:%s" % (d['name'], d['address'], d['ttl']))
return DNS
process = subprocess.Popen(['/usr/bin/ssh', 'tinydns@%s' %
settings['dns_hostname']],
shell=False, stdin=subprocess.PIPE)
process.communicate("\n".join(DNS) + "\n")
# print "\n".join(DNS)+"\n"
def prefix_to_mask(prefix):
......@@ -480,9 +436,11 @@ def dhcp():
})
return DHCP
process = subprocess.Popen(['/usr/bin/ssh', 'fw2',
'cat > /tools/dhcp3/dhcpd.conf.generated;'
'sudo /etc/init.d/isc-dhcp-server restart'],
shell=False, stdin=subprocess.PIPE)
# print "\n".join(DHCP)+"\n"
process.communicate("\n".join(DHCP) + "\n")
def vlan():
obj = models.Vlan.objects.values('vid', 'name', 'network4', 'network6')
return {x['name']: {'tag': x['vid'],
'addresses': [str(x['network4']),
str(x['network6'])]}
for x in obj}
......@@ -12,6 +12,7 @@ import django.conf
from django.db.models.signals import post_save
import random
from firewall.tasks.local_tasks import reloadtask
settings = django.conf.settings.FIREWALL_SETTINGS
......@@ -62,10 +63,6 @@ class Rule(models.Model):
verbose_name=_("owner"),
help_text=_("The user responsible for "
"this rule."))
r_type = models.CharField(max_length=10, verbose_name=_("Rule type"),
choices=CHOICES_type,
help_text=_("The type of entity the rule "
"belongs to."))
nat = models.BooleanField(default=False, verbose_name=_("NAT"),
help_text=_("If network address translation "
"shoud be done."))
......@@ -129,6 +126,15 @@ class Rule(models.Model):
(("dport=%s " % self.dport) if self.dport else '')),
'desc': self.description}
@property
def r_type(self):
fields = [self.vlan, self.vlangroup, self.host, self.hostgroup,
self.firewall]
for field in fields:
if field is not None:
return field.__class__.__name__.lower()
return None
@models.permalink
def get_absolute_url(self):
return ('network.rule', None, {'pk': self.pk})
......@@ -137,7 +143,6 @@ class Rule(models.Model):
verbose_name = _("rule")
verbose_name_plural = _("rules")
ordering = (
'r_type',
'direction',
'proto',
'sport',
......@@ -278,6 +283,24 @@ class Vlan(models.Model):
def prefix6(self):
return self.network6.prefixlen
def get_new_address(self):
i = 0
hosts = Host.objects.filter(vlan=self)
used_v4 = hosts.values_list('ipv4', flat=True)
used_v6 = hosts.values_list('ipv6', flat=True)
for ipv4 in self.network4.iter_hosts():
i += 1
if i > 10000:
break
ipv4 = str(ipv4)
if ipv4 not in used_v4:
print ipv4
ipv6 = ipv4_2_ipv6(ipv4)
if ipv6 not in used_v6:
return {'ipv4': ipv4, 'ipv6': ipv6}
raise ValidationError(_("All IP addresses are already in use."))
class VlanGroup(models.Model):
"""
......@@ -495,11 +518,11 @@ class Host(models.Model):
if public < 1024:
raise ValidationError(_("Only ports above 1024 can be used."))
rule = Rule(direction='1', owner=self.owner, dport=public,
proto=proto, nat=True, accept=True, r_type="host",
proto=proto, nat=True, accept=True,
nat_dport=private, host=self, foreign_network=vg)
else:
rule = Rule(direction='1', owner=self.owner, dport=public,
proto=proto, nat=False, accept=True, r_type="host",
proto=proto, nat=False, accept=True,
host=self, foreign_network=vg)
rule.full_clean()
......@@ -778,7 +801,6 @@ class Blacklist(models.Model):
def send_task(sender, instance, created, **kwargs):
from firewall.tasks import reloadtask
reloadtask.apply_async(args=[sender.__name__])
......
import celery
from manager.mancelery import celery
from django.core.cache import cache
from firewall.fw import Firewall, dhcp, dns, ipset
import django.conf
settings = django.conf.settings.FIREWALL_SETTINGS
@celery.task
def reload_dns_task(data):
pass
@celery.task
def reload_firewall_task(data4, data6):
pass
@celery.task
def reload_dhcp_task(data):
pass
@celery.task
def reload_blacklist_task(data):
pass
@celery.task
def get_dhcp_clients_task(data):
pass
@celery.task
def periodic_task():
from firewall.fw import Firewall, dhcp, dns, ipset, vlan
import remote_tasks
if cache.get('dns_lock'):
cache.delete("dns_lock")
reload_dns_task.delay(dns())
remote_tasks.reload_dns.apply_async(args=[dns()],
queue='dns')
print "dns ujratoltese kesz"
if cache.get('dhcp_lock'):
cache.delete("dhcp_lock")
reload_dhcp_task.delay(dhcp())
remote_tasks.reload_dhcp.apply_async(args=[dhcp()],
queue='firewall')
print "dhcp ujratoltese kesz"
if cache.get('firewall_lock'):
cache.delete("firewall_lock")
ipv4 = Firewall().get()
ipv6 = Firewall(True).get()
reload_firewall_task.delay(ipv4, ipv6)
ipv4 = Firewall(proto=4).get()
ipv6 = Firewall(proto=6).get()
remote_tasks.reload_firewall.apply_async(args=[ipv4, ipv6],
queue='firewall')
print "firewall ujratoltese kesz"
if cache.get('firewall_vlan_lock'):
cache.delete("firewall_vlan_lock")
remote_tasks.reload_firewall_vlan.apply_async(args=[vlan()],
queue='firewall')
print "firewall_vlan ujratoltese kesz"
if cache.get('blacklist_lock'):
cache.delete("blacklist_lock")
reload_blacklist_task.delay(list(ipset()))
remote_tasks.reload_blacklist.apply_async(args=[list(ipset())],
queue='firewall')
print "blacklist ujratoltese kesz"
......@@ -70,4 +56,7 @@ def reloadtask(type='Host'):
if type == "Blacklist":
cache.add("blacklist_lock", "true", 30)
if type == "Vlan":
cache.add("firewall_vlan_lock", "true", 30)
print type
from manager.mancelery import celery
@celery.task(name='firewall.reload_dns')
def reload_dns(data):
pass
@celery.task(name='firewall.reload_firewall')
def reload_firewall(data4, data6):
pass
@celery.task(name='firewall.reload_firewall_vlan')
def reload_firewall_vlan(data):
pass
@celery.task(name='firewall.reload_dhcp')
def reload_dhcp(data):
pass
@celery.task(name='firewall.reload_blacklist')
def reload_blacklist(data):
pass
@celery.task(name='firewall.get_dhcp_clients')
def get_dhcp_clients(data):
pass
......@@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from .tasks import reloadtask
from .tasks.local_tasks import reloadtask
from .models import Blacklist, Host
......@@ -20,6 +20,7 @@ def reload_firewall(request):
html = (_("Dear %s, you've signed in as administrator!<br />"
"Reloading in 10 seconds...") % request.user.username)
reloadtask.delay()