Merge branch 'master' of git://git.onelab.eu/sfa into upmc
authorJordan Augé <jordan.auge@lip6.fr>
Sun, 9 Dec 2012 23:00:30 +0000 (00:00 +0100)
committerJordan Augé <jordan.auge@lip6.fr>
Sun, 9 Dec 2012 23:00:30 +0000 (00:00 +0100)
clientbin/Makefile
sfa.spec
sfa/client/sfaclientlib.py
sfa/client/sfi.py
sfa/importer/__init__.py
sfa/importer/plimporter.py
sfa/managers/registry_manager.py
sfa/planetlab/pldriver.py
sfa/trust/credential.py
sfa/util/method.py

index 061e1b2..6a7b844 100644 (file)
@@ -50,7 +50,7 @@ ALL += $(foreach bundle,$(BUNDLES-LR),$(word 2,$(subst @, ,$(bundle)))-lr)
 
 all: $(ALL)
 
-ple: auto-ple-reg auto-ple-sa-lr.out
+ple: auto-ple-reg auto-ple-sa-lr
 
 ####################
 define bundle_scan_target
index 72feac8..18251d3 100644 (file)
--- a/sfa.spec
+++ b/sfa.spec
@@ -1,6 +1,6 @@
 %define name sfa
 %define version 2.1
-%define taglevel 17
+%define taglevel 20
 
 %define release %{taglevel}%{?pldistro:.%{pldistro}}%{?date:.%{date}}
 %global python_sitearch        %( python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)" )
@@ -270,6 +270,22 @@ fi
 [ "$1" -ge "1" ] && service sfa-cm restart || :
 
 %changelog
+* Mon Dec 03 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-2.1-20
+- fix 2 major bugs in PL importer
+- esp. wrt GID management against PLC key
+
+* Wed Nov 28 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-2.1-19
+- nicer sfi delegate, can handle multiple delegations and for authorities(pi) as well
+
+* Wed Nov 28 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-2.1-18
+- support fordelegation in sfaclientlib
+- sfi delegate fixed
+- other delegation-related sfi option trashed
+- new config (based on ini format)
+- new dummy driver and related package
+- pl importer has more explicit error messages
+- credential dump shows expiration
+
 * Tue Oct 16 2012 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - sfa-2.1-17
 - bugfix in forwarding Resolve requests
 - various fixes in the nitos driver wrt keys and users
index c5c5b80..dce2201 100644 (file)
@@ -22,6 +22,7 @@ from sfa.client.sfaserverproxy import SfaServerProxy
 # see optimizing dependencies below
 from sfa.trust.certificate import Keypair, Certificate
 from sfa.trust.credential import Credential
+from sfa.trust.gid import GID
 ########## 
 # a helper class to implement the bootstrapping of crypto. material
 # assuming we are starting from scratch on the client side 
@@ -82,9 +83,9 @@ from sfa.trust.credential import Credential
 # the usage model is to reuse an existing keypair)
 # 
 # there might be a more portable, i.e. less language-dependant way, to
-# implement this step by exec'ing the openssl command a known
-# successful attempt at this approach that worked for Java is
-# documented below
+# implement this step by exec'ing the openssl command.
+# a known successful attempt at this approach that worked 
+# for Java is documented below
 # http://nam.ece.upatras.gr/fstoolkit/trac/wiki/JavaSFAClient
 #
 ####################
@@ -354,3 +355,38 @@ class SfaClientBootstrap:
     def private_key (self):
         self.assert_private_key()
         return self.private_key_filename()
