delegate_cred comes from self
[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     slicemgr = None
121     registry = None
122     user = None
123     authority = None
124     options = None
125     hashrequest = False
126    
127     def create_cmd_parser(self, command, additional_cmdargs=None):
128         cmdargs = {"list": "name",
129                   "show": "name",
130                   "remove": "name",
131                   "add": "record",
132                   "update": "record",
133                   "aggregates": "[name]",
134                   "registries": "[name]",
135                   "get_gid": [],  
136                   "get_trusted_certs": "cred",
137                   "slices": "",
138                   "resources": "[name]",
139                   "create": "name rspec",
140                   "get_ticket": "name rspec",
141                   "redeem_ticket": "ticket",
142                   "delete": "name",
143                   "reset": "name",
144                   "start": "name",
145                   "stop": "name",
146                   "delegate": "name",
147                   "status": "name",
148                   "renew": "name",
149                   "shutdown": "name",
150                   "version": "",  
151                  }
152
153         if additional_cmdargs:
154             cmdargs.update(additional_cmdargs)
155
156         if command not in cmdargs:
157             print "Invalid command\n"
158             print "Commands: ",
159             for key in cmdargs.keys():
160                 print key + ",",
161             print ""
162             sys.exit(2)
163
164         parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
165                                      % (command, cmdargs[command]))
166
167         # user specifies remote aggregate/sm/component                          
168         if command in ("resources", "slices", "create", "delete", "start", "stop", "restart", "get_ticket", "redeem_ticket"):
169             parser.add_option("-a", "--aggregate", dest="aggregate",
170                              default=None, help="aggregate host")
171             parser.add_option("-p", "--port", dest="port",
172                              default=AGGREGATE_PORT, help="aggregate port")
173             parser.add_option("-c", "--component", dest="component", default=None,
174                              help="component hrn")
175         
176         # registy filter option    
177         if command in ("list", "show", "remove"):
178             parser.add_option("-t", "--type", dest="type", type="choice",
179                             help="type filter ([all]|user|slice|authority|node|aggregate)",
180                             choices=("all", "user", "slice", "authority", "node", "aggregate"),
181                             default="all")
182         # display formats
183         if command in ("resources"):
184             parser.add_option("-f", "--format", dest="format", type="choice",
185                              help="display format ([xml]|dns|ip)", default="xml",
186                              choices=("xml", "dns", "ip"))
187
188         if command in ("resources", "show", "list"):
189            parser.add_option("-o", "--output", dest="file",
190                             help="output XML to file", metavar="FILE", default=None)
191         
192         if command in ("show", "list"):
193            parser.add_option("-f", "--format", dest="format", type="choice",
194                              help="display format ([text]|xml)", default="text",
195                              choices=("text", "xml"))
196
197         if command in ("delegate"):
198            parser.add_option("-u", "--user",
199                             action="store_true", dest="delegate_user", default=False,
200                             help="delegate user credential")
201            parser.add_option("-s", "--slice", dest="delegate_slice",
202                             help="delegate slice credential", metavar="HRN", default=None)
203         
204         return parser
205
206         
207     def create_parser(self):
208
209         # Generate command line parser
210         parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
211                              description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
212         parser.add_option("-r", "--registry", dest="registry",
213                          help="root registry", metavar="URL", default=None)
214         parser.add_option("-s", "--slicemgr", dest="sm",
215                          help="slice manager", metavar="URL", default=None)
216         default_sfi_dir = os.path.expanduser("~/.sfi/")
217         parser.add_option("-d", "--dir", dest="sfi_dir",
218                          help="config & working directory - default is " + default_sfi_dir,
219                          metavar="PATH", default=default_sfi_dir)
220         parser.add_option("-u", "--user", dest="user",
221                          help="user name", metavar="HRN", default=None)
222         parser.add_option("-a", "--auth", dest="auth",
223                          help="authority name", metavar="HRN", default=None)
224         parser.add_option("-v", "--verbose",
225                          action="store_true", dest="verbose", default=False,
226                          help="verbose mode")
227         parser.add_option("-D", "--debug",
228                           action="store_true", dest="debug", default=False,
229                           help="Debug (xml-rpc) protocol messages")
230         parser.add_option("-p", "--protocol",
231                          dest="protocol", default="xmlrpc",
232                          help="RPC protocol (xmlrpc or soap)")
233         parser.add_option("-k", "--hashrequest",
234                          action="store_true", dest="hashrequest", default=False,
235                          help="Create a hash of the request that will be authenticated on the server")
236         parser.disable_interspersed_args()
237
238         return parser
239         
240  
241     #
242     # Establish Connection to SliceMgr and Registry Servers
243     #
244     def set_servers(self):
245        config_file = self.options.sfi_dir + os.sep + "sfi_config"
246        try:
247           config = Config (config_file)
248        except:
249           print "Failed to read configuration file", config_file
250           print "Make sure to remove the export clauses and to add quotes"
251           if not self.options.verbose:
252              print "Re-run with -v for more details"
253           else:
254              traceback.print_exc()
255           sys.exit(1)
256     
257        errors = 0
258        # Set SliceMgr URL
259        if (self.options.sm is not None):
260           sm_url = self.options.sm
261        elif hasattr(config, "SFI_SM"):
262           sm_url = config.SFI_SM
263        else:
264           print "You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file
265           errors += 1 
266     
267        # Set Registry URL
268        if (self.options.registry is not None):
269           reg_url = self.options.registry
270        elif hasattr(config, "SFI_REGISTRY"):
271           reg_url = config.SFI_REGISTRY
272        else:
273           print "You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file
274           errors += 1 
275           
276
277        # Set user HRN
278        if (self.options.user is not None):
279           self.user = self.options.user
280        elif hasattr(config, "SFI_USER"):
281           self.user = config.SFI_USER
282        else:
283           print "You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file
284           errors += 1 
285     
286        # Set authority HRN
287        if (self.options.auth is not None):
288           self.authority = self.options.auth
289        elif hasattr(config, "SFI_AUTH"):
290           self.authority = config.SFI_AUTH
291        else:
292           print "You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file
293           errors += 1 
294     
295        if errors:
296           sys.exit(1)
297     
298        if self.options.verbose :
299           print "Contacting Slice Manager at:", sm_url
300           print "Contacting Registry at:", reg_url
301     
302        # Get key and certificate
303        key_file = self.get_key_file()
304        cert_file = self.get_cert_file(key_file)
305        self.key = Keypair(filename=key_file) 
306        self.key_file = key_file
307        self.cert_file = cert_file
308        self.cert = Certificate(filename=cert_file) 
309        # Establish connection to server(s)
310        self.registry = xmlrpcprotocol.get_server(reg_url, key_file, cert_file, self.options.debug)  
311        self.slicemgr = xmlrpcprotocol.get_server(sm_url, key_file, cert_file, self.options.debug)
312
313        return
314     
315     #
316     # Get various credential and spec files
317     #
318     # Establishes limiting conventions
319     #   - conflates MAs and SAs
320     #   - assumes last token in slice name is unique
321     #
322     # Bootstraps credentials
323     #   - bootstrap user credential from self-signed certificate
324     #   - bootstrap authority credential from user credential
325     #   - bootstrap slice credential from user credential
326     #
327     
328     
329     def get_key_file(self):
330        file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
331        #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".pkey")
332        if (os.path.isfile(file)):
333           return file
334        else:
335           print "Key file", file, "does not exist"
336           sys.exit(-1)
337        return
338     
339     def get_cert_file(self, key_file):
340     
341        #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cert")
342        file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
343        if (os.path.isfile(file)):
344           return file
345        else:
346           k = Keypair(filename=key_file)
347           cert = Certificate(subject=self.user)
348           cert.set_pubkey(k)
349           cert.set_issuer(k, self.user)
350           cert.sign()
351           if self.options.verbose :
352              print "Writing self-signed certificate to", file
353           cert.save_to_file(file)
354           return file
355
356     def get_cached_gid(self, file):
357         """
358         Return a cached gid    
359         """
360         gid = None 
361         if (os.path.isfile(file)):
362             gid = GID(filename=file)
363         return gid
364
365     def get_gid(self, opts, args):
366         hrn = None
367         if args:
368             hrn = args[0]
369         gid = self._get_gid(hrn)
370         print gid.save_to_string(save_parents=True)
371         return gid
372
373     def _get_gid(self, hrn=None):
374         if not hrn:
375             hrn = self.user
376  
377         gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
378         gid = self.get_cached_gid(gidfile)
379         if not gid:
380             user_cred = self.get_user_cred()
381             records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
382             if not records:
383                 raise RecordNotFound(args[0])
384             gid = GID(string=records[0]['gid'])
385             if self.options.verbose:
386                 print "Writing gid to ", gidfile 
387             gid.save_to_file(filename=gidfile)
388         return gid   
389                 
390      
391     def get_cached_credential(self, file):
392         """
393         Return a cached credential only if it hasn't expired.
394         """
395         if (os.path.isfile(file)):
396             credential = Credential(filename=file)
397             # make sure it isnt expired 
398             if not credential.get_lifetime or \
399                datetime.datetime.today() < credential.get_lifetime():
400                 return credential
401         return None 
402  
403     def get_user_cred(self):
404         #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
405         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
406         return self.get_cred(file, 'user', self.user)
407
408     def get_auth_cred(self):
409         if not self.authority:
410             print "no authority specified. Use -a or set SF_AUTH"
411             sys.exit(-1)
412         file = os.path.join(self.options.sfi_dir, get_leaf("authority") + ".cred")
413         return self.get_cred(file, 'authority', self.authority)
414
415     def get_slice_cred(self, name):
416         file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
417         return self.get_cred(file, 'slice', name)
418  
419     def get_cred(self, file, type, hrn):
420         # attempt to load a cached credential 
421         cred = self.get_cached_credential(file)    
422         if not cred:
423             if type in ['user']:
424                 cert_string = self.cert.save_to_string(save_parents=True)
425                 user_name = self.user.replace(self.authority + ".", '')
426                 if user_name.count(".") > 0:
427                     user_name = user_name.replace(".", '_')
428                     self.user = self.authority + "." + user_name
429                 cred_str = self.registry.get_self_credential(cert_string, "user", hrn)
430             else:
431                 # bootstrap slice credential from user credential
432                 user_cred = self.get_user_cred().save_to_string(save_parents=True)
433                 cred_str = self.registry.get_credential(user_cred, type, hrn)
434             
435             if not cred_str:
436                 print "Failed to get %s credential" % (type)
437                 sys.exit(-1)
438                 
439             cred = Credential(string=cred_str)
440             cred.save_to_file(file, save_parents=True)
441             if self.options.verbose:
442                 print "Writing %s credential to %s" %(type, file)
443
444         return cred
445  
446     
447     def get_rspec_file(self, rspec):
448        if (os.path.isabs(rspec)):
449           file = rspec
450        else:
451           file = os.path.join(self.options.sfi_dir, rspec)
452        if (os.path.isfile(file)):
453           return file
454        else:
455           print "No such rspec file", rspec
456           sys.exit(1)
457     
458     def get_record_file(self, record):
459        if (os.path.isabs(record)):
460           file = record
461        else:
462           file = os.path.join(self.options.sfi_dir, record)
463        if (os.path.isfile(file)):
464           return file
465        else:
466           print "No such registry record file", record
467           sys.exit(1)
468     
469     def load_publickey_string(self, fn):
470        f = file(fn, "r")
471        key_string = f.read()
472     
473        # if the filename is a private key file, then extract the public key
474        if "PRIVATE KEY" in key_string:
475            outfn = tempfile.mktemp()
476            cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
477            os.system(cmd)
478            f = file(outfn, "r")
479            key_string = f.read()
480            os.remove(outfn)
481     
482        return key_string
483
484     def get_component_server_from_hrn(self, hrn):
485         # direct connection to the nodes component manager interface
486         user_cred = self.get_user_cred().save_to_string(save_parents=True)
487         records = self.registry.Resolve(hrn, user_cred)
488         records = filter_records('node', records)
489         if not records:
490             print "No such component:", opts.component
491         record = records[0]
492   
493         return self.get_server(record['hostname'], CM_PORT, self.key_file, \
494                                self.cert_file, self.options.debug)
495  
496     def get_server(self, host, port, keyfile, certfile, debug):
497         """
498         Return an instnace of an xmlrpc server connection    
499         """
500         url = "http://%s:%s" % (host, port)
501         return xmlrpcprotocol.get_server(url, keyfile, certfile, debug)
502
503     def get_server_from_opts(self, opts):
504         """
505         Return instance of an xmlrpc connection to a slice manager, aggregate
506         or component server depending on the specified opts
507         """
508         server = self.slicemgr
509         # direct connection to an aggregate
510         if hasattr(opts, 'aggregate') and opts.aggregate:
511             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
512                                      self.cert_file, self.options.debug)
513         # direct connection to the nodes component manager interface
514         if hasattr(opts, 'component') and opts.component:
515             server = self.get_component_server_from_hrn(opts.component)    
516  
517         return server
518     #==========================================================================
519     # Following functions implement the commands
520     #
521     # Registry-related commands
522     #==========================================================================
523   
524     def dispatch(self, command, cmd_opts, cmd_args):
525         getattr(self, command)(cmd_opts, cmd_args)
526  
527     # list entires in named authority registry
528     def list(self, opts, args):
529         user_cred = self.get_user_cred().save_to_string(save_parents=True)
530         hrn = args[0]
531         try:
532             list = self.registry.List(hrn, user_cred)
533         except IndexError:
534             raise Exception, "Not enough parameters for the 'list' command"
535           
536         # filter on person, slice, site, node, etc.  
537         # THis really should be in the self.filter_records funct def comment...
538         list = filter_records(opts.type, list)
539         for record in list:
540             print "%s (%s)" % (record['hrn'], record['type'])     
541         if opts.file:
542             file = opts.file
543             if not file.startswith(os.sep):
544                 file = os.path.join(self.options.sfi_dir, file)
545             save_records_to_file(file, list)
546         return
547     
548     # show named registry record
549     def show(self, opts, args):
550         user_cred = self.get_user_cred().save_to_string(save_parents=True)
551         hrn = args[0]
552         records = self.registry.Resolve(hrn, user_cred)
553         records = filter_records(opts.type, records)
554         if not records:
555             print "No record of type", opts.type
556         for record in records:
557             if record['type'] in ['user']:
558                 record = UserRecord(dict=record)
559             elif record['type'] in ['slice']:
560                 record = SliceRecord(dict=record)
561             elif record['type'] in ['node']:
562                 record = NodeRecord(dict=record)
563             elif record['type'] in ['authority', 'ma', 'sa']:
564                 record = AuthorityRecord(dict=record)
565             else:
566                 record = SfaRecord(dict=record)
567             if (opts.format == "text"): 
568                 record.dump()  
569             else:
570                 print record.save_to_string() 
571        
572         if opts.file:
573             file = opts.file
574             if not file.startswith(os.sep):
575                 file = os.path.join(self.options.sfi_dir, file)
576             save_records_to_file(file, records)
577         return
578     
579     def delegate(self, opts, args):
580
581         delegee_hrn = args[0]
582         if opts.delegate_user:
583             user_cred = self.get_user_cred()
584             cred = self.delegate_cred(user_cred, delegee_hrn)
585         elif opts.delegate_slice:
586             slice_cred = self.get_slice_cred(opts.delegate_slice)
587             cred = self.delegate_cred(slice_cred, delegee_hrn)
588         else:
589             print "Must specify either --user or --slice <hrn>"
590             return
591         delegated_cred = Credential(string=cred)
592         object_hrn = delegated_cred.get_gid_object().get_hrn()
593         if opts.delegate_user:
594             dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
595                                   + get_leaf(object_hrn) + ".cred")
596         elif opts.delegate_slice:
597             dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
598                                   + get_leaf(object_hrn) + ".cred")
599
600         delegated_cred.save_to_file(dest_fn, save_parents=True)
601
602         print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
603     
604     def delegate_cred(self, object_cred, hrn):
605         # the gid and hrn of the object we are delegating
606         if isinstance(object_cred, str):
607             object_cred = Credential(string=object_cred) 
608         object_gid = object_cred.get_gid_object()
609         object_hrn = object_gid.get_hrn()
610     
611         if not object_cred.get_privileges().get_all_delegate():
612             print "Error: Object credential", object_hrn, "does not have delegate bit set"
613             return
614     
615         # the gid of the user who will be delegated to
616         delegee_gid = self._get_gid(hrn)
617         delegee_hrn = delegee_gid.get_hrn()
618         delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
619         delegee_gid.save_to_file(filename=delegee_gidfile)
620         dcred = object_cred.delegate(delegee_gidfile, self.get_key_file())
621         return dcred.save_to_string(save_parents=True)
622      
623     # removed named registry record
624     #   - have to first retrieve the record to be removed
625     def remove(self, opts, args):
626         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
627         hrn = args[0]
628         type = opts.type 
629         if type in ['all']:
630             type = '*'
631         return self.registry.Remove(hrn, auth_cred, type)
632     
633     # add named registry record
634     def add(self, opts, args):
635         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
636         record_filepath = args[0]
637         rec_file = self.get_record_file(record_filepath)
638         record = load_record_from_file(rec_file).as_dict()
639         return self.registry.Register(record, auth_cred)
640     
641     # update named registry entry
642     def update(self, opts, args):
643         user_cred = self.get_user_cred()
644         rec_file = self.get_record_file(args[0])
645         record = load_record_from_file(rec_file)
646         if record['type'] == "user":
647             if record.get_name() == user_cred.get_gid_object().get_hrn():
648                 cred = user_cred.save_to_string(save_parents=True)
649             else:
650                 cred = self.get_auth_cred().save_to_string(save_parents=True)
651         elif record['type'] in ["slice"]:
652             try:
653                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
654             except ServerException, e:
655                # XXX smbaker -- once we have better error return codes, update this
656                # to do something better than a string compare
657                if "Permission error" in e.args[0]:
658                    cred = self.get_auth_cred().save_to_string(save_parents=True)
659                else:
660                    raise
661         elif record.get_type() in ["authority"]:
662             cred = self.get_auth_cred().save_to_string(save_parents=True)
663         elif record.get_type() == 'node':
664             cred = self.get_auth_cred().save_to_string(save_parents=True)
665         else:
666             raise "unknown record type" + record.get_type()
667         record = record.as_dict()
668         return self.registry.Update(record, cred)
669   
670     def get_trusted_certs(self, opts, args):
671         """
672         return uhe trusted certs at this interface 
673         """ 
674         trusted_certs = self.registry.get_trusted_certs()
675         for trusted_cert in trusted_certs:
676             cert = Certificate(string=trusted_cert)
677             print cert.get_subject()
678         return 
679
680     def aggregates(self, opts, args):
681         """
682         return a list of details about known aggregates
683         """
684         user_cred = self.get_user_cred().save_to_string(save_parents=True)
685         hrn = None
686         if args:
687             hrn = args[0]
688
689         result = self.registry.get_aggregates(user_cred, hrn)
690         display_list(result)
691         return 
692
693     def registries(self, opts, args):
694         """
695         return a list of details about known registries
696         """
697         user_cred = self.get_user_cred().save_to_string(save_parents=True)
698         hrn = None
699         if args:
700             hrn = args[0]
701         result = self.registry.get_registries(user_cred, hrn)
702         display_list(result)
703         return
704
705  
706     # ==================================================================
707     # Slice-related commands
708     # ==================================================================
709     
710
711     def version(self, opts, args):
712         server = self.get_server_from_opts(opts)
713         
714         print server.GetVersion()
715
716     # list instantiated slices
717     def slices(self, opts, args):
718         """
719         list instantiated slices
720         """
721         user_cred = self.get_user_cred().save_to_string(save_parents=True)
722         server = self.get_server_from_opts(opts)
723         results = server.ListSlices([user_cred])
724         display_list(results)
725         return
726     
727     # show rspec for named slice
728     def resources(self, opts, args):
729         user_cred = self.get_user_cred().save_to_string(save_parents=True)
730         server = self.slicemgr
731         call_options = {}
732         server = self.get_server_from_opts(opts)
733         
734         if args:
735             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
736             hrn = args[0]
737             call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
738         else:
739             cred = user_cred
740             hrn = None
741       
742         delegated_cred = self.delegate_cred(cred, self.authority) 
743         creds = [cred, delegated_cred] 
744         result = server.ListResources(creds, call_options)
745         format = opts.format
746         display_rspec(result, format)
747         if (opts.file is not None):
748             file = opts.file
749             if not file.startswith(os.sep):
750                 file = os.path.join(self.options.sfi_dir, file)
751             save_rspec_to_file(result, file)
752         return
753     
754     # created named slice with given rspec
755     def create(self, opts, args):
756         slice_hrn = args[0]
757         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
758         user_cred = self.get_user_cred()
759         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
760         rspec_file = self.get_rspec_file(args[1])
761         rspec = open(rspec_file).read()
762         server = self.get_server_from_opts(opts)
763         result =  server.CreateSliver(slice_urn, [slice_cred], rspec, [])
764         print result
765         return result
766
767     # get a ticket for the specified slice
768     def get_ticket(self, opts, args):
769         slice_hrn, rspec_path = args[0], args[1]
770         slice_urn = hrn_to_urn(slice_hrn, 'slice')
771         user_cred = self.get_user_cred()
772         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
773         rspec_file = self.get_rspec_file(rspec_path) 
774         rspec = open(rspec_file).read()
775         server = self.get_server_from_opts(opts)
776         ticket_string = server.GetTicket(slice_urn, [slice_cred], rspec, [])
777         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
778         print "writing ticket to ", file        
779         ticket = SfaTicket(string=ticket_string)
780         ticket.save_to_file(filename=file, save_parents=True)
781
782     def redeem_ticket(self, opts, args):
783         ticket_file = args[0]
784         
785         # get slice hrn from the ticket
786         # use this to get the right slice credential 
787         ticket = SfaTicket(filename=ticket_file)
788         ticket.decode()
789         slice_hrn = ticket.gidObject.get_hrn()
790         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
791         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
792         user_cred = self.get_user_cred()
793         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
794         
795         # get a list of node hostnames from the RSpec 
796         tree = etree.parse(StringIO(ticket.rspec))
797         root = tree.getroot()
798         hostnames = root.xpath("./network/site/node/hostname/text()")
799         
800         # create an xmlrpc connection to the component manager at each of these
801         # components and gall redeem_ticket
802         connections = {}
803         for hostname in hostnames:
804             try:
805                 print "Calling redeem_ticket at %(hostname)s " % locals(),
806                 server = self.get_server(hostname, CM_PORT, self.key_file, \
807                                          self.cert_file, self.options.debug)
808                 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
809                 print "Success"
810             except socket.gaierror:
811                 print "Failed:",
812                 print "Componet Manager not accepting requests" 
813             except Exception, e:
814                 print "Failed:", e.message
815         return
816  
817     # delete named slice
818     def delete(self, opts, args):
819         slice_hrn = args[0]
820         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
821         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
822         server = self.get_server_from_opts(opts)
823         return server.DeleteSliver(slice_urn, [slice_cred])
824     
825     # start named slice
826     def start(self, opts, args):
827         slice_hrn = args[0]
828         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
829         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
830         server = self.get_server_from_opts(opts)
831         return server.Start(slice_urn, [slice_cred])
832     
833     # stop named slice
834     def stop(self, opts, args):
835         slice_hrn = args[0]
836         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
837         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
838         server = self.get_server_from_opts(opts)
839         return server.Stop(slice_urn, [slice_cred])
840     
841     # reset named slice
842     def reset(self, opts, args):
843         slice_hrn = args[0]
844         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
845         server = self.get_server_from_opts(opts)
846         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
847         return server.reset_slice(slice_cred, slice_urn)
848
849     def renew(self, opts, args):
850         slice_hrn = args[0]
851         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
852         server = self.get_server_from_opts(opts)
853         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
854         time = args[1]
855         return server.RenewSliver(slice_urn, [slice_cred], time)
856
857
858     def status(self, opts, args):
859         slice_hrn = args[0]
860         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
861         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
862         server = self.get_server_from_opts(opts)
863         print server.SliverStatus(slice_urn, [slice_cred])
864
865
866     def shutdown(self, opts, args):
867         slice_hrn = args[0]
868         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
869         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
870         server = self.get_server_from_opts(opts)
871         return server.Shutdown(slice_urn, [slice_cred])         
872     
873     #
874     # Main: parse arguments and dispatch to command
875     #
876     def main(self):
877         parser = self.create_parser()
878         (options, args) = parser.parse_args()
879         self.options = options
880    
881         if options.hashrequest:
882             self.hashrequest = True
883  
884         if len(args) <= 0:
885             print "No command given. Use -h for help."
886             return - 1
887     
888         command = args[0]
889         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
890         if self.options.verbose :
891             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
892                                                                    options.sfi_dir, options.user,
893                                                                    options.auth)
894             print "Command %s" % command
895             if command in ("resources"):
896                 print "resources cmd_opts %s" % cmd_opts.format
897             elif command in ("list", "show", "remove"):
898                 print "cmd_opts.type %s" % cmd_opts.type
899             print "cmd_args %s" % cmd_args
900     
901         self.set_servers()
902     
903         try:
904             self.dispatch(command, cmd_opts, cmd_args)
905         except KeyError:
906             raise 
907             print "Command not found:", command
908             sys.exit(1)
909     
910         return
911     
912 if __name__ == "__main__":
913    Sfi().main()