3 # sfi -- slice-based facility interface
13 from lxml import etree
14 from StringIO import StringIO
15 from types import StringTypes, ListType
16 from optparse import OptionParser
19 from sfa.util.sfalogging import sfa_logger,sfa_logger_goes_to_console
20 from sfa.trust.certificate import Keypair, Certificate
21 from sfa.trust.gid import GID
22 from sfa.trust.credential import Credential
23 from sfa.util.sfaticket import SfaTicket
24 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
25 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
26 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
27 from sfa.util.config import Config
28 from sfa.util.version import version_core
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.options = options
141 self.authority = None
142 self.hashrequest = False
143 sfa_logger_goes_to_console()
144 self.logger=sfa_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 # Establish connection to server(s)
349 self.logger.info("Contacting Registry at: %s"%self.reg_url)
350 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
351 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
352 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, self.options)
357 # Get various credential and spec files
359 # Establishes limiting conventions
360 # - conflates MAs and SAs
361 # - assumes last token in slice name is unique
363 # Bootstraps credentials
364 # - bootstrap user credential from self-signed certificate
365 # - bootstrap authority credential from user credential
366 # - bootstrap slice credential from user credential
370 def get_key_file(self):
371 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
372 if (os.path.isfile(file)):
375 self.logger.error("Key file %s does not exist"%file)
379 def get_cert_file(self, key_file):
381 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
382 if (os.path.isfile(cert_file)):
383 # we'd perfer to use Registry issued certs instead of self signed certs.
384 # if this is a Registry cert (GID) then we are done
385 gid = GID(filename=cert_file)
389 # generate self signed certificate
390 k = Keypair(filename=key_file)
391 cert = Certificate(subject=self.user)
393 cert.set_issuer(k, self.user)
395 self.logger.info("Writing self-signed certificate to %s"%cert_file)
396 cert.save_to_file(cert_file)
397 # try to get registry issued cert
399 self.logger.info("Getting Registry issued cert")
401 # *hack. need to set registyr before _get_gid() is called
402 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
403 gid = self._get_gid(type='user')
405 self.logger.info("Writing certificate to %s"%cert_file)
406 gid.save_to_file(cert_file)
408 self.logger.info("Failed to download Registry issued cert")
412 def get_cached_gid(self, file):
417 if (os.path.isfile(file)):
418 gid = GID(filename=file)
422 def get_gid(self, opts, args):
424 Get the specify gid and save it to file
429 gid = self._get_gid(hrn)
430 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
433 def _get_gid(self, hrn=None, type=None):
435 git_gid helper. Retrive the gid from the registry and save it to file.
441 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
442 gid = self.get_cached_gid(gidfile)
444 user_cred = self.get_user_cred()
445 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
449 if type == record['type']:
452 raise RecordNotFound(args[0])
453 gid = GID(string=records[0]['gid'])
454 self.logger.info("Writing gid to %s"%gidfile)
455 gid.save_to_file(filename=gidfile)
459 def get_cached_credential(self, file):
461 Return a cached credential only if it hasn't expired.
463 if (os.path.isfile(file)):
464 credential = Credential(filename=file)
465 # make sure it isnt expired
466 if not credential.get_expiration or \
467 datetime.datetime.today() < credential.get_expiration():
471 def get_user_cred(self):
472 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
473 return self.get_cred(file, 'user', self.user)
475 def get_auth_cred(self):
476 if not self.authority:
477 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
479 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
480 return self.get_cred(file, 'authority', self.authority)
482 def get_slice_cred(self, name):
483 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
484 return self.get_cred(file, 'slice', name)
486 def get_cred(self, file, type, hrn):
487 # attempt to load a cached credential
488 cred = self.get_cached_credential(file)
491 cert_string = self.cert.save_to_string(save_parents=True)
492 user_name = self.user.replace(self.authority + ".", '')
493 if user_name.count(".") > 0:
494 user_name = user_name.replace(".", '_')
495 self.user = self.authority + "." + user_name
496 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
498 # bootstrap slice credential from user credential
499 user_cred = self.get_user_cred().save_to_string(save_parents=True)
500 cred_str = self.registry.GetCredential(user_cred, hrn, type)
503 self.logger.critical("Failed to get %s credential" % type)
506 cred = Credential(string=cred_str)
507 cred.save_to_file(file, save_parents=True)
508 self.logger.info("Writing %s credential to %s" %(type, file))
513 def get_rspec_file(self, rspec):
514 if (os.path.isabs(rspec)):
517 file = os.path.join(self.options.sfi_dir, rspec)
518 if (os.path.isfile(file)):
521 self.logger.critical("No such rspec file %s"%rspec)
524 def get_record_file(self, record):
525 if (os.path.isabs(record)):
528 file = os.path.join(self.options.sfi_dir, record)
529 if (os.path.isfile(file)):
532 self.logger.critical("No such registry record file %s"%record)
535 def load_publickey_string(self, fn):
537 key_string = f.read()
539 # if the filename is a private key file, then extract the public key
540 if "PRIVATE KEY" in key_string:
541 outfn = tempfile.mktemp()
542 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
545 key_string = f.read()
551 def get_component_server_from_hrn(self, hrn):
552 # direct connection to the nodes component manager interface
553 user_cred = self.get_user_cred().save_to_string(save_parents=True)
554 records = self.registry.Resolve(hrn, user_cred)
555 records = filter_records('node', records)
557 self.logger.warning("No such component:%r"% opts.component)
560 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
562 def get_server(self, host, port, keyfile, certfile):
564 Return an instance of an xmlrpc server connection
566 # port is appended onto the domain, before the path. Should look like:
567 # http://domain:port/path
568 host_parts = host.split('/')
569 host_parts[0] = host_parts[0] + ":" + str(port)
570 url = "http://%s" % "/".join(host_parts)
571 return xmlrpcprotocol.get_server(url, keyfile, certfile, self.options)
573 # xxx opts could be retrieved in self.options
574 def get_server_from_opts(self, opts):
576 Return instance of an xmlrpc connection to a slice manager, aggregate
577 or component server depending on the specified opts
579 server = self.slicemgr
580 # direct connection to an aggregate
581 if hasattr(opts, 'aggregate') and opts.aggregate:
582 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
583 # direct connection to the nodes component manager interface
584 if hasattr(opts, 'component') and opts.component:
585 server = self.get_component_server_from_hrn(opts.component)
588 #==========================================================================
589 # Following functions implement the commands
591 # Registry-related commands
592 #==========================================================================
594 def dispatch(self, command, cmd_opts, cmd_args):
595 return getattr(self, command)(cmd_opts, cmd_args)
597 # list entires in named authority registry
598 def list(self, opts, args):
603 user_cred = self.get_user_cred().save_to_string(save_parents=True)
605 list = self.registry.List(hrn, user_cred)
607 raise Exception, "Not enough parameters for the 'list' command"
609 # filter on person, slice, site, node, etc.
610 # THis really should be in the self.filter_records funct def comment...
611 list = filter_records(opts.type, list)
613 print "%s (%s)" % (record['hrn'], record['type'])
616 if not file.startswith(os.sep):
617 file = os.path.join(self.options.sfi_dir, file)
618 save_records_to_file(file, list)
621 # show named registry record
622 def show(self, opts, args):
627 user_cred = self.get_user_cred().save_to_string(save_parents=True)
628 records = self.registry.Resolve(hrn, user_cred)
629 records = filter_records(opts.type, records)
631 print "No record of type", opts.type
632 for record in records:
633 if record['type'] in ['user']:
634 record = UserRecord(dict=record)
635 elif record['type'] in ['slice']:
636 record = SliceRecord(dict=record)
637 elif record['type'] in ['node']:
638 record = NodeRecord(dict=record)
639 elif record['type'] in ['authority', 'ma', 'sa']:
640 record = AuthorityRecord(dict=record)
642 record = SfaRecord(dict=record)
643 if (opts.format == "text"):
646 print record.save_to_string()
650 if not file.startswith(os.sep):
651 file = os.path.join(self.options.sfi_dir, file)
652 save_records_to_file(file, records)
655 def delegate(self, opts, args):
657 delegee_hrn = args[0]
658 if opts.delegate_user:
659 user_cred = self.get_user_cred()
660 cred = self.delegate_cred(user_cred, delegee_hrn)
661 elif opts.delegate_slice:
662 slice_cred = self.get_slice_cred(opts.delegate_slice)
663 cred = self.delegate_cred(slice_cred, delegee_hrn)
665 self.logger.warning("Must specify either --user or --slice <hrn>")
667 delegated_cred = Credential(string=cred)
668 object_hrn = delegated_cred.get_gid_object().get_hrn()
669 if opts.delegate_user:
670 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
671 + get_leaf(object_hrn) + ".cred")
672 elif opts.delegate_slice:
673 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
674 + get_leaf(object_hrn) + ".cred")
676 delegated_cred.save_to_file(dest_fn, save_parents=True)
678 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
680 def delegate_cred(self, object_cred, hrn):
681 # the gid and hrn of the object we are delegating
682 if isinstance(object_cred, str):
683 object_cred = Credential(string=object_cred)
684 object_gid = object_cred.get_gid_object()
685 object_hrn = object_gid.get_hrn()
687 if not object_cred.get_privileges().get_all_delegate():
688 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
691 # the delegating user's gid
692 caller_gid = self._get_gid(self.user)
693 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
695 # the gid of the user who will be delegated to
696 delegee_gid = self._get_gid(hrn)
697 delegee_hrn = delegee_gid.get_hrn()
698 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
699 delegee_gid.save_to_file(filename=delegee_gidfile)
700 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
701 return dcred.save_to_string(save_parents=True)
703 # removed named registry record
704 # - have to first retrieve the record to be removed
705 def remove(self, opts, args):
706 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
714 return self.registry.Remove(hrn, auth_cred, type)
716 # add named registry record
717 def add(self, opts, args):
718 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
722 record_filepath = args[0]
723 rec_file = self.get_record_file(record_filepath)
724 record = load_record_from_file(rec_file).as_dict()
725 return self.registry.Register(record, auth_cred)
727 # update named registry entry
728 def update(self, opts, args):
729 user_cred = self.get_user_cred()
733 rec_file = self.get_record_file(args[0])
734 record = load_record_from_file(rec_file)
735 if record['type'] == "user":
736 if record.get_name() == user_cred.get_gid_object().get_hrn():
737 cred = user_cred.save_to_string(save_parents=True)
739 cred = self.get_auth_cred().save_to_string(save_parents=True)
740 elif record['type'] in ["slice"]:
742 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
743 except xmlrpcprotocol.ServerException, e:
744 # XXX smbaker -- once we have better error return codes, update this
745 # to do something better than a string compare
746 if "Permission error" in e.args[0]:
747 cred = self.get_auth_cred().save_to_string(save_parents=True)
750 elif record.get_type() in ["authority"]:
751 cred = self.get_auth_cred().save_to_string(save_parents=True)
752 elif record.get_type() == 'node':
753 cred = self.get_auth_cred().save_to_string(save_parents=True)
755 raise "unknown record type" + record.get_type()
756 record = record.as_dict()
757 return self.registry.Update(record, cred)
759 def get_trusted_certs(self, opts, args):
761 return uhe trusted certs at this interface
763 trusted_certs = self.registry.get_trusted_certs()
764 for trusted_cert in trusted_certs:
765 cert = Certificate(string=trusted_cert)
766 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
769 def aggregates(self, opts, args):
771 return a list of details about known aggregates
773 user_cred = self.get_user_cred().save_to_string(save_parents=True)
778 result = self.registry.get_aggregates(user_cred, hrn)
782 def registries(self, opts, args):
784 return a list of details about known registries
786 user_cred = self.get_user_cred().save_to_string(save_parents=True)
790 result = self.registry.get_registries(user_cred, hrn)
795 # ==================================================================
796 # Slice-related commands
797 # ==================================================================
800 def version(self, opts, args):
801 if opts.version_local:
802 version=version_core()
804 if opts.version_registry:
807 server = self.get_server_from_opts(opts)
808 version=server.GetVersion()
809 for (k,v) in version.iteritems():
810 print "%-20s: %s"%(k,v)
812 # list instantiated slices
813 def slices(self, opts, args):
815 list instantiated slices
817 user_cred = self.get_user_cred().save_to_string(save_parents=True)
820 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
821 creds.append(delegated_cred)
822 server = self.get_server_from_opts(opts)
823 #results = server.ListSlices(creds, unique_call_id())
824 results = server.ListSlices(creds)
825 display_list(results)
828 # show rspec for named slice
829 def resources(self, opts, args):
830 user_cred = self.get_user_cred().save_to_string(save_parents=True)
831 server = self.slicemgr
833 server = self.get_server_from_opts(opts)
836 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
838 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
845 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
846 creds.append(delegated_cred)
847 if opts.rspec_version:
848 call_options['rspec_version'] = opts.rspec_version
849 #panos add info options
851 call_options['info'] = opts.info
852 result = server.ListResources(creds, call_options,unique_call_id())
854 if opts.file is None:
855 display_rspec(result, format)
858 if not file.startswith(os.sep):
859 file = os.path.join(self.options.sfi_dir, file)
860 save_rspec_to_file(result, file)
863 # created named slice with given rspec
864 def create(self, opts, args):
866 slice_urn = hrn_to_urn(slice_hrn, 'slice')
867 user_cred = self.get_user_cred()
868 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
871 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
872 creds.append(delegated_cred)
873 rspec_file = self.get_rspec_file(args[1])
874 rspec = open(rspec_file).read()
877 # { urn: urn:publicid:IDN+emulab.net+user+alice
878 # keys: [<ssh key A>, <ssh key B>]
881 server = self.get_server_from_opts(opts)
882 version = server.GetVersion()
883 if 'sfa' not in version:
884 # need to pass along user keys if this request is going to a ProtoGENI aggregate
885 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
886 # request. So we will only pass in one user that contains the keys for all
888 user = {'urn': user_cred.get_gid_caller().get_urn(),
890 slice_record = self.registry.Resolve(slice_urn, creds)
891 if slice_record and 'researchers' in slice_record:
892 user_hrns = slice_record['researchers']
893 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
894 user_records = self.registry.Resolve(user_urns, creds)
895 for user_record in user_records:
896 if 'keys' in user_record:
897 user['keys'].extend(user_record['keys'])
899 result = server.CreateSliver(slice_urn, creds, rspec, users, unique_call_id())
903 # get a ticket for the specified slice
904 def get_ticket(self, opts, args):
905 slice_hrn, rspec_path = args[0], args[1]
906 slice_urn = hrn_to_urn(slice_hrn, 'slice')
907 user_cred = self.get_user_cred()
908 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
911 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
912 creds.append(delegated_cred)
913 rspec_file = self.get_rspec_file(rspec_path)
914 rspec = open(rspec_file).read()
915 server = self.get_server_from_opts(opts)
916 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
917 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
918 self.logger.info("writing ticket to %s"%file)
919 ticket = SfaTicket(string=ticket_string)
920 ticket.save_to_file(filename=file, save_parents=True)
922 def redeem_ticket(self, opts, args):
923 ticket_file = args[0]
925 # get slice hrn from the ticket
926 # use this to get the right slice credential
927 ticket = SfaTicket(filename=ticket_file)
929 slice_hrn = ticket.gidObject.get_hrn()
930 slice_urn = hrn_to_urn(slice_hrn, 'slice')
931 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
932 user_cred = self.get_user_cred()
933 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
935 # get a list of node hostnames from the RSpec
936 tree = etree.parse(StringIO(ticket.rspec))
937 root = tree.getroot()
938 hostnames = root.xpath("./network/site/node/hostname/text()")
940 # create an xmlrpc connection to the component manager at each of these
941 # components and gall redeem_ticket
943 for hostname in hostnames:
945 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
946 server = self.get_server(hostname, CM_PORT, self.key_file, \
947 self.cert_file, self.options.debug)
948 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
949 self.logger.info("Success")
950 except socket.gaierror:
951 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
953 self.logger.log_exc(e.message)
957 def delete(self, opts, args):
959 slice_urn = hrn_to_urn(slice_hrn, 'slice')
960 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
963 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
964 creds.append(delegated_cred)
965 server = self.get_server_from_opts(opts)
966 return server.DeleteSliver(slice_urn, creds, unique_call_id())
969 def start(self, opts, args):
971 slice_urn = hrn_to_urn(slice_hrn, 'slice')
972 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
975 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
976 creds.append(delegated_cred)
977 server = self.get_server_from_opts(opts)
978 return server.Start(slice_urn, creds)
981 def stop(self, opts, args):
983 slice_urn = hrn_to_urn(slice_hrn, 'slice')
984 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
987 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
988 creds.append(delegated_cred)
989 server = self.get_server_from_opts(opts)
990 return server.Stop(slice_urn, creds)
993 def reset(self, opts, args):
995 slice_urn = hrn_to_urn(slice_hrn, 'slice')
996 server = self.get_server_from_opts(opts)
997 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1000 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1001 creds.append(delegated_cred)
1002 return server.reset_slice(creds, slice_urn)
1004 def renew(self, opts, args):
1006 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1007 server = self.get_server_from_opts(opts)
1008 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1009 creds = [slice_cred]
1011 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1012 creds.append(delegated_cred)
1014 return server.RenewSliver(slice_urn, creds, time, unique_call_id())
1017 def status(self, opts, args):
1019 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1020 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1021 creds = [slice_cred]
1023 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1024 creds.append(delegated_cred)
1025 server = self.get_server_from_opts(opts)
1026 print server.SliverStatus(slice_urn, creds, unique_call_id())
1029 def shutdown(self, opts, args):
1031 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1032 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1033 creds = [slice_cred]
1035 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1036 creds.append(delegated_cred)
1037 server = self.get_server_from_opts(opts)
1038 return server.Shutdown(slice_urn, creds)
1040 def print_help (self):
1041 self.sfi_parser.print_help()
1042 self.cmd_parser.print_help()
1045 # Main: parse arguments and dispatch to command
1048 self.sfi_parser = self.create_parser()
1049 (options, args) = self.sfi_parser.parse_args()
1050 self.options = options
1052 self.logger.setLevelFromOptVerbose(self.options.verbose)
1053 if options.hashrequest:
1054 self.hashrequest = True
1057 self.logger.critical("No command given. Use -h for help.")
1061 self.cmd_parser = self.create_cmd_parser(command)
1062 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1066 self.logger.info("Command=%s" % command)
1067 if command in ("resources"):
1068 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1069 elif command in ("list", "show", "remove"):
1070 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1071 self.logger.debug('cmd_args %s',cmd_args)
1074 self.dispatch(command, cmd_opts, cmd_args)
1076 self.logger.critical ("Unknown command %s"%command)
1081 if __name__ == "__main__":