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