Merge branch 'master' of ssh://git.planet-lab.org/git/sfa
[sfa.git] / sfa / client / sfi.py
index 579d38e..80cb34b 100755 (executable)
@@ -10,13 +10,12 @@ import traceback
 import socket
 import random
 import datetime
+import zlib
 from lxml import etree
 from StringIO import StringIO
 from types import StringTypes, ListType
 from optparse import OptionParser
-import zlib
-
-from sfa.util.sfalogging import sfa_logger,sfa_logger_goes_to_console
+from sfa.util.sfalogging import _SfaLogger, logging
 from sfa.trust.certificate import Keypair, Certificate
 from sfa.trust.gid import GID
 from sfa.trust.credential import Credential
@@ -26,6 +25,7 @@ from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
 from sfa.util.config import Config
 from sfa.util.version import version_core
+from sfa.util.cache import Cache
 
 AGGREGATE_PORT=12346
 CM_PORT=12346
@@ -134,14 +134,14 @@ class Sfi:
         for opt in Sfi.required_options:
             if not hasattr(options,opt): setattr(options,opt,None)
         if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
+        self.sfi_dir = options.sfi_dir
         self.options = options
         self.slicemgr = None
         self.registry = None
         self.user = None
         self.authority = None
         self.hashrequest = False
-        sfa_logger_goes_to_console()
-        self.logger=sfa_logger()
+        self.logger = _SfaLogger(self.sfi_dir + 'sfi.log', level = logging.INFO)
    
     def create_cmd_parser(self, command, additional_cmdargs=None):
         cmdargs = {"list": "authority",
@@ -276,7 +276,7 @@ class Sfi:
 
         return parser
         
+
     def read_config(self):
        config_file = self.options.sfi_dir + os.sep + "sfi_config"
        try:
@@ -344,15 +344,54 @@ class Sfi:
        self.key = Keypair(filename=key_file) 
        self.key_file = key_file
        self.cert_file = cert_file
-       self.cert = GID(filename=cert_file) 
-       # Establish connection to server(s)
+       self.cert = GID(filename=cert_file)
        self.logger.info("Contacting Registry at: %s"%self.reg_url)
        self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)  
        self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
        self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, self.options)
-
        return
-    
+
+    def get_cached_server_version(self, server):
+        # check local cache first
+        cache = None
+        version = None 
+        cache_file = self.sfi_dir + os.path.sep + 'sfi_cache.dat'
+        cache_key = server.url + "-version"
+        try:
+            cache = Cache(cache_file)
+        except IOError:
+            cache = Cache()
+            self.logger.info("Local cache not found at: %s" % cache_file)
+
+        if cache:
+            version = cache.get(cache_key)
+            
+        if not version: 
+            version = server.GetVersion()
+            # cache version for 24 hours
+            cache.add(cache_key, version, ttl= 60*60*24)
+
+
+        return version   
+        
+
+    def server_supports_call_id_arg(self, server):
+        """
+        Returns true if server support the optional call_id arg, false otherwise. 
+        """
+        server_version = self.get_cached_server_version(server)
+        if 'sfa' in server_version:
+            code_tag = server_version['code_tag']
+            code_tag_parts = code_tag.split("-")
+            
+            version_parts = code_tag_parts[0].split(".")
+            major, minor = version_parts[0], version_parts[1]
+            rev = code_tag_parts[1]
+            if int(major) > 1:
+                if int(minor) > 0 or int(rev) > 20:
+                    return True
+        return False                
+             
     #
     # Get various credential and spec files
     #
@@ -394,6 +433,7 @@ class Sfi:
         cert.sign()
         self.logger.info("Writing self-signed certificate to %s"%cert_file)
         cert.save_to_file(cert_file)
+        self.cert = cert
         # try to get registry issued cert
         try:
             self.logger.info("Getting Registry issued cert")
@@ -406,7 +446,7 @@ class Sfi:
             gid.save_to_file(cert_file)
         except:
             self.logger.info("Failed to download Registry issued cert")
+
         return cert_file
 
     def get_cached_gid(self, file):
