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