3 # sfi -- slice-based facility interface
15 from lxml import etree
16 from StringIO import StringIO
17 from types import StringTypes, ListType
18 from optparse import OptionParser
19 from sfa.client.client_helper import pg_users_arg, sfa_users_arg, sfa_to_pg_users_arg
20 from sfa.util.sfalogging import sfi_logger
21 from sfa.trust.certificate import Keypair, Certificate
22 from sfa.trust.gid import GID
23 from sfa.trust.credential import Credential
24 from sfa.util.sfaticket import SfaTicket
25 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
26 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
27 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
28 from sfa.util.config import Config
29 from sfa.util.version import version_core
30 from sfa.util.cache import Cache
31 from sfa.rspecs.version_manager import VersionManager
36 # utility methods here
38 def display_rspec(rspec, format='rspec'):
40 tree = etree.parse(StringIO(rspec))
42 result = root.xpath("./network/site/node/hostname/text()")
43 elif format in ['ip']:
44 # The IP address is not yet part of the new RSpec
45 # so this doesn't do anything yet.
46 tree = etree.parse(StringIO(rspec))
48 result = root.xpath("./network/site/node/ipv4/text()")
55 def display_list(results):
56 for result in results:
59 def display_records(recordList, dump=False):
60 ''' Print all fields in the record'''
61 for record in recordList:
62 display_record(record, dump)
64 def display_record(record, dump=False):
68 info = record.getdict()
69 print "%s (%s)" % (info['hrn'], info['type'])
73 def filter_records(type, records):
75 for record in records:
76 if (record['type'] == type) or (type == "all"):
77 filtered_records.append(record)
78 return filtered_records
82 def save_rspec_to_file(rspec, filename):
83 if not filename.endswith(".rspec"):
84 filename = filename + ".rspec"
85 f = open(filename, 'w')
90 def save_records_to_file(filename, recordList, format="xml"):
93 for record in recordList:
95 save_record_to_file(filename + "." + str(index), record)
97 save_record_to_file(filename, record)
99 elif format == "xmllist":
100 f = open(filename, "w")
101 f.write("<recordlist>\n")
102 for record in recordList:
103 record = SfaRecord(dict=record)
104 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
105 f.write("</recordlist>\n");
107 elif format == "hrnlist":
108 f = open(filename, "w")
109 for record in recordList:
110 record = SfaRecord(dict=record)
111 f.write(record.get_name() + "\n")
114 # this should never happen
115 print "unknown output format", format
117 def save_record_to_file(filename, record):
118 if record['type'] in ['user']:
119 record = UserRecord(dict=record)
120 elif record['type'] in ['slice']:
121 record = SliceRecord(dict=record)
122 elif record['type'] in ['node']:
123 record = NodeRecord(dict=record)
124 elif record['type'] in ['authority', 'ma', 'sa']:
125 record = AuthorityRecord(dict=record)
127 record = SfaRecord(dict=record)
128 str = record.save_to_string()
129 f=codecs.open(filename, encoding='utf-8',mode="w")
136 def load_record_from_file(filename):
137 f=codecs.open(filename, encoding="utf-8", mode="r")
140 record = SfaRecord(string=str)
145 def unique_call_id(): return uuid.uuid4().urn
149 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
151 # dummy to meet Sfi's expectations for its 'options' field
152 # i.e. s/t we can do setattr on
156 def __init__ (self,options=None):
157 if options is None: options=Sfi.DummyOptions()
158 for opt in Sfi.required_options:
159 if not hasattr(options,opt): setattr(options,opt,None)
160 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
161 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
162 # would be safer to remove self.sfi_dir altogether
163 self.sfi_dir = options.sfi_dir
164 self.options = options
168 self.authority = None
169 self.hashrequest = False
170 self.logger = sfi_logger
171 self.logger.enable_console()
173 def create_cmd_parser(self, command, additional_cmdargs=None):
174 cmdargs = {"list": "authority",
179 "aggregates": "[name]",
180 "registries": "[name]",
181 "create_gid": "[name]",
183 "get_trusted_certs": "cred",
185 "resources": "[name]",
186 "create": "name rspec",
187 "get_ticket": "name rspec",
188 "redeem_ticket": "ticket",
200 if additional_cmdargs:
201 cmdargs.update(additional_cmdargs)
203 if command not in cmdargs:
204 msg="Invalid command\n"
206 msg += ','.join(cmdargs.keys())
207 self.logger.critical(msg)
210 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
211 % (command, cmdargs[command]))
213 # user specifies remote aggregate/sm/component
214 if command in ("resources", "slices", "create", "delete", "start", "stop",
215 "restart", "shutdown", "get_ticket", "renew", "status"):
216 parser.add_option("-a", "--aggregate", dest="aggregate",
217 default=None, help="aggregate host")
218 parser.add_option("-p", "--port", dest="port",
219 default=AGGREGATE_PORT, help="aggregate port")
220 parser.add_option("-c", "--component", dest="component", default=None,
221 help="component hrn")
222 parser.add_option("-d", "--delegate", dest="delegate", default=None,
224 help="Include a credential delegated to the user's root"+\
225 "authority in set of credentials for this call")
227 # registy filter option
228 if command in ("list", "show", "remove"):
229 parser.add_option("-t", "--type", dest="type", type="choice",
230 help="type filter ([all]|user|slice|authority|node|aggregate)",
231 choices=("all", "user", "slice", "authority", "node", "aggregate"),
234 if command in ("resources"):
235 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
236 help="schema type and version of resulting RSpec")
237 parser.add_option("-f", "--format", dest="format", type="choice",
238 help="display format ([xml]|dns|ip)", default="xml",
239 choices=("xml", "dns", "ip"))
240 #panos: a new option to define the type of information about resources a user is interested in
241 parser.add_option("-i", "--info", dest="info",
242 help="optional component information", default=None)
245 # 'create' does return the new rspec, makes sense to save that too
246 if command in ("resources", "show", "list", "create_gid", 'create'):
247 parser.add_option("-o", "--output", dest="file",
248 help="output XML to file", metavar="FILE", default=None)
250 if command in ("show", "list"):
251 parser.add_option("-f", "--format", dest="format", type="choice",
252 help="display format ([text]|xml)", default="text",
253 choices=("text", "xml"))
255 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
256 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
257 choices=("xml", "xmllist", "hrnlist"))
259 if command in ("delegate"):
260 parser.add_option("-u", "--user",
261 action="store_true", dest="delegate_user", default=False,
262 help="delegate user credential")
263 parser.add_option("-s", "--slice", dest="delegate_slice",
264 help="delegate slice credential", metavar="HRN", default=None)
266 if command in ("version"):
267 parser.add_option("-a", "--aggregate", dest="aggregate",
268 default=None, help="aggregate host")
269 parser.add_option("-p", "--port", dest="port",
270 default=AGGREGATE_PORT, help="aggregate port")
271 parser.add_option("-R","--registry-version",
272 action="store_true", dest="version_registry", default=False,
273 help="probe registry version instead of slicemgr")
274 parser.add_option("-l","--local",
275 action="store_true", dest="version_local", default=False,
276 help="display version of the local client")
281 def create_parser(self):
283 # Generate command line parser
284 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
285 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
286 parser.add_option("-r", "--registry", dest="registry",
287 help="root registry", metavar="URL", default=None)
288 parser.add_option("-s", "--slicemgr", dest="sm",
289 help="slice manager", metavar="URL", default=None)
290 default_sfi_dir = os.path.expanduser("~/.sfi/")
291 parser.add_option("-d", "--dir", dest="sfi_dir",
292 help="config & working directory - default is " + default_sfi_dir,
293 metavar="PATH", default=default_sfi_dir)
294 parser.add_option("-u", "--user", dest="user",
295 help="user name", metavar="HRN", default=None)
296 parser.add_option("-a", "--auth", dest="auth",
297 help="authority name", metavar="HRN", default=None)
298 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
299 help="verbose mode - cumulative")
300 parser.add_option("-D", "--debug",
301 action="store_true", dest="debug", default=False,
302 help="Debug (xml-rpc) protocol messages")
303 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
304 help="RPC protocol (xmlrpc or soap)")
305 parser.add_option("-k", "--hashrequest",
306 action="store_true", dest="hashrequest", default=False,
307 help="Create a hash of the request that will be authenticated on the server")
308 parser.add_option("-t", "--timeout", dest="timeout", default=None,
309 help="Amout of time tom wait before timing out the request")
310 parser.disable_interspersed_args()
315 def read_config(self):
316 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
318 config = Config (config_file)
320 self.logger.critical("Failed to read configuration file %s"%config_file)
321 self.logger.info("Make sure to remove the export clauses and to add quotes")
322 if self.options.verbose==0:
323 self.logger.info("Re-run with -v for more details")
325 self.logger.log_exc("Could not read config file %s"%config_file)
330 if (self.options.sm is not None):
331 self.sm_url = self.options.sm
332 elif hasattr(config, "SFI_SM"):
333 self.sm_url = config.SFI_SM
335 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
339 if (self.options.registry is not None):
340 self.reg_url = self.options.registry
341 elif hasattr(config, "SFI_REGISTRY"):
342 self.reg_url = config.SFI_REGISTRY
344 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
349 if (self.options.user is not None):
350 self.user = self.options.user
351 elif hasattr(config, "SFI_USER"):
352 self.user = config.SFI_USER
354 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
358 if (self.options.auth is not None):
359 self.authority = self.options.auth
360 elif hasattr(config, "SFI_AUTH"):
361 self.authority = config.SFI_AUTH
363 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
371 # Establish Connection to SliceMgr and Registry Servers
373 def set_servers(self):
376 # Get key and certificate
377 key_file = self.get_key_file()
378 cert_file = self.get_cert_file(key_file)
379 self.key = Keypair(filename=key_file)
380 self.key_file = key_file
381 self.cert_file = cert_file
382 self.cert = GID(filename=cert_file)
383 self.logger.info("Contacting Registry at: %s"%self.reg_url)
384 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
385 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
386 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
389 def get_cached_server_version(self, server):
390 # check local cache first
393 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
394 cache_key = server.url + "-version"
396 cache = Cache(cache_file)
399 self.logger.info("Local cache not found at: %s" % cache_file)
402 version = cache.get(cache_key)
405 version = server.GetVersion()
406 # cache version for 24 hours
407 cache.add(cache_key, version, ttl= 60*60*24)
408 self.logger.info("Updating cache file %s" % cache_file)
409 cache.save_to_file(cache_file)
415 def server_supports_call_id_arg(self, server):
417 Returns true if server support the optional call_id arg, false otherwise.
419 server_version = self.get_cached_server_version(server)
420 if 'sfa' in server_version and 'code_tag' in server_version:
421 code_tag = server_version['code_tag']
422 code_tag_parts = code_tag.split("-")
424 version_parts = code_tag_parts[0].split(".")
425 major, minor = version_parts[0], version_parts[1]
426 rev = code_tag_parts[1]
428 if int(minor) > 0 or int(rev) > 20:
433 # Get various credential and spec files
435 # Establishes limiting conventions
436 # - conflates MAs and SAs
437 # - assumes last token in slice name is unique
439 # Bootstraps credentials
440 # - bootstrap user credential from self-signed certificate
441 # - bootstrap authority credential from user credential
442 # - bootstrap slice credential from user credential
446 def get_key_file(self):
447 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
448 if (os.path.isfile(file)):
451 self.logger.error("Key file %s does not exist"%file)
455 def get_cert_file(self, key_file):
457 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
458 if (os.path.isfile(cert_file)):
459 # we'd perfer to use Registry issued certs instead of self signed certs.
460 # if this is a Registry cert (GID) then we are done
461 gid = GID(filename=cert_file)
465 # generate self signed certificate
466 k = Keypair(filename=key_file)
467 cert = Certificate(subject=self.user)
469 cert.set_issuer(k, self.user)
471 self.logger.info("Writing self-signed certificate to %s"%cert_file)
472 cert.save_to_file(cert_file)
474 # try to get registry issued cert
476 self.logger.info("Getting Registry issued cert")
478 # *hack. need to set registyr before _get_gid() is called
479 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
480 gid = self._get_gid(type='user')
482 self.logger.info("Writing certificate to %s"%cert_file)
483 gid.save_to_file(cert_file)
485 self.logger.info("Failed to download Registry issued cert")
489 def get_cached_gid(self, file):
494 if (os.path.isfile(file)):
495 gid = GID(filename=file)
499 def get_gid(self, opts, args):
501 Get the specify gid and save it to file
506 gid = self._get_gid(hrn)
507 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
510 def _get_gid(self, hrn=None, type=None):
512 git_gid helper. Retrive the gid from the registry and save it to file.
518 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
520 gid = self.get_cached_gid(gidfile)
522 user_cred = self.get_user_cred()
523 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
525 raise RecordNotFound(args[0])
530 if type == rec['type']:
533 raise RecordNotFound(args[0])
535 gid = GID(string=record['gid'])
536 self.logger.info("Writing gid to %s"%gidfile)
537 gid.save_to_file(filename=gidfile)
541 def get_cached_credential(self, file):
543 Return a cached credential only if it hasn't expired.
545 if (os.path.isfile(file)):
546 credential = Credential(filename=file)
547 # make sure it isnt expired
548 if not credential.get_expiration or \
549 datetime.datetime.today() < credential.get_expiration():
553 def get_user_cred(self):
554 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
555 return self.get_cred(file, 'user', self.user)
557 def get_auth_cred(self):
558 if not self.authority:
559 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
561 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
562 return self.get_cred(file, 'authority', self.authority)
564 def get_slice_cred(self, name):
565 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
566 return self.get_cred(file, 'slice', name)
568 def get_cred(self, file, type, hrn):
569 # attempt to load a cached credential
570 cred = self.get_cached_credential(file)
573 cert_string = self.cert.save_to_string(save_parents=True)
574 user_name = self.user.replace(self.authority + ".", '')
575 if user_name.count(".") > 0:
576 user_name = user_name.replace(".", '_')
577 self.user = self.authority + "." + user_name
578 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
580 # bootstrap slice credential from user credential
581 user_cred = self.get_user_cred().save_to_string(save_parents=True)
582 cred_str = self.registry.GetCredential(user_cred, hrn, type)
585 self.logger.critical("Failed to get %s credential" % type)
588 cred = Credential(string=cred_str)
589 cred.save_to_file(file, save_parents=True)
590 self.logger.info("Writing %s credential to %s" %(type, file))
595 def get_rspec_file(self, rspec):
596 if (os.path.isabs(rspec)):
599 file = os.path.join(self.options.sfi_dir, rspec)
600 if (os.path.isfile(file)):
603 self.logger.critical("No such rspec file %s"%rspec)
606 def get_record_file(self, record):
607 if (os.path.isabs(record)):
610 file = os.path.join(self.options.sfi_dir, record)
611 if (os.path.isfile(file)):
614 self.logger.critical("No such registry record file %s"%record)
617 def load_publickey_string(self, fn):
619 key_string = f.read()
621 # if the filename is a private key file, then extract the public key
622 if "PRIVATE KEY" in key_string:
623 outfn = tempfile.mktemp()
624 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
627 key_string = f.read()
633 def get_component_server_from_hrn(self, hrn):
634 # direct connection to the nodes component manager interface
635 user_cred = self.get_user_cred().save_to_string(save_parents=True)
636 records = self.registry.Resolve(hrn, user_cred)
637 records = filter_records('node', records)
639 self.logger.warning("No such component:%r"% opts.component)
642 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
644 def get_server(self, host, port, keyfile, certfile):
646 Return an instance of an xmlrpc server connection
648 # port is appended onto the domain, before the path. Should look like:
649 # http://domain:port/path
650 host_parts = host.split('/')
651 host_parts[0] = host_parts[0] + ":" + str(port)
652 url = "http://%s" % "/".join(host_parts)
653 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
655 # xxx opts could be retrieved in self.options
656 def get_server_from_opts(self, opts):
658 Return instance of an xmlrpc connection to a slice manager, aggregate
659 or component server depending on the specified opts
661 server = self.slicemgr
662 # direct connection to an aggregate
663 if hasattr(opts, 'aggregate') and opts.aggregate:
664 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
665 # direct connection to the nodes component manager interface
666 if hasattr(opts, 'component') and opts.component:
667 server = self.get_component_server_from_hrn(opts.component)
670 #==========================================================================
671 # Following functions implement the commands
673 # Registry-related commands
674 #==========================================================================
676 def dispatch(self, command, cmd_opts, cmd_args):
677 return getattr(self, command)(cmd_opts, cmd_args)
679 def create_gid(self, opts, args):
684 user_cred = self.get_user_cred().save_to_string(save_parents=True)
685 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
689 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
690 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
691 GID(string=gid).save_to_file(filename)
694 # list entires in named authority registry
695 def list(self, opts, args):
700 user_cred = self.get_user_cred().save_to_string(save_parents=True)
702 list = self.registry.List(hrn, user_cred)
704 raise Exception, "Not enough parameters for the 'list' command"
706 # filter on person, slice, site, node, etc.
707 # THis really should be in the self.filter_records funct def comment...
708 list = filter_records(opts.type, list)
710 print "%s (%s)" % (record['hrn'], record['type'])
712 save_records_to_file(opts.file, list, opts.fileformat)
715 # show named registry record
716 def show(self, opts, args):
721 user_cred = self.get_user_cred().save_to_string(save_parents=True)
722 records = self.registry.Resolve(hrn, user_cred)
723 records = filter_records(opts.type, records)
725 print "No record of type", opts.type
726 for record in records:
727 if record['type'] in ['user']:
728 record = UserRecord(dict=record)
729 elif record['type'] in ['slice']:
730 record = SliceRecord(dict=record)
731 elif record['type'] in ['node']:
732 record = NodeRecord(dict=record)
733 elif record['type'].startswith('authority'):
734 record = AuthorityRecord(dict=record)
736 record = SfaRecord(dict=record)
737 if (opts.format == "text"):
740 print record.save_to_string()
742 save_records_to_file(opts.file, records, opts.fileformat)
745 def delegate(self, opts, args):
747 delegee_hrn = args[0]
748 if opts.delegate_user:
749 user_cred = self.get_user_cred()
750 cred = self.delegate_cred(user_cred, delegee_hrn)
751 elif opts.delegate_slice:
752 slice_cred = self.get_slice_cred(opts.delegate_slice)
753 cred = self.delegate_cred(slice_cred, delegee_hrn)
755 self.logger.warning("Must specify either --user or --slice <hrn>")
757 delegated_cred = Credential(string=cred)
758 object_hrn = delegated_cred.get_gid_object().get_hrn()
759 if opts.delegate_user:
760 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
761 + get_leaf(object_hrn) + ".cred")
762 elif opts.delegate_slice:
763 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
764 + get_leaf(object_hrn) + ".cred")
766 delegated_cred.save_to_file(dest_fn, save_parents=True)
768 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
770 def delegate_cred(self, object_cred, hrn):
771 # the gid and hrn of the object we are delegating
772 if isinstance(object_cred, str):
773 object_cred = Credential(string=object_cred)
774 object_gid = object_cred.get_gid_object()
775 object_hrn = object_gid.get_hrn()
777 if not object_cred.get_privileges().get_all_delegate():
778 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
781 # the delegating user's gid
782 caller_gid = self._get_gid(self.user)
783 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
785 # the gid of the user who will be delegated to
786 delegee_gid = self._get_gid(hrn)
787 delegee_hrn = delegee_gid.get_hrn()
788 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
789 delegee_gid.save_to_file(filename=delegee_gidfile)
790 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
791 return dcred.save_to_string(save_parents=True)
793 # removed named registry record
794 # - have to first retrieve the record to be removed
795 def remove(self, opts, args):
796 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
804 return self.registry.Remove(hrn, auth_cred, type)
806 # add named registry record
807 def add(self, opts, args):
808 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
812 record_filepath = args[0]
813 rec_file = self.get_record_file(record_filepath)
814 record = load_record_from_file(rec_file).as_dict()
815 return self.registry.Register(record, auth_cred)
817 # update named registry entry
818 def update(self, opts, args):
819 user_cred = self.get_user_cred()
823 rec_file = self.get_record_file(args[0])
824 record = load_record_from_file(rec_file)
825 if record['type'] == "user":
826 if record.get_name() == user_cred.get_gid_object().get_hrn():
827 cred = user_cred.save_to_string(save_parents=True)
829 cred = self.get_auth_cred().save_to_string(save_parents=True)
830 elif record['type'] in ["slice"]:
832 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
833 except xmlrpcprotocol.ServerException, e:
834 # XXX smbaker -- once we have better error return codes, update this
835 # to do something better than a string compare
836 if "Permission error" in e.args[0]:
837 cred = self.get_auth_cred().save_to_string(save_parents=True)
840 elif record.get_type() in ["authority"]:
841 cred = self.get_auth_cred().save_to_string(save_parents=True)
842 elif record.get_type() == 'node':
843 cred = self.get_auth_cred().save_to_string(save_parents=True)
845 raise "unknown record type" + record.get_type()
846 record = record.as_dict()
847 return self.registry.Update(record, cred)
849 def get_trusted_certs(self, opts, args):
851 return uhe trusted certs at this interface
853 trusted_certs = self.registry.get_trusted_certs()
854 for trusted_cert in trusted_certs:
855 gid = GID(string=trusted_cert)
857 cert = Certificate(string=trusted_cert)
858 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
861 def aggregates(self, opts, args):
863 return a list of details about known aggregates
865 user_cred = self.get_user_cred().save_to_string(save_parents=True)
870 result = self.registry.get_aggregates(user_cred, hrn)
874 def registries(self, opts, args):
876 return a list of details about known registries
878 user_cred = self.get_user_cred().save_to_string(save_parents=True)
882 result = self.registry.get_registries(user_cred, hrn)
887 # ==================================================================
888 # Slice-related commands
889 # ==================================================================
891 def version(self, opts, args):
892 if opts.version_local:
893 version=version_core()
895 if opts.version_registry:
898 server = self.get_server_from_opts(opts)
899 version=server.GetVersion()
900 for (k,v) in version.iteritems():
901 print "%-20s: %s"%(k,v)
903 # list instantiated slices
904 def slices(self, opts, args):
906 list instantiated slices
908 user_cred = self.get_user_cred().save_to_string(save_parents=True)
911 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
912 creds.append(delegated_cred)
913 server = self.get_server_from_opts(opts)
914 #results = server.ListSlices(creds, unique_call_id())
915 results = server.ListSlices(creds)
916 display_list(results)
919 # show rspec for named slice
920 def resources(self, opts, args):
921 user_cred = self.get_user_cred().save_to_string(save_parents=True)
922 server = self.slicemgr
924 server = self.get_server_from_opts(opts)
927 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
929 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
936 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
937 creds.append(delegated_cred)
938 if opts.rspec_version:
939 version_manager = VersionManager()
940 server_version = self.get_cached_server_version(server)
941 if 'sfa' in server_version:
942 # just request the version the client wants
943 call_options['rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
945 # this must be a protogeni aggregate. We should request a v2 ad rspec
946 # regardless of what the client user requested
947 call_options['rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
948 #panos add info options
950 call_options['info'] = opts.info
952 call_args = [creds, call_options]
953 if self.server_supports_call_id_arg(server):
954 call_args.append(unique_call_id())
955 result = server.ListResources(*call_args)
956 if opts.file is None:
957 display_rspec(result, opts.format)
959 save_rspec_to_file(result, opts.file)
962 # created named slice with given rspec
963 def create(self, opts, args):
964 server = self.get_server_from_opts(opts)
965 server_version = self.get_cached_server_version(server)
967 slice_urn = hrn_to_urn(slice_hrn, 'slice')
968 user_cred = self.get_user_cred()
969 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
972 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
973 creds.append(delegated_cred)
974 rspec_file = self.get_rspec_file(args[1])
975 rspec = open(rspec_file).read()
977 # need to pass along user keys to the aggregate.
979 # { urn: urn:publicid:IDN+emulab.net+user+alice
980 # keys: [<ssh key A>, <ssh key B>]
983 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
984 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
985 slice_record = slice_records[0]
986 user_hrns = slice_record['researcher']
987 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
988 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
990 if 'sfa' not in server_version:
991 users = pg_users_arg(user_records)
993 users = sfa_users_arg(user_records, slice_record)
994 call_args = [slice_urn, creds, rspec, users]
995 if self.server_supports_call_id_arg(server):
996 call_args.append(unique_call_id())
998 result = server.CreateSliver(*call_args)
999 if opts.file is None:
1002 save_rspec_to_file (result, opts.file)
1005 # get a ticket for the specified slice
1006 def get_ticket(self, opts, args):
1007 slice_hrn, rspec_path = args[0], args[1]
1008 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1009 user_cred = self.get_user_cred()
1010 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1011 creds = [slice_cred]
1013 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1014 creds.append(delegated_cred)
1015 rspec_file = self.get_rspec_file(rspec_path)
1016 rspec = open(rspec_file).read()
1017 server = self.get_server_from_opts(opts)
1018 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1019 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1020 self.logger.info("writing ticket to %s"%file)
1021 ticket = SfaTicket(string=ticket_string)
1022 ticket.save_to_file(filename=file, save_parents=True)
1024 def redeem_ticket(self, opts, args):
1025 ticket_file = args[0]
1027 # get slice hrn from the ticket
1028 # use this to get the right slice credential
1029 ticket = SfaTicket(filename=ticket_file)
1031 slice_hrn = ticket.gidObject.get_hrn()
1032 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1033 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1034 user_cred = self.get_user_cred()
1035 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1037 # get a list of node hostnames from the RSpec
1038 tree = etree.parse(StringIO(ticket.rspec))
1039 root = tree.getroot()
1040 hostnames = root.xpath("./network/site/node/hostname/text()")
1042 # create an xmlrpc connection to the component manager at each of these
1043 # components and gall redeem_ticket
1045 for hostname in hostnames:
1047 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1048 server = self.get_server(hostname, CM_PORT, self.key_file, \
1049 self.cert_file, self.options.debug)
1050 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1051 self.logger.info("Success")
1052 except socket.gaierror:
1053 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1054 except Exception, e:
1055 self.logger.log_exc(e.message)
1058 # delete named slice
1059 def delete(self, opts, args):
1061 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1062 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1063 creds = [slice_cred]
1065 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1066 creds.append(delegated_cred)
1067 server = self.get_server_from_opts(opts)
1069 call_args = [slice_urn, creds]
1070 if self.server_supports_call_id_arg(server):
1071 call_args.append(unique_call_id())
1072 return server.DeleteSliver(*call_args)
1075 def start(self, opts, args):
1077 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1078 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1079 creds = [slice_cred]
1081 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1082 creds.append(delegated_cred)
1083 server = self.get_server_from_opts(opts)
1084 return server.Start(slice_urn, creds)
1087 def stop(self, opts, args):
1089 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1090 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1091 creds = [slice_cred]
1093 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1094 creds.append(delegated_cred)
1095 server = self.get_server_from_opts(opts)
1096 return server.Stop(slice_urn, creds)
1099 def reset(self, opts, args):
1101 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1102 server = self.get_server_from_opts(opts)
1103 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1104 creds = [slice_cred]
1106 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1107 creds.append(delegated_cred)
1108 return server.reset_slice(creds, slice_urn)
1110 def renew(self, opts, args):
1112 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1113 server = self.get_server_from_opts(opts)
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)
1121 call_args = [slice_urn, creds, time]
1122 if self.server_supports_call_id_arg(server):
1123 call_args.append(unique_call_id())
1124 return server.RenewSliver(*call_args)
1127 def status(self, opts, args):
1129 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1130 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1131 creds = [slice_cred]
1133 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1134 creds.append(delegated_cred)
1135 server = self.get_server_from_opts(opts)
1136 call_args = [slice_urn, creds]
1137 if self.server_supports_call_id_arg(server):
1138 call_args.append(unique_call_id())
1139 print server.SliverStatus(*call_args)
1142 def shutdown(self, opts, args):
1144 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1145 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1146 creds = [slice_cred]
1148 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1149 creds.append(delegated_cred)
1150 server = self.get_server_from_opts(opts)
1151 return server.Shutdown(slice_urn, creds)
1153 def print_help (self):
1154 self.sfi_parser.print_help()
1155 self.cmd_parser.print_help()
1158 # Main: parse arguments and dispatch to command
1161 self.sfi_parser = self.create_parser()
1162 (options, args) = self.sfi_parser.parse_args()
1163 self.options = options
1165 self.logger.setLevelFromOptVerbose(self.options.verbose)
1166 if options.hashrequest:
1167 self.hashrequest = True
1170 self.logger.critical("No command given. Use -h for help.")
1174 self.cmd_parser = self.create_cmd_parser(command)
1175 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1178 self.logger.info("Command=%s" % command)
1179 if command in ("resources"):
1180 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1181 elif command in ("list", "show", "remove"):
1182 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1183 self.logger.debug('cmd_args %s' % cmd_args)
1186 self.dispatch(command, cmd_opts, cmd_args)
1188 self.logger.critical ("Unknown command %s"%command)
1194 if __name__ == "__main__":