+
+    def delegate_credential_string (self, original_credential, to_hrn, to_type='authority'):
+        """
+        sign a delegation credential to someone else
+
+        original_credential : typically one's user- or slice- credential to be delegated to s/b else
+        to_hrn : the hrn of the person that will be allowed to do stuff on our behalf
+        to_type : goes with to_hrn, usually 'user' or 'authority'
+
+        returns a string with the delegated credential
+
+        this internally uses self.my_gid()
+        it also retrieves the gid for to_hrn/to_type
+        and uses Credential.delegate()"""
+
+        # the gid and hrn of the object we are delegating
+        if isinstance (original_credential, str):
+            original_credential = Credential (string=original_credential)
+        original_gid = original_credential.get_gid_object()
+        original_hrn = original_gid.get_hrn()
+
+        if not original_credential.get_privileges().get_all_delegate():
+            self.logger.error("delegate_credential_string: original credential %s does not have delegate bit set"%original_hrn)
+            return
+
+        # the delegating user's gid
+        my_gid = self.my_gid()
+
+        # retrieve the GID for the entity that we're delegating to
+        to_gidfile = self.gid (to_hrn,to_type)
+#        to_gid = GID ( to_gidfile )
+#        to_hrn = delegee_gid.get_hrn()
+#        print 'to_hrn',to_hrn
+        delegated_credential = original_credential.delegate(to_gidfile, self.private_key(), my_gid)
+        return delegated_credential.save_to_string(save_parents=True)
index 8cc8903..8f9682f 100644 (file)
@@ -328,8 +328,8 @@ class Sfi:
         ("version", ""),  
         ("list", "authority"),
         ("show", "name"),
-        ("add", "record"),
-        ("update", "record"),
+        ("add", "[record]"),
+        ("update", "[record]"),
         ("remove", "name"),
         ("slices", ""),
         ("resources", "[slice_hrn]"),
@@ -343,7 +343,7 @@ class Sfi:
         ("shutdown", "slice_hrn"),
         ("get_ticket", "slice_hrn rspec"),
         ("redeem_ticket", "ticket"),
-        ("delegate", "name"),
+        ("delegate", "to_hrn"),
         ("gid", "[name]"),
         ("trusted", "cred"),
         ("config", ""),
@@ -408,14 +408,6 @@ class Sfi:
                                action="callback", callback=optparse_dictvalue_callback, nargs=1,
                                help="set extra/testbed-dependent flags, e.g. --extra enabled=true")
 
