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']
171 def default_sfi_dir ():
172 if os.path.isfile("./sfi_config"):
175 return os.path.expanduser("~/.sfi/")
177 # dummy to meet Sfi's expectations for its 'options' field
178 # i.e. s/t we can do setattr on
182 def __init__ (self,options=None):
183 if options is None: options=Sfi.DummyOptions()
184 for opt in Sfi.required_options:
185 if not hasattr(options,opt): setattr(options,opt,None)
186 if not hasattr(options,'sfi_dir'): options.sfi_dir=Sfi.default_sfi_dir()
187 self.options = options
191 self.authority = None
192 self.hashrequest = False
193 self.logger = sfi_logger
194 self.logger.enable_console()
196 def create_cmd_parser(self, command):
197 cmdargs = {"list": "authority",
202 "create_gid": "[name]",
204 "get_trusted_certs": "cred",
206 "resources": "[name]",
207 "create": "name rspec",
208 "get_ticket": "name rspec",
209 "redeem_ticket": "ticket",
221 if command not in cmdargs:
222 msg="Invalid command\n"
224 msg += ','.join(cmdargs.keys())
225 self.logger.critical(msg)
228 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
229 % (command, cmdargs[command]))
231 # user specifies remote aggregate/sm/component
232 if command in ("resources", "slices", "create", "delete", "start", "stop",
233 "restart", "shutdown", "get_ticket", "renew", "status"):
234 parser.add_option("-a", "--aggregate", dest="aggregate",
235 default=None, help="aggregate host")
236 parser.add_option("-p", "--port", dest="port",
237 default=AGGREGATE_PORT, help="aggregate port")
238 parser.add_option("-c", "--component", dest="component", default=None,
239 help="component hrn")
240 parser.add_option("-d", "--delegate", dest="delegate", default=None,
242 help="Include a credential delegated to the user's root"+\
243 "authority in set of credentials for this call")
245 # registy filter option
246 if command in ("list", "show", "remove"):
247 parser.add_option("-t", "--type", dest="type", type="choice",
248 help="type filter ([all]|user|slice|authority|node|aggregate)",
249 choices=("all", "user", "slice", "authority", "node", "aggregate"),
252 if command in ("resources"):
253 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
254 help="schema type and version of resulting RSpec")
255 parser.add_option("-f", "--format", dest="format", type="choice",
256 help="display format ([xml]|dns|ip)", default="xml",
257 choices=("xml", "dns", "ip"))
258 #panos: a new option to define the type of information about resources a user is interested in
259 parser.add_option("-i", "--info", dest="info",
260 help="optional component information", default=None)
263 # 'create' does return the new rspec, makes sense to save that too
264 if command in ("resources", "show", "list", "create_gid", 'create'):
265 parser.add_option("-o", "--output", dest="file",
266 help="output XML to file", metavar="FILE", default=None)
268 if command in ("show", "list"):
269 parser.add_option("-f", "--format", dest="format", type="choice",
270 help="display format ([text]|xml)", default="text",
271 choices=("text", "xml"))
273 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
274 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
275 choices=("xml", "xmllist", "hrnlist"))
277 if command in ("status", "version"):
278 parser.add_option("-o", "--output", dest="file",
279 help="output dictionary to file", metavar="FILE", default=None)
280 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
281 help="output file format ([text]|pickled)", default="text",
282 choices=("text","pickled"))
284 if command in ("delegate"):
285 parser.add_option("-u", "--user",
286 action="store_true", dest="delegate_user", default=False,
287 help="delegate user credential")
288 parser.add_option("-s", "--slice", dest="delegate_slice",
289 help="delegate slice credential", metavar="HRN", default=None)
291 if command in ("version"):
292 parser.add_option("-a", "--aggregate", dest="aggregate",
293 default=None, help="aggregate host")
294 parser.add_option("-p", "--port", dest="port",
295 default=AGGREGATE_PORT, help="aggregate port")
296 parser.add_option("-R","--registry-version",
297 action="store_true", dest="version_registry", default=False,
298 help="probe registry version instead of slicemgr")
299 parser.add_option("-l","--local",
300 action="store_true", dest="version_local", default=False,
301 help="display version of the local client")
306 def create_parser(self):
308 # Generate command line parser
309 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
310 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
311 parser.add_option("-r", "--registry", dest="registry",
312 help="root registry", metavar="URL", default=None)
313 parser.add_option("-s", "--slicemgr", dest="sm",
314 help="slice manager", metavar="URL", default=None)
315 parser.add_option("-d", "--dir", dest="sfi_dir",
316 help="config & working directory - default is " + Sfi.default_sfi_dir(),
317 metavar="PATH", default=Sfi.default_sfi_dir())
318 parser.add_option("-u", "--user", dest="user",
319 help="user name", metavar="HRN", default=None)
320 parser.add_option("-a", "--auth", dest="auth",
321 help="authority name", metavar="HRN", default=None)
322 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
323 help="verbose mode - cumulative")
324 parser.add_option("-D", "--debug",
325 action="store_true", dest="debug", default=False,
326 help="Debug (xml-rpc) protocol messages")
327 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
328 help="RPC protocol (xmlrpc or soap)")
329 parser.add_option("-k", "--hashrequest",
330 action="store_true", dest="hashrequest", default=False,
331 help="Create a hash of the request that will be authenticated on the server")
332 parser.add_option("-t", "--timeout", dest="timeout", default=None,
333 help="Amout of time tom wait before timing out the request")
334 parser.disable_interspersed_args()
339 def read_config(self):
340 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
342 config = Config (config_file)
344 self.logger.critical("Failed to read configuration file %s"%config_file)
345 self.logger.info("Make sure to remove the export clauses and to add quotes")
346 if self.options.verbose==0:
347 self.logger.info("Re-run with -v for more details")
349 self.logger.log_exc("Could not read config file %s"%config_file)
354 if (self.options.sm is not None):
355 self.sm_url = self.options.sm
356 elif hasattr(config, "SFI_SM"):
357 self.sm_url = config.SFI_SM
359 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
363 if (self.options.registry is not None):
364 self.reg_url = self.options.registry
365 elif hasattr(config, "SFI_REGISTRY"):
366 self.reg_url = config.SFI_REGISTRY
368 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
373 if (self.options.user is not None):
374 self.user = self.options.user
375 elif hasattr(config, "SFI_USER"):
376 self.user = config.SFI_USER
378 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
382 if (self.options.auth is not None):
383 self.authority = self.options.auth
384 elif hasattr(config, "SFI_AUTH"):
385 self.authority = config.SFI_AUTH
387 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
395 # Establish Connection to SliceMgr and Registry Servers
397 def set_servers(self):
400 # Get key and certificate
401 key_file = self.get_key_file()
402 cert_file = self.get_cert_file(key_file)
403 self.key_file = key_file
404 self.cert_file = cert_file
405 self.cert = GID(filename=cert_file)
406 self.logger.info("Contacting Registry at: %s"%self.reg_url)
407 self.registry = sfaprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
408 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
409 self.slicemgr = sfaprotocol.server_proxy(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
412 def get_cached_server_version(self, server):
413 # check local cache first
416 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
417 cache_key = server.url + "-version"
419 cache = Cache(cache_file)
422 self.logger.info("Local cache not found at: %s" % cache_file)
425 version = cache.get(cache_key)
428 result = server.GetVersion()
429 version= ReturnValue.get_value(result)
430 # cache version for 24 hours
431 cache.add(cache_key, version, ttl= 60*60*24)
432 self.logger.info("Updating cache file %s" % cache_file)
433 cache.save_to_file(cache_file)
438 def server_supports_options_arg(self, server):
440 Returns true if server support the optional call_id arg, false otherwise.
442 server_version = self.get_cached_server_version(server)
443 if 'sfa' in server_version and 'code_tag' in server_version:
444 code_tag = server_version['code_tag']
445 code_tag_parts = code_tag.split("-")
447 version_parts = code_tag_parts[0].split(".")
448 major, minor = version_parts[0], version_parts[1]
449 rev = code_tag_parts[1]
456 # Get various credential and spec files
458 # Establishes limiting conventions
459 # - conflates MAs and SAs
460 # - assumes last token in slice name is unique
462 # Bootstraps credentials
463 # - bootstrap user credential from self-signed certificate
464 # - bootstrap authority credential from user credential
465 # - bootstrap slice credential from user credential
469 def get_key_file(self):
470 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
471 if (os.path.isfile(file)):
474 self.logger.error("Key file %s does not exist"%file)
478 def get_cert_file(self, key_file):
480 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
481 if (os.path.isfile(cert_file)):
482 # we'd perfer to use Registry issued certs instead of self signed certs.
483 # if this is a Registry cert (GID) then we are done
484 gid = GID(filename=cert_file)
488 # generate self signed certificate
489 k = Keypair(filename=key_file)
490 cert = Certificate(subject=self.user)
492 cert.set_issuer(k, self.user)
494 self.logger.info("Writing self-signed certificate to %s"%cert_file)
495 cert.save_to_file(cert_file)
497 # try to get registry issued cert
499 self.logger.info("Getting Registry issued cert")
501 # *hack. need to set registry before _get_gid() is called
502 self.registry = sfaprotocol.server_proxy(self.reg_url, key_file, cert_file,
503 timeout=self.options.timeout, verbose=self.options.debug)
504 gid = self._get_gid(type='user')
506 self.logger.info("Writing certificate to %s"%cert_file)
507 gid.save_to_file(cert_file)
509 self.logger.info("Failed to download Registry issued cert")
513 def get_cached_gid(self, file):
518 if (os.path.isfile(file)):
519 gid = GID(filename=file)
523 def get_gid(self, opts, args):
525 Get the specify gid and save it to file
530 gid = self._get_gid(hrn)
531 self.logger.debug("Sfi.get_gid-> %s" % gid.save_to_string(save_parents=True))
534 def _get_gid(self, hrn=None, type=None):
536 git_gid helper. Retrive the gid from the registry and save it to file.
542 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
543 gid = self.get_cached_gid(gidfile)
545 user_cred = self.get_user_cred()
546 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
548 raise RecordNotFound(args[0])
553 if type == rec['type']:
556 raise RecordNotFound(args[0])
558 gid = GID(string=record['gid'])
559 self.logger.info("Writing gid to %s"%gidfile)
560 gid.save_to_file(filename=gidfile)
564 def get_cached_credential(self, file):
566 Return a cached credential only if it hasn't expired.
568 if (os.path.isfile(file)):
569 credential = Credential(filename=file)
570 # make sure it isnt expired
571 if not credential.get_expiration or \
572 datetime.datetime.today() < credential.get_expiration():
576 def get_user_cred(self):
577 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
578 return self.get_cred(file, 'user', self.user)
580 def get_auth_cred(self):
581 if not self.authority:
582 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
584 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
585 return self.get_cred(file, 'authority', self.authority)
587 def get_slice_cred(self, name):
588 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
589 return self.get_cred(file, 'slice', name)
591 def get_cred(self, file, type, hrn):
592 # attempt to load a cached credential
593 cred = self.get_cached_credential(file)
596 cert_string = self.cert.save_to_string(save_parents=True)
597 user_name = self.user.replace(self.authority + ".", '')
598 if user_name.count(".") > 0:
599 user_name = user_name.replace(".", '_')
600 self.user = self.authority + "." + user_name
601 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
603 # bootstrap slice credential from user credential
604 user_cred = self.get_user_cred().save_to_string(save_parents=True)
605 cred_str = self.registry.GetCredential(user_cred, hrn, type)
608 self.logger.critical("Failed to get %s credential" % type)
611 cred = Credential(string=cred_str)
612 cred.save_to_file(file, save_parents=True)
613 self.logger.info("Writing %s credential to %s" %(type, file))
618 def get_rspec_file(self, rspec):
619 if (os.path.isabs(rspec)):
622 file = os.path.join(self.options.sfi_dir, rspec)
623 if (os.path.isfile(file)):
626 self.logger.critical("No such rspec file %s"%rspec)
629 def get_record_file(self, record):
630 if (os.path.isabs(record)):
633 file = os.path.join(self.options.sfi_dir, record)
634 if (os.path.isfile(file)):
637 self.logger.critical("No such registry record file %s"%record)
641 def get_component_proxy_from_hrn(self, hrn):
642 # direct connection to the nodes component manager interface
643 user_cred = self.get_user_cred().save_to_string(save_parents=True)
644 records = self.registry.Resolve(hrn, user_cred)
645 records = filter_records('node', records)
647 self.logger.warning("No such component:%r"% opts.component)
650 return self.server_proxy(record['hostname'], CM_PORT, self.key_file, self.cert_file)
652 def server_proxy(self, host, port, keyfile, certfile):
654 Return an instance of an xmlrpc server connection
656 # port is appended onto the domain, before the path. Should look like:
657 # http://domain:port/path
658 host_parts = host.split('/')
659 host_parts[0] = host_parts[0] + ":" + str(port)
660 url = "http://%s" % "/".join(host_parts)
661 return sfaprotocol.server_proxy(url, keyfile, certfile, timeout=self.options.timeout,
662 verbose=self.options.debug)
664 # xxx opts could be retrieved in self.options
665 def server_proxy_from_opts(self, opts):
667 Return instance of an xmlrpc connection to a slice manager, aggregate
668 or component server depending on the specified opts
670 server = self.slicemgr
671 # direct connection to an aggregate
672 if hasattr(opts, 'aggregate') and opts.aggregate:
673 server = self.server_proxy(opts.aggregate, opts.port, self.key_file, self.cert_file)
674 # direct connection to the nodes component manager interface
675 if hasattr(opts, 'component') and opts.component:
676 server = self.get_component_proxy_from_hrn(opts.component)
679 #==========================================================================
680 # Following functions implement the commands
682 # Registry-related commands
683 #==========================================================================
685 def create_gid(self, opts, args):
690 user_cred = self.get_user_cred().save_to_string(save_parents=True)
691 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
695 filename = os.sep.join([self.options.sfi_dir, '%s.gid' % target_hrn])
696 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
697 GID(string=gid).save_to_file(filename)
700 # list entires in named authority registry
701 def list(self, opts, args):
706 user_cred = self.get_user_cred().save_to_string(save_parents=True)
708 list = self.registry.List(hrn, user_cred)
710 raise Exception, "Not enough parameters for the 'list' command"
712 # filter on person, slice, site, node, etc.
713 # THis really should be in the self.filter_records funct def comment...
714 list = filter_records(opts.type, list)
716 print "%s (%s)" % (record['hrn'], record['type'])
718 save_records_to_file(opts.file, list, opts.fileformat)
721 # show named registry record
722 def show(self, opts, args):
727 user_cred = self.get_user_cred().save_to_string(save_parents=True)
728 records = self.registry.Resolve(hrn, user_cred)
729 records = filter_records(opts.type, records)
731 self.logger.error("No record of type %s"% opts.type)
732 for record in records:
733 if record['type'] in ['user']:
734 record = UserRecord(dict=record)
735 elif record['type'] in ['slice']:
736 record = SliceRecord(dict=record)
737 elif record['type'] in ['node']:
738 record = NodeRecord(dict=record)
739 elif record['type'].startswith('authority'):
740 record = AuthorityRecord(dict=record)
742 record = SfaRecord(dict=record)
743 if (opts.format == "text"):
746 print record.save_to_string()
748 save_records_to_file(opts.file, records, opts.fileformat)
751 def delegate(self, opts, args):
753 delegee_hrn = args[0]
754 if opts.delegate_user:
755 user_cred = self.get_user_cred()
756 cred = self.delegate_cred(user_cred, delegee_hrn)
757 elif opts.delegate_slice:
758 slice_cred = self.get_slice_cred(opts.delegate_slice)
759 cred = self.delegate_cred(slice_cred, delegee_hrn)
761 self.logger.warning("Must specify either --user or --slice <hrn>")
763 delegated_cred = Credential(string=cred)
764 object_hrn = delegated_cred.get_gid_object().get_hrn()
765 if opts.delegate_user:
766 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
767 + get_leaf(object_hrn) + ".cred")
768 elif opts.delegate_slice:
769 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
770 + get_leaf(object_hrn) + ".cred")
772 delegated_cred.save_to_file(dest_fn, save_parents=True)
774 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
776 def delegate_cred(self, object_cred, hrn):
777 # the gid and hrn of the object we are delegating
778 if isinstance(object_cred, str):
779 object_cred = Credential(string=object_cred)
780 object_gid = object_cred.get_gid_object()
781 object_hrn = object_gid.get_hrn()
783 if not object_cred.get_privileges().get_all_delegate():
784 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
787 # the delegating user's gid
788 caller_gid = self._get_gid(self.user)
789 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
791 # the gid of the user who will be delegated to
792 delegee_gid = self._get_gid(hrn)
793 delegee_hrn = delegee_gid.get_hrn()
794 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
795 delegee_gid.save_to_file(filename=delegee_gidfile)
796 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
797 return dcred.save_to_string(save_parents=True)
799 # removed named registry record
800 # - have to first retrieve the record to be removed
801 def remove(self, opts, args):
802 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
810 return self.registry.Remove(hrn, auth_cred, type)
812 # add named registry record
813 def add(self, opts, args):
814 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
818 record_filepath = args[0]
819 rec_file = self.get_record_file(record_filepath)
820 record = load_record_from_file(rec_file).as_dict()
821 return self.registry.Register(record, auth_cred)
823 # update named registry entry
824 def update(self, opts, args):
825 user_cred = self.get_user_cred()
829 rec_file = self.get_record_file(args[0])
830 record = load_record_from_file(rec_file)
831 if record['type'] == "user":
832 if record.get_name() == user_cred.get_gid_object().get_hrn():
833 cred = user_cred.save_to_string(save_parents=True)
835 cred = self.get_auth_cred().save_to_string(save_parents=True)
836 elif record['type'] in ["slice"]:
838 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
839 except sfaprotocol.ServerException, e:
840 # XXX smbaker -- once we have better error return codes, update this
841 # to do something better than a string compare
842 if "Permission error" in e.args[0]:
843 cred = self.get_auth_cred().save_to_string(save_parents=True)
846 elif record.get_type() in ["authority"]:
847 cred = self.get_auth_cred().save_to_string(save_parents=True)
848 elif record.get_type() == 'node':
849 cred = self.get_auth_cred().save_to_string(save_parents=True)
851 raise "unknown record type" + record.get_type()
852 record = record.as_dict()
853 return self.registry.Update(record, cred)
855 def get_trusted_certs(self, opts, args):
857 return uhe trusted certs at this interface
859 trusted_certs = self.registry.get_trusted_certs()
860 for trusted_cert in trusted_certs:
861 gid = GID(string=trusted_cert)
863 cert = Certificate(string=trusted_cert)
864 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
867 # ==================================================================
868 # Slice-related commands
869 # ==================================================================
871 def version(self, opts, args):
872 if opts.version_local:
873 version=version_core()
875 if opts.version_registry:
878 server = self.server_proxy_from_opts(opts)
879 result = server.GetVersion()
880 version = ReturnValue.get_value(result)
881 for (k,v) in version.iteritems():
882 print "%-20s: %s"%(k,v)
884 save_variable_to_file(version, opts.file, opts.fileformat)
886 # list instantiated slices
887 def slices(self, opts, args):
889 list instantiated slices
891 user_cred = self.get_user_cred().save_to_string(save_parents=True)
894 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
895 creds.append(delegated_cred)
896 server = self.server_proxy_from_opts(opts)
898 if self.server_supports_options_arg(server):
899 options = {'call_id': unique_call_id()}
900 call_args.append(options)
901 result = server.ListSlices(*call_args)
902 value = ReturnValue.get_value(result)
906 # show rspec for named slice
907 def resources(self, opts, args):
908 user_cred = self.get_user_cred().save_to_string(save_parents=True)
909 server = self.server_proxy_from_opts(opts)
911 options = {'call_id': unique_call_id()}
912 #panos add info options
914 options['info'] = opts.info
917 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
919 options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
925 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
926 creds.append(delegated_cred)
927 if opts.rspec_version:
928 version_manager = VersionManager()
929 server_version = self.get_cached_server_version(server)
930 if 'sfa' in server_version:
931 # just request the version the client wants
932 options['geni_rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
934 # this must be a protogeni aggregate. We should request a v2 ad rspec
935 # regardless of what the client user requested
936 options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
938 options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
940 call_args = [creds, options]
941 result = server.ListResources(*call_args)
942 value = ReturnValue.get_value(result)
943 if opts.file is None:
944 display_rspec(value, opts.format)
946 save_rspec_to_file(value, opts.file)
949 # created named slice with given rspec
950 def create(self, opts, args):
951 server = self.server_proxy_from_opts(opts)
952 server_version = self.get_cached_server_version(server)
954 slice_urn = hrn_to_urn(slice_hrn, 'slice')
955 user_cred = self.get_user_cred()
956 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
957 delegated_cred = None
958 if server_version.get('interface') == 'slicemgr':
959 # delegate our cred to the slice manager
960 # do not delegate cred to slicemgr...not working at the moment
962 #if server_version.get('hrn'):
963 # delegated_cred = self.delegate_cred(slice_cred, server_version['hrn'])
964 #elif server_version.get('urn'):
965 # delegated_cred = self.delegate_cred(slice_cred, urn_to_hrn(server_version['urn']))
967 rspec_file = self.get_rspec_file(args[1])
968 rspec = open(rspec_file).read()
970 # need to pass along user keys to the aggregate.
972 # { urn: urn:publicid:IDN+emulab.net+user+alice
973 # keys: [<ssh key A>, <ssh key B>]
976 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
977 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
978 slice_record = slice_records[0]
979 user_hrns = slice_record['researcher']
980 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
981 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
983 if 'sfa' not in server_version:
984 users = pg_users_arg(user_records)
986 rspec.filter({'component_manager_id': server_version['urn']})
987 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
990 users = sfa_users_arg(user_records, slice_record)
993 creds.append(delegated_cred)
994 call_args = [slice_urn, creds, rspec, users]
995 if self.server_supports_options_arg(server):
996 options = {'call_id': unique_call_id()}
997 call_args.append(options)
998 result = server.CreateSliver(*call_args)
999 value = ReturnValue.get_value(result)
1000 if opts.file is None:
1003 save_rspec_to_file (value, opts.file)
1006 # get a ticket for the specified slice
1007 def get_ticket(self, opts, args):
1008 slice_hrn, rspec_path = args[0], args[1]
1009 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1010 user_cred = self.get_user_cred()
1011 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1012 creds = [slice_cred]
1014 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1015 creds.append(delegated_cred)
1016 rspec_file = self.get_rspec_file(rspec_path)
1017 rspec = open(rspec_file).read()
1018 server = self.server_proxy_from_opts(opts)
1019 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1020 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1021 self.logger.info("writing ticket to %s"%file)
1022 ticket = SfaTicket(string=ticket_string)
1023 ticket.save_to_file(filename=file, save_parents=True)
1025 def redeem_ticket(self, opts, args):
1026 ticket_file = args[0]
1028 # get slice hrn from the ticket
1029 # use this to get the right slice credential
1030 ticket = SfaTicket(filename=ticket_file)
1032 slice_hrn = ticket.gidObject.get_hrn()
1033 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1034 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1035 user_cred = self.get_user_cred()
1036 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1038 # get a list of node hostnames from the RSpec
1039 tree = etree.parse(StringIO(ticket.rspec))
1040 root = tree.getroot()
1041 hostnames = root.xpath("./network/site/node/hostname/text()")
1043 # create an xmlrpc connection to the component manager at each of these
1044 # components and gall redeem_ticket
1046 for hostname in hostnames:
1048 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1049 server = self.server_proxy(hostname, CM_PORT, self.key_file, \
1050 self.cert_file, self.options.debug)
1051 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1052 self.logger.info("Success")
1053 except socket.gaierror:
1054 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1055 except Exception, e:
1056 self.logger.log_exc(e.message)
1059 # delete named slice
1060 def delete(self, opts, args):
1062 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1063 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1064 creds = [slice_cred]
1066 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1067 creds.append(delegated_cred)
1068 server = self.server_proxy_from_opts(opts)
1069 call_args = [slice_urn, creds]
1070 if self.server_supports_options_arg(server):
1071 options = {'call_id': unique_call_id()}
1072 call_args.append(options)
1073 return server.DeleteSliver(*call_args)
1076 def start(self, opts, args):
1078 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1079 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1080 creds = [slice_cred]
1082 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1083 creds.append(delegated_cred)
1084 server = self.server_proxy_from_opts(opts)
1085 return server.Start(slice_urn, creds)
1088 def stop(self, opts, args):
1090 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1091 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1092 creds = [slice_cred]
1094 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1095 creds.append(delegated_cred)
1096 server = self.server_proxy_from_opts(opts)
1097 return server.Stop(slice_urn, creds)
1100 def reset(self, opts, args):
1102 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1103 server = self.server_proxy_from_opts(opts)
1104 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1105 creds = [slice_cred]
1107 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1108 creds.append(delegated_cred)
1109 return server.reset_slice(creds, slice_urn)
1111 def renew(self, opts, args):
1113 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1114 server = self.server_proxy_from_opts(opts)
1115 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1116 creds = [slice_cred]
1118 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1119 creds.append(delegated_cred)
1122 call_args = [slice_urn, creds, time]
1123 if self.server_supports_options_arg(server):
1124 options = {'call_id': unique_call_id()}
1125 call_args.append(options)
1126 result = server.RenewSliver(*call_args)
1127 value = ReturnValue.get_value(result)
1131 def status(self, opts, args):
1133 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1134 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1135 creds = [slice_cred]
1137 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1138 creds.append(delegated_cred)
1139 server = self.server_proxy_from_opts(opts)
1140 call_args = [slice_urn, creds]
1141 if self.server_supports_options_arg(server):
1142 options = {'call_id': unique_call_id()}
1143 call_args.append(options)
1144 result = server.SliverStatus(*call_args)
1145 value = ReturnValue.get_value(result)
1148 save_variable_to_file(value, opts.file, opts.fileformat)
1151 def shutdown(self, opts, args):
1153 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1154 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1155 creds = [slice_cred]
1157 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1158 creds.append(delegated_cred)
1159 server = self.server_proxy_from_opts(opts)
1160 return server.Shutdown(slice_urn, creds)
1162 def print_help (self):
1163 self.sfi_parser.print_help()
1164 self.cmd_parser.print_help()
1167 # Main: parse arguments and dispatch to command
1169 def dispatch(self, command, cmd_opts, cmd_args):
1170 return getattr(self, command)(cmd_opts, cmd_args)
1173 self.sfi_parser = self.create_parser()
1174 (options, args) = self.sfi_parser.parse_args()
1175 self.options = options
1177 self.logger.setLevelFromOptVerbose(self.options.verbose)
1178 if options.hashrequest:
1179 self.hashrequest = True
1182 self.logger.critical("No command given. Use -h for help.")
1186 self.cmd_parser = self.create_cmd_parser(command)
1187 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1190 self.logger.info("Command=%s" % command)
1191 if command in ("resources"):
1192 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1193 elif command in ("list", "show", "remove"):
1194 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1195 self.logger.debug('cmd_args %s' % cmd_args)
1198 self.dispatch(command, cmd_opts, cmd_args)
1200 self.logger.critical ("Unknown command %s"%command)
1206 if __name__ == "__main__":