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