# when running GetCredential
# This is to reflect the 'enabled' user field in planetlab testbeds
# expected retcod boolean
- def is_enabled_entity (self, record, aggregates) : return True
+ def is_enabled_entity (self, record) :
+ return True
# incoming record, as provided by the client to the Register API call
# expected retcod 'pointer'
# 'pointer' is typically an int db id, that makes sense in the testbed environment
# -1 if this feature is not relevant
# here type will be 'authority'
- def register (self, hrn, sfa_record, pub_key) : return -1
+ def register (self, sfa_record, hrn, pub_key) :
+ return -1
# incoming record is the existing sfa_record
- # no retcod expected for now
- def remove (self, sfa_record): return None
+ # error message logged if result is False
+ def remove (self, sfa_record):
+ return True
+
+ # incoming are the sfa_record:
+ # (*) old_sfa_record is what we have in the db for that hrn
+ # (*) new_sfa_record is what was passed in the Update call
+ # error message logged if result is False
+ # NOTE 1. about keys
+ # this is confusing because a user may have several ssh keys in
+ # the planetlab database, but we need to pick one to generate its cert
+ # so as much as in principle we should be able to use new_sfa_record['keys']
+ # the manager code actually picks one, and it's safer to pass it along
+ # rather than depending on the driver code to do the same
+ # xxx
+ # NOTE 2. about keys
+ # when changing the ssh key through this method the gid gets changed too
+ # should anything be passed back to the caller in this case ?
+ def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
+ return True
# verify_cancreate_credential requires that the member lists
# (researchers, pis, etc) be filled in
- if not self.driver.is_enabled_entity (record, api.aggregates):
+ if not self.driver.is_enabled_entity (record):
raise AccountNotEnabled(": PlanetLab account %s is not enabled. Please contact your site PI" %(record['email']))
# get the callers gid
#
table = SfaTable()
local_records = table.findObjects({'hrn': local_hrns})
- # xxx driver todo
+
if full:
- self.driver.fill_record_info(local_records, api.aggregates)
+ # in full mode we get as much info as we can, which involves contacting the
+ # testbed for getting implementation details about the record
+ self.driver.fill_record_info(local_records)
+ # also we fill the 'url' field for known authorities
+ # used to be in the driver code, sounds like a poorman thing though
+ def solve_neighbour_url (record):
+ if not record['type'].startswith('authority'): return
+ hrn=record['hrn']
+ for neighbour_dict in [ api.aggregates, api.registries ]:
+ if hrn in neighbour_dict:
+ record['url']=neighbour_dict[hrn].get_url()
+ return
+ [ solve_neighbour_url (record) for record in local_records ]
+
+
# convert local record objects to dicts
records.extend([dict(record) for record in local_records])
if 'gid' not in record:
uuid = create_uuid()
pkey = Keypair(create=True)
- if 'key' in record and record['key']:
+ if 'keys' in record and record['keys']:
+ pub_key=record['keys']
# use only first key in record
- if isinstance(record['key'], types.ListType):
- pub_key = record['key'][0]
- else:
- pub_key = record['key']
+ if isinstance(record['keys'], types.ListType):
+ pub_key = record['keys'][0]
pkey = convert_public_key(pub_key)
gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
# update testbed-specific data f needed
logger.info("Getting driver from manager=%s"%self)
- pointer = self.driver.register (hrn, record, pub_key)
+ pointer = self.driver.register (record, hrn, pub_key)
record.set_pointer(pointer)
record_id = table.insert(record)
record = records[0]
record['last_updated'] = time.gmtime()
- # Update_membership needs the membership lists in the existing record
- # filled in, so it can see if members were added or removed
- self.driver.fill_record_info(record, api.aggregates)
-
+ # validate the type
+ if type not in ['authority', 'slice', 'node', 'user']:
+ raise UnknownSfaType(type)
+
# Use the pointer from the existing record, not the one that the user
# gave us. This prevents the user from inserting a forged pointer
pointer = record['pointer']
- # update the PLC information that was specified with the record
- if (type == "authority"):
- self.driver.UpdateSite(pointer, new_record)
-
- elif type == "slice":
- pl_record=self.driver.sfa_fields_to_pl_fields(type, hrn, new_record)
- if 'name' in pl_record:
- pl_record.pop('name')
- self.driver.UpdateSlice(pointer, pl_record)
-
- elif type == "user":
- # SMBAKER: UpdatePerson only allows a limited set of fields to be
- # updated. Ideally we should have a more generic way of doing
- # this. I copied the field names from UpdatePerson.py...
- update_fields = {}
- all_fields = new_record
- for key in all_fields.keys():
- if key in ['first_name', 'last_name', 'title', 'email',
- 'password', 'phone', 'url', 'bio', 'accepted_aup',
- 'enabled']:
- update_fields[key] = all_fields[key]
- self.driver.UpdatePerson(pointer, update_fields)
-
- if 'key' in new_record and new_record['key']:
- # must check this key against the previous one if it exists
- persons = self.driver.GetPersons([pointer], ['key_ids'])
- person = persons[0]
- keys = person['key_ids']
- keys = self.driver.GetKeys(person['key_ids'])
- key_exists = False
- if isinstance(new_record['key'], types.ListType):
- new_key = new_record['key'][0]
- else:
- new_key = new_record['key']
-
- # Delete all stale keys
- for key in keys:
- if new_record['key'] != key['key']:
- self.driver.DeleteKey(key['key_id'])
- else:
- key_exists = True
- if not key_exists:
- self.driver.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
-
- # update the openssl key and gid
- pkey = convert_public_key(new_key)
- uuid = create_uuid()
- gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
- gid = gid_object.save_to_string(save_parents=True)
- record['gid'] = gid
- record = SfaRecord(dict=record)
- table.update(record)
-
- elif type == "node":
- self.driver.UpdateNode(pointer, new_record)
+ # is the a change in keys ?
+ new_key=None
+ if type=='user':
+ if 'keys' in new_record and new_record['keys']:
+ new_key=new_record['keys']
+ if isinstance (new_key,types.ListType):
+ new_key=new_key[0]
+
+ # Update_membership needs the membership lists in the existing record
+ # filled in, so it can see if members were added or removed
+ self.driver.fill_record_info(record)
- else:
- raise UnknownSfaType(type)
+ # update the PLC information that was specified with the record
+ if not self.driver.update (record, new_record, hrn, new_key):
+ logger.warning("driver.update failed")
+ # take new_key into account
+ if new_key:
+ # update the openssl key and gid
+ pkey = convert_public_key(new_key)
+ uuid = create_uuid()
+ gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
+ gid = gid_object.save_to_string(save_parents=True)
+ record['gid'] = gid
+ record = SfaRecord(dict=record)
+ table.update(record)
+
# update membership for researchers, pis, owners, operators
self.driver.update_membership(record, new_record)
record = records[0]
type = record['type']
- if not type in ['slice', 'user', 'node', 'authority'] :
+ if type not in ['slice', 'user', 'node', 'authority'] :
raise UnknownSfaType(type)
credential = api.getCredential()
result=registries[registry].remove_peer_object(credential, record, origin_hrn)
except:
pass
+
# call testbed callback first
- self.driver.remove(record)
+ # IIUC this is done on the local testbed TOO because of the refreshpeer link
+ if not self.driver.remove(record):
+ logger.warning("driver.remove failed")
+
# delete from sfa db
table.remove(record)
#
-from sfa.util.faults import MissingSfaInfo
+from sfa.util.faults import MissingSfaInfo, UnknownSfaType
from sfa.util.sfalogging import logger
from sfa.util.table import SfaTable
from sfa.util.defaultdict import defaultdict
rspec_type == 'eucalyptus' or rspec_type == 'max')
########## disabled users
- def is_enabled_entity (self, record, aggregates):
- self.fill_record_info(record, aggregates)
+ def is_enabled_entity (self, record):
+ self.fill_record_info(record)
if record['type'] == 'user':
return record['enabled']
# only users can be disabled
return True
##########
- def register (self, hrn, sfa_record, pub_key):
+ def register (self, sfa_record, hrn, pub_key):
type = sfa_record['type']
pl_record = self.sfa_fields_to_pl_fields(type, hrn, sfa_record)
return pointer
+ ##########
+ # xxx actually old_sfa_record comes filled with plc stuff as well in the original code
+ def update (self, old_sfa_record, new_sfa_record, hrn, new_key):
+ pointer = old_sfa_record['pointer']
+ type = old_sfa_record['type']
+
+ # new_key implemented for users only
+ if new_key and type not in [ 'user' ]:
+ raise UnknownSfaType(type)
+
+ if (type == "authority"):
+ self.UpdateSite(pointer, new_sfa_record)
+
+ elif type == "slice":
+ pl_record=self.sfa_fields_to_pl_fields(type, hrn, new_sfa_record)
+ if 'name' in pl_record:
+ pl_record.pop('name')
+ self.UpdateSlice(pointer, pl_record)
+
+ elif type == "user":
+ # SMBAKER: UpdatePerson only allows a limited set of fields to be
+ # updated. Ideally we should have a more generic way of doing
+ # this. I copied the field names from UpdatePerson.py...
+ update_fields = {}
+ all_fields = new_sfa_record
+ for key in all_fields.keys():
+ if key in ['first_name', 'last_name', 'title', 'email',
+ 'password', 'phone', 'url', 'bio', 'accepted_aup',
+ 'enabled']:
+ update_fields[key] = all_fields[key]
+ self.UpdatePerson(pointer, update_fields)
+
+ if new_key:
+ # must check this key against the previous one if it exists
+ persons = self.GetPersons([pointer], ['key_ids'])
+ person = persons[0]
+ keys = person['key_ids']
+ keys = self.GetKeys(person['key_ids'])
+
+ # Delete all stale keys
+ key_exists = False
+ for key in keys:
+ if new_key != key['key']:
+ self.DeleteKey(key['key_id'])
+ else:
+ key_exists = True
+ if not key_exists:
+ self.AddPersonKey(pointer, {'key_type': 'ssh', 'key': new_key})
+
+ elif type == "node":
+ self.UpdateNode(pointer, new_sfa_record)
+
+ return True
+
+
+ ##########
def remove (self, sfa_record):
type=sfa_record['type']
pointer=sfa_record['pointer']
if self.GetSites(pointer):
self.DeleteSite(pointer)
+ return True
+
return pl_record
####################
- def fill_record_info(self, records, aggregates):
+ def fill_record_info(self, records):
"""
Given a (list of) SFA record, fill in the PLC specific
and SFA specific fields in the record.
records = [records]
self.fill_record_pl_info(records)
- self.fill_record_sfa_info(records, aggregates)
+ self.fill_record_sfa_info(records)
def fill_record_pl_info(self, records):
"""
Fill in the planetlab specific fields of a SFA record. This
involves calling the appropriate PLC method to retrieve the
database record for the object.
-
- PLC data is filled into the pl_info field of the record.
-
+
@param record: record to fill in field (in/out param)
"""
# get ids by type
return records
# aggregates is basically api.aggregates
- def fill_record_sfa_info(self, records, aggregates):
+ def fill_record_sfa_info(self, records):
def startswith(prefix, values):
return [value for value in values if value.startswith(prefix)]
elif (type.startswith("authority")):
record['url'] = None
- if record['hrn'] in aggregates:
-
- record['url'] = aggregates[record['hrn']].get_url()
-
if record['pointer'] != -1:
record['PI'] = []
record['operator'] = []