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 _SfaLogger, logging
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 #sfa_logger_goes_to_console()
145 #self.logger=sfa_logger()
146 self.logger = _SfaLogger(self.sfi_dir + 'sfi.log', level = logging.INFO)
148 def create_cmd_parser(self, command, additional_cmdargs=None):
149 cmdargs = {"list": "authority",
154 "aggregates": "[name]",
155 "registries": "[name]",
157 "get_trusted_certs": "cred",
159 "resources": "[name]",
160 "create": "name rspec",
161 "get_ticket": "name rspec",
162 "redeem_ticket": "ticket",
174 if additional_cmdargs:
175 cmdargs.update(additional_cmdargs)
177 if command not in cmdargs:
178 msg="Invalid command\n"
180 msg += ','.join(cmdargs.keys())
181 self.logger.critical(msg)
184 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
185 % (command, cmdargs[command]))
187 # user specifies remote aggregate/sm/component
188 if command in ("resources", "slices", "create", "delete", "start", "stop",
189 "restart", "shutdown", "get_ticket", "renew", "status"):
190 parser.add_option("-a", "--aggregate", dest="aggregate",
191 default=None, help="aggregate host")
192 parser.add_option("-p", "--port", dest="port",
193 default=AGGREGATE_PORT, help="aggregate port")
194 parser.add_option("-c", "--component", dest="component", default=None,
195 help="component hrn")
196 parser.add_option("-d", "--delegate", dest="delegate", default=None,
198 help="Include a credential delegated to the user's root"+\
199 "authority in set of credentials for this call")
201 # registy filter option
202 if command in ("list", "show", "remove"):
203 parser.add_option("-t", "--type", dest="type", type="choice",
204 help="type filter ([all]|user|slice|authority|node|aggregate)",
205 choices=("all", "user", "slice", "authority", "node", "aggregate"),
208 if command in ("resources"):
209 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
210 help="schema type and version of resulting RSpec")
211 parser.add_option("-f", "--format", dest="format", type="choice",
212 help="display format ([xml]|dns|ip)", default="xml",
213 choices=("xml", "dns", "ip"))
214 #panos: a new option to define the type of information about resources a user is interested in
215 parser.add_option("-i", "--info", dest="info",
216 help="optional component information", default=None)
219 if command in ("resources", "show", "list"):
220 parser.add_option("-o", "--output", dest="file",
221 help="output XML to file", metavar="FILE", default=None)
223 if command in ("show", "list"):
224 parser.add_option("-f", "--format", dest="format", type="choice",
225 help="display format ([text]|xml)", default="text",
226 choices=("text", "xml"))
228 if command in ("delegate"):
229 parser.add_option("-u", "--user",
230 action="store_true", dest="delegate_user", default=False,
231 help="delegate user credential")
232 parser.add_option("-s", "--slice", dest="delegate_slice",
233 help="delegate slice credential", metavar="HRN", default=None)
235 if command in ("version"):
236 parser.add_option("-a", "--aggregate", dest="aggregate",
237 default=None, help="aggregate host")
238 parser.add_option("-p", "--port", dest="port",
239 default=AGGREGATE_PORT, help="aggregate port")
240 parser.add_option("-R","--registry-version",
241 action="store_true", dest="version_registry", default=False,
242 help="probe registry version instead of slicemgr")
243 parser.add_option("-l","--local",
244 action="store_true", dest="version_local", default=False,
245 help="display version of the local client")
250 def create_parser(self):
252 # Generate command line parser
253 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
254 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
255 parser.add_option("-r", "--registry", dest="registry",
256 help="root registry", metavar="URL", default=None)
257 parser.add_option("-s", "--slicemgr", dest="sm",
258 help="slice manager", metavar="URL", default=None)
259 default_sfi_dir = os.path.expanduser("~/.sfi/")
260 parser.add_option("-d", "--dir", dest="sfi_dir",
261 help="config & working directory - default is " + default_sfi_dir,
262 metavar="PATH", default=default_sfi_dir)
263 parser.add_option("-u", "--user", dest="user",
264 help="user name", metavar="HRN", default=None)
265 parser.add_option("-a", "--auth", dest="auth",
266 help="authority name", metavar="HRN", default=None)
267 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
268 help="verbose mode - cumulative")
269 parser.add_option("-D", "--debug",
270 action="store_true", dest="debug", default=False,
271 help="Debug (xml-rpc) protocol messages")
272 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
273 help="RPC protocol (xmlrpc or soap)")
274 parser.add_option("-k", "--hashrequest",
275 action="store_true", dest="hashrequest", default=False,
276 help="Create a hash of the request that will be authenticated on the server")
277 parser.disable_interspersed_args()
282 def read_config(self):
283 config_file = self.options.sfi_dir + os.sep + "sfi_config"
285 config = Config (config_file)
287 self.logger.critical("Failed to read configuration file %s"%config_file)
288 self.logger.info("Make sure to remove the export clauses and to add quotes")
289 if self.options.verbose==0:
290 self.logger.info("Re-run with -v for more details")
292 self.logger.log_exc("Could not read config file %s"%config_file)
297 if (self.options.sm is not None):
298 self.sm_url = self.options.sm
299 elif hasattr(config, "SFI_SM"):
300 self.sm_url = config.SFI_SM
302 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
306 if (self.options.registry is not None):
307 self.reg_url = self.options.registry
308 elif hasattr(config, "SFI_REGISTRY"):
309 self.reg_url = config.SFI_REGISTRY
311 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
316 if (self.options.user is not None):
317 self.user = self.options.user
318 elif hasattr(config, "SFI_USER"):
319 self.user = config.SFI_USER
321 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
325 if (self.options.auth is not None):
326 self.authority = self.options.auth
327 elif hasattr(config, "SFI_AUTH"):
328 self.authority = config.SFI_AUTH
330 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
338 # Establish Connection to SliceMgr and Registry Servers
340 def set_servers(self):
343 # Get key and certificate
344 key_file = self.get_key_file()
345 cert_file = self.get_cert_file(key_file)
346 self.key = Keypair(filename=key_file)
347 self.key_file = key_file
348 self.cert_file = cert_file
349 self.cert = GID(filename=cert_file)
350 self.logger.info("Contacting Registry at: %s"%self.reg_url)
351 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
352 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
353 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, self.options)
356 def get_cached_server_version(self, server):
357 # check local cache first
360 cache_file = self.sfi_dir + os.path.sep + 'sfi_cache.dat'
361 cache_key = server.url + "-version"
363 cache = Cache(cache_file)
366 self.logger.info("Local cache not found at: %s" % cache_file)
369 version = cache.get(cache_key)
372 version = server.GetVersion()
373 # cache version for 24 hours
374 cache.add(cache_key, version, ttl= 60*60*24)
380 def server_supports_call_id_arg(self, server):
382 Returns true if server support the optional call_id arg, false otherwise.
384 server_version = self.get_cached_server_version(server)
385 if 'sfa' in server_version:
386 code_tag = server_version['code_tag']
387 code_tag_parts = code_tag.split("-")
389 version_parts = code_tag_parts[0].split(".")
390 major, minor = version_parts[0], version_parts[1]
391 rev = code_tag_parts[1]
393 if int(minor) > 0 or int(rev) > 20:
398 # Get various credential and spec files
400 # Establishes limiting conventions
401 # - conflates MAs and SAs
402 # - assumes last token in slice name is unique
404 # Bootstraps credentials
405 # - bootstrap user credential from self-signed certificate
406 # - bootstrap authority credential from user credential
407 # - bootstrap slice credential from user credential
411 def get_key_file(self):
412 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
413 if (os.path.isfile(file)):
416 self.logger.error("Key file %s does not exist"%file)
420 def get_cert_file(self, key_file):
422 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
423 if (os.path.isfile(cert_file)):
424 # we'd perfer to use Registry issued certs instead of self signed certs.
425 # if this is a Registry cert (GID) then we are done
426 gid = GID(filename=cert_file)
430 # generate self signed certificate
431 k = Keypair(filename=key_file)
432 cert = Certificate(subject=self.user)
434 cert.set_issuer(k, self.user)
436 self.logger.info("Writing self-signed certificate to %s"%cert_file)
437 print "Writing self-signed certificate to %s"%cert_file
438 cert.save_to_file(cert_file)
440 # try to get registry issued cert
442 self.logger.info("Getting Registry issued cert")
443 print "Getting Registry issued cert"
445 # *hack. need to set registyr before _get_gid() is called
446 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
447 gid = self._get_gid(type='user')
449 self.logger.info("Writing certificate to %s"%cert_file)
450 gid.save_to_file(cert_file)
453 print "Failed to download Registry issued cert"
454 self.logger.info("Failed to download Registry issued cert")
458 def get_cached_gid(self, file):
463 if (os.path.isfile(file)):
464 gid = GID(filename=file)
468 def get_gid(self, opts, args):
470 Get the specify gid and save it to file
475 gid = self._get_gid(hrn)
476 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
479 def _get_gid(self, hrn=None, type=None):
481 git_gid helper. Retrive the gid from the registry and save it to file.
487 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
488 gid = self.get_cached_gid(gidfile)
490 user_cred = self.get_user_cred()
491 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
493 raise RecordNotFound(args[0])
498 if type == rec['type']:
501 raise RecordNotFound(args[0])
503 gid = GID(string=record['gid'])
504 self.logger.info("Writing gid to %s"%gidfile)
505 gid.save_to_file(filename=gidfile)
509 def get_cached_credential(self, file):
511 Return a cached credential only if it hasn't expired.
513 if (os.path.isfile(file)):
514 credential = Credential(filename=file)
515 # make sure it isnt expired
516 if not credential.get_expiration or \
517 datetime.datetime.today() < credential.get_expiration():
521 def get_user_cred(self):
522 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
523 return self.get_cred(file, 'user', self.user)
525 def get_auth_cred(self):
526 if not self.authority:
527 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
529 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
530 return self.get_cred(file, 'authority', self.authority)
532 def get_slice_cred(self, name):
533 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
534 return self.get_cred(file, 'slice', name)
536 def get_cred(self, file, type, hrn):
537 # attempt to load a cached credential
538 cred = self.get_cached_credential(file)
541 cert_string = self.cert.save_to_string(save_parents=True)
542 user_name = self.user.replace(self.authority + ".", '')
543 if user_name.count(".") > 0:
544 user_name = user_name.replace(".", '_')
545 self.user = self.authority + "." + user_name
546 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
548 # bootstrap slice credential from user credential
549 user_cred = self.get_user_cred().save_to_string(save_parents=True)
550 cred_str = self.registry.GetCredential(user_cred, hrn, type)
553 self.logger.critical("Failed to get %s credential" % type)
556 cred = Credential(string=cred_str)
557 cred.save_to_file(file, save_parents=True)
558 self.logger.info("Writing %s credential to %s" %(type, file))
563 def get_rspec_file(self, rspec):
564 if (os.path.isabs(rspec)):
567 file = os.path.join(self.options.sfi_dir, rspec)
568 if (os.path.isfile(file)):
571 self.logger.critical("No such rspec file %s"%rspec)
574 def get_record_file(self, record):
575 if (os.path.isabs(record)):
578 file = os.path.join(self.options.sfi_dir, record)
579 if (os.path.isfile(file)):
582 self.logger.critical("No such registry record file %s"%record)
585 def load_publickey_string(self, fn):
587 key_string = f.read()
589 # if the filename is a private key file, then extract the public key
590 if "PRIVATE KEY" in key_string:
591 outfn = tempfile.mktemp()
592 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
595 key_string = f.read()
601 def get_component_server_from_hrn(self, hrn):
602 # direct connection to the nodes component manager interface
603 user_cred = self.get_user_cred().save_to_string(save_parents=True)
604 records = self.registry.Resolve(hrn, user_cred)
605 records = filter_records('node', records)
607 self.logger.warning("No such component:%r"% opts.component)
610 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
612 def get_server(self, host, port, keyfile, certfile):
614 Return an instance of an xmlrpc server connection
616 # port is appended onto the domain, before the path. Should look like:
617 # http://domain:port/path
618 host_parts = host.split('/')
619 host_parts[0] = host_parts[0] + ":" + str(port)
620 url = "http://%s" % "/".join(host_parts)
621 return xmlrpcprotocol.get_server(url, keyfile, certfile, self.options)
623 # xxx opts could be retrieved in self.options
624 def get_server_from_opts(self, opts):
626 Return instance of an xmlrpc connection to a slice manager, aggregate
627 or component server depending on the specified opts
629 server = self.slicemgr
630 # direct connection to an aggregate
631 if hasattr(opts, 'aggregate') and opts.aggregate:
632 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
633 # direct connection to the nodes component manager interface
634 if hasattr(opts, 'component') and opts.component:
635 server = self.get_component_server_from_hrn(opts.component)
638 #==========================================================================
639 # Following functions implement the commands
641 # Registry-related commands
642 #==========================================================================
644 def dispatch(self, command, cmd_opts, cmd_args):
645 return getattr(self, command)(cmd_opts, cmd_args)
647 # list entires in named authority registry
648 def list(self, opts, args):
653 user_cred = self.get_user_cred().save_to_string(save_parents=True)
655 list = self.registry.List(hrn, user_cred)
657 raise Exception, "Not enough parameters for the 'list' command"
659 # filter on person, slice, site, node, etc.
660 # THis really should be in the self.filter_records funct def comment...
661 list = filter_records(opts.type, list)
663 print "%s (%s)" % (record['hrn'], record['type'])
666 if not file.startswith(os.sep):
667 file = os.path.join(self.options.sfi_dir, file)
668 save_records_to_file(file, list)
671 # show named registry record
672 def show(self, opts, args):
677 user_cred = self.get_user_cred().save_to_string(save_parents=True)
678 records = self.registry.Resolve(hrn, user_cred)
679 records = filter_records(opts.type, records)
681 print "No record of type", opts.type
682 for record in records:
683 if record['type'] in ['user']:
684 record = UserRecord(dict=record)
685 elif record['type'] in ['slice']:
686 record = SliceRecord(dict=record)
687 elif record['type'] in ['node']:
688 record = NodeRecord(dict=record)
689 elif record['type'].startswith('authority'):
690 record = AuthorityRecord(dict=record)
692 record = SfaRecord(dict=record)
693 if (opts.format == "text"):
696 print record.save_to_string()
700 if not file.startswith(os.sep):
701 file = os.path.join(self.options.sfi_dir, file)
702 save_records_to_file(file, records)
705 def delegate(self, opts, args):
707 delegee_hrn = args[0]
708 if opts.delegate_user:
709 user_cred = self.get_user_cred()
710 cred = self.delegate_cred(user_cred, delegee_hrn)
711 elif opts.delegate_slice:
712 slice_cred = self.get_slice_cred(opts.delegate_slice)
713 cred = self.delegate_cred(slice_cred, delegee_hrn)
715 self.logger.warning("Must specify either --user or --slice <hrn>")
717 delegated_cred = Credential(string=cred)
718 object_hrn = delegated_cred.get_gid_object().get_hrn()
719 if opts.delegate_user:
720 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
721 + get_leaf(object_hrn) + ".cred")
722 elif opts.delegate_slice:
723 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
724 + get_leaf(object_hrn) + ".cred")
726 delegated_cred.save_to_file(dest_fn, save_parents=True)
728 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
730 def delegate_cred(self, object_cred, hrn):
731 # the gid and hrn of the object we are delegating
732 if isinstance(object_cred, str):
733 object_cred = Credential(string=object_cred)
734 object_gid = object_cred.get_gid_object()
735 object_hrn = object_gid.get_hrn()
737 if not object_cred.get_privileges().get_all_delegate():
738 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
741 # the delegating user's gid
742 caller_gid = self._get_gid(self.user)
743 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
745 # the gid of the user who will be delegated to
746 delegee_gid = self._get_gid(hrn)
747 delegee_hrn = delegee_gid.get_hrn()
748 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
749 delegee_gid.save_to_file(filename=delegee_gidfile)
750 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
751 return dcred.save_to_string(save_parents=True)
753 # removed named registry record
754 # - have to first retrieve the record to be removed
755 def remove(self, opts, args):
756 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
764 return self.registry.Remove(hrn, auth_cred, type)
766 # add named registry record
767 def add(self, opts, args):
768 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
772 record_filepath = args[0]
773 rec_file = self.get_record_file(record_filepath)
774 record = load_record_from_file(rec_file).as_dict()
775 return self.registry.Register(record, auth_cred)
777 # update named registry entry
778 def update(self, opts, args):
779 user_cred = self.get_user_cred()
783 rec_file = self.get_record_file(args[0])
784 record = load_record_from_file(rec_file)
785 if record['type'] == "user":
786 if record.get_name() == user_cred.get_gid_object().get_hrn():
787 cred = user_cred.save_to_string(save_parents=True)
789 cred = self.get_auth_cred().save_to_string(save_parents=True)
790 elif record['type'] in ["slice"]:
792 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
793 except xmlrpcprotocol.ServerException, e:
794 # XXX smbaker -- once we have better error return codes, update this
795 # to do something better than a string compare
796 if "Permission error" in e.args[0]:
797 cred = self.get_auth_cred().save_to_string(save_parents=True)
800 elif record.get_type() in ["authority"]:
801 cred = self.get_auth_cred().save_to_string(save_parents=True)
802 elif record.get_type() == 'node':
803 cred = self.get_auth_cred().save_to_string(save_parents=True)
805 raise "unknown record type" + record.get_type()
806 record = record.as_dict()
807 return self.registry.Update(record, cred)
809 def get_trusted_certs(self, opts, args):
811 return uhe trusted certs at this interface
813 trusted_certs = self.registry.get_trusted_certs()
814 for trusted_cert in trusted_certs:
815 cert = Certificate(string=trusted_cert)
816 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
819 def aggregates(self, opts, args):
821 return a list of details about known aggregates
823 user_cred = self.get_user_cred().save_to_string(save_parents=True)
828 result = self.registry.get_aggregates(user_cred, hrn)
832 def registries(self, opts, args):
834 return a list of details about known registries
836 user_cred = self.get_user_cred().save_to_string(save_parents=True)
840 result = self.registry.get_registries(user_cred, hrn)
845 # ==================================================================
846 # Slice-related commands
847 # ==================================================================
849 def version(self, opts, args):
850 if opts.version_local:
851 version=version_core()
853 if opts.version_registry:
856 server = self.get_server_from_opts(opts)
857 version=server.GetVersion()
858 for (k,v) in version.iteritems():
859 print "%-20s: %s"%(k,v)
861 # list instantiated slices
862 def slices(self, opts, args):
864 list instantiated slices
866 user_cred = self.get_user_cred().save_to_string(save_parents=True)
869 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
870 creds.append(delegated_cred)
871 server = self.get_server_from_opts(opts)
872 #results = server.ListSlices(creds, unique_call_id())
873 results = server.ListSlices(creds)
874 display_list(results)
877 # show rspec for named slice
878 def resources(self, opts, args):
879 user_cred = self.get_user_cred().save_to_string(save_parents=True)
880 server = self.slicemgr
882 server = self.get_server_from_opts(opts)
885 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
887 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
894 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
895 creds.append(delegated_cred)
896 if opts.rspec_version:
897 call_options['rspec_version'] = opts.rspec_version
898 #panos add info options
900 call_options['info'] = opts.info
902 call_args = [creds, call_options]
903 if self.server_supports_call_id_arg(server):
904 call_args.append(unique_call_id())
905 result = server.ListResources(*call_args)
907 if opts.file is None:
908 display_rspec(result, format)
911 if not file.startswith(os.sep):
912 file = os.path.join(self.options.sfi_dir, file)
913 save_rspec_to_file(result, file)
916 # created named slice with given rspec
917 def create(self, opts, args):
919 slice_urn = hrn_to_urn(slice_hrn, 'slice')
920 user_cred = self.get_user_cred()
921 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
924 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
925 creds.append(delegated_cred)
926 rspec_file = self.get_rspec_file(args[1])
927 rspec = open(rspec_file).read()
930 # { urn: urn:publicid:IDN+emulab.net+user+alice
931 # keys: [<ssh key A>, <ssh key B>]
934 server = self.get_server_from_opts(opts)
935 version = server.GetVersion()
936 if 'sfa' not in version:
937 # need to pass along user keys if this request is going to a ProtoGENI aggregate
938 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
939 # request. So we will only pass in one user that contains the keys for all
941 user = {'urn': user_cred.get_gid_caller().get_urn(),
943 slice_record = self.registry.Resolve(slice_urn, creds)
944 if slice_record and 'researchers' in slice_record:
945 user_hrns = slice_record['researchers']
946 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
947 user_records = self.registry.Resolve(user_urns, creds)
948 for user_record in user_records:
949 if 'keys' in user_record:
950 user['keys'].extend(user_record['keys'])
953 call_args = [slice_urn, creds, rspec, users]
954 if self.server_supports_call_id_arg(server):
955 call_args.append(unique_call_id())
957 result = server.CreateSliver(*call_args)
961 # get a ticket for the specified slice
962 def get_ticket(self, opts, args):
963 slice_hrn, rspec_path = args[0], args[1]
964 slice_urn = hrn_to_urn(slice_hrn, 'slice')
965 user_cred = self.get_user_cred()
966 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
969 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
970 creds.append(delegated_cred)
971 rspec_file = self.get_rspec_file(rspec_path)
972 rspec = open(rspec_file).read()
973 server = self.get_server_from_opts(opts)
974 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
975 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
976 self.logger.info("writing ticket to %s"%file)
977 ticket = SfaTicket(string=ticket_string)
978 ticket.save_to_file(filename=file, save_parents=True)
980 def redeem_ticket(self, opts, args):
981 ticket_file = args[0]
983 # get slice hrn from the ticket
984 # use this to get the right slice credential
985 ticket = SfaTicket(filename=ticket_file)
987 slice_hrn = ticket.gidObject.get_hrn()
988 slice_urn = hrn_to_urn(slice_hrn, 'slice')
989 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
990 user_cred = self.get_user_cred()
991 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
993 # get a list of node hostnames from the RSpec
994 tree = etree.parse(StringIO(ticket.rspec))
995 root = tree.getroot()
996 hostnames = root.xpath("./network/site/node/hostname/text()")
998 # create an xmlrpc connection to the component manager at each of these
999 # components and gall redeem_ticket
1001 for hostname in hostnames:
1003 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1004 server = self.get_server(hostname, CM_PORT, self.key_file, \
1005 self.cert_file, self.options.debug)
1006 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1007 self.logger.info("Success")
1008 except socket.gaierror:
1009 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1010 except Exception, e:
1011 self.logger.log_exc(e.message)
1014 # delete named slice
1015 def delete(self, opts, args):
1017 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1018 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1019 creds = [slice_cred]
1021 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1022 creds.append(delegated_cred)
1023 server = self.get_server_from_opts(opts)
1025 call_args = [slice_urn, creds]
1026 if self.server_supports_call_id_arg(server):
1027 call_args.append(unique_call_id())
1028 return server.DeleteSliver(*call_args)
1031 def start(self, opts, args):
1033 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1034 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1035 creds = [slice_cred]
1037 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1038 creds.append(delegated_cred)
1039 server = self.get_server_from_opts(opts)
1040 return server.Start(slice_urn, creds)
1043 def stop(self, opts, args):
1045 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1046 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1047 creds = [slice_cred]
1049 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1050 creds.append(delegated_cred)
1051 server = self.get_server_from_opts(opts)
1052 return server.Stop(slice_urn, creds)
1055 def reset(self, opts, args):
1057 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1058 server = self.get_server_from_opts(opts)
1059 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1060 creds = [slice_cred]
1062 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1063 creds.append(delegated_cred)
1064 return server.reset_slice(creds, slice_urn)
1066 def renew(self, opts, args):
1068 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1069 server = self.get_server_from_opts(opts)
1070 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1071 creds = [slice_cred]
1073 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1074 creds.append(delegated_cred)
1077 call_args = [slice_urn, creds, time]
1078 if self.server_supports_call_id_arg(server):
1079 call_args.append(unique_call_id())
1080 return server.RenewSliver(*call_args)
1083 def status(self, opts, args):
1085 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1086 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1087 creds = [slice_cred]
1089 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1090 creds.append(delegated_cred)
1091 server = self.get_server_from_opts(opts)
1092 call_args = [slice_urn, creds]
1093 if self.server_supports_call_id_arg(server):
1094 call_args.append(unique_call_id())
1095 print server.SliverStatus(*call_args)
1098 def shutdown(self, opts, args):
1100 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1101 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1102 creds = [slice_cred]
1104 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1105 creds.append(delegated_cred)
1106 server = self.get_server_from_opts(opts)
1107 return server.Shutdown(slice_urn, creds)
1109 def print_help (self):
1110 self.sfi_parser.print_help()
1111 self.cmd_parser.print_help()
1114 # Main: parse arguments and dispatch to command
1117 self.sfi_parser = self.create_parser()
1118 (options, args) = self.sfi_parser.parse_args()
1119 self.options = options
1121 self.logger.setLevelFromOptVerbose(self.options.verbose)
1122 if options.hashrequest:
1123 self.hashrequest = True
1126 self.logger.critical("No command given. Use -h for help.")
1130 self.cmd_parser = self.create_cmd_parser(command)
1131 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1134 self.logger.info("Command=%s" % command)
1135 if command in ("resources"):
1136 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1137 elif command in ("list", "show", "remove"):
1138 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1139 self.logger.debug('cmd_args %s',cmd_args)
1142 self.dispatch(command, cmd_opts, cmd_args)
1144 self.logger.critical ("Unknown command %s"%command)
1149 if __name__ == "__main__":