whitespace
[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 import datetime
13 from lxml import etree
14 from StringIO import StringIO
15 from types import StringTypes, ListType
16 from optparse import OptionParser
17 from sfa.trust.certificate import Keypair, Certificate
18 from sfa.trust.credential import Credential
19 from sfa.util.sfaticket import SfaTicket
20 from sfa.util.record import *
21 from sfa.util.namespace import *
22 from sfa.util.xmlrpcprotocol import ServerException
23 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
24 from sfa.util.config import Config
25 import zlib
26
27 AGGREGATE_PORT=12346
28 CM_PORT=12346
29
30 # utility methods here
31 # display methods
32 def display_rspec(rspec, format='rspec'):
33     if format in ['dns']:
34         tree = etree.parse(StringIO(rspec))
35         root = tree.getroot()
36         result = root.xpath("./network/site/node/hostname/text()")
37     elif format in ['ip']:
38         # The IP address is not yet part of the new RSpec
39         # so this doesn't do anything yet.
40         tree = etree.parse(StringIO(rspec))
41         root = tree.getroot()
42         result = root.xpath("./network/site/node/ipv4/text()")
43     else:
44         result = rspec
45
46     print result
47     return
48
49 def display_list(results):
50     for result in results:
51         print result
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_cached_credential(self, file):
385         """
386         Return a cached credential only if it hasn't expired.
387         """
388         if (os.path.isfile(file)):
389             credential = Credential(filename=file)
390             # make sure it isnt expired 
391             if not credential.get_lifetime or \
392                datetime.datetime.today() < credential.get_lifetime():
393                 return credential
394         return None 
395  
396     def get_user_cred(self):
397         #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
398         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
399         return self.get_cred(file, 'user', self.user)
400
401     def get_auth_cred(self):
402         if not self.authority:
403             print "no authority specified. Use -a or set SF_AUTH"
404             sys.exit(-1)
405         file = os.path.join(self.options.sfi_dir, get_leaf("authority") + ".cred")
406         return self.get_cred(file, 'authority', name)
407
408     def get_slice_cred(self, name):
409         file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
410         return self.get_cred(file, 'slice', name)
411  
412     def get_cred(self, file, type, hrn):
413         # attempt to load a cached credential 
414         cred = self.get_cached_credential(file)    
415         if not cred:
416             if type in ['user']:
417                 cert_string = self.cert.save_to_string(save_parents=True)
418                 user_name = self.user.replace(self.authority + ".", '')
419                 if user_name.count(".") > 0:
420                     user_name = user_name.replace(".", '_')
421                     self.user = self.authority + "." + user_name
422                 cred_str = self.registry.get_self_credential(cert_string, "user", hrn)
423             else:
424                 # bootstrap slice credential from user credential
425                 user_cred = self.get_user_cred().save_to_string(save_parents=True)
426                 cred_str = self.registry.get_credential(user_cred, type, hrn)
427             
428             if not cred_str:
429                 print "Failed to get %s credential" % (type)
430                 sys.exit(-1)
431                 
432             cred = Credential(string=cred_str)
433             cred.save_to_file(file, save_parents=True)
434             if self.options.verbose:
435                 print "Writing %s credential to %s" %(type, file)
436
437         return cred
438  
439     def delegate_cred(self, cred, hrn, type='authority'):
440         # the gid and hrn of the object we are delegating
441         user_cred = Credential(string=cred)
442         object_gid = user_cred.get_gid_object()
443         object_hrn = object_gid.get_hrn()
444         #cred.set_delegate(True)
445         #if not cred.get_delegate():
446         #    raise Exception, "Error: Object credential %(object_hrn)s does not have delegate bit set" % locals()
447            
448     
449         records = self.registry.resolve(cred, hrn)
450         records = filter_records(type, records)
451         
452         if not records:
453             raise Exception, "Error: Didn't find a %(type)s record for %(hrn)s" % locals()
454     
455         # the gid of the user who will be delegated too
456         record = SfaRecord(dict=records[0])
457         delegee_gid = record.get_gid_object()
458         delegee_hrn = delegee_gid.get_hrn()
459         
460         # the key and hrn of the user who will be delegating
461         user_key = Keypair(filename=self.get_key_file())
462         user_hrn = user_cred.get_gid_caller().get_hrn()
463     
464         dcred = Credential(subject=object_hrn + " delegated to " + delegee_hrn)
465         dcred.set_gid_caller(delegee_gid)
466         dcred.set_gid_object(object_gid)
467         dcred.set_privileges(user_cred.get_privileges())
468         dcred.get_privileges().delegate_all_privileges(True)
469         
470
471         # Save the issuer's gid to a file
472         fname = self.options.sfi_dir + os.sep + "gid_%d" % random.randint(0, 999999999)
473         f = open(fname, "w")
474         f.write(user_cred.get_gid_caller().save_to_string())
475         f.close()
476         dcred.set_issuer_keys(self.get_key_file(), fname)
477         os.remove(fname)
478         
479         dcred.set_parent(user_cred)
480         dcred.encode()
481         dcred.sign()
482     
483         return dcred.save_to_string(save_parents=True)
484     
485     def get_rspec_file(self, rspec):
486        if (os.path.isabs(rspec)):
487           file = rspec
488        else:
489           file = os.path.join(self.options.sfi_dir, rspec)
490        if (os.path.isfile(file)):
491           return file
492        else:
493           print "No such rspec file", rspec
494           sys.exit(1)
495     
496     def get_record_file(self, record):
497        if (os.path.isabs(record)):
498           file = record
499        else:
500           file = os.path.join(self.options.sfi_dir, record)
501        if (os.path.isfile(file)):
502           return file
503        else:
504           print "No such registry record file", record
505           sys.exit(1)
506     
507     def load_publickey_string(self, fn):
508        f = file(fn, "r")
509        key_string = f.read()
510     
511        # if the filename is a private key file, then extract the public key
512        if "PRIVATE KEY" in key_string:
513            outfn = tempfile.mktemp()
514            cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
515            os.system(cmd)
516            f = file(outfn, "r")
517            key_string = f.read()
518            os.remove(outfn)
519     
520        return key_string
521
522     def get_component_server_from_hrn(self, hrn):
523         # direct connection to the nodes component manager interface
524         user_cred = self.get_user_cred().save_to_string(save_parents=True)
525         records = self.registry.resolve(user_cred, hrn)
526         records = filter_records('node', records)
527         if not records:
528             print "No such component:", opts.component
529         record = records[0]
530   
531         return self.get_server(record['hostname'], CM_PORT, self.key_file, \
532                                self.cert_file, self.options.debug)
533  
534     def get_server(self, host, port, keyfile, certfile, debug):
535         """
536         Return an instnace of an xmlrpc server connection    
537         """
538         url = "http://%s:%s" % (host, port)
539         return xmlrpcprotocol.get_server(url, keyfile, certfile, debug)
540
541     def get_server_from_opts(self, opts):
542         """
543         Return instance of an xmlrpc connection to a slice manager, aggregate
544         or component server depending on the specified opts
545         """
546         server = self.slicemgr
547         # direct connection to an aggregate
548         if opts.aggregate:
549             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
550                                      self.cert_file, self.options.debug)
551         # direct connection to the nodes component manager interface
552         if opts.component:
553             server = self.get_component_server_from_hrn(opts.component)    
554  
555         return server
556     #==========================================================================
557     # Following functions implement the commands
558     #
559     # Registry-related commands
560     #==========================================================================
561   
562     def dispatch(self, command, cmd_opts, cmd_args):
563         getattr(self, command)(cmd_opts, cmd_args)
564  
565     def gid(self, opts, args):
566         gid = self.get_gid()
567         print "GID: %s" % (gid.save_to_string(save_parents=True))
568         return   
569  
570     # list entires in named authority registry
571     def list(self, opts, args):
572         user_cred = self.get_user_cred().save_to_string(save_parents=True)
573         hrn = args[0]
574         try:
575             list = self.registry.list(user_cred, hrn)
576         except IndexError:
577             raise Exception, "Not enough parameters for the 'list' command"
578           
579         # filter on person, slice, site, node, etc.  
580         # THis really should be in the self.filter_records funct def comment...
581         list = filter_records(opts.type, list)
582         for record in list:
583             print "%s (%s)" % (record['hrn'], record['type'])     
584         if opts.file:
585             file = opts.file
586             if not file.startswith(os.sep):
587                 file = os.path.join(self.options.sfi_dir, file)
588             save_records_to_file(file, list)
589         return
590     
591     # show named registry record
592     def show(self, opts, args):
593         user_cred = self.get_user_cred().save_to_string(save_parents=True)
594         hrn = args[0]
595         records = self.registry.resolve(user_cred, hrn)
596         records = filter_records(opts.type, records)
597         if not records:
598             print "No record of type", opts.type
599         for record in records:
600             if record['type'] in ['user']:
601                 record = UserRecord(dict=record)
602             elif record['type'] in ['slice']:
603                 record = SliceRecord(dict=record)
604             elif record['type'] in ['node']:
605                 record = NodeRecord(dict=record)
606             elif record['type'] in ['authority', 'ma', 'sa']:
607                 record = AuthorityRecord(dict=record)
608             else:
609                 record = SfaRecord(dict=record)
610             if (opts.format == "text"): 
611                 record.dump()  
612             else:
613                 print record.save_to_string() 
614        
615         if opts.file:
616             file = opts.file
617             if not file.startswith(os.sep):
618                 file = os.path.join(self.options.sfi_dir, file)
619             save_records_to_file(file, records)
620         return
621     
622     def delegate(self, opts, args):
623        user_cred = self.get_user_cred()
624        if opts.delegate_user:
625            object_cred = user_cred
626        elif opts.delegate_slice:
627            object_cred = self.get_slice_cred(opts.delegate_slice)
628        else:
629            print "Must specify either --user or --slice <hrn>"
630            return
631     
632        # the gid and hrn of the object we are delegating
633        object_gid = object_cred.get_gid_object()
634        object_hrn = object_gid.get_hrn()
635     
636        if not object_cred.get_privileges().get_all_delegate():
637            print "Error: Object credential", object_hrn, "does not have delegate bit set"
638            return
639     
640        records = self.registry.resolve(user_cred.save_to_string(save_parents=True), args[0])
641        records = filter_records("user", records)
642     
643        if not records:
644            print "Error: Didn't find a user record for", args[0]
645            return
646     
647        # the gid of the user who will be delegated to
648        delegee_gid = GID(string=records[0]['gid'])
649        delegee_hrn = delegee_gid.get_hrn()
650    
651        # the key and hrn of the user who will be delegating
652        user_key = Keypair(filename=self.get_key_file())
653        user_hrn = user_cred.get_gid_caller().get_hrn()
654        subject_string = "%s delegated to %s" % (object_hrn, delegee_hrn)
655        dcred = Credential(subject=subject_string)
656        dcred.set_gid_caller(delegee_gid)
657        dcred.set_gid_object(object_gid)
658        privs = object_cred.get_privileges()
659        dcred.set_privileges(object_cred.get_privileges())
660        dcred.get_privileges().delegate_all_privileges(True)
661        dcred.set_pubkey(object_gid.get_pubkey())
662        dcred.set_issuer(user_key, user_hrn)
663        dcred.set_parent(object_cred)
664        dcred.encode()
665        dcred.sign()
666     
667        if opts.delegate_user:
668            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_" 
669                                   + get_leaf(object_hrn) + ".cred")
670        elif opts.delegate_slice:
671            dest_fn = os.path_join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_" 
672                                   + get_leaf(object_hrn) + ".cred")
673     
674        dcred.save_to_file(dest_fn, save_parents=True)
675     
676        print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
677     
678     # removed named registry record
679     #   - have to first retrieve the record to be removed
680     def remove(self, opts, args):
681         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
682         hrn = args[0]
683         type = opts.type 
684         if type in ['all']:
685             type = '*'
686         return self.registry.remove(auth_cred, type, hrn)
687     
688     # add named registry record
689     def add(self, opts, args):
690         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
691         record_filepath = args[0]
692         rec_file = self.get_record_file(record_filepath)
693         record = load_record_from_file(rec_file).as_dict()
694         return self.registry.register(auth_cred, record)
695     
696     # update named registry entry
697     def update(self, opts, args):
698         user_cred = self.get_user_cred()
699         rec_file = self.get_record_file(args[0])
700         record = load_record_from_file(rec_file)
701         if record['type'] == "user":
702             if record.get_name() == user_cred.get_gid_object().get_hrn():
703                 cred = user_cred.save_to_string(save_parents=True)
704             else:
705                 cred = self.get_auth_cred().save_to_string(save_parents=True)
706         elif record['type'] in ["slice"]:
707             try:
708                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
709             except ServerException, e:
710                # XXX smbaker -- once we have better error return codes, update this
711                # to do something better than a string compare
712                if "Permission error" in e.args[0]:
713                    cred = self.get_auth_cred().save_to_string(save_parents=True)
714                else:
715                    raise
716         elif record.get_type() in ["authority"]:
717             cred = self.get_auth_cred().save_to_string(save_parents=True)
718         elif record.get_type() == 'node':
719             cred = self.get_auth_cred().save_to_string(save_parents=True)
720         else:
721             raise "unknown record type" + record.get_type()
722         record = record.as_dict()
723         return self.registry.update(cred, record)
724   
725     def get_trusted_certs(self, opts, args):
726         """
727         return the trusted certs at this interface 
728         """ 
729         trusted_certs = self.registry.get_trusted_certs()
730         for trusted_cert in trusted_certs:
731             cert = Certificate(string=trusted_cert)
732             print cert.get_subject()
733         return 
734
735     def aggregates(self, opts, args):
736         """
737         return a list of details about known aggregates
738         """
739         user_cred = self.get_user_cred().save_to_string(save_parents=True)
740         hrn = None
741         if args:
742             hrn = args[0]
743
744         result = self.registry.get_aggregates(user_cred, hrn)
745         display_list(result)
746         return 
747
748     def get_geni_aggregates(self, opts, args):
749         """
750         return a list of details about known aggregates
751         """
752         user_cred = self.get_user_cred().save_to_string(save_parents=True)
753         hrn = None
754         if args:
755             hrn = args[0]
756
757         result = self.registry.get_geni_aggregates(user_cred, hrn)
758         display_list(result)
759         return 
760
761
762     def registries(self, opts, args):
763         """
764         return a list of details about known registries
765         """
766         user_cred = self.get_user_cred().save_to_string(save_parents=True)
767         hrn = None
768         if args:
769             hrn = args[0]
770         result = self.registry.get_registries(user_cred, hrn)
771         display_list(result)
772         return
773
774  
775     # ==================================================================
776     # Slice-related commands
777     # ==================================================================
778     
779
780     # list instantiated slices
781     def slices(self, opts, args):
782         """
783         list instantiated slices
784         """
785         user_cred = self.get_user_cred().save_to_string(save_parents=True)
786         server = self.slicemgr
787         if opts.aggregate:
788             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
789                                      self.cert_file, self.options.debug)
790         # direct connection to the nodes component manager interface
791         if opts.component:
792             server = self.get_component_server_from_hrn(opts.component)
793         results = server.get_slices(user_cred)
794         display_list(results)
795         return
796     
797     # show rspec for named slice
798     def resources(self, opts, args):
799         user_cred = self.get_user_cred().save_to_string(save_parents=True)
800         server = self.slicemgr
801         if opts.aggregate:
802             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
803                                      self.cert_file, self.options.debug)
804         if args:
805             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
806             hrn = args[0]
807         else:
808             cred = user_cred
809             hrn = None
810
811         result = server.get_resources(cred, hrn)
812         format = opts.format
813        
814         display_rspec(result, format)
815         if (opts.file is not None):
816             file = opts.file
817             if not file.startswith(os.sep):
818                 file = os.path.join(self.options.sfi_dir, file)
819             save_rspec_to_file(result, file)
820         return
821     
822     # created named slice with given rspec
823     def create(self, opts, args):
824         slice_hrn = args[0]
825         user_cred = self.get_user_cred()
826         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
827         rspec_file = self.get_rspec_file(args[1])
828         rspec = open(rspec_file).read()
829         server = self.slicemgr
830
831         if opts.aggregate:
832             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
833                                      self.cert_file, self.options.debug)
834
835         return server.create_slice(slice_cred, slice_hrn, rspec)
836
837     # get a ticket for the specified slice
838     def get_ticket(self, opts, args):
839         slice_hrn, rspec_path = args[0], args[1]
840         user_cred = self.get_user_cred()
841         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
842         rspec_file = self.get_rspec_file(rspec_path) 
843         rspec = open(rspec_file).read()
844         server = self.slicemgr
845         if opts.aggregate:
846             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
847                                      self.cert_file, self.options.debug)
848         ticket_string = server.get_ticket(slice_cred, slice_hrn, rspec)
849         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
850         print "writing ticket to ", file        
851         ticket = SfaTicket(string=ticket_string)
852         ticket.save_to_file(filename=file, save_parents=True)
853
854     def redeem_ticket(self, opts, args):
855         ticket_file = args[0]
856         
857         # get slice hrn from the ticket
858         # use this to get the right slice credential 
859         ticket = SfaTicket(filename=ticket_file)
860         ticket.decode()
861         slice_hrn = ticket.gidObject.get_hrn()
862         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
863         user_cred = self.get_user_cred()
864         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
865         
866         # get a list of node hostnames from the RSpec 
867         tree = etree.parse(StringIO(ticket.rspec))
868         root = tree.getroot()
869         hostnames = root.xpath("./network/site/node/hostname/text()")
870         
871         # create an xmlrpc connection to the component manager at each of these
872         # components and gall redeem_ticket
873         connections = {}
874         for hostname in hostnames:
875             try:
876                 print "Calling redeem_ticket at %(hostname)s " % locals(),
877                 server = self.get_server(hostname, CM_PORT, self.key_file, \
878                                          self.cert_file, self.options.debug)
879                 server.redeem_ticket(slice_cred, ticket.save_to_string(save_parents=True))
880                 print "Success"
881             except socket.gaierror:
882                 print "Failed:",
883                 print "Componet Manager not accepting requests" 
884             except Exception, e:
885                 print "Failed:", e.message
886         return
887  
888     # delete named slice
889     def delete(self, opts, args):
890         slice_hrn = args[0]
891         server = self.slicemgr
892         if opts.aggregate:
893             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
894                                      self.cert_file, self.options.debug)
895         # direct connection to the nodes component manager interface
896         if opts.component:
897             server = self.get_component_server_from_hrn(opts.component)
898         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
899         return server.delete_slice(slice_cred, slice_hrn)
900     
901     # start named slice
902     def start(self, opts, args):
903         slice_hrn = args[0]
904         server = self.slicemgr
905         # direct connection to an aggregagte
906         if opts.aggregate:
907             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
908                                      self.cert_file, self.options.debug)
909         if opts.component:
910             server = self.get_component_server_from_hrn(opts.component)
911         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
912         return server.start_slice(slice_cred, slice_hrn)
913     
914     # stop named slice
915     def stop(self, opts, args):
916         slice_hrn = args[0]
917         server = self.slicemgr
918         # direct connection to an aggregate
919         if opts.aggregate:
920             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
921                                      self.cert_file, self.options.debug)
922         # direct connection to the nodes component manager interface
923         if opts.component:
924             server = self.get_component_server_from_hrn(opts.component)
925         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
926         return server.stop_slice(slice_cred, slice_hrn)
927     
928     # reset named slice
929     def reset(self, opts, args):
930         slice_hrn = args[0]
931         server = self.slicemgr
932         # direct connection to the nodes component manager interface
933         if opts.component:
934             server = self.get_component_server_from_hrn(opts.component)
935         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
936         return server.reset_slice(slice_cred, slice_hrn)
937
938
939     # =====================================================================
940     # GENI AM related calls
941     # =====================================================================
942
943     def GetVersion(self, opts, args):
944         server = self.geni_am
945         #server = self.get_server_from_opts(opts)
946         print server.GetVersion()
947
948     def ListResources(self, opts, args):
949         user_cred = self.get_user_cred().save_to_string(save_parents=True)
950         server = self.geni_am
951         call_options = {'geni_compressed': True}
952         xrn = None
953         cred = user_cred
954         if args:
955             xrn = args[0]
956             cred = self.get_slice_cred(xrn).save_to_string(save_parents=True)
957
958         if xrn:
959             call_options['geni_slice_urn'] = xrn
960             
961         rspec = server.ListResources([cred], call_options)
962         rspec = zlib.decompress(rspec.decode('base64'))
963         print rspec
964         
965     def CreateSliver(self, opts, args):
966         slice_xrn = args[0]
967         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
968         rspec_file = self.get_rspec_file(args[1])
969         rspec = open(rspec_file).read()
970         server = self.geni_am
971         return server.CreateSliver(slice_xrn, [slice_cred], rspec, [])
972     
973     def DeleteSliver(self, opts, args):
974         slice_xrn = args[0]
975         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
976         server = self.geni_am
977         return server.DeleteSliver(slice_xrn, [slice_cred])    
978
979     def SliverStatus(self, opts, args):
980         slice_xrn = args[0]
981         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
982         server = self.geni_am
983         print server.SliverStatus(slice_xrn, [slice_cred])
984     
985     def RenewSliver(self, opts, args):
986         slice_xrn = args[0]
987         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
988         time = args[1]
989         server = self.geni_am
990         return server.RenewSliver(slice_xrn, [slice_cred], time)   
991
992     def Shutdown(self, opts, args):
993         slice_xrn = args[0]
994         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
995         server = self.geni_am
996         return server.Shutdown(slice_xrn, [slice_cred])         
997     
998     #
999     # Main: parse arguments and dispatch to command
1000     #
1001     def main(self):
1002         parser = self.create_parser()
1003         (options, args) = parser.parse_args()
1004         self.options = options
1005    
1006         if options.hashrequest:
1007             self.hashrequest = True
1008  
1009         if len(args) <= 0:
1010             print "No command given. Use -h for help."
1011             return - 1
1012     
1013         command = args[0]
1014         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
1015         if self.options.verbose :
1016             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
1017                                                                    options.sfi_dir, options.user,
1018                                                                    options.auth)
1019             print "Command %s" % command
1020             if command in ("resources"):
1021                 print "resources cmd_opts %s" % cmd_opts.format
1022             elif command in ("list", "show", "remove"):
1023                 print "cmd_opts.type %s" % cmd_opts.type
1024             print "cmd_args %s" % cmd_args
1025     
1026         self.set_servers()
1027     
1028         try:
1029             self.dispatch(command, cmd_opts, cmd_args)
1030         except KeyError:
1031             raise 
1032             print "Command not found:", command
1033             sys.exit(1)
1034     
1035         return
1036     
1037 if __name__ == "__main__":
1038    Sfi().main()