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