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 info_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
33 # utility methods here
35 def display_rspec(rspec, format='rspec'):
37 tree = etree.parse(StringIO(rspec))
39 result = root.xpath("./network/site/node/hostname/text()")
40 elif format in ['ip']:
41 # The IP address is not yet part of the new RSpec
42 # so this doesn't do anything yet.
43 tree = etree.parse(StringIO(rspec))
45 result = root.xpath("./network/site/node/ipv4/text()")
52 def display_list(results):
53 for result in results:
56 def display_records(recordList, dump=False):
57 ''' Print all fields in the record'''
58 for record in recordList:
59 display_record(record, dump)
61 def display_record(record, dump=False):
65 info = record.getdict()
66 print "%s (%s)" % (info['hrn'], info['type'])
70 def filter_records(type, records):
72 for record in records:
73 if (record['type'] == type) or (type == "all"):
74 filtered_records.append(record)
75 return filtered_records
79 def save_rspec_to_file(rspec, filename):
80 if not filename.endswith(".rspec"):
81 filename = filename + ".rspec"
83 f = open(filename, 'w')
88 def save_records_to_file(filename, recordList):
90 for record in recordList:
92 save_record_to_file(filename + "." + str(index), record)
94 save_record_to_file(filename, record)
97 def save_record_to_file(filename, record):
98 if record['type'] in ['user']:
99 record = UserRecord(dict=record)
100 elif record['type'] in ['slice']:
101 record = SliceRecord(dict=record)
102 elif record['type'] in ['node']:
103 record = NodeRecord(dict=record)
104 elif record['type'] in ['authority', 'ma', 'sa']:
105 record = AuthorityRecord(dict=record)
107 record = SfaRecord(dict=record)
108 str = record.save_to_string()
109 file(filename, "w").write(str)
114 def load_record_from_file(filename):
115 str = file(filename, "r").read()
116 record = SfaRecord(string=str)
121 def unique_call_id(): return uuid.uuid4().urn
125 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
127 # dummy to meet Sfi's expectations for its 'options' field
128 # i.e. s/t we can do setattr on
132 def __init__ (self,options=None):
133 if options is None: options=Sfi.DummyOptions()
134 for opt in Sfi.required_options:
135 if not hasattr(options,opt): setattr(options,opt,None)
136 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
137 self.sfi_dir = options.sfi_dir
138 self.options = options
142 self.authority = None
143 self.hashrequest = False
144 self.logger = info_logger
146 def create_cmd_parser(self, command, additional_cmdargs=None):
147 cmdargs = {"list": "authority",
152 "aggregates": "[name]",
153 "registries": "[name]",
155 "get_trusted_certs": "cred",
157 "resources": "[name]",
158 "create": "name rspec",
159 "get_ticket": "name rspec",
160 "redeem_ticket": "ticket",
172 if additional_cmdargs:
173 cmdargs.update(additional_cmdargs)
175 if command not in cmdargs:
176 msg="Invalid command\n"
178 msg += ','.join(cmdargs.keys())
179 self.logger.critical(msg)
182 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
183 % (command, cmdargs[command]))
185 # user specifies remote aggregate/sm/component
186 if command in ("resources", "slices", "create", "delete", "start", "stop",
187 "restart", "shutdown", "get_ticket", "renew", "status"):
188 parser.add_option("-a", "--aggregate", dest="aggregate",
189 default=None, help="aggregate host")
190 parser.add_option("-p", "--port", dest="port",
191 default=AGGREGATE_PORT, help="aggregate port")
192 parser.add_option("-c", "--component", dest="component", default=None,
193 help="component hrn")
194 parser.add_option("-d", "--delegate", dest="delegate", default=None,
196 help="Include a credential delegated to the user's root"+\
197 "authority in set of credentials for this call")
199 # registy filter option
200 if command in ("list", "show", "remove"):
201 parser.add_option("-t", "--type", dest="type", type="choice",
202 help="type filter ([all]|user|slice|authority|node|aggregate)",
203 choices=("all", "user", "slice", "authority", "node", "aggregate"),
206 if command in ("resources"):
207 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
208 help="schema type and version of resulting RSpec")
209 parser.add_option("-f", "--format", dest="format", type="choice",
210 help="display format ([xml]|dns|ip)", default="xml",
211 choices=("xml", "dns", "ip"))
212 #panos: a new option to define the type of information about resources a user is interested in
213 parser.add_option("-i", "--info", dest="info",
214 help="optional component information", default=None)
217 if command in ("resources", "show", "list"):
218 parser.add_option("-o", "--output", dest="file",
219 help="output XML to file", metavar="FILE", default=None)
221 if command in ("show", "list"):
222 parser.add_option("-f", "--format", dest="format", type="choice",
223 help="display format ([text]|xml)", default="text",
224 choices=("text", "xml"))
226 if command in ("delegate"):
227 parser.add_option("-u", "--user",
228 action="store_true", dest="delegate_user", default=False,
229 help="delegate user credential")
230 parser.add_option("-s", "--slice", dest="delegate_slice",
231 help="delegate slice credential", metavar="HRN", default=None)
233 if command in ("version"):
234 parser.add_option("-a", "--aggregate", dest="aggregate",
235 default=None, help="aggregate host")
236 parser.add_option("-p", "--port", dest="port",
237 default=AGGREGATE_PORT, help="aggregate port")
238 parser.add_option("-R","--registry-version",
239 action="store_true", dest="version_registry", default=False,
240 help="probe registry version instead of slicemgr")
241 parser.add_option("-l","--local",
242 action="store_true", dest="version_local", default=False,
243 help="display version of the local client")
248 def create_parser(self):
250 # Generate command line parser
251 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
252 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
253 parser.add_option("-r", "--registry", dest="registry",
254 help="root registry", metavar="URL", default=None)
255 parser.add_option("-s", "--slicemgr", dest="sm",
256 help="slice manager", metavar="URL", default=None)
257 default_sfi_dir = os.path.expanduser("~/.sfi/")
258 parser.add_option("-d", "--dir", dest="sfi_dir",
259 help="config & working directory - default is " + default_sfi_dir,
260 metavar="PATH", default=default_sfi_dir)
261 parser.add_option("-u", "--user", dest="user",
262 help="user name", metavar="HRN", default=None)
263 parser.add_option("-a", "--auth", dest="auth",
264 help="authority name", metavar="HRN", default=None)
265 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
266 help="verbose mode - cumulative")
267 parser.add_option("-D", "--debug",
268 action="store_true", dest="debug", default=False,
269 help="Debug (xml-rpc) protocol messages")
270 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
271 help="RPC protocol (xmlrpc or soap)")
272 parser.add_option("-k", "--hashrequest",
273 action="store_true", dest="hashrequest", default=False,
274 help="Create a hash of the request that will be authenticated on the server")
275 parser.disable_interspersed_args()
280 def read_config(self):
281 config_file = self.options.sfi_dir + os.sep + "sfi_config"
283 config = Config (config_file)
285 self.logger.critical("Failed to read configuration file %s"%config_file)
286 self.logger.info("Make sure to remove the export clauses and to add quotes")
287 if self.options.verbose==0:
288 self.logger.info("Re-run with -v for more details")
290 self.logger.log_exc("Could not read config file %s"%config_file)
295 if (self.options.sm is not None):
296 self.sm_url = self.options.sm
297 elif hasattr(config, "SFI_SM"):
298 self.sm_url = config.SFI_SM
300 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
304 if (self.options.registry is not None):
305 self.reg_url = self.options.registry
306 elif hasattr(config, "SFI_REGISTRY"):
307 self.reg_url = config.SFI_REGISTRY
309 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
314 if (self.options.user is not None):
315 self.user = self.options.user
316 elif hasattr(config, "SFI_USER"):
317 self.user = config.SFI_USER
319 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
323 if (self.options.auth is not None):
324 self.authority = self.options.auth
325 elif hasattr(config, "SFI_AUTH"):
326 self.authority = config.SFI_AUTH
328 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
336 # Establish Connection to SliceMgr and Registry Servers
338 def set_servers(self):
341 # Get key and certificate
342 key_file = self.get_key_file()
343 cert_file = self.get_cert_file(key_file)
344 self.key = Keypair(filename=key_file)
345 self.key_file = key_file
346 self.cert_file = cert_file
347 self.cert = GID(filename=cert_file)
348 self.logger.info("Contacting Registry at: %s"%self.reg_url)
349 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
350 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
351 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, self.options)
354 def get_cached_server_version(self, server):
355 # check local cache first
358 cache_file = self.sfi_dir + os.path.sep + 'sfi_cache.dat'
359 cache_key = server.url + "-version"
361 cache = Cache(cache_file)
364 self.logger.info("Local cache not found at: %s" % cache_file)
367 version = cache.get(cache_key)
370 version = server.GetVersion()
371 # cache version for 24 hours
372 cache.add(cache_key, version, ttl= 60*60*24)
378 def server_supports_call_id_arg(self, server):
380 Returns true if server support the optional call_id arg, false otherwise.
382 server_version = self.get_cached_server_version(server)
383 if 'sfa' in server_version:
384 code_tag = server_version['code_tag']
385 code_tag_parts = code_tag.split("-")
387 version_parts = code_tag_parts[0].split(".")
388 major, minor = version_parts[0], version_parts[1]
389 rev = code_tag_parts[1]
391 if int(minor) > 0 or int(rev) > 20:
396 # Get various credential and spec files
398 # Establishes limiting conventions
399 # - conflates MAs and SAs
400 # - assumes last token in slice name is unique
402 # Bootstraps credentials
403 # - bootstrap user credential from self-signed certificate
404 # - bootstrap authority credential from user credential
405 # - bootstrap slice credential from user credential
409 def get_key_file(self):
410 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
411 if (os.path.isfile(file)):
414 self.logger.error("Key file %s does not exist"%file)
418 def get_cert_file(self, key_file):
420 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
421 if (os.path.isfile(cert_file)):
422 # we'd perfer to use Registry issued certs instead of self signed certs.
423 # if this is a Registry cert (GID) then we are done
424 gid = GID(filename=cert_file)
428 # generate self signed certificate
429 k = Keypair(filename=key_file)
430 cert = Certificate(subject=self.user)
432 cert.set_issuer(k, self.user)
434 self.logger.info("Writing self-signed certificate to %s"%cert_file)
435 cert.save_to_file(cert_file)
437 # try to get registry issued cert
439 self.logger.info("Getting Registry issued cert")
441 # *hack. need to set registyr before _get_gid() is called
442 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
443 gid = self._get_gid(type='user')
445 self.logger.info("Writing certificate to %s"%cert_file)
446 gid.save_to_file(cert_file)
448 self.logger.info("Failed to download Registry issued cert")
452 def get_cached_gid(self, file):
457 if (os.path.isfile(file)):
458 gid = GID(filename=file)
462 def get_gid(self, opts, args):
464 Get the specify gid and save it to file
469 gid = self._get_gid(hrn)
470 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
473 def _get_gid(self, hrn=None, type=None):
475 git_gid helper. Retrive the gid from the registry and save it to file.
481 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
483 gid = self.get_cached_gid(gidfile)
485 user_cred = self.get_user_cred()
486 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
488 raise RecordNotFound(args[0])
493 if type == rec['type']:
496 raise RecordNotFound(args[0])
498 gid = GID(string=record['gid'])
499 self.logger.info("Writing gid to %s"%gidfile)
500 gid.save_to_file(filename=gidfile)
504 def get_cached_credential(self, file):
506 Return a cached credential only if it hasn't expired.
508 if (os.path.isfile(file)):
509 credential = Credential(filename=file)
510 # make sure it isnt expired
511 if not credential.get_expiration or \
512 datetime.datetime.today() < credential.get_expiration():
516 def get_user_cred(self):
517 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
518 return self.get_cred(file, 'user', self.user)
520 def get_auth_cred(self):
521 if not self.authority:
522 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
524 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
525 return self.get_cred(file, 'authority', self.authority)
527 def get_slice_cred(self, name):
528 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
529 return self.get_cred(file, 'slice', name)
531 def get_cred(self, file, type, hrn):
532 # attempt to load a cached credential
533 cred = self.get_cached_credential(file)
536 cert_string = self.cert.save_to_string(save_parents=True)
537 user_name = self.user.replace(self.authority + ".", '')
538 if user_name.count(".") > 0:
539 user_name = user_name.replace(".", '_')
540 self.user = self.authority + "." + user_name
541 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
543 # bootstrap slice credential from user credential
544 user_cred = self.get_user_cred().save_to_string(save_parents=True)
545 cred_str = self.registry.GetCredential(user_cred, hrn, type)
548 self.logger.critical("Failed to get %s credential" % type)
551 cred = Credential(string=cred_str)
552 cred.save_to_file(file, save_parents=True)
553 self.logger.info("Writing %s credential to %s" %(type, file))
558 def get_rspec_file(self, rspec):
559 if (os.path.isabs(rspec)):
562 file = os.path.join(self.options.sfi_dir, rspec)
563 if (os.path.isfile(file)):
566 self.logger.critical("No such rspec file %s"%rspec)
569 def get_record_file(self, record):
570 if (os.path.isabs(record)):
573 file = os.path.join(self.options.sfi_dir, record)
574 if (os.path.isfile(file)):
577 self.logger.critical("No such registry record file %s"%record)
580 def load_publickey_string(self, fn):
582 key_string = f.read()
584 # if the filename is a private key file, then extract the public key
585 if "PRIVATE KEY" in key_string:
586 outfn = tempfile.mktemp()
587 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
590 key_string = f.read()
596 def get_component_server_from_hrn(self, hrn):
597 # direct connection to the nodes component manager interface
598 user_cred = self.get_user_cred().save_to_string(save_parents=True)
599 records = self.registry.Resolve(hrn, user_cred)
600 records = filter_records('node', records)
602 self.logger.warning("No such component:%r"% opts.component)
605 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
607 def get_server(self, host, port, keyfile, certfile):
609 Return an instance of an xmlrpc server connection
611 # port is appended onto the domain, before the path. Should look like:
612 # http://domain:port/path
613 host_parts = host.split('/')
614 host_parts[0] = host_parts[0] + ":" + str(port)
615 url = "http://%s" % "/".join(host_parts)
616 return xmlrpcprotocol.get_server(url, keyfile, certfile, self.options)
618 # xxx opts could be retrieved in self.options
619 def get_server_from_opts(self, opts):
621 Return instance of an xmlrpc connection to a slice manager, aggregate
622 or component server depending on the specified opts
624 server = self.slicemgr
625 # direct connection to an aggregate
626 if hasattr(opts, 'aggregate') and opts.aggregate:
627 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
628 # direct connection to the nodes component manager interface
629 if hasattr(opts, 'component') and opts.component:
630 server = self.get_component_server_from_hrn(opts.component)
633 #==========================================================================
634 # Following functions implement the commands
636 # Registry-related commands
637 #==========================================================================
639 def dispatch(self, command, cmd_opts, cmd_args):
640 return getattr(self, command)(cmd_opts, cmd_args)
642 # list entires in named authority registry
643 def list(self, opts, args):
648 user_cred = self.get_user_cred().save_to_string(save_parents=True)
650 list = self.registry.List(hrn, user_cred)
652 raise Exception, "Not enough parameters for the 'list' command"
654 # filter on person, slice, site, node, etc.
655 # THis really should be in the self.filter_records funct def comment...
656 list = filter_records(opts.type, list)
658 print "%s (%s)" % (record['hrn'], record['type'])
661 if not file.startswith(os.sep):
662 file = os.path.join(self.options.sfi_dir, file)
663 save_records_to_file(file, list)
666 # show named registry record
667 def show(self, opts, args):
672 user_cred = self.get_user_cred().save_to_string(save_parents=True)
673 records = self.registry.Resolve(hrn, user_cred)
674 records = filter_records(opts.type, records)
676 print "No record of type", opts.type
677 for record in records:
678 if record['type'] in ['user']:
679 record = UserRecord(dict=record)
680 elif record['type'] in ['slice']:
681 record = SliceRecord(dict=record)
682 elif record['type'] in ['node']:
683 record = NodeRecord(dict=record)
684 elif record['type'].startswith('authority'):
685 record = AuthorityRecord(dict=record)
687 record = SfaRecord(dict=record)
688 if (opts.format == "text"):
691 print record.save_to_string()
695 if not file.startswith(os.sep):
696 file = os.path.join(self.options.sfi_dir, file)
697 save_records_to_file(file, records)
700 def delegate(self, opts, args):
702 delegee_hrn = args[0]
703 if opts.delegate_user:
704 user_cred = self.get_user_cred()
705 cred = self.delegate_cred(user_cred, delegee_hrn)
706 elif opts.delegate_slice:
707 slice_cred = self.get_slice_cred(opts.delegate_slice)
708 cred = self.delegate_cred(slice_cred, delegee_hrn)
710 self.logger.warning("Must specify either --user or --slice <hrn>")
712 delegated_cred = Credential(string=cred)
713 object_hrn = delegated_cred.get_gid_object().get_hrn()
714 if opts.delegate_user:
715 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
716 + get_leaf(object_hrn) + ".cred")
717 elif opts.delegate_slice:
718 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
719 + get_leaf(object_hrn) + ".cred")
721 delegated_cred.save_to_file(dest_fn, save_parents=True)
723 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
725 def delegate_cred(self, object_cred, hrn):
726 # the gid and hrn of the object we are delegating
727 if isinstance(object_cred, str):
728 object_cred = Credential(string=object_cred)
729 object_gid = object_cred.get_gid_object()
730 object_hrn = object_gid.get_hrn()
732 if not object_cred.get_privileges().get_all_delegate():
733 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
736 # the delegating user's gid
737 caller_gid = self._get_gid(self.user)
738 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
740 # the gid of the user who will be delegated to
741 delegee_gid = self._get_gid(hrn)
742 delegee_hrn = delegee_gid.get_hrn()
743 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
744 delegee_gid.save_to_file(filename=delegee_gidfile)
745 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
746 return dcred.save_to_string(save_parents=True)
748 # removed named registry record
749 # - have to first retrieve the record to be removed
750 def remove(self, opts, args):
751 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
759 return self.registry.Remove(hrn, auth_cred, type)
761 # add named registry record
762 def add(self, opts, args):
763 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
767 record_filepath = args[0]
768 rec_file = self.get_record_file(record_filepath)
769 record = load_record_from_file(rec_file).as_dict()
770 return self.registry.Register(record, auth_cred)
772 # update named registry entry
773 def update(self, opts, args):
774 user_cred = self.get_user_cred()
778 rec_file = self.get_record_file(args[0])
779 record = load_record_from_file(rec_file)
780 if record['type'] == "user":
781 if record.get_name() == user_cred.get_gid_object().get_hrn():
782 cred = user_cred.save_to_string(save_parents=True)
784 cred = self.get_auth_cred().save_to_string(save_parents=True)
785 elif record['type'] in ["slice"]:
787 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
788 except xmlrpcprotocol.ServerException, e:
789 # XXX smbaker -- once we have better error return codes, update this
790 # to do something better than a string compare
791 if "Permission error" in e.args[0]:
792 cred = self.get_auth_cred().save_to_string(save_parents=True)
795 elif record.get_type() in ["authority"]:
796 cred = self.get_auth_cred().save_to_string(save_parents=True)
797 elif record.get_type() == 'node':
798 cred = self.get_auth_cred().save_to_string(save_parents=True)
800 raise "unknown record type" + record.get_type()
801 record = record.as_dict()
802 return self.registry.Update(record, cred)
804 def get_trusted_certs(self, opts, args):
806 return uhe trusted certs at this interface
808 trusted_certs = self.registry.get_trusted_certs()
809 for trusted_cert in trusted_certs:
810 gid = GID(string=trusted_cert)
812 cert = Certificate(string=trusted_cert)
813 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
816 def aggregates(self, opts, args):
818 return a list of details about known aggregates
820 user_cred = self.get_user_cred().save_to_string(save_parents=True)
825 result = self.registry.get_aggregates(user_cred, hrn)
829 def registries(self, opts, args):
831 return a list of details about known registries
833 user_cred = self.get_user_cred().save_to_string(save_parents=True)
837 result = self.registry.get_registries(user_cred, hrn)
842 # ==================================================================
843 # Slice-related commands
844 # ==================================================================
846 def version(self, opts, args):
847 if opts.version_local:
848 version=version_core()
850 if opts.version_registry:
853 server = self.get_server_from_opts(opts)
854 version=server.GetVersion()
855 for (k,v) in version.iteritems():
856 print "%-20s: %s"%(k,v)
858 # list instantiated slices
859 def slices(self, opts, args):
861 list instantiated slices
863 user_cred = self.get_user_cred().save_to_string(save_parents=True)
866 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
867 creds.append(delegated_cred)
868 server = self.get_server_from_opts(opts)
869 #results = server.ListSlices(creds, unique_call_id())
870 results = server.ListSlices(creds)
871 display_list(results)
874 # show rspec for named slice
875 def resources(self, opts, args):
876 user_cred = self.get_user_cred().save_to_string(save_parents=True)
877 server = self.slicemgr
879 server = self.get_server_from_opts(opts)
882 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
884 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
891 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
892 creds.append(delegated_cred)
893 if opts.rspec_version:
894 call_options['rspec_version'] = opts.rspec_version
895 #panos add info options
897 call_options['info'] = opts.info
899 call_args = [creds, call_options]
900 if self.server_supports_call_id_arg(server):
901 call_args.append(unique_call_id())
902 result = server.ListResources(*call_args)
904 if opts.file is None:
905 display_rspec(result, format)
908 if not file.startswith(os.sep):
909 file = os.path.join(self.options.sfi_dir, file)
910 save_rspec_to_file(result, file)
913 # created named slice with given rspec
914 def create(self, opts, args):
916 slice_urn = hrn_to_urn(slice_hrn, 'slice')
917 user_cred = self.get_user_cred()
918 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
921 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
922 creds.append(delegated_cred)
923 rspec_file = self.get_rspec_file(args[1])
924 rspec = open(rspec_file).read()
927 # { urn: urn:publicid:IDN+emulab.net+user+alice
928 # keys: [<ssh key A>, <ssh key B>]
931 server = self.get_server_from_opts(opts)
932 version = server.GetVersion()
933 if 'sfa' not in version:
934 # need to pass along user keys if this request is going to a ProtoGENI aggregate
935 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
936 # request. So we will only pass in one user that contains the keys for all
938 user = {'urn': user_cred.get_gid_caller().get_urn(),
940 slice_record = self.registry.Resolve(slice_urn, creds)
941 if slice_record and 'researchers' in slice_record:
942 user_hrns = slice_record['researchers']
943 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
944 user_records = self.registry.Resolve(user_urns, creds)
945 for user_record in user_records:
946 if 'keys' in user_record:
947 user['keys'].extend(user_record['keys'])
950 call_args = [slice_urn, creds, rspec, users]
951 if self.server_supports_call_id_arg(server):
952 call_args.append(unique_call_id())
954 result = server.CreateSliver(*call_args)
958 # get a ticket for the specified slice
959 def get_ticket(self, opts, args):
960 slice_hrn, rspec_path = args[0], args[1]
961 slice_urn = hrn_to_urn(slice_hrn, 'slice')
962 user_cred = self.get_user_cred()
963 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
966 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
967 creds.append(delegated_cred)
968 rspec_file = self.get_rspec_file(rspec_path)
969 rspec = open(rspec_file).read()
970 server = self.get_server_from_opts(opts)
971 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
972 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
973 self.logger.info("writing ticket to %s"%file)
974 ticket = SfaTicket(string=ticket_string)
975 ticket.save_to_file(filename=file, save_parents=True)
977 def redeem_ticket(self, opts, args):
978 ticket_file = args[0]
980 # get slice hrn from the ticket
981 # use this to get the right slice credential
982 ticket = SfaTicket(filename=ticket_file)
984 slice_hrn = ticket.gidObject.get_hrn()
985 slice_urn = hrn_to_urn(slice_hrn, 'slice')
986 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
987 user_cred = self.get_user_cred()
988 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
990 # get a list of node hostnames from the RSpec
991 tree = etree.parse(StringIO(ticket.rspec))
992 root = tree.getroot()
993 hostnames = root.xpath("./network/site/node/hostname/text()")
995 # create an xmlrpc connection to the component manager at each of these
996 # components and gall redeem_ticket
998 for hostname in hostnames:
1000 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1001 server = self.get_server(hostname, CM_PORT, self.key_file, \
1002 self.cert_file, self.options.debug)
1003 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1004 self.logger.info("Success")
1005 except socket.gaierror:
1006 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1007 except Exception, e:
1008 self.logger.log_exc(e.message)
1011 # delete named slice
1012 def delete(self, opts, args):
1014 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1015 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1016 creds = [slice_cred]
1018 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1019 creds.append(delegated_cred)
1020 server = self.get_server_from_opts(opts)
1022 call_args = [slice_urn, creds]
1023 if self.server_supports_call_id_arg(server):
1024 call_args.append(unique_call_id())
1025 return server.DeleteSliver(*call_args)
1028 def start(self, opts, args):
1030 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1031 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1032 creds = [slice_cred]
1034 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1035 creds.append(delegated_cred)
1036 server = self.get_server_from_opts(opts)
1037 return server.Start(slice_urn, creds)
1040 def stop(self, opts, args):
1042 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1043 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1044 creds = [slice_cred]
1046 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1047 creds.append(delegated_cred)
1048 server = self.get_server_from_opts(opts)
1049 return server.Stop(slice_urn, creds)
1052 def reset(self, opts, args):
1054 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1055 server = self.get_server_from_opts(opts)
1056 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1057 creds = [slice_cred]
1059 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1060 creds.append(delegated_cred)
1061 return server.reset_slice(creds, slice_urn)
1063 def renew(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)
1074 call_args = [slice_urn, creds, time]
1075 if self.server_supports_call_id_arg(server):
1076 call_args.append(unique_call_id())
1077 return server.RenewSliver(*call_args)
1080 def status(self, opts, args):
1082 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1083 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1084 creds = [slice_cred]
1086 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1087 creds.append(delegated_cred)
1088 server = self.get_server_from_opts(opts)
1089 call_args = [slice_urn, creds]
1090 if self.server_supports_call_id_arg(server):
1091 call_args.append(unique_call_id())
1092 print server.SliverStatus(*call_args)
1095 def shutdown(self, opts, args):
1097 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1098 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1099 creds = [slice_cred]
1101 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1102 creds.append(delegated_cred)
1103 server = self.get_server_from_opts(opts)
1104 return server.Shutdown(slice_urn, creds)
1106 def print_help (self):
1107 self.sfi_parser.print_help()
1108 self.cmd_parser.print_help()
1111 # Main: parse arguments and dispatch to command
1114 self.sfi_parser = self.create_parser()
1115 (options, args) = self.sfi_parser.parse_args()
1116 self.options = options
1118 self.logger.setLevelFromOptVerbose(self.options.verbose)
1119 if options.hashrequest:
1120 self.hashrequest = True
1123 self.logger.critical("No command given. Use -h for help.")
1127 self.cmd_parser = self.create_cmd_parser(command)
1128 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1131 self.logger.info("Command=%s" % command)
1132 if command in ("resources"):
1133 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1134 elif command in ("list", "show", "remove"):
1135 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1136 self.logger.debug('cmd_args %s' % cmd_args)
1139 self.dispatch(command, cmd_opts, cmd_args)
1141 self.logger.critical ("Unknown command %s"%command)
1146 if __name__ == "__main__":