diff --git a/app/settings.py b/app/settings.py
index f966f70..1f71d8d 100644
--- a/app/settings.py
+++ b/app/settings.py
@@ -162,6 +162,8 @@
NGNIX_DEFAULT_REDIRECT = ''
+BACKUP_SET_LOCK = '/tmp/_azimutgestion_backuplock.lock'
+
try:
from settingsLocal import *
except ImportError:
diff --git a/app/utils.py b/app/utils.py
new file mode 100644
index 0000000..c670764
--- /dev/null
+++ b/app/utils.py
@@ -0,0 +1,20 @@
+class DjangoLock:
+
+ def __init__(self, filename):
+ self.filename = filename
+ # This will create it if it does not exist already
+ self.handle = open(filename, 'w')
+
+ # flock() is a blocking call unless it is bitwise ORed with LOCK_NB to avoid blocking
+ # on lock acquisition. This blocking is what I use to provide atomicity across forked
+ # Django processes since native python locks and semaphores only work at the thread level
+ def acquire(self):
+ import fcntl
+ fcntl.flock(self.handle, fcntl.LOCK_EX)
+
+ def release(self):
+ import fcntl
+ fcntl.flock(self.handle, fcntl.LOCK_UN)
+
+ def __del__(self):
+ self.handle.close()
diff --git a/backups/migrations/0006_auto__add_backupsetofrun.py b/backups/migrations/0006_auto__add_backupsetofrun.py
new file mode 100644
index 0000000..d25b6ba
--- /dev/null
+++ b/backups/migrations/0006_auto__add_backupsetofrun.py
@@ -0,0 +1,138 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as 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 'BackupSetOfRun'
+ db.create_table(u'backups_backupsetofrun', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('type', self.gf('django.db.models.fields.CharField')(max_length=16)),
+ ('status', self.gf('django.db.models.fields.CharField')(max_length=16)),
+ ('start_date', self.gf('django.db.models.fields.DateTimeField')()),
+ ('end_date', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('total_size', self.gf('django.db.models.fields.BigIntegerField')()),
+ ('total_files', self.gf('django.db.models.fields.BigIntegerField')()),
+ ))
+ db.send_create_signal(u'backups', ['BackupSetOfRun'])
+
+ # Adding M2M table for field backups on 'BackupSetOfRun'
+ m2m_table_name = db.shorten_name(u'backups_backupsetofrun_backups')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('backupsetofrun', models.ForeignKey(orm[u'backups.backupsetofrun'], null=False)),
+ ('backuprun', models.ForeignKey(orm[u'backups.backuprun'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['backupsetofrun_id', 'backuprun_id'])
+
+
+ def backwards(self, orm):
+ # Deleting model 'BackupSetOfRun'
+ db.delete_table(u'backups_backupsetofrun')
+
+ # Removing M2M table for field backups on 'BackupSetOfRun'
+ db.delete_table(db.shorten_name(u'backups_backupsetofrun_backups'))
+
+
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'backups.backup': {
+ 'Meta': {'object_name': 'Backup'},
+ 'active': ('django.db.models.fields.BooleanField', [], {}),
+ 'excludes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'folder_from': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'folder_to': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'prox_and_sys_excludes': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'server_from': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_of_the_server'", 'to': u"orm['servers.Server']"}),
+ 'server_to': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_on_the_server'", 'to': u"orm['servers.Server']"})
+ },
+ u'backups.backuprun': {
+ 'Meta': {'object_name': 'BackupRun'},
+ 'backup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['backups.Backup']"}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nb_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'stderr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'stdout': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ u'backups.backupsetofrun': {
+ 'Meta': {'object_name': 'BackupSetOfRun'},
+ 'backups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.BackupRun']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'total_files': ('django.db.models.fields.BigIntegerField', [], {}),
+ 'total_size': ('django.db.models.fields.BigIntegerField', [], {}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+ },
+ 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'servers.server': {
+ 'Meta': {'object_name': 'Server'},
+ 'external_hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'external_interface': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'external_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'internal_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'is_proxmox': ('django.db.models.fields.BooleanField', [], {}),
+ 'is_vm': ('django.db.models.fields.BooleanField', [], {}),
+ 'keymanger_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'logstash_shipper': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'mysql_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'mysqled_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'ngnix_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ngnixed_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'proxmox_node_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_base_folder': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_management': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_connection_string_from_backup': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'ssh_connection_string_from_gestion': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'users_owning_the_server': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ }
+ }
+
+ complete_apps = ['backups']
\ No newline at end of file
diff --git a/backups/migrations/0007_auto.py b/backups/migrations/0007_auto.py
new file mode 100644
index 0000000..735680e
--- /dev/null
+++ b/backups/migrations/0007_auto.py
@@ -0,0 +1,124 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding M2M table for field backupruns on 'BackupSetOfRun'
+ m2m_table_name = db.shorten_name(u'backups_backupsetofrun_backupruns')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('backupsetofrun', models.ForeignKey(orm[u'backups.backupsetofrun'], null=False)),
+ ('backuprun', models.ForeignKey(orm[u'backups.backuprun'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['backupsetofrun_id', 'backuprun_id'])
+
+
+ def backwards(self, orm):
+ # Removing M2M table for field backupruns on 'BackupSetOfRun'
+ db.delete_table(db.shorten_name(u'backups_backupsetofrun_backupruns'))
+
+
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'backups.backup': {
+ 'Meta': {'object_name': 'Backup'},
+ 'active': ('django.db.models.fields.BooleanField', [], {}),
+ 'excludes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'folder_from': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'folder_to': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'prox_and_sys_excludes': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'server_from': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_of_the_server'", 'to': u"orm['servers.Server']"}),
+ 'server_to': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_on_the_server'", 'to': u"orm['servers.Server']"})
+ },
+ u'backups.backuprun': {
+ 'Meta': {'object_name': 'BackupRun'},
+ 'backup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['backups.Backup']"}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nb_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'stderr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'stdout': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ u'backups.backupsetofrun': {
+ 'Meta': {'object_name': 'BackupSetOfRun'},
+ 'backupruns': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.BackupRun']", 'symmetrical': 'False'}),
+ 'backups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.Backup']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'running'", 'max_length': '16'}),
+ 'total_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'total_size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+ },
+ 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'servers.server': {
+ 'Meta': {'object_name': 'Server'},
+ 'external_hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'external_interface': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'external_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'internal_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'is_proxmox': ('django.db.models.fields.BooleanField', [], {}),
+ 'is_vm': ('django.db.models.fields.BooleanField', [], {}),
+ 'keymanger_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'logstash_shipper': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'mysql_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'mysqled_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'ngnix_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ngnixed_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'proxmox_node_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_base_folder': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_management': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_connection_string_from_backup': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'ssh_connection_string_from_gestion': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'users_owning_the_server': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ }
+ }
+
+ complete_apps = ['backups']
\ No newline at end of file
diff --git a/backups/migrations/0008_auto__chg_field_backupsetofrun_start_date.py b/backups/migrations/0008_auto__chg_field_backupsetofrun_start_date.py
new file mode 100644
index 0000000..4f41dcf
--- /dev/null
+++ b/backups/migrations/0008_auto__chg_field_backupsetofrun_start_date.py
@@ -0,0 +1,118 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Changing field 'BackupSetOfRun.start_date'
+ db.alter_column(u'backups_backupsetofrun', 'start_date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True))
+
+ def backwards(self, orm):
+
+ # Changing field 'BackupSetOfRun.start_date'
+ db.alter_column(u'backups_backupsetofrun', 'start_date', self.gf('django.db.models.fields.DateTimeField')())
+
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'backups.backup': {
+ 'Meta': {'object_name': 'Backup'},
+ 'active': ('django.db.models.fields.BooleanField', [], {}),
+ 'excludes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'folder_from': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'folder_to': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'prox_and_sys_excludes': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'server_from': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_of_the_server'", 'to': u"orm['servers.Server']"}),
+ 'server_to': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_on_the_server'", 'to': u"orm['servers.Server']"})
+ },
+ u'backups.backuprun': {
+ 'Meta': {'object_name': 'BackupRun'},
+ 'backup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['backups.Backup']"}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nb_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'stderr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'stdout': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ u'backups.backupsetofrun': {
+ 'Meta': {'object_name': 'BackupSetOfRun'},
+ 'backupruns': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.BackupRun']", 'symmetrical': 'False'}),
+ 'backups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.Backup']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'running'", 'max_length': '16'}),
+ 'total_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'total_size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+ },
+ 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'servers.server': {
+ 'Meta': {'object_name': 'Server'},
+ 'external_hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'external_interface': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'external_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'internal_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'is_proxmox': ('django.db.models.fields.BooleanField', [], {}),
+ 'is_vm': ('django.db.models.fields.BooleanField', [], {}),
+ 'keymanger_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'logstash_shipper': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'mysql_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'mysqled_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'ngnix_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ngnixed_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'proxmox_node_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_base_folder': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_management': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_connection_string_from_backup': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'ssh_connection_string_from_gestion': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'users_owning_the_server': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ }
+ }
+
+ complete_apps = ['backups']
\ No newline at end of file
diff --git a/backups/migrations/0009_auto.py b/backups/migrations/0009_auto.py
new file mode 100644
index 0000000..5923abc
--- /dev/null
+++ b/backups/migrations/0009_auto.py
@@ -0,0 +1,134 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Removing M2M table for field backups on 'BackupSetOfRun'
+ db.delete_table(db.shorten_name(u'backups_backupsetofrun_backups'))
+
+ # Removing M2M table for field backupruns on 'BackupSetOfRun'
+ db.delete_table(db.shorten_name(u'backups_backupsetofrun_backupruns'))
+
+
+ def backwards(self, orm):
+ # Adding M2M table for field backups on 'BackupSetOfRun'
+ m2m_table_name = db.shorten_name(u'backups_backupsetofrun_backups')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('backupsetofrun', models.ForeignKey(orm[u'backups.backupsetofrun'], null=False)),
+ ('backup', models.ForeignKey(orm[u'backups.backup'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['backupsetofrun_id', 'backup_id'])
+
+ # Adding M2M table for field backupruns on 'BackupSetOfRun'
+ m2m_table_name = db.shorten_name(u'backups_backupsetofrun_backupruns')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('backupsetofrun', models.ForeignKey(orm[u'backups.backupsetofrun'], null=False)),
+ ('backuprun', models.ForeignKey(orm[u'backups.backuprun'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['backupsetofrun_id', 'backuprun_id'])
+
+
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'backups.backup': {
+ 'Meta': {'object_name': 'Backup'},
+ 'active': ('django.db.models.fields.BooleanField', [], {}),
+ 'excludes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'folder_from': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'folder_to': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'prox_and_sys_excludes': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'server_from': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_of_the_server'", 'to': u"orm['servers.Server']"}),
+ 'server_to': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_on_the_server'", 'to': u"orm['servers.Server']"})
+ },
+ u'backups.backuprun': {
+ 'Meta': {'object_name': 'BackupRun'},
+ 'backup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['backups.Backup']"}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nb_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'stderr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'stdout': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ u'backups.backupsetofrun': {
+ 'Meta': {'object_name': 'BackupSetOfRun'},
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'running'", 'max_length': '16'}),
+ 'total_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'total_size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+ },
+ 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'servers.server': {
+ 'Meta': {'object_name': 'Server'},
+ 'external_hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'external_interface': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'external_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'internal_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'is_proxmox': ('django.db.models.fields.BooleanField', [], {}),
+ 'is_vm': ('django.db.models.fields.BooleanField', [], {}),
+ 'keymanger_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'logstash_shipper': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'mysql_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'mysqled_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'ngnix_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ngnixed_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'proxmox_node_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_base_folder': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_management': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_connection_string_from_backup': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'ssh_connection_string_from_gestion': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'users_owning_the_server': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ }
+ }
+
+ complete_apps = ['backups']
\ No newline at end of file
diff --git a/backups/migrations/0010_auto.py b/backups/migrations/0010_auto.py
new file mode 100644
index 0000000..8f50fd7
--- /dev/null
+++ b/backups/migrations/0010_auto.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding M2M table for field backupruns on 'BackupSetOfRun'
+ m2m_table_name = db.shorten_name(u'backups_backupsetofrun_backupruns')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('backupsetofrun', models.ForeignKey(orm[u'backups.backupsetofrun'], null=False)),
+ ('backuprun', models.ForeignKey(orm[u'backups.backuprun'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['backupsetofrun_id', 'backuprun_id'])
+
+ # Adding M2M table for field backups on 'BackupSetOfRun'
+ m2m_table_name = db.shorten_name(u'backups_backupsetofrun_backups')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('backupsetofrun', models.ForeignKey(orm[u'backups.backupsetofrun'], null=False)),
+ ('backup', models.ForeignKey(orm[u'backups.backup'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['backupsetofrun_id', 'backup_id'])
+
+
+ def backwards(self, orm):
+ # Removing M2M table for field backupruns on 'BackupSetOfRun'
+ db.delete_table(db.shorten_name(u'backups_backupsetofrun_backupruns'))
+
+ # Removing M2M table for field backups on 'BackupSetOfRun'
+ db.delete_table(db.shorten_name(u'backups_backupsetofrun_backups'))
+
+
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'backups.backup': {
+ 'Meta': {'object_name': 'Backup'},
+ 'active': ('django.db.models.fields.BooleanField', [], {}),
+ 'excludes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'folder_from': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'folder_to': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'prox_and_sys_excludes': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'server_from': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_of_the_server'", 'to': u"orm['servers.Server']"}),
+ 'server_to': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_on_the_server'", 'to': u"orm['servers.Server']"})
+ },
+ u'backups.backuprun': {
+ 'Meta': {'object_name': 'BackupRun'},
+ 'backup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['backups.Backup']"}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nb_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'stderr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'stdout': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ u'backups.backupsetofrun': {
+ 'Meta': {'object_name': 'BackupSetOfRun'},
+ 'backupruns': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.BackupRun']", 'symmetrical': 'False'}),
+ 'backups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.Backup']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'running'", 'max_length': '16'}),
+ 'total_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'total_size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+ },
+ 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'servers.server': {
+ 'Meta': {'object_name': 'Server'},
+ 'external_hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'external_interface': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'external_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'internal_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'is_proxmox': ('django.db.models.fields.BooleanField', [], {}),
+ 'is_vm': ('django.db.models.fields.BooleanField', [], {}),
+ 'keymanger_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'logstash_shipper': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'mysql_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'mysqled_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'ngnix_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ngnixed_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'proxmox_node_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_base_folder': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_management': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_connection_string_from_backup': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'ssh_connection_string_from_gestion': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'users_owning_the_server': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ }
+ }
+
+ complete_apps = ['backups']
\ No newline at end of file
diff --git a/backups/migrations/0011_auto__add_backupnotification__add_backupuserwhowantnotifs.py b/backups/migrations/0011_auto__add_backupnotification__add_backupuserwhowantnotifs.py
new file mode 100644
index 0000000..341be33
--- /dev/null
+++ b/backups/migrations/0011_auto__add_backupnotification__add_backupuserwhowantnotifs.py
@@ -0,0 +1,148 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as 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 'BackupNotification'
+ db.create_table(u'backups_backupnotification', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('when', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+ ('type', self.gf('django.db.models.fields.CharField')(max_length=32)),
+ ('message', self.gf('django.db.models.fields.TextField')()),
+ ))
+ db.send_create_signal(u'backups', ['BackupNotification'])
+
+ # Adding model 'BackupUserWhoWantNotifs'
+ db.create_table(u'backups_backupuserwhowantnotifs', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('type', self.gf('django.db.models.fields.CharField')(max_length=32)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ))
+ db.send_create_signal(u'backups', ['BackupUserWhoWantNotifs'])
+
+
+ def backwards(self, orm):
+ # Deleting model 'BackupNotification'
+ db.delete_table(u'backups_backupnotification')
+
+ # Deleting model 'BackupUserWhoWantNotifs'
+ db.delete_table(u'backups_backupuserwhowantnotifs')
+
+
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ 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', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'backups.backup': {
+ 'Meta': {'object_name': 'Backup'},
+ 'active': ('django.db.models.fields.BooleanField', [], {}),
+ 'excludes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'folder_from': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'folder_to': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'prox_and_sys_excludes': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'server_from': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_of_the_server'", 'to': u"orm['servers.Server']"}),
+ 'server_to': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_on_the_server'", 'to': u"orm['servers.Server']"})
+ },
+ u'backups.backupnotification': {
+ 'Meta': {'object_name': 'BackupNotification'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'message': ('django.db.models.fields.TextField', [], {}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ u'backups.backuprun': {
+ 'Meta': {'object_name': 'BackupRun'},
+ 'backup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['backups.Backup']"}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nb_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'stderr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'stdout': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ u'backups.backupsetofrun': {
+ 'Meta': {'object_name': 'BackupSetOfRun'},
+ 'backupruns': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.BackupRun']", 'symmetrical': 'False'}),
+ 'backups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.Backup']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'running'", 'max_length': '16'}),
+ 'total_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'total_size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+ },
+ u'backups.backupuserwhowantnotifs': {
+ 'Meta': {'object_name': 'BackupUserWhoWantNotifs'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
+ },
+ 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'servers.server': {
+ 'Meta': {'object_name': 'Server'},
+ 'external_hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'external_interface': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'external_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'internal_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'is_proxmox': ('django.db.models.fields.BooleanField', [], {}),
+ 'is_vm': ('django.db.models.fields.BooleanField', [], {}),
+ 'keymanger_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'logstash_shipper': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'mysql_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'mysqled_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'ngnix_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ngnixed_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'proxmox_node_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_base_folder': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_management': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_connection_string_from_backup': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'ssh_connection_string_from_gestion': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'users_owning_the_server': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ }
+ }
+
+ complete_apps = ['backups']
\ No newline at end of file
diff --git a/backups/migrations/0012_auto__add_field_backuprun_type.py b/backups/migrations/0012_auto__add_field_backuprun_type.py
new file mode 100644
index 0000000..33eb5e3
--- /dev/null
+++ b/backups/migrations/0012_auto__add_field_backuprun_type.py
@@ -0,0 +1,134 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'BackupRun.type'
+ db.add_column(u'backups_backuprun', 'type',
+ self.gf('django.db.models.fields.CharField')(default='hourly', max_length=16),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'BackupRun.type'
+ db.delete_column(u'backups_backuprun', 'type')
+
+
+ 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'backups.backup': {
+ 'Meta': {'object_name': 'Backup'},
+ 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'excludes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'folder_from': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'folder_to': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'prox_and_sys_excludes': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'server_from': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_of_the_server'", 'to': u"orm['servers.Server']"}),
+ 'server_to': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'backups_on_the_server'", 'to': u"orm['servers.Server']"})
+ },
+ u'backups.backupnotification': {
+ 'Meta': {'object_name': 'BackupNotification'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'message': ('django.db.models.fields.TextField', [], {}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ u'backups.backuprun': {
+ 'Meta': {'object_name': 'BackupRun'},
+ 'backup': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['backups.Backup']"}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'nb_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {}),
+ 'stderr': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'stdout': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+ },
+ u'backups.backupsetofrun': {
+ 'Meta': {'object_name': 'BackupSetOfRun'},
+ 'backupruns': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.BackupRun']", 'symmetrical': 'False'}),
+ 'backups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['backups.Backup']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'running'", 'max_length': '16'}),
+ 'total_files': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'total_size': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '16'})
+ },
+ u'backups.backupuserwhowantnotifs': {
+ 'Meta': {'object_name': 'BackupUserWhoWantNotifs'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
+ },
+ 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'servers.server': {
+ 'Meta': {'object_name': 'Server'},
+ 'external_hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'external_interface': ('django.db.models.fields.CharField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'external_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'hostname_for_vms_creation': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'internal_ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}),
+ 'is_proxmox': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_vm': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'keymanger_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'logstash_shipper': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'mysql_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'mysqled_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'ngnix_server': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ngnixed_server_set'", 'null': 'True', 'to': u"orm['servers.Server']"}),
+ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'proxmox_node_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_base_folder': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'samba_management': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'ssh_connection_string_from_backup': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'ssh_connection_string_from_gestion': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'users_owning_the_server': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ }
+ }
+
+ complete_apps = ['backups']
\ No newline at end of file
diff --git a/backups/models.py b/backups/models.py
index 898528a..ff543f0 100644
--- a/backups/models.py
+++ b/backups/models.py
@@ -1,6 +1,11 @@
from django.db import models
from servers.models import Server
+from django.utils import timezone
+
+from django.contrib.auth.models import User
+
+from django.core.mail import send_mail
class Backup(models.Model):
@@ -38,7 +43,120 @@ class BackupRun(models.Model):
stdout = models.TextField(blank=True, null=True)
stderr = models.TextField(blank=True, null=True)
+ TYPE_CHOICES = (
+ ('hourly', 'Hourly'),
+ ('daily', 'Daily'),
+ ('weekly', 'Weekly'),
+ ('monthly', 'Monthly'),
+ )
+
+ type = models.CharField(max_length=16, choices=TYPE_CHOICES)
+
def not_too_old(self):
from django.utils import timezone
import datetime
return (self.end_date + datetime.timedelta(days=3)) > timezone.now()
+
+
+class BackupSetOfRun(models.Model):
+
+ TYPE_CHOICES = (
+ ('hourly', 'Hourly'),
+ ('daily', 'Daily'),
+ ('weekly', 'Weekly'),
+ ('monthly', 'Monthly'),
+ )
+
+ type = models.CharField(max_length=16, choices=TYPE_CHOICES)
+
+ STATUS_CHOICES = (
+ ('running', 'Running'),
+ ('done', 'Done'),
+ ('canceled', 'Cancelled'),
+ )
+
+ status = models.CharField(max_length=16, choices=STATUS_CHOICES, default='running')
+
+ start_date = models.DateTimeField(auto_now_add=True)
+ end_date = models.DateTimeField(blank=True, null=True)
+
+ backupruns = models.ManyToManyField(BackupRun)
+ backups = models.ManyToManyField(Backup)
+
+ total_size = models.BigIntegerField(default=0)
+ total_files = models.BigIntegerField(default=0)
+
+ def get_status_label(self):
+ VALUES = {'running': 'warning', 'done': 'success', 'canceled': 'important'}
+
+ if self.status in VALUES:
+ return VALUES[self.status]
+ else:
+ return 'important'
+
+ def get_total_time(self):
+ if not self.end_date:
+ end_date = timezone.now()
+ else:
+ end_date = self.end_date
+
+ return int((end_date - self.start_date).total_seconds() / 36.0) / 100.0
+
+ def get_total_time_label(self):
+
+ tt = self.get_total_time()
+
+ if tt < 3.5:
+ return 'success'
+ if tt < 4.0:
+ return 'warning'
+ return 'important'
+
+
+class BackupNotification(models.Model):
+
+ when = models.DateTimeField(auto_now_add=True)
+
+ TYPE_CHOICES = (
+ ('bkpdone', 'Backup completed'),
+ ('bkpsetdone', 'Set of backup completed'),
+ ('bkpsetnotstarted', 'Set of backup not started'),
+ ('bkpsetcanceled', 'Set of backup canceled'),
+ ('bkpfailled', 'Backup failled'),
+ )
+
+ type = models.CharField(max_length=32, choices=TYPE_CHOICES)
+
+ message = models.TextField()
+
+ VALUES = {'bkpdone': 'success', 'bkpsetdone': 'success', 'bkpsetnotstarted': 'important', 'bkpfailled': 'important', 'bkpsetcanceled': 'warning'}
+
+ @staticmethod
+ def get_types_with_labels():
+ retour = []
+
+ for (key, text) in BackupNotification.TYPE_CHOICES:
+ retour.append((key, text, BackupNotification.VALUES[key]))
+
+ return retour
+
+ def get_type_label(self):
+
+ if self.type in self.VALUES:
+ return self.VALUES[self.type]
+ else:
+ return 'important'
+
+ def send_notifications(self):
+
+ subject = "Notification from AzimutGestion: %s" % (self.get_type_display(), )
+
+ recpts = [buwwn.user.email for buwwn in BackupUserWhoWantNotifs.objects.filter(type=self.type).all()]
+
+ send_mail(subject, self.message, 'norepoly@azimut-prod.com', recpts, True)
+
+
+class BackupUserWhoWantNotifs(models.Model):
+
+ type = models.CharField(max_length=32, choices=BackupNotification.TYPE_CHOICES)
+ user = models.ForeignKey(User)
diff --git a/backups/tasks.py b/backups/tasks.py
index 78c6f4b..d65c2f0 100644
--- a/backups/tasks.py
+++ b/backups/tasks.py
@@ -3,39 +3,51 @@
import re
from django.utils import timezone
-from backups.models import Backup, BackupRun
+from backups.models import Backup, BackupRun, BackupSetOfRun, BackupNotification
import os
from django.conf import settings
+from app.utils import DjangoLock
+
@task(ignore_result=True)
-def run_backup(id, mode='hourly'):
+def run_backup(id, mode='hourly', backupsetpk=None):
"""Run a backup"""
backup = Backup.objects.get(pk=id)
# Create the run
- backuprun = BackupRun(backup=backup, start_date=timezone.now())
+ backuprun = BackupRun(backup=backup, start_date=timezone.now(), type=mode)
backuprun.save()
+ def _notify_set_if_needed():
+ if backupsetpk:
+ check_end_of_backupset.delay(backupsetpk, backuprun.pk)
+
# Backup
if not backup.server_to.ssh_connection_string_from_gestion:
- print "Error: No connection from gestion"
+ print("Error: No connection from gestion")
+ _notify_set_if_needed()
return
if not backup.server_from.ssh_connection_string_from_backup:
- print "Error: No connection from backup"
+ print("Error: No connection from backup")
+ _notify_set_if_needed()
return
- os.system('ssh ' + backup.server_to.ssh_connection_string_from_gestion + ' wget ' + settings.GESTION_URL + 'backups/get_conf/' + str(backup.pk) + '/ -O /tmp/azimut-gestion-backup-config-' + str(backup.pk))
-
- to_do_string = ['rsnapshot -c /tmp/azimut-gestion-backup-config-' + str(backup.pk) + ' -v ' + mode]
-
- import subprocess
- p = subprocess.Popen(['ssh'] + backup.server_to.ssh_connection_string_from_gestion.split(' ') + [' '.join(to_do_string)], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+# os.system('ssh ' + backup.server_to.ssh_connection_string_from_gestion + ' wget ' + settings.GESTION_URL + 'backups/get_conf/' + str(backup.pk) + '/ -O /tmp/azimut-gestion-backup-config-' + str(backup.pk))
+#
+# to_do_string = ['rsnapshot -c /tmp/azimut-gestion-backup-config-' + str(backup.pk) + ' -v ' + mode]
+#
+# import subprocess
+# p = subprocess.Popen(['ssh'] + backup.server_to.ssh_connection_string_from_gestion.split(' ') + [' '.join(to_do_string)], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+#
+# out, err = p.communicate()
- out, err = p.communicate()
+ import time
+ time.sleep(10)
+ out, err = "1", "2"
backuprun.end_date = timezone.now()
backuprun.stdout = out
@@ -44,20 +56,94 @@ def run_backup(id, mode='hourly'):
try:
backuprun.nb_files = re.search('Number of files: (\d*)', out).group(1) or 0
except:
- print "Error getting nb files"
+ print("Error getting nb files")
pass
try:
backuprun.size = re.search('Total file size: (\d*)', out).group(1) or 0
except:
- print "Error getting total file size"
+ print("Error getting total file size")
pass
backuprun.save()
+ if not backuprun.nb_files or not backuprun.size:
+ bn = BackupNotification(type='bkpfailled')
+ bn.message = "The backuprun for the backup %s started at %s, ended at %s, type %s has failled:" % (backuprun.backup.name, str(backuprun.start_date), str(backuprun.end_date), mode,)
+ else:
+ bn = BackupNotification(type='bkpfailled')
+ bn.message = "The backuprun for the backup %s started at %s, ended at %s, type %s was succesfull:" % (backuprun.backup.name, str(backuprun.start_date), str(backuprun.end_date), mode,)
+
+ bn.message += "\n\n%s files where copied for a total size of %s." % (str(backuprun.nb_files), str(backuprun.size),)
+ bn.save()
+ bn.send_notifications()
+
+ _notify_set_if_needed()
+
@task(ignore_result=True)
def run_active_backups(mode):
"""Run all actives backups"""
- for bkp in Backup.objects.filter(active=True).all():
- run_backup.delay(bkp.pk, mode)
+ # If we're in hourly mode, check that the previous backup was done. (In
+ # othercases, it's ok to run more than one at a time)
+ if mode == 'hourly':
+ oldbackupruns = BackupSetOfRun.objects.filter(type='hourly', status='running').all()
+
+ if oldbackupruns:
+
+ bn = BackupNotification(type='bkpsetnotstarted')
+ bn.message = "The backupset of type %s whould should have been started at %s was not executed. A previous backupset was still running. If it's not the case, you can, after carefully checked what happened, use the interface to manually ignore the set." % (mode, str(timezone.now()),)
+
+ bn.save()
+ bn.send_notifications()
+ print("Aborting run as there is still backup runnning !")
+ return
+
+ backups_to_run = Backup.objects.filter(active=True).all()
+
+ backupset = BackupSetOfRun(type=mode)
+ backupset.save()
+
+ for bpk in backups_to_run:
+ backupset.backups.add(bpk)
+
+ backupset.save()
+
+ for bkp in backups_to_run:
+ run_backup.delay(bkp.pk, mode, backupset.pk)
+
+
+@task(ignore_result=True)
+def check_end_of_backupset(backupsetpk, backuprunpk):
+
+ l = DjangoLock(settings.BACKUP_SET_LOCK)
+
+ l.acquire()
+
+ backupset = BackupSetOfRun.objects.get(pk=backupsetpk)
+ backuprun = BackupRun.objects.get(pk=backuprunpk)
+
+ try:
+
+ backupset.backups.remove(backuprun.backup)
+ backupset.backupruns.add(backuprun)
+
+ backupset.total_size += backuprun.size
+ backupset.total_files += backuprun.nb_files
+
+ if not backupset.backups.all(): # End :)
+ backupset.end_date = timezone.now()
+ backupset.status = 'done'
+
+ bn = BackupNotification(type='bkpsetdone')
+ bn.message = "The backupset of type %s, started at %s, ended at %s (runned for %s hours) is now Done. %s files where copied for a total size of %s." % (backupset.type, str(backupset.start_date), str(backupset.end_date), str(backupset.get_total_time()), str(backupset.total_files), str(backupset.total_size))
+
+ bn.save()
+ bn.send_notifications()
+
+ backupset.save()
+
+ except Exception as e:
+ print("Error during check end of backup set !" + str(e))
+
+ l.release()
diff --git a/backups/templates/backups/backupnotifications/list.html b/backups/templates/backups/backupnotifications/list.html
new file mode 100644
index 0000000..0bb21ba
--- /dev/null
+++ b/backups/templates/backups/backupnotifications/list.html
@@ -0,0 +1,102 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+
+{% block title %}Backup notifications{% endblock %}
+
+{% block content %}
+
+
{% trans "Backups notifications" %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% trans "When" %} |
+ {% trans "Type" %} |
+ {% trans "Message" %} |
+
+
+
+ {% for elem in liste %}
+
+ {{elem.when}} ({{elem.when|timesince}}) |
+ {{elem.get_type_display}} |
+ {{elem.message}} |
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% trans "User" %} |
+ {% for key, text, label in notif_types %}
+ {{text}} |
+ {% endfor %}
+
+
+
+ {% for u, data in users_with_things %}
+
+ {{u.get_full_name}} |
+ {% for key, has in data %}
+ {{has|yesno}} |
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/backups/templates/backups/backupnotifications/switch.html b/backups/templates/backups/backupnotifications/switch.html
new file mode 100644
index 0000000..4e5cd55
--- /dev/null
+++ b/backups/templates/backups/backupnotifications/switch.html
@@ -0,0 +1 @@
+{{is_ok|yesno}}
diff --git a/backups/templates/backups/backups/_runs.html b/backups/templates/backups/backups/_runs.html
index ed0d9e3..5a2b6de 100644
--- a/backups/templates/backups/backups/_runs.html
+++ b/backups/templates/backups/backups/_runs.html
@@ -11,6 +11,7 @@
{% trans "Start date" %} |
{% trans "End date" %} |
+ {% trans "Type" %} |
{% trans "Size" %} |
{% trans "Nb files" %} |
{% trans "Stdout" %} |
@@ -22,6 +23,7 @@
{{elem.start_date|date:"Y/m/d"}} {{elem.start_date|time}} |
{% if elem.end_date %}{{elem.end_date|date}} {{elem.end_date|time}} ({{elem.end_date|timesince}}){% else %}{% trans "In progress or failled" %}{% endif %} |
+ {{elem.get_type_display}} |
{{elem.size|filesizeformat}} |
{{elem.nb_files}} |
{{elem.stdout|default:""}} |
@@ -34,4 +36,4 @@
-
\ No newline at end of file
+
diff --git a/backups/templates/backups/backups/list.html b/backups/templates/backups/backups/list.html
index f6ab0f1..4da4aad 100644
--- a/backups/templates/backups/backups/list.html
+++ b/backups/templates/backups/backups/list.html
@@ -72,7 +72,7 @@ {% trans "Backups" %}
diff --git a/backups/templates/backups/backupsets/list.html b/backups/templates/backups/backupsets/list.html
new file mode 100644
index 0000000..795bece
--- /dev/null
+++ b/backups/templates/backups/backupsets/list.html
@@ -0,0 +1,64 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+
+{% block title %}Backup sets{% endblock %}
+
+{% block content %}
+
+ {% trans "Backups sets" %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% trans "Start date" %} |
+ {% trans "End date" %} |
+ {% trans "Type" %} |
+ {% trans "Status" %} |
+ {% trans "Total time" %} |
+ {% trans "Total size" %} |
+ {% trans "Total files" %} |
+ |
+
+
+
+ {% for elem in liste %}
+
+ {{elem.start_date}} |
+ {% if elem.end_date %}{{elem.end_date}} ({{elem.end_date|timesince}}){% endif %} |
+ {{elem.get_type_display}} |
+ {{elem.get_status_display}} |
+ {{elem.get_total_time}} hours |
+ {% if elem.type == 'hourly' %}{{elem.total_size|filesizeformat}}{% endif %} |
+ {% if elem.type == 'hourly' %}{{elem.total_files}}{% endif %} |
+
+ {% if elem.status == 'running' %}
+ {% trans "Set as canceled" %}
+ {% endif %}
+ |
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/backups/urls.py b/backups/urls.py
index 99492f4..42820f7 100644
--- a/backups/urls.py
+++ b/backups/urls.py
@@ -13,5 +13,17 @@
url(r'^get_conf/(?P[0-9]*)/$', 'get_conf'),
url(r'^clean_up$', 'clean_up'),
+ url(r'^clean_up_old_sets$', 'clean_up_old_sets'),
+ url(r'^runs$', 'backupsets_list'),
+ url(r'^runs/(?P[0-9]*)/cancel$', 'backupsets_cancel'),
+
+ url(r'^notifications$', 'backupnotifications_list'),
+ url(r'^notifications/switch$', 'backupnotifications_switch'),
+ url(r'^notifications/cleanup$', 'clean_up_notifications'),
+
+ url(r'^zabbix/list/_$', 'zabbix_list'),
+ url(r'^zabbix/last_hourly_duration/_$', 'zabbix_last_hourly_duration'),
+ url(r'^zabbix/last_(?P(hourly|weekly|daily|monthly))/(?P[0-9]*)$', 'zabbix_last_nb_hours'),
+ url(r'^zabbix/last_(?P(files|size))/(?P[0-9]*)$', 'zabbix_last_files_or_size'),
)
diff --git a/backups/views.py b/backups/views.py
index f74e0b7..b18c3a9 100644
--- a/backups/views.py
+++ b/backups/views.py
@@ -16,12 +16,15 @@
from django.core.urlresolvers import reverse
from django.contrib import messages
-from backups.models import Backup, BackupRun
+from backups.models import Backup, BackupRun, BackupSetOfRun, BackupNotification, BackupUserWhoWantNotifs
from backups.forms import BackupForm
from backups.tasks import run_backup
+from django.contrib.auth.models import User
+
from django.utils import timezone
import datetime
+import json
@login_required
@@ -167,8 +170,160 @@ def get_conf(request, pk):
@staff_member_required
def clean_up(request):
- BackupRun.objects.filter(start_date__lt=timezone.now() - datetime.timedelta(days=1)).delete()
+ for b in BackupRun.objects.filter(start_date__lt=timezone.now() - datetime.timedelta(days=1)).all():
+ if b.backupsetofrun_set.count() == 0:
+ b.delete()
messages.success(request, "Old backups runs have been deleted")
return HttpResponseRedirect(reverse('backups.views.backups_list'))
+
+
+@login_required
+@staff_member_required
+def backupsets_list(request):
+ """Show the list of backup sets"""
+
+ liste = BackupSetOfRun.objects.order_by('-start_date').all()
+
+ return render_to_response('backups/backupsets/list.html', {'liste': liste}, context_instance=RequestContext(request))
+
+
+@login_required
+@staff_member_required
+def backupsets_cancel(request, pk):
+
+ backupset = get_object_or_404(BackupSetOfRun, pk=pk, status='running')
+ backupset.status = 'canceled'
+ backupset.end_date = timezone.now()
+ backupset.save()
+
+ bn = BackupNotification(type='bkpsetcanceled')
+ bn.message = "The backupset of type %s, started at %s, has been set as canceled." % (backupset.type, str(backupset.start_date), )
+ bn.save()
+ bn.send_notifications()
+
+ return HttpResponseRedirect(reverse('backups.views.backupsets_list'))
+
+
+@login_required
+@staff_member_required
+def clean_up_old_sets(request):
+
+ NB_OK = {'hourly': 6, 'daily': 7, 'weekly': 7, 'monthly': 3}
+
+ for b in BackupSetOfRun.objects.order_by('-start_date').all():
+ if NB_OK[b.type] >= 0:
+ NB_OK[b.type] -= 1
+ else:
+ b.delete()
+
+ messages.success(request, "Old backups sets have been deleted")
+
+ return HttpResponseRedirect(reverse('backups.views.backupsets_list'))
+
+
+@login_required
+@staff_member_required
+def backupnotifications_list(request):
+ """Show the list of backup notifications"""
+
+ liste = BackupNotification.objects.order_by('-when').all()
+
+ notif_types = BackupNotification.get_types_with_labels()
+
+ users_with_things = []
+
+ for u in User.objects.order_by('username').all():
+ data = []
+
+ for key, __, __ in notif_types:
+ data.append((key, BackupUserWhoWantNotifs.objects.filter(type=key, user=u).count() > 0))
+
+ users_with_things.append((u, data))
+
+ return render_to_response('backups/backupnotifications/list.html', {'liste': liste, 'notif_types': notif_types, 'users_with_things': users_with_things}, context_instance=RequestContext(request))
+
+
+@login_required
+@staff_member_required
+def backupnotifications_switch(request):
+ """Switch a backup notification"""
+
+ (obj, created) = BackupUserWhoWantNotifs.objects.get_or_create(type=request.GET.get('key'), user=get_object_or_404(User, pk=request.GET.get('uPk')))
+
+ if not created:
+ obj.delete()
+
+ return render_to_response('backups/backupnotifications/switch.html', {'is_ok': created}, context_instance=RequestContext(request))
+
+
+@login_required
+@staff_member_required
+def clean_up_notifications(request):
+
+ for b in BackupNotification.objects.filter(when__lt=timezone.now() - datetime.timedelta(days=15)).all():
+ b.delete()
+
+ messages.success(request, "Old notifications have been deleted")
+
+ return HttpResponseRedirect(reverse('backups.views.backupnotifications_list'))
+
+
+def zabbix_list(request):
+
+ data = []
+
+ for b in Backup.objects.filter(active=True).all():
+ data.append({'{#BACKUP_ID}': b.pk, '{#BACKUP_NAME}': b.name})
+
+ # return HttpResponse(build_zabbix_json(data))
+ return HttpResponse(json.dumps({'data': data}))
+
+
+def zabbix_last_nb_hours(request, pk, mode):
+
+ backup = get_object_or_404(Backup, pk=pk)
+
+ elem = backup.backuprun_set.order_by('-start_date').exclude(end_date=None).filter(type=mode)
+
+ if elem.count() == 0:
+ return HttpResponse('0')
+
+ last_elem = elem.all()[0]
+
+ diff = (timezone.now() - last_elem.start_date).total_seconds() / 3600.0
+
+ diff = int(diff)
+
+ if diff == 0:
+ diff = 1
+
+ return HttpResponse(str(diff))
+
+
+def zabbix_last_files_or_size(request, pk, mode):
+
+
+ backup = get_object_or_404(Backup, pk=pk)
+
+ elem = backup.backuprun_set.order_by('-start_date').exclude(end_date=None).filter(type='hourly')
+
+ if elem.count() == 0:
+ return HttpResponse('0')
+
+ last_elem = elem.all()[0]
+
+ val = last_elem.size if mode == 'size' else last_elem.nb_files
+
+ return HttpResponse(str(val))
+
+
+def zabbix_last_hourly_duration(request):
+
+ bs = BackupSetOfRun.objects.filter(type='hourly', status='done').exclude(total_size=0).order_by('-start_date')
+
+ if bs.count():
+ return HttpResponse(str(bs.get_total_time()))
+
+ return HttpResponse("0")
diff --git a/doc/setup.md b/doc/setup.md
index a3487fb..d4f18ac 100644
--- a/doc/setup.md
+++ b/doc/setup.md
@@ -116,4 +116,11 @@ Update `settingsLocal.py`:
Add a portforwarding entry to your ngnix server, from port 443 to port 443.
-You can now add hostnameforwarding entry from the port 443 to your server (using port 80 as destination !).
\ No newline at end of file
+You can now add hostnameforwarding entry from the port 443 to your server (using port 80 as destination !).
+
+## Zabbix
+
+To monitor backups with zabbix, add this to one of your zabbix agent
+`UserParameter=azimutgestion.[*],wget http://GESTION_HOST/backups/zabbix/$1/$2 -O - -o /dev/null`
+
+and use the zabbix template 'Azmiut-gestion: Backups'
diff --git a/doc/zabbix_template.xml b/doc/zabbix_template.xml
new file mode 100644
index 0000000..29f9dc7
--- /dev/null
+++ b/doc/zabbix_template.xml
@@ -0,0 +1,464 @@
+
+
+ 2.0
+ 2014-06-18T16:29:35Z
+
+
+ Templates
+
+
+
+
+ AzimutGestionBackups
+ Azimut-gestion: Backups
+
+
+ Templates
+
+
+
+
+ Backups of azimut-gestion
+
+
+
+ -
+ Last duration of successful hourly backup set
+ 0
+
+ 0
+
+ azimutgestion.[last_hourly_duration,_]
+ 3600
+ 90
+ 365
+ 0
+ 0
+
+ Hours
+ 0
+
+
+ 0
+ 0
+
+ 0
+
+ 1
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 0
+
+
+ Backups of azimut-gestion
+
+
+
+
+
+
+
+ Discover list of backups
+ 0
+
+
+ azimutgestion.[list,_]
+ 3600
+ 0
+
+
+
+ 0
+ 0
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+
+ :
+ 30
+
+
+
+ Last daily execution of {#BACKUP_NAME}
+ 0
+
+ 0
+
+ azimutgestion.[last_daily,{#BACKUP_ID}]
+ 3600
+ 90
+ 365
+ 0
+ 3
+
+ Hours
+ 0
+
+
+ 0
+ 0
+
+ 0
+
+ 1
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 0
+
+
+ Backups of azimut-gestion
+
+
+
+
+
+ Last hourly execution of {#BACKUP_NAME}
+ 0
+
+ 0
+
+ azimutgestion.[last_hourly,{#BACKUP_ID}]
+ 3600
+ 90
+ 365
+ 0
+ 3
+
+ Hours
+ 0
+
+
+ 0
+ 0
+
+ 0
+
+ 1
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 0
+
+
+ Backups of azimut-gestion
+
+
+
+
+
+ Last monthly execution of {#BACKUP_NAME}
+ 0
+
+ 0
+
+ azimutgestion.[last_monthly,{#BACKUP_ID}]
+ 3600
+ 90
+ 365
+ 0
+ 3
+
+ Hours
+ 0
+
+
+ 0
+ 0
+
+ 0
+
+ 1
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 0
+
+
+ Backups of azimut-gestion
+
+
+
+
+
+ Last number of files of {#BACKUP_NAME}
+ 0
+
+ 0
+
+ azimutgestion.[last_files,{#BACKUP_ID}]
+ 3600
+ 90
+ 365
+ 0
+ 3
+
+
+ 0
+
+
+ 0
+ 0
+
+ 0
+
+ 1
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 0
+
+
+ Backups of azimut-gestion
+
+
+
+
+
+ Last size of {#BACKUP_NAME}
+ 0
+
+ 0
+
+ azimutgestion.[last_size,{#BACKUP_ID}]
+ 3600
+ 90
+ 365
+ 0
+ 3
+
+
+ 0
+
+
+ 0
+ 0
+
+ 0
+
+ 1
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 0
+
+
+ Backups of azimut-gestion
+
+
+
+
+
+ Last weekly execution of {#BACKUP_NAME}
+ 0
+
+ 0
+
+ azimutgestion.[last_weekly,{#BACKUP_ID}]
+ 3600
+ 90
+ 365
+ 0
+ 3
+
+ Hours
+ 0
+
+
+ 0
+ 0
+
+ 0
+
+ 1
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ 0
+
+
+ Backups of azimut-gestion
+
+
+
+
+
+
+
+ {AzimutGestionBackups:azimutgestion.[last_daily,{#BACKUP_ID}].last(0)}<1
+ Daily backup of {#BACKUP_NAME} has not been executed recentily
+
+ 0
+ 2
+
+ 0
+
+
+ {AzimutGestionBackups:azimutgestion.[last_daily,{#BACKUP_ID}].last(0)}>28
+ Daily backup of {#BACKUP_NAME} is too old
+
+ 0
+ 4
+
+ 0
+
+
+ {AzimutGestionBackups:azimutgestion.[last_hourly,{#BACKUP_ID}].last(0)}<1
+ Hourly backup of {#BACKUP_NAME} has not been executed recentily
+
+ 0
+ 2
+
+ 0
+
+
+ {AzimutGestionBackups:azimutgestion.[last_hourly,{#BACKUP_ID}].last(0)}>8
+ Hourly backup of {#BACKUP_NAME} is too old
+
+ 0
+ 4
+
+ 0
+
+
+ {AzimutGestionBackups:azimutgestion.[last_files,{#BACKUP_ID}].last(0)}<1
+ Last number of files of {#BACKUP_NAME} is not ok
+
+ 0
+ 4
+
+ 0
+
+
+ {AzimutGestionBackups:azimutgestion.[last_size,{#BACKUP_ID}].last(0)}<1
+ Last size of {#BACKUP_NAME} is not ok
+
+ 0
+ 4
+
+ 0
+
+
+ {AzimutGestionBackups:azimutgestion.[last_monthly,{#BACKUP_ID}].last(0)}<1
+ Monthly backup of {#BACKUP_NAME} has not been executed recentily
+
+ 0
+ 2
+
+ 0
+
+
+ {AzimutGestionBackups:azimutgestion.[last_monthly,{#BACKUP_ID}].last(0)}>748
+ Monthly backup of {#BACKUP_NAME} is too old
+
+ 0
+ 4
+
+ 0
+
+
+ {AzimutGestionBackups:azimutgestion.[last_weekly,{#BACKUP_ID}].last(0)}<1
+ Weekly backup of {#BACKUP_NAME} has not been executed recentily
+
+ 0
+ 2
+
+ 0
+
+
+ {AzimutGestionBackups:azimutgestion.[last_weekly,{#BACKUP_ID}].last(0)}>172
+ Weekly backup of {#BACKUP_NAME} is too old
+
+ 0
+ 4
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {AzimutGestionBackups:azimutgestion.[last_hourly_duration,_].last(0)}>4.0
+ Last hourly set was too slow
+
+ 0
+ 3
+
+ 0
+
+
+
+
diff --git a/main/templates/main/_backupset.html b/main/templates/main/_backupset.html
new file mode 100644
index 0000000..c825b21
--- /dev/null
+++ b/main/templates/main/_backupset.html
@@ -0,0 +1,9 @@
+{% if b %}
+
+ {{b.get_type_display}} |
+ {{b.start_date|timesince}}
+ | {{b.get_status_display}} |
+ {{b.get_total_time}} hours |
+ {% if b.type == 'hourly' %}{{b.total_size|filesizeformat}}{% endif %} |
+
+{% endif %}
diff --git a/main/templates/main/_backupsets.html b/main/templates/main/_backupsets.html
new file mode 100644
index 0000000..82be248
--- /dev/null
+++ b/main/templates/main/_backupsets.html
@@ -0,0 +1,22 @@
+{% load i18n %}
+
+
+
+
+
+
+
+ {% trans "Type" %} | {% trans "Last backup" %} | {% trans "Status" %} | {% trans "Total time" %} | Size |
+ {% with last_hourlys.0 as b %}{% include "main/_backupset.html" %}{% endwith %}
+ {% with last_hourlys.1 as b %}{% include "main/_backupset.html" %}{% endwith %}
+ {% with last_daily.0 as b %}{% include "main/_backupset.html" %}{% endwith %}
+ {% with last_daily.1 as b %}{% include "main/_backupset.html" %}{% endwith %}
+ {% with last_weekly.0 as b %}{% include "main/_backupset.html" %}{% endwith %}
+ {% with last_weekly.1 as b %}{% include "main/_backupset.html" %}{% endwith %}
+ {% with last_monthly.0 as b %}{% include "main/_backupset.html" %}{% endwith %}
+ {% with last_monthly.1 as b %}{% include "main/_backupset.html" %}{% endwith %}
+
+
+
diff --git a/main/templates/main/home.html b/main/templates/main/home.html
index 8ef74ea..5489684 100644
--- a/main/templates/main/home.html
+++ b/main/templates/main/home.html
@@ -14,6 +14,7 @@ {% trans "Welcome !" %}
+ {% include "main/_backupsets.html" %}
{% include "main/_backups.html" %}
@@ -21,4 +22,4 @@ {% trans "Welcome !" %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/main/views.py b/main/views.py
index 36c118c..2d14dad 100644
--- a/main/views.py
+++ b/main/views.py
@@ -23,7 +23,7 @@
from main.models import SshKey
from groups.models import Group
from main.tasks import update_git_repo
-from backups.models import Backup
+from backups.models import Backup, BackupSetOfRun
from servers.models import Server
@@ -48,7 +48,12 @@ def home(request):
backups = Backup.objects.order_by('name').all()
- return render_to_response('main/home.html', {'backups': backups}, context_instance=RequestContext(request))
+ last_hourlys = BackupSetOfRun.objects.order_by('-start_date').filter(type='hourly').all()
+ last_daily = BackupSetOfRun.objects.order_by('-start_date').filter(type='daily').all()
+ last_weekly = BackupSetOfRun.objects.order_by('-start_date').filter(type='weekly').all()
+ last_monthly = BackupSetOfRun.objects.order_by('-start_date').filter(type='monthly').all()
+
+ return render_to_response('main/home.html', {'backups': backups, 'last_daily': last_daily, 'last_weekly': last_weekly, 'last_hourlys': last_hourlys, 'last_monthly': last_monthly}, context_instance=RequestContext(request))
@login_required
diff --git a/templates/base.html b/templates/base.html
index 16e6d86..ab0d1d3 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -118,6 +118,12 @@
+
+