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