SF.net SVN: gar:[23434] csw/mgar/gar/v2/lib/python/chkdbcat.py

guengel at users.sourceforge.net guengel at users.sourceforge.net
Sun Apr 20 13:52:46 CEST 2014


Revision: 23434
          http://sourceforge.net/p/gar/code/23434
Author:   guengel
Date:     2014-04-20 11:52:43 +0000 (Sun, 20 Apr 2014)
Log Message:
-----------
lib/python/chkdbcat.py: cache file can store date of last check for several catalog/arch/osrel. List of notified maintainers in cache file too. Notification when catalog is unbroken.

Modified Paths:
--------------
    csw/mgar/gar/v2/lib/python/chkdbcat.py

Modified: csw/mgar/gar/v2/lib/python/chkdbcat.py
===================================================================
--- csw/mgar/gar/v2/lib/python/chkdbcat.py	2014-04-20 09:51:06 UTC (rev 23433)
+++ csw/mgar/gar/v2/lib/python/chkdbcat.py	2014-04-20 11:52:43 UTC (rev 23434)
@@ -78,7 +78,8 @@
                                    "-output", os.path.join(catalogdir, "catalog")])
 
 class TimestampRecord(object):
-      """Record Timestamp for a given Catalog, Architecture, and OS Release into a json encoded file."""
+      """Record Timestamp for a given Catalog, Architecture, and OS Release
+into a json encoded file."""
       def __init__(self, fn):
             """Constructor.
 
@@ -143,7 +144,7 @@
             """
             catkey = (catrel, arch, osrel)
             if self.__ts_by_catalog.has_key(catkey):
-                  return dateutil.parser.parse(self.__ts_by_catalog[catkey])
+                  return dateutil.parser.parse(self.__ts_by_catalog[catkey]['timestamp'])
             else:
                   return None
 
@@ -155,20 +156,52 @@
 
             If date is an instance of str, it has to be a date in iso format.
 
+            In any case, set will clear the notified list.
+
             """
             assert date is not None
 
             catkey = (catrel, arch, osrel)
+            
+            if not catkey in self.__ts_by_catalog:
+                  self.__ts_by_catalog[catkey] = dict()
+
             if isinstance(date, datetime.datetime):
-                  self.__ts_by_catalog[catkey] = date.replace(microsecond=0).isoformat()
+                  self.__ts_by_catalog[catkey]['timestamp'] = date.replace(microsecond=0).isoformat()
             elif isinstance(date, str):
                   # try to convert string into datetime, so that we
                   # know it has proper format.
-                  self.__ts_by_catalog[catkey] = dateutil.parser.parse(date).isoformat()
+                  self.__ts_by_catalog[catkey]['timestamp'] = dateutil.parser.parse(date).isoformat()
             else:
                   raise TypeError("Expected instance of str or datetime, got %s" % str(type(date)))
+            # clear out the notified list
+            self.__ts_by_catalog[catkey]['notified'] = list()
 
+      def notified(self, catrel, arch, osrel, email):
+            catkey = (catrel, arch, osrel)
 
+            assert 'notified' in self.__ts_by_catalog[catkey]
+            assert type(self.__ts_by_catalog[catkey]['notified']) is list
+
+            self.__ts_by_catalog[catkey]['notified'].append(email)
+
+      def is_notified(self, catrel, arch, osrel, email):
+            catkey = (catrel, arch, osrel)
+
+            assert 'notified' in self.__ts_by_catalog[catkey]
+            assert type(self.__ts_by_catalog[catkey]['notified']) is list
+
+            return email in self.__ts_by_catalog[catkey]['notified']
+
+      def get_notified(self):
+            catkey = (catrel, arch, osrel)
+
+            assert 'notified' in self.__ts_by_catalog[catkey]
+            assert type(self.__ts_by_catalog[catkey]['notified']) is list
+
+            return self.__ts_by_catalog[catkey]['notified']            
+            
+
 class CatalogTiming(object):
       """Fetch Catalog Timing information.
 
@@ -371,8 +404,8 @@
                   return self.rest_client.GetMaintainerByMd5(
                       pkginfo['md5'])['maintainer_email']
 
-      def notify(self, date, addr, pkginfo):
-            """Notification.
+      def notify_broken(self, date, addr, pkginfo):
+            """Notification on broken database catalog.
 
             Will be called for each "addr" once. "pkginfo" is a list
             with packages as retrieved by 'CatalogTiming' since last
@@ -382,6 +415,15 @@
             logging.info("TO: %s" % addr)
             [logging.info("packge %s uploaded since %s might have caused catalog break" % (p['fullname'],str(date))) for p in pkginfo]
 
