3 # sfi -- slice-based facility interface
14 from lxml import etree
15 from StringIO import StringIO
16 from optparse import OptionParser
18 from sfa.trust.certificate import Keypair, Certificate
19 from sfa.trust.gid import GID
20 from sfa.trust.credential import Credential
21 from sfa.trust.sfaticket import SfaTicket
23 from sfa.util.sfalogging import sfi_logger
24 from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn
25 from sfa.util.config import Config
26 from sfa.util.version import version_core
27 from sfa.util.cache import Cache
28 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
30 from sfa.rspecs.rspec import RSpec
31 from sfa.rspecs.rspec_converter import RSpecConverter
32 from sfa.rspecs.version_manager import VersionManager
34 import sfa.client.xmlrpcprotocol as xmlrpcprotocol
35 from sfa.client.client_helper import pg_users_arg, sfa_users_arg
40 # utility methods here
42 def display_rspec(rspec, format='rspec'):
44 tree = etree.parse(StringIO(rspec))
46 result = root.xpath("./network/site/node/hostname/text()")
47 elif format in ['ip']:
48 # The IP address is not yet part of the new RSpec
49 # so this doesn't do anything yet.
50 tree = etree.parse(StringIO(rspec))
52 result = root.xpath("./network/site/node/ipv4/text()")
59 def display_list(results):
60 for result in results:
63 def display_records(recordList, dump=False):
64 ''' Print all fields in the record'''
65 for record in recordList:
66 display_record(record, dump)
68 def display_record(record, dump=False):
72 info = record.getdict()
73 print "%s (%s)" % (info['hrn'], info['type'])
77 def filter_records(type, records):
79 for record in records:
80 if (record['type'] == type) or (type == "all"):
81 filtered_records.append(record)
82 return filtered_records
86 def save_variable_to_file(var, filename, format="text"):
87 f = open(filename, "w")
90 elif format == "pickled":
91 f.write(pickle.dumps(var))
93 # this should never happen
94 print "unknown output format", format
97 def save_rspec_to_file(rspec, filename):
98 if not filename.endswith(".rspec"):
99 filename = filename + ".rspec"
100 f = open(filename, 'w')
105 def save_records_to_file(filename, recordList, format="xml"):
108 for record in recordList:
110 save_record_to_file(filename + "." + str(index), record)
112 save_record_to_file(filename, record)
114 elif format == "xmllist":
115 f = open(filename, "w")
116 f.write("<recordlist>\n")
117 for record in recordList:
118 record = SfaRecord(dict=record)
119 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
120 f.write("</recordlist>\n")
122 elif format == "hrnlist":
123 f = open(filename, "w")
124 for record in recordList:
125 record = SfaRecord(dict=record)
126 f.write(record.get_name() + "\n")
129 # this should never happen
130 print "unknown output format", format
132 def save_record_to_file(filename, record):
133 if record['type'] in ['user']:
134 record = UserRecord(dict=record)
135 elif record['type'] in ['slice']:
136 record = SliceRecord(dict=record)
137 elif record['type'] in ['node']:
138 record = NodeRecord(dict=record)
139 elif record['type'] in ['authority', 'ma', 'sa']:
140 record = AuthorityRecord(dict=record)
142 record = SfaRecord(dict=record)
143 str = record.save_to_string()
144 f=codecs.open(filename, encoding='utf-8',mode="w")
151 def load_record_from_file(filename):
152 f=codecs.open(filename, encoding="utf-8", mode="r")
155 record = SfaRecord(string=str)
160 def unique_call_id(): return uuid.uuid4().urn
164 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
166 # dummy to meet Sfi's expectations for its 'options' field
167 # i.e. s/t we can do setattr on
171 def __init__ (self,options=None):
172 if options is None: options=Sfi.DummyOptions()
173 for opt in Sfi.required_options:
174 if not hasattr(options,opt): setattr(options,opt,None)
175 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
176 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
177 # would be safer to remove self.sfi_dir altogether
178 self.sfi_dir = options.sfi_dir
179 self.options = options
183 self.authority = None
184 self.hashrequest = False
185 self.logger = sfi_logger
186 self.logger.enable_console()
188 def create_cmd_parser(self, command, additional_cmdargs=None):
189 cmdargs = {"list": "authority",
194 "aggregates": "[name]",
195 "registries": "[name]",
196 "create_gid": "[name]",
198 "get_trusted_certs": "cred",
200 "resources": "[name]",
201 "create": "name rspec",
202 "get_ticket": "name rspec",
203 "redeem_ticket": "ticket",
215 if additional_cmdargs:
216 cmdargs.update(additional_cmdargs)
218 if command not in cmdargs:
219 msg="Invalid command\n"
221 msg += ','.join(cmdargs.keys())
222 self.logger.critical(msg)
225 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
226 % (command, cmdargs[command]))
228 # user specifies remote aggregate/sm/component
229 if command in ("resources", "slices", "create", "delete", "start", "stop",
230 "restart", "shutdown", "get_ticket", "renew", "status"):
231 parser.add_option("-a", "--aggregate", dest="aggregate",
232 default=None, help="aggregate host")
233 parser.add_option("-p", "--port", dest="port",
234 default=AGGREGATE_PORT, help="aggregate port")
235 parser.add_option("-c", "--component", dest="component", default=None,
236 help="component hrn")
237 parser.add_option("-d", "--delegate", dest="delegate", default=None,
239 help="Include a credential delegated to the user's root"+\
240 "authority in set of credentials for this call")
242 # registy filter option
243 if command in ("list", "show", "remove"):
244 parser.add_option("-t", "--type", dest="type", type="choice",
245 help="type filter ([all]|user|slice|authority|node|aggregate)",
246 choices=("all", "user", "slice", "authority", "node", "aggregate"),
249 if command in ("resources"):
250 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
251 help="schema type and version of resulting RSpec")
252 parser.add_option("-f", "--format", dest="format", type="choice",
253 help="display format ([xml]|dns|ip)", default="xml",
254 choices=("xml", "dns", "ip"))
255 #panos: a new option to define the type of information about resources a user is interested in
256 parser.add_option("-i", "--info", dest="info",
257 help="optional component information", default=None)
260 # 'create' does return the new rspec, makes sense to save that too
261 if command in ("resources", "show", "list", "create_gid", 'create'):
262 parser.add_option("-o", "--output", dest="file",
263 help="output XML to file", metavar="FILE", default=None)
265 if command in ("show", "list"):
266 parser.add_option("-f", "--format", dest="format", type="choice",
267 help="display format ([text]|xml)", default="text",
268 choices=("text", "xml"))
270 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
271 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
272 choices=("xml", "xmllist", "hrnlist"))
274 if command in ("status", "version"):
275 parser.add_option("-o", "--output", dest="file",
276 help="output dictionary to file", metavar="FILE", default=None)
277 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
278 help="output file format ([text]|pickled)", default="text",
279 choices=("text","pickled"))
281 if command in ("delegate"):
282 parser.add_option("-u", "--user",
283 action="store_true", dest="delegate_user", default=False,
284 help="delegate user credential")
285 parser.add_option("-s", "--slice", dest="delegate_slice",
286 help="delegate slice credential", metavar="HRN", default=None)
288 if command in ("version"):
289 parser.add_option("-a", "--aggregate", dest="aggregate",
290 default=None, help="aggregate host")
291 parser.add_option("-p", "--port", dest="port",
292 default=AGGREGATE_PORT, help="aggregate port")
293 parser.add_option("-R","--registry-version",
294 action="store_true", dest="version_registry", default=False,
295 help="probe registry version instead of slicemgr")
296 parser.add_option("-l","--local",
297 action="store_true", dest="version_local", default=False,
298 help="display version of the local client")
303 def create_parser(self):
305 # Generate command line parser
306 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
307 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
308 parser.add_option("-r", "--registry", dest="registry",
309 help="root registry", metavar="URL", default=None)
310 parser.add_option("-s", "--slicemgr", dest="sm",
311 help="slice manager", metavar="URL", default=None)
312 default_sfi_dir = os.path.expanduser("~/.sfi/")
313 parser.add_option("-d", "--dir", dest="sfi_dir",
314 help="config & working directory - default is " + default_sfi_dir,
315 metavar="PATH", default=default_sfi_dir)
316 parser.add_option("-u", "--user", dest="user",
317 help="user name", metavar="HRN", default=None)
318 parser.add_option("-a", "--auth", dest="auth",
319 help="authority name", metavar="HRN", default=None)
320 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
321 help="verbose mode - cumulative")
322 parser.add_option("-D", "--debug",
323 action="store_true", dest="debug", default=False,
324 help="Debug (xml-rpc) protocol messages")
325 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
326 help="RPC protocol (xmlrpc or soap)")
327 parser.add_option("-k", "--hashrequest",
328 action="store_true", dest="hashrequest", default=False,
329 help="Create a hash of the request that will be authenticated on the server")
330 parser.add_option("-t", "--timeout", dest="timeout", default=None,
331 help="Amout of time tom wait before timing out the request")
332 parser.disable_interspersed_args()
337 def read_config(self):
338 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
340 config = Config (config_file)
342 self.logger.critical("Failed to read configuration file %s"%config_file)
343 self.logger.info("Make sure to remove the export clauses and to add quotes")
344 if self.options.verbose==0:
345 self.logger.info("Re-run with -v for more details")
347 self.logger.log_exc("Could not read config file %s"%config_file)
352 if (self.options.sm is not None):
353 self.sm_url = self.options.sm
354 elif hasattr(config, "SFI_SM"):
355 self.sm_url = config.SFI_SM
357 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
361 if (self.options.registry is not None):
362 self.reg_url = self.options.registry
363 elif hasattr(config, "SFI_REGISTRY"):
364 self.reg_url = config.SFI_REGISTRY
366 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
371 if (self.options.user is not None):
372 self.user = self.options.user
373 elif hasattr(config, "SFI_USER"):
374 self.user = config.SFI_USER
376 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
380 if (self.options.auth is not None):
381 self.authority = self.options.auth
382 elif hasattr(config, "SFI_AUTH"):
383 self.authority = config.SFI_AUTH
385 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
393 # Establish Connection to SliceMgr and Registry Servers
395 def set_servers(self):
398 # Get key and certificate
399 key_file = self.get_key_file()
400 cert_file = self.get_cert_file(key_file)
401 self.key = Keypair(filename=key_file)
402 self.key_file = key_file
403 self.cert_file = cert_file
404 self.cert = GID(filename=cert_file)
405 self.logger.info("Contacting Registry at: %s"%self.reg_url)
406 self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
407 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
408 self.slicemgr = xmlrpcprotocol.server_proxy(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
411 def get_cached_server_version(self, server):
412 # check local cache first
415 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
416 cache_key = server.url + "-version"
418 cache = Cache(cache_file)
421 self.logger.info("Local cache not found at: %s" % cache_file)
424 version = cache.get(cache_key)
427 version = server.GetVersion()
428 # cache version for 24 hours
429 cache.add(cache_key, version, ttl= 60*60*24)
430 self.logger.info("Updating cache file %s" % cache_file)
431 cache.save_to_file(cache_file)
437 def server_supports_options_arg(self, server):
439 Returns true if server support the optional call_id arg, false otherwise.
441 server_version = self.get_cached_server_version(server)
442 if 'sfa' in server_version and 'code_tag' in server_version:
443 code_tag = server_version['code_tag']
444 code_tag_parts = code_tag.split("-")
446 version_parts = code_tag_parts[0].split(".")
447 major, minor = version_parts[0], version_parts[1]
448 rev = code_tag_parts[1]
455 # Get various credential and spec files
457 # Establishes limiting conventions
458 # - conflates MAs and SAs
459 # - assumes last token in slice name is unique
461 # Bootstraps credentials
462 # - bootstrap user credential from self-signed certificate
463 # - bootstrap authority credential from user credential
464 # - bootstrap slice credential from user credential
468 def get_key_file(self):
469 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
470 if (os.path.isfile(file)):
473 self.logger.error("Key file %s does not exist"%file)
477 def get_cert_file(self, key_file):
479 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
480 if (os.path.isfile(cert_file)):
481 # we'd perfer to use Registry issued certs instead of self signed certs.
482 # if this is a Registry cert (GID) then we are done
483 gid = GID(filename=cert_file)
487 # generate self signed certificate
488 k = Keypair(filename=key_file)
489 cert = Certificate(subject=self.user)
491 cert.set_issuer(k, self.user)
493 self.logger.info("Writing self-signed certificate to %s"%cert_file)
494 cert.save_to_file(cert_file)
496 # try to get registry issued cert
498 self.logger.info("Getting Registry issued cert")
500 # *hack. need to set registyr before _get_gid() is called
501 self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
502 gid = self._get_gid(type='user')
504 self.logger.info("Writing certificate to %s"%cert_file)
505 gid.save_to_file(cert_file)
507 self.logger.info("Failed to download Registry issued cert")
511 def get_cached_gid(self, file):
516 if (os.path.isfile(file)):
517 gid = GID(filename=file)
521 def get_gid(self, opts, args):
523 Get the specify gid and save it to file
528 gid = self._get_gid(hrn)
529 self.logger.debug("Sfi.get_gid-> %s" % gid.save_to_string(save_parents=True))
532 def _get_gid(self, hrn=None, type=None):
534 git_gid helper. Retrive the gid from the registry and save it to file.
540 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
541 gid = self.get_cached_gid(gidfile)
543 user_cred = self.get_user_cred()
544 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
546 raise RecordNotFound(args[0])
551 if type == rec['type']:
554 raise RecordNotFound(args[0])
556 gid = GID(string=record['gid'])
557 self.logger.info("Writing gid to %s"%gidfile)
558 gid.save_to_file(filename=gidfile)
562 def get_cached_credential(self, file):
564 Return a cached credential only if it hasn't expired.
566 if (os.path.isfile(file)):
567 credential = Credential(filename=file)
568 # make sure it isnt expired
569 if not credential.get_expiration or \
570 datetime.datetime.today() < credential.get_expiration():
574 def get_user_cred(self):
575 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
576 return self.get_cred(file, 'user', self.user)
578 def get_auth_cred(self):
579 if not self.authority:
580 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
582 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
583 return self.get_cred(file, 'authority', self.authority)
585 def get_slice_cred(self, name):
586 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
587 return self.get_cred(file, 'slice', name)
589 def get_cred(self, file, type, hrn):
590 # attempt to load a cached credential
591 cred = self.get_cached_credential(file)
594 cert_string = self.cert.save_to_string(save_parents=True)
595 user_name = self.user.replace(self.authority + ".", '')
596 if user_name.count(".") > 0:
597 user_name = user_name.replace(".", '_')
598 self.user = self.authority + "." + user_name
599 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
601 # bootstrap slice credential from user credential
602 user_cred = self.get_user_cred().save_to_string(save_parents=True)
603 cred_str = self.registry.GetCredential(user_cred, hrn, type)
606 self.logger.critical("Failed to get %s credential" % type)
609 cred = Credential(string=cred_str)
610 cred.save_to_file(file, save_parents=True)
611 self.logger.info("Writing %s credential to %s" %(type, file))
616 def get_rspec_file(self, rspec):
617 if (os.path.isabs(rspec)):
620 file = os.path.join(self.options.sfi_dir, rspec)
621 if (os.path.isfile(file)):
624 self.logger.critical("No such rspec file %s"%rspec)
627 def get_record_file(self, record):
628 if (os.path.isabs(record)):
631 file = os.path.join(self.options.sfi_dir, record)
632 if (os.path.isfile(file)):
635 self.logger.critical("No such registry record file %s"%record)
638 def load_publickey_string(self, fn):
640 key_string = f.read()
642 # if the filename is a private key file, then extract the public key
643 if "PRIVATE KEY" in key_string:
644 outfn = tempfile.mktemp()
645 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
648 key_string = f.read()
654 def get_component_proxy_from_hrn(self, hrn):
655 # direct connection to the nodes component manager interface
656 user_cred = self.get_user_cred().save_to_string(save_parents=True)
657 records = self.registry.Resolve(hrn, user_cred)
658 records = filter_records('node', records)
660 self.logger.warning("No such component:%r"% opts.component)
663 return self.server_proxy(record['hostname'], CM_PORT, self.key_file, self.cert_file)
665 def server_proxy(self, host, port, keyfile, certfile):
667 Return an instance of an xmlrpc server connection
669 # port is appended onto the domain, before the path. Should look like:
670 # http://domain:port/path
671 host_parts = host.split('/')
672 host_parts[0] = host_parts[0] + ":" + str(port)
673 url = "http://%s" % "/".join(host_parts)
674 return xmlrpcprotocol.server_proxy(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
676 # xxx opts could be retrieved in self.options
677 def server_proxy_from_opts(self, opts):
679 Return instance of an xmlrpc connection to a slice manager, aggregate
680 or component server depending on the specified opts
682 server = self.slicemgr
683 # direct connection to an aggregate
684 if hasattr(opts, 'aggregate') and opts.aggregate:
685 server = self.server_proxy(opts.aggregate, opts.port, self.key_file, self.cert_file)
686 # direct connection to the nodes component manager interface
687 if hasattr(opts, 'component') and opts.component:
688 server = self.get_component_proxy_from_hrn(opts.component)
691 #==========================================================================
692 # Following functions implement the commands
694 # Registry-related commands
695 #==========================================================================
697 def dispatch(self, command, cmd_opts, cmd_args):
698 return getattr(self, command)(cmd_opts, cmd_args)
700 def create_gid(self, opts, args):
705 user_cred = self.get_user_cred().save_to_string(save_parents=True)
706 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
710 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
711 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
712 GID(string=gid).save_to_file(filename)
715 # list entires in named authority registry
716 def list(self, opts, args):
721 user_cred = self.get_user_cred().save_to_string(save_parents=True)
723 list = self.registry.List(hrn, user_cred)
725 raise Exception, "Not enough parameters for the 'list' command"
727 # filter on person, slice, site, node, etc.
728 # THis really should be in the self.filter_records funct def comment...
729 list = filter_records(opts.type, list)
731 print "%s (%s)" % (record['hrn'], record['type'])
733 save_records_to_file(opts.file, list, opts.fileformat)
736 # show named registry record
737 def show(self, opts, args):
742 user_cred = self.get_user_cred().save_to_string(save_parents=True)
743 records = self.registry.Resolve(hrn, user_cred)
744 records = filter_records(opts.type, records)
746 print "No record of type", opts.type
747 for record in records:
748 if record['type'] in ['user']:
749 record = UserRecord(dict=record)
750 elif record['type'] in ['slice']:
751 record = SliceRecord(dict=record)
752 elif record['type'] in ['node']:
753 record = NodeRecord(dict=record)
754 elif record['type'].startswith('authority'):
755 record = AuthorityRecord(dict=record)
757 record = SfaRecord(dict=record)
758 if (opts.format == "text"):
761 print record.save_to_string()
763 save_records_to_file(opts.file, records, opts.fileformat)
766 def delegate(self, opts, args):
768 delegee_hrn = args[0]
769 if opts.delegate_user:
770 user_cred = self.get_user_cred()
771 cred = self.delegate_cred(user_cred, delegee_hrn)
772 elif opts.delegate_slice:
773 slice_cred = self.get_slice_cred(opts.delegate_slice)
774 cred = self.delegate_cred(slice_cred, delegee_hrn)
776 self.logger.warning("Must specify either --user or --slice <hrn>")
778 delegated_cred = Credential(string=cred)
779 object_hrn = delegated_cred.get_gid_object().get_hrn()
780 if opts.delegate_user:
781 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
782 + get_leaf(object_hrn) + ".cred")
783 elif opts.delegate_slice:
784 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
785 + get_leaf(object_hrn) + ".cred")
787 delegated_cred.save_to_file(dest_fn, save_parents=True)
789 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
791 def delegate_cred(self, object_cred, hrn):
792 # the gid and hrn of the object we are delegating
793 if isinstance(object_cred, str):
794 object_cred = Credential(string=object_cred)
795 object_gid = object_cred.get_gid_object()
796 object_hrn = object_gid.get_hrn()
798 if not object_cred.get_privileges().get_all_delegate():
799 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
802 # the delegating user's gid
803 caller_gid = self._get_gid(self.user)
804 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
806 # the gid of the user who will be delegated to
807 delegee_gid = self._get_gid(hrn)
808 delegee_hrn = delegee_gid.get_hrn()
809 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
810 delegee_gid.save_to_file(filename=delegee_gidfile)
811 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
812 return dcred.save_to_string(save_parents=True)
814 # removed named registry record
815 # - have to first retrieve the record to be removed
816 def remove(self, opts, args):
817 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
825 return self.registry.Remove(hrn, auth_cred, type)
827 # add named registry record
828 def add(self, opts, args):
829 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
833 record_filepath = args[0]
834 rec_file = self.get_record_file(record_filepath)
835 record = load_record_from_file(rec_file).as_dict()
836 return self.registry.Register(record, auth_cred)
838 # update named registry entry
839 def update(self, opts, args):
840 user_cred = self.get_user_cred()
844 rec_file = self.get_record_file(args[0])
845 record = load_record_from_file(rec_file)
846 if record['type'] == "user":
847 if record.get_name() == user_cred.get_gid_object().get_hrn():
848 cred = user_cred.save_to_string(save_parents=True)
850 cred = self.get_auth_cred().save_to_string(save_parents=True)
851 elif record['type'] in ["slice"]:
853 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
854 except xmlrpcprotocol.ServerException, e:
855 # XXX smbaker -- once we have better error return codes, update this
856 # to do something better than a string compare
857 if "Permission error" in e.args[0]:
858 cred = self.get_auth_cred().save_to_string(save_parents=True)
861 elif record.get_type() in ["authority"]:
862 cred = self.get_auth_cred().save_to_string(save_parents=True)
863 elif record.get_type() == 'node':
864 cred = self.get_auth_cred().save_to_string(save_parents=True)
866 raise "unknown record type" + record.get_type()
867 record = record.as_dict()
868 return self.registry.Update(record, cred)
870 def get_trusted_certs(self, opts, args):
872 return uhe trusted certs at this interface
874 trusted_certs = self.registry.get_trusted_certs()
875 for trusted_cert in trusted_certs:
876 gid = GID(string=trusted_cert)
878 cert = Certificate(string=trusted_cert)
879 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
882 def aggregates(self, opts, args):
884 return a list of details about known aggregates
886 user_cred = self.get_user_cred().save_to_string(save_parents=True)
891 result = self.registry.get_aggregates(user_cred, hrn)
895 def registries(self, opts, args):
897 return a list of details about known registries
899 user_cred = self.get_user_cred().save_to_string(save_parents=True)
903 result = self.registry.get_registries(user_cred, hrn)
908 # ==================================================================
909 # Slice-related commands
910 # ==================================================================
912 def version(self, opts, args):
913 if opts.version_local:
914 version=version_core()
916 if opts.version_registry:
919 server = self.server_proxy_from_opts(opts)
920 version=server.GetVersion()
921 for (k,v) in version.iteritems():
922 print "%-20s: %s"%(k,v)
924 save_variable_to_file(version, opts.file, opts.fileformat)
926 # list instantiated slices
927 def slices(self, opts, args):
929 list instantiated slices
931 user_cred = self.get_user_cred().save_to_string(save_parents=True)
934 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
935 creds.append(delegated_cred)
936 server = self.server_proxy_from_opts(opts)
938 if self.server_supports_options_arg(server):
939 options = {'call_id': unique_call_id()}
940 call_args.append(options)
941 results = server.ListSlices(*call_args)
942 display_list(results)
945 # show rspec for named slice
946 def resources(self, opts, args):
947 user_cred = self.get_user_cred().save_to_string(save_parents=True)
948 server = self.slicemgr
949 server = self.server_proxy_from_opts(opts)
951 options = {'call_id': unique_call_id()}
952 #panos add info options
954 options['info'] = opts.info
957 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
959 options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
965 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
966 creds.append(delegated_cred)
967 if opts.rspec_version:
968 version_manager = VersionManager()
969 server_version = self.get_cached_server_version(server)
970 if 'sfa' in server_version:
971 # just request the version the client wants
972 options['rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
974 # this must be a protogeni aggregate. We should request a v2 ad rspec
975 # regardless of what the client user requested
976 options['rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
978 call_args = [creds, options]
979 result = server.ListResources(*call_args)
980 if opts.file is None:
981 display_rspec(result, opts.format)
983 save_rspec_to_file(result, opts.file)
986 # created named slice with given rspec
987 def create(self, opts, args):
988 server = self.server_proxy_from_opts(opts)
989 server_version = self.get_cached_server_version(server)
991 slice_urn = hrn_to_urn(slice_hrn, 'slice')
992 user_cred = self.get_user_cred()
993 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
995 if hasattr(opts, 'aggregate') and opts.aggregate:
996 delegated_cred = None
998 # delegate the cred to the callers root authority
999 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)+'.slicemanager')
1000 #delegated_cred = self.delegate_cred(slice_cred, get_authority(slice_hrn))
1001 #creds.append(delegated_cred)
1003 rspec_file = self.get_rspec_file(args[1])
1004 rspec = open(rspec_file).read()
1006 # need to pass along user keys to the aggregate.
1008 # { urn: urn:publicid:IDN+emulab.net+user+alice
1009 # keys: [<ssh key A>, <ssh key B>]
1012 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
1013 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
1014 slice_record = slice_records[0]
1015 user_hrns = slice_record['researcher']
1016 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
1017 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
1019 if 'sfa' not in server_version:
1020 users = pg_users_arg(user_records)
1021 rspec = RSpec(rspec)
1022 rspec.filter({'component_manager_id': server_version['urn']})
1023 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
1024 creds = [slice_cred]
1026 users = sfa_users_arg(user_records, slice_record)
1027 creds = [slice_cred]
1029 creds.append(delegated_cred)
1030 call_args = [slice_urn, creds, rspec, users]
1031 if self.server_supports_options_arg(server):
1032 options = {'call_id': unique_call_id()}
1033 call_args.append(options)
1034 result = server.CreateSliver(*call_args)
1035 if opts.file is None:
1038 save_rspec_to_file (result, opts.file)
1041 # get a ticket for the specified slice
1042 def get_ticket(self, opts, args):
1043 slice_hrn, rspec_path = args[0], args[1]
1044 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1045 user_cred = self.get_user_cred()
1046 slice_cred = self.get_slice_cred(slice_hrn).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 rspec_file = self.get_rspec_file(rspec_path)
1052 rspec = open(rspec_file).read()
1053 server = self.server_proxy_from_opts(opts)
1054 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1055 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1056 self.logger.info("writing ticket to %s"%file)
1057 ticket = SfaTicket(string=ticket_string)
1058 ticket.save_to_file(filename=file, save_parents=True)
1060 def redeem_ticket(self, opts, args):
1061 ticket_file = args[0]
1063 # get slice hrn from the ticket
1064 # use this to get the right slice credential
1065 ticket = SfaTicket(filename=ticket_file)
1067 slice_hrn = ticket.gidObject.get_hrn()
1068 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1069 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1070 user_cred = self.get_user_cred()
1071 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1073 # get a list of node hostnames from the RSpec
1074 tree = etree.parse(StringIO(ticket.rspec))
1075 root = tree.getroot()
1076 hostnames = root.xpath("./network/site/node/hostname/text()")
1078 # create an xmlrpc connection to the component manager at each of these
1079 # components and gall redeem_ticket
1081 for hostname in hostnames:
1083 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1084 server = self.server_proxy(hostname, CM_PORT, self.key_file, \
1085 self.cert_file, self.options.debug)
1086 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1087 self.logger.info("Success")
1088 except socket.gaierror:
1089 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1090 except Exception, e:
1091 self.logger.log_exc(e.message)
1094 # delete named slice
1095 def delete(self, opts, args):
1097 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1098 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1099 creds = [slice_cred]
1101 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1102 creds.append(delegated_cred)
1103 server = self.server_proxy_from_opts(opts)
1104 call_args = [slice_urn, creds]
1105 if self.server_supports_options_arg(server):
1106 options = {'call_id': unique_call_id()}
1107 call_args.append(options)
1108 return server.DeleteSliver(*call_args)
1111 def start(self, opts, args):
1113 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1114 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1115 creds = [slice_cred]
1117 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1118 creds.append(delegated_cred)
1119 server = self.server_proxy_from_opts(opts)
1120 return server.Start(slice_urn, creds)
1123 def stop(self, opts, args):
1125 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1126 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1127 creds = [slice_cred]
1129 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1130 creds.append(delegated_cred)
1131 server = self.server_proxy_from_opts(opts)
1132 return server.Stop(slice_urn, creds)
1135 def reset(self, opts, args):
1137 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1138 server = self.server_proxy_from_opts(opts)
1139 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1140 creds = [slice_cred]
1142 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1143 creds.append(delegated_cred)
1144 return server.reset_slice(creds, slice_urn)
1146 def renew(self, opts, args):
1148 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1149 server = self.server_proxy_from_opts(opts)
1150 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1151 creds = [slice_cred]
1153 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1154 creds.append(delegated_cred)
1157 call_args = [slice_urn, creds, time]
1158 if self.server_supports_options_arg(server):
1159 options = {'call_id': unique_call_id()}
1160 call_args.append(options)
1161 return server.RenewSliver(*call_args)
1164 def status(self, opts, args):
1166 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1167 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1168 creds = [slice_cred]
1170 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1171 creds.append(delegated_cred)
1172 server = self.server_proxy_from_opts(opts)
1173 call_args = [slice_urn, creds]
1174 if self.server_supports_options_arg(server):
1175 options = {'call_id': unique_call_id()}
1176 call_args.append(options)
1177 result = server.SliverStatus(*call_args)
1180 save_variable_to_file(result, opts.file, opts.fileformat)
1183 def shutdown(self, opts, args):
1185 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1186 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1187 creds = [slice_cred]
1189 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1190 creds.append(delegated_cred)
1191 server = self.server_proxy_from_opts(opts)
1192 return server.Shutdown(slice_urn, creds)
1194 def print_help (self):
1195 self.sfi_parser.print_help()
1196 self.cmd_parser.print_help()
1199 # Main: parse arguments and dispatch to command
1202 self.sfi_parser = self.create_parser()
1203 (options, args) = self.sfi_parser.parse_args()
1204 self.options = options
1206 self.logger.setLevelFromOptVerbose(self.options.verbose)
1207 if options.hashrequest:
1208 self.hashrequest = True
1211 self.logger.critical("No command given. Use -h for help.")
1215 self.cmd_parser = self.create_cmd_parser(command)
1216 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1219 self.logger.info("Command=%s" % command)
1220 if command in ("resources"):
1221 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1222 elif command in ("list", "show", "remove"):
1223 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1224 self.logger.debug('cmd_args %s' % cmd_args)
1227 self.dispatch(command, cmd_opts, cmd_args)
1229 self.logger.critical ("Unknown command %s"%command)
1235 if __name__ == "__main__":