3 # sfi -- slice-based facility interface
14 from lxml import etree
15 from StringIO import StringIO
16 from types import StringTypes, ListType
17 from optparse import OptionParser
18 from sfa.util.sfalogging import sfi_logger
19 from sfa.trust.certificate import Keypair, Certificate
20 from sfa.trust.gid import GID
21 from sfa.trust.credential import Credential
22 from sfa.util.sfaticket import SfaTicket
23 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
24 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
25 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
26 from sfa.util.config import Config
27 from sfa.util.version import version_core
28 from sfa.util.cache import Cache
29 from sfa.rspecs.rspec_version import RSpecVersion
30 from sfa.rspecs.pg_rspec import pg_rspec_request_version
35 # utility methods here
37 def display_rspec(rspec, format='rspec'):
39 tree = etree.parse(StringIO(rspec))
41 result = root.xpath("./network/site/node/hostname/text()")
42 elif format in ['ip']:
43 # The IP address is not yet part of the new RSpec
44 # so this doesn't do anything yet.
45 tree = etree.parse(StringIO(rspec))
47 result = root.xpath("./network/site/node/ipv4/text()")
54 def display_list(results):
55 for result in results:
58 def display_records(recordList, dump=False):
59 ''' Print all fields in the record'''
60 for record in recordList:
61 display_record(record, dump)
63 def display_record(record, dump=False):
67 info = record.getdict()
68 print "%s (%s)" % (info['hrn'], info['type'])
72 def filter_records(type, records):
74 for record in records:
75 if (record['type'] == type) or (type == "all"):
76 filtered_records.append(record)
77 return filtered_records
81 def save_rspec_to_file(rspec, filename):
82 if not filename.endswith(".rspec"):
83 filename = filename + ".rspec"
85 f = open(filename, 'w')
90 def save_records_to_file(filename, recordList):
92 for record in recordList:
94 save_record_to_file(filename + "." + str(index), record)
96 save_record_to_file(filename, record)
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)
109 record = SfaRecord(dict=record)
110 str = record.save_to_string()
111 file(filename, "w").write(str)
116 def load_record_from_file(filename):
117 str = file(filename, "r").read()
118 record = SfaRecord(string=str)
123 def unique_call_id(): return uuid.uuid4().urn
127 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
129 # dummy to meet Sfi's expectations for its 'options' field
130 # i.e. s/t we can do setattr on
134 def __init__ (self,options=None):
135 if options is None: options=Sfi.DummyOptions()
136 for opt in Sfi.required_options:
137 if not hasattr(options,opt): setattr(options,opt,None)
138 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
139 self.sfi_dir = options.sfi_dir
140 self.options = options
144 self.authority = None
145 self.hashrequest = False
146 self.logger = sfi_logger
148 def create_cmd_parser(self, command, additional_cmdargs=None):
149 cmdargs = {"list": "authority",
154 "aggregates": "[name]",
155 "registries": "[name]",
157 "get_trusted_certs": "cred",
159 "resources": "[name]",
160 "create": "name rspec",
161 "get_ticket": "name rspec",
162 "redeem_ticket": "ticket",
174 if additional_cmdargs:
175 cmdargs.update(additional_cmdargs)
177 if command not in cmdargs:
178 msg="Invalid command\n"
180 msg += ','.join(cmdargs.keys())
181 self.logger.critical(msg)
184 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
185 % (command, cmdargs[command]))
187 # user specifies remote aggregate/sm/component
188 if command in ("resources", "slices", "create", "delete", "start", "stop",
189 "restart", "shutdown", "get_ticket", "renew", "status"):
190 parser.add_option("-a", "--aggregate", dest="aggregate",
191 default=None, help="aggregate host")
192 parser.add_option("-p", "--port", dest="port",
193 default=AGGREGATE_PORT, help="aggregate port")
194 parser.add_option("-c", "--component", dest="component", default=None,
195 help="component hrn")
196 parser.add_option("-d", "--delegate", dest="delegate", default=None,
198 help="Include a credential delegated to the user's root"+\
199 "authority in set of credentials for this call")
201 # registy filter option
202 if command in ("list", "show", "remove"):
203 parser.add_option("-t", "--type", dest="type", type="choice",
204 help="type filter ([all]|user|slice|authority|node|aggregate)",
205 choices=("all", "user", "slice", "authority", "node", "aggregate"),
208 if command in ("resources"):
209 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
210 help="schema type and version of resulting RSpec")
211 parser.add_option("-f", "--format", dest="format", type="choice",
212 help="display format ([xml]|dns|ip)", default="xml",
213 choices=("xml", "dns", "ip"))
214 #panos: a new option to define the type of information about resources a user is interested in
215 parser.add_option("-i", "--info", dest="info",
216 help="optional component information", default=None)
219 if command in ("resources", "show", "list"):
220 parser.add_option("-o", "--output", dest="file",
221 help="output XML to file", metavar="FILE", default=None)
223 if command in ("show", "list"):
224 parser.add_option("-f", "--format", dest="format", type="choice",
225 help="display format ([text]|xml)", default="text",
226 choices=("text", "xml"))
228 if command in ("delegate"):
229 parser.add_option("-u", "--user",
230 action="store_true", dest="delegate_user", default=False,
231 help="delegate user credential")
232 parser.add_option("-s", "--slice", dest="delegate_slice",
233 help="delegate slice credential", metavar="HRN", default=None)
235 if command in ("version"):
236 parser.add_option("-a", "--aggregate", dest="aggregate",
237 default=None, help="aggregate host")
238 parser.add_option("-p", "--port", dest="port",
239 default=AGGREGATE_PORT, help="aggregate port")
240 parser.add_option("-R","--registry-version",
241 action="store_true", dest="version_registry", default=False,
242 help="probe registry version instead of slicemgr")
243 parser.add_option("-l","--local",
244 action="store_true", dest="version_local", default=False,
245 help="display version of the local client")
250 def create_parser(self):
252 # Generate command line parser
253 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
254 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
255 parser.add_option("-r", "--registry", dest="registry",
256 help="root registry", metavar="URL", default=None)
257 parser.add_option("-s", "--slicemgr", dest="sm",
258 help="slice manager", metavar="URL", default=None)
259 default_sfi_dir = os.path.expanduser("~/.sfi/")
260 parser.add_option("-d", "--dir", dest="sfi_dir",
261 help="config & working directory - default is " + default_sfi_dir,
262 metavar="PATH", default=default_sfi_dir)
263 parser.add_option("-u", "--user", dest="user",
264 help="user name", metavar="HRN", default=None)
265 parser.add_option("-a", "--auth", dest="auth",
266 help="authority name", metavar="HRN", default=None)
267 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
268 help="verbose mode - cumulative")
269 parser.add_option("-D", "--debug",
270 action="store_true", dest="debug", default=False,
271 help="Debug (xml-rpc) protocol messages")
272 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
273 help="RPC protocol (xmlrpc or soap)")
274 parser.add_option("-k", "--hashrequest",
275 action="store_true", dest="hashrequest", default=False,
276 help="Create a hash of the request that will be authenticated on the server")
277 parser.disable_interspersed_args()
282 def read_config(self):
283 config_file = self.options.sfi_dir + os.sep + "sfi_config"
285 config = Config (config_file)
287 self.logger.critical("Failed to read configuration file %s"%config_file)
288 self.logger.info("Make sure to remove the export clauses and to add quotes")
289 if self.options.verbose==0:
290 self.logger.info("Re-run with -v for more details")
292 self.logger.log_exc("Could not read config file %s"%config_file)
297 if (self.options.sm is not None):
298 self.sm_url = self.options.sm
299 elif hasattr(config, "SFI_SM"):
300 self.sm_url = config.SFI_SM
302 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
306 if (self.options.registry is not None):
307 self.reg_url = self.options.registry
308 elif hasattr(config, "SFI_REGISTRY"):
309 self.reg_url = config.SFI_REGISTRY
311 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
316 if (self.options.user is not None):
317 self.user = self.options.user
318 elif hasattr(config, "SFI_USER"):
319 self.user = config.SFI_USER
321 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
325 if (self.options.auth is not None):
326 self.authority = self.options.auth
327 elif hasattr(config, "SFI_AUTH"):
328 self.authority = config.SFI_AUTH
330 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
338 # Establish Connection to SliceMgr and Registry Servers
340 def set_servers(self):
343 # Get key and certificate
344 key_file = self.get_key_file()
345 cert_file = self.get_cert_file(key_file)
346 self.key = Keypair(filename=key_file)
347 self.key_file = key_file
348 self.cert_file = cert_file
349 self.cert = GID(filename=cert_file)
350 self.logger.info("Contacting Registry at: %s"%self.reg_url)
351 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
352 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
353 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, self.options)
356 def get_cached_server_version(self, server):
357 # check local cache first
360 cache_file = self.sfi_dir + os.path.sep + 'sfi_cache.dat'
361 cache_key = server.url + "-version"
363 cache = Cache(cache_file)
366 self.logger.info("Local cache not found at: %s" % cache_file)
369 version = cache.get(cache_key)
372 version = server.GetVersion()
373 # cache version for 24 hours
374 cache.add(cache_key, version, ttl= 60*60*24)
375 self.logger.info("Updating cache file %s" % cache_file)
376 cache.save_to_file(cache_file)
382 def server_supports_call_id_arg(self, server):
384 Returns true if server support the optional call_id arg, false otherwise.
386 server_version = self.get_cached_server_version(server)
387 if 'sfa' in server_version:
388 code_tag = server_version['code_tag']
389 code_tag_parts = code_tag.split("-")
391 version_parts = code_tag_parts[0].split(".")
392 major, minor = version_parts[0], version_parts[1]
393 rev = code_tag_parts[1]
395 if int(minor) > 0 or int(rev) > 20:
400 # Get various credential and spec files
402 # Establishes limiting conventions
403 # - conflates MAs and SAs
404 # - assumes last token in slice name is unique
406 # Bootstraps credentials
407 # - bootstrap user credential from self-signed certificate
408 # - bootstrap authority credential from user credential
409 # - bootstrap slice credential from user credential
413 def get_key_file(self):
414 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
415 if (os.path.isfile(file)):
418 self.logger.error("Key file %s does not exist"%file)
422 def get_cert_file(self, key_file):
424 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
425 if (os.path.isfile(cert_file)):
426 # we'd perfer to use Registry issued certs instead of self signed certs.
427 # if this is a Registry cert (GID) then we are done
428 gid = GID(filename=cert_file)
432 # generate self signed certificate
433 k = Keypair(filename=key_file)
434 cert = Certificate(subject=self.user)
436 cert.set_issuer(k, self.user)
438 self.logger.info("Writing self-signed certificate to %s"%cert_file)
439 cert.save_to_file(cert_file)
441 # try to get registry issued cert
443 self.logger.info("Getting Registry issued cert")
445 # *hack. need to set registyr before _get_gid() is called
446 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
447 gid = self._get_gid(type='user')
449 self.logger.info("Writing certificate to %s"%cert_file)
450 gid.save_to_file(cert_file)
452 self.logger.info("Failed to download Registry issued cert")
456 def get_cached_gid(self, file):
461 if (os.path.isfile(file)):
462 gid = GID(filename=file)
466 def get_gid(self, opts, args):
468 Get the specify gid and save it to file
473 gid = self._get_gid(hrn)
474 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
477 def _get_gid(self, hrn=None, type=None):
479 git_gid helper. Retrive the gid from the registry and save it to file.
485 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
487 gid = self.get_cached_gid(gidfile)
489 user_cred = self.get_user_cred()
490 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
492 raise RecordNotFound(args[0])
497 if type == rec['type']:
500 raise RecordNotFound(args[0])
502 gid = GID(string=record['gid'])
503 self.logger.info("Writing gid to %s"%gidfile)
504 gid.save_to_file(filename=gidfile)
508 def get_cached_credential(self, file):
510 Return a cached credential only if it hasn't expired.
512 if (os.path.isfile(file)):
513 credential = Credential(filename=file)
514 # make sure it isnt expired
515 if not credential.get_expiration or \
516 datetime.datetime.today() < credential.get_expiration():
520 def get_user_cred(self):
521 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
522 return self.get_cred(file, 'user', self.user)
524 def get_auth_cred(self):
525 if not self.authority:
526 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
528 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
529 return self.get_cred(file, 'authority', self.authority)
531 def get_slice_cred(self, name):
532 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
533 return self.get_cred(file, 'slice', name)
535 def get_cred(self, file, type, hrn):
536 # attempt to load a cached credential
537 cred = self.get_cached_credential(file)
540 cert_string = self.cert.save_to_string(save_parents=True)
541 user_name = self.user.replace(self.authority + ".", '')
542 if user_name.count(".") > 0:
543 user_name = user_name.replace(".", '_')
544 self.user = self.authority + "." + user_name
545 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
547 # bootstrap slice credential from user credential
548 user_cred = self.get_user_cred().save_to_string(save_parents=True)
549 cred_str = self.registry.GetCredential(user_cred, hrn, type)
552 self.logger.critical("Failed to get %s credential" % type)
555 cred = Credential(string=cred_str)
556 cred.save_to_file(file, save_parents=True)
557 self.logger.info("Writing %s credential to %s" %(type, file))
562 def get_rspec_file(self, rspec):
563 if (os.path.isabs(rspec)):
566 file = os.path.join(self.options.sfi_dir, rspec)
567 if (os.path.isfile(file)):
570 self.logger.critical("No such rspec file %s"%rspec)
573 def get_record_file(self, record):
574 if (os.path.isabs(record)):
577 file = os.path.join(self.options.sfi_dir, record)
578 if (os.path.isfile(file)):
581 self.logger.critical("No such registry record file %s"%record)
584 def load_publickey_string(self, fn):
586 key_string = f.read()
588 # if the filename is a private key file, then extract the public key
589 if "PRIVATE KEY" in key_string:
590 outfn = tempfile.mktemp()
591 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
594 key_string = f.read()
600 def get_component_server_from_hrn(self, hrn):
601 # direct connection to the nodes component manager interface
602 user_cred = self.get_user_cred().save_to_string(save_parents=True)
603 records = self.registry.Resolve(hrn, user_cred)
604 records = filter_records('node', records)
606 self.logger.warning("No such component:%r"% opts.component)
609 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
611 def get_server(self, host, port, keyfile, certfile):
613 Return an instance of an xmlrpc server connection
615 # port is appended onto the domain, before the path. Should look like:
616 # http://domain:port/path
617 host_parts = host.split('/')
618 host_parts[0] = host_parts[0] + ":" + str(port)
619 url = "http://%s" % "/".join(host_parts)
620 return xmlrpcprotocol.get_server(url, keyfile, certfile, self.options)
622 # xxx opts could be retrieved in self.options
623 def get_server_from_opts(self, opts):
625 Return instance of an xmlrpc connection to a slice manager, aggregate
626 or component server depending on the specified opts
628 server = self.slicemgr
629 # direct connection to an aggregate
630 if hasattr(opts, 'aggregate') and opts.aggregate:
631 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
632 # direct connection to the nodes component manager interface
633 if hasattr(opts, 'component') and opts.component:
634 server = self.get_component_server_from_hrn(opts.component)
637 #==========================================================================
638 # Following functions implement the commands
640 # Registry-related commands
641 #==========================================================================
643 def dispatch(self, command, cmd_opts, cmd_args):
644 return getattr(self, command)(cmd_opts, cmd_args)
646 # list entires in named authority registry
647 def list(self, opts, args):
652 user_cred = self.get_user_cred().save_to_string(save_parents=True)
654 list = self.registry.List(hrn, user_cred)
656 raise Exception, "Not enough parameters for the 'list' command"
658 # filter on person, slice, site, node, etc.
659 # THis really should be in the self.filter_records funct def comment...
660 list = filter_records(opts.type, list)
662 print "%s (%s)" % (record['hrn'], record['type'])
665 if not file.startswith(os.sep):
666 file = os.path.join(self.options.sfi_dir, file)
667 save_records_to_file(file, list)
670 # show named registry record
671 def show(self, opts, args):
676 user_cred = self.get_user_cred().save_to_string(save_parents=True)
677 records = self.registry.Resolve(hrn, user_cred)
678 records = filter_records(opts.type, records)
680 print "No record of type", opts.type
681 for record in records:
682 if record['type'] in ['user']:
683 record = UserRecord(dict=record)
684 elif record['type'] in ['slice']:
685 record = SliceRecord(dict=record)
686 elif record['type'] in ['node']:
687 record = NodeRecord(dict=record)
688 elif record['type'].startswith('authority'):
689 record = AuthorityRecord(dict=record)
691 record = SfaRecord(dict=record)
692 if (opts.format == "text"):
695 print record.save_to_string()
699 if not file.startswith(os.sep):
700 file = os.path.join(self.options.sfi_dir, file)
701 save_records_to_file(file, records)
704 def delegate(self, opts, args):
706 delegee_hrn = args[0]
707 if opts.delegate_user:
708 user_cred = self.get_user_cred()
709 cred = self.delegate_cred(user_cred, delegee_hrn)
710 elif opts.delegate_slice:
711 slice_cred = self.get_slice_cred(opts.delegate_slice)
712 cred = self.delegate_cred(slice_cred, delegee_hrn)
714 self.logger.warning("Must specify either --user or --slice <hrn>")
716 delegated_cred = Credential(string=cred)
717 object_hrn = delegated_cred.get_gid_object().get_hrn()
718 if opts.delegate_user:
719 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
720 + get_leaf(object_hrn) + ".cred")
721 elif opts.delegate_slice:
722 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
723 + get_leaf(object_hrn) + ".cred")
725 delegated_cred.save_to_file(dest_fn, save_parents=True)
727 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
729 def delegate_cred(self, object_cred, hrn):
730 # the gid and hrn of the object we are delegating
731 if isinstance(object_cred, str):
732 object_cred = Credential(string=object_cred)
733 object_gid = object_cred.get_gid_object()
734 object_hrn = object_gid.get_hrn()
736 if not object_cred.get_privileges().get_all_delegate():
737 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
740 # the delegating user's gid
741 caller_gid = self._get_gid(self.user)
742 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
744 # the gid of the user who will be delegated to
745 delegee_gid = self._get_gid(hrn)
746 delegee_hrn = delegee_gid.get_hrn()
747 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
748 delegee_gid.save_to_file(filename=delegee_gidfile)
749 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
750 return dcred.save_to_string(save_parents=True)
752 # removed named registry record
753 # - have to first retrieve the record to be removed
754 def remove(self, opts, args):
755 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
763 return self.registry.Remove(hrn, auth_cred, type)
765 # add named registry record
766 def add(self, opts, args):
767 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
771 record_filepath = args[0]
772 rec_file = self.get_record_file(record_filepath)
773 record = load_record_from_file(rec_file).as_dict()
774 return self.registry.Register(record, auth_cred)
776 # update named registry entry
777 def update(self, opts, args):
778 user_cred = self.get_user_cred()
782 rec_file = self.get_record_file(args[0])
783 record = load_record_from_file(rec_file)
784 if record['type'] == "user":
785 if record.get_name() == user_cred.get_gid_object().get_hrn():
786 cred = user_cred.save_to_string(save_parents=True)
788 cred = self.get_auth_cred().save_to_string(save_parents=True)
789 elif record['type'] in ["slice"]:
791 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
792 except xmlrpcprotocol.ServerException, e:
793 # XXX smbaker -- once we have better error return codes, update this
794 # to do something better than a string compare
795 if "Permission error" in e.args[0]:
796 cred = self.get_auth_cred().save_to_string(save_parents=True)
799 elif record.get_type() in ["authority"]:
800 cred = self.get_auth_cred().save_to_string(save_parents=True)
801 elif record.get_type() == 'node':
802 cred = self.get_auth_cred().save_to_string(save_parents=True)
804 raise "unknown record type" + record.get_type()
805 record = record.as_dict()
806 return self.registry.Update(record, cred)
808 def get_trusted_certs(self, opts, args):
810 return uhe trusted certs at this interface
812 trusted_certs = self.registry.get_trusted_certs()
813 for trusted_cert in trusted_certs:
814 gid = GID(string=trusted_cert)
816 cert = Certificate(string=trusted_cert)
817 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
820 def aggregates(self, opts, args):
822 return a list of details about known aggregates
824 user_cred = self.get_user_cred().save_to_string(save_parents=True)
829 result = self.registry.get_aggregates(user_cred, hrn)
833 def registries(self, opts, args):
835 return a list of details about known registries
837 user_cred = self.get_user_cred().save_to_string(save_parents=True)
841 result = self.registry.get_registries(user_cred, hrn)
846 # ==================================================================
847 # Slice-related commands
848 # ==================================================================
850 def version(self, opts, args):
851 if opts.version_local:
852 version=version_core()
854 if opts.version_registry:
857 server = self.get_server_from_opts(opts)
858 version=server.GetVersion()
859 for (k,v) in version.iteritems():
860 print "%-20s: %s"%(k,v)
862 # list instantiated slices
863 def slices(self, opts, args):
865 list instantiated slices
867 user_cred = self.get_user_cred().save_to_string(save_parents=True)
870 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
871 creds.append(delegated_cred)
872 server = self.get_server_from_opts(opts)
873 #results = server.ListSlices(creds, unique_call_id())
874 results = server.ListSlices(creds)
875 display_list(results)
878 # show rspec for named slice
879 def resources(self, opts, args):
880 user_cred = self.get_user_cred().save_to_string(save_parents=True)
881 server = self.slicemgr
883 server = self.get_server_from_opts(opts)
886 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
888 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
895 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
896 creds.append(delegated_cred)
897 if opts.rspec_version:
898 server_version = self.get_cached_server_version(server)
899 if 'sfa' in server_version:
900 # just request the version the client wants
901 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
903 # this must be a protogeni aggregate. We should request a v2 ad rspec
904 # regardless of what the client user requested
905 call_options['rspec_version'] = dict(pg_rspec_request_version)
906 #panos add info options
908 call_options['info'] = opts.info
910 call_args = [creds, call_options]
911 if self.server_supports_call_id_arg(server):
912 call_args.append(unique_call_id())
913 result = server.ListResources(*call_args)
915 if opts.file is None:
916 display_rspec(result, format)
919 if not file.startswith(os.sep):
920 file = os.path.join(self.options.sfi_dir, file)
921 save_rspec_to_file(result, file)
924 # created named slice with given rspec
925 def create(self, opts, args):
927 slice_urn = hrn_to_urn(slice_hrn, 'slice')
928 user_cred = self.get_user_cred()
929 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
932 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
933 creds.append(delegated_cred)
934 rspec_file = self.get_rspec_file(args[1])
935 rspec = open(rspec_file).read()
938 # { urn: urn:publicid:IDN+emulab.net+user+alice
939 # keys: [<ssh key A>, <ssh key B>]
942 server = self.get_server_from_opts(opts)
943 version = server.GetVersion()
944 if 'sfa' not in version:
945 # need to pass along user keys if this request is going to a ProtoGENI aggregate
946 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
947 # request. So we will only pass in one user that contains the keys for all
949 user = {'urn': user_cred.get_gid_caller().get_urn(),
951 slice_record = self.registry.Resolve(slice_urn, creds)
952 if slice_record and 'researchers' in slice_record:
953 user_hrns = slice_record['researchers']
954 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
955 user_records = self.registry.Resolve(user_urns, creds)
956 for user_record in user_records:
957 if 'keys' in user_record:
958 user['keys'].extend(user_record['keys'])
961 call_args = [slice_urn, creds, rspec, users]
962 if self.server_supports_call_id_arg(server):
963 call_args.append(unique_call_id())
965 result = server.CreateSliver(*call_args)
969 # get a ticket for the specified slice
970 def get_ticket(self, opts, args):
971 slice_hrn, rspec_path = args[0], args[1]
972 slice_urn = hrn_to_urn(slice_hrn, 'slice')
973 user_cred = self.get_user_cred()
974 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
977 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
978 creds.append(delegated_cred)
979 rspec_file = self.get_rspec_file(rspec_path)
980 rspec = open(rspec_file).read()
981 server = self.get_server_from_opts(opts)
982 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
983 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
984 self.logger.info("writing ticket to %s"%file)
985 ticket = SfaTicket(string=ticket_string)
986 ticket.save_to_file(filename=file, save_parents=True)
988 def redeem_ticket(self, opts, args):
989 ticket_file = args[0]
991 # get slice hrn from the ticket
992 # use this to get the right slice credential
993 ticket = SfaTicket(filename=ticket_file)
995 slice_hrn = ticket.gidObject.get_hrn()
996 slice_urn = hrn_to_urn(slice_hrn, 'slice')
997 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
998 user_cred = self.get_user_cred()
999 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1001 # get a list of node hostnames from the RSpec
1002 tree = etree.parse(StringIO(ticket.rspec))
1003 root = tree.getroot()
1004 hostnames = root.xpath("./network/site/node/hostname/text()")
1006 # create an xmlrpc connection to the component manager at each of these
1007 # components and gall redeem_ticket
1009 for hostname in hostnames:
1011 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1012 server = self.get_server(hostname, CM_PORT, self.key_file, \
1013 self.cert_file, self.options.debug)
1014 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1015 self.logger.info("Success")
1016 except socket.gaierror:
1017 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1018 except Exception, e:
1019 self.logger.log_exc(e.message)
1022 # delete named slice
1023 def delete(self, opts, args):
1025 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1026 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1027 creds = [slice_cred]
1029 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1030 creds.append(delegated_cred)
1031 server = self.get_server_from_opts(opts)
1033 call_args = [slice_urn, creds]
1034 if self.server_supports_call_id_arg(server):
1035 call_args.append(unique_call_id())
1036 return server.DeleteSliver(*call_args)
1039 def start(self, opts, args):
1041 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1042 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1043 creds = [slice_cred]
1045 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1046 creds.append(delegated_cred)
1047 server = self.get_server_from_opts(opts)
1048 return server.Start(slice_urn, creds)
1051 def stop(self, opts, args):
1053 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1054 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1055 creds = [slice_cred]
1057 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1058 creds.append(delegated_cred)
1059 server = self.get_server_from_opts(opts)
1060 return server.Stop(slice_urn, creds)
1063 def reset(self, opts, args):
1065 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1066 server = self.get_server_from_opts(opts)
1067 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1068 creds = [slice_cred]
1070 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1071 creds.append(delegated_cred)
1072 return server.reset_slice(creds, slice_urn)
1074 def renew(self, opts, args):
1076 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1077 server = self.get_server_from_opts(opts)
1078 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1079 creds = [slice_cred]
1081 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1082 creds.append(delegated_cred)
1085 call_args = [slice_urn, creds, time]
1086 if self.server_supports_call_id_arg(server):
1087 call_args.append(unique_call_id())
1088 return server.RenewSliver(*call_args)
1091 def status(self, opts, args):
1093 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1094 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1095 creds = [slice_cred]
1097 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1098 creds.append(delegated_cred)
1099 server = self.get_server_from_opts(opts)
1100 call_args = [slice_urn, creds]
1101 if self.server_supports_call_id_arg(server):
1102 call_args.append(unique_call_id())
1103 print server.SliverStatus(*call_args)
1106 def shutdown(self, opts, args):
1108 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1109 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1110 creds = [slice_cred]
1112 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1113 creds.append(delegated_cred)
1114 server = self.get_server_from_opts(opts)
1115 return server.Shutdown(slice_urn, creds)
1117 def print_help (self):
1118 self.sfi_parser.print_help()
1119 self.cmd_parser.print_help()
1122 # Main: parse arguments and dispatch to command
1125 self.sfi_parser = self.create_parser()
1126 (options, args) = self.sfi_parser.parse_args()
1127 self.options = options
1129 self.logger.setLevelFromOptVerbose(self.options.verbose)
1130 if options.hashrequest:
1131 self.hashrequest = True
1134 self.logger.critical("No command given. Use -h for help.")
1138 self.cmd_parser = self.create_cmd_parser(command)
1139 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1142 self.logger.info("Command=%s" % command)
1143 if command in ("resources"):
1144 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1145 elif command in ("list", "show", "remove"):
1146 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1147 self.logger.debug('cmd_args %s' % cmd_args)
1150 self.dispatch(command, cmd_opts, cmd_args)
1152 self.logger.critical ("Unknown command %s"%command)
1157 if __name__ == "__main__":