@@ -439,18 +479,23 @@ class Sfi:
             hrn = self.user
  
         gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
+        print gidfile
         gid = self.get_cached_gid(gidfile)
         if not gid:
             user_cred = self.get_user_cred()
             records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
-            record = None
+            if not records:
+                raise RecordNotFound(args[0])
+            record = records[0]
             if type:
+                record=None
                 for rec in records:
-                   if type == record['type']:
+                   if type == rec['type']:
                         record = rec 
             if not record:
                 raise RecordNotFound(args[0])
-            gid = GID(string=records[0]['gid'])
+            
+            gid = GID(string=record['gid'])
             self.logger.info("Writing gid to %s"%gidfile)
             gid.save_to_file(filename=gidfile)
         return gid   
@@ -636,7 +681,7 @@ class Sfi:
                 record = SliceRecord(dict=record)
             elif record['type'] in ['node']:
                 record = NodeRecord(dict=record)
-            elif record['type'] in ['authority', 'ma', 'sa']:
+            elif record['type'].startswith('authority'):
                 record = AuthorityRecord(dict=record)
             else:
                 record = SfaRecord(dict=record)
@@ -644,7 +689,7 @@ class Sfi:
                 record.dump()  
             else:
                 print record.save_to_string() 
-       
         if opts.file:
             file = opts.file
             if not file.startswith(os.sep):
@@ -762,6 +807,8 @@ class Sfi:
         """ 
         trusted_certs = self.registry.get_trusted_certs()
         for trusted_cert in trusted_certs:
+            gid = GID(string=trusted_cert)
+            gid.dump()
             cert = Certificate(string=trusted_cert)
             self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
         return 
@@ -795,7 +842,6 @@ class Sfi:
     # ==================================================================
     # Slice-related commands
     # ==================================================================
-    
 
     def version(self, opts, args):
         if opts.version_local:
@@ -849,7 +895,11 @@ class Sfi:
         #panos add info options
         if opts.info:
             call_options['info'] = opts.info 
-        result = server.ListResources(creds, call_options,unique_call_id())
+
+        call_args = [creds, call_options]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+        result = server.ListResources(*call_args)
         format = opts.format
         if opts.file is None:
             display_rspec(result, format)
@@ -895,8 +945,13 @@ class Sfi:
                 for user_record in user_records:
                     if 'keys' in user_record:
                         user['keys'].extend(user_record['keys'])
-            users.append(user)             
-        result =  server.CreateSliver(slice_urn, creds, rspec, users, unique_call_id())
+            users.append(user)
+
+        call_args = [slice_urn, creds, rspec, users]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+             
+        result =  server.CreateSliver(*call_args)
         print result
         return result
 
@@ -963,8 +1018,12 @@ class Sfi:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         server = self.get_server_from_opts(opts)
-        return server.DeleteSliver(slice_urn, creds, unique_call_id())
-    
+
+        call_args = [slice_urn, creds]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+        return server.DeleteSliver(*call_args) 
+  
     # start named slice
     def start(self, opts, args):
         slice_hrn = args[0]
@@ -1011,7 +1070,11 @@ class Sfi:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         time = args[1]
-        return server.RenewSliver(slice_urn, creds, time, unique_call_id())
+        
+        call_args = [slice_urn, creds, time]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+        return server.RenewSliver(*call_args)
 
 
     def status(self, opts, args):
@@ -1023,7 +1086,10 @@ class Sfi:
             delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
             creds.append(delegated_cred)
         server = self.get_server_from_opts(opts)
-        print server.SliverStatus(slice_urn, creds, unique_call_id())
+        call_args = [slice_urn, creds]
+        if self.server_supports_call_id_arg(server):
+            call_args.append(unique_call_id())
+        print server.SliverStatus(*call_args)
 
 
     def shutdown(self, opts, args):
@@ -1062,7 +1128,6 @@ class Sfi:
         (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
 
         self.set_servers()
-    
         self.logger.info("Command=%s" % command)
         if command in ("resources"):
             self.logger.debug("resources cmd_opts %s" % cmd_opts.format)