+      def notify_unbroken(self, date, addr):
+            """Notification on broken database catalog.
+
+            Will be called for each "addr" once. 
+
+            """
+            logging.info("TO: %s" % addr)
+            logging.info("catalog has been unbroken on %s" % (str(date),))
+
       def fetch_db_cat(self):
             """Fetch catalog stored in database into temporary direcotry."""
             assert self.tmpdir is not None
@@ -417,11 +459,18 @@
 
                   # Only record successful checks.
                   if retval:
+                        rightnow = datetime.datetime.now()
                         with self.__timestamp_record:
+                              try:
+                                    [self.notify_unbroken(rightnow, addr) for addr in
+                                     self.__timestamp_record.get_notified()]
+                              except Exception as ex:
+                                    logging.error("Error notifying about unbroken catalog: %s",
+                                                  repr(ex))
                               self.__timestamp_record.set(self._catrel,
                                                           self._arch,
                                                           self._osrel,
-                                                          datetime.datetime.now())
+                                                          rightnow)
 
                   # Compose list of packages uploaded since last successful
                   # check by `uploader'.
@@ -451,7 +500,7 @@
                               notifications[addr].setdefault('newpkgs', []).append(np)
 
                         for n in notifications:
-                              self.notify(notifications[n]['lastsuccessful'], n, notifications[n]['newpkgs'], self.stdout, self.stderr)
+                              self.notify_broken(notifications[n]['lastsuccessful'], n, notifications[n]['newpkgs'], self.stdout, self.stderr)
 
             return retval
 
@@ -461,7 +510,7 @@
 
       """
 
-      MAIL_TEMPLATE = u"""Hi there
+      MAIL_TEMPLATE_BROKEN = u"""Hi there
 
 You uploaded following packages
 
@@ -485,6 +534,12 @@
 
 """
 
+      MAIL_TEMPLATE_OK = u"""Hi There
+Apparently, somebody (maybe you) unbroke the Database Catalog on $date.
+
+Kudos.
+"""
+
       def __init__(self, cat_tuple, date, addr, pkginfo, chkcat_stdout, chkcat_stderr):
             self._cat_tuple = cat_tuple
             self._date = date
@@ -493,7 +548,7 @@
             self._chkcat_stdout = chkcat_stdout
             self._chkcat_stderr = chkcat_stderr
 
-      def _compose_mail(self, from_address):
+      def _compose_mail_broken(self, from_address):
             """Compose Mail"""
 
             namespace = {
@@ -503,7 +558,7 @@
                   'stdout': self._chkcat_stdout
             }
 
-            t = Template.Template(InformMaintainer.MAIL_TEMPLATE, searchList=[namespace])
+            t = Template.Template(InformMaintainer.MAIL_TEMPLATE_BROKEN, searchList=[namespace])
 
             mail = MIMEText(unicode(t))
             mail['From'] = from_address
@@ -512,15 +567,40 @@
 
             return mail
 
-      def send_mail(self):
+      def _compose_mail_unbroken(self, from_address):
+            namespace = {
+                  'date': self._date,
+            }
+
+            t = Template.Template(InformMaintainer.MAIL_TEMPLATE_OK, searchList=[namespace])
+
+            mail = MIMEText(unicode(t))
+            mail['From'] = from_address
+            mail['To'] = self._addr
+            mail['Subject'] = "[chkdbcat] Database Catalog unbroken"
+
+            return mail
+
+      def send_mail_broken(self):
             from_address = "Check Database Catalog <noreply at opencsw.org>"
             s = smtplib.SMTP('mail.opencsw.org')
             try:
                   s.sendmail(from_address, [self._addr],
-                             self._compose_mail(from_address).as_string())
+                             self._compose_mail_broken(from_address).as_string())
                   logging.debug("E-mail sending finished.")
             except smtplib.SMTPRecipientsRefused, e:
                   logging.error(
                         "Sending email to %s failed, recipient refused.",
                         repr(self._addr))
             
+      def send_mail_unbroken(self):
+            from_address = "Check Database Catalog <noreply at opencsw.org>"
+            s = smtplib.SMTP('mail.opencsw.org')
+            try:
+                  s.sendmail(from_address, [self._addr],
+                             self._compose_mail_unbroken(from_address).as_string())
+                  logging.debug("E-mail sending finished.")
+            except smtplib.SMTPRecipientsRefused, e:
+                  logging.error(
+                        "Sending email to %s failed, recipient refused.",
+                        repr(self._addr))

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the devel mailing list