sfaprotocol is renamed into sfaserverproxy, with class SfaServerProxy
[sfa.git] / sfa / client / sfascan.py
old mode 100755 (executable)
new mode 100644 (file)
index 4120e85..fdfa580
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
 import sys, os.path
 import pickle
 import time
 import sys, os.path
 import pickle
 import time
@@ -7,13 +5,16 @@ import socket
 import traceback
 from urlparse import urlparse
 
 import traceback
 from urlparse import urlparse
 
-import pygraphviz
+try:
+    import pygraphviz
+except:
+    print 'Warning, could not import pygraphviz, test mode only'
 
 from optparse import OptionParser
 
 from sfa.client.sfi import Sfi
 from sfa.util.sfalogging import logger, DEBUG
 
 from optparse import OptionParser
 
 from sfa.client.sfi import Sfi
 from sfa.util.sfalogging import logger, DEBUG
-import sfa.client.xmlrpcprotocol as xmlrpcprotocol
+from sfa.client.sfaserverproxy import SfaServerProxy
 
 def url_hostname_port (url):
     if url.find("://")<0:
 
 def url_hostname_port (url):
     if url.find("://")<0:
@@ -50,9 +51,9 @@ class VersionCache:
             self.url2version=pickle.load(infile)
             infile.close()
         except:
             self.url2version=pickle.load(infile)
             infile.close()
         except:
-            logger.info("Cannot load version cache, restarting from scratch")
+            logger.debug("Cannot load version cache, restarting from scratch")
             self.url2version = {}
             self.url2version = {}
-        logger.debug("loaded version cache with %d entries"%(len(self.url2version)))
+        logger.debug("loaded version cache with %d entries %s"%(len(self.url2version),self.url2version.keys()))
 
     def save (self):
         try:
 
     def save (self):
         try:
@@ -63,25 +64,35 @@ class VersionCache:
             logger.log_exc ("Cannot save version cache into %s"%self.filename)
     def clean (self):
         try:
             logger.log_exc ("Cannot save version cache into %s"%self.filename)
     def clean (self):
         try:
-            os.unlink(self.filename)
-            logger.info("Cleaned up version cache %s"%self.filename)
+            retcod=os.unlink(self.filename)
+            logger.info("Cleaned up version cache %s, retcod=%d"%(self.filename,retcod))
         except:
         except:
-            logger.log_exc ("Could not unlink version cache %s"%self.filename)
+            logger.info ("Could not unlink version cache %s"%self.filename)
 
     def show (self):
         entries=len(self.url2version)
         print "version cache from file %s has %d entries"%(self.filename,entries)
 
     def show (self):
         entries=len(self.url2version)
         print "version cache from file %s has %d entries"%(self.filename,entries)
-        for (url,tuple) in self.url2version.iteritems():
+        key_values=self.url2version.items()
+        def old_first (kv1,kv2): return int(kv1[1][0]-kv2[1][0])
+        key_values.sort(old_first)
+        for key_value in key_values:
+            (url,tuple) = key_value
             (timestamp,version) = tuple
             how_old = time.time()-timestamp
             if how_old<=self.expires:
             (timestamp,version) = tuple
             how_old = time.time()-timestamp
             if how_old<=self.expires:
-                print url,"(%d seconds ago)"%how_old,"-> keys=",version.keys()
+                print url,"-- %d seconds ago"%how_old
             else:
             else:
-                print url,"(%d seconds ago)"%how_old,"too old"
+                print "OUTDATED",url,"(%d seconds ago, expires=%d)"%(how_old,self.expires)
     
     
+    # turns out we might have trailing slashes or not
+    def normalize (self, url):
+        return url.strip("/")
+        
     def set (self,url,version):
     def set (self,url,version):
+        url=self.normalize(url)
         self.url2version[url]=( time.time(), version)
     def get (self,url):
         self.url2version[url]=( time.time(), version)
     def get (self,url):
+        url=self.normalize(url)
         try:
             (timestamp,version)=self.url2version[url]
             how_old = time.time()-timestamp
         try:
             (timestamp,version)=self.url2version[url]
             how_old = time.time()-timestamp
@@ -121,8 +132,9 @@ class Interface:
         if self.probed:
             return self._version
         ### otherwise let's look in the cache file
         if self.probed:
             return self._version
         ### otherwise let's look in the cache file
