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