sfa-0.9-17 tag
[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 delegating user's gid
616         caller_gid = self._get_gid(self.user)
617         caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
618   
619         # the gid of the user who will be delegated to
620         delegee_gid = self._get_gid(hrn)
621         delegee_hrn = delegee_gid.get_hrn()
622         delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
623         delegee_gid.save_to_file(filename=delegee_gidfile)
624         dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
625         return dcred.save_to_string(save_parents=True)
626      
627     # removed named registry record
628     #   - have to first retrieve the record to be removed
629     def remove(self, opts, args):
630         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
631         hrn = args[0]
632         type = opts.type 
633         if type in ['all']:
634             type = '*'
635         return self.registry.Remove(hrn, auth_cred, type)
636     
637     # add named registry record
638     def add(self, opts, args):
639         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
640         record_filepath = args[0]
641         rec_file = self.get_record_file(record_filepath)
642         record = load_record_from_file(rec_file).as_dict()
643         return self.registry.Register(record, auth_cred)
644     
645     # update named registry entry
646     def update(self, opts, args):
647         user_cred = self.get_user_cred()
648         rec_file = self.get_record_file(args[0])
649         record = load_record_from_file(rec_file)
650         if record['type'] == "user":
651             if record.get_name() == user_cred.get_gid_object().get_hrn():
652                 cred = user_cred.save_to_string(save_parents=True)
653             else:
654                 cred = self.get_auth_cred().save_to_string(save_parents=True)
655         elif record['type'] in ["slice"]:
656             try:
657                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
658             except ServerException, e:
659                # XXX smbaker -- once we have better error return codes, update this
660                # to do something better than a string compare
661                if "Permission error" in e.args[0]:
662                    cred = self.get_auth_cred().save_to_string(save_parents=True)
663                else:
664                    raise
665         elif record.get_type() in ["authority"]:
666             cred = self.get_auth_cred().save_to_string(save_parents=True)
667         elif record.get_type() == 'node':
668             cred = self.get_auth_cred().save_to_string(save_parents=True)
669         else:
670             raise "unknown record type" + record.get_type()
671         record = record.as_dict()
672         return self.registry.Update(record, cred)
673   
674     def get_trusted_certs(self, opts, args):
675         """
676         return uhe trusted certs at this interface 
677         """ 
678         trusted_certs = self.registry.get_trusted_certs()
679         for trusted_cert in trusted_certs:
680             cert = Certificate(string=trusted_cert)
681             print cert.get_subject()
682         return 
683
684     def aggregates(self, opts, args):
685         """
686         return a list of details about known aggregates
687         """
688         user_cred = self.get_user_cred().save_to_string(save_parents=True)
689         hrn = None
690         if args:
691             hrn = args[0]
692
693         result = self.registry.get_aggregates(user_cred, hrn)
694         display_list(result)
695         return 
696
697     def registries(self, opts, args):
698         """
699         return a list of details about known registries
700         """
701         user_cred = self.get_user_cred().save_to_string(save_parents=True)
702         hrn = None
703         if args:
704             hrn = args[0]
705         result = self.registry.get_registries(user_cred, hrn)
706         display_list(result)
707         return
708
709  
710     # ==================================================================
711     # Slice-related commands
712     # ==================================================================
713     
714
715     def version(self, opts, args):
716         server = self.get_server_from_opts(opts)
717         
718         print server.GetVersion()
719
720     # list instantiated slices
721     def slices(self, opts, args):
722         """
723         list instantiated slices
724         """
725         user_cred = self.get_user_cred().save_to_string(save_parents=True)
726         delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
727         creds = [user_cred, delegated_cred]
728         server = self.get_server_from_opts(opts)
729         results = server.ListSlices(creds)
730         display_list(results)
731         return
732     
733     # show rspec for named slice
734     def resources(self, opts, args):
735         user_cred = self.get_user_cred().save_to_string(save_parents=True)
736         server = self.slicemgr
737         call_options = {}
738         server = self.get_server_from_opts(opts)
739         
740         if args:
741             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
742             hrn = args[0]
743             call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
744         else:
745             cred = user_cred
746             hrn = None
747      
748         delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
749         creds = [cred, delegated_cred] 
750         result = server.ListResources(creds, call_options)
751         format = opts.format
752         display_rspec(result, format)
753         if (opts.file is not None):
754             file = opts.file
755             if not file.startswith(os.sep):
756                 file = os.path.join(self.options.sfi_dir, file)
757             save_rspec_to_file(result, file)
758         return
759     
760     # created named slice with given rspec
761     def create(self, opts, args):
762         slice_hrn = args[0]
763         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
764         user_cred = self.get_user_cred()
765         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
766         delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
767         creds = [slice_cred, delegated_cred]
768         rspec_file = self.get_rspec_file(args[1])
769         rspec = open(rspec_file).read()
770         server = self.get_server_from_opts(opts)
771         result =  server.CreateSliver(slice_urn, creds, rspec, [])
772         print result
773         return result
774
775     # get a ticket for the specified slice
776     def get_ticket(self, opts, args):
777         slice_hrn, rspec_path = args[0], args[1]
778         slice_urn = hrn_to_urn(slice_hrn, 'slice')
779         user_cred = self.get_user_cred()
780         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
781         delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
782         creds = [slice_cred, delegated_cred]
783         rspec_file = self.get_rspec_file(rspec_path) 
784         rspec = open(rspec_file).read()
785         server = self.get_server_from_opts(opts)
786         ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
787         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
788         print "writing ticket to ", file        
789         ticket = SfaTicket(string=ticket_string)
790         ticket.save_to_file(filename=file, save_parents=True)
791
792     def redeem_ticket(self, opts, args):
793         ticket_file = args[0]
794         
795         # get slice hrn from the ticket
796         # use this to get the right slice credential 
797         ticket = SfaTicket(filename=ticket_file)
798         ticket.decode()
799         slice_hrn = ticket.gidObject.get_hrn()
800         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
801         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
802         user_cred = self.get_user_cred()
803         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
804         
805         # get a list of node hostnames from the RSpec 
806         tree = etree.parse(StringIO(ticket.rspec))
807         root = tree.getroot()
808         hostnames = root.xpath("./network/site/node/hostname/text()")
809         
810         # create an xmlrpc connection to the component manager at each of these
811         # components and gall redeem_ticket
812         connections = {}
813         for hostname in hostnames:
814             try:
815                 print "Calling redeem_ticket at %(hostname)s " % locals(),
816                 server = self.get_server(hostname, CM_PORT, self.key_file, \
817                                          self.cert_file, self.options.debug)
818                 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
819                 print "Success"
820             except socket.gaierror:
821                 print "Failed:",
822                 print "Componet Manager not accepting requests" 
823             except Exception, e:
824                 print "Failed:", e.message
825         return
826  
827     # delete named slice
828     def delete(self, opts, args):
829         slice_hrn = args[0]
830         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
831         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
832         delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
833         creds = [slice_cred, delegated_cred]
834         server = self.get_server_from_opts(opts)
835         return server.DeleteSliver(slice_urn, creds)
836     
837     # start named slice
838     def start(self, opts, args):
839         slice_hrn = args[0]
840         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
841         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
842         delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
843         creds = [slice_cred, delegated_cred]
844         server = self.get_server_from_opts(opts)
845         return server.Start(slice_urn, creds)
846     
847     # stop named slice
848     def stop(self, opts, args):
849         slice_hrn = args[0]
850         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
851         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
852         delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
853         creds = [slice_cred, delegated_cred]
854         server = self.get_server_from_opts(opts)
855         return server.Stop(slice_urn, creds)
856     
857     # reset named slice
858     def reset(self, opts, args):
859         slice_hrn = args[0]
860         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
861         server = self.get_server_from_opts(opts)
862         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
863         delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
864         creds = [slice_cred, delegated_cred]
865         return server.reset_slice(creds, slice_urn)
866
867     def renew(self, opts, args):
868         slice_hrn = args[0]
869         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
870         server = self.get_server_from_opts(opts)
871         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
872         delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
873         creds = [slice_cred, delegated_cred]
874         time = args[1]
875         return server.RenewSliver(slice_urn, creds, time)
876
877
878     def status(self, opts, args):
879         slice_hrn = args[0]
880         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
881         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
882         delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
883         creds = [slice_cred, delegated_cred]
884         server = self.get_server_from_opts(opts)
885         print server.SliverStatus(slice_urn, creds)
886
887
888     def shutdown(self, opts, args):
889         slice_hrn = args[0]
890         slice_urn = hrn_to_urn(slice_hrn, 'slice') 
891         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
892         delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
893
894         server = self.get_server_from_opts(opts)
895         return server.Shutdown(slice_urn, [slice_cred])         
896     
897     #
898     # Main: parse arguments and dispatch to command
899     #
900     def main(self):
901         parser = self.create_parser()
902         (options, args) = parser.parse_args()
903         self.options = options
904    
905         if options.hashrequest:
906             self.hashrequest = True
907  
908         if len(args) <= 0:
909             print "No command given. Use -h for help."
910             return - 1
911     
912         command = args[0]
913         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
914         if self.options.verbose :
915             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
916                                                                    options.sfi_dir, options.user,
917                                                                    options.auth)
918             print "Command %s" % command
919             if command in ("resources"):
920                 print "resources cmd_opts %s" % cmd_opts.format
921             elif command in ("list", "show", "remove"):
922                 print "cmd_opts.type %s" % cmd_opts.type
923             print "cmd_args %s" % cmd_args
924     
925         self.set_servers()
926     
927         try:
928             self.dispatch(command, cmd_opts, cmd_args)
929         except KeyError:
930             raise 
931             print "Command not found:", command
932             sys.exit(1)
933     
934         return
935     
936 if __name__ == "__main__":
937    Sfi().main()