+        logger.debug("searching in version cache %s"%self.url())
         cached_version = VersionCache().get(self.url())
         cached_version = VersionCache().get(self.url())
-        if cached_version:
+        if cached_version is not None:
             logger.info("Retrieved version info from cache")
             return cached_version
         ### otherwise let's do the hard work
             logger.info("Retrieved version info from cache")
             return cached_version
         ### otherwise let's do the hard work
@@ -137,11 +149,12 @@ class Interface:
             client.read_config()
             key_file = client.get_key_file()
             cert_file = client.get_cert_file(key_file)
             client.read_config()
             key_file = client.get_key_file()
             cert_file = client.get_cert_file(key_file)
+            logger.debug("using key %s & cert %s"%(key_file,cert_file))
             url=self.url()
             logger.info('issuing GetVersion at %s'%url)
             # setting timeout here seems to get the call to fail - even though the response time is fast
             url=self.url()
             logger.info('issuing GetVersion at %s'%url)
             # setting timeout here seems to get the call to fail - even though the response time is fast
-            #server=xmlrpcprotocol.server_proxy(url, key_file, cert_file, verbose=self.verbose, timeout=options.timeout)
-            server=xmlrpcprotocol.server_proxy(url, key_file, cert_file, verbose=self.verbose)
+            #server=SfaServerProxy(url, key_file, cert_file, verbose=self.verbose, timeout=options.timeout)
+            server=SfaServerProxy(url, key_file, cert_file, verbose=self.verbose)
             self._version=server.GetVersion()
         except:
             logger.log_exc("failed to get version")
             self._version=server.GetVersion()
         except:
             logger.log_exc("failed to get version")
@@ -152,7 +165,7 @@ class Interface:
         cache=VersionCache()
         cache.set(self.url(),self._version)
         cache.save()
         cache=VersionCache()
         cache.set(self.url(),self._version)
         cache.save()
-        logger.info("Saved version for url=%s in version cache"%self.url())
+        logger.debug("Saved version for url=%s in version cache"%self.url())
         # that's our result
         return self._version
 
         # that's our result
         return self._version
 
@@ -202,7 +215,7 @@ class Interface:
             layout['fillcolor']='gray'
         return layout
 
             layout['fillcolor']='gray'
         return layout
 
-class SfaScan:
+class Scanner:
 
     # provide the entry points (a list of interfaces)
     def __init__ (self, left_to_right=False, verbose=False):
 
     # provide the entry points (a list of interfaces)
     def __init__ (self, left_to_right=False, verbose=False):
@@ -234,19 +247,18 @@ class SfaScan:
         while to_scan:
             for interface in to_scan:
                 # performing xmlrpc call
         while to_scan:
             for interface in to_scan:
                 # performing xmlrpc call
+                logger.info("retrieving/fetching version at interface %s"%interface.url())
                 version=interface.get_version()
                 version=interface.get_version()
-                if self.verbose:
-                    logger.info("GetVersion at interface %s"%interface.url())
-                    if not version:
-                        logger.info("<EMPTY GetVersion(); offline or cannot authenticate>")
-                    else: 
-                        for (k,v) in version.iteritems(): 
-                            if not isinstance(v,dict):
-                                logger.info("\r\t%s:%s"%(k,v))
-                            else:
-                                logger.info(k)
-                                for (k1,v1) in v.iteritems():
-                                    logger.info("\r\t\t%s:%s"%(k1,v1))
+                if not version:
+                    logger.info("<EMPTY GetVersion(); offline or cannot authenticate>")
+                else: 
+                    for (k,v) in version.iteritems(): 
+                        if not isinstance(v,dict):
+                            logger.debug("\r\t%s:%s"%(k,v))
+                        else:
+                            logger.debug(k)
+                            for (k1,v1) in v.iteritems():
+                                logger.debug("\r\t\t%s:%s"%(k1,v1))
                 # 'geni_api' is expected if the call succeeded at all
                 # 'peers' is needed as well as AMs typically don't have peers
                 if 'geni_api' in version and 'peers' in version: 
                 # 'geni_api' is expected if the call succeeded at all
                 # 'peers' is needed as well as AMs typically don't have peers
                 if 'geni_api' in version and 'peers' in version: 
@@ -276,51 +288,60 @@ class SfaScan:
                     logger.error("MISSED interface with node %s"%node)
     
 
                     logger.error("MISSED interface with node %s"%node)
     
 
