#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)
 - `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
 - `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
 - `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
 - `DEBUG` : Enable debug for development **do not use in production** : display
    stracktraces and enable [django-debug-toolbar](https://django-debug-toolbar.readthedocs.io).
    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 -*-
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 from __future__ import unicode_literals
 
 
+import logging
+
 from django.db import models
 from django.db import models
 from polymorphic import PolymorphicModel
 from polymorphic import PolymorphicModel
 from coin.offers.models import OfferSubscription
 from coin.offers.models import OfferSubscription
 from django.db.models.signals import post_save, post_delete
 from django.db.models.signals import post_save, post_delete
 from django.core.exceptions import ObjectDoesNotExist
 from django.core.exceptions import ObjectDoesNotExist
 from django.dispatch import receiver
 from django.dispatch import receiver
+from django.conf import settings
 
 
 from coin.resources.models import IPSubnet
 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
 To add a new configuration backend, you have to create a new app with a model
 which inherit from Configuration.
 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.
 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
         Génère automatiquement la liste de choix possibles de configurations
         en fonction des classes enfants de Configuration
         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__())
             for x in Configuration.__subclasses__())
-    
+
     def model_name(self):
     def model_name(self):
         return self.__class__.__name__
         return self.__class__.__name__
     model_name.short_description = 'Nom du modèle'
     model_name.short_description = 'Nom du modèle'
@@ -52,7 +55,7 @@ class Configuration(PolymorphicModel):
         Une url doit être nommée "details"
         Une url doit être nommée "details"
         """
         """
         from django.core.urlresolvers import reverse
         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)])
                        args=[str(self.id)])
 
 
     def get_url_namespace(self):
     def get_url_namespace(self):
@@ -70,8 +73,38 @@ class Configuration(PolymorphicModel):
         verbose_name = 'configuration'
         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)
 @receiver(post_save, sender=IPSubnet)
+def subnet_event_save(sender, **kwargs):
+    kwargs["signal_type"] = "save"
+    subnet_event(sender, **kwargs)
+
+
 @receiver(post_delete, sender=IPSubnet)
 @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):
 def subnet_event(sender, **kwargs):
     """Fires when a subnet is created, modified or deleted.  We tell the
     """Fires when a subnet is created, modified or deleted.  We tell the
     configuration backend to do whatever it needs to do with it.
     configuration backend to do whatever it needs to do with it.
@@ -105,5 +138,21 @@ def subnet_event(sender, **kwargs):
         config = subnet.configuration
         config = subnet.configuration
         if hasattr(config, 'subnet_event'):
         if hasattr(config, 'subnet_event'):
             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:
     except ObjectDoesNotExist:
         pass
         pass

+ 8 - 0
coin/settings_base.py

@@ -216,6 +216,10 @@ LOGGING = {
         "coin.billing": {
         "coin.billing": {
             'handlers': ['console'],
             'handlers': ['console'],
             'level': 'INFO',
             'level': 'INFO',
+        },
+        "coin.subnets": {
+            'handlers': ['console'],
+            'level': 'INFO',
         }
         }
     }
     }
 }
 }
@@ -302,3 +306,7 @@ HANDLE_BALANCE = False
 
 
 # Add subscription comments in invoice items
 # Add subscription comments in invoice items
 INVOICES_INCLUDE_CONFIG_COMMENTS = True
 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})"