fusion avec progfou/gestionmateriel
authorPatrick Hetu <patrick.hetu@auf.org>
Tue, 5 Aug 2014 20:34:17 +0000 (16:34 -0400)
committerPatrick Hetu <patrick.hetu@auf.org>
Tue, 5 Aug 2014 20:34:17 +0000 (16:34 -0400)
38 files changed:
montreal/gestionmateriel/ansible.py [new file with mode: 0755]
montreal/gestionmateriel/djcelery/static/djcelery/style.css [deleted file]
montreal/gestionmateriel/djcelery/templates/admin/djcelery/change_list.html [deleted file]
montreal/gestionmateriel/djcelery/templates/djcelery/confirm_rate_limit.html [deleted file]
montreal/gestionmateriel/docs/index.rst
montreal/gestionmateriel/majsite/maj/__init__.py [deleted file]
montreal/gestionmateriel/majsite/maj/admin.py [deleted file]
montreal/gestionmateriel/majsite/maj/management/__init__.py [deleted file]
montreal/gestionmateriel/majsite/maj/management/commands/__init__.py [deleted file]
montreal/gestionmateriel/majsite/maj/management/commands/get.py [deleted file]
montreal/gestionmateriel/majsite/maj/models.py [deleted file]
montreal/gestionmateriel/majsite/maj/tasks.py [deleted file]
montreal/gestionmateriel/majsite/materiel/__init__.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/admin.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/management/__init__.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/management/commands/__init__.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/management/commands/inventory.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/management/commands/update.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/models.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/tasks.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/templates/admin/maj_confirmation.html [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/templates/fichier_dhcpd.txt [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/templates/fichier_dns-inverse.txt [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/templates/fichier_dns.txt [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/templates/fichier_ethers.txt [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/templates/machine_list.html [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/urls.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/materiel/views.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/settings/10-local.py
montreal/gestionmateriel/majsite/settings/50-celery.py [deleted file]
montreal/gestionmateriel/majsite/settings/50-rq.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/settings/99-custom.py
montreal/gestionmateriel/majsite/urls/10-admin.py [new file with mode: 0644]
montreal/gestionmateriel/majsite/urls/50-saml.py
montreal/gestionmateriel/majsite/urls/60-admin.py [deleted file]
montreal/gestionmateriel/majsite/urls/60-rq.py [new file with mode: 0644]
montreal/gestionmateriel/requirements/base.txt
montreal/gestionmateriel/requirements/wheezy.txt [new file with mode: 0644]

diff --git a/montreal/gestionmateriel/ansible.py b/montreal/gestionmateriel/ansible.py
new file mode 100755 (executable)
index 0000000..bdf509c
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+import os
+import sys
+
+sys.path.append('./majsite/')
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "majsite.settings")
+
+    from django.core.management import call_command
+
+    call_command('inventory')
diff --git a/montreal/gestionmateriel/djcelery/static/djcelery/style.css b/montreal/gestionmateriel/djcelery/static/djcelery/style.css
deleted file mode 100644 (file)
index b4f4c6a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-.form-row.field-traceback p {
-    font-family: monospace;
-    white-space: pre;
-}
diff --git a/montreal/gestionmateriel/djcelery/templates/admin/djcelery/change_list.html b/montreal/gestionmateriel/djcelery/templates/admin/djcelery/change_list.html
deleted file mode 100644 (file)
index f35a801..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-{% extends "admin/change_list.html" %}
-{% load i18n %}
-
-{% block breadcrumbs %}
-  <div class="breadcrumbs">
-    <a href="../../">
-      {% trans "Home" %}
-    </a>
-    &rsaquo;
-    <a href="../">
-      {{ app_label|capfirst }}
-    </a>
-    &rsaquo;
-    {{ cl.opts.verbose_name_plural|capfirst }}
-  </div>
-  {% if wrong_scheduler %}
-    <ul class="messagelist">
-      <li class="warning">
-      Periodic tasks won't be dispatched unless you set the
-      <code>CELERYBEAT_SCHEDULER</code> setting to
-      <code>djcelery.schedulers.DatabaseScheduler</code>,
-      or specify it using the <code>-S</code> option to celerybeat
-      </li>
-    </ul>
-  {% endif %}
-{% endblock %}
diff --git a/montreal/gestionmateriel/djcelery/templates/djcelery/confirm_rate_limit.html b/montreal/gestionmateriel/djcelery/templates/djcelery/confirm_rate_limit.html
deleted file mode 100644 (file)
index 6152b76..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{% extends "admin/base_site.html" %}
-{% load i18n %}
-
-{% block breadcrumbs %}
-<div class="breadcrumbs">
-     <a href="../../">{% trans "Home" %}</a> &rsaquo;
-     <a href="../">{{ app_label|capfirst }}</a> &rsaquo;
-     <a href="./">{{ opts.verbose_name_plural|capfirst }}</a> &rsaquo;
-     {% trans 'Rate limit selected tasks' %}
-</div>
-{% endblock %}
-
-{% block content %}
-    <form action="" method="post">{% csrf_token %}
-    <div>
-    {% for obj in queryset %}
-    <input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk }}" />
-    {% endfor %}
-    <input type="hidden" name="action" value="rate_limit_tasks" />
-    <input type="hidden" name="post" value="yes" />
-    <input type="text" name="rate_limit" value="" />
-    <input type="submit" value="{% trans "Rate limit" %}" />
-    </div>
-    </form>
-{% endblock %}
index dcd3bed..608d7fe 100644 (file)
@@ -37,10 +37,6 @@ Pour démarrer le service Django utilisé la commande::
 
   bin/python manage.py runserver
 
-.. Pour démarrer le service Celery utilisé la commande suivante::
-..
-..   bin/python -O manage.py celery worker
-
 Pour utiliser l'interface web vous devez d'abord vous autentifier:
 
   http://localhost:8000/sandbox/login
@@ -56,7 +52,11 @@ Il est aussi possible d'utiliser la ligne de commande pour certaines tâches com
 
 Collecter le nombre de paquets à mettre à jour sur l'ensemble des machines::
 
-  bin/python manage.py get
+  bin/python manage.py update
+
+Rouler un module Ansible sur toutes les machines d'une catégorie::
+
+  bin/ansible -i ansible.py categorie -m ping
 
 Aides et supports
 -----------------
@@ -66,8 +66,6 @@ Aides et supports
 Améliorations possibles
 -----------------------
 
-* Fusion avec le site: http://git.auf.org/?p=progfou.git;a=tree;f=gestionmateriel
-* Serveur API REST: http://docs.celeryproject.org/en/latest/userguide/remote-tasks.html
 * Démarrage des machines à l'aide de la commande `wakeonlan`
 * Sauvegarde des traces de l'exécution (logs)
 * Sommaire de la mise-à-jour par courriel
@@ -75,6 +73,15 @@ Améliorations possibles
 * Interface utilisateur améliorée
 * Tâches planifiées (cron)
 * Tests unitaires et d'intégration
+* Intégration avec GLPI: https://github.com/mcphargus/python-glpi
+
+Versions
+--------
+
+1.0
+^^^
+
+* Fusion avec le site: http://git.auf.org/?p=progfou.git;a=tree;f=gestionmateriel
 
 Licence
 -------
diff --git a/montreal/gestionmateriel/majsite/maj/__init__.py b/montreal/gestionmateriel/majsite/maj/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/montreal/gestionmateriel/majsite/maj/admin.py b/montreal/gestionmateriel/majsite/maj/admin.py
deleted file mode 100644 (file)
index bd8d147..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# -*- encoding: utf-8 -*-
-
-from django.contrib import admin
-from django.conf.urls import patterns, url
-
-from .tasks import maj_status, maj
-from .models import Machine
-
-
-def make_maj_status(modeladmin, request, queryset):
-    maj_status.delay(queryset)
-make_maj_status.short_description = "Mettre-à-jour la liste des paquets"
-
-
-def make_maj(modeladmin, request, queryset):
-    maj.delay(queryset)
-make_maj.short_description = "apt-get dist-upgrade"
-
-
-class MachineAdmin(admin.ModelAdmin):
-    list_display = ['hostname', 'nb_inst', 'nb_remv', 'status', 'maj_le']
-    list_filter = ['status']
-    actions = [make_maj_status, make_maj]
-
-admin.site.register(Machine, MachineAdmin)
diff --git a/montreal/gestionmateriel/majsite/maj/management/__init__.py b/montreal/gestionmateriel/majsite/maj/management/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/montreal/gestionmateriel/majsite/maj/management/commands/__init__.py b/montreal/gestionmateriel/majsite/maj/management/commands/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/montreal/gestionmateriel/majsite/maj/management/commands/get.py b/montreal/gestionmateriel/majsite/maj/management/commands/get.py
deleted file mode 100644 (file)
index 8237ab4..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-import datetime
-
-from django.core.management.base import BaseCommand, CommandError
-
-import ansible.runner
-
-from maj.models import Machine
-
-
-class Command(BaseCommand):
-    help = 'Get maj status'
-
-    def handle(self, *args, **options):
-        machines = Machine.objects.all()
-
-        # construct the ansible runner and execute on all hosts
-        results = ansible.runner.Runner(
-            pattern='*',
-            forks=10,
-            host_list=list(machines.values_list('hostname', flat=True)),
-            module_name='shell',
-            module_args="sudo apt-get -s dist-upgrade",
-        ).run()
-
-        if results is None:
-            raise CommandError("No hosts found")
-
-        print "UP ***********"
-        for (hostname, result) in results['contacted'].items():
-            if not 'failed' in result:
-                print "%s >>> %s" % (hostname, result['stdout'])
-                machines.filter(hostname=hostname).update(
-                    nb_inst=len([l for l in result['stdout'].split()
-                                if l.startswith('Inst') or l.startswith('Conf')]),
-                    nb_remv=len([l for l in result['stdout'].split() if l.startswith('Remv')]),
-                    packages=result['stdout'], status="Verifie", maj_le=datetime.datetime.now())
-
-        print "FAILED *******"
-        for (hostname, result) in results['contacted'].items():
-            if 'failed' in result:
-                print "%s >>> %s" % (hostname, result['msg'])
-                machines.filter(hostname=hostname).update(status="Erreur", maj_le=datetime.datetime.now())
-
-        print "DOWN *********"
-        for (hostname, result) in results['dark'].items():
-            print "%s >>> %s" % (hostname, result)
-            machines.filter(hostname=hostname).update(status="Eteinte", maj_le=datetime.datetime.now())
-
-        # nb_remv
-        # nb_inst
-        # packages
-        # error
-        # down
-        # machine.save()
diff --git a/montreal/gestionmateriel/majsite/maj/models.py b/montreal/gestionmateriel/majsite/maj/models.py
deleted file mode 100644 (file)
index 4a6daf3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# -*- encoding: utf-8 -*-
-
-from django.db import models
-
-
-class Machine(models.Model):
-    hostname = models.CharField(max_length=64)
-    nb_remv = models.IntegerField(default=0, verbose_name=u"Paquets à enlever")
-    nb_inst = models.IntegerField(default=0, verbose_name=u"Paquets à installer")
-    packages = models.TextField(blank=True, null=True)
-    status = models.CharField(default="Inconnu", max_length=32)
-
-    maj_le = models.DateTimeField(blank=True, null=True)
-
diff --git a/montreal/gestionmateriel/majsite/maj/tasks.py b/montreal/gestionmateriel/majsite/maj/tasks.py
deleted file mode 100644 (file)
index abcf393..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# -*- encoding: utf-8 -*-
-
-import datetime
-
-from celery.decorators import task
-
-import ansible.runner
-import ansible.playbook
-from ansible import callbacks
-
-
-@task()
-def maj_status(machines):
-    # construct the ansible runner and execute on all hosts
-    results = ansible.runner.Runner(
-        pattern='*',
-        forks=60,
-        host_list=list(machines.values_list('hostname', flat=True)),
-        module_name='shell',
-        module_args="sudo apt-get -s dist-upgrade",
-        remote_user="root",
-    ).run()
-
-    if results is None:
-        return
-
-        print "UP ***********"
-    for (hostname, result) in results['contacted'].items():
-        if not 'failed' in result:
-            print hostname
-            machines.filter(hostname__startswith=hostname).update(
-                nb_inst=len([l for l in result['stdout'].split()
-                            if l.startswith('Inst') or l.startswith('Conf')]),
-                nb_remv=len([l for l in result['stdout'].split() if l.startswith('Remv')]),
-                packages=result['stdout'], status=u"Allumée", maj_le=datetime.datetime.now())
-
-    for (hostname, result) in results['contacted'].items():
-        if 'failed' in result:
-            machines.filter(hostname__startswith=hostname).update(status="Erreur", maj_le=datetime.datetime.now())
-
-    for (hostname, result) in results['dark'].items():
-        machines.filter(hostname__startswith=hostname).update(status="Eteinte")
-
-
-@task()
-def maj(machines):
-    stats = callbacks.AggregateStats()
-    playbook_cb = callbacks.PlaybookCallbacks(verbose=True)
-    runner_cb = callbacks.DefaultRunnerCallbacks()
-    play = ansible.playbook.PlayBook(
-        forks=60,
-        host_list=list(machines.values_list('hostname', flat=True)),
-        playbook='maj.yml',
-        remote_user="root",
-        stats=stats,
-        callbacks=playbook_cb,
-        runner_callbacks=runner_cb
-    )
-    play.run()
diff --git a/montreal/gestionmateriel/majsite/materiel/__init__.py b/montreal/gestionmateriel/majsite/materiel/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/montreal/gestionmateriel/majsite/materiel/admin.py b/montreal/gestionmateriel/majsite/materiel/admin.py
new file mode 100644 (file)
index 0000000..288e93b
--- /dev/null
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+
+from django.contrib import admin
+from django import forms
+from django.utils.translation import ugettext as _
+from django.utils.encoding import force_text
+from django.template.response import TemplateResponse
+from django.contrib.admin import helpers
+
+from .tasks import maj_status, maj, wol
+from .models import Machine, Categorie
+
+
+class MyMachineAdminForm(forms.ModelForm):
+    class Meta:
+        model = Machine
+
+    def clean_adresse_mac(self):
+        return self.cleaned_data['adresse_mac'].lower()
+
+
+def make_maj_status(modeladmin, request, queryset):
+    maj_status.delay(queryset)
+make_maj_status.short_description = "Mettre-à-jour la liste des paquets"
+
+
+def make_wol(modeladmin, request, queryset):
+    for machine in queryset:
+        wol.delay(machine)
+make_wol.short_description = "Wakeonlan"
+
+
+def make_maj(modeladmin, request, queryset):
+    opts = modeladmin.model._meta
+
+    if request.POST.get('post'):
+        maj.delay(queryset)
+        return None
+
+    if len(queryset) == 1:
+        objects_name = force_text(opts.verbose_name)
+    else:
+        objects_name = force_text(opts.verbose_name_plural)
+
+    context = {
+        "title": _("Are you sure?"),
+        "objects_name": objects_name,
+        "deletable_objects": [queryset],
+        'queryset': queryset,
+        "perms_lacking": False,
+        "protected": False,
+        "opts": opts,
+        'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
+    }
+
+    # Display the confirmation page
+    return TemplateResponse(request, "admin/maj_confirmation.html",
+                            context, current_app=modeladmin.admin_site.name)
+
+make_maj.short_description = "apt-get dist-upgrade"
+
+
+class MachineAdmin(admin.ModelAdmin):
+    form = MyMachineAdminForm
+    list_display = ['nom_dns_complet', 'adresse_ip', 'adresse_mac',
+                    'emplacement', 'nb_inst', 'nb_remv', 'status', 'maj_le']
+    list_filter = ['emplacement', 'categorie', 'status']
+    actions = [make_maj_status, make_maj, make_wol]
+
+
+admin.site.register(Categorie)
+admin.site.register(Machine, MachineAdmin)
diff --git a/montreal/gestionmateriel/majsite/materiel/management/__init__.py b/montreal/gestionmateriel/majsite/materiel/management/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/montreal/gestionmateriel/majsite/materiel/management/commands/__init__.py b/montreal/gestionmateriel/majsite/materiel/management/commands/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/montreal/gestionmateriel/majsite/materiel/management/commands/inventory.py b/montreal/gestionmateriel/majsite/materiel/management/commands/inventory.py
new file mode 100644 (file)
index 0000000..f2585e9
--- /dev/null
@@ -0,0 +1,17 @@
+import json
+
+from django.core.management.base import BaseCommand
+
+from materiel.models import Categorie
+
+
+class Command(BaseCommand):
+    help = 'Inventory for ansible-playbook'
+
+    def handle(self, *args, **options):
+        data = {}
+        cats = Categorie.objects.all()
+        for cat in cats:
+            data[cat.nom_categorie] = [unicode(t) for t in cat.machine_set.values_list('nom_dns_complet', flat=True)]
+        print json.dumps(data)
+
diff --git a/montreal/gestionmateriel/majsite/materiel/management/commands/update.py b/montreal/gestionmateriel/majsite/materiel/management/commands/update.py
new file mode 100644 (file)
index 0000000..50aeb93
--- /dev/null
@@ -0,0 +1,54 @@
+import datetime
+
+from django.core.management.base import BaseCommand, CommandError
+
+import ansible.runner
+
+from materiel.models import Machine
+
+
+class Command(BaseCommand):
+    help = 'Get maj status'
+
+    def handle(self, *args, **options):
+        machines = Machine.objects.all()
+
+        # construct the ansible runner and execute on all hosts
+        results = ansible.runner.Runner(
+            pattern='*',
+            forks=10,
+            host_list=list(machines.values_list('nom_dns_complet', flat=True)),
+            module_name='shell',
+            module_args="sudo apt-get -s dist-upgrade",
+        ).run()
+
+        if results is None:
+            raise CommandError("No hosts found")
+
+        print "UP ***********"
+        for (nom_dns_complet, result) in results['contacted'].items():
+            if not 'failed' in result:
+                print "%s >>> %s" % (nom_dns_complet, result['stdout'])
+                machines.filter(nom_dns_complet=nom_dns_complet).update(
+                    nb_inst=len([l for l in result['stdout'].split()
+                                if l.startswith('Inst') or l.startswith('Conf')]),
+                    nb_remv=len([l for l in result['stdout'].split() if l.startswith('Remv')]),
+                    packages=result['stdout'], status="Verifie", maj_le=datetime.datetime.now())
+
+        print "FAILED *******"
+        for (nom_dns_complet, result) in results['contacted'].items():
+            if 'failed' in result:
+                print "%s >>> %s" % (nom_dns_complet, result['msg'])
+                machines.filter(nom_dns_complet=nom_dns_complet).update(status="Erreur", maj_le=datetime.datetime.now())
+
+        print "DOWN *********"
+        for (nom_dns_complet, result) in results['dark'].items():
+            print "%s >>> %s" % (nom_dns_complet, result)
+            machines.filter(nom_dns_complet=nom_dns_complet).update(status="Eteinte", maj_le=datetime.datetime.now())
+
+        # nb_remv
+        # nb_inst
+        # packages
+        # error
+        # down
+        # machine.save()
diff --git a/montreal/gestionmateriel/majsite/materiel/models.py b/montreal/gestionmateriel/majsite/materiel/models.py
new file mode 100644 (file)
index 0000000..13b8624
--- /dev/null
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+from django.db import models
+
+
+class Categorie(models.Model):
+    nom_categorie = models.CharField("Nom de catégorie", max_length=32)
+
+    def __unicode__(self):
+        return u'%s' % (self.nom_categorie,)
+
+    class Meta:
+        ordering = ['nom_categorie']
+
+
+class Machine(models.Model):
+    adresse_mac = models.CharField("Adresse MAC", max_length=17)
+    adresse_ip = models.IPAddressField("Adresse IP", unique=True)
+    nom_dns_complet = models.CharField("Nom DNS complet", max_length=64, unique=True)
+    emplacement = models.CharField("Emplacement", max_length=16)
+    categorie = models.ForeignKey(Categorie)
+
+    nb_remv = models.IntegerField(default=0, verbose_name=u"Paquets à enlever")
+    nb_inst = models.IntegerField(default=0, verbose_name=u"Paquets à installer")
+    packages = models.TextField(blank=True, null=True)
+    status = models.CharField(default="Inconnu", max_length=32)
+
+    maj_le = models.DateTimeField(blank=True, null=True)
+
+    class Meta:
+        ordering = ['adresse_mac']
+
+    def numero_machine(self):
+        return self.adresse_ip.split('.')[3]  # découper et prendre le 4ème
+
+    def reseau_ip_inverse(self):
+        l = self.adresse_ip.split('.')[:3]  # découper et prendre les 3 premiers
+        l.reverse()  # inverser l'ordre
+        return '.'.join(l)  # relier ensemble avec le point (.)
+
+    def nom_machine(self):
+        return self.nom_dns_complet.split('.', 1)[0]
+
+    def domaine_dns(self):
+        return self.nom_dns_complet.split('.', 1)[1]
+
+    def is_st2030(self):
+        return "ST2030" in str(self.categorie)
+
+    def __unicode__(self):
+        return u'%s' % (self.nom_dns_complet,)
+
diff --git a/montreal/gestionmateriel/majsite/materiel/tasks.py b/montreal/gestionmateriel/majsite/materiel/tasks.py
new file mode 100644 (file)
index 0000000..760bd10
--- /dev/null
@@ -0,0 +1,71 @@
+# -*- encoding: utf-8 -*-
+
+import datetime
+
+from django_rq import job
+
+import ansible.runner
+import ansible.playbook
+from ansible import callbacks
+
+
+@job
+def maj_status(machines):
+    # construct the ansible runner and execute on all hosts
+    results = ansible.runner.Runner(
+        pattern='*',
+        forks=60,
+        host_list=list(machines.values_list('nom_dns_complet', flat=True)),
+        module_name='shell',
+        module_args="sudo apt-get -s dist-upgrade",
+        remote_user="root",
+    ).run()
+
+    if results is None:
+        return
+
+        print "UP ***********"
+    for (nom_dns_complet, result) in results['contacted'].items():
+        if not 'failed' in result:
+            print nom_dns_complet
+            machines.filter(nom_dns_complet__startswith=nom_dns_complet).update(
+                nb_inst=len([l for l in result['stdout'].split()
+                            if l.startswith('Inst') or l.startswith('Conf')]),
+                nb_remv=len([l for l in result['stdout'].split() if l.startswith('Remv')]),
+                packages=result['stdout'], status=u"Allumée", maj_le=datetime.datetime.now())
+
+    for (nom_dns_complet, result) in results['contacted'].items():
+        if 'failed' in result:
+            machines.filter(nom_dns_complet__startswith=nom_dns_complet).update(status="Erreur", maj_le=datetime.datetime.now())
+
+    for (nom_dns_complet, result) in results['dark'].items():
+        machines.filter(nom_dns_complet__startswith=nom_dns_complet).update(status="Eteinte")
+
+
+@job
+def wol(machine):
+    ansible.runner.Runner(
+        pattern='*',
+        forks=60,
+        host_list=['localhost'],
+        transport='local',
+        module_name='shell',
+        module_args="wakeonlan %s" % machine.adresse_mac,
+    ).run()
+
+
+@job
+def maj(machines):
+    stats = callbacks.AggregateStats()
+    playbook_cb = callbacks.PlaybookCallbacks(verbose=True)
+    runner_cb = callbacks.DefaultRunnerCallbacks()
+    play = ansible.playbook.PlayBook(
+        forks=60,
+        host_list=list(machines.values_list('nom_dns_complet', flat=True)),
+        playbook='maj.yml',
+        remote_user="root",
+        stats=stats,
+        callbacks=playbook_cb,
+        runner_callbacks=runner_cb
+    )
+    play.run()
diff --git a/montreal/gestionmateriel/majsite/materiel/templates/admin/maj_confirmation.html b/montreal/gestionmateriel/majsite/materiel/templates/admin/maj_confirmation.html
new file mode 100644 (file)
index 0000000..b126237
--- /dev/null
@@ -0,0 +1,30 @@
+{% extends "admin/base_site.html" %}
+{% load url from future %}
+{% load i18n l10n admin_urls %}
+
+{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation delete-selected-confirmation{% endblock %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
+&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
+&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
+</div>
+{% endblock %}
+
+{% block content %}
+    <p>Êtes-vous certain de vouloir mettre-à-jour (et redémarrer) les postes suivants:</p>
+    {% for deletable_object in deletable_objects %}
+        <ul>{{ deletable_object|unordered_list }}</ul>
+    {% endfor %}
+    <form action="" method="post">{% csrf_token %}
+    <div>
+    {% for obj in queryset %}
+    <input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
+    {% endfor %}
+    <input type="hidden" name="action" value="make_maj" />
+    <input type="hidden" name="post" value="yes" />
+    <input type="submit" value="{% trans "Yes, I'm sure" %}" />
+    </div>
+    </form>
+{% endblock %}
diff --git a/montreal/gestionmateriel/majsite/materiel/templates/fichier_dhcpd.txt b/montreal/gestionmateriel/majsite/materiel/templates/fichier_dhcpd.txt
new file mode 100644 (file)
index 0000000..ac9441c
--- /dev/null
@@ -0,0 +1,5 @@
+# Fichier: /etc/dhcp3/dhcpd.conf
+# Généré automatiquement depuis l'application "materiel",
+# ne pas éditer manuellement !
+{% for o in object_list %}host {{ o.nom_machine }}     { hardware ethernet {{ o.adresse_mac }}; fixed-address {{ o.nom_dns_complet }};{% if o.is_st2030 %} option st2030-http "http://10.230.2.10/provisioning/ST2030.inf";{% endif %} }
+{% endfor %}
diff --git a/montreal/gestionmateriel/majsite/materiel/templates/fichier_dns-inverse.txt b/montreal/gestionmateriel/majsite/materiel/templates/fichier_dns-inverse.txt
new file mode 100644 (file)
index 0000000..779dd32
--- /dev/null
@@ -0,0 +1,5 @@
+; Fichier: /etc/bind/db.numero.reseau.inverse
+; Généré automatiquement depuis l'application "materiel",
+; ne pas éditer manuellement !
+{% for o in object_list %}{{ o.numero_machine }}       PTR {{ o.nom_dns_complet }}.
+{% endfor %}
diff --git a/montreal/gestionmateriel/majsite/materiel/templates/fichier_dns.txt b/montreal/gestionmateriel/majsite/materiel/templates/fichier_dns.txt
new file mode 100644 (file)
index 0000000..835195f
--- /dev/null
@@ -0,0 +1,5 @@
+; Fichier: /etc/bind/db.domaine.dns
+; Généré automatiquement depuis l'application "materiel",
+; ne pas éditer manuellement !
+{% for o in object_list %}{{ o.nom_machine }}  A {{ o.adresse_ip }}
+{% endfor %}
diff --git a/montreal/gestionmateriel/majsite/materiel/templates/fichier_ethers.txt b/montreal/gestionmateriel/majsite/materiel/templates/fichier_ethers.txt
new file mode 100644 (file)
index 0000000..4740a25
--- /dev/null
@@ -0,0 +1,5 @@
+# Fichier: /etc/ethers
+# Généré automatiquement depuis l'application "materiel",
+# ne pas éditer manuellement !
+{% for o in object_list %}{{ o.adresse_mac }}  {{ o.nom_machine }}
+{% endfor %}
diff --git a/montreal/gestionmateriel/majsite/materiel/templates/machine_list.html b/montreal/gestionmateriel/majsite/materiel/templates/machine_list.html
new file mode 100644 (file)
index 0000000..f2c1374
--- /dev/null
@@ -0,0 +1,19 @@
+<h2>Machines</h2>
+<table border="1" cellpadding="2">
+<tr>
+ <th>Nom DNS complet</th>
+ <th>Adresse IP</th>
+ <th>Adresse MAC</th>
+ <th>Catégorie</th>
+ <th>Emplacement</th>
+</tr>
+{% for machine in object_list %}
+<tr>
+ <td>{{ machine.nom_dns_complet }}</td>
+ <td>{{ machine.adresse_ip }}</td>
+ <td>{{ machine.adresse_mac }}</td>
+ <td>{{ machine.categorie }}</td>
+ <td>{{ machine.emplacement }}</td>
+</tr>
+{% endfor %}
+</table>
diff --git a/montreal/gestionmateriel/majsite/materiel/urls.py b/montreal/gestionmateriel/majsite/materiel/urls.py
new file mode 100644 (file)
index 0000000..0ffef81
--- /dev/null
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+from django.conf.urls.defaults import *
+from django.views.generic.list_detail import object_list
+from models import Machine
+from views import export_fichier
+
+urlpatterns = patterns('',
+    (r'^$', object_list, {'queryset': Machine.objects.all()}),
+    (r'^fichier/(?P<fichier>[\w-]+)$', export_fichier),
+    (r'^emplacement/(?P<emplacement>\w+)/(?P<fichier>[\w-]+)$', export_fichier),
+)
diff --git a/montreal/gestionmateriel/majsite/materiel/views.py b/montreal/gestionmateriel/majsite/materiel/views.py
new file mode 100644 (file)
index 0000000..b0e8683
--- /dev/null
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+from django.views.generic.list_detail import object_list
+from models import Machine
+
+def export_fichier(request, fichier, emplacement=None):
+    if emplacement is not None:
+        queryset = Machine.objects.filter(emplacement=emplacement)
+    else:
+        queryset = Machine.objects.all()
+    return object_list(
+        request,
+        queryset=queryset,
+        template_name="materiel/fichier_%s.txt" % fichier,
+        mimetype="text/plain; charset=utf-8"
+    )
diff --git a/montreal/gestionmateriel/majsite/settings/50-celery.py b/montreal/gestionmateriel/majsite/settings/50-celery.py
deleted file mode 100644 (file)
index 0b95d55..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-INSTALLED_APPS += (
-    'djcelery',
-)
-
-BROKER_URL = 'redis://localhost:6379/0'
-CELERY_ACCEPT_CONTENT = ['pickle', 'json', 'msgpack', 'yaml']
-
-import djcelery
-djcelery.setup_loader()
-
diff --git a/montreal/gestionmateriel/majsite/settings/50-rq.py b/montreal/gestionmateriel/majsite/settings/50-rq.py
new file mode 100644 (file)
index 0000000..c2520b3
--- /dev/null
@@ -0,0 +1,13 @@
+INSTALLED_APPS += ("django_rq",)
+
+RQ_QUEUES = {
+    'default': {
+        'HOST': 'localhost',
+        'PORT': 6379,
+        'DB': 0,
+        'PASSWORD': '',
+        'DEFAULT_TIMEOUT': 360,
+    },
+}
+
+RQ_SHOW_ADMIN_LINK = True
index 7c63b6d..3446cac 100644 (file)
@@ -13,7 +13,7 @@ ROOT_URLCONF = 'majsite.urls'
 INSTALLED_APPS += (
     'south',
     'raven.contrib.django',
-    'maj',
+    'materiel',
 )
 
 TEMPLATE_CONTEXT_PROCESSORS += (
diff --git a/montreal/gestionmateriel/majsite/urls/10-admin.py b/montreal/gestionmateriel/majsite/urls/10-admin.py
new file mode 100644 (file)
index 0000000..8ef18e0
--- /dev/null
@@ -0,0 +1,18 @@
+try:
+    from django.conf.urls.defaults import patterns, include, \
+        handler500, handler404, url
+except ImportError:
+    from django.conf.urls import patterns, include, \
+        handler500, handler404, url
+
+from django.contrib import admin
+
+admin.autodiscover()
+
+handler404
+handler500 # Pyflakes
+
+urlpatterns = patterns('',
+    url(r'^jsi18n/(?P<packages>\S+?)/$', 'django.views.i18n.javascript_catalog'),
+    url(r'', include(admin.site.urls)),
+)
index 88072f7..254af97 100644 (file)
@@ -7,7 +7,7 @@ except ImportError:
 
 from auf.django.saml import settings as saml_settings
 
-urlpatterns = patterns(
+urlpatterns += patterns(
     '',
     (r'^', include('auf.django.saml.urls')),
 )
diff --git a/montreal/gestionmateriel/majsite/urls/60-admin.py b/montreal/gestionmateriel/majsite/urls/60-admin.py
deleted file mode 100644 (file)
index 8ef18e0..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-try:
-    from django.conf.urls.defaults import patterns, include, \
-        handler500, handler404, url
-except ImportError:
-    from django.conf.urls import patterns, include, \
-        handler500, handler404, url
-
-from django.contrib import admin
-
-admin.autodiscover()
-
-handler404
-handler500 # Pyflakes
-
-urlpatterns = patterns('',
-    url(r'^jsi18n/(?P<packages>\S+?)/$', 'django.views.i18n.javascript_catalog'),
-    url(r'', include(admin.site.urls)),
-)
diff --git a/montreal/gestionmateriel/majsite/urls/60-rq.py b/montreal/gestionmateriel/majsite/urls/60-rq.py
new file mode 100644 (file)
index 0000000..4142d62
--- /dev/null
@@ -0,0 +1,5 @@
+from django.conf.urls import include, patterns
+
+urlpatterns += patterns('',
+    (r'^django-rq/', include('django_rq.urls')),
+)
index 03c34e9..3169d8e 100644 (file)
@@ -12,9 +12,7 @@ django-taggit
 django-siteblocks
 django-suit
 
-celery
-django-celery
-flower
+django-rq
 redis
 ansible
 
diff --git a/montreal/gestionmateriel/requirements/wheezy.txt b/montreal/gestionmateriel/requirements/wheezy.txt
new file mode 100644 (file)
index 0000000..a0ff884
--- /dev/null
@@ -0,0 +1,3 @@
+django>=1.4,<1.5
+South==0.7.5
+