-default_outfiles=['sfa.png','sfa.svg','sfa.dot']
+class SfaScan:
 
 
-def main():
-    usage="%prog [options] url-entry-point(s)"
-    parser=OptionParser(usage=usage)
-    parser.add_option("-o","--output",action='append',dest='outfiles',default=[],
-                      help="output filenames (cumulative) - defaults are %r"%default_outfiles)
-    parser.add_option("-l","--left-to-right",action="store_true",dest="left_to_right",default=False,
-                      help="instead of top-to-bottom")
-    parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
-                      help="verbose - can be repeated for more verbosity")
-    parser.add_option("-c", "--clear-cache",action='store_true',
-                      dest='clear_cache',default=False,
-                      help='clear/trash version cache and exit')
-    parser.add_option("-s","--show-cache",action='store_true',
-                      dest='show_cache',default=False,
-                      help='show/display version cache')
-    
-    (options,args)=parser.parse_args()
-    if options.show_cache: 
-        VersionCache().show()
-        sys.exit(0)
-    if options.clear_cache:
-        VersionCache().clean()
-        sys.exit(0)
-    if not args:
-        parser.print_help()
-        sys.exit(1)
+    default_outfiles=['sfa.png','sfa.svg','sfa.dot']
+
+    def main(self):
+        usage="%prog [options] url-entry-point(s)"
+        parser=OptionParser(usage=usage)
+        parser.add_option("-d", "--dir", dest="sfi_dir",
+                          help="config & working directory - default is " + Sfi.default_sfi_dir(),
+                          metavar="PATH", default=Sfi.default_sfi_dir())
+        parser.add_option("-o","--output",action='append',dest='outfiles',default=[],
+                          help="output filenames (cumulative) - defaults are %r"%SfaScan.default_outfiles)
+        parser.add_option("-l","--left-to-right",action="store_true",dest="left_to_right",default=False,
+                          help="instead of top-to-bottom")
+        parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
+                          help="verbose - can be repeated for more verbosity")
+        parser.add_option("-c", "--clean-cache",action='store_true',
+                          dest='clean_cache',default=False,
+                          help='clean/trash version cache and exit')
+        parser.add_option("-s","--show-cache",action='store_true',
+                          dest='show_cache',default=False,
+                          help='show/display version cache')
         
         
-    if not options.outfiles:
-        options.outfiles=default_outfiles
-    logger.enable_console()
-    # apply current verbosity to logger
-    logger.setLevelFromOptVerbose(options.verbose)
-    # figure if we need to be verbose for these local classes that only have a bool flag
-    bool_verbose=logger.getBoolVerboseFromOpt(options.verbose)
-    scanner=SfaScan(left_to_right=options.left_to_right, verbose=bool_verbose)
-    entries = [ Interface(entry) for entry in args ]
-    g=scanner.graph(entries)
-    logger.info("creating layout")
-    g.layout(prog='dot')
-    for outfile in options.outfiles:
-        logger.info("drawing in %s"%outfile)
-        g.draw(outfile)
-    logger.info("done")
+        (options,args)=parser.parse_args()
+        logger.enable_console()
+        # apply current verbosity to logger
+        logger.setLevelFromOptVerbose(options.verbose)
+        # figure if we need to be verbose for these local classes that only have a bool flag
+        bool_verbose=logger.getBoolVerboseFromOpt(options.verbose)
+    
+        if options.show_cache: 
+            VersionCache().show()
+            sys.exit(0)
+        if options.clean_cache:
+            VersionCache().clean()
+            sys.exit(0)
+        if not args:
+            parser.print_help()
+            sys.exit(1)
+            
+        if not options.outfiles:
+            options.outfiles=SfaScan.default_outfiles
+        scanner=Scanner(left_to_right=options.left_to_right, verbose=bool_verbose)
+        entries = [ Interface(entry) for entry in args ]
+        try:
+            g=scanner.graph(entries)
+            logger.info("creating layout")
+            g.layout(prog='dot')
+            for outfile in options.outfiles:
+                logger.info("drawing in %s"%outfile)
+                g.draw(outfile)
+            logger.info("done")
+        # test mode when pygraphviz is not available
+        except:
+            entry=entries[0]
+            print "GetVersion at %s returned %s"%(entry.url(),entry.get_version())
 
 
-if __name__ == '__main__':
-    main()