]> git.ipfire.org Git - ddns.git/commitdiff
Merge branch 'database'
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 14 Sep 2014 18:10:43 +0000 (18:10 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 14 Sep 2014 18:10:43 +0000 (18:10 +0000)
1  2 
src/ddns/providers.py

diff --combined src/ddns/providers.py
index b13565e9f8c530d44e0b74b09c197e0eed6f19cb,28bdf41613cd0fd22649bbfa020fe5da82782510..c6ef5c0d7c0cd0a22e4f43d8ead72615e35d6e25
@@@ -19,6 -19,7 +19,7 @@@
  #                                                                             #
  ###############################################################################
  
+ import datetime
  import logging
  import subprocess
  import urllib2
@@@ -57,6 -58,10 +58,10 @@@ class DDNSProvider(object)
  
        DEFAULT_SETTINGS = {}
  
+       # holdoff time - Number of days no update is performed unless
+       # the IP address has changed.
+       holdoff_days = 30
        # Automatically register all providers.
        class __metaclass__(type):
                def __init__(provider, name, bases, dict):
        def __cmp__(self, other):
                return cmp(self.hostname, other.hostname)
  
+       @property
+       def db(self):
+               return self.core.db
        def get(self, key, default=None):
                """
                        Get a setting from the settings dictionary.
                if force:
                        logger.debug(_("Updating %s forced") % self.hostname)
  
-               # Check if we actually need to update this host.
-               elif self.is_uptodate(self.protocols):
-                       logger.debug(_("The dynamic host %(hostname)s (%(provider)s) is already up to date") % \
-                               { "hostname" : self.hostname, "provider" : self.name })
+               # Do nothing if no update is required
+               elif not self.requires_update:
                        return
  
                # Execute the update.
-               self.update()
+               try:
+                       self.update()
+               # In case of any errors, log the failed request and
+               # raise the exception.
+               except DDNSError as e:
+                       self.core.db.log_failure(self.hostname, e)
+                       raise
  
                logger.info(_("Dynamic DNS update for %(hostname)s (%(provider)s) successful") % \
                        { "hostname" : self.hostname, "provider" : self.name })
+               self.core.db.log_success(self.hostname)
  
        def update(self):
                for protocol in self.protocols:
                # Maybe this will raise NotImplementedError at some time
                #raise NotImplementedError
  
-       def is_uptodate(self, protos):
+       @property
+       def requires_update(self):
+               # If the IP addresses have changed, an update is required
+               if self.ip_address_changed(self.protocols):
+                       logger.debug(_("An update for %(hostname)s (%(provider)s)"
+                               " is performed because of an IP address change") % \
+                               { "hostname" : self.hostname, "provider" : self.name })
+                       return True
+               # If the holdoff time has expired, an update is required, too
+               if self.holdoff_time_expired():
+                       logger.debug(_("An update for %(hostname)s (%(provider)s)"
+                               " is performed because the holdoff time has expired") % \
+                               { "hostname" : self.hostname, "provider" : self.name })
+                       return True
+               # Otherwise, we don't need to perform an update
+               logger.debug(_("No update required for %(hostname)s (%(provider)s)") % \
+                       { "hostname" : self.hostname, "provider" : self.name })
+               return False
+       def ip_address_changed(self, protos):
                """
                        Returns True if this host is already up to date
                        and does not need to change the IP address on the
                                continue
  
                        if not current_address in addresses:
-                               return False
+                               return True
+               return False
+       def holdoff_time_expired(self):
+               """
+                       Returns true if the holdoff time has expired
+                       and the host requires an update
+               """
+               # If no holdoff days is defined, we cannot go on
+               if not self.holdoff_days:
+                       return False
+               # Get the timestamp of the last successfull update
+               last_update = self.db.last_update(self.hostname)
+               # If no timestamp has been recorded, no update has been
+               # performed. An update should be performed now.
+               if not last_update:
+                       return True
  
-               return True
+               # Determine when the holdoff time ends
+               holdoff_end = last_update + datetime.timedelta(days=self.holdoff_days)
+               now = datetime.datetime.utcnow()
+               if now >= holdoff_end:
+                       logger.debug("The holdoff time has expired for %s" % self.hostname)
+                       return True
+               else:
+                       logger.debug("Updates for %s are held off until %s" % \
+                               (self.hostname, holdoff_end))
+                       return False
  
        def send_request(self, *args, **kwargs):
                """
@@@ -795,25 -864,6 +864,25 @@@ class DDNSProviderLightningWireLabs(DDN
                raise DDNSUpdateError
  
  
 +class DDNSProviderMyOnlinePortal(DDNSProtocolDynDNS2, DDNSProvider):
 +      handle    = "myonlineportal.net"
 +      name      = "myonlineportal.net"
 +      website   = "https:/myonlineportal.net/"
 +
 +      # Information about the request and response can be obtained here:
 +      # https://myonlineportal.net/howto_dyndns
 +
 +      url = "https://myonlineportal.net/updateddns"
 +
 +      def prepare_request_data(self, proto):
 +              data = {
 +                      "hostname" : self.hostname,
 +                      "ip"     : self.get_address(proto),
 +              }
 +
 +              return data
 +
 +
  class DDNSProviderNamecheap(DDNSResponseParserXML, DDNSProvider):
        handle    = "namecheap.com"
        name      = "Namecheap"
@@@ -904,7 -954,7 +973,7 @@@ class DDNSProviderNsupdateINFO(DDNSProt
  
        @property
        def password(self):
 -              return self.get("secret")
 +              return self.token or self.get("secret")
  
        @property
        def url(self):
@@@ -1059,6 -1109,7 +1128,6 @@@ class DDNSProviderSPDNS(DDNSProtocolDyn
        handle    = "spdns.org"
        name      = "SPDNS"
        website   = "http://spdns.org/"
 -      protocols = ("ipv4",)
  
        # Detailed information about request and response codes are provided
        # by the vendor. They are using almost the same mechanism and status