def install_gids(api, slivers):
    # install node gid
    node_gid_file = api.config.config_path + os.sep + "node.gid"
    node_gid = GID(filename=node_gid_file)
    node_gid_str = node_gid.save_to_string(save_parents=True)    
    node_hrn = node_gid.get_hrn()    

    # get currently installed slice and node gids 
    interface_hrn = api.config.SFA_INTERFACE_HRN
    slice_gids = {}
    node_gids = {}
    for slicename in slivers:
        slice_gid_filename = "/vservers/%s/etc/slice.gid" % slicename
        node_gid_filename = "/vservers/%s/etc/node.gid" % slicename
        if os.path.isfile(slice_gid_filename):
            gid_file = open(slice_gid_filename, 'r') 
            slice_gids[sliver] = gid_file.read()
            gid_file.close()
        if os.path.isfile(node_gid_filename):
            gid_file = open(node_gid_filename, 'r')
            node_gids[sliver] = gid_file.read()
            gid_file.close()

    # convert slicenames to hrns
    hrns = [slicename_to_hrn(interface_hrn, slicename) \
            for slicename in slivers]

    # get current gids from registry
    cred = api.getCredential()
    registry = api.get_registry()
    #records = registry.GetGids(cred, hrns)
    records = registry.get_gids(cred, hrns)
    for record in records:
        # skip if this isnt a slice record 
        if not record['type'] == 'slice':
            continue
        vserver_path = "/vservers/%(slicename)s" % locals()
        # skip if the slice isnt instantiated
        if not os.path.exists(vserver_path):
            continue
        
        # install slice gid if it doesnt already exist or has changed
        slice_gid_str = record['gid']
        slicename = hrn_to_pl_slicename(record['hrn'])
        if slicename not in slice_gids or slice_gids[slicename] != slice_gid_str:
            gid_filename = os.sep.join([vserver_path, "etc", "slice.gid"])
            GID(string=slice_gid_str).save_to_file(gid_filename, save_parents=True)

        # install slice gid if it doesnt already exist or has changed
        if slicename not in node_gids or node_gids[slicename] != node_gid_str:
            gid_filename = os.sep.join([vserver_path, "etc", "node.gid"])
            GID(string=node_gid_str).save_to_file(gid_filename, save_parents=True) 
Exemple #2
0
def import_gid(options):
    """
    Import the specified gid into the registry (db and authorities 
    hierarchy) overwriting any previous gid.
    """
    from sfa.util.table import SfaTable
    from sfa.util.record import SfaRecord
    # load the gid
    gidfile = os.path.abspath(options.importgid)
    if not gidfile or not os.path.isfile(gidfile):
        print "No such gid: %s" % gidfile
        sys.exit(1)
    gid = GID(filename=gidfile)
    
    # check if it exists within the hierarchy
    hierarchy = Hierarchy()
    if not hierarchy.auth_exists(gid.get_hrn()):
        print "%s not found in hierarchy" % gid.get_hrn()
        sys.exit(1)

    # check if record exists in db
    table = SfaTable()
    records = table.find({'hrn': gid.get_hrn(), 'type': 'authority'})
    if not records:
        print "%s not found in record database" % get.get_hrn()  
        sys.exit(1)

    # update the database record
    record = records[0]
    record['gid'] = gid.save_to_string(save_parents=True)
    table.update(record)
    if options.verbose:
        print "Imported %s gid into db" % record['hrn']

    # update the hierarchy
    auth_info = hierarchy.get_auth_info(gid.get_hrn())  
    filename = auth_info.gid_filename
    gid.save_to_file(filename, save_parents=True)
    if options.verbose:
        print "Writing %s gid to %s" % (gid.get_hrn(), filename)

    # ending here
    return
