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"))
213 if command in ("resources", "show", "list"):
214 parser.add_option("-o", "--output", dest="file",
215 help="output XML to file", metavar="FILE", default=None)
217 if command in ("show", "list"):
218 parser.add_option("-f", "--format", dest="format", type="choice",
219 help="display format ([text]|xml)", default="text",
220 choices=("text", "xml"))
222 if command in ("delegate"):
223 parser.add_option("-u", "--user",
224 action="store_true", dest="delegate_user", default=False,
225 help="delegate user credential")
226 parser.add_option("-s", "--slice", dest="delegate_slice",
227 help="delegate slice credential", metavar="HRN", default=None)
229 if command in ("version"):
230 parser.add_option("-a", "--aggregate", dest="aggregate",
231 default=None, help="aggregate host")
232 parser.add_option("-p", "--port", dest="port",
233 default=AGGREGATE_PORT, help="aggregate port")
234 parser.add_option("-R","--registry-version",
235 action="store_true", dest="version_registry", default=False,
236 help="probe registry version instead of slicemgr")
237 parser.add_option("-l","--local",
238 action="store_true", dest="version_local", default=False,
239 help="display version of the local client")
244 def create_parser(self):
246 # Generate command line parser
247 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
248 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
249 parser.add_option("-r", "--registry", dest="registry",
250 help="root registry", metavar="URL", default=None)
251 parser.add_option("-s", "--slicemgr", dest="sm",
252 help="slice manager", metavar="URL", default=None)
253 default_sfi_dir = os.path.expanduser("~/.sfi/")
254 parser.add_option("-d", "--dir", dest="sfi_dir",
255 help="config & working directory - default is " + default_sfi_dir,
256 metavar="PATH", default=default_sfi_dir)
257 parser.add_option("-u", "--user", dest="user",
258 help="user name", metavar="HRN", default=None)
259 parser.add_option("-a", "--auth", dest="auth",
260 help="authority name", metavar="HRN", default=None)
261 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
262 help="verbose mode - cumulative")
263 parser.add_option("-D", "--debug",
264 action="store_true", dest="debug", default=False,
265 help="Debug (xml-rpc) protocol messages")
266 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
267 help="RPC protocol (xmlrpc or soap)")
268 parser.add_option("-k", "--hashrequest",
269 action="store_true", dest="hashrequest", default=False,
270 help="Create a hash of the request that will be authenticated on the server")
271 parser.disable_interspersed_args()
276 def read_config(self):
277 config_file = self.options.sfi_dir + os.sep + "sfi_config"
279 config = Config (config_file)
281 self.logger.critical("Failed to read configuration file %s"%config_file)
282 self.logger.info("Make sure to remove the export clauses and to add quotes")
283 if self.options.verbose==0:
284 self.logger.info("Re-run with -v for more details")
286 self.logger.log_exc("Could not read config file %s"%config_file)
291 if (self.options.sm is not None):
292 self.sm_url = self.options.sm
293 elif hasattr(config, "SFI_SM"):
294 self.sm_url = config.SFI_SM
296 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
300 if (self.options.registry is not None):
301 self.reg_url = self.options.registry
302 elif hasattr(config, "SFI_REGISTRY"):
303 self.reg_url = config.SFI_REGISTRY
305 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
310 if (self.options.user is not None):
311 self.user = self.options.user
312 elif hasattr(config, "SFI_USER"):
313 self.user = config.SFI_USER
315 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
319 if (self.options.auth is not None):
320 self.authority = self.options.auth
321 elif hasattr(config, "SFI_AUTH"):
322 self.authority = config.SFI_AUTH
324 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
332 # Establish Connection to SliceMgr and Registry Servers
334 def set_servers(self):
337 # Get key and certificate
338 key_file = self.get_key_file()
339 cert_file = self.get_cert_file(key_file)
340 self.key = Keypair(filename=key_file)
341 self.key_file = key_file
342 self.cert_file = cert_file
343 self.cert = GID(filename=cert_file)
344 # Establish connection to server(s)
345 self.logger.info("Contacting Registry at: %s"%self.reg_url)
346 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
347 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
348 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, self.options)
353 # Get various credential and spec files
355 # Establishes limiting conventions
356 # - conflates MAs and SAs
357 # - assumes last token in slice name is unique
359 # Bootstraps credentials
360 # - bootstrap user credential from self-signed certificate
361 # - bootstrap authority credential from user credential
362 # - bootstrap slice credential from user credential
366 def get_key_file(self):
367 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
368 if (os.path.isfile(file)):
371 self.logger.error("Key file %s does not exist"%file)
375 def get_cert_file(self, key_file):
377 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
378 if (os.path.isfile(cert_file)):
379 # we'd perfer to use Registry issued certs instead of self signed certs.
380 # if this is a Registry cert (GID) then we are done
381 gid = GID(filename=cert_file)
385 # generate self signed certificate
386 k = Keypair(filename=key_file)
387 cert = Certificate(subject=self.user)
389 cert.set_issuer(k, self.user)
391 self.logger.info("Writing self-signed certificate to %s"%cert_file)
392 cert.save_to_file(cert_file)
393 # try to get registry issued cert
395 self.logger.info("Getting Registry issued cert")
397 # *hack. need to set registyr before _get_gid() is called
398 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
399 gid = self._get_gid(type='user')
401 self.logger.info("Writing certificate to %s"%cert_file)
402 gid.save_to_file(cert_file)
404 self.logger.info("Failed to download Registry issued cert")
408 def get_cached_gid(self, file):
413 if (os.path.isfile(file)):
414 gid = GID(filename=file)
418 def get_gid(self, opts, args):
420 Get the specify gid and save it to file
425 gid = self._get_gid(hrn)
426 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
429 def _get_gid(self, hrn=None, type=None):
431 git_gid helper. Retrive the gid from the registry and save it to file.
437 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
438 gid = self.get_cached_gid(gidfile)
440 user_cred = self.get_user_cred()
441 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
445 if type == record['type']:
448 raise RecordNotFound(args[0])
449 gid = GID(string=records[0]['gid'])
450 self.logger.info("Writing gid to %s"%gidfile)
451 gid.save_to_file(filename=gidfile)
455 def get_cached_credential(self, file):
457 Return a cached credential only if it hasn't expired.
459 if (os.path.isfile(file)):
460 credential = Credential(filename=file)
461 # make sure it isnt expired
462 if not credential.get_expiration or \
463 datetime.datetime.today() < credential.get_expiration():
467 def get_user_cred(self):
468 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
469 return self.get_cred(file, 'user', self.user)
471 def get_auth_cred(self):
472 if not self.authority:
473 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
475 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
476 return self.get_cred(file, 'authority', self.authority)
478 def get_slice_cred(self, name):
479 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
480 return self.get_cred(file, 'slice', name)
482 def get_cred(self, file, type, hrn):
483 # attempt to load a cached credential
484 cred = self.get_cached_credential(file)
487 cert_string = self.cert.save_to_string(save_parents=True)
488 user_name = self.user.replace(self.authority + ".", '')
489 if user_name.count(".") > 0:
490 user_name = user_name.replace(".", '_')
491 self.user = self.authority + "." + user_name
492 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
494 # bootstrap slice credential from user credential
495 user_cred = self.get_user_cred().save_to_string(save_parents=True)
496 cred_str = self.registry.GetCredential(user_cred, hrn, type)
499 self.logger.critical("Failed to get %s credential" % type)
502 cred = Credential(string=cred_str)
503 cred.save_to_file(file, save_parents=True)
504 self.logger.info("Writing %s credential to %s" %(type, file))
509 def get_rspec_file(self, rspec):
510 if (os.path.isabs(rspec)):
513 file = os.path.join(self.options.sfi_dir, rspec)
514 if (os.path.isfile(file)):
517 self.logger.critical("No such rspec file %s"%rspec)
520 def get_record_file(self, record):
521 if (os.path.isabs(record)):
524 file = os.path.join(self.options.sfi_dir, record)
525 if (os.path.isfile(file)):
528 self.logger.critical("No such registry record file %s"%record)
531 def load_publickey_string(self, fn):
533 key_string = f.read()
535 # if the filename is a private key file, then extract the public key
536 if "PRIVATE KEY" in key_string:
537 outfn = tempfile.mktemp()
538 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
541 key_string = f.read()
547 def get_component_server_from_hrn(self, hrn):
548 # direct connection to the nodes component manager interface
549 user_cred = self.get_user_cred().save_to_string(save_parents=True)
550 records = self.registry.Resolve(hrn, user_cred)
551 records = filter_records('node', records)
553 self.logger.warning("No such component:%r"% opts.component)
556 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
558 def get_server(self, host, port, keyfile, certfile):
560 Return an instance of an xmlrpc server connection
562 # port is appended onto the domain, before the path. Should look like:
563 # http://domain:port/path
564 host_parts = host.split('/')
565 host_parts[0] = host_parts[0] + ":" + str(port)
566 url = "http://%s" % "/".join(host_parts)
567 return xmlrpcprotocol.get_server(url, keyfile, certfile, self.options)
569 # xxx opts could be retrieved in self.options
570 def get_server_from_opts(self, opts):
572 Return instance of an xmlrpc connection to a slice manager, aggregate
573 or component server depending on the specified opts
575 server = self.slicemgr
576 # direct connection to an aggregate
577 if hasattr(opts, 'aggregate') and opts.aggregate:
578 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
579 # direct connection to the nodes component manager interface
580 if hasattr(opts, 'component') and opts.component:
581 server = self.get_component_server_from_hrn(opts.component)
584 #==========================================================================
585 # Following functions implement the commands
587 # Registry-related commands
588 #==========================================================================
590 def dispatch(self, command, cmd_opts, cmd_args):
591 return getattr(self, command)(cmd_opts, cmd_args)
593 # list entires in named authority registry
594 def list(self, opts, args):
599 user_cred = self.get_user_cred().save_to_string(save_parents=True)
601 list = self.registry.List(hrn, user_cred)
603 raise Exception, "Not enough parameters for the 'list' command"
605 # filter on person, slice, site, node, etc.
606 # THis really should be in the self.filter_records funct def comment...
607 list = filter_records(opts.type, list)
609 print "%s (%s)" % (record['hrn'], record['type'])
612 if not file.startswith(os.sep):
613 file = os.path.join(self.options.sfi_dir, file)
614 save_records_to_file(file, list)
617 # show named registry record
618 def show(self, opts, args):
623 user_cred = self.get_user_cred().save_to_string(save_parents=True)
624 records = self.registry.Resolve(hrn, user_cred)
625 records = filter_records(opts.type, records)
627 print "No record of type", opts.type
628 for record in records:
629 if record['type'] in ['user']:
630 record = UserRecord(dict=record)
631 elif record['type'] in ['slice']:
632 record = SliceRecord(dict=record)
633 elif record['type'] in ['node']:
634 record = NodeRecord(dict=record)
635 elif record['type'] in ['authority', 'ma', 'sa']:
636 record = AuthorityRecord(dict=record)
638 record = SfaRecord(dict=record)
639 if (opts.format == "text"):
642 print record.save_to_string()
646 if not file.startswith(os.sep):
647 file = os.path.join(self.options.sfi_dir, file)
648 save_records_to_file(file, records)
651 def delegate(self, opts, args):
653 delegee_hrn = args[0]
654 if opts.delegate_user:
655 user_cred = self.get_user_cred()
656 cred = self.delegate_cred(user_cred, delegee_hrn)
657 elif opts.delegate_slice:
658 slice_cred = self.get_slice_cred(opts.delegate_slice)
659 cred = self.delegate_cred(slice_cred, delegee_hrn)
661 self.logger.warning("Must specify either --user or --slice <hrn>")
663 delegated_cred = Credential(string=cred)
664 object_hrn = delegated_cred.get_gid_object().get_hrn()
665 if opts.delegate_user:
666 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
667 + get_leaf(object_hrn) + ".cred")
668 elif opts.delegate_slice:
669 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
670 + get_leaf(object_hrn) + ".cred")
672 delegated_cred.save_to_file(dest_fn, save_parents=True)
674 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
676 def delegate_cred(self, object_cred, hrn):
677 # the gid and hrn of the object we are delegating
678 if isinstance(object_cred, str):
679 object_cred = Credential(string=object_cred)
680 object_gid = object_cred.get_gid_object()
681 object_hrn = object_gid.get_hrn()
683 if not object_cred.get_privileges().get_all_delegate():
684 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
687 # the delegating user's gid
688 caller_gid = self._get_gid(self.user)
689 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
691 # the gid of the user who will be delegated to
692 delegee_gid = self._get_gid(hrn)
693 delegee_hrn = delegee_gid.get_hrn()
694 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
695 delegee_gid.save_to_file(filename=delegee_gidfile)
696 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
697 return dcred.save_to_string(save_parents=True)
699 # removed named registry record
700 # - have to first retrieve the record to be removed
701 def remove(self, opts, args):
702 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
710 return self.registry.Remove(hrn, auth_cred, type)
712 # add named registry record
713 def add(self, opts, args):
714 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
718 record_filepath = args[0]
719 rec_file = self.get_record_file(record_filepath)
720 record = load_record_from_file(rec_file).as_dict()
721 return self.registry.Register(record, auth_cred)
723 # update named registry entry
724 def update(self, opts, args):
725 user_cred = self.get_user_cred()
729 rec_file = self.get_record_file(args[0])
730 record = load_record_from_file(rec_file)
731 if record['type'] == "user":
732 if record.get_name() == user_cred.get_gid_object().get_hrn():
733 cred = user_cred.save_to_string(save_parents=True)
735 cred = self.get_auth_cred().save_to_string(save_parents=True)
736 elif record['type'] in ["slice"]:
738 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
739 except xmlrpcprotocol.ServerException, e:
740 # XXX smbaker -- once we have better error return codes, update this
741 # to do something better than a string compare
742 if "Permission error" in e.args[0]:
743 cred = self.get_auth_cred().save_to_string(save_parents=True)
746 elif record.get_type() in ["authority"]:
747 cred = self.get_auth_cred().save_to_string(save_parents=True)
748 elif record.get_type() == 'node':
749 cred = self.get_auth_cred().save_to_string(save_parents=True)
751 raise "unknown record type" + record.get_type()
752 record = record.as_dict()
753 return self.registry.Update(record, cred)
755 def get_trusted_certs(self, opts, args):
757 return uhe trusted certs at this interface
759 trusted_certs = self.registry.get_trusted_certs()
760 for trusted_cert in trusted_certs:
761 cert = Certificate(string=trusted_cert)
762 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
765 def aggregates(self, opts, args):
767 return a list of details about known aggregates
769 user_cred = self.get_user_cred().save_to_string(save_parents=True)
774 result = self.registry.get_aggregates(user_cred, hrn)
778 def registries(self, opts, args):
780 return a list of details about known registries
782 user_cred = self.get_user_cred().save_to_string(save_parents=True)
786 result = self.registry.get_registries(user_cred, hrn)
791 # ==================================================================
792 # Slice-related commands
793 # ==================================================================
796 def version(self, opts, args):
797 if opts.version_local:
798 version=version_core()
800 if opts.version_registry:
803 server = self.get_server_from_opts(opts)
804 version=server.GetVersion()
805 for (k,v) in version.iteritems():
806 print "%-20s: %s"%(k,v)
808 # list instantiated slices
809 def slices(self, opts, args):
811 list instantiated slices
813 user_cred = self.get_user_cred().save_to_string(save_parents=True)
816 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
817 creds.append(delegated_cred)
818 server = self.get_server_from_opts(opts)
819 #results = server.ListSlices(creds, unique_call_id())
820 results = server.ListSlices(creds)
821 display_list(results)
824 # show rspec for named slice
825 def resources(self, opts, args):
826 user_cred = self.get_user_cred().save_to_string(save_parents=True)
827 server = self.slicemgr
829 server = self.get_server_from_opts(opts)
832 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
834 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
841 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
842 creds.append(delegated_cred)
843 if opts.rspec_version:
844 call_options['rspec_version'] = opts.rspec_version
845 result = server.ListResources(creds, call_options,unique_call_id())
847 if opts.file is None:
848 display_rspec(result, format)
851 if not file.startswith(os.sep):
852 file = os.path.join(self.options.sfi_dir, file)
853 save_rspec_to_file(result, file)
856 # created named slice with given rspec
857 def create(self, opts, args):
859 slice_urn = hrn_to_urn(slice_hrn, 'slice')
860 user_cred = self.get_user_cred()
861 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
864 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
865 creds.append(delegated_cred)
866 rspec_file = self.get_rspec_file(args[1])
867 rspec = open(rspec_file).read()
870 # { urn: urn:publicid:IDN+emulab.net+user+alice
871 # keys: [<ssh key A>, <ssh key B>]
874 server = self.get_server_from_opts(opts)
875 version = server.GetVersion()
876 if 'sfa' not in version:
877 # need to pass along user keys if this request is going to a ProtoGENI aggregate
878 # ProtoGeni Aggregaes will only install the keys of the user that is issuing the
879 # request. all slice keys
880 user = {'urn': user_cred.get_gid_caller().get_urn(),
882 slice_record = self.registry.Resolve(slice_urn, creds)
883 if slice_record and 'researchers' in slice_record:
884 user_hrns = slice_record['researchers']
885 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
886 user_records = self.registry.Resolve(user_urns, creds)
887 for user_record in user_records:
888 if 'keys' in user_record:
889 user['keys'].extend(user_record['keys'])
891 result = server.CreateSliver(slice_urn, creds, rspec, users, unique_call_id())
895 # get a ticket for the specified slice
896 def get_ticket(self, opts, args):
897 slice_hrn, rspec_path = args[0], args[1]
898 slice_urn = hrn_to_urn(slice_hrn, 'slice')
899 user_cred = self.get_user_cred()
900 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
903 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
904 creds.append(delegated_cred)
905 rspec_file = self.get_rspec_file(rspec_path)
906 rspec = open(rspec_file).read()
907 server = self.get_server_from_opts(opts)
908 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
909 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
910 self.logger.info("writing ticket to %s"%file)
911 ticket = SfaTicket(string=ticket_string)
912 ticket.save_to_file(filename=file, save_parents=True)
914 def redeem_ticket(self, opts, args):
915 ticket_file = args[0]
917 # get slice hrn from the ticket
918 # use this to get the right slice credential
919 ticket = SfaTicket(filename=ticket_file)
921 slice_hrn = ticket.gidObject.get_hrn()
922 slice_urn = hrn_to_urn(slice_hrn, 'slice')
923 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
924 user_cred = self.get_user_cred()
925 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
927 # get a list of node hostnames from the RSpec
928 tree = etree.parse(StringIO(ticket.rspec))
929 root = tree.getroot()
930 hostnames = root.xpath("./network/site/node/hostname/text()")
932 # create an xmlrpc connection to the component manager at each of these
933 # components and gall redeem_ticket
935 for hostname in hostnames:
937 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
938 server = self.get_server(hostname, CM_PORT, self.key_file, \
939 self.cert_file, self.options.debug)
940 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
941 self.logger.info("Success")
942 except socket.gaierror:
943 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
945 self.logger.log_exc(e.message)
949 def delete(self, opts, args):
951 slice_urn = hrn_to_urn(slice_hrn, 'slice')
952 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
955 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
956 creds.append(delegated_cred)
957 server = self.get_server_from_opts(opts)
958 return server.DeleteSliver(slice_urn, creds, unique_call_id())
961 def start(self, opts, args):
963 slice_urn = hrn_to_urn(slice_hrn, 'slice')
964 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
967 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
968 creds.append(delegated_cred)
969 server = self.get_server_from_opts(opts)
970 return server.Start(slice_urn, creds)
973 def stop(self, opts, args):
975 slice_urn = hrn_to_urn(slice_hrn, 'slice')
976 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
979 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
980 creds.append(delegated_cred)
981 server = self.get_server_from_opts(opts)
982 return server.Stop(slice_urn, creds)
985 def reset(self, opts, args):
987 slice_urn = hrn_to_urn(slice_hrn, 'slice')
988 server = self.get_server_from_opts(opts)
989 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
992 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
993 creds.append(delegated_cred)
994 return server.reset_slice(creds, slice_urn)
996 def renew(self, opts, args):
998 slice_urn = hrn_to_urn(slice_hrn, 'slice')
999 server = self.get_server_from_opts(opts)
1000 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1001 creds = [slice_cred]
1003 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1004 creds.append(delegated_cred)
1006 return server.RenewSliver(slice_urn, creds, time, unique_call_id())
1009 def status(self, opts, args):
1011 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1012 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1013 creds = [slice_cred]
1015 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1016 creds.append(delegated_cred)
1017 server = self.get_server_from_opts(opts)
1018 print server.SliverStatus(slice_urn, creds, unique_call_id())
1021 def shutdown(self, opts, args):
1023 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1024 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1025 creds = [slice_cred]
1027 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1028 creds.append(delegated_cred)
1029 server = self.get_server_from_opts(opts)
1030 return server.Shutdown(slice_urn, creds)
1032 def print_help (self):
1033 self.sfi_parser.print_help()
1034 self.cmd_parser.print_help()
1037 # Main: parse arguments and dispatch to command
1040 self.sfi_parser = self.create_parser()
1041 (options, args) = self.sfi_parser.parse_args()
1042 self.options = options
1044 self.logger.setLevelFromOptVerbose(self.options.verbose)
1045 if options.hashrequest:
1046 self.hashrequest = True
1049 self.logger.critical("No command given. Use -h for help.")
1053 self.cmd_parser = self.create_cmd_parser(command)
1054 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1058 self.logger.info("Command=%s" % command)
1059 if command in ("resources"):
1060 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1061 elif command in ("list", "show", "remove"):
1062 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1063 self.logger.debug('cmd_args %s',cmd_args)
1066 self.dispatch(command, cmd_opts, cmd_args)
1068 self.logger.critical ("Unknown command %s"%command)
1073 if __name__ == "__main__":