3 # sfi -- slice-based facility interface
13 from lxml import etree
14 from StringIO import StringIO
15 from optparse import OptionParser
16 from sfa.client.client_helper import pg_users_arg, sfa_users_arg
17 from sfa.util.sfalogging import sfi_logger
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
22 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
23 from sfa.rspecs.rspec import RSpec
24 from sfa.rspecs.rspec_converter import RSpecConverter
25 from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn
26 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
27 from sfa.util.config import Config
28 from sfa.util.version import version_core
29 from sfa.util.cache import Cache
30 from sfa.rspecs.version_manager import VersionManager
35 # utility methods here
37 def display_rspec(rspec, format='rspec'):
39 tree = etree.parse(StringIO(rspec))
41 result = root.xpath("./network/site/node/hostname/text()")
42 elif format in ['ip']:
43 # The IP address is not yet part of the new RSpec
44 # so this doesn't do anything yet.
45 tree = etree.parse(StringIO(rspec))
47 result = root.xpath("./network/site/node/ipv4/text()")
54 def display_list(results):
55 for result in results:
58 def display_records(recordList, dump=False):
59 ''' Print all fields in the record'''
60 for record in recordList:
61 display_record(record, dump)
63 def display_record(record, dump=False):
67 info = record.getdict()
68 print "%s (%s)" % (info['hrn'], info['type'])
72 def filter_records(type, records):
74 for record in records:
75 if (record['type'] == type) or (type == "all"):
76 filtered_records.append(record)
77 return filtered_records
81 def save_variable_to_file(var, filename, format="text"):
82 f = open(filename, "w")
85 elif format == "pickled":
86 f.write(pickle.dumps(var))
88 # this should never happen
89 print "unknown output format", format
92 def save_rspec_to_file(rspec, filename):
93 if not filename.endswith(".rspec"):
94 filename = filename + ".rspec"
95 f = open(filename, 'w')
100 def save_records_to_file(filename, recordList, format="xml"):
103 for record in recordList:
105 save_record_to_file(filename + "." + str(index), record)
107 save_record_to_file(filename, record)
109 elif format == "xmllist":
110 f = open(filename, "w")
111 f.write("<recordlist>\n")
112 for record in recordList:
113 record = SfaRecord(dict=record)
114 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
115 f.write("</recordlist>\n")
117 elif format == "hrnlist":
118 f = open(filename, "w")
119 for record in recordList:
120 record = SfaRecord(dict=record)
121 f.write(record.get_name() + "\n")
124 # this should never happen
125 print "unknown output format", format
127 def save_record_to_file(filename, record):
128 if record['type'] in ['user']:
129 record = UserRecord(dict=record)
130 elif record['type'] in ['slice']:
131 record = SliceRecord(dict=record)
132 elif record['type'] in ['node']:
133 record = NodeRecord(dict=record)
134 elif record['type'] in ['authority', 'ma', 'sa']:
135 record = AuthorityRecord(dict=record)
137 record = SfaRecord(dict=record)
138 str = record.save_to_string()
139 f=codecs.open(filename, encoding='utf-8',mode="w")
146 def load_record_from_file(filename):
147 f=codecs.open(filename, encoding="utf-8", mode="r")
150 record = SfaRecord(string=str)
155 def unique_call_id(): return uuid.uuid4().urn
159 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
161 # dummy to meet Sfi's expectations for its 'options' field
162 # i.e. s/t we can do setattr on
166 def __init__ (self,options=None):
167 if options is None: options=Sfi.DummyOptions()
168 for opt in Sfi.required_options:
169 if not hasattr(options,opt): setattr(options,opt,None)
170 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
171 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
172 # would be safer to remove self.sfi_dir altogether
173 self.sfi_dir = options.sfi_dir
174 self.options = options
178 self.authority = None
179 self.hashrequest = False
180 self.logger = sfi_logger
181 self.logger.enable_console()
183 def create_cmd_parser(self, command, additional_cmdargs=None):
184 cmdargs = {"list": "authority",
189 "aggregates": "[name]",
190 "registries": "[name]",
191 "create_gid": "[name]",
193 "get_trusted_certs": "cred",
195 "resources": "[name]",
196 "create": "name rspec",
197 "get_ticket": "name rspec",
198 "redeem_ticket": "ticket",
210 if additional_cmdargs:
211 cmdargs.update(additional_cmdargs)
213 if command not in cmdargs:
214 msg="Invalid command\n"
216 msg += ','.join(cmdargs.keys())
217 self.logger.critical(msg)
220 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
221 % (command, cmdargs[command]))
223 # user specifies remote aggregate/sm/component
224 if command in ("resources", "slices", "create", "delete", "start", "stop",
225 "restart", "shutdown", "get_ticket", "renew", "status"):
226 parser.add_option("-a", "--aggregate", dest="aggregate",
227 default=None, help="aggregate host")
228 parser.add_option("-p", "--port", dest="port",
229 default=AGGREGATE_PORT, help="aggregate port")
230 parser.add_option("-c", "--component", dest="component", default=None,
231 help="component hrn")
232 parser.add_option("-d", "--delegate", dest="delegate", default=None,
234 help="Include a credential delegated to the user's root"+\
235 "authority in set of credentials for this call")
237 # registy filter option
238 if command in ("list", "show", "remove"):
239 parser.add_option("-t", "--type", dest="type", type="choice",
240 help="type filter ([all]|user|slice|authority|node|aggregate)",
241 choices=("all", "user", "slice", "authority", "node", "aggregate"),
244 if command in ("resources"):
245 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
246 help="schema type and version of resulting RSpec")
247 parser.add_option("-f", "--format", dest="format", type="choice",
248 help="display format ([xml]|dns|ip)", default="xml",
249 choices=("xml", "dns", "ip"))
250 #panos: a new option to define the type of information about resources a user is interested in
251 parser.add_option("-i", "--info", dest="info",
252 help="optional component information", default=None)
255 # 'create' does return the new rspec, makes sense to save that too
256 if command in ("resources", "show", "list", "create_gid", 'create'):
257 parser.add_option("-o", "--output", dest="file",
258 help="output XML to file", metavar="FILE", default=None)
260 if command in ("show", "list"):
261 parser.add_option("-f", "--format", dest="format", type="choice",
262 help="display format ([text]|xml)", default="text",
263 choices=("text", "xml"))
265 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
266 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
267 choices=("xml", "xmllist", "hrnlist"))
269 if command in ("status", "version"):
270 parser.add_option("-o", "--output", dest="file",
271 help="output dictionary to file", metavar="FILE", default=None)
272 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
273 help="output file format ([text]|pickled)", default="text",
274 choices=("text","pickled"))
276 if command in ("delegate"):
277 parser.add_option("-u", "--user",
278 action="store_true", dest="delegate_user", default=False,
279 help="delegate user credential")
280 parser.add_option("-s", "--slice", dest="delegate_slice",
281 help="delegate slice credential", metavar="HRN", default=None)
283 if command in ("version"):
284 parser.add_option("-a", "--aggregate", dest="aggregate",
285 default=None, help="aggregate host")
286 parser.add_option("-p", "--port", dest="port",
287 default=AGGREGATE_PORT, help="aggregate port")
288 parser.add_option("-R","--registry-version",
289 action="store_true", dest="version_registry", default=False,
290 help="probe registry version instead of slicemgr")
291 parser.add_option("-l","--local",
292 action="store_true", dest="version_local", default=False,
293 help="display version of the local client")
298 def create_parser(self):
300 # Generate command line parser
301 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
302 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
303 parser.add_option("-r", "--registry", dest="registry",
304 help="root registry", metavar="URL", default=None)
305 parser.add_option("-s", "--slicemgr", dest="sm",
306 help="slice manager", metavar="URL", default=None)
307 default_sfi_dir = os.path.expanduser("~/.sfi/")
308 parser.add_option("-d", "--dir", dest="sfi_dir",
309 help="config & working directory - default is " + default_sfi_dir,
310 metavar="PATH", default=default_sfi_dir)
311 parser.add_option("-u", "--user", dest="user",
312 help="user name", metavar="HRN", default=None)
313 parser.add_option("-a", "--auth", dest="auth",
314 help="authority name", metavar="HRN", default=None)
315 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
316 help="verbose mode - cumulative")
317 parser.add_option("-D", "--debug",
318 action="store_true", dest="debug", default=False,
319 help="Debug (xml-rpc) protocol messages")
320 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
321 help="RPC protocol (xmlrpc or soap)")
322 parser.add_option("-k", "--hashrequest",
323 action="store_true", dest="hashrequest", default=False,
324 help="Create a hash of the request that will be authenticated on the server")
325 parser.add_option("-t", "--timeout", dest="timeout", default=None,
326 help="Amout of time tom wait before timing out the request")
327 parser.disable_interspersed_args()
332 def read_config(self):
333 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
335 config = Config (config_file)
337 self.logger.critical("Failed to read configuration file %s"%config_file)
338 self.logger.info("Make sure to remove the export clauses and to add quotes")
339 if self.options.verbose==0:
340 self.logger.info("Re-run with -v for more details")
342 self.logger.log_exc("Could not read config file %s"%config_file)
347 if (self.options.sm is not None):
348 self.sm_url = self.options.sm
349 elif hasattr(config, "SFI_SM"):
350 self.sm_url = config.SFI_SM
352 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
356 if (self.options.registry is not None):
357 self.reg_url = self.options.registry
358 elif hasattr(config, "SFI_REGISTRY"):
359 self.reg_url = config.SFI_REGISTRY
361 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
366 if (self.options.user is not None):
367 self.user = self.options.user
368 elif hasattr(config, "SFI_USER"):
369 self.user = config.SFI_USER
371 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
375 if (self.options.auth is not None):
376 self.authority = self.options.auth
377 elif hasattr(config, "SFI_AUTH"):
378 self.authority = config.SFI_AUTH
380 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
388 # Establish Connection to SliceMgr and Registry Servers
390 def set_servers(self):
393 # Get key and certificate
394 key_file = self.get_key_file()
395 cert_file = self.get_cert_file(key_file)
396 self.key = Keypair(filename=key_file)
397 self.key_file = key_file
398 self.cert_file = cert_file
399 self.cert = GID(filename=cert_file)
400 self.logger.info("Contacting Registry at: %s"%self.reg_url)
401 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
402 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
403 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
406 def get_cached_server_version(self, server):
407 # check local cache first
410 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
411 cache_key = server.url + "-version"
413 cache = Cache(cache_file)
416 self.logger.info("Local cache not found at: %s" % cache_file)
419 version = cache.get(cache_key)
422 version = server.GetVersion()
423 # cache version for 24 hours
424 cache.add(cache_key, version, ttl= 60*60*24)
425 self.logger.info("Updating cache file %s" % cache_file)
426 cache.save_to_file(cache_file)
432 def server_supports_call_id_arg(self, server):
434 Returns true if server support the optional call_id arg, false otherwise.
436 server_version = self.get_cached_server_version(server)
437 if 'sfa' in server_version and 'code_tag' in server_version:
438 code_tag = server_version['code_tag']
439 code_tag_parts = code_tag.split("-")
441 version_parts = code_tag_parts[0].split(".")
442 major, minor = version_parts[0], version_parts[1]
443 rev = code_tag_parts[1]
445 if int(minor) > 0 or int(rev) > 20:
450 # Get various credential and spec files
452 # Establishes limiting conventions
453 # - conflates MAs and SAs
454 # - assumes last token in slice name is unique
456 # Bootstraps credentials
457 # - bootstrap user credential from self-signed certificate
458 # - bootstrap authority credential from user credential
459 # - bootstrap slice credential from user credential
463 def get_key_file(self):
464 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
465 if (os.path.isfile(file)):
468 self.logger.error("Key file %s does not exist"%file)
472 def get_cert_file(self, key_file):
474 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
475 if (os.path.isfile(cert_file)):
476 # we'd perfer to use Registry issued certs instead of self signed certs.
477 # if this is a Registry cert (GID) then we are done
478 gid = GID(filename=cert_file)
482 # generate self signed certificate
483 k = Keypair(filename=key_file)
484 cert = Certificate(subject=self.user)
486 cert.set_issuer(k, self.user)
488 self.logger.info("Writing self-signed certificate to %s"%cert_file)
489 cert.save_to_file(cert_file)
491 # try to get registry issued cert
493 self.logger.info("Getting Registry issued cert")
495 # *hack. need to set registyr before _get_gid() is called
496 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
497 gid = self._get_gid(type='user')
499 self.logger.info("Writing certificate to %s"%cert_file)
500 gid.save_to_file(cert_file)
502 self.logger.info("Failed to download Registry issued cert")
506 def get_cached_gid(self, file):
511 if (os.path.isfile(file)):
512 gid = GID(filename=file)
516 def get_gid(self, opts, args):
518 Get the specify gid and save it to file
523 gid = self._get_gid(hrn)
524 self.logger.debug("Sfi.get_gid-> %s" % gid.save_to_string(save_parents=True))
527 def _get_gid(self, hrn=None, type=None):
529 git_gid helper. Retrive the gid from the registry and save it to file.
535 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
536 gid = self.get_cached_gid(gidfile)
538 user_cred = self.get_user_cred()
539 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
541 raise RecordNotFound(args[0])
546 if type == rec['type']:
549 raise RecordNotFound(args[0])
551 gid = GID(string=record['gid'])
552 self.logger.info("Writing gid to %s"%gidfile)
553 gid.save_to_file(filename=gidfile)
557 def get_cached_credential(self, file):
559 Return a cached credential only if it hasn't expired.
561 if (os.path.isfile(file)):
562 credential = Credential(filename=file)
563 # make sure it isnt expired
564 if not credential.get_expiration or \
565 datetime.datetime.today() < credential.get_expiration():
569 def get_user_cred(self):
570 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
571 return self.get_cred(file, 'user', self.user)
573 def get_auth_cred(self):
574 if not self.authority:
575 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
577 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
578 return self.get_cred(file, 'authority', self.authority)
580 def get_slice_cred(self, name):
581 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
582 return self.get_cred(file, 'slice', name)
584 def get_cred(self, file, type, hrn):
585 # attempt to load a cached credential
586 cred = self.get_cached_credential(file)
589 cert_string = self.cert.save_to_string(save_parents=True)
590 user_name = self.user.replace(self.authority + ".", '')
591 if user_name.count(".") > 0:
592 user_name = user_name.replace(".", '_')
593 self.user = self.authority + "." + user_name
594 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
596 # bootstrap slice credential from user credential
597 user_cred = self.get_user_cred().save_to_string(save_parents=True)
598 cred_str = self.registry.GetCredential(user_cred, hrn, type)
601 self.logger.critical("Failed to get %s credential" % type)
604 cred = Credential(string=cred_str)
605 cred.save_to_file(file, save_parents=True)
606 self.logger.info("Writing %s credential to %s" %(type, file))
611 def get_rspec_file(self, rspec):
612 if (os.path.isabs(rspec)):
615 file = os.path.join(self.options.sfi_dir, rspec)
616 if (os.path.isfile(file)):
619 self.logger.critical("No such rspec file %s"%rspec)
622 def get_record_file(self, record):
623 if (os.path.isabs(record)):
626 file = os.path.join(self.options.sfi_dir, record)
627 if (os.path.isfile(file)):
630 self.logger.critical("No such registry record file %s"%record)
633 def load_publickey_string(self, fn):
635 key_string = f.read()
637 # if the filename is a private key file, then extract the public key
638 if "PRIVATE KEY" in key_string:
639 outfn = tempfile.mktemp()
640 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
643 key_string = f.read()
649 def get_component_server_from_hrn(self, hrn):
650 # direct connection to the nodes component manager interface
651 user_cred = self.get_user_cred().save_to_string(save_parents=True)
652 records = self.registry.Resolve(hrn, user_cred)
653 records = filter_records('node', records)
655 self.logger.warning("No such component:%r"% opts.component)
658 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
660 def get_server(self, host, port, keyfile, certfile):
662 Return an instance of an xmlrpc server connection
664 # port is appended onto the domain, before the path. Should look like:
665 # http://domain:port/path
666 host_parts = host.split('/')
667 host_parts[0] = host_parts[0] + ":" + str(port)
668 url = "http://%s" % "/".join(host_parts)
669 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
671 # xxx opts could be retrieved in self.options
672 def get_server_from_opts(self, opts):
674 Return instance of an xmlrpc connection to a slice manager, aggregate
675 or component server depending on the specified opts
677 server = self.slicemgr
678 # direct connection to an aggregate
679 if hasattr(opts, 'aggregate') and opts.aggregate:
680 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
681 # direct connection to the nodes component manager interface
682 if hasattr(opts, 'component') and opts.component:
683 server = self.get_component_server_from_hrn(opts.component)
686 #==========================================================================
687 # Following functions implement the commands
689 # Registry-related commands
690 #==========================================================================
692 def dispatch(self, command, cmd_opts, cmd_args):
693 return getattr(self, command)(cmd_opts, cmd_args)
695 def create_gid(self, opts, args):
700 user_cred = self.get_user_cred().save_to_string(save_parents=True)
701 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
705 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
706 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
707 GID(string=gid).save_to_file(filename)
710 # list entires in named authority registry
711 def list(self, opts, args):
716 user_cred = self.get_user_cred().save_to_string(save_parents=True)
718 list = self.registry.List(hrn, user_cred)
720 raise Exception, "Not enough parameters for the 'list' command"
722 # filter on person, slice, site, node, etc.
723 # THis really should be in the self.filter_records funct def comment...
724 list = filter_records(opts.type, list)
726 print "%s (%s)" % (record['hrn'], record['type'])
728 save_records_to_file(opts.file, list, opts.fileformat)
731 # show named registry record
732 def show(self, opts, args):
737 user_cred = self.get_user_cred().save_to_string(save_parents=True)
738 records = self.registry.Resolve(hrn, user_cred)
739 records = filter_records(opts.type, records)
741 print "No record of type", opts.type
742 for record in records:
743 if record['type'] in ['user']:
744 record = UserRecord(dict=record)
745 elif record['type'] in ['slice']:
746 record = SliceRecord(dict=record)
747 elif record['type'] in ['node']:
748 record = NodeRecord(dict=record)
749 elif record['type'].startswith('authority'):
750 record = AuthorityRecord(dict=record)
752 record = SfaRecord(dict=record)
753 if (opts.format == "text"):
756 print record.save_to_string()
758 save_records_to_file(opts.file, records, opts.fileformat)
761 def delegate(self, opts, args):
763 delegee_hrn = args[0]
764 if opts.delegate_user:
765 user_cred = self.get_user_cred()
766 cred = self.delegate_cred(user_cred, delegee_hrn)
767 elif opts.delegate_slice:
768 slice_cred = self.get_slice_cred(opts.delegate_slice)
769 cred = self.delegate_cred(slice_cred, delegee_hrn)
771 self.logger.warning("Must specify either --user or --slice <hrn>")
773 delegated_cred = Credential(string=cred)
774 object_hrn = delegated_cred.get_gid_object().get_hrn()
775 if opts.delegate_user:
776 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
777 + get_leaf(object_hrn) + ".cred")
778 elif opts.delegate_slice:
779 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
780 + get_leaf(object_hrn) + ".cred")
782 delegated_cred.save_to_file(dest_fn, save_parents=True)
784 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
786 def delegate_cred(self, object_cred, hrn):
787 # the gid and hrn of the object we are delegating
788 if isinstance(object_cred, str):
789 object_cred = Credential(string=object_cred)
790 object_gid = object_cred.get_gid_object()
791 object_hrn = object_gid.get_hrn()
793 if not object_cred.get_privileges().get_all_delegate():
794 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
797 # the delegating user's gid
798 caller_gid = self._get_gid(self.user)
799 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
801 # the gid of the user who will be delegated to
802 delegee_gid = self._get_gid(hrn)
803 delegee_hrn = delegee_gid.get_hrn()
804 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
805 delegee_gid.save_to_file(filename=delegee_gidfile)
806 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
807 return dcred.save_to_string(save_parents=True)
809 # removed named registry record
810 # - have to first retrieve the record to be removed
811 def remove(self, opts, args):
812 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
820 return self.registry.Remove(hrn, auth_cred, type)
822 # add named registry record
823 def add(self, opts, args):
824 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
828 record_filepath = args[0]
829 rec_file = self.get_record_file(record_filepath)
830 record = load_record_from_file(rec_file).as_dict()
831 return self.registry.Register(record, auth_cred)
833 # update named registry entry
834 def update(self, opts, args):
835 user_cred = self.get_user_cred()
839 rec_file = self.get_record_file(args[0])
840 record = load_record_from_file(rec_file)
841 if record['type'] == "user":
842 if record.get_name() == user_cred.get_gid_object().get_hrn():
843 cred = user_cred.save_to_string(save_parents=True)
845 cred = self.get_auth_cred().save_to_string(save_parents=True)
846 elif record['type'] in ["slice"]:
848 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
849 except xmlrpcprotocol.ServerException, e:
850 # XXX smbaker -- once we have better error return codes, update this
851 # to do something better than a string compare
852 if "Permission error" in e.args[0]:
853 cred = self.get_auth_cred().save_to_string(save_parents=True)
856 elif record.get_type() in ["authority"]:
857 cred = self.get_auth_cred().save_to_string(save_parents=True)
858 elif record.get_type() == 'node':
859 cred = self.get_auth_cred().save_to_string(save_parents=True)
861 raise "unknown record type" + record.get_type()
862 record = record.as_dict()
863 return self.registry.Update(record, cred)
865 def get_trusted_certs(self, opts, args):
867 return uhe trusted certs at this interface
869 trusted_certs = self.registry.get_trusted_certs()
870 for trusted_cert in trusted_certs:
871 gid = GID(string=trusted_cert)
873 cert = Certificate(string=trusted_cert)
874 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
877 def aggregates(self, opts, args):
879 return a list of details about known aggregates
881 user_cred = self.get_user_cred().save_to_string(save_parents=True)
886 result = self.registry.get_aggregates(user_cred, hrn)
890 def registries(self, opts, args):
892 return a list of details about known registries
894 user_cred = self.get_user_cred().save_to_string(save_parents=True)
898 result = self.registry.get_registries(user_cred, hrn)
903 # ==================================================================
904 # Slice-related commands
905 # ==================================================================
907 def version(self, opts, args):
908 if opts.version_local:
909 version=version_core()
911 if opts.version_registry:
914 server = self.get_server_from_opts(opts)
915 version=server.GetVersion()
916 for (k,v) in version.iteritems():
917 print "%-20s: %s"%(k,v)
919 save_variable_to_file(version, opts.file, opts.fileformat)
921 # list instantiated slices
922 def slices(self, opts, args):
924 list instantiated slices
926 user_cred = self.get_user_cred().save_to_string(save_parents=True)
929 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
930 creds.append(delegated_cred)
931 server = self.get_server_from_opts(opts)
932 #results = server.ListSlices(creds, unique_call_id())
933 results = server.ListSlices(creds)
934 display_list(results)
937 # show rspec for named slice
938 def resources(self, opts, args):
939 user_cred = self.get_user_cred().save_to_string(save_parents=True)
940 server = self.slicemgr
942 server = self.get_server_from_opts(opts)
945 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
947 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
954 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
955 creds.append(delegated_cred)
956 if opts.rspec_version:
957 version_manager = VersionManager()
958 server_version = self.get_cached_server_version(server)
959 if 'sfa' in server_version:
960 # just request the version the client wants
961 call_options['rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
963 # this must be a protogeni aggregate. We should request a v2 ad rspec
964 # regardless of what the client user requested
965 call_options['rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
966 #panos add info options
968 call_options['info'] = opts.info
970 call_args = [creds, call_options]
971 if self.server_supports_call_id_arg(server):
972 call_args.append(unique_call_id())
973 result = server.ListResources(*call_args)
974 if opts.file is None:
975 display_rspec(result, opts.format)
977 save_rspec_to_file(result, opts.file)
980 # created named slice with given rspec
981 def create(self, opts, args):
982 server = self.get_server_from_opts(opts)
983 server_version = self.get_cached_server_version(server)
985 slice_urn = hrn_to_urn(slice_hrn, 'slice')
986 user_cred = self.get_user_cred()
987 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
989 if hasattr(opts, 'aggregate') and opts.aggregate:
990 delegated_cred = None
992 # delegate the cred to the callers root authority
993 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)+'.slicemanager')
994 #delegated_cred = self.delegate_cred(slice_cred, get_authority(slice_hrn))
995 #creds.append(delegated_cred)
997 rspec_file = self.get_rspec_file(args[1])
998 rspec = open(rspec_file).read()
1000 # need to pass along user keys to the aggregate.
1002 # { urn: urn:publicid:IDN+emulab.net+user+alice
1003 # keys: [<ssh key A>, <ssh key B>]
1006 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
1007 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
1008 slice_record = slice_records[0]
1009 user_hrns = slice_record['researcher']
1010 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
1011 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
1013 if 'sfa' not in server_version:
1014 users = pg_users_arg(user_records)
1015 rspec = RSpec(rspec)
1016 rspec.filter({'component_manager_id': server_version['urn']})
1017 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
1018 creds = [slice_cred]
1020 users = sfa_users_arg(user_records, slice_record)
1021 creds = [slice_cred]
1023 creds.append(delegated_cred)
1024 call_args = [slice_urn, creds, rspec, users]
1025 if self.server_supports_call_id_arg(server):
1026 call_args.append(unique_call_id())
1028 result = server.CreateSliver(*call_args)
1029 if opts.file is None:
1032 save_rspec_to_file (result, opts.file)
1035 # get a ticket for the specified slice
1036 def get_ticket(self, opts, args):
1037 slice_hrn, rspec_path = args[0], args[1]
1038 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1039 user_cred = self.get_user_cred()
1040 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1041 creds = [slice_cred]
1043 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1044 creds.append(delegated_cred)
1045 rspec_file = self.get_rspec_file(rspec_path)
1046 rspec = open(rspec_file).read()
1047 server = self.get_server_from_opts(opts)
1048 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1049 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1050 self.logger.info("writing ticket to %s"%file)
1051 ticket = SfaTicket(string=ticket_string)
1052 ticket.save_to_file(filename=file, save_parents=True)
1054 def redeem_ticket(self, opts, args):
1055 ticket_file = args[0]
1057 # get slice hrn from the ticket
1058 # use this to get the right slice credential
1059 ticket = SfaTicket(filename=ticket_file)
1061 slice_hrn = ticket.gidObject.get_hrn()
1062 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1063 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1064 user_cred = self.get_user_cred()
1065 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1067 # get a list of node hostnames from the RSpec
1068 tree = etree.parse(StringIO(ticket.rspec))
1069 root = tree.getroot()
1070 hostnames = root.xpath("./network/site/node/hostname/text()")
1072 # create an xmlrpc connection to the component manager at each of these
1073 # components and gall redeem_ticket
1075 for hostname in hostnames:
1077 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1078 server = self.get_server(hostname, CM_PORT, self.key_file, \
1079 self.cert_file, self.options.debug)
1080 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1081 self.logger.info("Success")
1082 except socket.gaierror:
1083 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1084 except Exception, e:
1085 self.logger.log_exc(e.message)
1088 # delete named slice
1089 def delete(self, opts, args):
1091 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1092 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1093 creds = [slice_cred]
1095 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1096 creds.append(delegated_cred)
1097 server = self.get_server_from_opts(opts)
1099 call_args = [slice_urn, creds]
1100 if self.server_supports_call_id_arg(server):
1101 call_args.append(unique_call_id())
1102 return server.DeleteSliver(*call_args)
1105 def start(self, opts, args):
1107 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1108 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1109 creds = [slice_cred]
1111 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1112 creds.append(delegated_cred)
1113 server = self.get_server_from_opts(opts)
1114 return server.Start(slice_urn, creds)
1117 def stop(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.get_server_from_opts(opts)
1126 return server.Stop(slice_urn, creds)
1129 def reset(self, opts, args):
1131 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1132 server = self.get_server_from_opts(opts)
1133 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1134 creds = [slice_cred]
1136 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1137 creds.append(delegated_cred)
1138 return server.reset_slice(creds, slice_urn)
1140 def renew(self, opts, args):
1142 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1143 server = self.get_server_from_opts(opts)
1144 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1145 creds = [slice_cred]
1147 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1148 creds.append(delegated_cred)
1151 call_args = [slice_urn, creds, time]
1152 if self.server_supports_call_id_arg(server):
1153 call_args.append(unique_call_id())
1154 return server.RenewSliver(*call_args)
1157 def status(self, opts, args):
1159 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1160 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1161 creds = [slice_cred]
1163 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1164 creds.append(delegated_cred)
1165 server = self.get_server_from_opts(opts)
1166 call_args = [slice_urn, creds]
1167 if self.server_supports_call_id_arg(server):
1168 call_args.append(unique_call_id())
1169 result = server.SliverStatus(*call_args)
1172 save_variable_to_file(result, opts.file, opts.fileformat)
1175 def shutdown(self, opts, args):
1177 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1178 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1179 creds = [slice_cred]
1181 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1182 creds.append(delegated_cred)
1183 server = self.get_server_from_opts(opts)
1184 return server.Shutdown(slice_urn, creds)
1186 def print_help (self):
1187 self.sfi_parser.print_help()
1188 self.cmd_parser.print_help()
1191 # Main: parse arguments and dispatch to command
1194 self.sfi_parser = self.create_parser()
1195 (options, args) = self.sfi_parser.parse_args()
1196 self.options = options
1198 self.logger.setLevelFromOptVerbose(self.options.verbose)
1199 if options.hashrequest:
1200 self.hashrequest = True
1203 self.logger.critical("No command given. Use -h for help.")
1207 self.cmd_parser = self.create_cmd_parser(command)
1208 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1211 self.logger.info("Command=%s" % command)
1212 if command in ("resources"):
1213 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1214 elif command in ("list", "show", "remove"):
1215 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1216 self.logger.debug('cmd_args %s' % cmd_args)
1219 self.dispatch(command, cmd_opts, cmd_args)
1221 self.logger.critical ("Unknown command %s"%command)
1227 if __name__ == "__main__":