Exemple #3
0
class Sfi:
    
    required_options=['verbose',  'debug',  'registry',  'sm',  'auth',  'user']

    # dummy to meet Sfi's expectations for its 'options' field
    # i.e. s/t we can do setattr on
    class DummyOptions:
        pass

    def __init__ (self,options=None):
        if options is None: options=Sfi.DummyOptions()
        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/")
        # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
        # would be safer to remove self.sfi_dir altogether
        self.sfi_dir = options.sfi_dir
        self.options = options
        self.slicemgr = None
        self.registry = None
        self.user = None
        self.authority = None
        self.hashrequest = False
        self.logger = sfi_logger
        self.logger.enable_console()
   
    def create_cmd_parser(self, command, additional_cmdargs=None):
        cmdargs = {"list": "authority",
                  "show": "name",
                  "remove": "name",
                  "add": "record",
                  "update": "record",
                  "aggregates": "[name]",
                  "registries": "[name]",
                  "create_gid": "[name]",
                  "get_gid": [],  
                  "get_trusted_certs": "cred",
                  "slices": "",
                  "resources": "[name]",
                  "create": "name rspec",
                  "get_ticket": "name rspec",
                  "redeem_ticket": "ticket",
                  "delete": "name",
                  "reset": "name",
                  "start": "name",
                  "stop": "name",
                  "delegate": "name",
                  "status": "name",
                  "renew": "name",
                  "shutdown": "name",
                  "version": "",  
                 }

        if additional_cmdargs:
            cmdargs.update(additional_cmdargs)

        if command not in cmdargs:
            msg="Invalid command\n"
            msg+="Commands: "
            msg += ','.join(cmdargs.keys())            
            self.logger.critical(msg)
            sys.exit(2)

        parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
                                     % (command, cmdargs[command]))

        # user specifies remote aggregate/sm/component                          
        if command in ("resources", "slices", "create", "delete", "start", "stop", 
                       "restart", "shutdown",  "get_ticket", "renew", "status"):
            parser.add_option("-a", "--aggregate", dest="aggregate",
                             default=None, help="aggregate host")
            parser.add_option("-p", "--port", dest="port",
                             default=AGGREGATE_PORT, help="aggregate port")
            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"+\
                                  "authority in set of credentials for this call")  
        
        # registy filter option    
        if command in ("list", "show", "remove"):
            parser.add_option("-t", "--type", dest="type", type="choice",
                            help="type filter ([all]|user|slice|authority|node|aggregate)",
                            choices=("all", "user", "slice", "authority", "node", "aggregate"),
                            default="all")
        # display formats
        if command in ("resources"):
            parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
                              help="schema type and version of resulting RSpec")
            parser.add_option("-f", "--format", dest="format", type="choice",
                             help="display format ([xml]|dns|ip)", default="xml",
                             choices=("xml", "dns", "ip"))
            #panos: a new option to define the type of information about resources a user is interested in
	    parser.add_option("-i", "--info", dest="info",
                                help="optional component information", default=None)


        # 'create' does return the new rspec, makes sense to save that too
        if command in ("resources", "show", "list", "create_gid", 'create'):
           parser.add_option("-o", "--output", dest="file",
                            help="output XML to file", metavar="FILE", default=None)

        if command in ("show", "list"):
           parser.add_option("-f", "--format", dest="format", type="choice",
                             help="display format ([text]|xml)", default="text",
                             choices=("text", "xml"))

           parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
                             help="output file format ([xml]|xmllist|hrnlist)", default="xml",
                             choices=("xml", "xmllist", "hrnlist"))

        if command in ("status"):
           parser.add_option("-o", "--output", dest="file",
                            help="output dictionary to file", metavar="FILE", default=None)
           parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
                             help="output file format ([text]|pickled)", default="text",
                             choices=("text","pickled"))

        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)
        
        if command in ("version"):
            parser.add_option("-a", "--aggregate", dest="aggregate",
                             default=None, help="aggregate host")
            parser.add_option("-p", "--port", dest="port",
                             default=AGGREGATE_PORT, help="aggregate port")
            parser.add_option("-R","--registry-version",
                              action="store_true", dest="version_registry", default=False,
                              help="probe registry version instead of slicemgr")
            parser.add_option("-l","--local",
                              action="store_true", dest="version_local", default=False,
                              help="display version of the local client")

        return parser

        
    def create_parser(self):

        # Generate command line parser
        parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
                             description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
        parser.add_option("-r", "--registry", dest="registry",
                         help="root registry", metavar="URL", default=None)
        parser.add_option("-s", "--slicemgr", dest="sm",
                         help="slice manager", metavar="URL", default=None)
        default_sfi_dir = os.path.expanduser("~/.sfi/")
        parser.add_option("-d", "--dir", dest="sfi_dir",
                         help="config & working directory - default is " + default_sfi_dir,
                         metavar="PATH", default=default_sfi_dir)
        parser.add_option("-u", "--user", dest="user",
                         help="user name", metavar="HRN", default=None)
        parser.add_option("-a", "--auth", dest="auth",
                         help="authority name", metavar="HRN", default=None)
        parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
                         help="verbose mode - cumulative")
        parser.add_option("-D", "--debug",
                          action="store_true", dest="debug", default=False,
                          help="Debug (xml-rpc) protocol messages")
        parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
                         help="RPC protocol (xmlrpc or soap)")
        parser.add_option("-k", "--hashrequest",
                         action="store_true", dest="hashrequest", default=False,
                         help="Create a hash of the request that will be authenticated on the server")
        parser.add_option("-t", "--timeout", dest="timeout", default=None,
                         help="Amout of time tom wait before timing out the request")
        parser.disable_interspersed_args()

        return parser
        

    def read_config(self):
       config_file = os.path.join(self.options.sfi_dir,"sfi_config")
       try:
          config = Config (config_file)
       except:
          self.logger.critical("Failed to read configuration file %s"%config_file)
          self.logger.info("Make sure to remove the export clauses and to add quotes")
          if self.options.verbose==0:
              self.logger.info("Re-run with -v for more details")
          else:
              self.logger.log_exc("Could not read config file %s"%config_file)
          sys.exit(1)
    
       errors = 0
       # Set SliceMgr URL
       if (self.options.sm is not None):
          self.sm_url = self.options.sm
       elif hasattr(config, "SFI_SM"):
          self.sm_url = config.SFI_SM
       else:
          self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
          errors += 1 
    
       # Set Registry URL
       if (self.options.registry is not None):
          self.reg_url = self.options.registry
       elif hasattr(config, "SFI_REGISTRY"):
          self.reg_url = config.SFI_REGISTRY
       else:
          self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
          errors += 1 
          

       # Set user HRN
       if (self.options.user is not None):
          self.user = self.options.user
       elif hasattr(config, "SFI_USER"):
          self.user = config.SFI_USER
       else:
          self.logger.errors("You need to set e.g. SFI_USER='******' in %s" % config_file)
          errors += 1 
    
       # Set authority HRN
       if (self.options.auth is not None):
          self.authority = self.options.auth
       elif hasattr(config, "SFI_AUTH"):
          self.authority = config.SFI_AUTH
       else:
          self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
          errors += 1 
    
       if errors:
          sys.exit(1)


    #
    # Establish Connection to SliceMgr and Registry Servers
    #
    def set_servers(self):

       self.read_config() 
       # Get key and certificate
       key_file = self.get_key_file()
       cert_file = self.get_cert_file(key_file)
       self.key = Keypair(filename=key_file) 
       self.key_file = key_file
       self.cert_file = cert_file
       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, timeout=self.options.timeout, verbose=self.options.debug)  
       self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
       self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
       return

    def get_cached_server_version(self, server):
        # check local cache first
        cache = None
        version = None 
        cache_file = os.path.join(self.options.sfi_dir,'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)
            self.logger.info("Updating cache file %s" % cache_file)
            cache.save_to_file(cache_file)


        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 and 'code_tag' 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
    #
    # Establishes limiting conventions
    #   - conflates MAs and SAs
    #   - assumes last token in slice name is unique
    #
    # Bootstraps credentials
    #   - bootstrap user credential from self-signed certificate
    #   - bootstrap authority credential from user credential
    #   - bootstrap slice credential from user credential
    #
    
    
    def get_key_file(self):
       file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
       if (os.path.isfile(file)):
          return file
       else:
          self.logger.error("Key file %s does not exist"%file)
          sys.exit(-1)
       return
    
    def get_cert_file(self, key_file):
    
        cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
        if (os.path.isfile(cert_file)):
            # we'd perfer to use Registry issued certs instead of self signed certs. 
            # if this is a Registry cert (GID) then we are done 
            gid = GID(filename=cert_file)
            if gid.get_urn():
                return cert_file

        # generate self signed certificate
        k = Keypair(filename=key_file)
        cert = Certificate(subject=self.user)
        cert.set_pubkey(k)
        cert.set_issuer(k, self.user)
        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")
            self.read_config()
            # *hack.  need to set registyr before _get_gid() is called 
            self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
            gid = self._get_gid(type='user')
            self.registry = None 
            self.logger.info("Writing certificate to %s"%cert_file)
            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):
        """
        Return a cached gid    
        """
        gid = None 
        if (os.path.isfile(file)):
            gid = GID(filename=file)
        return gid

    # xxx opts unused
    def get_gid(self, opts, args):
        """
        Get the specify gid and save it to file
        """
        hrn = None
        if args:
            hrn = args[0]
        gid = self._get_gid(hrn)
        self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
        return gid

    def _get_gid(self, hrn=None, type=None):
        """
        git_gid helper. Retrive the gid from the registry and save it to file.
        """
        
        if not hrn:
            hrn = self.user
 
        gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
        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))
            if not records:
                raise RecordNotFound(args[0])
            record = records[0]
            if type:
                record=None
                for rec in records:
                   if type == rec['type']:
                        record = rec 
            if not record:
                raise RecordNotFound(args[0])
            
            gid = GID(string=record['gid'])
            self.logger.info("Writing gid to %s"%gidfile)
            gid.save_to_file(filename=gidfile)
        return gid   
                
     
    def get_cached_credential(self, file):
        """
        Return a cached credential only if it hasn't expired.
        """
        if (os.path.isfile(file)):
            credential = Credential(filename=file)
            # make sure it isnt expired 
            if not credential.get_expiration or \
               datetime.datetime.today() < credential.get_expiration():
                return credential
        return None 
 
    def get_user_cred(self):
        file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
        return self.get_cred(file, 'user', self.user)

    def get_auth_cred(self):
        if not self.authority:
            self.logger.critical("no authority specified. Use -a or set SF_AUTH")
            sys.exit(-1)
        file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
        return self.get_cred(file, 'authority', self.authority)

    def get_slice_cred(self, name):
        file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
        return self.get_cred(file, 'slice', name)
 
    def get_cred(self, file, type, hrn):
        # attempt to load a cached credential 
        cred = self.get_cached_credential(file)    
        if not cred:
            if type in ['user']:
                cert_string = self.cert.save_to_string(save_parents=True)
                user_name = self.user.replace(self.authority + ".", '')
                if user_name.count(".") > 0:
                    user_name = user_name.replace(".", '_')
                    self.user = self.authority + "." + user_name
                cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
            else:
                # bootstrap slice credential from user credential
                user_cred = self.get_user_cred().save_to_string(save_parents=True)
                cred_str = self.registry.GetCredential(user_cred, hrn, type)
            
            if not cred_str:
                self.logger.critical("Failed to get %s credential" % type)
                sys.exit(-1)
                
            cred = Credential(string=cred_str)
            cred.save_to_file(file, save_parents=True)
            self.logger.info("Writing %s credential to %s" %(type, file))

        return cred
 
    
    def get_rspec_file(self, rspec):
       if (os.path.isabs(rspec)):
          file = rspec
       else:
          file = os.path.join(self.options.sfi_dir, rspec)
       if (os.path.isfile(file)):
          return file
       else:
          self.logger.critical("No such rspec file %s"%rspec)
          sys.exit(1)
    
    def get_record_file(self, record):
       if (os.path.isabs(record)):
          file = record
       else:
          file = os.path.join(self.options.sfi_dir, record)
       if (os.path.isfile(file)):
          return file
       else:
          self.logger.critical("No such registry record file %s"%record)
          sys.exit(1)
    
    def load_publickey_string(self, fn):
       f = file(fn, "r")
       key_string = f.read()
    
       # if the filename is a private key file, then extract the public key
       if "PRIVATE KEY" in key_string:
           outfn = tempfile.mktemp()
           cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
           os.system(cmd)
           f = file(outfn, "r")
           key_string = f.read()
           os.remove(outfn)
    
       return key_string

    # xxx opts undefined
    def get_component_server_from_hrn(self, hrn):
        # direct connection to the nodes component manager interface
        user_cred = self.get_user_cred().save_to_string(save_parents=True)
        records = self.registry.Resolve(hrn, user_cred)
        records = filter_records('node', records)
        if not records:
            self.logger.warning("No such component:%r"% opts.component)
        record = records[0]
  
        return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
 
    def get_server(self, host, port, keyfile, certfile):
        """
        Return an instance of an xmlrpc server connection    
        """
        # port is appended onto the domain, before the path. Should look like:
        # http://domain:port/path
        host_parts = host.split('/')
        host_parts[0] = host_parts[0] + ":" + str(port)
        url =  "http://%s" %  "/".join(host_parts)    
        return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)

    # xxx opts could be retrieved in self.options
    def get_server_from_opts(self, opts):
        """
        Return instance of an xmlrpc connection to a slice manager, aggregate
        or component server depending on the specified opts
        """
        server = self.slicemgr
        # direct connection to an aggregate
        if hasattr(opts, 'aggregate') and opts.aggregate:
            server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
        # direct connection to the nodes component manager interface
        if hasattr(opts, 'component') and opts.component:
            server = self.get_component_server_from_hrn(opts.component)    
 
        return server
    #==========================================================================
    # Following functions implement the commands
    #
    # Registry-related commands
    #==========================================================================
  
    def dispatch(self, command, cmd_opts, cmd_args):
        return getattr(self, command)(cmd_opts, cmd_args)

    def create_gid(self, opts, args):
        if len(args) < 1:
            self.print_help()
            sys.exit(1)
        target_hrn = args[0]
        user_cred = self.get_user_cred().save_to_string(save_parents=True)
        gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
        if opts.file:
            filename = opts.file
        else:
            filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
        self.logger.info("writing %s gid to %s" % (target_hrn, filename))
        GID(string=gid).save_to_file(filename)
         
     
    # list entires in named authority registry
    def list(self, opts, args):
        if len(args)!= 1:
            self.print_help()
            sys.exit(1)
        hrn = args[0]
        user_cred = self.get_user_cred().save_to_string(save_parents=True)
        try:
            list = self.registry.List(hrn, user_cred)
        except IndexError:
            raise Exception, "Not enough parameters for the 'list' command"

        # filter on person, slice, site, node, etc.
        # THis really should be in the self.filter_records funct def comment...
        list = filter_records(opts.type, list)
        for record in list:
            print "%s (%s)" % (record['hrn'], record['type'])
        if opts.file:
            save_records_to_file(opts.file, list, opts.fileformat)
        return
    
    # show named registry record
    def show(self, opts, args):
        if len(args)!= 1:
            self.print_help()
            sys.exit(1)
        hrn = args[0]
        user_cred = self.get_user_cred().save_to_string(save_parents=True)
        records = self.registry.Resolve(hrn, user_cred)
        records = filter_records(opts.type, records)
        if not records:
            print "No record of type", opts.type
        for record in records:
            if record['type'] in ['user']:
                record = UserRecord(dict=record)
            elif record['type'] in ['slice']:
                record = SliceRecord(dict=record)
            elif record['type'] in ['node']:
                record = NodeRecord(dict=record)
            elif record['type'].startswith('authority'):
                record = AuthorityRecord(dict=record)
            else:
                record = SfaRecord(dict=record)
            if (opts.format == "text"): 
                record.dump()  
            else:
                print record.save_to_string() 
        if opts.file:
            save_records_to_file(opts.file, records, opts.fileformat)
        return
    
    def delegate(self, opts, args):

        delegee_hrn = args[0]
        if opts.delegate_user:
            user_cred = self.get_user_cred()
            cred = self.delegate_cred(user_cred, delegee_hrn)
        elif opts.delegate_slice:
            slice_cred = self.get_slice_cred(opts.delegate_slice)
            cred = self.delegate_cred(slice_cred, delegee_hrn)
        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 opts.delegate_user:
            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
                                  + get_leaf(object_hrn) + ".cred")
        elif opts.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))
    
    def delegate_cred(self, object_cred, hrn):
        # 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_gid = self._get_gid(self.user)
        caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
  
        # the gid of the user who will be delegated to
        delegee_gid = self._get_gid(hrn)
        delegee_hrn = delegee_gid.get_hrn()
        delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
        delegee_gid.save_to_file(filename=delegee_gidfile)
        dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
        return dcred.save_to_string(save_parents=True)
     
    # removed named registry record
    #   - have to first retrieve the record to be removed
    def remove(self, opts, args):
        auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
        if len(args)!=1:
            self.print_help()
            sys.exit(1)
        hrn = args[0]
        type = opts.type 
        if type in ['all']:
            type = '*'
        return self.registry.Remove(hrn, auth_cred, type)
    
    # add named registry record
    def add(self, opts, args):
        auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
        if len(args)!=1:
            self.print_help()
            sys.exit(1)
        record_filepath = args[0]
        rec_file = self.get_record_file(record_filepath)
        record = load_record_from_file(rec_file).as_dict()
        return self.registry.Register(record, auth_cred)
    
    # update named registry entry
    def update(self, opts, args):
        user_cred = self.get_user_cred()
        if len(args)!=1:
            self.print_help()
            sys.exit(1)
        rec_file = self.get_record_file(args[0])
        record = load_record_from_file(rec_file)
        if record['type'] == "user":
            if record.get_name() == user_cred.get_gid_object().get_hrn():
                cred = user_cred.save_to_string(save_parents=True)
            else:
                cred = self.get_auth_cred().save_to_string(save_parents=True)
        elif record['type'] in ["slice"]:
            try:
                cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
            except xmlrpcprotocol.ServerException, e:
               # XXX smbaker -- once we have better error return codes, update this
               # to do something better than a string compare
               if "Permission error" in e.args[0]:
                   cred = self.get_auth_cred().save_to_string(save_parents=True)
               else:
                   raise
        elif record.get_type() in ["authority"]:
            cred = self.get_auth_cred().save_to_string(save_parents=True)