Merge branch 'master' into senslab2
authorSandrine Avakian <sandrine.avakian@inria.fr>
Mon, 16 Jan 2012 14:17:48 +0000 (15:17 +0100)
committerSandrine Avakian <sandrine.avakian@inria.fr>
Mon, 16 Jan 2012 14:17:48 +0000 (15:17 +0100)
Conflicts:
sfa/managers/registry_manager.py

1  2 
setup.py
sfa/client/sfi.py
sfa/plc/plslices.py
sfa/trust/credential.py

diff --combined setup.py
+++ b/setup.py
@@@ -26,6 -26,7 +26,7 @@@ scripts = glob("sfa/clientbin/*.py") + 
  
  packages = [
      'sfa', 
+     'sfa/openstack',
      'sfa/trust',
      'sfa/storage',
      'sfa/util', 
@@@ -36,7 -37,6 +37,7 @@@
      'sfa/managers',
      'sfa/importer',
      'sfa/plc',
 +    'sfa/senslab',
      'sfa/rspecs',
      'sfa/rspecs/elements',
      'sfa/rspecs/elements/versions',
diff --combined sfa/client/sfi.py
@@@ -165,7 -165,8 +165,8 @@@ def unique_call_id(): return uuid.uuid4
  
  class Sfi:
      
-     required_options=['verbose',  'debug',  'registry',  'sm',  'auth',  'user']
+     # dirty hack to make this class usable from the outside
+     required_options=['verbose',  'debug',  'registry',  'sm',  'auth',  'user', 'user_private_key']
  
      @staticmethod
      def default_sfi_dir ():
          # user specifies remote aggregate/sm/component                          
          if command in ("resources", "slices", "create", "delete", "start", "stop", 
                         "restart", "shutdown",  "get_ticket", "renew", "status"):
-             parser.add_option("-c", "--component", dest="component", default=None,
-                              help="component hrn")
              parser.add_option("-d", "--delegate", dest="delegate", default=None, 
                               action="store_true",
                               help="Include a credential delegated to the user's root"+\
                              help="type filter ([all]|user|slice|authority|node|aggregate)",
                              choices=("all", "user", "slice", "authority", "node", "aggregate"),
                              default="all")
-         # display formats
          if command in ("resources"):
+             # rspec version
              parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
                                help="schema type and version of resulting RSpec")
+             # disable/enable cached rspecs
+             parser.add_option("-c", "--current", dest="current", default=False,
+                               action="store_true",  
+                               help="Request the current rspec bypassing the cache. Cached rspecs are returned by default")
+             # display formats
              parser.add_option("-f", "--format", dest="format", type="choice",
                               help="display format ([xml]|dns|ip)", default="xml",
                               choices=("xml", "dns", "ip"))
                  self.sliceapi_proxy=SfaServerProxy(cm_url, self.private_key, self.my_gid)
              else:
                  # otherwise use what was provided as --sliceapi, or SFI_SM in the config
+                 if not self.sm_url.startswith('http://') or self.sm_url.startswith('https://'):
+                     self.sm_url = 'http://' + self.sm_url
                  self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
                  self.sliceapi_proxy = SfaServerProxy(self.sm_url, self.private_key, self.my_gid, 
                                                       timeout=self.options.timeout, verbose=self.options.debug)  
@@@ -815,42 -821,35 +821,35 @@@ or with an slice hrn, shows currently p
              creds.append(self.my_credential_string)
          if options.delegate:
              creds.append(self.delegate_cred(cred, get_authority(self.authority)))
