732e76bc1d3369e2e4913ce3fb41eb3a2aa34cad
[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                   "slices": "",
136                   "resources": "[name]",
137                   "create": "name rspec",
138                   "get_trusted_certs": "cred",
139                   "get_ticket": "name rspec",
140                   "redeem_ticket": "ticket",
141                   "delete": "name",
142                   "reset": "name",
143                   "start": "name",
144                   "stop": "name",
145                   "delegate": "name",
146                   "version": "",
147                   "sliverStatus": "name",
148                   "renew": "name",
149                   "shutdown": "name"
150                  }
151
152         if additional_cmdargs:
153             cmdargs.update(additional_cmdargs)
154
155         if command not in cmdargs:
156             print "Invalid command\n"
157             print "Commands: ",
158             for key in cmdargs.keys():
159                 print key + ",",
160             print ""
161             sys.exit(2)
162
163         parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
164                                      % (command, cmdargs[command]))
165
166         # user specifies remote aggregate/sm/component                          
167         if command in ("resources", "slices", "create", "delete", "start", "stop", "restart", "get_ticket", "redeem_ticket"):
168             parser.add_option("-a", "--aggregate", dest="aggregate",
169                              default=None, help="aggregate host")
170             parser.add_option("-p", "--port", dest="port",
171                              default=AGGREGATE_PORT, help="aggregate port")
172             parser.add_option("-c", "--component", dest="component", default=None,
173                              help="component hrn")
174         
175         # registy filter option    
176         if command in ("list", "show", "remove"):
177             parser.add_option("-t", "--type", dest="type", type="choice",
178                             help="type filter ([all]|user|slice|authority|node|aggregate)",
179                             choices=("all", "user", "slice", "authority", "node", "aggregate"),
180                             default="all")
181
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_credential(self, file):
357         """
358         Return a cached credential only if it hasn't expired.
359         """
360         if (os.path.isfile(file)):
361             credential = Credential(filename=file)
362             # make sure it isnt expired 
363             if not credential.get_lifetime or \
364                datetime.datetime.today() < credential.get_lifetime():
365                 return credential
366         return None 
367  
368     def get_user_cred(self):
369         #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
370         file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
371         return self.get_cred(file, 'user', self.user)
372
373     def get_auth_cred(self):
374         if not self.authority:
375             print "no authority specified. Use -a or set SF_AUTH"
376             sys.exit(-1)
377         file = os.path.join(self.options.sfi_dir, get_leaf("authority") + ".cred")
378         return self.get_cred(file, 'authority', self.authority)
379
380     def get_slice_cred(self, name):
381         file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
382         return self.get_cred(file, 'slice', name)
383  
384     def get_cred(self, file, type, hrn):
385         # attempt to load a cached credential 
386         cred = self.get_cached_credential(file)    
387         if not cred:
388             if type in ['user']:
389                 cert_string = self.cert.save_to_string(save_parents=True)
390                 user_name = self.user.replace(self.authority + ".", '')
391                 if user_name.count(".") > 0:
392                     user_name = user_name.replace(".", '_')
393                     self.user = self.authority + "." + user_name
394                 cred_str = self.registry.get_self_credential(cert_string, "user", hrn)
395             else:
396                 # bootstrap slice credential from user credential
397                 user_cred = self.get_user_cred().save_to_string(save_parents=True)
398                 cred_str = self.registry.get_credential(user_cred, type, hrn)
399             
400             if not cred_str:
401                 print "Failed to get %s credential" % (type)
402                 sys.exit(-1)
403                 
404             cred = Credential(string=cred_str)
405             cred.save_to_file(file, save_parents=True)
406             if self.options.verbose:
407                 print "Writing %s credential to %s" %(type, file)
408
409         return cred
410  
411     
412     def get_rspec_file(self, rspec):
413        if (os.path.isabs(rspec)):
414           file = rspec
415        else:
416           file = os.path.join(self.options.sfi_dir, rspec)
417        if (os.path.isfile(file)):
418           return file
419        else:
420           print "No such rspec file", rspec
421           sys.exit(1)
422     
423     def get_record_file(self, record):
424        if (os.path.isabs(record)):
425           file = record
426        else:
427           file = os.path.join(self.options.sfi_dir, record)
428        if (os.path.isfile(file)):
429           return file
430        else:
431           print "No such registry record file", record
432           sys.exit(1)
433     
434     def load_publickey_string(self, fn):
435        f = file(fn, "r")
436        key_string = f.read()
437     
438        # if the filename is a private key file, then extract the public key
439        if "PRIVATE KEY" in key_string:
440            outfn = tempfile.mktemp()
441            cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
442            os.system(cmd)
443            f = file(outfn, "r")
444            key_string = f.read()
445            os.remove(outfn)
446     
447        return key_string
448
449     def get_component_server_from_hrn(self, hrn):
450         # direct connection to the nodes component manager interface
451         user_cred = self.get_user_cred().save_to_string(save_parents=True)
452         records = self.registry.resolve(user_cred, hrn)
453         records = filter_records('node', records)
454         if not records:
455             print "No such component:", opts.component
456         record = records[0]
457   
458         return self.get_server(record['hostname'], CM_PORT, self.key_file, \
459                                self.cert_file, self.options.debug)
460  
461     def get_server(self, host, port, keyfile, certfile, debug):
462         """
463         Return an instnace of an xmlrpc server connection    
464         """
465         url = "http://%s:%s" % (host, port)
466         return xmlrpcprotocol.get_server(url, keyfile, certfile, debug)
467
468     def get_server_from_opts(self, opts):
469         """
470         Return instance of an xmlrpc connection to a slice manager, aggregate
471         or component server depending on the specified opts
472         """
473         server = self.slicemgr
474         # direct connection to an aggregate
475         if hasattr(opts, 'aggregate') and opts.aggregate:
476             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
477                                      self.cert_file, self.options.debug)
478         # direct connection to the nodes component manager interface
479         if hasattr(opts, 'component') and opts.component:
480             server = self.get_component_server_from_hrn(opts.component)    
481  
482         return server
483     #==========================================================================
484     # Following functions implement the commands
485     #
486     # Registry-related commands
487     #==========================================================================
488   
489     def dispatch(self, command, cmd_opts, cmd_args):
490         getattr(self, command)(cmd_opts, cmd_args)
491  
492     # list entires in named authority registry
493     def list(self, opts, args):
494         user_cred = self.get_user_cred().save_to_string(save_parents=True)
495         hrn = args[0]
496         try:
497             list = self.registry.list(user_cred, hrn)
498         except IndexError:
499             raise Exception, "Not enough parameters for the 'list' command"
500           
501         # filter on person, slice, site, node, etc.  
502         # THis really should be in the self.filter_records funct def comment...
503         list = filter_records(opts.type, list)
504         for record in list:
505             print "%s (%s)" % (record['hrn'], record['type'])     
506         if opts.file:
507             file = opts.file
508             if not file.startswith(os.sep):
509                 file = os.path.join(self.options.sfi_dir, file)
510             save_records_to_file(file, list)
511         return
512     
513     # show named registry record
514     def show(self, opts, args):
515         user_cred = self.get_user_cred().save_to_string(save_parents=True)
516         hrn = args[0]
517         records = self.registry.resolve(user_cred, hrn)
518         records = filter_records(opts.type, records)
519         if not records:
520             print "No record of type", opts.type
521         for record in records:
522             if record['type'] in ['user']:
523                 record = UserRecord(dict=record)
524             elif record['type'] in ['slice']:
525                 record = SliceRecord(dict=record)
526             elif record['type'] in ['node']:
527                 record = NodeRecord(dict=record)
528             elif record['type'] in ['authority', 'ma', 'sa']:
529                 record = AuthorityRecord(dict=record)
530             else:
531                 record = SfaRecord(dict=record)
532             if (opts.format == "text"): 
533                 record.dump()  
534             else:
535                 print record.save_to_string() 
536        
537         if opts.file:
538             file = opts.file
539             if not file.startswith(os.sep):
540                 file = os.path.join(self.options.sfi_dir, file)
541             save_records_to_file(file, records)
542         return
543     
544     def delegate(self, opts, args):
545        user_cred = self.get_user_cred()
546        if opts.delegate_user:
547            object_cred = user_cred
548        elif opts.delegate_slice:
549            object_cred = self.get_slice_cred(opts.delegate_slice)
550        else:
551            print "Must specify either --user or --slice <hrn>"
552            return
553     
554        # the gid and hrn of the object we are delegating
555        object_gid = object_cred.get_gid_object()
556        object_hrn = object_gid.get_hrn()
557     
558        if not object_cred.get_privileges().get_all_delegate():
559            print "Error: Object credential", object_hrn, "does not have delegate bit set"
560            return
561     
562        records = self.registry.resolve(user_cred.save_to_string(save_parents=True), args[0])
563        records = filter_records("user", records)
564     
565        if not records:
566            print "Error: Didn't find a user record for", args[0]
567            return
568     
569        # the gid of the user who will be delegated to
570        delegee_gid = GID(string=records[0]['gid'])
571        delegee_hrn = delegee_gid.get_hrn()
572    
573        # the key and hrn of the user who will be delegating
574        user_key = Keypair(filename=self.get_key_file())
575        user_hrn = user_cred.get_gid_caller().get_hrn()
576        subject_string = "%s delegated to %s" % (object_hrn, delegee_hrn)
577        dcred = Credential(subject=subject_string)
578        dcred.set_gid_caller(delegee_gid)
579        dcred.set_gid_object(object_gid)
580        privs = object_cred.get_privileges()
581        dcred.set_privileges(object_cred.get_privileges())
582        dcred.get_privileges().delegate_all_privileges(True)
583        dcred.set_pubkey(object_gid.get_pubkey())
584        dcred.set_issuer(user_key, user_hrn)
585        dcred.set_parent(object_cred)
586        dcred.encode()
587        dcred.sign()
588     
589        if opts.delegate_user:
590            dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_" 
591                                   + get_leaf(object_hrn) + ".cred")
592        elif opts.delegate_slice:
593            dest_fn = os.path_join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_" 
594                                   + get_leaf(object_hrn) + ".cred")
595     
596        dcred.save_to_file(dest_fn, save_parents=True)
597     
598        print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
599     
600     # removed named registry record
601     #   - have to first retrieve the record to be removed
602     def remove(self, opts, args):
603         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
604         hrn = args[0]
605         type = opts.type 
606         if type in ['all']:
607             type = '*'
608         return self.registry.remove(auth_cred, type, hrn)
609     
610     # add named registry record
611     def add(self, opts, args):
612         auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
613         record_filepath = args[0]
614         rec_file = self.get_record_file(record_filepath)
615         record = load_record_from_file(rec_file).as_dict()
616         return self.registry.register(auth_cred, record)
617     
618     # update named registry entry
619     def update(self, opts, args):
620         user_cred = self.get_user_cred()
621         rec_file = self.get_record_file(args[0])
622         record = load_record_from_file(rec_file)
623         if record['type'] == "user":
624             if record.get_name() == user_cred.get_gid_object().get_hrn():
625                 cred = user_cred.save_to_string(save_parents=True)
626             else:
627                 cred = self.get_auth_cred().save_to_string(save_parents=True)
628         elif record['type'] in ["slice"]:
629             try:
630                 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
631             except ServerException, e:
632                # XXX smbaker -- once we have better error return codes, update this
633                # to do something better than a string compare
634                if "Permission error" in e.args[0]:
635                    cred = self.get_auth_cred().save_to_string(save_parents=True)
636                else:
637                    raise
638         elif record.get_type() in ["authority"]:
639             cred = self.get_auth_cred().save_to_string(save_parents=True)
640         elif record.get_type() == 'node':
641             cred = self.get_auth_cred().save_to_string(save_parents=True)
642         else:
643             raise "unknown record type" + record.get_type()
644         record = record.as_dict()
645         return self.registry.update(cred, record)
646   
647     def get_trusted_certs(self, opts, args):
648         """
649         return the trusted certs at this interface 
650         """ 
651         trusted_certs = self.registry.get_trusted_certs()
652         for trusted_cert in trusted_certs:
653             cert = Certificate(string=trusted_cert)
654             print cert.get_subject()
655         return 
656
657     def aggregates(self, opts, args):
658         """
659         return a list of details about known aggregates
660         """
661         user_cred = self.get_user_cred().save_to_string(save_parents=True)
662         hrn = None
663         if args:
664             hrn = args[0]
665
666         result = self.registry.get_aggregates(user_cred, hrn)
667         display_list(result)
668         return 
669
670     def registries(self, opts, args):
671         """
672         return a list of details about known registries
673         """
674         user_cred = self.get_user_cred().save_to_string(save_parents=True)
675         hrn = None
676         if args:
677             hrn = args[0]
678         result = self.registry.get_registries(user_cred, hrn)
679         display_list(result)
680         return
681
682  
683     # ==================================================================
684     # Slice-related commands
685     # ==================================================================
686     
687
688     # list instantiated slices
689     def slices(self, opts, args):
690         """
691         list instantiated slices
692         """
693         user_cred = self.get_user_cred().save_to_string(save_parents=True)
694         server = self.slicemgr
695         if opts.aggregate:
696             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
697                                      self.cert_file, self.options.debug)
698         # direct connection to the nodes component manager interface
699         if opts.component:
700             server = self.get_component_server_from_hrn(opts.component)
701         results = server.get_slices(user_cred)
702         display_list(results)
703         return
704     
705     # show rspec for named slice
706     def resources(self, opts, args):
707         user_cred = self.get_user_cred().save_to_string(save_parents=True)
708         server = self.slicemgr
709         if opts.aggregate:
710             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
711                                      self.cert_file, self.options.debug)
712         if args:
713             cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
714             hrn = args[0]
715         else:
716             cred = user_cred
717             hrn = None
718
719         result = server.get_resources(cred, hrn)
720         format = opts.format
721        
722         display_rspec(result, format)
723         if (opts.file is not None):
724             file = opts.file
725             if not file.startswith(os.sep):
726                 file = os.path.join(self.options.sfi_dir, file)
727             save_rspec_to_file(result, file)
728         return
729     
730     # created named slice with given rspec
731     def create(self, opts, args):
732         slice_hrn = args[0]
733         user_cred = self.get_user_cred()
734         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
735         rspec_file = self.get_rspec_file(args[1])
736         rspec = open(rspec_file).read()
737         server = self.slicemgr
738
739         if opts.aggregate:
740             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
741                                      self.cert_file, self.options.debug)
742
743         result =  server.create_slice(slice_cred, slice_hrn, rspec)
744         print result
745         return result
746
747     # get a ticket for the specified slice
748     def get_ticket(self, opts, args):
749         slice_hrn, rspec_path = args[0], args[1]
750         user_cred = self.get_user_cred()
751         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
752         rspec_file = self.get_rspec_file(rspec_path) 
753         rspec = open(rspec_file).read()
754         server = self.slicemgr
755         if opts.aggregate:
756             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
757                                      self.cert_file, self.options.debug)
758         ticket_string = server.get_ticket(slice_cred, slice_hrn, rspec)
759         file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
760         print "writing ticket to ", file        
761         ticket = SfaTicket(string=ticket_string)
762         ticket.save_to_file(filename=file, save_parents=True)
763
764     def redeem_ticket(self, opts, args):
765         ticket_file = args[0]
766         
767         # get slice hrn from the ticket
768         # use this to get the right slice credential 
769         ticket = SfaTicket(filename=ticket_file)
770         ticket.decode()
771         slice_hrn = ticket.gidObject.get_hrn()
772         #slice_hrn = ticket.attributes['slivers'][0]['hrn']
773         user_cred = self.get_user_cred()
774         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
775         
776         # get a list of node hostnames from the RSpec 
777         tree = etree.parse(StringIO(ticket.rspec))
778         root = tree.getroot()
779         hostnames = root.xpath("./network/site/node/hostname/text()")
780         
781         # create an xmlrpc connection to the component manager at each of these
782         # components and gall redeem_ticket
783         connections = {}
784         for hostname in hostnames:
785             try:
786                 print "Calling redeem_ticket at %(hostname)s " % locals(),
787                 server = self.get_server(hostname, CM_PORT, self.key_file, \
788                                          self.cert_file, self.options.debug)
789                 server.redeem_ticket(slice_cred, ticket.save_to_string(save_parents=True))
790                 print "Success"
791             except socket.gaierror:
792                 print "Failed:",
793                 print "Componet Manager not accepting requests" 
794             except Exception, e:
795                 print "Failed:", e.message
796         return
797  
798     # delete named slice
799     def delete(self, opts, args):
800         slice_hrn = args[0]
801         server = self.slicemgr
802         if opts.aggregate:
803             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
804                                      self.cert_file, self.options.debug)
805         # direct connection to the nodes component manager interface
806         if opts.component:
807             server = self.get_component_server_from_hrn(opts.component)
808         slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
809         return server.delete_slice(slice_cred, slice_hrn)
810     
811     # start named slice
812     def start(self, opts, args):
813         slice_hrn = args[0]
814         server = self.slicemgr
815         # direct connection to an aggregagte
816         if opts.aggregate:
817             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
818                                      self.cert_file, self.options.debug)
819         if opts.component:
820             server = self.get_component_server_from_hrn(opts.component)
821         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
822         return server.start_slice(slice_cred, slice_hrn)
823     
824     # stop named slice
825     def stop(self, opts, args):
826         slice_hrn = args[0]
827         server = self.slicemgr
828         # direct connection to an aggregate
829         if opts.aggregate:
830             server = self.get_server(opts.aggregate, opts.port, self.key_file, \
831                                      self.cert_file, self.options.debug)
832         # direct connection to the nodes component manager interface
833         if opts.component:
834             server = self.get_component_server_from_hrn(opts.component)
835         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
836         return server.stop_slice(slice_cred, slice_hrn)
837     
838     # reset named slice
839     def reset(self, opts, args):
840         slice_hrn = args[0]
841         server = self.slicemgr
842         # direct connection to the nodes component manager interface
843         if opts.component:
844             server = self.get_component_server_from_hrn(opts.component)
845         slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
846         return server.reset_slice(slice_cred, slice_hrn)
847
848
849     # =====================================================================
850     # GENI AM related calls
851     # =====================================================================
852
853     def GetVersion(self, opts, args):
854         server = self.get_server_from_opts(opts)
855         print server.GetVersion()
856
857     def ListResources(self, opts, args):
858         user_cred = self.get_user_cred().save_to_string(save_parents=True)
859         server = self.geni_am
860         call_options = {'geni_compressed': True}
861         xrn = None
862         cred = user_cred
863         if args:
864             xrn = args[0]
865             cred = self.get_slice_cred(xrn).save_to_string(save_parents=True)
866
867         if xrn:
868             call_options['geni_slice_urn'] = xrn
869             
870         rspec = server.ListResources([cred], call_options)
871         rspec = zlib.decompress(rspec.decode('base64'))
872         print rspec
873         
874     def CreateSliver(self, opts, args):
875         slice_xrn = args[0]
876         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
877         rspec_file = self.get_rspec_file(args[1])
878         rspec = open(rspec_file).read()
879         server = self.geni_am
880         return server.CreateSliver(slice_xrn, [slice_cred], rspec, [])
881     
882     def DeleteSliver(self, opts, args):
883         slice_xrn = args[0]
884         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
885         server = self.geni_am
886         return server.DeleteSliver(slice_xrn, [slice_cred])    
887
888     def SliverStatus(self, opts, args):
889         slice_xrn = args[0]
890         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
891         server = self.geni_am
892         print server.SliverStatus(slice_xrn, [slice_cred])
893     
894     def RenewSliver(self, opts, args):
895         slice_xrn = args[0]
896         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
897         time = args[1]
898         server = self.geni_am
899         return server.RenewSliver(slice_xrn, [slice_cred], time)   
900
901     def Shutdown(self, opts, args):
902         slice_xrn = args[0]
903         slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
904         server = self.geni_am
905         return server.Shutdown(slice_xrn, [slice_cred])         
906     
907     #
908     # Main: parse arguments and dispatch to command
909     #
910     def main(self):
911         parser = self.create_parser()
912         (options, args) = parser.parse_args()
913         self.options = options
914    
915         if options.hashrequest:
916             self.hashrequest = True
917  
918         if len(args) <= 0:
919             print "No command given. Use -h for help."
920             return - 1
921     
922         command = args[0]
923         (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
924         if self.options.verbose :
925             print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
926                                                                    options.sfi_dir, options.user,
927                                                                    options.auth)
928             print "Command %s" % command
929             if command in ("resources"):
930                 print "resources cmd_opts %s" % cmd_opts.format
931             elif command in ("list", "show", "remove"):
932                 print "cmd_opts.type %s" % cmd_opts.type
933             print "cmd_args %s" % cmd_args
934     
935         self.set_servers()
936     
937         try:
938             self.dispatch(command, cmd_opts, cmd_args)
939         except KeyError:
940             raise 
941             print "Command not found:", command
942             sys.exit(1)
943     
944         return
945     
946 if __name__ == "__main__":
947    Sfi().main()