apply triggers patch from Steve Salevan <ssalevan@redhat.com>
authorAdrian Likins <alikins@redhat.com>
Tue, 22 Apr 2008 18:36:17 +0000 (14:36 -0400)
committerAdrian Likins <alikins@redhat.com>
Tue, 22 Apr 2008 18:36:17 +0000 (14:36 -0400)
Steves comments:
Adding in triggering functionality, changed specfile and
MANIFEST.in to reflect changes.  Added sub_process.py file to
facilitate the subprocesses necessary for triggering to work.
Modified certmaster.py to add trigger points.

MANIFEST.in
certmaster.spec
certmaster/certmaster.py
certmaster/utils.py
setup.py

index bc0e08b..782337c 100644 (file)
@@ -4,6 +4,7 @@ recursive-include docs *
 recursive-include init-scripts *
 recursive-include po *.po
 recursive-include po *.pot
+recursice-include triggers *
 include AUTHORS
 include LICENSE
 include README
index bb252cc..e6868aa 100644 (file)
@@ -63,6 +63,12 @@ rm -fr $RPM_BUILD_ROOT
 %{python_sitelib}/certmaster/*.py*
 %dir /var/log/certmaster
 %dir /var/lib/certmaster
+%dir /var/lib/certmaster/triggers/sign/pre
+%dir /var/lib/certmaster/triggers/sign/post
+%dir /var/lib/certmaster/triggers/request/pre
+%dir /var/lib/certmaster/triggers/request/post
+%dir /var/lib/certmaster/triggers/remove/pre
+%dir /var/lib/certmaster/triggers/remove/post
 %doc AUTHORS README LICENSE
 %{_mandir}/man1/*.1.gz
 
@@ -99,6 +105,9 @@ fi
 
 
 %changelog
+* Tue Apr 15 2008 Steve Salevan <ssalevan@redhat.com> - 0.1-3
+- added in trigger directories
+
 * Mon Mar 17 2008 Adrian Likins <alikins@redhat.com> - 0.1-2
 - removed unused minion/ and overlord/ dirs
 
index 1bf3a2d..970ff59 100755 (executable)
@@ -90,7 +90,7 @@ class CertMaster(object):
         commonname = commonname.replace('\\', '')       
         return commonname
     
-    def wait_for_cert(self, csrbuf):
+    def wait_for_cert(self, csrbuf, with_triggers=True):
         """
            takes csr as a string
            returns True, caller_cert, ca_cert
@@ -104,7 +104,9 @@ class CertMaster(object):
             return False, '', ''
             
         requesting_host = self._sanitize_cn(csrreq.get_subject().CN)
-        
+
+        if with_triggers:
+            self._run_triggers(None, '/var/lib/certmaster/triggers/request/pre/*') 
 
         self.logger.info("%s requested signing of cert %s" % (requesting_host,csrreq.get_subject().CN))
         # get rid of dodgy characters in the filename we're about to make
@@ -137,6 +139,8 @@ class CertMaster(object):
             slavecert = certs.retrieve_cert_from_file(certfile)
             cert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, slavecert)
             cacert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, self.cacert)
+            if with_triggers:
+                self._run_triggers(None,'/var/lib/certmaster/triggers/request/post/*')
             return True, cert_buf, cacert_buf
         
         # if we don't have a cert then:
@@ -149,6 +153,8 @@ class CertMaster(object):
             cert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
             cacert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, self.cacert)
             self.logger.info("cert for %s was autosigned" % (requesting_host))
+            if with_triggers:
+                self._run_triggers(None,'/var/lib/certmaster/triggers/request/post/*')
             return True, cert_buf, cacert_buf
         
         else:
@@ -158,6 +164,8 @@ class CertMaster(object):
             destfo.close()
             del destfo
             self.logger.info("cert for %s created and ready to be signed" % (requesting_host))
+            if with_triggers:
+                self._run_triggers(None,'/var/lib/certmaster/triggers/request/post/*')
             return False, '', ''
 
         return False, '', ''
@@ -172,7 +180,7 @@ class CertMaster(object):
             hosts.append(hn)
         return hosts
    
-    def remove_this_cert(self, hn):
+    def remove_this_cert(self, hn, with_triggers=True):
         """ removes cert for hostname using unlink """
         cm = self
         csrglob = '%s/%s.csr' % (cm.cfg.csrroot, hn)
@@ -183,12 +191,16 @@ class CertMaster(object):
             # FIXME: should be an exception?
             print 'No match for %s to clean up' % hn
             return
+        if with_triggers:
+            self._run_triggers(None,'/var/lib/certmaster/triggers/remove/pre/*')
         for fn in csrs + certs:
             print 'Cleaning out %s for host matching %s' % (fn, hn)
             self.logger.info('Cleaning out %s for host matching %s' % (fn, hn))
-            os.unlink(fn)         
+            os.unlink(fn)
+        if with_triggers:
+            self._run_triggers(None,'/var/lib/certmaster/triggers/remove/post/*')
             
-    def sign_this_csr(self, csr):
+    def sign_this_csr(self, csr, with_triggers=True):
         """returns the path to the signed cert file"""
         csr_unlink_file = None
 
@@ -216,6 +228,9 @@ class CertMaster(object):
         else: # assume we got a bare csr req
             csrreq = csr
 
+        if with_triggers:
+            self._run_triggers(None,'/var/lib/certmaster/triggers/sign/pre/*')
+
 
         requesting_host = self._sanitize_cn(csrreq.get_subject().CN)        
         certfile = '%s/%s.cert' % (self.cfg.certroot, requesting_host)
@@ -228,13 +243,18 @@ class CertMaster(object):
         del destfo
 
 
-        self.logger.info("csr %s signed" % (certfile)) 
+        self.logger.info("csr %s signed" % (certfile))
+        if with_triggers:
+            self._run_triggers(None,'/var/lib/certmaster/triggers/sign/post/*')
+
+        
         if csr_unlink_file and os.path.exists(csr_unlink_file):
             os.unlink(csr_unlink_file)
             
         return certfile
         
-
+    def _run_triggers(self, ref, globber):
+        return utils.run_triggers(ref, globber)
 
 
 class CertmasterXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
index eec3d2b..209e758 100755 (executable)
@@ -24,6 +24,7 @@ import certs
 from config import read_config
 from commonconfig import MinionConfig
 import logger
+import sub_process
 
 # FIXME: module needs better pydoc
 
@@ -108,6 +109,7 @@ def get_hostname(talk_to_certmaster=True):
         try:
             s = socket.socket()
             s.settimeout(5)
+           print "server, port", server, port
             s.connect((server, port))
             (intf, port) = s.getsockname()
             remote_hostname = socket.gethostbyaddr(intf)[0]
@@ -191,6 +193,37 @@ def create_minion_keys():
         os.write(ca_cert_fd, ca_cert_string)
         os.close(ca_cert_fd)
 
+def run_triggers(ref, globber):
+    """
+    Runs all the trigger scripts in a given directory.
+    ref can be a certmaster object, if not None, the name will be passed
+    to the script.  If ref is None, the script will be called with
+    no argumenets.  Globber is a wildcard expression indicating which
+    triggers to run.  Example:  "/var/lib/certmaster/triggers/blah/*"
+    """
+
+    log = logger.Logger().logger
+    triggers = glob.glob(globber)
+    triggers.sort()
+    for file in triggers:
+        log.debug("Executing trigger: %s" % file)
+        try:
+            if file.find(".rpm") != -1:
+                # skip .rpmnew files that may have been installed
+                # in the triggers directory
+                continue
+            if ref:
+                rc = sub_process.call([file, ref.name], shell=False)
+            else:
+                rc = sub_process.call([file], shell=False)
+        except:
+            log.warning("Warning: failed to execute trigger: %s" % file)
+            continue
+
+        if rc != 0:
+            raise codes.CMException, "certmaster trigger failed: %(file)s returns %(code)d" % { "file" : file, "code" : rc }
+
+
 def submit_csr_to_master(csr_file, master_uri):
     """"
     gets us our cert back from the certmaster.wait_for_cert() method
index bd1cf53..e47e1b0 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -18,6 +18,7 @@ if __name__ == "__main__":
         initpath   = "/etc/init.d/"
         logpath    = "/var/log/%s/" % NAME
        certdir    = "/var/lib/%s/" % NAME
+       trigpath   = "/var/lib/%s/triggers/"% NAME
         pkipath    = "/etc/pki/%s" % NAME
         rotpath    = "/etc/logrotate.d"
         aclpath    = "%s/minion-acl.d" % etcpath
@@ -48,7 +49,13 @@ if __name__ == "__main__":
                              (certdir,  []),
                              (etcpath,  []),
                              (pkipath,  []),
-                             (aclpath,  [])
+                             (aclpath,  []),
+                             ("%s/sign/pre/"     % trigpath, []),
+                              ("%s/sign/post/"    % trigpath, []),
+                              ("%s/remove/pre/"   % trigpath, []),
+                              ("%s/remove/post/"  % trigpath, []),
+                              ("%s/request/pre/"  % trigpath, []),
+                              ("%s/request/post/" % trigpath, []),
                 ],
                 description = SHORT_DESC,
                 long_description = LONG_DESC