diff --git a/.gitignore b/.gitignore
index 7e99e36..4f47d0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-*.pyc
\ No newline at end of file
+*.pyc
+.ropeproject/
diff --git a/app/settings.py b/app/settings.py
index b8f2dec..f966f70 100644
--- a/app/settings.py
+++ b/app/settings.py
@@ -103,7 +103,7 @@
'main',
'servers',
- 'groups',
+ 'groups',
'keymanager',
'hostnameforwarding',
'portforwarding',
@@ -112,6 +112,7 @@
'fabrun',
'wizard',
'samba',
+ 'logstash',
)
LOGGING = {
@@ -157,6 +158,10 @@
CREATE_VM_STORAGE = 'local'
+FORCE_SECURE_FOR_USER = False
+
+NGNIX_DEFAULT_REDIRECT = ''
+
try:
from settingsLocal import *
except ImportError:
diff --git a/app/settingsLocal.py.dist b/app/settingsLocal.py.dist
index b7d0688..1a54b17 100644
--- a/app/settingsLocal.py.dist
+++ b/app/settingsLocal.py.dist
@@ -47,3 +47,10 @@ BROKER_URL = ''
NGNIX_SSL_PEM = ''
NGNIX_SSL_KEY = ''
+
+LOGSTASH_SERVER = ''
+
+MYSQL_USERNAME = ''
+MYSQL_PASSWORD = ''
+
+NGNIX_DEFAULT_REDIRECT = ''
diff --git a/app/urls.py b/app/urls.py
index a0a2ad2..01dde56 100644
--- a/app/urls.py
+++ b/app/urls.py
@@ -18,6 +18,7 @@
url(r'^fabrun/', include('fabrun.urls')),
url(r'^wizards/', include('wizard.urls')),
url(r'^samba/', include('samba.urls')),
+ url(r'^logstash/', include('logstash.urls')),
(r'^users/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
(r'^users/logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}),
diff --git a/backups/templates/backups/backups/show.html b/backups/templates/backups/backups/show.html
index 39ab726..4132b61 100644
--- a/backups/templates/backups/backups/show.html
+++ b/backups/templates/backups/backups/show.html
@@ -66,10 +66,12 @@
{{object.name}}
+ {% if user.is_staff %}
+ {% trans "Force execution" %}
+ {% trans "Back to the list" %}
+ {% trans "Edit" %}
+ {% endif %}
+
diff --git a/backups/views.py b/backups/views.py
index 994c642..f74e0b7 100644
--- a/backups/views.py
+++ b/backups/views.py
@@ -35,12 +35,14 @@ def backups_list(request):
@login_required
-@staff_member_required
def backups_show(request, pk):
- """Show details of a hostname forwarder"""
+ """Show details of a backup"""
object = get_object_or_404(Backup, pk=pk)
+ if not request.user.is_staff and (request.user not in object.server_from.users_owning_the_server.all() and request.user not in object.server_to.users_owning_the_server.all()):
+ raise Http404
+
liste = object.backuprun_set.order_by('-start_date').all()
return render_to_response('backups/backups/show.html', {'object': object, 'liste': liste}, context_instance=RequestContext(request))
diff --git a/fabrun/views.py b/fabrun/views.py
index 7ce0512..cd21e0f 100644
--- a/fabrun/views.py
+++ b/fabrun/views.py
@@ -91,7 +91,7 @@ def show_run(request, pk):
@staff_member_required
def clean_up(request):
- Task.objects.filter(creation_date__lt = timezone.now() - datetime.timedelta(days=1)).delete()
+ Task.objects.filter(creation_date__lt=timezone.now() - datetime.timedelta(days=1)).delete()
messages.success(request, "Old fabric runs have been deleted")
diff --git a/hostnameforwarding/views.py b/hostnameforwarding/views.py
index 8fbad8f..c5d4a3e 100644
--- a/hostnameforwarding/views.py
+++ b/hostnameforwarding/views.py
@@ -138,7 +138,14 @@ def get_conf(request, pk):
root /usr/share/nginx/www;
index index.html index.htm;
+"""
+
+ if settings.NGNIX_DEFAULT_REDIRECT:
+ script += """
+ return 301 """ + settings.NGNIX_DEFAULT_REDIRECT + """;
+"""
+ script += """
server_name localhost;
}
diff --git a/keymanager/views.py b/keymanager/views.py
index 9751aec..70f7349 100644
--- a/keymanager/views.py
+++ b/keymanager/views.py
@@ -63,4 +63,10 @@ def get_keys(request, server, user):
if key.key not in ssh_keys:
ssh_keys.append(key.key)
+ # Allow each user who 'own' the server
+ for user in server.users_owning_the_server.all():
+ for key in user.sshkey_set.all():
+ if key.key not in ssh_keys:
+ ssh_keys.append(key.key)
+
return render_to_response('keymanager/get_keys.html', {'ssh_keys': ssh_keys}, context_instance=RequestContext(request))
diff --git a/logstash/__init__.py b/logstash/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/logstash/forms.py b/logstash/forms.py
new file mode 100644
index 0000000..497077a
--- /dev/null
+++ b/logstash/forms.py
@@ -0,0 +1,16 @@
+from django.forms import ModelForm
+
+from logstash.models import File
+
+from servers.models import Server
+
+
+class FileForm(ModelForm):
+ class Meta:
+ model = File
+ exclude = ()
+
+ def __init__(self, *args, **kwargs):
+ super(FileForm, self).__init__(*args, **kwargs)
+
+ self.fields["server"].queryset = Server.objects.order_by('name').filter(logstash_shipper=True)
diff --git a/logstash/migrations/0001_initial.py b/logstash/migrations/0001_initial.py
new file mode 100644
index 0000000..09ce04c
--- /dev/null
+++ b/logstash/migrations/0001_initial.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'File'
+ db.create_table(u'logstash_file', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('server', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['servers.Server'])),
+ ('file', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('type', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('tags', self.gf('django.db.models.fields.CharField')(max_length=512)),
+ ))
+ db.send_create_signal(u'logstash', ['File'])
+
+
+ def backwards(self, orm):
+ # Deleting model 'File'
+ db.delete_table(u'logstash_file')
+
+
+ models = {
+ u'logstash.file': {
+ 'Meta': {'object_name': 'File'},
+ 'file': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"}),
+ 'tags': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 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'}),
+ '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']"}),
+ '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'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ }
+ }
+
+ complete_apps = ['logstash']
\ No newline at end of file
diff --git a/logstash/migrations/0002_auto__add_execution.py b/logstash/migrations/0002_auto__add_execution.py
new file mode 100644
index 0000000..1d40fd3
--- /dev/null
+++ b/logstash/migrations/0002_auto__add_execution.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'Execution'
+ db.create_table(u'logstash_execution', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('output', self.gf('django.db.models.fields.TextField')()),
+ ('done', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('sugested_result', self.gf('django.db.models.fields.TextField')()),
+ ))
+ db.send_create_signal(u'logstash', ['Execution'])
+
+
+ def backwards(self, orm):
+ # Deleting model 'Execution'
+ db.delete_table(u'logstash_execution')
+
+
+ models = {
+ u'logstash.execution': {
+ 'Meta': {'object_name': 'Execution'},
+ 'done': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'output': ('django.db.models.fields.TextField', [], {}),
+ 'sugested_result': ('django.db.models.fields.TextField', [], {})
+ },
+ u'logstash.file': {
+ 'Meta': {'object_name': 'File'},
+ 'file': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"}),
+ 'tags': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 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'}),
+ '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']"}),
+ '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'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ }
+ }
+
+ complete_apps = ['logstash']
\ No newline at end of file
diff --git a/logstash/migrations/__init__.py b/logstash/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/logstash/models.py b/logstash/models.py
new file mode 100644
index 0000000..131d20c
--- /dev/null
+++ b/logstash/models.py
@@ -0,0 +1,30 @@
+from django.db import models
+
+
+from servers.models import Server
+
+
+class File(models.Model):
+ """A file to monitor"""
+
+ server = models.ForeignKey(Server)
+
+ file = models.CharField(max_length=255)
+
+ TYPE_CHOICES = (('apachelog', 'Apache log'), ('syslog', 'Syslog'), ('misc', 'Misc'))
+ type = models.CharField(max_length=255, choices=TYPE_CHOICES)
+
+ tags = models.CharField(max_length=512)
+
+ def sorted_tags(self):
+ """Return the list of tags, sorted"""
+ return ','.join(sorted(self.tags.split(',')))
+
+
+
+
+class Execution(models.Model):
+
+ output = models.TextField()
+ done = models.BooleanField(default=False)
+ sugested_result = models.TextField()
diff --git a/logstash/tasks.py b/logstash/tasks.py
new file mode 100644
index 0000000..ca4cb9b
--- /dev/null
+++ b/logstash/tasks.py
@@ -0,0 +1,145 @@
+from celery import task
+
+from servers.models import Server
+import os
+from django.conf import settings
+import subprocess
+from logstash.models import Execution
+import json
+from proxmoxs.views import gimme_prox_cox
+
+
+@task(ignore_result=True)
+def do_autodetection(expk):
+ """Do automatic detection of logstash config"""
+
+ ex = Execution.objects.get(pk=expk)
+
+ ex.output += 'Sarting execution\n'
+ ex.save()
+
+ def work_on_host(server, base_tags, base_path, no_vhost_check=True):
+ """Work on host"""
+
+ things_to_checks = []
+
+ def check_file(file, type, file_tags):
+
+ things_to_checks.append((base_path + file, type, file_tags + base_tags))
+
+ def do_query(query):
+ p = subprocess.Popen(['ssh'] + server.ssh_connection_string_from_gestion.split(' ') + ["cat - | sh"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=1)
+ return p.communicate(query + '\nexit')[0].split()
+
+ ex.output += '---Checking common files\n'
+ ex.save()
+
+ # Syslog
+ check_file('/var/log/syslog', 'syslog', ['syslog'])
+
+ # Auth.log
+ check_file('/var/log/auth.log', 'syslog', ['auth.log'])
+
+ # Apache logs
+ ex.output += '---Checking apache logs\n'
+ ex.save()
+
+ for folder in ['apache2', 'httpd']:
+ for prefix in ['', 'ssl_', 'others_vhost_']:
+ for end in ['.log', '_log']:
+ for postfix in ['', '_ssl']:
+ check_file('/var/log/' + folder + '/' + prefix + 'access' + postfix + end, 'apachelog', ['access.log'])
+ check_file('/var/log/' + folder + '/' + prefix + 'error' + postfix + end, 'apachelog', ['error.log'])
+
+ # Ngnix log
+ ex.output += '---Checking ngnix logs\n'
+ ex.save()
+
+ check_file('/var/log/nginx.log', 'nginxlog', ['ngnix.log'])
+ check_file('/var/log/error.log', 'nginxerrlog', ['ngnixerror.log'])
+
+ # Mysql log
+ ex.output += '---Checking mysql logs\n'
+ ex.save()
+
+ check_file('/var/log/mysql.log', 'mysqllog', ['mysql.log'])
+ check_file('/var/log/mysql.err', 'mysqlerrlog', ['mysqlerror.log'])
+
+ if not no_vhost_check:
+ # Apache logs by vhost,
+ ex.output += '---Checking apache logs in vhost folders\n'
+ ex.save()
+
+ base_list = do_query('for x in `ls /var/www/vhosts/*/logs/*/access_log`; do echo $x; done') + do_query('for x in `ls /var/www/vhosts/*/logs/access_log`; do echo $x; done')
+
+ for elem in base_list:
+ bpath = '/'.join(elem.split('/')[:-1]) + '/'
+ tag = elem.split('/')[-2]
+
+ check_file(bpath + 'access_log', 'apachelog', ['access.log', tag])
+ check_file(bpath + 'access_ssl_log', 'apachelog', ['access.log', tag])
+ check_file(bpath + 'error_log', 'apachelog', ['error.log', tag])
+
+ # Do check in one pass
+ entries_list = []
+
+ output = do_query('\n'.join(['ls ' + x[0] + ' 2>/dev/null' for x in things_to_checks]))
+
+ for (path, type, tags) in things_to_checks:
+
+ if path in output:
+ entries_list.append((path, type, ','.join(sorted(tags)), server.pk))
+ ex.output += '---' + path + ': ' + type + '\n'
+
+ ex.save()
+
+ return entries_list
+
+ retour = []
+
+ # Get all shipper
+ for s in Server.objects.filter(logstash_shipper=True).all():
+ ex.output += 'Working on ' + s.name + '\n'
+ ex.save()
+
+ bn = s.name.split('.')[-2]
+
+ tags = [bn, s.name]
+
+ if s.is_proxmox:
+ tags.append('proxmox')
+
+ # Do normal checks
+ retour += work_on_host(s, tags, '', no_vhost_check=s.is_proxmox) # If not proxmox, check vhosts
+
+ # If proxmox, check subvms
+ if s.is_proxmox:
+
+ vm_ids = {}
+
+ proxretour = gimme_prox_cox(s.ip_for_proxmox()).getNodeContainerIndex(s.proxmox_node_name)
+
+ if 'data' in proxretour:
+ for elem in proxretour['data']:
+ vm_ids[elem['ip']] = elem['vmid']
+
+ for proxmox in s.server_set.all():
+ tags = [bn, proxmox.name, 'vm']
+
+ if proxmox.internal_ip in vm_ids:
+ id = vm_ids[proxmox.internal_ip]
+
+ ex.output += 'Working on ' + proxmox.name + ', proxmox vm\n'
+ ex.save()
+
+ retour += work_on_host(s, tags, '/var/lib/vz/root/' + str(id))
+ else:
+
+ ex.output += 'Cannot work on ' + proxmox.name + ', no id\n'
+ ex.save()
+
+ ex.sugested_result = json.dumps(retour)
+
+ ex.output += 'Done !\n'
+ ex.done = True
+ ex.save()
diff --git a/logstash/templates/logstash/autodetect/final.html b/logstash/templates/logstash/autodetect/final.html
new file mode 100644
index 0000000..c004845
--- /dev/null
+++ b/logstash/templates/logstash/autodetect/final.html
@@ -0,0 +1,81 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load bootstrap_toolkit %}
+
+
+{% block title %}Logstash{% endblock %}
+
+{% block content %}
+
+ Automatic detection
+
+
+
+
+
+
+{% endblock %}
+
diff --git a/logstash/templates/logstash/autodetect/watch.html b/logstash/templates/logstash/autodetect/watch.html
new file mode 100644
index 0000000..464bf11
--- /dev/null
+++ b/logstash/templates/logstash/autodetect/watch.html
@@ -0,0 +1,57 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load bootstrap_toolkit %}
+
+
+{% block title %}Logstash{% endblock %}
+
+{% block content %}
+
+ Automatic detection
+
+
+
+
+
+
+
+
+{% endblock %}
+
diff --git a/logstash/templates/logstash/files/edit.html b/logstash/templates/logstash/files/edit.html
new file mode 100644
index 0000000..66ba201
--- /dev/null
+++ b/logstash/templates/logstash/files/edit.html
@@ -0,0 +1,49 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load bootstrap_toolkit %}
+
+
+{% block title %}Logstash{% endblock %}
+
+{% block content %}
+
+ {% trans "File management" %}
+
+
+
+
+
+
+
+
+{% endblock %}
+
diff --git a/logstash/templates/logstash/files/list.html b/logstash/templates/logstash/files/list.html
new file mode 100644
index 0000000..7697312
--- /dev/null
+++ b/logstash/templates/logstash/files/list.html
@@ -0,0 +1,63 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load bootstrap_toolkit %}
+
+
+{% block title %}LogStash{% endblock %}
+
+{% block content %}
+
+ Monitored files
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% trans "File" %}
+ {% trans "Server" %}
+ {% trans "Type" %}
+ {% trans "Tags" %}
+
+
+
+
+ {% for elem in liste %}
+
+ {{elem.file}}
+ {{elem.server}}
+ {{elem.type}}
+ {{elem.sorted_tags}}
+
+ {% trans "Delete" %}
+ {% trans "Edit" %}
+
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
+
diff --git a/logstash/templates/logstash/files/show.html b/logstash/templates/logstash/files/show.html
new file mode 100644
index 0000000..b2015fa
--- /dev/null
+++ b/logstash/templates/logstash/files/show.html
@@ -0,0 +1,84 @@
+{% extends "base.html" %}
+{% load i18n %}
+{% load bootstrap_toolkit %}
+
+
+{% block title %}Logstash{% endblock %}
+
+{% block content %}
+
+
+ {{object.file}}
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/logstash/tests.py b/logstash/tests.py
new file mode 100644
index 0000000..501deb7
--- /dev/null
+++ b/logstash/tests.py
@@ -0,0 +1,16 @@
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.assertEqual(1 + 1, 2)
diff --git a/logstash/urls.py b/logstash/urls.py
new file mode 100644
index 0000000..f2d4206
--- /dev/null
+++ b/logstash/urls.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns(
+ 'logstash.views',
+
+ url(r'^$', 'file_list'),
+ url(r'^(?P[0-9]*)/show/$', 'file_show'),
+ url(r'^(?P[0-9]*)/edit/$', 'file_edit'),
+ url(r'^(?P[0-9]*)/delete/$', 'file_delete'),
+
+ url(r'^(?P.*)/shipper.conf$', 'generate_config'),
+
+ url(r'^auto$', 'start_autodetect'),
+ url(r'^auto/(?P[0-9]*)$', 'watch_autodetect'),
+ url(r'^auto/w/(?P[0-9]*)$', 'watch_get_status'),
+ url(r'^auto/confirm/(?P[0-9]*)$', 'watch_final'),
+
+)
diff --git a/logstash/views.py b/logstash/views.py
new file mode 100644
index 0000000..b53985b
--- /dev/null
+++ b/logstash/views.py
@@ -0,0 +1,256 @@
+# -*- coding: utf-8 -*-
+
+from django.shortcuts import get_object_or_404, render_to_response, redirect
+from django.template import RequestContext
+from django.core.context_processors import csrf
+from django.views.decorators.csrf import csrf_exempt
+from django.http import Http404, HttpResponse, HttpResponseForbidden, HttpResponseNotFound
+from django.utils.encoding import smart_str
+from django.conf import settings
+from django.contrib.admin.views.decorators import staff_member_required
+from django.contrib.auth.decorators import login_required
+from django.http import HttpResponseRedirect
+from django.db import connections
+from django.core.paginator import InvalidPage, EmptyPage, Paginator
+from django.core.cache import cache
+from django.core.urlresolvers import reverse
+from django.contrib import messages
+
+from servers.models import Server
+from logstash.models import File, Execution
+from logstash.forms import FileForm
+from logstash.tasks import do_autodetection
+
+import json
+
+
+@login_required
+@staff_member_required
+def file_list(request):
+ """Show the home page with the list of monitored files"""
+
+ liste = File.objects.order_by('file').all()
+
+ return render_to_response('logstash/files/list.html', {'liste': liste}, context_instance=RequestContext(request))
+
+
+@login_required
+@staff_member_required
+def file_show(request, pk):
+ """Show details of an file"""
+
+ object = get_object_or_404(File, pk=pk)
+
+ return render_to_response('logstash/files/show.html', {'object': object}, context_instance=RequestContext(request))
+
+
+@login_required
+@staff_member_required
+def file_edit(request, pk):
+ """Edit an file"""
+
+ try:
+ object = File.objects.get(pk=pk)
+ except:
+ object = File()
+
+ if request.method == 'POST': # If the form has been submitted...
+ form = FileForm(request.POST, instance=object)
+
+ if form.is_valid(): # If the form is valid
+ object = form.save()
+
+ messages.success(request, 'The file has been saved.')
+
+ return redirect(reverse('logstash.views.file_list'))
+ else:
+ form = FileForm(instance=object)
+
+ tags = []
+
+ for f in File.objects.all():
+ for t in f.tags.split(','):
+ if t not in tags:
+ tags.append(t)
+
+ return render_to_response('logstash/files/edit.html', {'form': form, 'tags': tags}, context_instance=RequestContext(request))
+
+
+@login_required
+@staff_member_required
+def file_delete(request, pk):
+ """Delete an file"""
+
+ object = get_object_or_404(File, pk=pk)
+
+ object.delete()
+
+ messages.success(request, 'File has been deleted.')
+
+ return redirect(reverse('logstash.views.file_list', args=()))
+
+
+def generate_config(request, name):
+ """Generate logstash shipper config"""
+
+ server = get_object_or_404(Server, logstash_shipper=True, name=name)
+
+ config = """input {
+
+ """
+
+ for file in server.file_set.all():
+ config += """file {
+ type => \"""" + file.type + """\"
+ path => [ \"""" + file.file + """\" ]
+ tags => [ """ + ','.join(['"' + x + '"' for x in file.tags.split(',')]) + """ ]
+ sincedb_path => "/var/cache/logstash/.sincedb"
+ }
+"""
+
+ config += """
+}
+
+filter {
+ if [type] == "apachelog" {
+ grok {
+ match => { "message" => "%{IPORHOST:clientip} %{USER:ident} %{USER:auth} \[%{HTTPDATE:timestamp}\] \\"(?:%{WORD:verb} %{URIPATHPARAM:request}(?: HTTP/%{NUMBER:httpversion})?|-)\\" %{NUMBER:response} (?:%{NUMBER:bytes}|-)" }
+ }
+
+ date {
+ match => { "timestamp" => "dd/MMM/yyyy:HH:mm:ss Z" }
+ }
+ }
+
+ if [type] == "syslog" {
+
+ grok {
+ pattern => [ "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\\[%{POSINT:syslog_pid}\\])?: %{GREEDYDATA:syslog_message}" ]
+ add_field => [ "received_at", "%{@timestamp}" ]
+ }
+
+ date {
+ match => [ "syslog_timestamp", "MMM d HH:mm:ss", "MMM dd HH:mm:ss" ]
+ }
+ if !("_grokparsefailure" in [tags]) {
+ mutate {
+ replace => [ "@source_host", "%{syslog_hostname}" ]
+ replace => [ "message", "%{syslog_message}" ]
+ }
+ }
+
+ mutate {
+ remove => [ "syslog_hostname", "syslog_message", "syslog_timestamp" ]
+ }
+ }
+
+ if [type] == "nginxlog" {
+ grok {
+ match => { "message" => "%{IPORHOST:clientip} %{GREEDYDATA:ident} %{GREEDYDATA:auth} \\[%{HTTPDATE:timestamp}\\] \\"%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}\\" %{NUMBER:response} (?:%{NUMBER:bytes}|-) (?:\\"(?:%{URI:referrer}|-)\\"|%{QS:referrer}) %{QS:agent} %{QS:xforwardedfor} %{IPORHOST:host} %{BASE10NUM:request_duration}" }
+ }
+
+ date {
+ match => { "timestamp" => "dd/MMM/yyyy:HH:mm:ss Z" }
+ }
+ }
+
+ if [type] == "nginxerrlog" {
+ grok {
+ match => { "message" => "%{DATESTAMP:timestamp} %{GREEDYDATA:message}, client: %{IP:clientip}, server: %{IPORHOST:host}, request: \\"%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}\\", upstream: \\"%{URI:upstream}\\", host: \\"%{IPORHOST:host}\\", referrer: \\"%{URI:referrer}\\"" }
+ }
+
+ date {
+ match => { "timestamp" => "yyyy/mm/dd HH:mm:ss" }
+ }
+ }
+
+}
+
+output {
+ redis { host => \"""" + settings.LOGSTASH_SERVER + """\" data_type => "list" key => "logstash" }
+}
+"""
+ return HttpResponse(config)
+
+
+@login_required
+@staff_member_required
+def start_autodetect(request):
+ """Start automatic detection"""
+
+ e = Execution()
+ e.save()
+
+ do_autodetection.delay(e.pk)
+
+ return redirect(reverse('logstash.views.watch_autodetect', args=(e.pk,)))
+
+
+@login_required
+@staff_member_required
+def watch_autodetect(request, key):
+ """Watch automatic detection"""
+
+ ex = get_object_or_404(Execution, pk=key)
+
+ return render_to_response('logstash/autodetect/watch.html', {'ex': ex}, context_instance=RequestContext(request))
+
+
+@login_required
+@staff_member_required
+def watch_get_status(request, key):
+ """Return current status about automatic detection"""
+
+ ex = get_object_or_404(Execution, pk=key)
+
+ sta = 'd' if ex.done else 'r'
+
+ return HttpResponse(sta + ex.output)
+
+
+@login_required
+@staff_member_required
+def watch_final(request, key):
+ """Final step for automatic detection: Display results and save"""
+
+ ex = get_object_or_404(Execution, pk=key)
+
+ if request.method == 'POST':
+
+ for elem in request.POST.getlist('todel[]'):
+ File.objects.get(pk=elem).delete()
+
+ for elem in request.POST.getlist('toadd[]'):
+ file, type, tags, server_pk = json.loads(elem)
+ server = Server.objects.get(pk=server_pk)
+
+ File(file=file, type=type, tags=tags, server=server).save()
+
+ messages.success(request, 'The file list has been updated !')
+ return redirect(reverse('logstash.views.file_list'))
+
+ toadd = []
+ todel = []
+
+ data = json.loads(ex.sugested_result)
+
+ for elem in data:
+ toadd.append(json.dumps(elem))
+
+ for file in File.objects.all():
+ json_repr = json.dumps((file.file, file.type, file.sorted_tags(), file.server.pk))
+
+ if json_repr in toadd:
+ toadd.remove(json_repr)
+ else:
+ todel.append(file)
+
+ toadd_with_data = []
+
+ for elem in toadd:
+ file, type, tags, server_pk = json.loads(elem)
+ server = Server.objects.get(pk=server_pk)
+
+ toadd_with_data.append((file, type, tags, server, elem))
+
+ return render_to_response('logstash/autodetect/final.html', {'ex': ex, 'toadd': toadd_with_data, 'todel': todel}, context_instance=RequestContext(request))
diff --git a/main/templates/main/users/_servers.html b/main/templates/main/users/_servers.html
new file mode 100644
index 0000000..57ca19c
--- /dev/null
+++ b/main/templates/main/users/_servers.html
@@ -0,0 +1,46 @@
+{% load i18n %}
+
+
+
+
+
+
+
+
+ {% if user.is_staff %}
+
+
+
+ {% for s in servers %}
+ {{s}}
+ {% endfor %}
+
+ {% trans "Add" %}
+
+ {% endif %}
+
+
+
+
+
+
diff --git a/main/templates/main/users/show.html b/main/templates/main/users/show.html
index 57ada57..f01b40f 100644
--- a/main/templates/main/users/show.html
+++ b/main/templates/main/users/show.html
@@ -86,6 +86,10 @@ {{user.username}}
{% include "main/users/_groups.html" %}
+
+ {% include "main/users/_servers.html" %}
+
+
{% endblock %}
diff --git a/main/urls.py b/main/urls.py
index 782e553..791de7a 100644
--- a/main/urls.py
+++ b/main/urls.py
@@ -6,7 +6,8 @@
urlpatterns = patterns(
'main.views',
- url(r'^$', 'home'),
+ url(r'^$', 'home_redirect'),
+ url(r'^home/$', 'home'),
url(r'^about/me$', 'me'),
url(r'^about/me/edit$', 'me_edit'),
@@ -30,5 +31,8 @@
url(r'^users/groups/add/(?P[0-9]*)$', 'users_groups_add'),
url(r'^users/groups/delete/(?P[0-9]*)/(?P[0-9]*)$', 'users_groups_delete'),
+ url(r'^users/servers/add/(?P[0-9]*)$', 'users_server_add'),
+ url(r'^users/servers/delete/(?P[0-9]*)/(?P[0-9]*)$', 'users_server_delete'),
+
url(r'^git_hook/(?P.*)/$', 'git_hook'),
)
diff --git a/main/views.py b/main/views.py
index 3013fa0..36c118c 100644
--- a/main/views.py
+++ b/main/views.py
@@ -24,12 +24,28 @@
from groups.models import Group
from main.tasks import update_git_repo
from backups.models import Backup
+from servers.models import Server
+
+
+def home_redirect(request):
+ """Redirect the user to the home page, forcing HTTPs if needed. As the real home force authentification, this try to force https for the login too"""
+
+ if not request.is_secure() and settings.FORCE_SECURE_FOR_USER:
+ return HttpResponseRedirect('https://' + request.get_host() + request.path)
+
+ r = redirect('main.views.home')
+ if settings.FORCE_SECURE_FOR_USER:
+ r['Strict-Transport-Security'] = 'max-age=31536000'
+ return r
@login_required
def home(request):
"""Show the welcome page"""
+ if not request.is_secure() and settings.FORCE_SECURE_FOR_USER:
+ return HttpResponseRedirect('https://' + request.get_host() + request.path)
+
backups = Backup.objects.order_by('name').all()
return render_to_response('main/home.html', {'backups': backups}, context_instance=RequestContext(request))
@@ -60,8 +76,9 @@ def users_show(request, pk):
object = get_object_or_404(User, pk=pk)
groups = Group.objects.exclude(users=object).order_by('name').all()
+ servers = Server.objects.exclude(users_owning_the_server=object).order_by('name').all()
- return render_to_response('main/users/show.html', {'object': object, 'groups': groups}, context_instance=RequestContext(request))
+ return render_to_response('main/users/show.html', {'object': object, 'groups': groups, 'servers': servers}, context_instance=RequestContext(request))
@login_required
@@ -312,3 +329,35 @@ def git_hook(request, id):
update_git_repo.delay(id)
return HttpResponse('Happy')
+
+
+@login_required
+@staff_member_required
+def users_server_add(request, pk):
+ """Add a user to a server access"""
+
+ user = get_object_or_404(User, pk=pk)
+
+ server = get_object_or_404(Server, pk=request.GET.get('serverPk'))
+
+ server.users_owning_the_server.add(user)
+
+ messages.success(request, 'The user has been added to the server.')
+
+ return redirect(reverse('main.views.users_show', args=(pk, )))
+
+
+@login_required
+@staff_member_required
+def users_server_delete(request, pk, serverPk):
+ """Delete an user from a server access"""
+
+ user = get_object_or_404(User, pk=pk)
+
+ server = get_object_or_404(Server, pk=serverPk)
+
+ server.users_owning_the_server.remove(user)
+
+ messages.success(request, 'The user has been removed from the server.')
+
+ return redirect(reverse('main.views.users_show', args=(pk, )))
diff --git a/servers/migrations/0014_auto__add_field_server_logstash_shipper.py b/servers/migrations/0014_auto__add_field_server_logstash_shipper.py
new file mode 100644
index 0000000..37aaeb9
--- /dev/null
+++ b/servers/migrations/0014_auto__add_field_server_logstash_shipper.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Server.logstash_shipper'
+ db.add_column(u'servers_server', 'logstash_shipper',
+ self.gf('django.db.models.fields.BooleanField')(default=False),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Server.logstash_shipper'
+ db.delete_column(u'servers_server', 'logstash_shipper')
+
+
+ models = {
+ 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'}),
+ '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']"}),
+ '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'}),
+ 'vm_host': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'server_set'", 'null': 'True', 'to': u"orm['servers.Server']"})
+ },
+ u'servers.serveruser': {
+ 'Meta': {'object_name': 'ServerUser'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"})
+ },
+ u'servers.sshkey': {
+ 'Meta': {'object_name': 'SshKey'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.TextField', [], {}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"}),
+ 'user': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ }
+ }
+
+ complete_apps = ['servers']
\ No newline at end of file
diff --git a/servers/migrations/0015_auto.py b/servers/migrations/0015_auto.py
new file mode 100644
index 0000000..acbb8b3
--- /dev/null
+++ b/servers/migrations/0015_auto.py
@@ -0,0 +1,100 @@
+# -*- 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 users_owning_the_server on 'Server'
+ m2m_table_name = db.shorten_name(u'servers_server_users_owning_the_server')
+ db.create_table(m2m_table_name, (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('server', models.ForeignKey(orm[u'servers.server'], null=False)),
+ ('user', models.ForeignKey(orm[u'auth.user'], null=False))
+ ))
+ db.create_unique(m2m_table_name, ['server_id', 'user_id'])
+
+
+ def backwards(self, orm):
+ # Removing M2M table for field users_owning_the_server on 'Server'
+ db.delete_table(db.shorten_name(u'servers_server_users_owning_the_server'))
+
+
+ models = {
+ u'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ u'auth.permission': {
+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ u'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'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'}),
+ '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']"}),
+ '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']"})
+ },
+ u'servers.serveruser': {
+ 'Meta': {'object_name': 'ServerUser'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"})
+ },
+ u'servers.sshkey': {
+ 'Meta': {'object_name': 'SshKey'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.TextField', [], {}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"}),
+ 'user': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ }
+ }
+
+ complete_apps = ['servers']
\ No newline at end of file
diff --git a/servers/migrations/0016_auto__add_field_server_notes.py b/servers/migrations/0016_auto__add_field_server_notes.py
new file mode 100644
index 0000000..79ee8db
--- /dev/null
+++ b/servers/migrations/0016_auto__add_field_server_notes.py
@@ -0,0 +1,97 @@
+# -*- 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 'Server.notes'
+ db.add_column(u'servers_server', 'notes',
+ self.gf('django.db.models.fields.TextField')(null=True, blank=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Server.notes'
+ db.delete_column(u'servers_server', 'notes')
+
+
+ models = {
+ u'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ u'auth.permission': {
+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ u'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'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'}),
+ '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']"})
+ },
+ u'servers.serveruser': {
+ 'Meta': {'object_name': 'ServerUser'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"})
+ },
+ u'servers.sshkey': {
+ 'Meta': {'object_name': 'SshKey'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.TextField', [], {}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"}),
+ 'user': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ }
+ }
+
+ complete_apps = ['servers']
\ No newline at end of file
diff --git a/servers/migrations/0017_auto__add_field_server_mysql_server.py b/servers/migrations/0017_auto__add_field_server_mysql_server.py
new file mode 100644
index 0000000..167e495
--- /dev/null
+++ b/servers/migrations/0017_auto__add_field_server_mysql_server.py
@@ -0,0 +1,98 @@
+# -*- 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 'Server.mysql_server'
+ db.add_column(u'servers_server', 'mysql_server',
+ self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='mysqled_server_set', null=True, to=orm['servers.Server']),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Server.mysql_server'
+ db.delete_column(u'servers_server', 'mysql_server_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', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'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']"})
+ },
+ u'servers.serveruser': {
+ 'Meta': {'object_name': 'ServerUser'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"})
+ },
+ u'servers.sshkey': {
+ 'Meta': {'object_name': 'SshKey'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.TextField', [], {}),
+ 'server': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['servers.Server']"}),
+ 'user': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ }
+ }
+
+ complete_apps = ['servers']
\ No newline at end of file
diff --git a/servers/models.py b/servers/models.py
index 88442fd..1fd47fa 100644
--- a/servers/models.py
+++ b/servers/models.py
@@ -4,6 +4,8 @@
import hashlib
+from main.models import User
+
class Server(models.Model):
name = models.CharField(max_length=255)
@@ -14,6 +16,7 @@ class Server(models.Model):
internal_ip = models.IPAddressField(blank=True, null=True)
vm_host = models.ForeignKey('Server', blank=True, null=True, related_name='server_set')
ngnix_server = models.ForeignKey('Server', blank=True, null=True, related_name='ngnixed_server_set')
+ mysql_server = models.ForeignKey('Server', blank=True, null=True, related_name='mysqled_server_set')
ssh_connection_string_from_gestion = models.CharField(max_length=255, blank=True, null=True)
ssh_connection_string_from_backup = models.CharField(max_length=255, blank=True, null=True)
@@ -29,6 +32,12 @@ class Server(models.Model):
samba_management = models.BooleanField(default=False)
samba_base_folder = models.CharField(max_length=255, blank=True, null=True, default='')
+ logstash_shipper = models.BooleanField(default=False)
+
+ users_owning_the_server = models.ManyToManyField(User, blank=True, null=True, help_text='Keys of users will be allowed and he will be able do display the server page details')
+
+ notes = models.TextField(blank=True, null=True)
+
def all_ports(self):
"""Return all ports (forwarded from and to)"""
@@ -92,7 +101,6 @@ def get_port(self):
# Hack, but easy way :D
return self.get_host_for_fabric().split(':')[-1]
-
def random_proxmox_password(self):
"""Return a unique but hard to guess password for new VMs"""
b = ''
diff --git a/servers/templates/servers/servers/_groups_allowed.html b/servers/templates/servers/servers/_groups_allowed.html
index 476c69e..b902cf8 100644
--- a/servers/templates/servers/servers/_groups_allowed.html
+++ b/servers/templates/servers/servers/_groups_allowed.html
@@ -11,7 +11,9 @@
{% for group in object.groupwithaccess_set.all %}
- {{group}}
+ {% if user.is_staff %}{% endif %}
+ {{group}}
+ {% if user.is_staff %} {% endif %}
@@ -30,7 +32,9 @@
{% for group in user_.group_set.all %}
- {{group}}
+ {% if user.is_staff %}{% endif %}
+ {{group}}
+ {% if user.is_staff %} {% endif %}
@@ -75,4 +79,4 @@
$("#group_select2").select2({placeholder: "{% trans 'Select a group to add' %}"});
$("#user_select").select2({placeholder: "{% trans 'Select an user' %}"});
-
\ No newline at end of file
+
diff --git a/servers/templates/servers/servers/_groups_membership.html b/servers/templates/servers/servers/_groups_membership.html
index 1ef2696..b813345 100644
--- a/servers/templates/servers/servers/_groups_membership.html
+++ b/servers/templates/servers/servers/_groups_membership.html
@@ -11,7 +11,9 @@
{% for group in object.group_set.all %}
- {{group}}
+ {% if user.is_staff %}{% endif %}
+ {{group}}
+ {% if user.is_staff %} {% endif %}
@@ -30,7 +32,9 @@
{% for group in key.group_set.all %}
- {{group}}
+ {% if user.is_staff %}{% endif %}
+ {{group}}
+ {% if user.is_staff %} {% endif %}
@@ -77,4 +81,4 @@
$("#key_select").select2({placeholder: "{% trans 'Select a key' %}"});
$("#group_select").select2({placeholder: "{% trans 'Select a group to add' %}"});
-
\ No newline at end of file
+
diff --git a/servers/templates/servers/servers/_runs.html b/servers/templates/servers/servers/_runs.html
index b531948..c6cb22d 100644
--- a/servers/templates/servers/servers/_runs.html
+++ b/servers/templates/servers/servers/_runs.html
@@ -12,7 +12,9 @@
{% for run in object.last_runs %}
- {{run.command}}
+ {% if user.is_staff %}{% endif %}
+ {{run.command}}
+ {% if user.is_staff %} {% endif %}
{{run.creation_date|timesince}} {% trans "ago" %}
diff --git a/servers/templates/servers/servers/edit.html b/servers/templates/servers/servers/edit.html
index 10267ab..b821eb7 100644
--- a/servers/templates/servers/servers/edit.html
+++ b/servers/templates/servers/servers/edit.html
@@ -12,35 +12,33 @@ {% trans "Servers management" %}
-
-
-
-
-
-
+
+
+
+
+
@@ -55,10 +53,13 @@
{% trans "Servers management" %}
$('#id_vm_host').parent().parent().show();
$('#id_ngnix_server').parent().parent().hide();
$('#id_ngnix_server').val('');
+ $('#id_mysql_server').parent().parent().hide();
+ $('#id_mysql_server').val('');
} else {
$('#id_internal_ip').parent().parent().hide();
$('#id_vm_host').parent().parent().hide();
$('#id_ngnix_server').parent().parent().show();
+ $('#id_mysql_server').parent().parent().show();
$('#id_internal_ip').val('');
$('#id_vm_host').val('');
}
@@ -84,9 +85,8 @@
{% trans "Servers management" %}
$("#users").select2({tags:[{% for u in all_users %}"{{u}}",{% endfor %}],tokenSeparators: [",", " "]});
- $('#id_vm_host,#id_ngnix_server').css('width', '220px').select2();
-
+ $('#id_vm_host,#id_ngnix_server,#id_mysql_server,#id_users_owning_the_server').css('width', '220px').select2();
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/servers/templates/servers/servers/list.html b/servers/templates/servers/servers/list.html
index 5df69fa..1664e64 100644
--- a/servers/templates/servers/servers/list.html
+++ b/servers/templates/servers/servers/list.html
@@ -28,7 +28,7 @@
{% trans "Servers management" %}
{% trans "Proxmox ?" %}
{% trans "Vm Host" %}
{% trans "IP" %}
-
+ {% if user.is_staff %}
{% endif %}
@@ -39,10 +39,12 @@ {% trans "Servers management" %}
{{elem.is_proxmox|yesno}}
{{elem.vm_host|default:""}}
{{elem.external_ip|default:""}} {{elem.internal_ip|default:""}}
-
- {% trans "Delete" %}
- {% trans "Edit" %}
-
+ {% if user.is_staff %}
+
+ {% trans "Delete" %}
+ {% trans "Edit" %}
+
+ {% endif %}
{% endfor %}
@@ -59,4 +61,4 @@ {% trans "Servers management" %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/servers/templates/servers/servers/show.html b/servers/templates/servers/servers/show.html
index 1e3f584..b96e42b 100644
--- a/servers/templates/servers/servers/show.html
+++ b/servers/templates/servers/servers/show.html
@@ -30,6 +30,13 @@ {{server.name}}
{{object.name}}
+ {% if object.notes %}
+
+
{% trans "Notes" %}
+
{{object.notes|linebreaks}}
+
+ {% endif %}
+
{% if object.keymanger_name %}
{% trans "Key manager name" %}
@@ -42,8 +49,6 @@
{{server.name}}
{{object.is_vm|yesno}}
-
-
{% if object.vm_host %}
{% trans "VM Host" %}
@@ -85,6 +90,13 @@
{{server.name}}
{% endif %}
+ {% if object.mysql_server %}
+
+
{% trans "Mysql server" %}
+
{{object.mysql_server}}
+
+ {% endif %}
+
{% if object.ssh_connection_string_from_gestion %}
{% trans "SSH connection string for gestion" %}
@@ -134,6 +146,11 @@
{{server.name}}
{% endif %}
+
+
{% trans "Logstash shipper ?" %}
+
{{object.logstash_shipper|yesno}}
+
+
{% if object.serveruser_set.all %}
{% trans "Users" %}
@@ -147,15 +164,26 @@
{{server.name}}
{% endif %}
+ {% if object.users_owning_the_server.all %}
+
+
{% trans "Users with access to the server" %}
+
+
+ {% for u in object.users_owning_the_server.all %}
+ {{u}}
+ {% endfor %}
+
+
+
+ {% endif %}
+
-
-
diff --git a/servers/views.py b/servers/views.py
index 4766e78..8549f9b 100644
--- a/servers/views.py
+++ b/servers/views.py
@@ -23,22 +23,26 @@
@login_required
-@staff_member_required
def servers_list(request):
"""Show the list of servers"""
- liste = Server.objects.order_by('-is_vm', 'vm_host__name', 'name').all()
+ if request.user.is_staff:
+ liste = Server.objects.order_by('-is_vm', 'vm_host__name', 'name').all()
+ else:
+ liste = Server.objects.order_by('-is_vm', 'vm_host__name', 'name').filter(users_owning_the_server=request.user).all()
return render_to_response('servers/servers/list.html', {'liste': liste}, context_instance=RequestContext(request))
@login_required
-@staff_member_required
def servers_show(request, pk):
"""Show details of an Server"""
object = get_object_or_404(Server, pk=pk)
+ if not request.user.is_staff and not request.user in object.users_owning_the_server.all():
+ raise Http404
+
groups = Group.objects.order_by('name').all()
return render_to_response('servers/servers/show.html', {'object': object, 'groups': groups}, context_instance=RequestContext(request))
@@ -330,4 +334,4 @@ def servers_map(request):
proxmox_servers = Server.objects.order_by('name').filter(is_proxmox=True).all()
outside_servers = Server.objects.order_by('name').filter(is_proxmox=False, is_vm=False).all()
- return render_to_response('servers/map.html', {'proxmox_servers': proxmox_servers, 'outside_servers': outside_servers }, context_instance=RequestContext(request))
+ return render_to_response('servers/map.html', {'proxmox_servers': proxmox_servers, 'outside_servers': outside_servers}, context_instance=RequestContext(request))
diff --git a/templates/base.html b/templates/base.html
index 84199bc..16e6d86 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -81,10 +81,12 @@
{% trans "Users" %}
+ {% endif %}
+ {% if user.is_staff %}
@@ -128,6 +130,10 @@
+
+
{% endif %}
diff --git a/wizard/views.py b/wizard/views.py
index 3cbec5e..5d14354 100644
--- a/wizard/views.py
+++ b/wizard/views.py
@@ -143,7 +143,7 @@ def do_tasks(request, uid):
status_id = request.session['wiz_' + uid + '_status_id']
- return render_to_response('wizard/task.html', {'wiz': wiz, 'tasks': tasks, 'nb_tasks': wiz.get_nb_task(), 'status_id': status_id}, context_instance=RequestContext(request))
+ return render_to_response('wizard/task.html', {'wiz': wiz, 'tasks': tasks, 'nb_tasks': wiz.get_nb_task(), 'status_id': status_id}, context_instance=RequestContext(request))
@login_required
diff --git a/wizard/wizards/create_mysql_table.py b/wizard/wizards/create_mysql_table.py
new file mode 100644
index 0000000..29835aa
--- /dev/null
+++ b/wizard/wizards/create_mysql_table.py
@@ -0,0 +1,117 @@
+
+from _wizard import _Wizard
+
+from django import forms
+
+from django.conf import settings
+
+from django.utils import timezone
+
+from servers.models import Server
+import os
+import uuid
+import re
+
+
+class Step1Form(forms.Form):
+ name = forms.CharField(help_text='The name of the database and the user. This will be prefixed with the VM name')
+ password = forms.CharField(widget=forms.PasswordInput(), required=False, help_text='Leave blank to generate a random password')
+ save_in_notes = forms.BooleanField(help_text='Check this to save the password in the server\'s note')
+ server = forms.ModelChoiceField(queryset=Server.objects.exclude(ssh_connection_string_from_gestion=None).order_by('name'))
+
+
+class CreateMysqlTable(_Wizard):
+ """Simple wizard to create a mysql table"""
+
+ _name = 'CreateMysqlTable'
+ _description = 'Simple wizard to create a mysql table and a linked user'
+
+ _nb_step = 1
+ _nb_task = 5
+
+ _steps_names = ['Informations needed']
+ _tasks_names = ['Create database', 'Create mysql user', 'Grand rights on the server', 'Flush privileges', 'Save data']
+
+ def display_step_1(self, request):
+
+ if request.method == 'POST':
+ form = Step1Form(request.POST)
+ else:
+ form = Step1Form()
+
+ return ('', form, "$('#id_server').css('width', '220px').select2();")
+
+ def save_step_1(self, form):
+ server = Server.objects.get(pk=form.cleaned_data['server'].pk)
+ name = re.sub('[\W_]+', '', server.name) + '_' + form.cleaned_data['name']
+ server_pk = form.cleaned_data['server'].pk
+ password = form.cleaned_data['password']
+ save_in_notes = form.cleaned_data['save_in_notes']
+
+ if not password:
+ password = str(uuid.uuid4())
+
+ return {'name': name, 'server_pk': server_pk, 'password': password, 'save_in_notes': save_in_notes}
+
+ def do_task_1(self):
+ """Create the database"""
+
+ server = Server.objects.get(pk=self.step_data[0]['server_pk'])
+
+ # Find the mysql server
+ try:
+ server_mysql = server.vm_host.mysql_server
+ except:
+ return (False, None)
+
+ os.system('ssh ' + server_mysql.ssh_connection_string_from_gestion + ' "echo \'CREATE DATABASE %s DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;\' | mysql --user=\'%s\' --password=\'%s\'"' % (self.step_data[0]['name'], settings.MYSQL_USERNAME, settings.MYSQL_PASSWORD))
+
+ return (True, None)
+
+ def do_task_2(self):
+ """Create the mysql user"""
+
+ server = Server.objects.get(pk=self.step_data[0]['server_pk'])
+ server_mysql = server.vm_host.mysql_server
+
+ os.system('ssh ' + server_mysql.ssh_connection_string_from_gestion + ' "echo \'CREATE USER %s@%s IDENTIFIED BY \\"%s\\";\' | mysql --user=\'%s\' --password=\'%s\'"' % (self.step_data[0]['name'], server.internal_ip, self.step_data[0]['password'], settings.MYSQL_USERNAME, settings.MYSQL_PASSWORD))
+
+ return (True, None)
+
+ def do_task_3(self):
+ """Grand rights on the server"""
+
+ server = Server.objects.get(pk=self.step_data[0]['server_pk'])
+ server_mysql = server.vm_host.mysql_server
+
+ os.system('ssh ' + server_mysql.ssh_connection_string_from_gestion + ' "echo \'GRANT ALL ON %s.* TO %s@%s;\' | mysql --user=\'%s\' --password=\'%s\'"' % (self.step_data[0]['name'], self.step_data[0]['name'], server.internal_ip, settings.MYSQL_USERNAME, settings.MYSQL_PASSWORD))
+
+ return (True, None)
+
+ def do_task_4(self):
+ """Flush privileges"""
+
+ server = Server.objects.get(pk=self.step_data[0]['server_pk'])
+ server_mysql = server.vm_host.mysql_server
+
+ os.system('ssh ' + server_mysql.ssh_connection_string_from_gestion + ' "echo \'FLUSH PRIVILEGES;\' | mysql --user=\'%s\' --password=\'%s\'"' % (settings.MYSQL_USERNAME, settings.MYSQL_PASSWORD))
+
+ return (True, None)
+
+ def do_task_5(self):
+ """Save data"""
+
+ if self.step_data[0]['save_in_notes']:
+ server = Server.objects.get(pk=self.step_data[0]['server_pk'])
+
+ if not server.notes:
+ server.notes = ""
+
+ server.notes += """
+ ==MysqlDB Created %s==
+ Mysql database: %s
+ Mysql username: %s
+ Mysql password: %s""" % (str(timezone.now()), self.step_data[0]['name'], self.step_data[0]['name'], self.step_data[0]['password'])
+ server.save()
+
+ return (True, None)
diff --git a/wizard/wizards/create_user.py b/wizard/wizards/create_user.py
index fd7f11c..8d246b7 100644
--- a/wizard/wizards/create_user.py
+++ b/wizard/wizards/create_user.py
@@ -20,7 +20,7 @@ class Step1Form(forms.Form):
class CreateUser(_Wizard):
- """Simple wizard to create a VM"""
+ """Simple wizard to create a user on a VM"""
_name = 'CreateUser'
_description = 'Simple wizard to create a new user on a server'
diff --git a/wizard/wizards/create_vm.py b/wizard/wizards/create_vm.py
index 21d6668..a135568 100644
--- a/wizard/wizards/create_vm.py
+++ b/wizard/wizards/create_vm.py
@@ -18,6 +18,7 @@
from fabrun.models import Task
from fabrun.tasks import run_task
from backups.tasks import run_backup
+from logstash.models import File
class Step1Form(forms.Form):
@@ -43,7 +44,6 @@ def get_full_name(self):
return self.cleaned_data['name'] + '.' + self.cleaned_data['proxmox'].name
-
class Step2Form(forms.Form):
add_to_groups = forms.BooleanField(initial=True, required=False)
add_groups = forms.BooleanField(initial=True, required=False)
@@ -53,6 +53,7 @@ class Step2Form(forms.Form):
setup_hostforwarding = forms.BooleanField(initial=True, required=False)
setup_backups = forms.BooleanField(initial=True, required=False)
do_first_backup = forms.BooleanField(initial=True, required=False)
+ create_logstash_entries = forms.BooleanField(initial=True, required=False)
name = forms.CharField()
keymanager_name = forms.CharField()
@@ -166,10 +167,10 @@ class CreateVm(_Wizard):
_description = 'Simple wizard to create a VM'
_nb_step = 2
- _nb_task = 9
+ _nb_task = 10
_steps_names = ['VM Name and Host', 'Advanced parameters']
- _tasks_names = ['Create server', 'Setup VM groups', 'Create VM', 'Start VM', 'Open ports', 'Forward domain', 'Execute setup script', 'Create backup task', 'Execute backup task']
+ _tasks_names = ['Create server', 'Setup VM groups', 'Create VM', 'Start VM', 'Open ports', 'Forward domain', 'Execute setup script', 'Create backup task', 'Execute backup task', 'Create logstash entries']
def display_step_1(self, request):
@@ -371,3 +372,15 @@ def do_task_9(self):
run_backup(id)
return (True, None)
+
+ def do_task_10(self):
+ """Create logstash entries"""
+ if self.step_data[1]['create_logstash_entries']:
+
+ srv = Server.objects.get(pk=self.task_data[0]['server_pk'])
+
+ if srv.vm_host.logstash_shipper:
+ File(server=srv.vm_host, file='/var/lib/vz/root/' + str(self.task_data[2]['vm_id']) + '/var/log/auth.log', type='syslog', tags=srv.vm_host.name.split('.')[-2] + ',vm,auth.log,' + srv.name).save()
+ File(server=srv.vm_host, file='/var/lib/vz/root/' + str(self.task_data[2]['vm_id']) + '/var/log/syslog', type='syslog', tags=srv.vm_host.name.split('.')[-2] + ',vm,syslog,' + srv.name).save()
+
+ return (True, None)