Commit 883d6de6 by Őry Máté

Merge branch 'master' into acl

Conflicts:
	circle/circle/settings/base.py
parents e1b8a82b 97b69b04
"""Common settings and globals.""" """Common settings and globals."""
from datetime import timedelta
from os import environ from os import environ
from os.path import abspath, basename, dirname, join, normpath from os.path import abspath, basename, dirname, join, normpath
from json import loads from json import loads
# from socket import SOCK_STREAM # from socket import SOCK_STREAM
from sys import path from sys import path
# Normally you should not import ANYTHING from Django directly # Normally you should not import ANYTHING from Django directly
# into your settings, but ImproperlyConfigured is an exception. # into your settings, but ImproperlyConfigured is an exception.
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
...@@ -311,3 +312,11 @@ AUTHENTICATION_BACKENDS = ( ...@@ -311,3 +312,11 @@ AUTHENTICATION_BACKENDS = (
'guardian.backends.ObjectPermissionBackend', 'guardian.backends.ObjectPermissionBackend',
) )
ANONYMOUS_USER_ID = -1 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 import Table, A
from django_tables2.columns import Column, LinkColumn, TemplateColumn from django_tables2.columns import LinkColumn, TemplateColumn
from vm.models import Instance from vm.models import Instance
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
class VmListTable(Table): class VmListTable(Table):
name = LinkColumn('dashboard.views.detail', args=[A('pk')]) pk = TemplateColumn(
admin = TemplateColumn(template_name='dashboard/vm-list/column-admin.html') template_name='dashboard/vm-list/column-id.html',
details = TemplateColumn(template_name= verbose_name="ID",
'dashboard/vm-list/column-details.html') attrs={'th': {'class': 'vm-list-table-thin'}},
actions = TemplateColumn(template_name= )
'dashboard/vm-list/column-actions.html') 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( time_of_suspend = TemplateColumn(
'{{ record.time_of_suspend|timesince }}', '{{ record.time_of_suspend|timeuntil }}',
verbose_name=_("Suspend in")) 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: class Meta:
model = Instance model = Instance
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
<label for="cpu-priority-slider"><i class="icon-trophy"></i> CPU priority</label> <label for="cpu-priority-slider"><i class="icon-trophy"></i> CPU priority</label>
</div> </div>
<div class="col-sm-9"> <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> </div>
</p> </p>
...@@ -13,7 +14,7 @@ ...@@ -13,7 +14,7 @@
<label for="cpu-count-slider"><i class="icon-cogs"></i> CPU count</label> <label for="cpu-count-slider"><i class="icon-cogs"></i> CPU count</label>
</div> </div>
<div class="col-sm-9"> <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> </div>
</p> </p>
...@@ -23,7 +24,7 @@ ...@@ -23,7 +24,7 @@
<label for="ram-slider"><i class="icon-ticket"></i> RAM amount</label> <label for="ram-slider"><i class="icon-ticket"></i> RAM amount</label>
</div> </div>
<div class="col-sm-9"> <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> </div>
</p> </p>
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<div class="row"> <div class="row">
<div class="col-md-4" id="vm-info-pane"> <div class="col-md-4" id="vm-info-pane">
<div class="big"> <div class="big">
<span class="label label-success ">RUNNING</span> <span class="label label-success">{{ instance.state }}</span>
<div class="btn-group"> <div class="btn-group">
<button type="button" class="btn btn-warning dropdown-toggle" data-toggle="dropdown">Action <i class="icon-caret-down"></i></button> <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"> <ul class="dropdown-menu" role="menu">
......
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
{% block content %} {% block content %}
<div class="alert alert-info"> <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>
<div class="row"> <div class="row">
...@@ -13,6 +17,16 @@ ...@@ -13,6 +17,16 @@
<div class="panel-heading"> <div class="panel-heading">
<h3 class="no-margin"><i class="icon-desktop"></i> Your virtual machines</h3> <h3 class="no-margin"><i class="icon-desktop"></i> Your virtual machines</h3>
</div> </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"> <div class="panel-body">
<table class="table table-bordered table-striped table-hover vm-list-table"> <table class="table table-bordered table-striped table-hover vm-list-table">
<thead> <thead>
...@@ -71,27 +85,79 @@ ...@@ -71,27 +85,79 @@
.vm-list-selected td:first-child { .vm-list-selected td:first-child {
font-weight: bold; font-weight: bold;
} }
.vm-list-table-thin {
width: 10px;
}
.vm-list-table-admin {
width: 130px;
}
</style> </style>
{% endblock %} {% endblock %}
{% block extra_js %} {% block extra_js %}
$(function() { $(function() {
var ctrlDown = false; var ctrlDown, shiftDown = false;
var ctrlKey = 17; var ctrlKey = 17;
var shiftKey = 16;
var selected = [];
$(document).keydown(function(e) { $(document).keydown(function(e) {
if (e.keyCode == ctrlKey) ctrlDown = true; if (e.keyCode == ctrlKey) ctrlDown = true;
if (e.keyCode == shiftKey) shiftDown = true;
}).keyup(function(e) { }).keyup(function(e) {
if (e.keyCode == ctrlKey) ctrlDown = false; 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) { if (ctrlDown) {
setRowColor($(this)); 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 { } else {
$('.vm-list-selected').removeClass('vm-list-selected'); $('.vm-list-selected').removeClass('vm-list-selected');
$(this).addClass('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({ $('.vm-list-details').popover({
...@@ -106,25 +172,28 @@ $(function() { ...@@ -106,25 +172,28 @@ $(function() {
'trigger': 'click' 'trigger': 'click'
}); });
/* $('tbody a').mousedown(function(e) {
$('#check_all').click(function() { // parent tr doesn't get selected when clicked
var checked = $(this).prop('checked'); e.stopPropagation();
$('.vm-checkbox').each(function() {
// reverse
// $(this).prop('checked', !$(this).prop('checked'));
// set
$(this).prop('checked', checked);
setRowColor($(this))
})
}); });
$('.vm-checkbox').click(function() { $('tbody a').click(function(e) {
setRowColor($(this)); // 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) { function setRowColor(row) {
if(!row.hasClass('vm-list-selected')) { 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> <tr>
<!--<td><input type="checkbox"/ class="vm-checkbox" id="vm-1825{{ c }}"></td>--> <!--<td><input type="checkbox"/ class="vm-checkbox" id="vm-1825{{ c }}"></td>-->
<td>182{{ c }}</td> <td>
<td><a href="">network-devenv</a></td> <div id="vm-1{{ c }}">1{{ c }}</div>
</td>
<td><a href="" class="real-link">network-devenv</a></td>
<td>running</td> <td>running</td>
<td>10 days</td> <td>10 days</td>
<td>1 month</td> <td>1 month</td>
<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> <i class="icon-truck"></i>
</span> </a>
<span class="btn btn-default btn-xs" title data-original-title="Rename"> <a class="btn btn-default btn-xs" title data-original-title="Rename">
<i class="icon-pencil"></i> <i class="icon-pencil"></i>
</span> </a>
<a href="#" class="btn btn-default btn-xs vm-list-connect" data-toggle="popover" <a href="#" class="btn btn-default btn-xs vm-list-connect" data-toggle="popover"
data-content=' data-content='
Belépés: <input style="width: 300px;" type="text" class="form-control" value="ssh cloud@vm.ik.bme.hu -p22312"/> 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): ...@@ -74,3 +74,4 @@ class VmList(SingleTableView):
template_name = "dashboard/vm-list.html" template_name = "dashboard/vm-list.html"
model = Instance model = Instance
table_class = VmListTable table_class = VmListTable
table_pagination = False
...@@ -49,7 +49,7 @@ class RuleAdmin(admin.ModelAdmin): ...@@ -49,7 +49,7 @@ class RuleAdmin(admin.ModelAdmin):
list_display = ('r_type', 'color_desc', 'owner', 'extra', 'direction', list_display = ('r_type', 'color_desc', 'owner', 'extra', 'direction',
'accept', 'proto', 'sport', 'dport', 'nat', 'accept', 'proto', 'sport', 'dport', 'nat',
'nat_dport', 'used_in') 'nat_dport', 'used_in')
list_filter = ('r_type', 'vlan', 'owner', 'direction', 'accept', list_filter = ('vlan', 'owner', 'direction', 'accept',
'proto', 'nat') 'proto', 'nat')
def color_desc(self, instance): def color_desc(self, instance):
......
...@@ -64,7 +64,7 @@ class IPNetworkField(models.Field): ...@@ -64,7 +64,7 @@ class IPNetworkField(models.Field):
description = _('IP Network object') description = _('IP Network object')
__metaclass__ = models.SubfieldBase __metaclass__ = models.SubfieldBase
def __init__(self, version=4, *args, **kwargs): def __init__(self, version=4, serialize=True, *args, **kwargs):
kwargs['max_length'] = 100 kwargs['max_length'] = 100
self.version = version self.version = version
super(IPNetworkField, self).__init__(*args, **kwargs) super(IPNetworkField, self).__init__(*args, **kwargs)
...@@ -98,7 +98,7 @@ class IPNetworkField(models.Field): ...@@ -98,7 +98,7 @@ class IPNetworkField(models.Field):
def value_to_string(self, obj): def value_to_string(self, obj):
value = self._get_val_from_obj(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): def clean(self, value, model_instance):
value = super(IPNetworkField, self).clean(value, model_instance) value = super(IPNetworkField, self).clean(value, model_instance)
......
from firewall import models from firewall import models
import django.conf import django.conf
import subprocess
import re import re
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.db.models import Q from django.db.models import Q
...@@ -12,14 +10,6 @@ settings = django.conf.settings.FIREWALL_SETTINGS ...@@ -12,14 +10,6 @@ settings = django.conf.settings.FIREWALL_SETTINGS
class Firewall: class Firewall:
IPV6 = False
RULES = None
RULES_NAT = []
vlans = None
pub = None
hosts = None
fw = None
def dportsport(self, rule, repl=True): def dportsport(self, rule, repl=True):
retval = ' ' retval = ' '
if rule.proto == 'tcp' or rule.proto == 'udp': if rule.proto == 'tcp' or rule.proto == 'udp':
...@@ -46,7 +36,7 @@ class Firewall: ...@@ -46,7 +36,7 @@ class Firewall:
if not rule.foreign_network: if not rule.foreign_network:
return return
if self.IPV6 and host.ipv6: if self.proto == 6 and host.ipv6:
ipaddr = host.ipv6 + '/112' ipaddr = host.ipv6 + '/112'
else: else:
ipaddr = host.ipv4 ipaddr = host.ipv4
...@@ -156,10 +146,6 @@ class Firewall: ...@@ -156,10 +146,6 @@ class Firewall:
'-j ACCEPT') '-j ACCEPT')
def postrun(self): 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 25 -j LOG_DROP')
self.iptables('-A PUB_OUT -p tcp --dport 445 -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') self.iptables('-A PUB_OUT -p udp --dport 445 -j LOG_DROP')
...@@ -206,15 +192,6 @@ class Firewall: ...@@ -206,15 +192,6 @@ class Firewall:
(str(s_vlan.network4), d_vlan.interface, (str(s_vlan.network4), d_vlan.interface,
s_vlan.snat_ip)) 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') self.iptablesnat('COMMIT')
def ipt_filter(self): def ipt_filter(self):
...@@ -258,45 +235,29 @@ class Firewall: ...@@ -258,45 +235,29 @@ class Firewall:
# post-run stuff # post-run stuff
self.postrun() 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 for x in self.RULES if not ipv4_re.search(x)]
self.RULES = [x.replace('icmp', 'icmpv6') for x in self.RULES] 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 = []
self.RULES_NAT = [] self.RULES_NAT = []
self.IPV6 = IPV6 self.proto = proto
self.vlans = models.Vlan.objects.all() self.vlans = models.Vlan.objects.all()
self.hosts = models.Host.objects.all() self.hosts = models.Host.objects.all()
self.pub = models.Vlan.objects.get(name='PUB')
self.fw = models.Firewall.objects.all() self.fw = models.Firewall.objects.all()
self.ipt_filter() self.ipt_filter()
if not self.IPV6: if self.proto != 6:
self.ipt_nat() 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): def get(self):
if self.IPV6: if self.proto == 6:
return {'filter': self.RULES, } return {'filter': self.RULES, }
else: else:
return {'filter': self.RULES, 'nat': self.RULES_NAT} return {'filter': self.RULES, 'nat': self.RULES_NAT}
def show(self): def show(self):
if self.IPV6: if self.proto == 6:
return '\n'.join(self.RULES) + '\n' return '\n'.join(self.RULES) + '\n'
else: else:
return ('\n'.join(self.RULES) + '\n' + return ('\n'.join(self.RULES) + '\n' +
...@@ -413,11 +374,6 @@ def dns(): ...@@ -413,11 +374,6 @@ def dns():
DNS.append("^%s:%s:%s" % (d['name'], d['address'], d['ttl'])) DNS.append("^%s:%s:%s" % (d['name'], d['address'], d['ttl']))
return DNS 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): def prefix_to_mask(prefix):
...@@ -480,9 +436,11 @@ def dhcp(): ...@@ -480,9 +436,11 @@ def dhcp():
}) })
return DHCP return DHCP
process = subprocess.Popen(['/usr/bin/ssh', 'fw2',
'cat > /tools/dhcp3/dhcpd.conf.generated;'
'sudo /etc/init.d/isc-dhcp-server restart'], def vlan():
shell=False, stdin=subprocess.PIPE) obj = models.Vlan.objects.values('vid', 'name', 'network4', 'network6')
# print "\n".join(DHCP)+"\n" return {x['name']: {'tag': x['vid'],
process.communicate("\n".join(DHCP) + "\n") 'addresses': [str(x['network4']),
str(x['network6'])]}
for x in obj}
...@@ -12,6 +12,7 @@ import django.conf ...@@ -12,6 +12,7 @@ import django.conf
from django.db.models.signals import post_save from django.db.models.signals import post_save
import random import random
from firewall.tasks.local_tasks import reloadtask
settings = django.conf.settings.FIREWALL_SETTINGS settings = django.conf.settings.FIREWALL_SETTINGS
...@@ -62,10 +63,6 @@ class Rule(models.Model): ...@@ -62,10 +63,6 @@ class Rule(models.Model):
verbose_name=_("owner"), verbose_name=_("owner"),
help_text=_("The user responsible for " help_text=_("The user responsible for "
"this rule.")) "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"), nat = models.BooleanField(default=False, verbose_name=_("NAT"),
help_text=_("If network address translation " help_text=_("If network address translation "
"shoud be done.")) "shoud be done."))
...@@ -129,6 +126,15 @@ class Rule(models.Model): ...@@ -129,6 +126,15 @@ class Rule(models.Model):
(("dport=%s " % self.dport) if self.dport else '')), (("dport=%s " % self.dport) if self.dport else '')),
'desc': self.description} '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 @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
return ('network.rule', None, {'pk': self.pk}) return ('network.rule', None, {'pk': self.pk})
...@@ -137,7 +143,6 @@ class Rule(models.Model): ...@@ -137,7 +143,6 @@ class Rule(models.Model):
verbose_name = _("rule") verbose_name = _("rule")
verbose_name_plural = _("rules") verbose_name_plural = _("rules")
ordering = ( ordering = (
'r_type',
'direction', 'direction',
'proto', 'proto',
'sport', 'sport',
...@@ -278,6 +283,24 @@ class Vlan(models.Model): ...@@ -278,6 +283,24 @@ class Vlan(models.Model):
def prefix6(self): def prefix6(self):
return self.network6.prefixlen 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): class VlanGroup(models.Model):
""" """
...@@ -495,11 +518,11 @@ class Host(models.Model): ...@@ -495,11 +518,11 @@ class Host(models.Model):
if public < 1024: if public < 1024:
raise ValidationError(_("Only ports above 1024 can be used.")) raise ValidationError(_("Only ports above 1024 can be used."))
rule = Rule(direction='1', owner=self.owner, dport=public, 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) nat_dport=private, host=self, foreign_network=vg)
else: else:
rule = Rule(direction='1', owner=self.owner, dport=public, 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) host=self, foreign_network=vg)
rule.full_clean() rule.full_clean()
...@@ -778,7 +801,6 @@ class Blacklist(models.Model): ...@@ -778,7 +801,6 @@ class Blacklist(models.Model):
def send_task(sender, instance, created, **kwargs): def send_task(sender, instance, created, **kwargs):
from firewall.tasks import reloadtask
reloadtask.apply_async(args=[sender.__name__]) reloadtask.apply_async(args=[sender.__name__])
......
import celery from manager.mancelery import celery
from django.core.cache import cache from django.core.cache import cache
from firewall.fw import Firewall, dhcp, dns, ipset
import django.conf import django.conf
settings = django.conf.settings.FIREWALL_SETTINGS settings = django.conf.settings.FIREWALL_SETTINGS
@celery.task @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(): def periodic_task():
from firewall.fw import Firewall, dhcp, dns, ipset, vlan
import remote_tasks
if cache.get('dns_lock'): if cache.get('dns_lock'):
cache.delete("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" print "dns ujratoltese kesz"
if cache.get('dhcp_lock'): if cache.get('dhcp_lock'):
cache.delete("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" print "dhcp ujratoltese kesz"
if cache.get('firewall_lock'): if cache.get('firewall_lock'):
cache.delete("firewall_lock") cache.delete("firewall_lock")
ipv4 = Firewall().get() ipv4 = Firewall(proto=4).get()
ipv6 = Firewall(True).get() ipv6 = Firewall(proto=6).get()
reload_firewall_task.delay(ipv4, ipv6) remote_tasks.reload_firewall.apply_async(args=[ipv4, ipv6],
queue='firewall')
print "firewall ujratoltese kesz" 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'): if cache.get('blacklist_lock'):
cache.delete("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" print "blacklist ujratoltese kesz"
...@@ -70,4 +56,7 @@ def reloadtask(type='Host'): ...@@ -70,4 +56,7 @@ def reloadtask(type='Host'):
if type == "Blacklist": if type == "Blacklist":
cache.add("blacklist_lock", "true", 30) cache.add("blacklist_lock", "true", 30)
if type == "Vlan":
cache.add("firewall_vlan_lock", "true", 30)
print type 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 _ ...@@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST from django.views.decorators.http import require_POST
from .tasks import reloadtask from .tasks.local_tasks import reloadtask
from .models import Blacklist, Host from .models import Blacklist, Host
...@@ -20,6 +20,7 @@ def reload_firewall(request): ...@@ -20,6 +20,7 @@ def reload_firewall(request):
html = (_("Dear %s, you've signed in as administrator!<br />" html = (_("Dear %s, you've signed in as administrator!<br />"
"Reloading in 10 seconds...") % request.user.username) "Reloading in 10 seconds...") % request.user.username)
reloadtask.delay() reloadtask.delay()
reloadtask.delay('Vlan')
else: else:
html = (_("Dear %s, you've signed in!") % request.user.username) html = (_("Dear %s, you've signed in!") % request.user.username)
else: else:
......
...@@ -6,7 +6,8 @@ HOSTNAME = "localhost" ...@@ -6,7 +6,8 @@ HOSTNAME = "localhost"
celery = Celery('manager', backend='amqp', celery = Celery('manager', backend='amqp',
broker=getenv("AMQP_URI"), broker=getenv("AMQP_URI"),
include=['vm.tasks.local_tasks', 'storage.tasks.local_tasks']) include=['vm.tasks.local_tasks', 'storage.tasks.local_tasks',
'firewall.tasks.local_tasks'])
celery.conf.update( celery.conf.update(
CELERY_QUEUES=( CELERY_QUEUES=(
......
...@@ -166,7 +166,6 @@ class RuleForm(ModelForm): ...@@ -166,7 +166,6 @@ class RuleForm(ModelForm):
'extra', 'extra',
'accept', 'accept',
'owner', 'owner',
'r_type',
'nat', 'nat',
'nat_dport', 'nat_dport',
), ),
......
...@@ -90,6 +90,9 @@ class SmallHostTable(Table): ...@@ -90,6 +90,9 @@ class SmallHostTable(Table):
class RecordTable(Table): class RecordTable(Table):
fqdn = LinkColumn('network.record', args=[A('pk')], orderable=False) fqdn = LinkColumn('network.record', args=[A('pk')], orderable=False)
address = TemplateColumn(
template_name="network/columns/records-address.html"
)
class Meta: class Meta:
model = Record model = Record
......
{% if record.host %}
{% if record.type == "A" %}
{{ record.host.ipv4 }}
{% elif record.type == "AAAA" %}
{{ record.host.ipv6 }}
{% elif record.type == "CNAME" %}
{{ record.host.get_fqdn }}
{% elif record.type == "MX" %}
{{ record.host.get_fqdn }}
{% else %}
This should not appear!
{% endif %}
{% else %}
{{ record.address }}
{% endif %}
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'DiskActivity'
db.create_table(u'storage_diskactivity', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('created', self.gf('model_utils.fields.AutoCreatedField')(default=datetime.datetime.now)),
('modified', self.gf('model_utils.fields.AutoLastModifiedField')(default=datetime.datetime.now)),
('activity_code', self.gf('django.db.models.fields.CharField')(max_length=100)),
('task_uuid', self.gf('django.db.models.fields.CharField')(max_length=50, unique=True, null=True, blank=True)),
('disk', self.gf('django.db.models.fields.related.ForeignKey')(related_name='activity_log', to=orm['storage.Disk'])),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)),
('started', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
('finished', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
('result', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
('state', self.gf('django.db.models.fields.CharField')(default='PENDING', max_length=50)),
))
db.send_create_signal(u'storage', ['DiskActivity'])
# Adding field 'Disk.removed'
db.add_column(u'storage_disk', 'removed',
self.gf('django.db.models.fields.DateTimeField')(default=None, null=True, blank=True),
keep_default=False)
def backwards(self, orm):
# Deleting model 'DiskActivity'
db.delete_table(u'storage_diskactivity')
# Deleting field 'Disk.removed'
db.delete_column(u'storage_disk', 'removed')
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'storage.datastore': {
'Meta': {'ordering': "['name']", 'object_name': 'DataStore'},
'hostname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
},
u'storage.disk': {
'Meta': {'ordering': "['name']", 'object_name': 'Disk'},
'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'derivatives'", 'null': 'True', 'to': u"orm['storage.Disk']"}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'datastore': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['storage.DataStore']"}),
'dev_num': ('django.db.models.fields.CharField', [], {'default': "'a'", 'max_length': '1'}),
'filename': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
'ready': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'removed': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'size': ('sizefield.models.FileSizeField', [], {}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
},
u'storage.diskactivity': {
'Meta': {'object_name': 'DiskActivity'},
'activity_code': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
'disk': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_log'", 'to': u"orm['storage.Disk']"}),
'finished': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
'result': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'started': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'state': ('django.db.models.fields.CharField', [], {'default': "'PENDING'", 'max_length': '50'}),
'task_uuid': ('django.db.models.fields.CharField', [], {'max_length': '50', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'})
}
}
complete_apps = ['storage']
\ No newline at end of file
...@@ -6,6 +6,7 @@ import uuid ...@@ -6,6 +6,7 @@ import uuid
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models import (Model, BooleanField, CharField, DateTimeField, from django.db.models import (Model, BooleanField, CharField, DateTimeField,
ForeignKey, TextField) ForeignKey, TextField)
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils.models import TimeStampedModel from model_utils.models import TimeStampedModel
from sizefield.models import FileSizeField from sizefield.models import FileSizeField
...@@ -49,13 +50,31 @@ class Disk(TimeStampedModel): ...@@ -49,13 +50,31 @@ class Disk(TimeStampedModel):
related_name='derivatives') related_name='derivatives')
ready = BooleanField(default=False) ready = BooleanField(default=False)
dev_num = CharField(default='a', max_length=1, dev_num = CharField(default='a', max_length=1,
verbose_name="device number") verbose_name=_("device number"))
removed = DateTimeField(blank=True, default=None, null=True)
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
verbose_name = _('disk') verbose_name = _('disk')
verbose_name_plural = _('disks') verbose_name_plural = _('disks')
class WrongDiskTypeError(Exception):
def __init__(self, type):
self.type = type
def __str__(self):
return ("Operation can't be invoked on a disk of type '%s'." %
self.type)
class DiskInUseError(Exception):
def __init__(self, disk):
self.disk = disk
def __str__(self):
return ("The requested operation can't be performed on disk "
"'%s (%s)' because it is in use." %
(self.disk.name, self.disk.filename))
@property @property
def path(self): def path(self):
return self.datastore.path + '/' + self.filename return self.datastore.path + '/' + self.filename
...@@ -70,39 +89,38 @@ class Disk(TimeStampedModel): ...@@ -70,39 +89,38 @@ class Disk(TimeStampedModel):
'raw-rw': 'raw', 'raw-rw': 'raw',
}[self.type] }[self.type]
class WrongDiskTypeError(Exception): @property
def __init__(self, type): def device_type(self):
self.type = type return {
'qcow2': 'vd',
'raw': 'vd',
'iso': 'hd',
}[self.format]
def __str__(self): def is_in_use(self):
return ("Operation can't be invoked on a disk of type '%s'." % return self.instance_set.exclude(state='SHUTOFF').exists()
self.type)
def get_exclusive(self): def get_exclusive(self):
"""Get an instance of the disk for exclusive usage. """Get an instance of the disk for exclusive usage.
"""
if self.type in ['qcow2-snap', 'raw-rw']:
raise self.WrongDiskTypeError(self.type)
filename = self.filename if self.type == 'iso' else str(uuid.uuid4()) This method manipulates the database only.
new_type = { """
type_mapping = {
'qcow2-norm': 'qcow2-snap', 'qcow2-norm': 'qcow2-snap',
'iso': 'iso', 'iso': 'iso',
'raw-ro': 'raw-rw', 'raw-ro': 'raw-rw',
}[self.type] }
if self.type not in type_mapping.keys():
raise self.WrongDiskTypeError(self.type)
filename = self.filename if self.type == 'iso' else str(uuid.uuid4())
new_type = type_mapping[self.type]
return Disk.objects.create(base=self, datastore=self.datastore, return Disk.objects.create(base=self, datastore=self.datastore,
filename=filename, name=self.name, filename=filename, name=self.name,
size=self.size, type=new_type) size=self.size, type=new_type)
@property
def device_type(self):
return {
'qcow2': 'vd',
'raw': 'vd',
'iso': 'hd',
}[self.format]
def get_vmdisk_desc(self): def get_vmdisk_desc(self):
return { return {
'source': self.path, 'source': self.path,
...@@ -111,10 +129,25 @@ class Disk(TimeStampedModel): ...@@ -111,10 +129,25 @@ class Disk(TimeStampedModel):
'target_device': self.device_type + self.dev_num 'target_device': self.device_type + self.dev_num
} }
def get_disk_desc(self):
return {
'name': self.filename,
'dir': self.datastore.path,
'format': self.format,
'size': self.size,
'base_name': self.base.filename if self.base else None,
'type': 'snapshot' if self.type == 'qcow2-snap' else 'normal'
}
def __unicode__(self): def __unicode__(self):
return u"%s (#%d)" % (self.name, self.id) return u"%s (#%d)" % (self.name, self.id)
def deploy(self): def clean(self, *args, **kwargs):
if self.size == "" and self.base:
self.size = self.base.size
super(Disk, self).clean(*args, **kwargs)
def deploy(self, user=None, task_uuid=None):
"""Reify the disk model on the associated data store. """Reify the disk model on the associated data store.
:param self: the disk model to reify :param self: the disk model to reify
...@@ -127,38 +160,96 @@ class Disk(TimeStampedModel): ...@@ -127,38 +160,96 @@ class Disk(TimeStampedModel):
if self.ready: if self.ready:
return False return False
disk_desc = { act = DiskActivity(activity_code='storage.Disk.deploy')
'name': self.filename, act.disk = self
'dir': self.datastore.path, act.started = timezone.now()
'format': self.format, act.state = 'PENDING'
'size': self.size, act.task_uuid = task_uuid
'base_name': self.base.filename if self.base else None, act.user = user
'type': 'snapshot' if self.type == 'qcow2-snap' else 'normal' act.save()
}
# Delegate create / snapshot jobs # Delegate create / snapshot jobs
queue_name = self.datastore.hostname + ".storage"
disk_desc = self.get_disk_desc()
if self.type == 'qcow2-snap': if self.type == 'qcow2-snap':
remote_tasks.snapshot.apply_async( act.update_state('CREATING SNAPSHOT')
args=[disk_desc], remote_tasks.snapshot.apply_async(args=[disk_desc],
queue=self.datastore.hostname + ".storage").get() queue=queue_name).get()
else: else:
remote_tasks.create.apply_async( act.update_state('CREATING DISK')
args=[disk_desc], remote_tasks.create.apply_async(args=[disk_desc],
queue=self.datastore.hostname + ".storage").get() queue=queue_name).get()
self.ready = True self.ready = True
self.save() self.save()
act.finish('SUCCESS')
return True return True
def deploy_async(self): def deploy_async(self, user=None):
"""Execute deploy asynchronously. """Execute deploy asynchronously.
""" """
local_tasks.deploy.apply_async(self) local_tasks.deploy.apply_async(args=[self, user],
queue="localhost.man")
def delete(self): def remove(self, user=None, task_uuid=None):
# TODO add activity logging
self.removed = timezone.now()
self.save()
def remove_async(self, user=None):
local_tasks.remove.apply_async(args=[self, user],
queue='localhost.man')
def restore(self, user=None, task_uuid=None):
"""Restore removed disk.
"""
# TODO # TODO
# StorageDriver.delete_disk.delay(instance.to_json()).get()
pass pass
def restore_async(self, user=None):
local_tasks.restore.apply_async(args=[self, user],
queue='localhost.man')
def save_as(self, name, user=None, task_uuid=None):
mapping = {
'qcow2-snap': ('qcow2-norm', self.base),
}
if self.type not in mapping.keys():
raise self.WrongDiskTypeError(self.type)
if self.is_in_use():
raise self.DiskInUseError(self)
# from this point on, the caller has to guarantee that the disk is not
# going to be used until the operation is complete
act = DiskActivity(activity_code='storage.Disk.save_as')
act.disk = self
act.started = timezone.now()
act.state = 'PENDING'
act.task_uuid = task_uuid
act.user = user
act.save()
filename = str(uuid.uuid4())
new_type, new_base = mapping[self.type]
disk = Disk.objects.create(base=new_base, datastore=self.datastore,
filename=filename, name=name,
size=self.size, type=new_type)
queue_name = self.datastore.hostname + ".storage"
remote_tasks.merge.apply_async(args=[self.get_disk_desc(),
disk.get_disk_desc()],
queue=queue_name).get()
disk.ready = True
disk.save()
act.finish('SUCCESS')
return disk
class DiskActivity(TimeStampedModel): class DiskActivity(TimeStampedModel):
activity_code = CharField(verbose_name=_('activity_code'), max_length=100) activity_code = CharField(verbose_name=_('activity_code'), max_length=100)
...@@ -172,3 +263,14 @@ class DiskActivity(TimeStampedModel): ...@@ -172,3 +263,14 @@ class DiskActivity(TimeStampedModel):
result = TextField(verbose_name=_('result'), blank=True, null=True) result = TextField(verbose_name=_('result'), blank=True, null=True)
state = CharField(verbose_name=_('state'), default='PENDING', state = CharField(verbose_name=_('state'), default='PENDING',
max_length=50) max_length=50)
def update_state(self, new_state):
self.state = new_state
self.save()
def finish(self, result=None):
if not self.finished:
self.finished = timezone.now()
self.result = result
self.state = 'COMPLETED'
self.save()
...@@ -3,16 +3,14 @@ from manager.mancelery import celery ...@@ -3,16 +3,14 @@ from manager.mancelery import celery
@celery.task @celery.task
def deploy(disk, user): def deploy(disk, user):
'''Create new virtual machine from VM class. disk.deploy(task_uuid=deploy.request.id, user=user)
'''
disk.deploy(task_uuid=deploy.rdiskd, user=user)
@celery.task @celery.task
def delete(): def remove(disk, user):
pass disk.remove(task_uuid=remove.request.id, user=user)
@celery.task @celery.task
def save_as(): def restore(disk, user):
pass disk.restore(task_uuid=restore.request.id, user=user)
...@@ -12,15 +12,20 @@ def create(disk_desc): ...@@ -12,15 +12,20 @@ def create(disk_desc):
@celery.task(name='storagedriver.delete') @celery.task(name='storagedriver.delete')
def delete(json_data): def delete(path):
pass pass
@celery.task(name='storagedriver.snapshot') @celery.task(name='storagedriver.snapshot')
def snapshot(json_data): def snapshot(disk_desc):
pass pass
@celery.task(name='storagedriver.get') @celery.task(name='storagedriver.get')
def get(json_data): def get(path):
pass
@celery.task(name='storagedriver.merge')
def merge(src_disk_desc, dst_disk_desc):
pass pass
from django.contrib import admin from django.contrib import admin
from .models import (Instance, InstanceActivity, InstanceTemplate, Interface, from .models import (Instance, InstanceActivity, InstanceTemplate, Interface,
InterfaceTemplate, Lease, Node, NodeActivity) InterfaceTemplate, Lease, NamedBaseResourceConfig, Node,
NodeActivity)
admin.site.register(Instance) admin.site.register(Instance)
...@@ -10,5 +11,6 @@ admin.site.register(InstanceTemplate) ...@@ -10,5 +11,6 @@ admin.site.register(InstanceTemplate)
admin.site.register(Interface) admin.site.register(Interface)
admin.site.register(InterfaceTemplate) admin.site.register(InterfaceTemplate)
admin.site.register(Lease) admin.site.register(Lease)
admin.site.register(NamedBaseResourceConfig)
admin.site.register(Node) admin.site.register(Node)
admin.site.register(NodeActivity) admin.site.register(NodeActivity)
from manager.mancelery import celery from manager.mancelery import celery
# TODO: Keep syncronhised with Instance funcs
@celery.task @celery.task
def deploy(instance, user): def deploy(instance, user):
'''Create new virtual machine from VM class. ''' Call Insance.deploy() from celery task.
''' '''
instance.deploy(task_uuid=deploy.request.id, user=user) instance.deploy(task_uuid=deploy.request.id, user=user)
def delete(): def destroy():
pass pass
......
from manager.mancelery import celery
@celery.task(name='netdriver.create')
def create(params):
pass
@celery.task(name='netdriver.delete')
def destroy(params):
pass
...@@ -2,52 +2,47 @@ from manager.mancelery import celery ...@@ -2,52 +2,47 @@ from manager.mancelery import celery
@celery.task(name='vmdriver.create') @celery.task(name='vmdriver.create')
def create(params): def deploy(params):
pass pass
@celery.task(name='vmdriver.suspend') @celery.task(name='vmdriver.delete')
def stop(params): def destroy(params):
pass
@celery.task(name='vmdriver.resume')
def resume(params):
pass pass
@celery.task(name='vmdriver.delete') @celery.task(name='vmdriver.save')
def poweroff(params): def sleep(params):
pass pass
@celery.task(name='vmdriver.shutdown') @celery.task(name='vmdriver.restore')
def shutdown(params): def wake_up(params):
pass pass
@celery.task(name='vmdriver.reset') @celery.task(name='vmdriver.suspend')
def reset(params): def suspend(params):
pass pass
@celery.task(name='vmdriver.start') @celery.task(name='vmdriver.resume')
def restart(params): def resume(params):
pass pass
@celery.task(name='vmdriver.reboot') @celery.task(name='vmdriver.shutdown')
def reboot(params): def shutdown(params):
pass pass
@celery.task(name='vmdriver.save') @celery.task(name='vmdriver.reset')
def save(params): def reset(params):
pass pass
@celery.task(name='vmdriver.restore') @celery.task(name='vmdriver.reboot')
def restore(params): def reboot(params):
pass pass
...@@ -64,8 +59,3 @@ def domain_info(params): ...@@ -64,8 +59,3 @@ def domain_info(params):
@celery.task(name='vmdriver.list_domains') @celery.task(name='vmdriver.list_domains')
def list_domains(params): def list_domains(params):
pass pass
@celery.task(name='vmdriver.delete')
def delete(params):
pass
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