-         
-         # V2 API
-         if self.server_supports_options_arg(server):
-             # with v2 everything goes in options inclusing the subject slice
-             api_options = {}
-             if args:
-                 hrn = args[0]
-                 api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
-             if options.info:
-                 api_options['info'] = options.info
-             if options.rspec_version:
-                 version_manager = VersionManager()
-                 server_version = self.get_cached_server_version(server)
-                 if 'sfa' in server_version:
-                     # just request the version the client wants
-                     api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict()
-                 else:
-                     # this must be a protogeni aggregate. We should request a v2 ad rspec
-                     # regardless of what the client user requested
-                     api_options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict() 
+        
+         # no need to check if server accepts the options argument since the options has
+         # been a required argument since v1 API   
+         api_options = {}
+         # always send call_id to v2 servers
+         api_options ['call_id'] = unique_call_id()
+         # ask for cached value if available
+         api_options ['cached'] = True
+         if args:
+             hrn = args[0]
+             api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
+         if options.info:
+             api_options['info'] = options.info
+         if options.current:
+             if options.current == True:
+                 api_options['cached'] = False
+             else:
+                 api_options['cached'] = True
+         if options.rspec_version:
+             version_manager = VersionManager()
+             server_version = self.get_cached_server_version(server)
+             if 'sfa' in server_version:
+                 # just request the version the client wants
+                 api_options['geni_rspec_version'] = version_manager.get_version(options.rspec_version).to_dict()
              else:
                  api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}    
-             # always send call_id to v2 servers
-             api_options ['call_id'] = unique_call_id()
-             # the V2 form
-             result = server.ListResources (creds, api_options)
-         # V1
          else:
-             # with an argument
-             if args:
-                 hrn = args[0]
-                 # xxx looks like we can pass a hrn and not a urn here ??
-                 # last arg. is a raw call_id when supported
-                 result = server.ListResources (creds, hrn, *self.cis(server))
-             else:
-                 result = server.ListResources (creds, *self.cis(server))
+             api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}    
+         result = server.ListResources (creds, api_options)
          value = ReturnValue.get_value(result)
          if options.file is None:
              display_rspec(value, options.format)
                  rspec.filter({'component_manager_id': server_version['urn']})
                  rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
              else:
 +                print >>sys.stderr, "\r\n \r\n \r\n WOOOOOO"
                  users = sfa_users_arg(user_records, slice_record)
          
          # do not append users, keys, or slice tags. Anything 
diff --combined sfa/plc/plslices.py
@@@ -1,14 -1,12 +1,13 @@@
  from types import StringTypes
  from collections import defaultdict
 +import sys
  
+ from sfa.util.sfatime import utcparse, datetime_to_epoch
  from sfa.util.sfalogging import logger
  from sfa.util.xrn import Xrn, get_leaf, get_authority, urn_to_hrn
  #from sfa.util.policy import Policy
- from sfa.util.xrn import Xrn
+ from sfa.util.plxrn import PlXrn
  from sfa.rspecs.rspec import RSpec
  from sfa.plc.vlink import VLink
  from sfa.util.plxrn import hrn_to_pl_slicename
  
@@@ -132,13 -130,13 +131,13 @@@ class PlSlices
          # slice belongs to out local plc or a myplc peer. We will assume it 
          # is a local site, unless we find out otherwise  
          peer = None
 -
 +        print>>sys.stderr, " \r\n \r\n \tplslices.py get_peer slice_authority  "
          # get this slice's authority (site)
          slice_authority = get_authority(hrn)
  
          # get this site's authority (sfa root authority or sub authority)
          site_authority = get_authority(slice_authority).lower()
 -
 +        print>>sys.stderr, " \r\n \r\n \tplslices.py get_peer slice_authority  %s site_authority %s" %(slice_authority,site_authority) 
          # check if we are already peered with this site_authority, if so
          peers = self.driver.shell.GetPeers({}, ['peer_id', 'peername', 'shortname', 'hrn_root'])
          for peer_record in peers:
                  # unbind from peer so we can modify if necessary. Will bind back later
                  self.driver.shell.UnBindObjectFromPeer('slice', slice['slice_id'], peer['shortname'])
                #Update existing record (e.g. expires field) it with the latest info.