-        # user specifies remote aggregate/sm/component                          
-        if command in ("resources", "slices", "create", "delete", "start", "stop", 
-                       "restart", "shutdown",  "get_ticket", "renew", "status"):
-            parser.add_option("-d", "--delegate", dest="delegate", default=None, 
-                             action="store_true",
-                             help="Include a credential delegated to the user's root"+\
-                                  "authority in set of credentials for this call")
-
         # show_credential option
         if command in ("list","resources","create","add","update","remove","slices","delete","status","renew"):
             parser.add_option("-C","--credential",dest='show_credential',action='store_true',default=False,
@@ -470,10 +462,18 @@ class Sfi:
                              help="gives details, like user keys", default=False)
         if command in ("delegate"):
            parser.add_option("-u", "--user",
-                            action="store_true", dest="delegate_user", default=False,
-                            help="delegate user credential")
-           parser.add_option("-s", "--slice", dest="delegate_slice",
-                            help="delegate slice credential", metavar="HRN", default=None)
+                             action="store_true", dest="delegate_user", default=False,
+                             help="delegate your own credentials; default if no other option is provided")
+           parser.add_option("-s", "--slice", dest="delegate_slices",action='append',default=[],
+                             metavar="slice_hrn", help="delegate cred. for slice HRN")
+           parser.add_option("-a", "--auths", dest='delegate_auths',action='append',default=[],
+                             metavar='auth_hrn', help="delegate cred for auth HRN")
+           # this primarily is a shorthand for -a my_hrn^
+           parser.add_option("-p", "--pi", dest='delegate_pi', default=None, action='store_true',
+                             help="delegate your PI credentials, so s.t. like -a your_hrn^")
+           parser.add_option("-A","--to-authority",dest='delegate_to_authority',action='store_true',default=False,
+                             help="""by default the mandatory argument is expected to be a user, 
+use this if you mean an authority instead""")
         
         if command in ("version"):
             parser.add_option("-R","--registry-version",
@@ -714,30 +714,12 @@ class Sfi:
             sys.exit(-1)
         return self.client_bootstrap.authority_credential_string (self.authority)
 
+    def authority_credential_string(self, auth_hrn):
+        return self.client_bootstrap.authority_credential_string (auth_hrn)
+
     def slice_credential_string(self, name):
         return self.client_bootstrap.slice_credential_string (name)
 
-    # xxx should be supported by sfaclientbootstrap as well
-    def delegate_cred(self, object_cred, hrn, type='authority'):
-        # the gid and hrn of the object we are delegating
-        if isinstance(object_cred, str):
-            object_cred = Credential(string=object_cred) 
-        object_gid = object_cred.get_gid_object()
-        object_hrn = object_gid.get_hrn()
-    
-        if not object_cred.get_privileges().get_all_delegate():
-            self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
-            return
-
-        # the delegating user's gid
-        caller_gidfile = self.my_gid()
-  
-        # the gid of the user who will be delegated to
-        delegee_gid = self.client_bootstrap.gid(hrn,type)
-        delegee_hrn = delegee_gid.get_hrn()
-        dcred = object_cred.delegate(delegee_gid, self.private_key, caller_gidfile)
-        return dcred.save_to_string(save_parents=True)
-     
     #
     # Management of the servers
     # 
@@ -949,7 +931,7 @@ or version information about sfi itself
         return
     
     def add(self, options, args):
-        "add record into registry from xml file (Register)"
+        "add record into registry by using the command options (Recommended) or from xml file (Register)"
         auth_cred = self.my_authority_credential_string()
         if options.show_credential:
             show_credentials(auth_cred)
@@ -974,7 +956,7 @@ or version information about sfi itself
         return self.registry().Register(record_dict, auth_cred)
     
     def update(self, options, args):
-        "update record into registry from xml file (Update)"
+        "update record into registry by using the command options (Recommended) or from xml file (Update)"
         record_dict = {}
         if len(args) > 0:
             record_filepath = args[0]
@@ -1037,9 +1019,6 @@ or version information about sfi itself
         server = self.sliceapi()
         # creds
         creds = [self.my_credential_string]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(self.my_credential_string, get_authority(self.authority))
-            creds.append(delegated_cred)  
         # options and call_id when supported
         api_options = {}
        api_options['call_id']=unique_call_id()
@@ -1064,11 +1043,11 @@ or with an slice hrn, shows currently provisioned resources
         # set creds
         creds = []
         if args:
-            creds.append(self.slice_credential_string(args[0]))
+            the_credential=self.slice_credential_string(args[0])
+            creds.append(the_credential)
         else:
-            creds.append(self.my_credential_string)
-        if options.delegate:
-            creds.append(self.delegate_cred(cred, get_authority(self.authority)))
+            the_credential=self.my_credential_string
+            creds.append(the_credential)
         if options.show_credential:
             show_credentials(creds)
 
@@ -1202,9 +1181,6 @@ or with an slice hrn, shows currently provisioned resources
         # creds
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         
         # options and call_id when supported
         api_options = {}
@@ -1232,9 +1208,6 @@ or with an slice hrn, shows currently provisioned resources
         # creds 
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
 
         # options and call_id when supported
         api_options = {}
@@ -1261,9 +1234,6 @@ or with an slice hrn, shows currently provisioned resources
         # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         # xxx Thierry - does this not need an api_options as well ?
         result = server.Start(slice_urn, creds)
         value = ReturnValue.get_value(result)
@@ -1284,9 +1254,6 @@ or with an slice hrn, shows currently provisioned resources
         # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         result =  server.Stop(slice_urn, creds)
         value = ReturnValue.get_value(result)
         if self.options.raw:
@@ -1307,9 +1274,6 @@ or with an slice hrn, shows currently provisioned resources
         # cred
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         result = server.reset_slice(creds, slice_urn)
         value = ReturnValue.get_value(result)
         if self.options.raw:
@@ -1333,9 +1297,6 @@ or with an slice hrn, shows currently provisioned resources
         # creds
         slice_cred = self.slice_credential_string(args[0])
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         # options and call_id when supported
         api_options = {}
        api_options['call_id']=unique_call_id()
@@ -1361,9 +1322,6 @@ or with an slice hrn, shows currently provisioned resources
         # creds
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         result = server.Shutdown(slice_urn, creds)
         value = ReturnValue.get_value(result)
         if self.options.raw:
@@ -1384,9 +1342,6 @@ or with an slice hrn, shows currently provisioned resources
         # creds
         slice_cred = self.slice_credential_string(slice_hrn)
         creds = [slice_cred]
-        if options.delegate:
-            delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
-            creds.append(delegated_cred)
         # rspec
         rspec_file = self.get_rspec_file(rspec_path) 
         rspec = open(rspec_file).read()
@@ -1460,31 +1415,51 @@ or with an slice hrn, shows currently provisioned resources
         GID(string=gid).save_to_file(filename)
          
 
-    def delegate(self, options, args):
+    def delegate (self, options, args):
         """
         (locally) create delegate credential for use by given hrn
         """
-        delegee_hrn = args[0]
-        if options.delegate_user:
-            cred = self.delegate_cred(self.my_credential_string, delegee_hrn, 'user')
-        elif options.delegate_slice:
-            slice_cred = self.slice_credential_string(options.delegate_slice)
-            cred = self.delegate_cred(slice_cred, delegee_hrn, 'slice')
-        else:
-            self.logger.warning("Must specify either --user or --slice <hrn>")
-            return
-        delegated_cred = Credential(string=cred)
-        object_hrn = delegated_cred.get_gid_object().get_hrn()
+        if len(args) != 1:
+            self.print_help()
+            sys.exit(1)
+        to_hrn = args[0]
+        # support for several delegations in the same call
+        # so first we gather the things to do
+        tuples=[]
+        for slice_hrn in options.delegate_slices:
+            message="%s.slice"%slice_hrn
+            original = self.slice_credential_string(slice_hrn)
+            tuples.append ( (message, original,) )
+        if options.delegate_pi:
+            my_authority=self.authority
+            message="%s.pi"%my_authority
+            original = self.my_authority_credential_string()
+            tuples.append ( (message, original,) )
+        for auth_hrn in options.delegate_auths:
+            message="%s.auth"%auth_hrn
+            original=self.authority_credential_string(auth_hrn)
+            tuples.append ( (message, original, ) )
+        # if nothing was specified at all at this point, let's assume -u
+        if not tuples: options.delegate_user=True
+        # this user cred
         if options.delegate_user:
-            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
-                                  + get_leaf(object_hrn) + ".cred")
-        elif options.delegate_slice:
-            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
-                                  + get_leaf(object_hrn) + ".cred")
-
-        delegated_cred.save_to_file(dest_fn, save_parents=True)
-
-        self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
+            message="%s.user"%self.user
+            original = self.my_credential_string
+            tuples.append ( (message, original, ) )
+
+        # default type for beneficial is user unless -A
+        if options.delegate_to_authority:       to_type='authority'
+        else:                                   to_type='user'
+
+        # let's now handle all this
+        # it's all in the filenaming scheme
+        for (message,original) in tuples:
+            delegated_string = self.client_bootstrap.delegate_credential_string(original, to_hrn, to_type)
+            delegated_credential = Credential (string=delegated_string)
+            filename = os.path.join ( self.options.sfi_dir,
+                                      "%s_for_%s.%s.cred"%(message,to_hrn,to_type))
+            delegated_credential.save_to_file(filename, save_parents=True)
+            self.logger.info("delegated credential for %s to %s and wrote to %s"%(message,to_hrn,filename))
     
     def trusted(self, options, args):
         """
index 6d3d482..35f8acd 100644 (file)
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 
 import sys
+from datetime import datetime
 
 from sfa.util.xrn import get_authority, hrn_to_urn
 from sfa.generic import Generic
@@ -115,9 +116,13 @@ class Importer:
         generic=Generic.the_flavour()
         importer_class = generic.importer_class()
         if importer_class:
-            self.logger.info ("Using flavour %s for importing (class %s)"%\
-                         (generic.flavour,importer_class.__name__))
+            begin_time=datetime.now()
+            self.logger.info ("Starting import on %s, using class %s from flavour %s"%\
+                         (begin_time,importer_class.__name__,generic.flavour))
             testbed_importer = importer_class (auth_hierarchy, self.logger)
             if testbed_importer:
                 testbed_importer.add_options(options)
                 testbed_importer.run (options)
+            end_time=datetime.now()
+            duration=end_time-begin_time
+            self.logger.info("Import took %s"%duration)
index 8c4ab5e..eeab8b6 100644 (file)
@@ -153,6 +153,9 @@ class PlImporter:
                                    ['person_id', 'email', 'key_ids', 'site_ids', 'role_ids'])
         # create a hash of persons by person_id
         persons_by_id = dict ( [ ( person['person_id'], person) for person in persons ] )
+        # also gather non-enabled user accounts so as to issue relevant warnings
+        disabled_persons = shell.GetPersons({'peer_id': None, 'enabled': False}, ['person_id'])
+        disabled_person_ids = [ person['person_id'] for person in disabled_persons ] 
         # Get all plc public keys
         # accumulate key ids for keys retrieval
         key_ids = []
@@ -245,6 +248,7 @@ class PlImporter:
                         self.remember_record (node_record)
                     except:
                         self.logger.log_exc("PlImporter: failed to import node %s"%node_hrn) 
+                        continue
                 else:
                     # xxx update the record ...
                     pass
@@ -253,10 +257,17 @@ class PlImporter:
             site_pis=[]
             # import persons
             for person_id in site['person_ids']:
-                try:
-                    person = persons_by_id[person_id]
-                except:
-                    self.logger.warning ("PlImporter: cannot locate person_id %s - ignored"%person_id)
+                proceed=False
+                if person_id in persons_by_id:
+                    person=persons_by_id[person_id]
+                    proceed=True
+                elif person_id in disabled_person_ids:
+                    pass
+                else:
+                    self.logger.warning ("PlImporter: cannot locate person_id %s in site %s - ignored"%(person_id,site_hrn))
+                # make sure to NOT run this if anything is wrong
+                if not proceed: continue
+
                 person_hrn = email_to_hrn(site_hrn, person['email'])
                 # xxx suspicious again
                 if len(person_hrn) > 64: person_hrn = person_hrn[:64]
@@ -289,9 +300,9 @@ class PlImporter:
                         person_gid = self.auth_hierarchy.create_gid(person_urn, create_uuid(), pkey)
                         person_gid.set_email(person['email'])
                         user_record = RegUser (hrn=person_hrn, gid=person_gid, 
-                                                 pointer=person['person_id'], 
-                                                 authority=get_authority(person_hrn),
-                                                 email=person['email'])
+                                               pointer=person['person_id'], 
+                                               authority=get_authority(person_hrn),
+                                               email=person['email'])
                         if pubkey: 
                             user_record.reg_keys=[RegKey (pubkey['key'], pubkey['key_id'])]
                         else:
@@ -303,25 +314,46 @@ class PlImporter:
                         self.remember_record ( user_record )
                     else:
                         # update the record ?
-                        # if user's primary key has changed then we need to update the 
+                        #
+                        # if a user key has changed then we need to update the
                         # users gid by forcing an update here
+                        #
+                        # right now, SFA only has *one* key attached to a user, and this is
+                        # the key that the GID was made with
+                        # so the logic here is, we consider that things are OK (unchanged) if
+                        # all the SFA keys are present as PLC keys
+                        # otherwise we trigger the creation of a new gid from *some* plc key
+                        # and record this on the SFA side
+                        # it would make sense to add a feature in PLC so that one could pick a 'primary'
+                        # key but this is not available on the myplc side for now
+                        # = or = it would be much better to support several keys in SFA but that
+                        # does not seem doable without a major overhaul in the data model as
+                        # a GID is attached to a hrn, but it's also linked to a key, so...
+                        # NOTE: with this logic, the first key entered in PLC remains the one
+                        # current in SFA until it is removed from PLC
                         sfa_keys = user_record.reg_keys
-                        def key_in_list (key,sfa_keys):
-                            for reg_key in sfa_keys:
-                                if reg_key.key==key['key']: return True
+                        def sfa_key_in_list (sfa_key,plc_keys):
+                            for plc_key in plc_keys:
+                                if plc_key['key']==sfa_key.key:
+                                    return True
                             return False
-                        # is there a new key in myplc ?
+                        # are all the SFA keys known to PLC ?
                         new_keys=False
-                        for key in plc_keys:
-                            if not key_in_list (key,sfa_keys):
-                                new_keys = True
+                        if not sfa_keys and plc_keys:
+                            new_keys=True
+                        else: 
+                            for sfa_key in sfa_keys:
+                                 if not sfa_key_in_list (sfa_key,plc_keys):
+                                     new_keys = True
                         if new_keys:
                             (pubkey,pkey) = init_person_key (person, plc_keys)
                             person_gid = self.auth_hierarchy.create_gid(person_urn, create_uuid(), pkey)
+                            person_gid.set_email(person['email'])
                             if not pubkey:
                                 user_record.reg_keys=[]
                             else:
                                 user_record.reg_keys=[ RegKey (pubkey['key'], pubkey['key_id'])]
+                            user_record.gid = person_gid
                             self.logger.info("PlImporter: updated person: %s" % user_record)
                     user_record.email = person['email']
                     dbsession.commit()
@@ -335,6 +367,12 @@ class PlImporter:
                     self.logger.log_exc("PlImporter: failed to import person %d %s"%(person['person_id'],person['email']))
     
             # maintain the list of PIs for a given site
+            # for the record, Jordan had proposed the following addition as a welcome hotfix to a previous version:
+            # site_pis = list(set(site_pis)) 
+            # this was likely due to a bug in the above logic, that had to do with disabled persons
+            # being improperly handled, and where the whole loop on persons
+            # could be performed twice with the same person...
+            # so hopefully we do not need to eliminate duplicates explicitly here anymore
             site_record.reg_pis = site_pis
             dbsession.commit()
 
@@ -363,7 +401,8 @@ class PlImporter:
                         self.logger.log_exc("PlImporter: failed to import slice %s (%s)"%(slice_hrn,slice['name']))
                 else:
                     # xxx update the record ...
-                    self.logger.warning ("Slice update not yet implemented on slice %s (%s)"%(slice_hrn,slice['name']))
+                    # given that we record the current set of users anyways, there does not seem to be much left to do here
+                    # self.logger.warning ("Slice update not yet implemented on slice %s (%s)"%(slice_hrn,slice['name']))
                     pass
                 # record current users affiliated with the slice
                 slice_record.reg_researchers = \
index e921d6e..95b4ed2 100644 (file)
@@ -215,6 +215,7 @@ class RegistryManager:
             record_dicts = record_list
         
         # if we still have not found the record yet, try the local registry
+#        logger.debug("before trying local records, %d foreign records"% len(record_dicts))
         if not record_dicts:
             recursive = False
             if ('recursive' in options and options['recursive']):
@@ -226,9 +227,11 @@ class RegistryManager:
             if not api.auth.hierarchy.auth_exists(hrn):
                 raise MissingAuthority(hrn)
             if recursive:
-                records = dbsession.query(RegRecord).filter(RegRecord.hrn.startswith(hrn))
+                records = dbsession.query(RegRecord).filter(RegRecord.hrn.startswith(hrn)).all()
+#                logger.debug("recursive mode, found %d local records"%(len(records)))
             else:
-                records = dbsession.query(RegRecord).filter_by(authority=hrn)
+                records = dbsession.query(RegRecord).filter_by(authority=hrn).all()
+#                logger.debug("non recursive mode, found %d local records"%(len(records)))
             # so that sfi list can show more than plain names...
             for record in records: augment_with_sfa_builtins (record)
             record_dicts=[ record.todict(exclude_types=[InstrumentedList]) for record in records ]
@@ -364,7 +367,7 @@ class RegistryManager:
         # is there a change in keys ?
         new_key=None
         if type=='user':
-            if getattr(new_key,'keys',None):
+            if getattr(new_record,'keys',None):
                 new_key=new_record.keys
                 if isinstance (new_key,types.ListType):
                     new_key=new_key[0]
@@ -377,8 +380,6 @@ class RegistryManager:
             urn = hrn_to_urn(hrn,type)
             gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
             gid = gid_object.save_to_string(save_parents=True)
-            record.gid = gid
-            dsession.commit()
         
         # xxx should do side effects from new_record to record
         # not too sure how to do that
@@ -388,12 +389,10 @@ class RegistryManager:
         if isinstance (record, RegSlice):
             researcher_hrns = getattr(new_record,'researcher',None)
             if researcher_hrns is not None: record.update_researchers (researcher_hrns)
-            dbsession.commit()
 
         elif isinstance (record, RegAuthority):
             pi_hrns = getattr(new_record,'pi',None)
             if pi_hrns is not None: record.update_pis (pi_hrns)
-            dbsession.commit()
         
         # update the PLC information that was specified with the record
         # xxx oddly enough, without this useless statement, 
@@ -401,9 +400,12 @@ class RegistryManager:
         # anyway the driver should receive an object 
         # (and then extract __dict__ itself if needed)
         print "DO NOT REMOVE ME before driver.update, record=%s"%record
-        if not self.driver.update (record.__dict__, new_record.__dict__, hrn, new_key):
-            logger.warning("driver.update failed")
-    
+        (pointer, new_key_pointer) = self.driver.update (record.__dict__, new_record.__dict__, hrn, new_key)
+        if new_key and new_key_pointer:    
+            record.reg_keys=[ RegKey (new_key, new_key_pointer)]
+            record.gid = gid
+
+        dbsession.commit();
         # update membership for researchers, pis, owners, operators
         self.update_driver_relations (record, new_record)
         
index abfcb92..9274f39 100644 (file)
@@ -135,6 +135,7 @@ class PlDriver (Driver):
     def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
         pointer = old_sfa_record['pointer']
         type = old_sfa_record['type']
+        new_key_pointer = None
 
         # new_key implemented for users only
         if new_key and type not in [ 'user' ]:
@@ -173,20 +174,19 @@ class PlDriver (Driver):
                 keys = person['key_ids']
                 keys = self.shell.GetKeys(person['key_ids'])
                 
-                # Delete all stale keys
                 key_exists = False
                 for key in keys:
-                    if new_key != key['key']:
-                        self.shell.DeleteKey(key['key_id'])
-                    else:
+                    if new_key == key['key']:
                         key_exists = True
+                        new_key_pointer = key['key_id']
+                        break
                 if not key_exists:
-                    self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
+                    new_key_pointer = self.shell.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
     
         elif type == "node":
             self.shell.UpdateNode(pointer, new_sfa_record)
 
-        return True
+        return (pointer, new_key_pointer)
         
 
     ##########
index cb02d86..135d817 100644 (file)
@@ -661,8 +661,10 @@ class Credential(object):
         # Call out to xmlsec1 to sign it
         ref = 'Sig_%s' % self.get_refid()
         filename = self.save_to_random_tmp_file()
-        signed = os.popen('%s --sign --node-id "%s" --privkey-pem %s,%s %s' \
-                 % (self.xmlsec_path, ref, self.issuer_privkey, ",".join(gid_files), filename)).read()
+        command='%s --sign --node-id "%s" --privkey-pem %s,%s %s' \
+            % (self.xmlsec_path, ref, self.issuer_privkey, ",".join(gid_files), filename)
+#        print 'command',command
+        signed = os.popen(command).read()
         os.remove(filename)
 
         for gid_file in gid_files:
@@ -1056,6 +1058,9 @@ class Credential(object):
             print "  gidIssuer:"
             self.get_signature().get_issuer_gid().dump(8, dump_parents)
 
+        if self.expiration:
+            print "  expiration:", self.expiration.isoformat()
+
         gidObject = self.get_gid_object()
         if gidObject:
             result += "  gidObject:\n"
index b9cd05e..eb3cba5 100644 (file)
@@ -56,7 +56,7 @@ class Method:
        
     def __call__(self, *args, **kwds):
         """
-        Main entry point for all SfaAPI functions. Type checks
+        Main entry point for all SFA API functions. Type checks
         arguments, authenticates, and executes call().
         """