#184 Log des attributions d'ip

Open
ljf wants to merge 5 commits from ARN/enh-ip-allocation-logging into FFDN/master
3 changed files with 62 additions and 4 deletions
  1. 1 0
      README.md
  2. 53 4
      coin/configuration/models.py
  3. 8 0
      coin/settings_base.py

+ 1 - 0
README.md

@@ -349,6 +349,7 @@ List of available settings in your `settings_local.py` file.
 - `HANDLE_BALANCE`: Allows to handle money balances for members (False default)
 - `INVOICES_INCLUDE_CONFIG_COMMENTS`: Add comment related to a subscription configuration when generating invoices
 - `MEMBER_CAN_EDIT_VPN_CONF`: Allow members to edit some part of their vpn configuration
+- `IP_ALLOCATION_MESSAGE`: Template string that will be used to log IP allocation in the corresponding coin.subnets logging system
 - `DEBUG` : Enable debug for development **do not use in production** : display
    stracktraces and enable [django-debug-toolbar](https://django-debug-toolbar.readthedocs.io).
 

+ 53 - 4
coin/configuration/models.py

@@ -1,12 +1,15 @@
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
+import logging
+
 from django.db import models
 from polymorphic import PolymorphicModel
 from coin.offers.models import OfferSubscription
 from django.db.models.signals import post_save, post_delete
 from django.core.exceptions import ObjectDoesNotExist
 from django.dispatch import receiver
+from django.conf import settings
 
 from coin.resources.models import IPSubnet
 
@@ -17,7 +20,7 @@ technical informations of a subscription.
 
 To add a new configuration backend, you have to create a new app with a model
 which inherit from Configuration.
-Your model can implement Meta verbose_name to have human readable name and a 
+Your model can implement Meta verbose_name to have human readable name and a
 url_namespace variable to specify the url namespace used by this model.
 """
 
@@ -35,9 +38,9 @@ class Configuration(PolymorphicModel):
         Génère automatiquement la liste de choix possibles de configurations
         en fonction des classes enfants de Configuration
         """
-        return tuple((x().__class__.__name__,x()._meta.verbose_name) 
+        return tuple((x().__class__.__name__,x()._meta.verbose_name)
             for x in Configuration.__subclasses__())
-    
+
     def model_name(self):
         return self.__class__.__name__
     model_name.short_description = 'Nom du modèle'
@@ -52,7 +55,7 @@ class Configuration(PolymorphicModel):
         Une url doit être nommée "details"
         """
         from django.core.urlresolvers import reverse
-        return reverse('%s:details' % self.get_url_namespace(), 
+        return reverse('%s:details' % self.get_url_namespace(),
                        args=[str(self.id)])
 
     def get_url_namespace(self):
@@ -70,8 +73,38 @@ class Configuration(PolymorphicModel):
         verbose_name = 'configuration'
 
 
+@receiver(post_save, sender=OfferSubscription)
+def offer_subscription_event(sender, **kwargs):
+    os = kwargs['instance']
+
+    if not hasattr(os, 'configuration'):
+        config_cls = None
+        for subconfig_cls in Configuration.__subclasses__():
+            if subconfig_cls().__class__.__name__ == os.offer.configuration_type:
+                config_cls = subconfig_cls
+                break
+
+        if config_cls is not None:
+            config = config_cls.objects.create(offersubscription=os)
+            for offer_ip_pool in os.offer.offerippool_set.order_by('-to_assign'):
+                IPSubnet.objects.create(
+                                configuration=config,
+                                ip_pool=offer_ip_pool.ip_pool)
+            config.save()
+
+
 @receiver(post_save, sender=IPSubnet)
+def subnet_event_save(sender, **kwargs):
+    kwargs["signal_type"] = "save"
+    subnet_event(sender, **kwargs)
+
+
 @receiver(post_delete, sender=IPSubnet)
+def subnet_event_delete(sender, **kwargs):
+    kwargs["signal_type"] = "delete"
+    subnet_event(sender, **kwargs)
+
+subnet_log = logging.getLogger("coin.subnets")
 def subnet_event(sender, **kwargs):
     """Fires when a subnet is created, modified or deleted.  We tell the
     configuration backend to do whatever it needs to do with it.
@@ -105,5 +138,21 @@ def subnet_event(sender, **kwargs):
         config = subnet.configuration
         if hasattr(config, 'subnet_event'):
             config.subnet_event()
+
+        offer = config.offersubscription.offer.name
+        ref = config.offersubscription.get_subscription_reference()
+        member = config.offersubscription.member
+        ip = subnet.inet
+
+        if kwargs['signal_type'] == "save":
+            msg = "[Allocating IP] " + settings.IP_ALLOCATION_MESSAGE
+        elif kwargs['signal_type'] == "delete":
+            msg = "[Deallocating IP] " + settings.IP_ALLOCATION_MESSAGE
+        else:
+            # Does not happens
+            msg = ""
+
+        subnet_log.debug(msg.format(ip=ip, member=member, offer=offer, ref=ref))
+
     except ObjectDoesNotExist:
         pass

+ 8 - 0
coin/settings_base.py

@@ -216,6 +216,10 @@ LOGGING = {
         "coin.billing": {
             'handlers': ['console'],
             'level': 'INFO',
+        },
+        "coin.subnets": {
+            'handlers': ['console'],
+            'level': 'INFO',
         }
     }
 }
@@ -302,3 +306,7 @@ HANDLE_BALANCE = False
 
 # Add subscription comments in invoice items
 INVOICES_INCLUDE_CONFIG_COMMENTS = True
+
+# String template used for the IP allocation log (c.f. coin.subnet loggers
+# This will get prefixed by [Allocating IP] or [Desallocating IP]
+IP_ALLOCATION_MESSAGE = "{ip} to {member.pk} ({member.username} - {member.first_name} {member.last_name}) (for offer {offer}, {ref})"