3 # sfi -- slice-based facility interface
5 # xxx NOTE this will soon be reviewed to take advantage of sfaclientlib
16 from lxml import etree
17 from StringIO import StringIO
18 from optparse import OptionParser
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.trust.sfaticket import SfaTicket
25 from sfa.util.sfalogging import sfi_logger
26 from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn
27 from sfa.util.config import Config
28 from sfa.util.version import version_core
29 from sfa.util.cache import Cache
31 from sfa.storage.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
33 from sfa.rspecs.rspec import RSpec
34 from sfa.rspecs.rspec_converter import RSpecConverter
35 from sfa.rspecs.version_manager import VersionManager
36 from sfa.client.return_value import ReturnValue
38 import sfa.client.sfaprotocol as sfaprotocol
39 from sfa.client.client_helper import pg_users_arg, sfa_users_arg
44 # utility methods here
46 def display_rspec(rspec, format='rspec'):
48 tree = etree.parse(StringIO(rspec))
50 result = root.xpath("./network/site/node/hostname/text()")
51 elif format in ['ip']:
52 # The IP address is not yet part of the new RSpec
53 # so this doesn't do anything yet.
54 tree = etree.parse(StringIO(rspec))
56 result = root.xpath("./network/site/node/ipv4/text()")
63 def display_list(results):
64 for result in results:
67 def display_records(recordList, dump=False):
68 ''' Print all fields in the record'''
69 for record in recordList:
70 display_record(record, dump)
72 def display_record(record, dump=False):
76 info = record.getdict()
77 print "%s (%s)" % (info['hrn'], info['type'])
81 def filter_records(type, records):
83 for record in records:
84 if (record['type'] == type) or (type == "all"):
85 filtered_records.append(record)
86 return filtered_records
90 def save_variable_to_file(var, filename, format="text"):
91 f = open(filename, "w")
94 elif format == "pickled":
95 f.write(pickle.dumps(var))
97 # this should never happen
98 print "unknown output format", format
101 def save_rspec_to_file(rspec, filename):
102 if not filename.endswith(".rspec"):
103 filename = filename + ".rspec"
104 f = open(filename, 'w')
109 def save_records_to_file(filename, recordList, format="xml"):
112 for record in recordList:
114 save_record_to_file(filename + "." + str(index), record)
116 save_record_to_file(filename, record)
118 elif format == "xmllist":
119 f = open(filename, "w")
120 f.write("<recordlist>\n")
121 for record in recordList:
122 record = SfaRecord(dict=record)
123 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
124 f.write("</recordlist>\n")
126 elif format == "hrnlist":
127 f = open(filename, "w")
128 for record in recordList:
129 record = SfaRecord(dict=record)
130 f.write(record.get_name() + "\n")
133 # this should never happen
134 print "unknown output format", format
136 def save_record_to_file(filename, record):
137 if record['type'] in ['user']:
138 record = UserRecord(dict=record)
139 elif record['type'] in ['slice']:
140 record = SliceRecord(dict=record)
141 elif record['type'] in ['node']:
142 record = NodeRecord(dict=record)
143 elif record['type'] in ['authority', 'ma', 'sa']:
144 record = AuthorityRecord(dict=record)
146 record = SfaRecord(dict=record)
147 str = record.save_to_string()
148 f=codecs.open(filename, encoding='utf-8',mode="w")
155 def load_record_from_file(filename):
156 f=codecs.open(filename, encoding="utf-8", mode="r")
159 record = SfaRecord(string=str)
164 def unique_call_id(): return uuid.uuid4().urn
168 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
170 # dummy to meet Sfi's expectations for its 'options' field
171 # i.e. s/t we can do setattr on
175 def __init__ (self,options=None):
176 if options is None: options=Sfi.DummyOptions()
177 for opt in Sfi.required_options:
178 if not hasattr(options,opt): setattr(options,opt,None)
179 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
180 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
181 # would be safer to remove self.sfi_dir altogether
182 self.sfi_dir = options.sfi_dir
183 self.options = options
187 self.authority = None
188 self.hashrequest = False
189 self.logger = sfi_logger
190 self.logger.enable_console()
192 def create_cmd_parser(self, command, additional_cmdargs=None):
193 cmdargs = {"list": "authority",
198 "aggregates": "[name]",
199 "registries": "[name]",
200 "create_gid": "[name]",
202 "get_trusted_certs": "cred",
204 "resources": "[name]",
205 "create": "name rspec",
206 "get_ticket": "name rspec",
207 "redeem_ticket": "ticket",
219 if additional_cmdargs:
220 cmdargs.update(additional_cmdargs)
222 if command not in cmdargs:
223 msg="Invalid command\n"
225 msg += ','.join(cmdargs.keys())
226 self.logger.critical(msg)
229 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
230 % (command, cmdargs[command]))
232 # user specifies remote aggregate/sm/component
233 if command in ("resources", "slices", "create", "delete", "start", "stop",
234 "restart", "shutdown", "get_ticket", "renew", "status"):
235 parser.add_option("-a", "--aggregate", dest="aggregate",
236 default=None, help="aggregate host")
237 parser.add_option("-p", "--port", dest="port",
238 default=AGGREGATE_PORT, help="aggregate port")
239 parser.add_option("-c", "--component", dest="component", default=None,
240 help="component hrn")
241 parser.add_option("-d", "--delegate", dest="delegate", default=None,
243 help="Include a credential delegated to the user's root"+\
244 "authority in set of credentials for this call")
246 # registy filter option
247 if command in ("list", "show", "remove"):
248 parser.add_option("-t", "--type", dest="type", type="choice",
249 help="type filter ([all]|user|slice|authority|node|aggregate)",
250 choices=("all", "user", "slice", "authority", "node", "aggregate"),
253 if command in ("resources"):
254 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
255 help="schema type and version of resulting RSpec")
256 parser.add_option("-f", "--format", dest="format", type="choice",
257 help="display format ([xml]|dns|ip)", default="xml",
258 choices=("xml", "dns", "ip"))
259 #panos: a new option to define the type of information about resources a user is interested in
260 parser.add_option("-i", "--info", dest="info",
261 help="optional component information", default=None)
264 # 'create' does return the new rspec, makes sense to save that too
265 if command in ("resources", "show", "list", "create_gid", 'create'):
266 parser.add_option("-o", "--output", dest="file",
267 help="output XML to file", metavar="FILE", default=None)
269 if command in ("show", "list"):
270 parser.add_option("-f", "--format", dest="format", type="choice",
271 help="display format ([text]|xml)", default="text",
272 choices=("text", "xml"))
274 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
275 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
276 choices=("xml", "xmllist", "hrnlist"))
278 if command in ("status", "version"):
279 parser.add_option("-o", "--output", dest="file",
280 help="output dictionary to file", metavar="FILE", default=None)
281 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
282 help="output file format ([text]|pickled)", default="text",
283 choices=("text","pickled"))
285 if command in ("delegate"):
286 parser.add_option("-u", "--user",
287 action="store_true", dest="delegate_user", default=False,
288 help="delegate user credential")
289 parser.add_option("-s", "--slice", dest="delegate_slice",
290 help="delegate slice credential", metavar="HRN", default=None)
292 if command in ("version"):
293 parser.add_option("-a", "--aggregate", dest="aggregate",
294 default=None, help="aggregate host")
295 parser.add_option("-p", "--port", dest="port",
296 default=AGGREGATE_PORT, help="aggregate port")
297 parser.add_option("-R","--registry-version",
298 action="store_true", dest="version_registry", default=False,
299 help="probe registry version instead of slicemgr")
300 parser.add_option("-l","--local",
301 action="store_true", dest="version_local", default=False,
302 help="display version of the local client")
307 def create_parser(self):
309 # Generate command line parser
310 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
311 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
312 parser.add_option("-r", "--registry", dest="registry",
313 help="root registry", metavar="URL", default=None)
314 parser.add_option("-s", "--slicemgr", dest="sm",
315 help="slice manager", metavar="URL", default=None)
316 default_sfi_dir = os.path.expanduser("~/.sfi/")
317 parser.add_option("-d", "--dir", dest="sfi_dir",
318 help="config & working directory - default is " + default_sfi_dir,
319 metavar="PATH", default=default_sfi_dir)
320 parser.add_option("-u", "--user", dest="user",
321 help="user name", metavar="HRN", default=None)
322 parser.add_option("-a", "--auth", dest="auth",
323 help="authority name", metavar="HRN", default=None)
324 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
325 help="verbose mode - cumulative")
326 parser.add_option("-D", "--debug",
327 action="store_true", dest="debug", default=False,
328 help="Debug (xml-rpc) protocol messages")
329 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
330 help="RPC protocol (xmlrpc or soap)")
331 parser.add_option("-k", "--hashrequest",
332 action="store_true", dest="hashrequest", default=False,
333 help="Create a hash of the request that will be authenticated on the server")
334 parser.add_option("-t", "--timeout", dest="timeout", default=None,
335 help="Amout of time tom wait before timing out the request")
336 parser.disable_interspersed_args()
341 def read_config(self):
342 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
344 config = Config (config_file)
346 self.logger.critical("Failed to read configuration file %s"%config_file)
347 self.logger.info("Make sure to remove the export clauses and to add quotes")
348 if self.options.verbose==0:
349 self.logger.info("Re-run with -v for more details")
351 self.logger.log_exc("Could not read config file %s"%config_file)
356 if (self.options.sm is not None):
357 self.sm_url = self.options.sm
358 elif hasattr(config, "SFI_SM"):
359 self.sm_url = config.SFI_SM
361 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
365 if (self.options.registry is not None):
366 self.reg_url = self.options.registry
367 elif hasattr(config, "SFI_REGISTRY"):
368 self.reg_url = config.SFI_REGISTRY
370 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
375 if (self.options.user is not None):
376 self.user = self.options.user
377 elif hasattr(config, "SFI_USER"):
378 self.user = config.SFI_USER
380 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
384 if (self.options.auth is not None):
385 self.authority = self.options.auth
386 elif hasattr(config, "SFI_AUTH"):
387 self.authority = config.SFI_AUTH
389 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
397 # Establish Connection to SliceMgr and Registry Servers
399 def set_servers(self):
402 # Get key and certificate
403 key_file = self.get_key_file()
404 cert_file = self.get_cert_file(key_file)
405 self.key_file = key_file
406 self.cert_file = cert_file
407 self.cert = GID(filename=cert_file)
408 self.logger.info("Contacting Registry at: %s"%self.reg_url)
409 self.registry = sfaprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
410 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
411 self.slicemgr = sfaprotocol.server_proxy(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
414 def get_cached_server_version(self, server):
415 # check local cache first
418 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
419 cache_key = server.url + "-version"
421 cache = Cache(cache_file)
424 self.logger.info("Local cache not found at: %s" % cache_file)
427 version = cache.get(cache_key)
430 result = server.GetVersion()
431 version= ReturnValue.get_value(result)
432 # cache version for 24 hours
433 cache.add(cache_key, version, ttl= 60*60*24)
434 self.logger.info("Updating cache file %s" % cache_file)
435 cache.save_to_file(cache_file)
440 def server_supports_options_arg(self, server):
442 Returns true if server support the optional call_id arg, false otherwise.
444 server_version = self.get_cached_server_version(server)
445 if 'sfa' in server_version and 'code_tag' in server_version:
446 code_tag = server_version['code_tag']
447 code_tag_parts = code_tag.split("-")
449 version_parts = code_tag_parts[0].split(".")
450 major, minor = version_parts[0], version_parts[1]
451 rev = code_tag_parts[1]
458 # Get various credential and spec files
460 # Establishes limiting conventions
461 # - conflates MAs and SAs
462 # - assumes last token in slice name is unique
464 # Bootstraps credentials
465 # - bootstrap user credential from self-signed certificate
466 # - bootstrap authority credential from user credential
467 # - bootstrap slice credential from user credential
471 def get_key_file(self):
472 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
473 if (os.path.isfile(file)):
476 self.logger.error("Key file %s does not exist"%file)
480 def get_cert_file(self, key_file):
482 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
483 if (os.path.isfile(cert_file)):
484 # we'd perfer to use Registry issued certs instead of self signed certs.
485 # if this is a Registry cert (GID) then we are done
486 gid = GID(filename=cert_file)
490 # generate self signed certificate
491 k = Keypair(filename=key_file)
492 cert = Certificate(subject=self.user)
494 cert.set_issuer(k, self.user)
496 self.logger.info("Writing self-signed certificate to %s"%cert_file)
497 cert.save_to_file(cert_file)
499 # try to get registry issued cert
501 self.logger.info("Getting Registry issued cert")
503 # *hack. need to set registry before _get_gid() is called
504 self.registry = sfaprotocol.server_proxy(self.reg_url, key_file, cert_file,
505 timeout=self.options.timeout, verbose=self.options.debug)
506 gid = self._get_gid(type='user')
508 self.logger.info("Writing certificate to %s"%cert_file)
509 gid.save_to_file(cert_file)
511 self.logger.info("Failed to download Registry issued cert")
515 def get_cached_gid(self, file):
520 if (os.path.isfile(file)):
521 gid = GID(filename=file)
525 def get_gid(self, opts, args):
527 Get the specify gid and save it to file
532 gid = self._get_gid(hrn)
533 self.logger.debug("Sfi.get_gid-> %s" % gid.save_to_string(save_parents=True))
536 def _get_gid(self, hrn=None, type=None):
538 git_gid helper. Retrive the gid from the registry and save it to file.
544 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
545 gid = self.get_cached_gid(gidfile)
547 user_cred = self.get_user_cred()
548 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
550 raise RecordNotFound(args[0])
555 if type == rec['type']:
558 raise RecordNotFound(args[0])
560 gid = GID(string=record['gid'])
561 self.logger.info("Writing gid to %s"%gidfile)
562 gid.save_to_file(filename=gidfile)
566 def get_cached_credential(self, file):
568 Return a cached credential only if it hasn't expired.
570 if (os.path.isfile(file)):
571 credential = Credential(filename=file)
572 # make sure it isnt expired
573 if not credential.get_expiration or \
574 datetime.datetime.today() < credential.get_expiration():
578 def get_user_cred(self):
579 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
580 return self.get_cred(file, 'user', self.user)
582 def get_auth_cred(self):
583 if not self.authority:
584 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
586 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
587 return self.get_cred(file, 'authority', self.authority)
589 def get_slice_cred(self, name):
590 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
591 return self.get_cred(file, 'slice', name)
593 def get_cred(self, file, type, hrn):
594 # attempt to load a cached credential
595 cred = self.get_cached_credential(file)
598 cert_string = self.cert.save_to_string(save_parents=True)
599 user_name = self.user.replace(self.authority + ".", '')
600 if user_name.count(".") > 0:
601 user_name = user_name.replace(".", '_')
602 self.user = self.authority + "." + user_name
603 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
605 # bootstrap slice credential from user credential
606 user_cred = self.get_user_cred().save_to_string(save_parents=True)
607 cred_str = self.registry.GetCredential(user_cred, hrn, type)
610 self.logger.critical("Failed to get %s credential" % type)
613 cred = Credential(string=cred_str)
614 cred.save_to_file(file, save_parents=True)
615 self.logger.info("Writing %s credential to %s" %(type, file))
620 def get_rspec_file(self, rspec):
621 if (os.path.isabs(rspec)):
624 file = os.path.join(self.options.sfi_dir, rspec)
625 if (os.path.isfile(file)):
628 self.logger.critical("No such rspec file %s"%rspec)
631 def get_record_file(self, record):
632 if (os.path.isabs(record)):
635 file = os.path.join(self.options.sfi_dir, record)
636 if (os.path.isfile(file)):
639 self.logger.critical("No such registry record file %s"%record)
642 def load_publickey_string(self, fn):
644 key_string = f.read()
646 # if the filename is a private key file, then extract the public key
647 if "PRIVATE KEY" in key_string:
648 outfn = tempfile.mktemp()
649 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
652 key_string = f.read()
658 def get_component_proxy_from_hrn(self, hrn):
659 # direct connection to the nodes component manager interface
660 user_cred = self.get_user_cred().save_to_string(save_parents=True)
661 records = self.registry.Resolve(hrn, user_cred)
662 records = filter_records('node', records)
664 self.logger.warning("No such component:%r"% opts.component)
667 return self.server_proxy(record['hostname'], CM_PORT, self.key_file, self.cert_file)
669 def server_proxy(self, host, port, keyfile, certfile):
671 Return an instance of an xmlrpc server connection
673 # port is appended onto the domain, before the path. Should look like:
674 # http://domain:port/path
675 host_parts = host.split('/')
676 host_parts[0] = host_parts[0] + ":" + str(port)
677 url = "http://%s" % "/".join(host_parts)
678 return sfaprotocol.server_proxy(url, keyfile, certfile, timeout=self.options.timeout,
679 verbose=self.options.debug)
681 # xxx opts could be retrieved in self.options
682 def server_proxy_from_opts(self, opts):
684 Return instance of an xmlrpc connection to a slice manager, aggregate
685 or component server depending on the specified opts
687 server = self.slicemgr
688 # direct connection to an aggregate
689 if hasattr(opts, 'aggregate') and opts.aggregate:
690 server = self.server_proxy(opts.aggregate, opts.port, self.key_file, self.cert_file)
691 # direct connection to the nodes component manager interface
692 if hasattr(opts, 'component') and opts.component:
693 server = self.get_component_proxy_from_hrn(opts.component)
696 #==========================================================================
697 # Following functions implement the commands
699 # Registry-related commands
700 #==========================================================================
702 def dispatch(self, command, cmd_opts, cmd_args):
703 return getattr(self, command)(cmd_opts, cmd_args)
705 def create_gid(self, opts, args):
710 user_cred = self.get_user_cred().save_to_string(save_parents=True)
711 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
715 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
716 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
717 GID(string=gid).save_to_file(filename)
720 # list entires in named authority registry
721 def list(self, opts, args):
726 user_cred = self.get_user_cred().save_to_string(save_parents=True)
728 list = self.registry.List(hrn, user_cred)
730 raise Exception, "Not enough parameters for the 'list' command"
732 # filter on person, slice, site, node, etc.
733 # THis really should be in the self.filter_records funct def comment...
734 list = filter_records(opts.type, list)
736 print "%s (%s)" % (record['hrn'], record['type'])
738 save_records_to_file(opts.file, list, opts.fileformat)
741 # show named registry record
742 def show(self, opts, args):
747 user_cred = self.get_user_cred().save_to_string(save_parents=True)
748 records = self.registry.Resolve(hrn, user_cred)
749 records = filter_records(opts.type, records)
751 self.logger.error("No record of type %s"% opts.type)
752 for record in records:
753 if record['type'] in ['user']:
754 record = UserRecord(dict=record)
755 elif record['type'] in ['slice']:
756 record = SliceRecord(dict=record)
757 elif record['type'] in ['node']:
758 record = NodeRecord(dict=record)
759 elif record['type'].startswith('authority'):
760 record = AuthorityRecord(dict=record)
762 record = SfaRecord(dict=record)
763 if (opts.format == "text"):
766 print record.save_to_string()
768 save_records_to_file(opts.file, records, opts.fileformat)
771 def delegate(self, opts, args):
773 delegee_hrn = args[0]
774 if opts.delegate_user:
775 user_cred = self.get_user_cred()
776 cred = self.delegate_cred(user_cred, delegee_hrn)
777 elif opts.delegate_slice:
778 slice_cred = self.get_slice_cred(opts.delegate_slice)
779 cred = self.delegate_cred(slice_cred, delegee_hrn)
781 self.logger.warning("Must specify either --user or --slice <hrn>")
783 delegated_cred = Credential(string=cred)
784 object_hrn = delegated_cred.get_gid_object().get_hrn()
785 if opts.delegate_user:
786 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
787 + get_leaf(object_hrn) + ".cred")
788 elif opts.delegate_slice:
789 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
790 + get_leaf(object_hrn) + ".cred")
792 delegated_cred.save_to_file(dest_fn, save_parents=True)
794 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
796 def delegate_cred(self, object_cred, hrn):
797 # the gid and hrn of the object we are delegating
798 if isinstance(object_cred, str):
799 object_cred = Credential(string=object_cred)
800 object_gid = object_cred.get_gid_object()
801 object_hrn = object_gid.get_hrn()
803 if not object_cred.get_privileges().get_all_delegate():
804 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
807 # the delegating user's gid
808 caller_gid = self._get_gid(self.user)
809 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
811 # the gid of the user who will be delegated to
812 delegee_gid = self._get_gid(hrn)
813 delegee_hrn = delegee_gid.get_hrn()
814 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
815 delegee_gid.save_to_file(filename=delegee_gidfile)
816 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
817 return dcred.save_to_string(save_parents=True)
819 # removed named registry record
820 # - have to first retrieve the record to be removed
821 def remove(self, opts, args):
822 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
830 return self.registry.Remove(hrn, auth_cred, type)
832 # add named registry record
833 def add(self, opts, args):
834 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
838 record_filepath = args[0]
839 rec_file = self.get_record_file(record_filepath)
840 record = load_record_from_file(rec_file).as_dict()
841 return self.registry.Register(record, auth_cred)
843 # update named registry entry
844 def update(self, opts, args):
845 user_cred = self.get_user_cred()
849 rec_file = self.get_record_file(args[0])
850 record = load_record_from_file(rec_file)
851 if record['type'] == "user":
852 if record.get_name() == user_cred.get_gid_object().get_hrn():
853 cred = user_cred.save_to_string(save_parents=True)
855 cred = self.get_auth_cred().save_to_string(save_parents=True)
856 elif record['type'] in ["slice"]:
858 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
859 except sfaprotocol.ServerException, e:
860 # XXX smbaker -- once we have better error return codes, update this
861 # to do something better than a string compare
862 if "Permission error" in e.args[0]:
863 cred = self.get_auth_cred().save_to_string(save_parents=True)
866 elif record.get_type() in ["authority"]:
867 cred = self.get_auth_cred().save_to_string(save_parents=True)
868 elif record.get_type() == 'node':
869 cred = self.get_auth_cred().save_to_string(save_parents=True)
871 raise "unknown record type" + record.get_type()
872 record = record.as_dict()
873 return self.registry.Update(record, cred)
875 def get_trusted_certs(self, opts, args):
877 return uhe trusted certs at this interface
879 trusted_certs = self.registry.get_trusted_certs()
880 for trusted_cert in trusted_certs:
881 gid = GID(string=trusted_cert)
883 cert = Certificate(string=trusted_cert)
884 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
887 def aggregates(self, opts, args):
889 return a list of details about known aggregates
891 user_cred = self.get_user_cred().save_to_string(save_parents=True)
896 result = self.registry.get_aggregates(user_cred, hrn)
900 def registries(self, opts, args):
902 return a list of details about known registries
904 user_cred = self.get_user_cred().save_to_string(save_parents=True)
908 result = self.registry.get_registries(user_cred, hrn)
913 # ==================================================================
914 # Slice-related commands
915 # ==================================================================
917 def version(self, opts, args):
918 if opts.version_local:
919 version=version_core()
921 if opts.version_registry:
924 server = self.server_proxy_from_opts(opts)
925 result = server.GetVersion()
926 version = ReturnValue.get_value(result)
927 for (k,v) in version.iteritems():
928 print "%-20s: %s"%(k,v)
930 save_variable_to_file(version, opts.file, opts.fileformat)
932 # list instantiated slices
933 def slices(self, opts, args):
935 list instantiated slices
937 user_cred = self.get_user_cred().save_to_string(save_parents=True)
940 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
941 creds.append(delegated_cred)
942 server = self.server_proxy_from_opts(opts)
944 if self.server_supports_options_arg(server):
945 options = {'call_id': unique_call_id()}
946 call_args.append(options)
947 result = server.ListSlices(*call_args)
948 value = ReturnValue.get_value(result)
952 # show rspec for named slice
953 def resources(self, opts, args):
954 user_cred = self.get_user_cred().save_to_string(save_parents=True)
955 server = self.server_proxy_from_opts(opts)
957 options = {'call_id': unique_call_id()}
958 #panos add info options
960 options['info'] = opts.info
963 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
965 options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
971 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
972 creds.append(delegated_cred)
973 if opts.rspec_version:
974 version_manager = VersionManager()
975 server_version = self.get_cached_server_version(server)
976 if 'sfa' in server_version:
977 # just request the version the client wants
978 options['geni_rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
980 # this must be a protogeni aggregate. We should request a v2 ad rspec
981 # regardless of what the client user requested
982 options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
984 options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
986 call_args = [creds, options]
987 result = server.ListResources(*call_args)
988 value = ReturnValue.get_value(result)
989 if opts.file is None:
990 display_rspec(value, opts.format)
992 save_rspec_to_file(value, opts.file)
995 # created named slice with given rspec
996 def create(self, opts, args):
997 server = self.server_proxy_from_opts(opts)
998 server_version = self.get_cached_server_version(server)
1000 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1001 user_cred = self.get_user_cred()
1002 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1004 if hasattr(opts, 'aggregate') and opts.aggregate:
1005 delegated_cred = None
1007 # delegate the cred to the callers root authority
1008 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)+'.slicemanager')
1009 #delegated_cred = self.delegate_cred(slice_cred, get_authority(slice_hrn))
1010 #creds.append(delegated_cred)
1012 rspec_file = self.get_rspec_file(args[1])
1013 rspec = open(rspec_file).read()
1015 # need to pass along user keys to the aggregate.
1017 # { urn: urn:publicid:IDN+emulab.net+user+alice
1018 # keys: [<ssh key A>, <ssh key B>]
1021 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
1022 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
1023 slice_record = slice_records[0]
1024 user_hrns = slice_record['researcher']
1025 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
1026 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
1028 if 'sfa' not in server_version:
1029 users = pg_users_arg(user_records)
1030 rspec = RSpec(rspec)
1031 rspec.filter({'component_manager_id': server_version['urn']})
1032 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
1033 creds = [slice_cred]
1035 users = sfa_users_arg(user_records, slice_record)
1036 creds = [slice_cred]
1038 creds.append(delegated_cred)
1039 call_args = [slice_urn, creds, rspec, users]
1040 if self.server_supports_options_arg(server):
1041 options = {'call_id': unique_call_id()}
1042 call_args.append(options)
1043 result = server.CreateSliver(*call_args)
1044 value = ReturnValue.get_value(result)
1045 if opts.file is None:
1048 save_rspec_to_file (value, opts.file)
1051 # get a ticket for the specified slice
1052 def get_ticket(self, opts, args):
1053 slice_hrn, rspec_path = args[0], args[1]
1054 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1055 user_cred = self.get_user_cred()
1056 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1057 creds = [slice_cred]
1059 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1060 creds.append(delegated_cred)
1061 rspec_file = self.get_rspec_file(rspec_path)
1062 rspec = open(rspec_file).read()
1063 server = self.server_proxy_from_opts(opts)
1064 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1065 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1066 self.logger.info("writing ticket to %s"%file)
1067 ticket = SfaTicket(string=ticket_string)
1068 ticket.save_to_file(filename=file, save_parents=True)
1070 def redeem_ticket(self, opts, args):
1071 ticket_file = args[0]
1073 # get slice hrn from the ticket
1074 # use this to get the right slice credential
1075 ticket = SfaTicket(filename=ticket_file)
1077 slice_hrn = ticket.gidObject.get_hrn()
1078 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1079 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1080 user_cred = self.get_user_cred()
1081 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1083 # get a list of node hostnames from the RSpec
1084 tree = etree.parse(StringIO(ticket.rspec))
1085 root = tree.getroot()
1086 hostnames = root.xpath("./network/site/node/hostname/text()")
1088 # create an xmlrpc connection to the component manager at each of these
1089 # components and gall redeem_ticket
1091 for hostname in hostnames:
1093 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1094 server = self.server_proxy(hostname, CM_PORT, self.key_file, \
1095 self.cert_file, self.options.debug)
1096 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1097 self.logger.info("Success")
1098 except socket.gaierror:
1099 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1100 except Exception, e:
1101 self.logger.log_exc(e.message)
1104 # delete named slice
1105 def delete(self, opts, args):
1107 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1108 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1109 creds = [slice_cred]
1111 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1112 creds.append(delegated_cred)
1113 server = self.server_proxy_from_opts(opts)
1114 call_args = [slice_urn, creds]
1115 if self.server_supports_options_arg(server):
1116 options = {'call_id': unique_call_id()}
1117 call_args.append(options)
1118 return server.DeleteSliver(*call_args)
1121 def start(self, opts, args):
1123 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1124 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1125 creds = [slice_cred]
1127 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1128 creds.append(delegated_cred)
1129 server = self.server_proxy_from_opts(opts)
1130 return server.Start(slice_urn, creds)
1133 def stop(self, opts, args):
1135 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1136 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1137 creds = [slice_cred]
1139 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1140 creds.append(delegated_cred)
1141 server = self.server_proxy_from_opts(opts)
1142 return server.Stop(slice_urn, creds)
1145 def reset(self, opts, args):
1147 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1148 server = self.server_proxy_from_opts(opts)
1149 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1150 creds = [slice_cred]
1152 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1153 creds.append(delegated_cred)
1154 return server.reset_slice(creds, slice_urn)
1156 def renew(self, opts, args):
1158 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1159 server = self.server_proxy_from_opts(opts)
1160 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1161 creds = [slice_cred]
1163 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1164 creds.append(delegated_cred)
1167 call_args = [slice_urn, creds, time]
1168 if self.server_supports_options_arg(server):
1169 options = {'call_id': unique_call_id()}
1170 call_args.append(options)
1171 result = server.RenewSliver(*call_args)
1172 value = ReturnValue.get_value(result)
1176 def status(self, opts, args):
1178 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1179 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1180 creds = [slice_cred]
1182 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1183 creds.append(delegated_cred)
1184 server = self.server_proxy_from_opts(opts)
1185 call_args = [slice_urn, creds]
1186 if self.server_supports_options_arg(server):
1187 options = {'call_id': unique_call_id()}
1188 call_args.append(options)
1189 result = server.SliverStatus(*call_args)
1190 value = ReturnValue.get_value(result)
1193 save_variable_to_file(value, opts.file, opts.fileformat)
1196 def shutdown(self, opts, args):
1198 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1199 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1200 creds = [slice_cred]
1202 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1203 creds.append(delegated_cred)
1204 server = self.server_proxy_from_opts(opts)
1205 return server.Shutdown(slice_urn, creds)
1207 def print_help (self):
1208 self.sfi_parser.print_help()
1209 self.cmd_parser.print_help()
1212 # Main: parse arguments and dispatch to command
1215 self.sfi_parser = self.create_parser()
1216 (options, args) = self.sfi_parser.parse_args()
1217 self.options = options
1219 self.logger.setLevelFromOptVerbose(self.options.verbose)
1220 if options.hashrequest:
1221 self.hashrequest = True
1224 self.logger.critical("No command given. Use -h for help.")
1228 self.cmd_parser = self.create_cmd_parser(command)
1229 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1232 self.logger.info("Command=%s" % command)
1233 if command in ("resources"):
1234 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1235 elif command in ("list", "show", "remove"):
1236 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1237 self.logger.debug('cmd_args %s' % cmd_args)
1240 self.dispatch(command, cmd_opts, cmd_args)
1242 self.logger.critical ("Unknown command %s"%command)
1248 if __name__ == "__main__":