-a --aggregate option sends request directly to the aggregate (bypass the slice manag...
[sfa.git] / sfa / client / sfi.py
1 #! /usr/bin/env python
2
3 # sfi -- slice-based facility interface
4
5 import sys
6 sys.path.append('.')
7 import os, os.path
8 import tempfile
9 import traceback
10 import socket
11 import random
12 from lxml import etree
13 from StringIO import StringIO
14 from types import StringTypes, ListType
15 from optparse import OptionParser
16 from sfa.trust.certificate import Keypair, Certificate
17 from sfa.trust.credential import Credential
18 from sfa.util.sfaticket import SfaTicket
19 from sfa.util.record import *
20 from sfa.util.namespace import *
21 from sfa.util.xmlrpcprotocol import ServerException
22 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
23 from sfa.util.config import Config
24 import zlib
25
26 AGGREGATE_PORT=12346
27 CM_PORT=12346
28
29 # utility methods here
30 # display methods
31 def display_rspec(rspec, format='rspec'):
32     if format in ['dns']:
33         tree = etree.parse(StringIO(rspec))
34         root = tree.getroot()
35         result = root.xpath("./network/site/node/hostname/text()")
36     elif format in ['ip']:
37         # The IP address is not yet part of the new RSpec
38         # so this doesn't do anything yet.
39         tree = etree.parse(StringIO(rspec))
40         root = tree.getroot()
41         result = root.xpath("./network/site/node/ipv4/text()")
42     else:
43         result = rspec
44
45     print result
46     return
47
48 def display_list(results):
49     for result in results:
50         print result
51
52
53 def display_records(recordList, dump=False):
54     ''' Print all fields in the record'''
55     for record in recordList:
56         display_record(record, dump)
57
58 def display_record(record, dump=False):
59     if dump:
60         record.dump()
61     else:
62         info = record.getdict()
63         print "%s (%s)" % (info['hrn'], info['type'])
64     return
65
66
67 def filter_records(type, records):
68     filtered_records = []
69     for record in records:
70         if (record['type'] == type) or (type == "all"):
71             filtered_records.append(record)
72     return filtered_records
73
74
75 # save methods
76 def save_rspec_to_file(rspec, filename):
77     if not filename.endswith(".rspec"):
78         filename = filename + ".rspec"
79
80     f = open(filename, 'w')
81     f.write(rspec)
82     f.close()
83     return
84
85 def save_records_to_file(filename, recordList):
86     index = 0
87     for record in recordList:
88         if index > 0:
89             save_record_to_file(filename + "." + str(index), record)
90         else:
91             save_record_to_file(filename, record)
92         index = index + 1
93
94 def save_record_to_file(filename, record):
95     if record['type'] in ['user']:
96         record = UserRecord(dict=record)
97     elif record['type'] in ['slice']:
98         record = SliceRecord(dict=record)
99     elif record['type'] in ['node']:
100         record = NodeRecord(dict=record)
101     elif record['type'] in ['authority', 'ma', 'sa']:
102         record = AuthorityRecord(dict=record)
103     else:
104         record = SfaRecord(dict=record)
105     str = record.save_to_string()
106     file(filename, "w").write(str)
107     return
108
109
110 # load methods
111 def load_record_from_file(filename):
112     str = file(filename, "r").read()
113     record = SfaRecord(string=str)
114     return record
115
116
117
118 class Sfi:
119
120     geni_am = None
121     slicemgr = None
122     registry = None
123     user = None
124     authority = None
125     options = None
126     hashrequest = False
127    
128     def create_cmd_parser(self, command, additional_cmdargs=None):
129         cmdargs = {"gid": "",
130                   "list": "name",
131                   "show": "name",
132                   "remove": "name",
133                   "add": "record",
134                   "update": "record",
135                   "aggregates": "[name]",
136                   "registries": "[name]",
137                   "slices": "",
138                   "resources": "[name]",
139                   "create": "name rspec",
140                   "get_trusted_certs": "cred",
141                   "get_ticket": "name rspec",
142                   "redeem_ticket": "ticket",
143                   "delete": "name",
144                   "reset": "name",
145                   "start": "name",
146                   "stop": "name",
147                   "delegate": "name",
148                   "GetVersion": "name",
149                   "ListResources": "name",
150                   "CreateSliver": "name",
151                   "get_geni_aggregates": "name",
152                   "DeleteSliver": "name",
153                   "SliverStatus": "name",
154                   "RenewSliver": "name",
155                   "Shutdown": "name"
156                  }
157
158         if additional_cmdargs:
159             cmdargs.update(additional_cmdargs)
160
161         if command not in cmdargs:
162             print "Invalid command\n"
163             print "Commands: ",
164             for key in cmdargs.keys():
165                 print key + ",",
166             print ""
167             sys.exit(2)
168
169         parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
170                                      % (command, cmdargs[command]))
171
172         if command in ("resources"):
173             parser.add_option("-f", "--format", dest="format", type="choice",
174                              help="display format ([xml]|dns|ip)", default="xml",
175                              choices=("xml", "dns", "ip"))
176                                 
177         if command in ("resources", "slices", "create", "delete", "start", "stop", "get_ticket"):
178             parser.add_option("-a", "--aggregate", dest="aggregate",
179                              default=None, help="aggregate host")
180             parser.add_option("-p", "--port", dest="port",
181                              default=AGGREGATE_PORT, help="aggregate port")
182
183         if command in ("start", "stop", "reset", "delete", "slices"):
184             parser.add_option("-c", "--component", dest="component", default=None,
185                              help="component hrn")
186             
187         if command in ("list", "show", "remove"):
188             parser.add_option("-t", "--type", dest="type", type="choice",
189                             help="type filter ([all]|user|slice|sa|ma|node|aggregate)",
190                             choices=("all", "user", "slice", "sa", "ma", "node", "aggregate"),
191                             default="all")
192
193         if command in ("resources", "show", "list"):
194            parser.add_option("-o", "--output", dest="file",
195                             help="output XML to file", metavar="FILE", default=None)
196         
197         if command in ("show", "list"):
198            parser.add_option("-f", "--format", dest="format", type="choice",
199                              help="display format ([text]|xml)", default="text",
200                              choices=("text", "xml"))
201
202         if command in ("delegate"):
203            parser.add_option("-u", "--user",
204                             action="store_true", dest="delegate_user", default=False,
205                             help="delegate user credential")
206            parser.add_option("-s", "--slice", dest="delegate_slice",
207                             help="delegate slice credential", metavar="HRN", default=None)
208         
209         return parser
210
211         
212     def create_parser(self):
213
214         # Generate command line parser
215         parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
216                              description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
217         parser.add_option("-g", "--geni_am", dest="geni_am",
218                           help="geni am", metavar="URL", default=None)
219         parser.add_option("-r", "--registry", dest="registry",
220                          help="root registry", metavar="URL", default=None)
221         parser.add_option("-s", "--slicemgr", dest="sm",
222                          help="slice manager", metavar="URL", default=None)
223         default_sfi_dir = os.path.expanduser("~/.sfi/")
224         parser.add_option("-d", "--dir", dest="sfi_dir",
225                          help="config & working directory - default is " + default_sfi_dir,
226                          metavar="PATH", default=default_sfi_dir)
227         parser.add_option("-u", "--user", dest="user",
228                          help="user name", metavar="HRN", default=None)
229         parser.add_option("-a", "--auth", dest="auth",
230                          help="authority name", metavar="HRN", default=None)
231         parser.add_option("-v", "--verbose",
232                          action="store_true", dest="verbose", default=False,
233                          help="verbose mode")
234         parser.add_option("-D", "--debug",
235                           action="store_true", dest="debug", default=False,
236                           help="Debug (xml-rpc) protocol messages")
237         parser.add_option("-p", "--protocol",
238                          dest="protocol", default="xmlrpc",
239                          help="RPC protocol (xmlrpc or soap)")
240         parser.add_option("-k", "--hashrequest",
241                          action="store_true", dest="hashrequest", default=False,
242                          help="Create a hash of the request that will be authenticated on the server")
243         parser.disable_interspersed_args()
244
245         return parser
246         
247  
248     #
249     # Establish Connection to SliceMgr and Registry Servers
250     #
251     def set_servers(self):
252        config_file = self.options.sfi_dir + os.sep + "sfi_config"
253        try:
254           config = Config (config_file)
255        except:
256           print "Failed to read configuration file", config_file
257           print "Make sure to remove the export clauses and to add quotes"
258           if not self.options.verbose:
259              print "Re-run with -v for more details"
260           else:
261              traceback.print_exc()
262           sys.exit(1)
263     
264        errors = 0
265        # Set SliceMgr URL
266        if (self.options.sm is not None):
267           sm_url = self.options.sm
268        elif hasattr(config, "SFI_SM"):
269           sm_url = config.SFI_SM
270        else:
271           print "You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file
272           errors += 1 
273     
274        # Set Registry URL
275        if (self.options.registry is not None):
276           reg_url = self.options.registry
277        elif hasattr(config, "SFI_REGISTRY"):
278           reg_url = config.SFI_REGISTRY
279        else:
280           print "You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file
281           errors += 1 
282           
283
284        if (self.options.geni_am is not None):
285            geni_am_url = self.options.geni_am
286        elif hasattr(config, "SFI_GENI_AM"):
287            geni_am_url = config.SFI_GENI_AM
288            
289        # Set user HRN
290        if (self.options.user is not None):
291           self.user = self.options.user
292        elif hasattr(config, "SFI_USER"):
293           self.user = config.SFI_USER
294        else:
295           print "You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file
296           errors += 1 
297     
298        # Set authority HRN
299        if (self.options.auth is not None):
300           self.authority = self.options.auth
301        elif hasattr(config, "SFI_AUTH"):
302           self.authority = config.SFI_AUTH
303        else:
304           print "You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file
305           errors += 1 
306     
307        if errors:
308           sys.exit(1)
309     
310        if self.options.verbose :
311           print "Contacting Slice Manager at:", sm_url
312           print "Contacting Registry at:", reg_url
313     
314        # Get key and certificate
315        key_file = self.get_key_file()
316        cert_file = self.get_cert_file(key_file)
317        self.key = Keypair(filename=key_file) 
318        self.key_file = key_file
319        self.cert_file = cert_file
320        self.cert = Certificate(filename=cert_file) 
321        # Establish connection to server(s)
322        self.registry = xmlrpcprotocol.get_server(reg_url, key_file, cert_file, self.options.debug)  
323        self.slicemgr = xmlrpcprotocol.get_server(sm_url, key_file, cert_file, self.options.debug)
324        self.geni_am = xmlrpcprotocol.get_server(geni_am_url, key_file, cert_file, self.options.debug)
325
326        return
327     
328     #
329     # Get various credential and spec files
330     #
331     # Establishes limiting conventions
332     #   - conflates MAs and SAs
333     #   - assumes last token in slice name is unique
334     #
335     # Bootstraps credentials
336     #   - bootstrap user credential from self-signed certificate
337     #   - bootstrap authority credential from user credential
338     #   - bootstrap slice credential from user credential
339     #
340     
341     
342     def get_key_file(self):
343        file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
344        #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".pkey")
345        if (os.path.isfile(file)):
346           return file
347        else:
348           print "Key file", file, "does not exist"
349           sys.exit(-1)
350        return
351     
352     def get_cert_file(self, key_file):
353     
354        #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cert")
355        file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
356        if (os.path.isfile(file)):
357           return file
358        else:
359           k = Keypair(filename=key_file)
360           cert = Certificate(subject=self.user)
361           cert.set_pubkey(k)
362           cert.set_issuer(k, self.user)
363           cert.sign()
364           if self.options.verbose :
365              print "Writing self-signed certificate to", file
366           cert.save_to_file(file)
367           return file
368    
369     def get_gid(self):
370         #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".gid")
371         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".gid")
372         if (os.path.isfile(file)):
373             gid = GID(filename=file)
374             return gid
375         else:
376             cert_str = self.cert.save_to_string(save_parents=True)
377             gid_str = self.registry.get_gid(cert_str, self.user, "user")
378             gid = GID(string=gid_str)
379             if self.options.verbose:
380                 print "Writing user gid to", file
381             gid.save_to_file(file, save_parents=True)
382             return gid       
383  
384     def get_user_cred(self):
385         #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
386         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
387         if (os.path.isfile(file)):
388             user_cred = Credential(filename=file)
389             return user_cred
390         else:
391             # bootstrap user credential
392             cert_string = self.cert.save_to_string(save_parents=True)
393             user_name = self.user.replace(self.authority + ".", '')
394             if user_name.count(".") > 0:
395                 user_name = user_name.replace(".", '_')
396                 self.user = self.authority + "." + user_name
397
398             user_cred = self.registry.get_self_credential(cert_string, "user", self.user)
399             if user_cred:
400                cred = Credential(string=user_cred)
401                cred.save_to_file(file, save_parents=True)
402                if self.options.verbose:
403                     print "Writing user credential to", file
404                return cred
405             else:
406                print "Failed to get user credential"
407                sys.exit(-1)
408   
409     def get_auth_cred(self):
410         if not self.authority:
411             print "no authority specified. Use -a or set SF_AUTH"
412             sys.exit(-1)
413     
414         file = os.path.join(self.options.sfi_dir, get_leaf("authority") + ".cred")
415         if (os.path.isfile(file)):
416             auth_cred = Credential(filename=file)
417             return auth_cred
418         else:
419             # bootstrap authority credential from user credential
420             user_cred = self.get_user_cred().save_to_string(save_parents=True)
421             auth_cred = self.registry.get_credential(user_cred, "authority", self.authority)
422             if auth_cred:
423                 cred = Credential(string=auth_cred)
424                 cred.save_to_file(file, save_parents=True)
425                 if self.options.verbose:
426                     print "Writing authority credential to", file
427                 return cred
428             else:
429                 print "Failed to get authority credential"
430                 sys.exit(-1)
431     
432     def get_slice_cred(self, name):
433         file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
434         if (os.path.isfile(file)):
435             slice_cred = Credential(filename=file)
436             return slice_cred
437         else:
438             # bootstrap slice credential from user credential
439             user_cred = self.get_user_cred().save_to_string(save_parents=True)
440             arg_list = [user_cred, "slice", name]
441             slice_cred_str = self.registry.get_credential(user_cred, "slice", name)
442             if slice_cred_str:
443                 slice_cred = Credential(string=slice_cred_str)
444                 slice_cred.save_to_file(file, save_parents=True)
445                 if self.options.verbose:
446                     print "Writing slice credential to", file
447                 return slice_cred
448             else:
449                 print "Failed to get slice credential"
450                 sys.exit(-1)
451     
452     def delegate_cred(self, cred, hrn, type='authority'):
453         # the gid and hrn of the object we are delegating
454         user_cred = Credential(string=cred)
455         object_gid = user_cred.get_gid_object()
456         object_hrn = object_gid.get_hrn()
457         #cred.set_delegate(True)
458         #if not cred.get_delegate():
459         #    raise Exception, "Error: Object credential %(object_hrn)s does not have delegate bit set" % locals()
460            
461     
462         records = self.registry.resolve(cred, hrn)
463         records = filter_records(type, records)
464         
465         if not records:
466             raise Exception, "Error: Didn't find a %(type)s record for %(hrn)s" % locals()
467     
468         # the gid of the user who will be delegated too
469         record = SfaRecord(dict=records[0])
470         delegee_gid = record.get_gid_object()
471         delegee_hrn = delegee_gid.get_hrn()
472         
473         # the key and hrn of the user who will be delegating
474         user_key = Keypair(filename=self.get_key_file())
475         user_hrn = user_cred.get_gid_caller().get_hrn()
476     
477         dcred = Credential(subject=object_hrn + " delegated to " + delegee_hrn)
478         dcred.set_gid_caller(delegee_gid)
479         dcred.set_gid_object(object_gid)
480         dcred.set_privileges(user_cred.get_privileges())
481         dcred.get_privileges().delegate_all_privileges(True)
482         
483
484         # Save the issuer's gid to a file
485         fname = self.options.sfi_dir + os.sep + "gid_%d" % random.randint(0, 999999999)
486         f = open(fname, "w")
487         f.write(user_cred.get_gid_caller().save_to_string())
488         f.close()
489         dcred.set_issuer_keys(self.get_key_file(), fname)
490         os.remove(fname)
491         
492         dcred.set_parent(user_cred)
493         dcred.encode()
494         dcred.sign()
495     
496         return dcred.save_to_string(save_parents=True)
497     
498     def get_rspec_file(self, rspec):
499        if (os.path.isabs(rspec)):
500           file = rspec
501        else:
502           file = os.path.join(self.options.sfi_dir, rspec)
503        if (os.path.isfile(file)):
504           return file
505        else:
506           print "No such rspec file", rspec
507           sys.exit(1)
508     
509     def get_record_file(self, record):
510        if (os.path.isabs(record)):
511           file = record
512        else:
513           file = os.path.join(self.options.sfi_dir, record)
514        if (os.path.isfile(file)):
515           return file
516        else:
517           print "No such registry record file", record
518           sys.exit(1)
519     
520     def load_publickey_string(self, fn):
521        f = file(fn, "r")
522        key_string = f.read()
523     
524        # if the filename is a private key file, then extract the public key
525        if "PRIVATE KEY" in key_string:
526            outfn = tempfile.mktemp()
527            cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
528            os.system(cmd)
529            f = file(outfn, "r")
530            key_string = f.read()
531            os.remove(outfn)
532     
533        return key_string
534
535     def get_component_server_from_hrn(self, hrn):
536         # direct connection to the nodes component manager interface
537         user_cred = self.get_user_cred().save_to_string(save_parents=True)
538         records = self.registry.resolve(user_cred, hrn)
539         records = filter_records('node', records)
540         if not records:
541             print "No such component:", opts.component
542         record = records[0]
543   
544         return self.get_server(record['hostname'], CM_PORT, self.key_file, \
545                                self.cert_file, self.options.debug)
546  
547     def get_server(self, host, port, keyfile, certfile, debug):
548         """
549         Return an instnace of an xmlrpc server connection    
550         """
551         url = "http://%s:%s" % (host, port)
552         return xmlrpcprotocol.get_server(url, keyfile, certfile, debug)
553  
554     #==========================================================================
555     # Following functions implement the commands
556     #
557     # Registry-related commands
558     #==========================================================================
559   
560     def dispatch(self, command, cmd_opts, cmd_args):
561         getattr(self, command)(cmd_opts, cmd_args)
562  
563     def gid(self, opts, args):
564         gid = self.get_gid()
565         print "GID: %s" % (gid.save_to_string(save_parents=True))
566         return   
567  
568     # list entires in named authority registry
569     def list(self, opts, args):
570         user_cred = self.get_user_cred().save_to_string(save_parents=True)
571         hrn = args[0]
572         try:
573             list = self.registry.list(user_cred, hrn)
574         except IndexError:
575             raise Exception, "Not enough parameters for the 'list' command"
576           
577         # filter on person, slice, site, node, etc.  
578         # THis really should be in the self.filter_records funct def comment...
579         list = filter_records(opts.type, list)
580         for record in list:
581             print "%s (%s)" % (record['hrn'], record['type'])     
582         if opts.file:
583             file = opts.file
584             if not file.startswith(os.sep):
585                 file = os.path.join(self.options.sfi_dir, file)
586             save_records_to_file(file, list)
587         return
588     
589     # show named registry record
590     def show(self, opts, args):
591         user_cred = self.get_user_cred().save_to_string(save_parents=True)
592         hrn = args[0]
593         records = self.registry.resolve(user_cred, hrn)
594         records = filter_records(opts.type, records)
595         if not records:
596             print "No record of type", opts.type
597         for record in records:
598             if record['type'] in ['user']:
599                 record = UserRecord(dict=record)
600             elif record['type'] in ['slice']:
601                 record = SliceRecord(dict=record)
602             elif record['type'] in ['node']:
603                 record = NodeRecord(dict=record)
604             elif record['type'] in ['authority', 'ma', 'sa']:
605                 record = AuthorityRecord(dict=record)
606             else:
607                 record = SfaRecord(dict=record)
608             if (opts.format == "text"): 
609                 record.dump()  
610             else:
611                 print record.save_to_string() 
612        
613         if opts.file:
614             file = opts.file
615             if not file.startswith(os.sep):
616                 file = os.path.join(self.options.sfi_dir, file)
617             save_records_to_file(file, records)
618         return
619     
620     def delegate(self, opts, args):
621        user_cred = self.get_user_cred()
622        if opts.delegate_user:
623            object_cred = user_cred
624        elif opts.delegate_slice:
625            object_cred = self.get_slice_cred(opts.delegate_slice)
626        else:
627            print "Must specify either --user or --slice <hrn>"
628            return
629     
630        # the gid and hrn of the object we are delegating
631        object_gid = object_cred.get_gid_object()
632        object_hrn = object_gid.get_hrn()
633     
634        if not object_cred.get_privileges().get_all_delegate():
635            print "Error: Object credential", object_hrn, "does not have delegate bit set"
636            return
637     
638        records = self.registry.resolve(user_cred.save_to_string(save_parents=True), args[0])
639        records = filter_records("user", records)
640     
641        if not records:
642            print "Error: Didn't find a user record for", args[0]
643            return
644     
645        # the gid of the user who will be delegated to
646        delegee_gid = GID(string=records[0]['gid'])
647        delegee_hrn = delegee_gid.get_hrn()
648    
649        # the key and hrn of the user who will be delegating
650        user_key = Keypair(filename=self.get_key_file())
651        user_hrn = user_cred.get_gid_caller().get_hrn()
652        subject_string = "%s delegated to %s" % (object_hrn, delegee_hrn)
653        dcred = Credential(subject=subject_string)
654        dcred.set_gid_caller(delegee_gid)
655        dcred.set_gid_object(object_gid)
656        privs = object_cred.get_privileges()
657        dcred.set_privileges(object_cred.get_privileges())
658        dcred.get_privileges().delegate_all_privileges(True)
659        dcred.set_pubkey(object_gid.get_pubkey())
660        dcred.set_issuer(user_key, user_hrn)
661        dcred.set_parent(object_cred)
662        dcred.encode()
663        dcred.sign()
664     
665        if opts.delegate_user:
666            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_" 
667                                   + get_leaf(object_hrn) + ".cred")
668        elif opts.delegate_slice:
669            dest_fn = os.path_join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_" 
670                                   + get_leaf(object_hrn) + ".cred")
671     
672        dcred.save_to_file(dest_fn, save_parents=True)
673     
674        print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
675     
676     # removed named registry record
677     #   - have to first retrieve the record to be removed
678     def remove(self, opts, args):
679         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
680         hrn = args[0]
681         type = opts.type 
682         if type in ['all']:
683             type = '*'
684         return self.registry.remove(auth_cred, type, hrn)
685     
686     # add named registry record
687     def add(self, opts, args):
688         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
689         record_filepath = args[0]
690         rec_file = self.get_record_file(record_filepath)
691         record = load_record_from_file(rec_file).as_dict()
692         return self.registry.register(auth_cred, record)
693     
694     # update named registry entry
695     def update(self, opts, args):
696         user_cred = self.get_user_cred()
697         rec_file = self.get_record_file(args[0])
698         record = load_record_from_file(rec_file)
699         if record['type'] == "user":
700             if record.get_name() == user_cred.get_gid_object().get_hrn():
701                 cred = user_cred.save_to_string(save_parents=True)
702             else:
703                 cred = self.get_auth_cred().save_to_string(save_parents=True)
704         elif record['type'] in ["slice"]:
705             try:
706                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
707             except ServerException, e:
708                # XXX smbaker -- once we have better error return codes, update this
709                # to do something better than a string compare
710                if "Permission error" in e.args[0]:
711                    cred = self.get_auth_cred().save_to_string(save_parents=True)
712                else:
713                    raise
714         elif record.get_type() in ["authority"]:
715             cred = self.get_auth_cred().save_to_string(save_parents=True)
716         elif record.get_type() == 'node':
717             cred = self.get_auth_cred().save_to_string(save_parents=True)
718         else:
719             raise "unknown record type" + record.get_type()
720         record = record.as_dict()
721         return self.registry.update(cred, record)
722   
723     def get_trusted_certs(self, opts, args):
724         """
725         return the trusted certs at this interface 
726         """ 
727         trusted_certs = self.registry.get_trusted_certs()
728         for trusted_cert in trusted_certs:
729             cert = Certificate(string=trusted_cert)
730             print cert.get_subject()
731         return 
732
733     def aggregates(self, opts, args):
734         """
735         return a list of details about known aggregates
736         """
737         user_cred = self.get_user_cred().save_to_string(save_parents=True)
738         hrn = None
739         if args:
740             hrn = args[0]
741
742         result = self.registry.get_aggregates(user_cred, hrn)
743         display_list(result)
744         return 
745
746     def get_geni_aggregates(self, opts, args):
747         """
748         return a list of details about known aggregates
749         """
750         user_cred = self.get_user_cred().save_to_string(save_parents=True)
751         hrn = None
752         if args:
753             hrn = args[0]
754
755         result = self.registry.get_geni_aggregates(user_cred, hrn)
756         display_list(result)
757         return 
758
759
760     def registries(self, opts, args):
761         """
762         return a list of details about known registries
763         """
764         user_cred = self.get_user_cred().save_to_string(save_parents=True)
765         hrn = None
766         if args:
767             hrn = args[0]
768         result = self.registry.get_registries(user_cred, hrn)
769         display_list(result)
770         return
771
772  
773     # ==================================================================
774     # Slice-related commands
775     # ==================================================================
776     
777
778     # list instantiated slices
779     def slices(self, opts, args):
780         """
781         list instantiated slices
782         """
783         user_cred = self.get_user_cred().save_to_string(save_parents=True)
784         server = self.slicemgr
785         if opts.aggregate:
786             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
787                                      self.cert_file, self.options.debug)
788         # direct connection to the nodes component manager interface
789         if opts.component:
790             server = self.get_component_server_from_hrn(opts.component)
791         results = server.get_slices(user_cred)
792         display_list(results)
793         return
794     
795     # show rspec for named slice
796     def resources(self, opts, args):
797         user_cred = self.get_user_cred().save_to_string(save_parents=True)
798         server = self.slicemgr
799         if opts.aggregate:
800             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
801                                      self.cert_file, self.options.debug)
802         if args:
803             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
804             hrn = args[0]
805         else:
806             cred = user_cred
807             hrn = None
808
809         result = server.get_resources(cred, hrn)
810         format = opts.format
811        
812         display_rspec(result, format)
813         if (opts.file is not None):
814             file = opts.file
815             if not file.startswith(os.sep):
816                 file = os.path.join(self.options.sfi_dir, file)
817             save_rspec_to_file(result, file)
818         return
819     
820     # created named slice with given rspec
821     def create(self, opts, args):
822         slice_hrn = args[0]
823         user_cred = self.get_user_cred()
824         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
825         rspec_file = self.get_rspec_file(args[1])
826         rspec = open(rspec_file).read()
827         server = self.slicemgr
828
829         if opts.aggregate:
830             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
831                                      self.cert_file, self.options.debug)
832
833         return server.create_slice(slice_cred, slice_hrn, rspec)
834
835     # get a ticket for the specified slice
836     def get_ticket(self, opts, args):
837         slice_hrn, rspec_path = args[0], args[1]
838         user_cred = self.get_user_cred()
839         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
840         rspec_file = self.get_rspec_file(rspec_path) 
841         rspec = open(rspec_file).read()
842         server = self.slicemgr
843         if opts.aggregate:
844             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
845                                      self.cert_file, self.options.debug)
846         ticket_string = server.get_ticket(slice_cred, slice_hrn, rspec)
847         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
848         print "writing ticket to ", file        
849         ticket = SfaTicket(string=ticket_string)
850         ticket.save_to_file(filename=file, save_parents=True)
851
852     def redeem_ticket(self, opts, args):
853         ticket_file = args[0]
854         
855         # get slice hrn from the ticket
856         # use this to get the right slice credential 
857         ticket = SfaTicket(filename=ticket_file)
858         ticket.decode()
859         slice_hrn = ticket.gidObject.get_hrn()
860         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
861         user_cred = self.get_user_cred()
862         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
863         
864         # get a list of node hostnames from the RSpec 
865         tree = etree.parse(StringIO(ticket.rspec))
866         root = tree.getroot()
867         hostnames = root.xpath("./network/site/node/hostname/text()")
868         
869         # create an xmlrpc connection to the component manager at each of these
870         # components and gall redeem_ticket
871         connections = {}
872         for hostname in hostnames:
873             try:
874                 print "Calling redeem_ticket at %(hostname)s " % locals(),
875                 server = self.get_server(hostname, CM_PORT, self.key_file, \
876                                          self.cert_file, self.options.debug)
877                 server.redeem_ticket(slice_cred, ticket.save_to_string(save_parents=True))
878                 print "Success"
879             except socket.gaierror:
880                 print "Failed:",
881                 print "Componet Manager not accepting requests" 
882             except Exception, e:
883                 print "Failed:", e.message
884         return
885  
886     # delete named slice
887     def delete(self, opts, args):
888         slice_hrn = args[0]
889         server = self.slicemgr
890         if opts.aggregate:
891             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
892                                      self.cert_file, self.options.debug)
893         # direct connection to the nodes component manager interface
894         if opts.component:
895             server = self.get_component_server_from_hrn(opts.component)
896         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
897         return server.delete_slice(slice_cred, slice_hrn)
898     
899     # start named slice
900     def start(self, opts, args):
901         slice_hrn = args[0]
902         server = self.slicemgr
903         # direct connection to an aggregagte
904         if opts.aggregate:
905             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
906                                      self.cert_file, self.options.debug)
907         if opts.component:
908             server = self.get_component_server_from_hrn(opts.component)
909         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
910         return server.start_slice(slice_cred, slice_hrn)
911     
912     # stop named slice
913     def stop(self, opts, args):
914         slice_hrn = args[0]
915         server = self.slicemgr
916         # direct connection to an aggregate
917         if opts.aggregate:
918             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
919                                      self.cert_file, self.options.debug)
920         # direct connection to the nodes component manager interface
921         if opts.component:
922             server = self.get_component_server_from_hrn(opts.component)
923         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
924         return server.stop_slice(slice_cred, slice_hrn)
925     
926     # reset named slice
927     def reset(self, opts, args):
928         slice_hrn = args[0]
929         server = self.slicemgr
930         # direct connection to the nodes component manager interface
931         if opts.component:
932             server = self.get_component_server_from_hrn(opts.component)
933         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
934         return server.reset_slice(slice_cred, slice_hrn)
935
936
937     # =====================================================================
938     # GENI AM related calls
939     # =====================================================================
940
941     def GetVersion(self, opts, args):
942         server = self.geni_am
943         print server.GetVersion()
944
945     def ListResources(self, opts, args):
946         user_cred = self.get_user_cred().save_to_string(save_parents=True)
947         server = self.geni_am
948         call_options = {'geni_compressed': True}
949         xrn = None
950         cred = user_cred
951         if args:
952             xrn = args[0]
953             cred = self.get_slice_cred(xrn).save_to_string(save_parents=True)
954
955         if xrn:
956             call_options['geni_slice_urn'] = xrn
957             
958         rspec = server.ListResources([cred], call_options)
959         rspec = zlib.decompress(rspec.decode('base64'))
960         print rspec
961         
962     def CreateSliver(self, opts, args):
963         slice_xrn = args[0]
964         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
965         rspec_file = self.get_rspec_file(args[1])
966         rspec = open(rspec_file).read()
967         server = self.geni_am
968         return server.CreateSliver(slice_xrn, [slice_cred], rspec, [])
969     
970     def DeleteSliver(self, opts, args):
971         slice_xrn = args[0]
972         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
973         server = self.geni_am
974         return server.DeleteSliver(slice_xrn, [slice_cred])    
975
976     def SliverStatus(self, opts, args):
977         slice_xrn = args[0]
978         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
979         server = self.geni_am
980         print server.SliverStatus(slice_xrn, [slice_cred])
981     
982     def RenewSliver(self, opts, args):
983         slice_xrn = args[0]
984         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
985         time = args[1]
986         server = self.geni_am
987         return server.RenewSliver(slice_xrn, [slice_cred], time)   
988
989     def Shutdown(self, opts, args):
990         slice_xrn = args[0]
991         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
992         server = self.geni_am
993         return server.Shutdown(slice_xrn, [slice_cred])         
994     
995     #
996     # Main: parse arguments and dispatch to command
997     #
998     def main(self):
999         parser = self.create_parser()
1000         (options, args) = parser.parse_args()
1001         self.options = options
1002    
1003         if options.hashrequest:
1004             self.hashrequest = True
1005  
1006         if len(args) <= 0:
1007             print "No command given. Use -h for help."
1008             return - 1
1009     
1010         command = args[0]
1011         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
1012         if self.options.verbose :
1013             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
1014                                                                    options.sfi_dir, options.user,
1015                                                                    options.auth)
1016             print "Command %s" % command
1017             if command in ("resources"):
1018                 print "resources cmd_opts %s" % cmd_opts.format
1019             elif command in ("list", "show", "remove"):
1020                 print "cmd_opts.type %s" % cmd_opts.type
1021             print "cmd_args %s" % cmd_args
1022     
1023         self.set_servers()
1024     
1025         try:
1026             self.dispatch(command, cmd_opts, cmd_args)
1027         except KeyError:
1028             raise 
1029             print "Command not found:", command
1030             sys.exit(1)
1031     
1032         return
1033     
1034 if __name__ == "__main__":
1035    Sfi().main()