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.sfaprotocol as sfaprotocol
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_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 registyr before _get_gid() is called
502 self.registry = sfaprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
503 gid = self._get_gid(type='user')
505 self.logger.info("Writing certificate to %s"%cert_file)
506 gid.save_to_file(cert_file)
508 self.logger.info("Failed to download Registry issued cert")
512 def get_cached_gid(self, file):
517 if (os.path.isfile(file)):
518 gid = GID(filename=file)
522 def get_gid(self, opts, args):
524 Get the specify gid and save it to file
529 gid = self._get_gid(hrn)
530 self.logger.debug("Sfi.get_gid-> %s" % gid.save_to_string(save_parents=True))
533 def _get_gid(self, hrn=None, type=None):
535 git_gid helper. Retrive the gid from the registry and save it to file.
541 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
542 gid = self.get_cached_gid(gidfile)
544 user_cred = self.get_user_cred()
545 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
547 raise RecordNotFound(args[0])
552 if type == rec['type']:
555 raise RecordNotFound(args[0])
557 gid = GID(string=record['gid'])
558 self.logger.info("Writing gid to %s"%gidfile)
559 gid.save_to_file(filename=gidfile)
563 def get_cached_credential(self, file):
565 Return a cached credential only if it hasn't expired.
567 if (os.path.isfile(file)):
568 credential = Credential(filename=file)
569 # make sure it isnt expired
570 if not credential.get_expiration or \
571 datetime.datetime.today() < credential.get_expiration():
575 def get_user_cred(self):
576 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
577 return self.get_cred(file, 'user', self.user)
579 def get_auth_cred(self):
580 if not self.authority:
581 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
583 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
584 return self.get_cred(file, 'authority', self.authority)
586 def get_slice_cred(self, name):
587 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
588 return self.get_cred(file, 'slice', name)
590 def get_cred(self, file, type, hrn):
591 # attempt to load a cached credential
592 cred = self.get_cached_credential(file)
595 cert_string = self.cert.save_to_string(save_parents=True)
596 user_name = self.user.replace(self.authority + ".", '')
597 if user_name.count(".") > 0:
598 user_name = user_name.replace(".", '_')
599 self.user = self.authority + "." + user_name
600 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
602 # bootstrap slice credential from user credential
603 user_cred = self.get_user_cred().save_to_string(save_parents=True)
604 cred_str = self.registry.GetCredential(user_cred, hrn, type)
607 self.logger.critical("Failed to get %s credential" % type)
610 cred = Credential(string=cred_str)
611 cred.save_to_file(file, save_parents=True)
612 self.logger.info("Writing %s credential to %s" %(type, file))
617 def get_rspec_file(self, rspec):
618 if (os.path.isabs(rspec)):
621 file = os.path.join(self.options.sfi_dir, rspec)
622 if (os.path.isfile(file)):
625 self.logger.critical("No such rspec file %s"%rspec)
628 def get_record_file(self, record):
629 if (os.path.isabs(record)):
632 file = os.path.join(self.options.sfi_dir, record)
633 if (os.path.isfile(file)):
636 self.logger.critical("No such registry record file %s"%record)
639 def load_publickey_string(self, fn):
641 key_string = f.read()
643 # if the filename is a private key file, then extract the public key
644 if "PRIVATE KEY" in key_string:
645 outfn = tempfile.mktemp()
646 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
649 key_string = f.read()
655 def get_component_proxy_from_hrn(self, hrn):
656 # direct connection to the nodes component manager interface
657 user_cred = self.get_user_cred().save_to_string(save_parents=True)
658 records = self.registry.Resolve(hrn, user_cred)
659 records = filter_records('node', records)
661 self.logger.warning("No such component:%r"% opts.component)
664 return self.server_proxy(record['hostname'], CM_PORT, self.key_file, self.cert_file)
666 def server_proxy(self, host, port, keyfile, certfile):
668 Return an instance of an xmlrpc server connection
670 # port is appended onto the domain, before the path. Should look like:
671 # http://domain:port/path
672 host_parts = host.split('/')
673 host_parts[0] = host_parts[0] + ":" + str(port)
674 url = "http://%s" % "/".join(host_parts)
675 return sfaprotocol.server_proxy(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
677 # xxx opts could be retrieved in self.options
678 def server_proxy_from_opts(self, opts):
680 Return instance of an xmlrpc connection to a slice manager, aggregate
681 or component server depending on the specified opts
683 server = self.slicemgr
684 # direct connection to an aggregate
685 if hasattr(opts, 'aggregate') and opts.aggregate:
686 server = self.server_proxy(opts.aggregate, opts.port, self.key_file, self.cert_file)
687 # direct connection to the nodes component manager interface
688 if hasattr(opts, 'component') and opts.component:
689 server = self.get_component_proxy_from_hrn(opts.component)
692 #==========================================================================
693 # Following functions implement the commands
695 # Registry-related commands
696 #==========================================================================
698 def dispatch(self, command, cmd_opts, cmd_args):
699 return getattr(self, command)(cmd_opts, cmd_args)
701 def create_gid(self, opts, args):
706 user_cred = self.get_user_cred().save_to_string(save_parents=True)
707 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
711 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
712 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
713 GID(string=gid).save_to_file(filename)
716 # list entires in named authority registry
717 def list(self, opts, args):
722 user_cred = self.get_user_cred().save_to_string(save_parents=True)
724 list = self.registry.List(hrn, user_cred)
726 raise Exception, "Not enough parameters for the 'list' command"
728 # filter on person, slice, site, node, etc.
729 # THis really should be in the self.filter_records funct def comment...
730 list = filter_records(opts.type, list)
732 print "%s (%s)" % (record['hrn'], record['type'])
734 save_records_to_file(opts.file, list, opts.fileformat)
737 # show named registry record
738 def show(self, opts, args):
743 user_cred = self.get_user_cred().save_to_string(save_parents=True)
744 records = self.registry.Resolve(hrn, user_cred)
745 records = filter_records(opts.type, records)
747 print "No record of type", opts.type
748 for record in records:
749 if record['type'] in ['user']:
750 record = UserRecord(dict=record)
751 elif record['type'] in ['slice']:
752 record = SliceRecord(dict=record)
753 elif record['type'] in ['node']:
754 record = NodeRecord(dict=record)
755 elif record['type'].startswith('authority'):
756 record = AuthorityRecord(dict=record)
758 record = SfaRecord(dict=record)
759 if (opts.format == "text"):
762 print record.save_to_string()
764 save_records_to_file(opts.file, records, opts.fileformat)
767 def delegate(self, opts, args):
769 delegee_hrn = args[0]
770 if opts.delegate_user:
771 user_cred = self.get_user_cred()
772 cred = self.delegate_cred(user_cred, delegee_hrn)
773 elif opts.delegate_slice:
774 slice_cred = self.get_slice_cred(opts.delegate_slice)
775 cred = self.delegate_cred(slice_cred, delegee_hrn)
777 self.logger.warning("Must specify either --user or --slice <hrn>")
779 delegated_cred = Credential(string=cred)
780 object_hrn = delegated_cred.get_gid_object().get_hrn()
781 if opts.delegate_user:
782 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
783 + get_leaf(object_hrn) + ".cred")
784 elif opts.delegate_slice:
785 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
786 + get_leaf(object_hrn) + ".cred")
788 delegated_cred.save_to_file(dest_fn, save_parents=True)
790 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
792 def delegate_cred(self, object_cred, hrn):
793 # the gid and hrn of the object we are delegating
794 if isinstance(object_cred, str):
795 object_cred = Credential(string=object_cred)
796 object_gid = object_cred.get_gid_object()
797 object_hrn = object_gid.get_hrn()
799 if not object_cred.get_privileges().get_all_delegate():
800 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
803 # the delegating user's gid
804 caller_gid = self._get_gid(self.user)
805 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
807 # the gid of the user who will be delegated to
808 delegee_gid = self._get_gid(hrn)
809 delegee_hrn = delegee_gid.get_hrn()
810 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
811 delegee_gid.save_to_file(filename=delegee_gidfile)
812 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
813 return dcred.save_to_string(save_parents=True)
815 # removed named registry record
816 # - have to first retrieve the record to be removed
817 def remove(self, opts, args):
818 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
826 return self.registry.Remove(hrn, auth_cred, type)
828 # add named registry record
829 def add(self, opts, args):
830 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
834 record_filepath = args[0]
835 rec_file = self.get_record_file(record_filepath)
836 record = load_record_from_file(rec_file).as_dict()
837 return self.registry.Register(record, auth_cred)
839 # update named registry entry
840 def update(self, opts, args):
841 user_cred = self.get_user_cred()
845 rec_file = self.get_record_file(args[0])
846 record = load_record_from_file(rec_file)
847 if record['type'] == "user":
848 if record.get_name() == user_cred.get_gid_object().get_hrn():
849 cred = user_cred.save_to_string(save_parents=True)
851 cred = self.get_auth_cred().save_to_string(save_parents=True)
852 elif record['type'] in ["slice"]:
854 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
855 except sfaprotocol.ServerException, e:
856 # XXX smbaker -- once we have better error return codes, update this
857 # to do something better than a string compare
858 if "Permission error" in e.args[0]:
859 cred = self.get_auth_cred().save_to_string(save_parents=True)
862 elif record.get_type() in ["authority"]:
863 cred = self.get_auth_cred().save_to_string(save_parents=True)
864 elif record.get_type() == 'node':
865 cred = self.get_auth_cred().save_to_string(save_parents=True)
867 raise "unknown record type" + record.get_type()
868 record = record.as_dict()
869 return self.registry.Update(record, cred)
871 def get_trusted_certs(self, opts, args):
873 return uhe trusted certs at this interface
875 trusted_certs = self.registry.get_trusted_certs()
876 for trusted_cert in trusted_certs:
877 gid = GID(string=trusted_cert)
879 cert = Certificate(string=trusted_cert)
880 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
883 def aggregates(self, opts, args):
885 return a list of details about known aggregates
887 user_cred = self.get_user_cred().save_to_string(save_parents=True)
892 result = self.registry.get_aggregates(user_cred, hrn)
896 def registries(self, opts, args):
898 return a list of details about known registries
900 user_cred = self.get_user_cred().save_to_string(save_parents=True)
904 result = self.registry.get_registries(user_cred, hrn)
909 # ==================================================================
910 # Slice-related commands
911 # ==================================================================
913 def version(self, opts, args):
914 if opts.version_local:
915 version=version_core()
917 if opts.version_registry:
920 server = self.server_proxy_from_opts(opts)
921 result = server.GetVersion()
922 version = ReturnValue.get_value(result)
923 for (k,v) in version.iteritems():
924 print "%-20s: %s"%(k,v)
926 save_variable_to_file(version, opts.file, opts.fileformat)
928 # list instantiated slices
929 def slices(self, opts, args):
931 list instantiated slices
933 user_cred = self.get_user_cred().save_to_string(save_parents=True)
936 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
937 creds.append(delegated_cred)
938 server = self.server_proxy_from_opts(opts)
940 if self.server_supports_options_arg(server):
941 options = {'call_id': unique_call_id()}
942 call_args.append(options)
943 result = server.ListSlices(*call_args)
944 value = ReturnValue.get_value(result)
948 # show rspec for named slice
949 def resources(self, opts, args):
950 user_cred = self.get_user_cred().save_to_string(save_parents=True)
951 server = self.server_proxy_from_opts(opts)
953 options = {'call_id': unique_call_id()}
954 #panos add info options
956 options['info'] = opts.info
959 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
961 options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
967 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
968 creds.append(delegated_cred)
969 if opts.rspec_version:
970 version_manager = VersionManager()
971 server_version = self.get_cached_server_version(server)
972 if 'sfa' in server_version:
973 # just request the version the client wants
974 options['geni_rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
976 # this must be a protogeni aggregate. We should request a v2 ad rspec
977 # regardless of what the client user requested
978 options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
980 options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
982 call_args = [creds, options]
983 result = server.ListResources(*call_args)
984 value = ReturnValue.get_value(result)
985 if opts.file is None:
986 display_rspec(value, opts.format)
988 save_rspec_to_file(value, opts.file)
991 # created named slice with given rspec
992 def create(self, opts, args):
993 server = self.server_proxy_from_opts(opts)
994 server_version = self.get_cached_server_version(server)
996 slice_urn = hrn_to_urn(slice_hrn, 'slice')
997 user_cred = self.get_user_cred()
998 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1000 if hasattr(opts, 'aggregate') and opts.aggregate:
1001 delegated_cred = None
1003 # delegate the cred to the callers root authority
1004 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)+'.slicemanager')
1005 #delegated_cred = self.delegate_cred(slice_cred, get_authority(slice_hrn))
1006 #creds.append(delegated_cred)
1008 rspec_file = self.get_rspec_file(args[1])
1009 rspec = open(rspec_file).read()
1011 # need to pass along user keys to the aggregate.
1013 # { urn: urn:publicid:IDN+emulab.net+user+alice
1014 # keys: [<ssh key A>, <ssh key B>]
1017 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
1018 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
1019 slice_record = slice_records[0]
1020 user_hrns = slice_record['researcher']
1021 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
1022 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
1024 if 'sfa' not in server_version:
1025 users = pg_users_arg(user_records)
1026 rspec = RSpec(rspec)
1027 rspec.filter({'component_manager_id': server_version['urn']})
1028 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
1029 creds = [slice_cred]
1031 users = sfa_users_arg(user_records, slice_record)
1032 creds = [slice_cred]
1034 creds.append(delegated_cred)
1035 call_args = [slice_urn, creds, rspec, users]
1036 if self.server_supports_options_arg(server):
1037 options = {'call_id': unique_call_id()}
1038 call_args.append(options)
1039 result = server.CreateSliver(*call_args)
1040 value = ReturnValue.get_value(result)
1041 if opts.file is None:
1044 save_rspec_to_file (value, opts.file)
1047 # get a ticket for the specified slice
1048 def get_ticket(self, opts, args):
1049 slice_hrn, rspec_path = args[0], args[1]
1050 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1051 user_cred = self.get_user_cred()
1052 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1053 creds = [slice_cred]
1055 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1056 creds.append(delegated_cred)
1057 rspec_file = self.get_rspec_file(rspec_path)
1058 rspec = open(rspec_file).read()
1059 server = self.server_proxy_from_opts(opts)
1060 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1061 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1062 self.logger.info("writing ticket to %s"%file)
1063 ticket = SfaTicket(string=ticket_string)
1064 ticket.save_to_file(filename=file, save_parents=True)
1066 def redeem_ticket(self, opts, args):
1067 ticket_file = args[0]
1069 # get slice hrn from the ticket
1070 # use this to get the right slice credential
1071 ticket = SfaTicket(filename=ticket_file)
1073 slice_hrn = ticket.gidObject.get_hrn()
1074 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1075 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1076 user_cred = self.get_user_cred()
1077 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1079 # get a list of node hostnames from the RSpec
1080 tree = etree.parse(StringIO(ticket.rspec))
1081 root = tree.getroot()
1082 hostnames = root.xpath("./network/site/node/hostname/text()")
1084 # create an xmlrpc connection to the component manager at each of these
1085 # components and gall redeem_ticket
1087 for hostname in hostnames:
1089 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1090 server = self.server_proxy(hostname, CM_PORT, self.key_file, \
1091 self.cert_file, self.options.debug)
1092 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1093 self.logger.info("Success")
1094 except socket.gaierror:
1095 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1096 except Exception, e:
1097 self.logger.log_exc(e.message)
1100 # delete named slice
1101 def delete(self, opts, args):
1103 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1104 slice_cred = self.get_slice_cred(slice_hrn).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 server = self.server_proxy_from_opts(opts)
1110 call_args = [slice_urn, creds]
1111 if self.server_supports_options_arg(server):
1112 options = {'call_id': unique_call_id()}
1113 call_args.append(options)
1114 return server.DeleteSliver(*call_args)
1117 def start(self, opts, args):
1119 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1120 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1121 creds = [slice_cred]
1123 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1124 creds.append(delegated_cred)
1125 server = self.server_proxy_from_opts(opts)
1126 return server.Start(slice_urn, creds)
1129 def stop(self, opts, args):
1131 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1132 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1133 creds = [slice_cred]
1135 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1136 creds.append(delegated_cred)
1137 server = self.server_proxy_from_opts(opts)
1138 return server.Stop(slice_urn, creds)
1141 def reset(self, opts, args):
1143 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1144 server = self.server_proxy_from_opts(opts)
1145 slice_cred = self.get_slice_cred(args[0]).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 return server.reset_slice(creds, slice_urn)
1152 def renew(self, opts, args):
1154 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1155 server = self.server_proxy_from_opts(opts)
1156 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1157 creds = [slice_cred]
1159 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1160 creds.append(delegated_cred)
1163 call_args = [slice_urn, creds, time]
1164 if self.server_supports_options_arg(server):
1165 options = {'call_id': unique_call_id()}
1166 call_args.append(options)
1167 result = server.RenewSliver(*call_args)
1168 value = ReturnValue.get_value(result)
1172 def status(self, opts, args):
1174 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1175 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1176 creds = [slice_cred]
1178 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1179 creds.append(delegated_cred)
1180 server = self.server_proxy_from_opts(opts)
1181 call_args = [slice_urn, creds]
1182 if self.server_supports_options_arg(server):
1183 options = {'call_id': unique_call_id()}
1184 call_args.append(options)
1185 result = server.SliverStatus(*call_args)
1186 value = ReturnValue.get_value(result)
1189 save_variable_to_file(value, opts.file, opts.fileformat)
1192 def shutdown(self, opts, args):
1194 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1195 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1196 creds = [slice_cred]
1198 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1199 creds.append(delegated_cred)
1200 server = self.server_proxy_from_opts(opts)
1201 return server.Shutdown(slice_urn, creds)
1203 def print_help (self):
1204 self.sfi_parser.print_help()
1205 self.cmd_parser.print_help()
1208 # Main: parse arguments and dispatch to command
1211 self.sfi_parser = self.create_parser()
1212 (options, args) = self.sfi_parser.parse_args()
1213 self.options = options
1215 self.logger.setLevelFromOptVerbose(self.options.verbose)
1216 if options.hashrequest:
1217 self.hashrequest = True
1220 self.logger.critical("No command given. Use -h for help.")
1224 self.cmd_parser = self.create_cmd_parser(command)
1225 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1228 self.logger.info("Command=%s" % command)
1229 if command in ("resources"):
1230 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1231 elif command in ("list", "show", "remove"):
1232 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1233 self.logger.debug('cmd_args %s' % cmd_args)
1236 self.dispatch(command, cmd_opts, cmd_args)
1238 self.logger.critical ("Unknown command %s"%command)
1244 if __name__ == "__main__":