-             if slice_record and slice['expires'] != slice_record['expires']:
-                 self.driver.shell.UpdateSlice( slice['slice_id'], {'expires' : slice_record['expires']})
+             if slice_record.get('expires'):
+                 requested_expires = int(datetime_to_epoch(utcparse(slice_record['expires'])))
+                 if requested_expires and slice['expires'] != requested_expires:
+                     self.driver.shell.UpdateSlice( slice['slice_id'], {'expires' : requested_expires})
         
          return slice
  
          for user in users:
              hrn, type = urn_to_hrn(user['urn'])
              username = get_leaf(hrn)
-             login_base = get_leaf(get_authority(user['urn']))
+             login_base = PlXrn(xrn=user['urn']).pl_login_base()
              user['username'] = username
              user['site'] = login_base
  
                                  if login_base == site['login_base'] and \
                                     existing_user['email'].startswith(requested_user['username']+'@'):
                                      existing_user_ids.append(existing_user['email'])
+                                     requested_user['email'] = existing_user['email']
                                      users_dict[existing_user['email']] = requested_user
                                      user_found = True
                                      break
        
                      if user_found == False:
                          fake_email = requested_user['username'] + '@geni.net'
+                         requested_user['email'] = fake_email
                          users_dict[fake_email] = requested_user
                  
          # requested slice users        
              for removed_user_id in removed_user_ids:
                  self.driver.shell.DeletePersonFromSlice(removed_user_id, slice_record['name'])
          # update_existing users
-         updated_users_list = [user for user in existing_slice_users if user['email'] in \
+         updated_users_list = [user for user in users_dict.values() if user['email'] in \
            updated_user_ids]
          self.verify_keys(existing_slice_users, updated_users_list, peer, options)
  
                  self.driver.shell.DeleteSliceTag(attribute['slice_tag_id'])
              except Exception, e:
                  logger.warn('Failed to remove sliver attribute. name: %s, value: %s, node_id: %s\nCause:%s'\
-                                 % (name, value,  node_id, str(e)))
+                                 % (slice['name'], attribute['value'],  attribute.get('node_id'), str(e)))
  
          # add requested_attributes
          for attribute in added_slice_attributes:
                  self.driver.shell.AddSliceTag(slice['name'], attribute['name'], attribute['value'], attribute.get('node_id', None))
              except Exception, e:
                  logger.warn('Failed to add sliver attribute. name: %s, value: %s, node_id: %s\nCause:%s'\
-                                 % (name, value,  node_id, str(e)))
+                                 % (slice['name'], attribute['value'],  attribute.get('node_id'), str(e)))
  
diff --combined sfa/trust/credential.py
@@@ -26,7 -26,7 +26,7 @@@
  # Credentials are signed XML files that assign a subject gid privileges to an object gid
  ##
  
 -import os
 +import os,sys
  from types import StringTypes
  import datetime
  from StringIO import StringIO
@@@ -51,7 -51,7 +51,7 @@@ from sfa.trust.gid import GI
  from sfa.util.xrn import urn_to_hrn, hrn_authfor_hrn
  
  # 2 weeks, in seconds 
- DEFAULT_CREDENTIAL_LIFETIME = 86400 * 14
+ DEFAULT_CREDENTIAL_LIFETIME = 86400 * 31
  
  
  # TODO:
@@@ -160,10 -160,8 +160,10 @@@ class Signature(object)
  
  
      def get_refid(self):
 +        #print>>sys.stderr," \r\n \r\n credential.py Signature get_refid\ self.refid %s " %(self.refid)
          if not self.refid:
              self.decode()
 +            #print>>sys.stderr," \r\n \r\n credential.py Signature get_refid self.refid %s " %(self.refid)
          return self.refid
  
      def get_xml(self):
