3 # sfi -- slice-based facility interface
14 from lxml import etree
15 from StringIO import StringIO
16 from optparse import OptionParser
18 from sfa.trust.certificate import Keypair, Certificate
19 from sfa.trust.gid import GID
20 from sfa.trust.credential import Credential
21 from sfa.trust.sfaticket import SfaTicket
23 from sfa.util.sfalogging import sfi_logger
24 from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn
25 from sfa.util.config import Config
26 from sfa.util.version import version_core
27 from sfa.util.cache import Cache
29 from sfa.storage.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
31 from sfa.rspecs.rspec import RSpec
32 from sfa.rspecs.rspec_converter import RSpecConverter
33 from sfa.rspecs.version_manager import VersionManager
34 from sfa.client.return_value import ReturnValue
36 import sfa.client.xmlrpcprotocol as xmlrpcprotocol
37 from sfa.client.client_helper import pg_users_arg, sfa_users_arg
42 # utility methods here
44 def display_rspec(rspec, format='rspec'):
46 tree = etree.parse(StringIO(rspec))
48 result = root.xpath("./network/site/node/hostname/text()")
49 elif format in ['ip']:
50 # The IP address is not yet part of the new RSpec
51 # so this doesn't do anything yet.
52 tree = etree.parse(StringIO(rspec))
54 result = root.xpath("./network/site/node/ipv4/text()")
61 def display_list(results):
62 for result in results:
65 def display_records(recordList, dump=False):
66 ''' Print all fields in the record'''
67 for record in recordList:
68 display_record(record, dump)
70 def display_record(record, dump=False):
74 info = record.getdict()
75 print "%s (%s)" % (info['hrn'], info['type'])
79 def filter_records(type, records):
81 for record in records:
82 if (record['type'] == type) or (type == "all"):
83 filtered_records.append(record)
84 return filtered_records
88 def save_variable_to_file(var, filename, format="text"):
89 f = open(filename, "w")
92 elif format == "pickled":
93 f.write(pickle.dumps(var))
95 # this should never happen
96 print "unknown output format", format
99 def save_rspec_to_file(rspec, filename):
100 if not filename.endswith(".rspec"):
101 filename = filename + ".rspec"
102 f = open(filename, 'w')
107 def save_records_to_file(filename, recordList, format="xml"):
110 for record in recordList:
112 save_record_to_file(filename + "." + str(index), record)
114 save_record_to_file(filename, record)
116 elif format == "xmllist":
117 f = open(filename, "w")
118 f.write("<recordlist>\n")
119 for record in recordList:
120 record = SfaRecord(dict=record)
121 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
122 f.write("</recordlist>\n")
124 elif format == "hrnlist":
125 f = open(filename, "w")
126 for record in recordList:
127 record = SfaRecord(dict=record)
128 f.write(record.get_name() + "\n")
131 # this should never happen
132 print "unknown output format", format
134 def save_record_to_file(filename, record):
135 if record['type'] in ['user']:
136 record = UserRecord(dict=record)
137 elif record['type'] in ['slice']:
138 record = SliceRecord(dict=record)
139 elif record['type'] in ['node']:
140 record = NodeRecord(dict=record)
141 elif record['type'] in ['authority', 'ma', 'sa']:
142 record = AuthorityRecord(dict=record)
144 record = SfaRecord(dict=record)
145 str = record.save_to_string()
146 f=codecs.open(filename, encoding='utf-8',mode="w")
153 def load_record_from_file(filename):
154 f=codecs.open(filename, encoding="utf-8", mode="r")
157 record = SfaRecord(string=str)
162 def unique_call_id(): return uuid.uuid4().urn
166 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
168 # dummy to meet Sfi's expectations for its 'options' field
169 # i.e. s/t we can do setattr on
173 def __init__ (self,options=None):
174 if options is None: options=Sfi.DummyOptions()
175 for opt in Sfi.required_options:
176 if not hasattr(options,opt): setattr(options,opt,None)
177 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
178 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
179 # would be safer to remove self.sfi_dir altogether
180 self.sfi_dir = options.sfi_dir
181 self.options = options
185 self.authority = None
186 self.hashrequest = False
187 self.logger = sfi_logger
188 self.logger.enable_console()
190 def create_cmd_parser(self, command, additional_cmdargs=None):
191 cmdargs = {"list": "authority",
196 "aggregates": "[name]",
197 "registries": "[name]",
198 "create_gid": "[name]",
200 "get_trusted_certs": "cred",
202 "resources": "[name]",
203 "create": "name rspec",
204 "get_ticket": "name rspec",
205 "redeem_ticket": "ticket",
217 if additional_cmdargs:
218 cmdargs.update(additional_cmdargs)
220 if command not in cmdargs:
221 msg="Invalid command\n"
223 msg += ','.join(cmdargs.keys())
224 self.logger.critical(msg)
227 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
228 % (command, cmdargs[command]))
230 # user specifies remote aggregate/sm/component
231 if command in ("resources", "slices", "create", "delete", "start", "stop",
232 "restart", "shutdown", "get_ticket", "renew", "status"):
233 parser.add_option("-a", "--aggregate", dest="aggregate",
234 default=None, help="aggregate host")
235 parser.add_option("-p", "--port", dest="port",
236 default=AGGREGATE_PORT, help="aggregate port")
237 parser.add_option("-c", "--component", dest="component", default=None,
238 help="component hrn")
239 parser.add_option("-d", "--delegate", dest="delegate", default=None,
241 help="Include a credential delegated to the user's root"+\
242 "authority in set of credentials for this call")
244 # registy filter option
245 if command in ("list", "show", "remove"):
246 parser.add_option("-t", "--type", dest="type", type="choice",
247 help="type filter ([all]|user|slice|authority|node|aggregate)",
248 choices=("all", "user", "slice", "authority", "node", "aggregate"),
251 if command in ("resources"):
252 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
253 help="schema type and version of resulting RSpec")
254 parser.add_option("-f", "--format", dest="format", type="choice",
255 help="display format ([xml]|dns|ip)", default="xml",
256 choices=("xml", "dns", "ip"))
257 #panos: a new option to define the type of information about resources a user is interested in
258 parser.add_option("-i", "--info", dest="info",
259 help="optional component information", default=None)
262 # 'create' does return the new rspec, makes sense to save that too
263 if command in ("resources", "show", "list", "create_gid", 'create'):
264 parser.add_option("-o", "--output", dest="file",
265 help="output XML to file", metavar="FILE", default=None)
267 if command in ("show", "list"):
268 parser.add_option("-f", "--format", dest="format", type="choice",
269 help="display format ([text]|xml)", default="text",
270 choices=("text", "xml"))
272 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
273 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
274 choices=("xml", "xmllist", "hrnlist"))
276 if command in ("status", "version"):
277 parser.add_option("-o", "--output", dest="file",
278 help="output dictionary to file", metavar="FILE", default=None)
279 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
280 help="output file format ([text]|pickled)", default="text",
281 choices=("text","pickled"))
283 if command in ("delegate"):
284 parser.add_option("-u", "--user",
285 action="store_true", dest="delegate_user", default=False,
286 help="delegate user credential")
287 parser.add_option("-s", "--slice", dest="delegate_slice",
288 help="delegate slice credential", metavar="HRN", default=None)
290 if command in ("version"):
291 parser.add_option("-a", "--aggregate", dest="aggregate",
292 default=None, help="aggregate host")
293 parser.add_option("-p", "--port", dest="port",
294 default=AGGREGATE_PORT, help="aggregate port")
295 parser.add_option("-R","--registry-version",
296 action="store_true", dest="version_registry", default=False,
297 help="probe registry version instead of slicemgr")
298 parser.add_option("-l","--local",
299 action="store_true", dest="version_local", default=False,
300 help="display version of the local client")
305 def create_parser(self):
307 # Generate command line parser
308 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
309 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
310 parser.add_option("-r", "--registry", dest="registry",
311 help="root registry", metavar="URL", default=None)
312 parser.add_option("-s", "--slicemgr", dest="sm",
313 help="slice manager", metavar="URL", default=None)
314 default_sfi_dir = os.path.expanduser("~/.sfi/")
315 parser.add_option("-d", "--dir", dest="sfi_dir",
316 help="config & working directory - default is " + default_sfi_dir,
317 metavar="PATH", default=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 = Keypair(filename=key_file)
404 self.key_file = key_file
405 self.cert_file = cert_file
406 self.cert = GID(filename=cert_file)
407 self.logger.info("Contacting Registry at: %s"%self.reg_url)
408 self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
409 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
410 self.slicemgr = xmlrpcprotocol.server_proxy(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
413 def get_cached_server_version(self, server):
414 # check local cache first
417 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
418 cache_key = server.url + "-version"
420 cache = Cache(cache_file)
423 self.logger.info("Local cache not found at: %s" % cache_file)
426 version = cache.get(cache_key)
429 result = server.GetVersion()
430 version= ReturnValue.get_value(result)
431 # cache version for 24 hours
432 cache.add(cache_key, version, ttl= 60*60*24)
433 self.logger.info("Updating cache file %s" % cache_file)
434 cache.save_to_file(cache_file)
439 def server_supports_options_arg(self, server):
441 Returns true if server support the optional call_id arg, false otherwise.
443 server_version = self.get_cached_server_version(server)
444 if 'sfa' in server_version and 'code_tag' in server_version:
445 code_tag = server_version['code_tag']
446 code_tag_parts = code_tag.split("-")
448 version_parts = code_tag_parts[0].split(".")
449 major, minor = version_parts[0], version_parts[1]
450 rev = code_tag_parts[1]
457 # Get various credential and spec files
459 # Establishes limiting conventions
460 # - conflates MAs and SAs
461 # - assumes last token in slice name is unique
463 # Bootstraps credentials
464 # - bootstrap user credential from self-signed certificate
465 # - bootstrap authority credential from user credential
466 # - bootstrap slice credential from user credential
470 def get_key_file(self):
471 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
472 if (os.path.isfile(file)):
475 self.logger.error("Key file %s does not exist"%file)
479 def get_cert_file(self, key_file):
481 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
482 if (os.path.isfile(cert_file)):
483 # we'd perfer to use Registry issued certs instead of self signed certs.
484 # if this is a Registry cert (GID) then we are done
485 gid = GID(filename=cert_file)
489 # generate self signed certificate
490 k = Keypair(filename=key_file)
491 cert = Certificate(subject=self.user)
493 cert.set_issuer(k, self.user)
495 self.logger.info("Writing self-signed certificate to %s"%cert_file)
496 cert.save_to_file(cert_file)
498 # try to get registry issued cert
500 self.logger.info("Getting Registry issued cert")
502 # *hack. need to set registyr before _get_gid() is called
503 self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, 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 print>>sys.stderr, " \r\n \t SFI.PY _get_gid "
547 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
549 raise RecordNotFound(args[0])
554 if type == rec['type']:
557 raise RecordNotFound(args[0])
559 gid = GID(string=record['gid'])
560 self.logger.info("Writing gid to %s"%gidfile)
561 gid.save_to_file(filename=gidfile)
565 def get_cached_credential(self, file):
567 Return a cached credential only if it hasn't expired.
569 if (os.path.isfile(file)):
570 credential = Credential(filename=file)
571 # make sure it isnt expired
572 if not credential.get_expiration or \
573 datetime.datetime.today() < credential.get_expiration():
577 def get_user_cred(self):
578 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
579 return self.get_cred(file, 'user', self.user)
581 def get_auth_cred(self):
582 if not self.authority:
583 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
585 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
586 return self.get_cred(file, 'authority', self.authority)
588 def get_slice_cred(self, name):
589 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
590 return self.get_cred(file, 'slice', name)
592 def get_cred(self, file, type, hrn):
593 # attempt to load a cached credential
594 cred = self.get_cached_credential(file)
597 cert_string = self.cert.save_to_string(save_parents=True)
598 user_name = self.user.replace(self.authority + ".", '')
599 if user_name.count(".") > 0:
600 user_name = user_name.replace(".", '_')
601 self.user = self.authority + "." + user_name
602 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
604 # bootstrap slice credential from user credential
605 user_cred = self.get_user_cred().save_to_string(save_parents=True)
606 cred_str = self.registry.GetCredential(user_cred, hrn, type)
609 self.logger.critical("Failed to get %s credential" % type)
612 cred = Credential(string=cred_str)
613 cred.save_to_file(file, save_parents=True)
614 self.logger.info("Writing %s credential to %s" %(type, file))
619 def get_rspec_file(self, rspec):
620 if (os.path.isabs(rspec)):
623 file = os.path.join(self.options.sfi_dir, rspec)
624 if (os.path.isfile(file)):
627 self.logger.critical("No such rspec file %s"%rspec)
630 def get_record_file(self, record):
631 if (os.path.isabs(record)):
634 file = os.path.join(self.options.sfi_dir, record)
635 if (os.path.isfile(file)):
638 self.logger.critical("No such registry record file %s"%record)
641 def load_publickey_string(self, fn):
643 key_string = f.read()
645 # if the filename is a private key file, then extract the public key
646 if "PRIVATE KEY" in key_string:
647 outfn = tempfile.mktemp()
648 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
651 key_string = f.read()
657 def get_component_proxy_from_hrn(self, hrn):
658 # direct connection to the nodes component manager interface
659 user_cred = self.get_user_cred().save_to_string(save_parents=True)
660 records = self.registry.Resolve(hrn, user_cred)
661 records = filter_records('node', records)
663 self.logger.warning("No such component:%r"% opts.component)
666 return self.server_proxy(record['hostname'], CM_PORT, self.key_file, self.cert_file)
668 def server_proxy(self, host, port, keyfile, certfile):
670 Return an instance of an xmlrpc server connection
672 # port is appended onto the domain, before the path. Should look like:
673 # http://domain:port/path
674 host_parts = host.split('/')
675 host_parts[0] = host_parts[0] + ":" + str(port)
676 url = "http://%s" % "/".join(host_parts)
677 return xmlrpcprotocol.server_proxy(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
679 # xxx opts could be retrieved in self.options
680 def server_proxy_from_opts(self, opts):
682 Return instance of an xmlrpc connection to a slice manager, aggregate
683 or component server depending on the specified opts
685 server = self.slicemgr
686 # direct connection to an aggregate
687 if hasattr(opts, 'aggregate') and opts.aggregate:
688 server = self.server_proxy(opts.aggregate, opts.port, self.key_file, self.cert_file)
689 # direct connection to the nodes component manager interface
690 if hasattr(opts, 'component') and opts.component:
691 server = self.get_component_proxy_from_hrn(opts.component)
694 #==========================================================================
695 # Following functions implement the commands
697 # Registry-related commands
698 #==========================================================================
700 def dispatch(self, command, cmd_opts, cmd_args):
701 return getattr(self, command)(cmd_opts, cmd_args)
703 def create_gid(self, opts, args):
708 user_cred = self.get_user_cred().save_to_string(save_parents=True)
709 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
713 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
714 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
715 GID(string=gid).save_to_file(filename)
718 # list entires in named authority registry
719 def list(self, opts, args):
724 user_cred = self.get_user_cred().save_to_string(save_parents=True)
726 list = self.registry.List(hrn, user_cred)
728 raise Exception, "Not enough parameters for the 'list' command"
730 # filter on person, slice, site, node, etc.
731 # THis really should be in the self.filter_records funct def comment...
732 list = filter_records(opts.type, list)
734 print "%s (%s)" % (record['hrn'], record['type'])
736 save_records_to_file(opts.file, list, opts.fileformat)
739 # show named registry record
740 def show(self, opts, args):
745 user_cred = self.get_user_cred().save_to_string(save_parents=True)
746 records = self.registry.Resolve(hrn, user_cred)
747 records = filter_records(opts.type, records)
749 print "No record of type", opts.type
750 for record in records:
751 if record['type'] in ['user']:
752 record = UserRecord(dict=record)
753 elif record['type'] in ['slice']:
754 record = SliceRecord(dict=record)
755 elif record['type'] in ['node']:
756 record = NodeRecord(dict=record)
757 elif record['type'].startswith('authority'):
758 record = AuthorityRecord(dict=record)
760 record = SfaRecord(dict=record)
761 if (opts.format == "text"):
764 print record.save_to_string()
766 save_records_to_file(opts.file, records, opts.fileformat)
769 def delegate(self, opts, args):
771 delegee_hrn = args[0]
772 if opts.delegate_user:
773 user_cred = self.get_user_cred()
774 cred = self.delegate_cred(user_cred, delegee_hrn)
775 elif opts.delegate_slice:
776 slice_cred = self.get_slice_cred(opts.delegate_slice)
777 cred = self.delegate_cred(slice_cred, delegee_hrn)
779 self.logger.warning("Must specify either --user or --slice <hrn>")
781 delegated_cred = Credential(string=cred)
782 object_hrn = delegated_cred.get_gid_object().get_hrn()
783 if opts.delegate_user:
784 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
785 + get_leaf(object_hrn) + ".cred")
786 elif opts.delegate_slice:
787 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
788 + get_leaf(object_hrn) + ".cred")
790 delegated_cred.save_to_file(dest_fn, save_parents=True)
792 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
794 def delegate_cred(self, object_cred, hrn):
795 # the gid and hrn of the object we are delegating
796 if isinstance(object_cred, str):
797 object_cred = Credential(string=object_cred)
798 object_gid = object_cred.get_gid_object()
799 object_hrn = object_gid.get_hrn()
801 if not object_cred.get_privileges().get_all_delegate():
802 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
805 # the delegating user's gid
806 caller_gid = self._get_gid(self.user)
807 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
809 # the gid of the user who will be delegated to
810 delegee_gid = self._get_gid(hrn)
811 delegee_hrn = delegee_gid.get_hrn()
812 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
813 delegee_gid.save_to_file(filename=delegee_gidfile)
814 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
815 return dcred.save_to_string(save_parents=True)
817 # removed named registry record
818 # - have to first retrieve the record to be removed
819 def remove(self, opts, args):
820 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
828 return self.registry.Remove(hrn, auth_cred, type)
830 # add named registry record
831 def add(self, opts, args):
832 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
836 record_filepath = args[0]
837 rec_file = self.get_record_file(record_filepath)
838 record = load_record_from_file(rec_file).as_dict()
839 return self.registry.Register(record, auth_cred)
841 # update named registry entry
842 def update(self, opts, args):
843 user_cred = self.get_user_cred()
847 rec_file = self.get_record_file(args[0])
848 record = load_record_from_file(rec_file)
849 if record['type'] == "user":
850 if record.get_name() == user_cred.get_gid_object().get_hrn():
851 cred = user_cred.save_to_string(save_parents=True)
853 cred = self.get_auth_cred().save_to_string(save_parents=True)
854 elif record['type'] in ["slice"]:
856 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
857 except xmlrpcprotocol.ServerException, e:
858 # XXX smbaker -- once we have better error return codes, update this
859 # to do something better than a string compare
860 if "Permission error" in e.args[0]:
861 cred = self.get_auth_cred().save_to_string(save_parents=True)
864 elif record.get_type() in ["authority"]:
865 cred = self.get_auth_cred().save_to_string(save_parents=True)
866 elif record.get_type() == 'node':
867 cred = self.get_auth_cred().save_to_string(save_parents=True)
869 raise "unknown record type" + record.get_type()
870 record = record.as_dict()
871 return self.registry.Update(record, cred)
873 def get_trusted_certs(self, opts, args):
875 return uhe trusted certs at this interface
877 trusted_certs = self.registry.get_trusted_certs()
878 for trusted_cert in trusted_certs:
879 gid = GID(string=trusted_cert)
881 cert = Certificate(string=trusted_cert)
882 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
885 def aggregates(self, opts, args):
887 return a list of details about known aggregates
889 user_cred = self.get_user_cred().save_to_string(save_parents=True)
894 result = self.registry.get_aggregates(user_cred, hrn)
898 def registries(self, opts, args):
900 return a list of details about known registries
902 user_cred = self.get_user_cred().save_to_string(save_parents=True)
906 result = self.registry.get_registries(user_cred, hrn)
911 # ==================================================================
912 # Slice-related commands
913 # ==================================================================
915 def version(self, opts, args):
916 if opts.version_local:
917 version=version_core()
919 if opts.version_registry:
922 server = self.server_proxy_from_opts(opts)
923 result = server.GetVersion()
924 version = ReturnValue.get_value(result)
925 for (k,v) in version.iteritems():
926 print "%-20s: %s"%(k,v)
928 save_variable_to_file(version, opts.file, opts.fileformat)
930 # list instantiated slices
931 def slices(self, opts, args):
933 list instantiated slices
935 user_cred = self.get_user_cred().save_to_string(save_parents=True)
938 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
939 creds.append(delegated_cred)
940 server = self.server_proxy_from_opts(opts)
942 if self.server_supports_options_arg(server):
943 options = {'call_id': unique_call_id()}
944 call_args.append(options)
945 result = server.ListSlices(*call_args)
946 value = ReturnValue.get_value(result)
950 # show rspec for named slice
951 def resources(self, opts, args):
952 user_cred = self.get_user_cred().save_to_string(save_parents=True)
953 server = self.slicemgr
954 server = self.server_proxy_from_opts(opts)
956 options = {'call_id': unique_call_id()}
957 #panos add info options
959 options['info'] = opts.info
962 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
964 options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
970 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
971 creds.append(delegated_cred)
972 if opts.rspec_version:
973 version_manager = VersionManager()
974 server_version = self.get_cached_server_version(server)
975 if 'sfa' in server_version:
976 # just request the version the client wants
977 options['geni_rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
979 # this must be a protogeni aggregate. We should request a v2 ad rspec
980 # regardless of what the client user requested
981 options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
983 options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
985 call_args = [creds, options]
986 result = server.ListResources(*call_args)
987 value = ReturnValue.get_value(result)
988 if opts.file is None:
989 display_rspec(value, opts.format)
991 save_rspec_to_file(value, opts.file)
994 # created named slice with given rspec
995 def create(self, opts, args):
996 server = self.server_proxy_from_opts(opts)
997 server_version = self.get_cached_server_version(server)
999 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1000 user_cred = self.get_user_cred()
1001 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1003 if hasattr(opts, 'aggregate') and opts.aggregate:
1004 delegated_cred = None
1006 # delegate the cred to the callers root authority
1007 print>>sys.stderr, " \r\n \r\n \t SFI.PY get_authority(self.authority+'.slicemanager') %s self.authority %s slice_cred \t %s " %(get_authority(self.authority+'.slicemanager'), self.authority, slice_cred)
1008 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority+'.slicemanager'))
1010 #delegated_cred = self.delegate_cred(slice_cred, get_authority(slice_hrn))
1011 #creds.append(delegated_cred)
1013 rspec_file = self.get_rspec_file(args[1])
1014 rspec = open(rspec_file).read()
1016 # need to pass along user keys to the aggregate.
1018 # { urn: urn:publicid:IDN+emulab.net+user+alice
1019 # keys: [<ssh key A>, <ssh key B>]
1022 print>>sys.stderr, " \r\n SFI.PY create slice_urn ", slice_urn
1023 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
1024 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
1025 slice_record = slice_records[0]
1026 user_hrns = slice_record['researcher']
1027 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
1028 print>>sys.stderr, " \r\n SFI.PY create user_urns %s \r\n \t slice_records %s"%( user_urns,slice_records)
1029 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
1031 if 'sfa' not in server_version:
1032 users = pg_users_arg(user_records)
1033 rspec = RSpec(rspec)
1034 rspec.filter({'component_manager_id': server_version['urn']})
1035 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
1036 creds = [slice_cred]
1038 print >>sys.stderr, "\r\n \r\n \r\n WOOOOOO"
1039 users = sfa_users_arg(user_records, slice_record)
1040 creds = [slice_cred]
1042 creds.append(delegated_cred)
1043 call_args = [slice_urn, creds, rspec, users]
1044 if self.server_supports_options_arg(server):
1045 options = {'call_id': unique_call_id()}
1046 call_args.append(options)
1047 print>>sys.stderr, " \r\n SFI.PY create user" ,users
1048 result = server.CreateSliver(*call_args)
1049 value = ReturnValue.get_value(result)
1050 if opts.file is None:
1053 save_rspec_to_file (value, opts.file)
1056 # get a ticket for the specified slice
1057 def get_ticket(self, opts, args):
1058 slice_hrn, rspec_path = args[0], args[1]
1059 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1060 user_cred = self.get_user_cred()
1061 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1062 creds = [slice_cred]
1064 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1065 creds.append(delegated_cred)
1066 rspec_file = self.get_rspec_file(rspec_path)
1067 rspec = open(rspec_file).read()
1068 server = self.server_proxy_from_opts(opts)
1069 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1070 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1071 self.logger.info("writing ticket to %s"%file)
1072 ticket = SfaTicket(string=ticket_string)
1073 ticket.save_to_file(filename=file, save_parents=True)
1075 def redeem_ticket(self, opts, args):
1076 ticket_file = args[0]
1078 # get slice hrn from the ticket
1079 # use this to get the right slice credential
1080 ticket = SfaTicket(filename=ticket_file)
1082 slice_hrn = ticket.gidObject.get_hrn()
1083 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1084 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1085 user_cred = self.get_user_cred()
1086 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1088 # get a list of node hostnames from the RSpec
1089 tree = etree.parse(StringIO(ticket.rspec))
1090 root = tree.getroot()
1091 hostnames = root.xpath("./network/site/node/hostname/text()")
1093 # create an xmlrpc connection to the component manager at each of these
1094 # components and gall redeem_ticket
1096 for hostname in hostnames:
1098 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1099 server = self.server_proxy(hostname, CM_PORT, self.key_file, \
1100 self.cert_file, self.options.debug)
1101 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1102 self.logger.info("Success")
1103 except socket.gaierror:
1104 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1105 except Exception, e:
1106 self.logger.log_exc(e.message)
1109 # delete named slice
1110 def delete(self, opts, args):
1112 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1113 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1114 creds = [slice_cred]
1116 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1117 creds.append(delegated_cred)
1118 server = self.server_proxy_from_opts(opts)
1119 call_args = [slice_urn, creds]
1120 if self.server_supports_options_arg(server):
1121 options = {'call_id': unique_call_id()}
1122 call_args.append(options)
1123 return server.DeleteSliver(*call_args)
1126 def start(self, opts, args):
1128 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1129 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1130 creds = [slice_cred]
1132 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1133 creds.append(delegated_cred)
1134 server = self.server_proxy_from_opts(opts)
1135 return server.Start(slice_urn, creds)
1138 def stop(self, opts, args):
1140 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1141 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1142 creds = [slice_cred]
1144 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1145 creds.append(delegated_cred)
1146 server = self.server_proxy_from_opts(opts)
1147 return server.Stop(slice_urn, creds)
1150 def reset(self, opts, args):
1152 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1153 server = self.server_proxy_from_opts(opts)
1154 slice_cred = self.get_slice_cred(args[0]).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 return server.reset_slice(creds, slice_urn)
1161 def renew(self, opts, args):
1163 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1164 server = self.server_proxy_from_opts(opts)
1165 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1166 creds = [slice_cred]
1168 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1169 creds.append(delegated_cred)
1172 call_args = [slice_urn, creds, time]
1173 if self.server_supports_options_arg(server):
1174 options = {'call_id': unique_call_id()}
1175 call_args.append(options)
1176 result = server.RenewSliver(*call_args)
1177 value = ReturnValue.get_value(result)
1181 def status(self, opts, args):
1183 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1184 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1185 creds = [slice_cred]
1187 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1188 creds.append(delegated_cred)
1189 server = self.server_proxy_from_opts(opts)
1190 call_args = [slice_urn, creds]
1191 if self.server_supports_options_arg(server):
1192 options = {'call_id': unique_call_id()}
1193 call_args.append(options)
1194 result = server.SliverStatus(*call_args)
1195 value = ReturnValue.get_value(result)
1198 save_variable_to_file(value, opts.file, opts.fileformat)
1201 def shutdown(self, opts, args):
1203 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1204 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1205 creds = [slice_cred]
1207 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1208 creds.append(delegated_cred)
1209 server = self.server_proxy_from_opts(opts)
1210 return server.Shutdown(slice_urn, creds)
1212 def print_help (self):
1213 self.sfi_parser.print_help()
1214 self.cmd_parser.print_help()
1217 # Main: parse arguments and dispatch to command
1220 self.sfi_parser = self.create_parser()
1221 (options, args) = self.sfi_parser.parse_args()
1222 self.options = options
1224 self.logger.setLevelFromOptVerbose(self.options.verbose)
1225 if options.hashrequest:
1226 self.hashrequest = True
1229 self.logger.critical("No command given. Use -h for help.")
1233 self.cmd_parser = self.create_cmd_parser(command)
1234 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1237 self.logger.info("Command=%s" % command)
1238 if command in ("resources"):
1239 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1240 elif command in ("list", "show", "remove"):
1241 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1242 self.logger.debug('cmd_args %s' % cmd_args)
1245 self.dispatch(command, cmd_opts, cmd_args)
1247 self.logger.critical ("Unknown command %s"%command)
1253 if __name__ == "__main__":