@@@ -590,23 -588,18 +590,23 @@@ class Credential(object)
      
      def updateRefID(self):
          if not self.parent:
 -            self.set_refid('ref0')
 +            self.set_refid('ref0') 
 +            #print>>sys.stderr, " \r\n \r\n updateRefID next_cred ref0 "
              return []
          
          refs = []
  
          next_cred = self.parent
 +       
          while next_cred:
 +          
              refs.append(next_cred.get_refid())
              if next_cred.parent:
                  next_cred = next_cred.parent
 +                #print>>sys.stderr, " \r\n \r\n updateRefID next_cred "
              else:
                  next_cred = None
 +                #print>>sys.stderr, " \r\n \r\n updateRefID next_cred NONE"
  
          
          # Find a unique refid for this credential
                      # Failures here include unreadable files
                      # or non PEM files
                      trusted_cert_objects.append(GID(filename=f))
 +                    #print>>sys.stderr, " \r\n \t\t\t credential.py verify trusted_certs %s" %(GID(filename=f).get_hrn())
                      ok_trusted_certs.append(f)
                  except Exception, exc:
                      logger.error("Failed to load trusted cert from %s: %r", f, exc)
              trusted_certs = ok_trusted_certs
 +            #print>>sys.stderr, " \r\n \t\t\t credential.py verify trusted_certs elemnebts %s" %(len(trusted_certs))
  
          # Use legacy verification if this is a legacy credential
          if self.legacy:
              # Verify the gids of this cred and of its parents
              for cur_cred in self.get_credential_list():
                  cur_cred.get_gid_object().verify_chain(trusted_cert_objects)
 -                cur_cred.get_gid_caller().verify_chain(trusted_cert_objects)
 +                cur_cred.get_gid_caller().verify_chain(trusted_cert_objects)        
 +                #print>>sys.stderr, " \r\n \t\t\t credential.py verify cur_cred get_gid_object hrn %s get_gid_caller %s" %(cur_cred.get_gid_object().get_hrn(),cur_cred.get_gid_caller().get_hrn()) 
  
          refs = []
          refs.append("Sig_%s" % self.get_refid())
          parentRefs = self.updateRefID()
          for ref in parentRefs:
              refs.append("Sig_%s" % ref)
 -
 +            #print>>sys.stderr, " \r\n \t\t\t credential.py verify trusted_certs refs",  ref 
          for ref in refs:
              # If caller explicitly passed in None that means skip xmlsec1 validation.
              # Strange and not typical
  #                (self.xmlsec_path, ref, cert_args, filename)
              verified = os.popen('%s --verify --node-id "%s" %s %s 2>&1' \
                              % (self.xmlsec_path, ref, cert_args, filename)).read()
 +            #print>>sys.stderr, " \r\n \t\t\t credential.py verify filename %s verified %s " %(filename,verified)             
              if not verified.strip().startswith("OK"):
                  # xmlsec errors have a msg= which is the interesting bit.
                  mstart = verified.find("msg=")
                      msg = verified[mstart:mend]
                  raise CredentialNotVerifiable("xmlsec1 error verifying cred %s using Signature ID %s: %s %s" % (self.get_summary_tostring(), ref, msg, verified.strip()))
          os.remove(filename)
 -
 +        
 +        #print>>sys.stderr, " \r\n \t\t\t credential.py HUMMM parents %s", self.parent
          # Verify the parents (delegation)
          if self.parent:
              self.verify_parent(self.parent)
 -
 +        #print>>sys.stderr, " \r\n \t\t\t credential.py verify trusted_certs parents" 
          # Make sure the issuer is the target's authority, and is
          # itself a valid GID
          self.verify_issuer(trusted_cert_objects)
      # . The expiry time on the child must be no later than the parent
      # . The signer of the child must be the owner of the parent        
      def verify_parent(self, parent_cred):
 +        #print>>sys.stderr, " \r\n\r\n \t verify_parent parent_cred.get_gid_caller().save_to_string(False) %s  self.get_signature().get_issuer_gid().save_to_string(False) %s" %(parent_cred.get_gid_caller().get_hrn(),self.get_signature().get_issuer_gid().get_hrn())
          # make sure the rights given to the child are a subset of the
          # parents rights (and check delegate bits)
          if not parent_cred.get_privileges().is_superset(self.get_privileges()):