3 # sfi -- slice-based facility interface
15 from lxml import etree
16 from StringIO import StringIO
17 from types import StringTypes, ListType
18 from optparse import OptionParser
20 from sfa.util.sfalogging import sfi_logger
21 from sfa.trust.certificate import Keypair, Certificate
22 from sfa.trust.gid import GID
23 from sfa.trust.credential import Credential
24 from sfa.util.sfaticket import SfaTicket
25 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
26 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
27 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
28 from sfa.util.config import Config
29 from sfa.util.version import version_core
30 from sfa.util.cache import Cache
31 from sfa.rspecs.rspec_version import RSpecVersion
32 from sfa.rspecs.pg_rspec import pg_rspec_request_version
37 # utility methods here
39 def display_rspec(rspec, format='rspec'):
41 tree = etree.parse(StringIO(rspec))
43 result = root.xpath("./network/site/node/hostname/text()")
44 elif format in ['ip']:
45 # The IP address is not yet part of the new RSpec
46 # so this doesn't do anything yet.
47 tree = etree.parse(StringIO(rspec))
49 result = root.xpath("./network/site/node/ipv4/text()")
56 def display_list(results):
57 for result in results:
60 def display_records(recordList, dump=False):
61 ''' Print all fields in the record'''
62 for record in recordList:
63 display_record(record, dump)
65 def display_record(record, dump=False):
69 info = record.getdict()
70 print "%s (%s)" % (info['hrn'], info['type'])
74 def filter_records(type, records):
76 for record in records:
77 if (record['type'] == type) or (type == "all"):
78 filtered_records.append(record)
79 return filtered_records
83 def save_rspec_to_file(rspec, filename):
84 if not filename.endswith(".rspec"):
85 filename = filename + ".rspec"
86 f = open(filename, 'w')
91 def save_records_to_file(filename, recordList, format="xml"):
94 for record in recordList:
96 save_record_to_file(filename + "." + str(index), record)
98 save_record_to_file(filename, record)
100 elif format == "xmllist":
101 f = open(filename, "w")
102 f.write("<recordlist>\n")
103 for record in recordList:
104 record = SfaRecord(dict=record)
105 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
106 f.write("</recordlist>\n");
108 elif format == "hrnlist":
109 f = open(filename, "w")
110 for record in recordList:
111 record = SfaRecord(dict=record)
112 f.write(record.get_name() + "\n")
115 # this should never happen
116 print "unknown output format", format
118 def save_record_to_file(filename, record):
119 if record['type'] in ['user']:
120 record = UserRecord(dict=record)
121 elif record['type'] in ['slice']:
122 record = SliceRecord(dict=record)
123 elif record['type'] in ['node']:
124 record = NodeRecord(dict=record)
125 elif record['type'] in ['authority', 'ma', 'sa']:
126 record = AuthorityRecord(dict=record)
128 record = SfaRecord(dict=record)
129 str = record.save_to_string()
130 f=codecs.open(filename, encoding='utf-8',mode="w")
137 def load_record_from_file(filename):
138 f=codecs.open(filename, encoding="utf-8", mode="r")
141 record = SfaRecord(string=str)
146 def unique_call_id(): return uuid.uuid4().urn
150 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
152 # dummy to meet Sfi's expectations for its 'options' field
153 # i.e. s/t we can do setattr on
157 def __init__ (self,options=None):
158 if options is None: options=Sfi.DummyOptions()
159 for opt in Sfi.required_options:
160 if not hasattr(options,opt): setattr(options,opt,None)
161 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
162 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
163 # would be safer to remove self.sfi_dir altogether
164 self.sfi_dir = options.sfi_dir
165 self.options = options
169 self.authority = None
170 self.hashrequest = False
171 self.logger = sfi_logger
172 self.logger.enable_console()
174 def create_cmd_parser(self, command, additional_cmdargs=None):
175 cmdargs = {"list": "authority",
180 "aggregates": "[name]",
181 "registries": "[name]",
182 "create_gid": "[name]",
184 "get_trusted_certs": "cred",
186 "resources": "[name]",
187 "create": "name rspec",
188 "get_ticket": "name rspec",
189 "redeem_ticket": "ticket",
201 if additional_cmdargs:
202 cmdargs.update(additional_cmdargs)
204 if command not in cmdargs:
205 msg="Invalid command\n"
207 msg += ','.join(cmdargs.keys())
208 self.logger.critical(msg)
211 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
212 % (command, cmdargs[command]))
214 # user specifies remote aggregate/sm/component
215 if command in ("resources", "slices", "create", "delete", "start", "stop",
216 "restart", "shutdown", "get_ticket", "renew", "status"):
217 parser.add_option("-a", "--aggregate", dest="aggregate",
218 default=None, help="aggregate host")
219 parser.add_option("-p", "--port", dest="port",
220 default=AGGREGATE_PORT, help="aggregate port")
221 parser.add_option("-c", "--component", dest="component", default=None,
222 help="component hrn")
223 parser.add_option("-d", "--delegate", dest="delegate", default=None,
225 help="Include a credential delegated to the user's root"+\
226 "authority in set of credentials for this call")
228 # registy filter option
229 if command in ("list", "show", "remove"):
230 parser.add_option("-t", "--type", dest="type", type="choice",
231 help="type filter ([all]|user|slice|authority|node|aggregate)",
232 choices=("all", "user", "slice", "authority", "node", "aggregate"),
235 if command in ("resources"):
236 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
237 help="schema type and version of resulting RSpec")
238 parser.add_option("-f", "--format", dest="format", type="choice",
239 help="display format ([xml]|dns|ip)", default="xml",
240 choices=("xml", "dns", "ip"))
241 #panos: a new option to define the type of information about resources a user is interested in
242 parser.add_option("-i", "--info", dest="info",
243 help="optional component information", default=None)
246 # 'create' does return the new rspec, makes sense to save that too
247 if command in ("resources", "show", "list", "create_gid", 'create'):
248 parser.add_option("-o", "--output", dest="file",
249 help="output XML to file", metavar="FILE", default=None)
251 if command in ("show", "list"):
252 parser.add_option("-f", "--format", dest="format", type="choice",
253 help="display format ([text]|xml)", default="text",
254 choices=("text", "xml"))
256 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
257 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
258 choices=("xml", "xmllist", "hrnlist"))
260 if command in ("delegate"):
261 parser.add_option("-u", "--user",
262 action="store_true", dest="delegate_user", default=False,
263 help="delegate user credential")
264 parser.add_option("-s", "--slice", dest="delegate_slice",
265 help="delegate slice credential", metavar="HRN", default=None)
267 if command in ("version"):
268 parser.add_option("-a", "--aggregate", dest="aggregate",
269 default=None, help="aggregate host")
270 parser.add_option("-p", "--port", dest="port",
271 default=AGGREGATE_PORT, help="aggregate port")
272 parser.add_option("-R","--registry-version",
273 action="store_true", dest="version_registry", default=False,
274 help="probe registry version instead of slicemgr")
275 parser.add_option("-l","--local",
276 action="store_true", dest="version_local", default=False,
277 help="display version of the local client")
282 def create_parser(self):
284 # Generate command line parser
285 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
286 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
287 parser.add_option("-r", "--registry", dest="registry",
288 help="root registry", metavar="URL", default=None)
289 parser.add_option("-s", "--slicemgr", dest="sm",
290 help="slice manager", metavar="URL", default=None)
291 default_sfi_dir = os.path.expanduser("~/.sfi/")
292 parser.add_option("-d", "--dir", dest="sfi_dir",
293 help="config & working directory - default is " + default_sfi_dir,
294 metavar="PATH", default=default_sfi_dir)
295 parser.add_option("-u", "--user", dest="user",
296 help="user name", metavar="HRN", default=None)
297 parser.add_option("-a", "--auth", dest="auth",
298 help="authority name", metavar="HRN", default=None)
299 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
300 help="verbose mode - cumulative")
301 parser.add_option("-D", "--debug",
302 action="store_true", dest="debug", default=False,
303 help="Debug (xml-rpc) protocol messages")
304 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
305 help="RPC protocol (xmlrpc or soap)")
306 parser.add_option("-k", "--hashrequest",
307 action="store_true", dest="hashrequest", default=False,
308 help="Create a hash of the request that will be authenticated on the server")
309 parser.add_option("-t", "--timeout", dest="timeout", default=None,
310 help="Amout of time tom wait before timing out the request")
311 parser.disable_interspersed_args()
316 def read_config(self):
317 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
319 config = Config (config_file)
321 self.logger.critical("Failed to read configuration file %s"%config_file)
322 self.logger.info("Make sure to remove the export clauses and to add quotes")
323 if self.options.verbose==0:
324 self.logger.info("Re-run with -v for more details")
326 self.logger.log_exc("Could not read config file %s"%config_file)
331 if (self.options.sm is not None):
332 self.sm_url = self.options.sm
333 elif hasattr(config, "SFI_SM"):
334 self.sm_url = config.SFI_SM
336 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
340 if (self.options.registry is not None):
341 self.reg_url = self.options.registry
342 elif hasattr(config, "SFI_REGISTRY"):
343 self.reg_url = config.SFI_REGISTRY
345 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
350 if (self.options.user is not None):
351 self.user = self.options.user
352 elif hasattr(config, "SFI_USER"):
353 self.user = config.SFI_USER
355 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
359 if (self.options.auth is not None):
360 self.authority = self.options.auth
361 elif hasattr(config, "SFI_AUTH"):
362 self.authority = config.SFI_AUTH
364 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
372 # Establish Connection to SliceMgr and Registry Servers
374 def set_servers(self):
377 # Get key and certificate
378 key_file = self.get_key_file()
379 cert_file = self.get_cert_file(key_file)
380 self.key = Keypair(filename=key_file)
381 self.key_file = key_file
382 self.cert_file = cert_file
383 self.cert = GID(filename=cert_file)
384 self.logger.info("Contacting Registry at: %s"%self.reg_url)
385 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
386 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
387 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
390 def get_cached_server_version(self, server):
391 # check local cache first
394 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
395 cache_key = server.url + "-version"
397 cache = Cache(cache_file)
400 self.logger.info("Local cache not found at: %s" % cache_file)
403 version = cache.get(cache_key)
406 version = server.GetVersion()
407 # cache version for 24 hours
408 cache.add(cache_key, version, ttl= 60*60*24)
409 self.logger.info("Updating cache file %s" % cache_file)
410 cache.save_to_file(cache_file)
416 def server_supports_call_id_arg(self, server):
418 Returns true if server support the optional call_id arg, false otherwise.
420 server_version = self.get_cached_server_version(server)
421 if 'sfa' in server_version:
422 code_tag = server_version['code_tag']
423 code_tag_parts = code_tag.split("-")
425 version_parts = code_tag_parts[0].split(".")
426 major, minor = version_parts[0], version_parts[1]
427 rev = code_tag_parts[1]
429 if int(minor) > 0 or int(rev) > 20:
434 # Get various credential and spec files
436 # Establishes limiting conventions
437 # - conflates MAs and SAs
438 # - assumes last token in slice name is unique
440 # Bootstraps credentials
441 # - bootstrap user credential from self-signed certificate
442 # - bootstrap authority credential from user credential
443 # - bootstrap slice credential from user credential
447 def get_key_file(self):
448 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
449 if (os.path.isfile(file)):
452 self.logger.error("Key file %s does not exist"%file)
456 def get_cert_file(self, key_file):
458 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
459 if (os.path.isfile(cert_file)):
460 # we'd perfer to use Registry issued certs instead of self signed certs.
461 # if this is a Registry cert (GID) then we are done
462 gid = GID(filename=cert_file)
466 # generate self signed certificate
467 k = Keypair(filename=key_file)
468 cert = Certificate(subject=self.user)
470 cert.set_issuer(k, self.user)
472 self.logger.info("Writing self-signed certificate to %s"%cert_file)
473 cert.save_to_file(cert_file)
475 # try to get registry issued cert
477 self.logger.info("Getting Registry issued cert")
479 # *hack. need to set registyr before _get_gid() is called
480 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
481 gid = self._get_gid(type='user')
483 self.logger.info("Writing certificate to %s"%cert_file)
484 gid.save_to_file(cert_file)
486 self.logger.info("Failed to download Registry issued cert")
490 def get_cached_gid(self, file):
495 if (os.path.isfile(file)):
496 gid = GID(filename=file)
500 def get_gid(self, opts, args):
502 Get the specify gid and save it to file
507 gid = self._get_gid(hrn)
508 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
511 def _get_gid(self, hrn=None, type=None):
513 git_gid helper. Retrive the gid from the registry and save it to file.
519 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
521 gid = self.get_cached_gid(gidfile)
523 user_cred = self.get_user_cred()
524 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
526 raise RecordNotFound(args[0])
531 if type == rec['type']:
534 raise RecordNotFound(args[0])
536 gid = GID(string=record['gid'])
537 self.logger.info("Writing gid to %s"%gidfile)
538 gid.save_to_file(filename=gidfile)
542 def get_cached_credential(self, file):
544 Return a cached credential only if it hasn't expired.
546 if (os.path.isfile(file)):
547 credential = Credential(filename=file)
548 # make sure it isnt expired
549 if not credential.get_expiration or \
550 datetime.datetime.today() < credential.get_expiration():
554 def get_user_cred(self):
555 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
556 return self.get_cred(file, 'user', self.user)
558 def get_auth_cred(self):
559 if not self.authority:
560 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
562 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
563 return self.get_cred(file, 'authority', self.authority)
565 def get_slice_cred(self, name):
566 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
567 return self.get_cred(file, 'slice', name)
569 def get_cred(self, file, type, hrn):
570 # attempt to load a cached credential
571 cred = self.get_cached_credential(file)
574 cert_string = self.cert.save_to_string(save_parents=True)
575 user_name = self.user.replace(self.authority + ".", '')
576 if user_name.count(".") > 0:
577 user_name = user_name.replace(".", '_')
578 self.user = self.authority + "." + user_name
579 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
581 # bootstrap slice credential from user credential
582 user_cred = self.get_user_cred().save_to_string(save_parents=True)
583 cred_str = self.registry.GetCredential(user_cred, hrn, type)
586 self.logger.critical("Failed to get %s credential" % type)
589 cred = Credential(string=cred_str)
590 cred.save_to_file(file, save_parents=True)
591 self.logger.info("Writing %s credential to %s" %(type, file))
596 def get_rspec_file(self, rspec):
597 if (os.path.isabs(rspec)):
600 file = os.path.join(self.options.sfi_dir, rspec)
601 if (os.path.isfile(file)):
604 self.logger.critical("No such rspec file %s"%rspec)
607 def get_record_file(self, record):
608 if (os.path.isabs(record)):
611 file = os.path.join(self.options.sfi_dir, record)
612 if (os.path.isfile(file)):
615 self.logger.critical("No such registry record file %s"%record)
618 def load_publickey_string(self, fn):
620 key_string = f.read()
622 # if the filename is a private key file, then extract the public key
623 if "PRIVATE KEY" in key_string:
624 outfn = tempfile.mktemp()
625 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
628 key_string = f.read()
634 def get_component_server_from_hrn(self, hrn):
635 # direct connection to the nodes component manager interface
636 user_cred = self.get_user_cred().save_to_string(save_parents=True)
637 records = self.registry.Resolve(hrn, user_cred)
638 records = filter_records('node', records)
640 self.logger.warning("No such component:%r"% opts.component)
643 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
645 def get_server(self, host, port, keyfile, certfile):
647 Return an instance of an xmlrpc server connection
649 # port is appended onto the domain, before the path. Should look like:
650 # http://domain:port/path
651 host_parts = host.split('/')
652 host_parts[0] = host_parts[0] + ":" + str(port)
653 url = "http://%s" % "/".join(host_parts)
654 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
656 # xxx opts could be retrieved in self.options
657 def get_server_from_opts(self, opts):
659 Return instance of an xmlrpc connection to a slice manager, aggregate
660 or component server depending on the specified opts
662 server = self.slicemgr
663 # direct connection to an aggregate
664 if hasattr(opts, 'aggregate') and opts.aggregate:
665 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
666 # direct connection to the nodes component manager interface
667 if hasattr(opts, 'component') and opts.component:
668 server = self.get_component_server_from_hrn(opts.component)
671 #==========================================================================
672 # Following functions implement the commands
674 # Registry-related commands
675 #==========================================================================
677 def dispatch(self, command, cmd_opts, cmd_args):
678 return getattr(self, command)(cmd_opts, cmd_args)
680 def create_gid(self, opts, args):
685 user_cred = self.get_user_cred().save_to_string(save_parents=True)
686 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
690 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
691 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
692 GID(string=gid).save_to_file(filename)
695 # list entires in named authority registry
696 def list(self, opts, args):
701 user_cred = self.get_user_cred().save_to_string(save_parents=True)
703 list = self.registry.List(hrn, user_cred)
705 raise Exception, "Not enough parameters for the 'list' command"
707 # filter on person, slice, site, node, etc.
708 # THis really should be in the self.filter_records funct def comment...
709 list = filter_records(opts.type, list)
711 print "%s (%s)" % (record['hrn'], record['type'])
713 save_records_to_file(opts.file, list, opts.fileformat)
716 # show named registry record
717 def show(self, opts, args):
722 user_cred = self.get_user_cred().save_to_string(save_parents=True)
723 records = self.registry.Resolve(hrn, user_cred)
724 records = filter_records(opts.type, records)
726 print "No record of type", opts.type
727 for record in records:
728 if record['type'] in ['user']:
729 record = UserRecord(dict=record)
730 elif record['type'] in ['slice']:
731 record = SliceRecord(dict=record)
732 elif record['type'] in ['node']:
733 record = NodeRecord(dict=record)
734 elif record['type'].startswith('authority'):
735 record = AuthorityRecord(dict=record)
737 record = SfaRecord(dict=record)
738 if (opts.format == "text"):
741 print record.save_to_string()
743 save_records_to_file(opts.file, records, opts.fileformat)
746 def delegate(self, opts, args):
748 delegee_hrn = args[0]
749 if opts.delegate_user:
750 user_cred = self.get_user_cred()
751 cred = self.delegate_cred(user_cred, delegee_hrn)
752 elif opts.delegate_slice:
753 slice_cred = self.get_slice_cred(opts.delegate_slice)
754 cred = self.delegate_cred(slice_cred, delegee_hrn)
756 self.logger.warning("Must specify either --user or --slice <hrn>")
758 delegated_cred = Credential(string=cred)
759 object_hrn = delegated_cred.get_gid_object().get_hrn()
760 if opts.delegate_user:
761 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
762 + get_leaf(object_hrn) + ".cred")
763 elif opts.delegate_slice:
764 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
765 + get_leaf(object_hrn) + ".cred")
767 delegated_cred.save_to_file(dest_fn, save_parents=True)
769 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
771 def delegate_cred(self, object_cred, hrn):
772 # the gid and hrn of the object we are delegating
773 if isinstance(object_cred, str):
774 object_cred = Credential(string=object_cred)
775 object_gid = object_cred.get_gid_object()
776 object_hrn = object_gid.get_hrn()
778 if not object_cred.get_privileges().get_all_delegate():
779 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
782 # the delegating user's gid
783 caller_gid = self._get_gid(self.user)
784 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
786 # the gid of the user who will be delegated to
787 delegee_gid = self._get_gid(hrn)
788 delegee_hrn = delegee_gid.get_hrn()
789 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
790 delegee_gid.save_to_file(filename=delegee_gidfile)
791 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
792 return dcred.save_to_string(save_parents=True)
794 # removed named registry record
795 # - have to first retrieve the record to be removed
796 def remove(self, opts, args):
797 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
805 return self.registry.Remove(hrn, auth_cred, type)
807 # add named registry record
808 def add(self, opts, args):
809 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
813 record_filepath = args[0]
814 rec_file = self.get_record_file(record_filepath)
815 record = load_record_from_file(rec_file).as_dict()
816 return self.registry.Register(record, auth_cred)
818 # update named registry entry
819 def update(self, opts, args):
820 user_cred = self.get_user_cred()
824 rec_file = self.get_record_file(args[0])
825 record = load_record_from_file(rec_file)
826 if record['type'] == "user":
827 if record.get_name() == user_cred.get_gid_object().get_hrn():
828 cred = user_cred.save_to_string(save_parents=True)
830 cred = self.get_auth_cred().save_to_string(save_parents=True)
831 elif record['type'] in ["slice"]:
833 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
834 except xmlrpcprotocol.ServerException, e:
835 # XXX smbaker -- once we have better error return codes, update this
836 # to do something better than a string compare
837 if "Permission error" in e.args[0]:
838 cred = self.get_auth_cred().save_to_string(save_parents=True)
841 elif record.get_type() in ["authority"]:
842 cred = self.get_auth_cred().save_to_string(save_parents=True)
843 elif record.get_type() == 'node':
844 cred = self.get_auth_cred().save_to_string(save_parents=True)
846 raise "unknown record type" + record.get_type()
847 record = record.as_dict()
848 return self.registry.Update(record, cred)
850 def get_trusted_certs(self, opts, args):
852 return uhe trusted certs at this interface
854 trusted_certs = self.registry.get_trusted_certs()
855 for trusted_cert in trusted_certs:
856 gid = GID(string=trusted_cert)
858 cert = Certificate(string=trusted_cert)
859 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
862 def aggregates(self, opts, args):
864 return a list of details about known aggregates
866 user_cred = self.get_user_cred().save_to_string(save_parents=True)
871 result = self.registry.get_aggregates(user_cred, hrn)
875 def registries(self, opts, args):
877 return a list of details about known registries
879 user_cred = self.get_user_cred().save_to_string(save_parents=True)
883 result = self.registry.get_registries(user_cred, hrn)
888 # ==================================================================
889 # Slice-related commands
890 # ==================================================================
892 def version(self, opts, args):
893 if opts.version_local:
894 version=version_core()
896 if opts.version_registry:
899 server = self.get_server_from_opts(opts)
900 version=server.GetVersion()
901 for (k,v) in version.iteritems():
902 print "%-20s: %s"%(k,v)
904 # list instantiated slices
905 def slices(self, opts, args):
907 list instantiated slices
909 user_cred = self.get_user_cred().save_to_string(save_parents=True)
912 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
913 creds.append(delegated_cred)
914 server = self.get_server_from_opts(opts)
915 #results = server.ListSlices(creds, unique_call_id())
916 results = server.ListSlices(creds)
917 display_list(results)
920 # show rspec for named slice
921 def resources(self, opts, args):
922 user_cred = self.get_user_cred().save_to_string(save_parents=True)
923 server = self.slicemgr
925 server = self.get_server_from_opts(opts)
928 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
930 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
937 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
938 creds.append(delegated_cred)
939 if opts.rspec_version:
940 server_version = self.get_cached_server_version(server)
941 if 'sfa' in server_version:
942 # just request the version the client wants
943 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
945 # this must be a protogeni aggregate. We should request a v2 ad rspec
946 # regardless of what the client user requested
947 call_options['rspec_version'] = dict(pg_rspec_request_version)
948 #panos add info options
950 call_options['info'] = opts.info
952 call_args = [creds, call_options]
953 if self.server_supports_call_id_arg(server):
954 call_args.append(unique_call_id())
955 result = server.ListResources(*call_args)
956 if opts.file is None:
957 display_rspec(result, opts.format)
959 save_rspec_to_file(result, opts.file)
962 # created named slice with given rspec
963 def create(self, opts, args):
964 server = self.get_server_from_opts(opts)
965 server_version = self.get_cached_server_version(server)
967 slice_urn = hrn_to_urn(slice_hrn, 'slice')
968 user_cred = self.get_user_cred()
969 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
972 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
973 creds.append(delegated_cred)
974 rspec_file = self.get_rspec_file(args[1])
975 rspec = open(rspec_file).read()
977 # need to pass along user keys to the aggregate.
979 # { urn: urn:publicid:IDN+emulab.net+user+alice
980 # keys: [<ssh key A>, <ssh key B>]
985 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
986 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
987 slice_record = slice_records[0]
988 user_hrns = slice_record['researcher']
989 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
990 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
991 for user_record in user_records:
992 if user_record['type'] != 'user':
994 #user = {'urn': user_cred.get_gid_caller().get_urn(),'keys': []}
995 user = {'urn': user_cred.get_gid_caller().get_urn(), #
996 'keys': user_record['keys'],
997 'email': user_record['email'], # needed for MyPLC
998 'person_id': user_record['person_id'], # needed for MyPLC
999 'first_name': user_record['first_name'], # needed for MyPLC
1000 'last_name': user_record['last_name'], # needed for MyPLC
1001 'slice_record': slice_record, # needed for legacy refresh peer
1002 'key_ids': user_record['key_ids'] # needed for legacy refresh peer
1005 all_keys.extend(user_record['keys'])
1006 all_key_ids.extend(user_record['key_ids'])
1007 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
1008 # request. So we will add all to the current caller's list of keys
1009 if 'sfa' not in server_version:
1011 if user['urn'] == user_cred.get_gid_caller().get_urn():
1012 user['keys'] = all_keys
1014 call_args = [slice_urn, creds, rspec, users]
1015 if self.server_supports_call_id_arg(server):
1016 call_args.append(unique_call_id())
1018 result = server.CreateSliver(*call_args)
1019 if opts.file is None:
1022 save_rspec_to_file (result, opts.file)
1025 # get a ticket for the specified slice
1026 def get_ticket(self, opts, args):
1027 slice_hrn, rspec_path = args[0], args[1]
1028 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1029 user_cred = self.get_user_cred()
1030 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1031 creds = [slice_cred]
1033 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1034 creds.append(delegated_cred)
1035 rspec_file = self.get_rspec_file(rspec_path)
1036 rspec = open(rspec_file).read()
1037 server = self.get_server_from_opts(opts)
1038 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1039 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1040 self.logger.info("writing ticket to %s"%file)
1041 ticket = SfaTicket(string=ticket_string)
1042 ticket.save_to_file(filename=file, save_parents=True)
1044 def redeem_ticket(self, opts, args):
1045 ticket_file = args[0]
1047 # get slice hrn from the ticket
1048 # use this to get the right slice credential
1049 ticket = SfaTicket(filename=ticket_file)
1051 slice_hrn = ticket.gidObject.get_hrn()
1052 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1053 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1054 user_cred = self.get_user_cred()
1055 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1057 # get a list of node hostnames from the RSpec
1058 tree = etree.parse(StringIO(ticket.rspec))
1059 root = tree.getroot()
1060 hostnames = root.xpath("./network/site/node/hostname/text()")
1062 # create an xmlrpc connection to the component manager at each of these
1063 # components and gall redeem_ticket
1065 for hostname in hostnames:
1067 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1068 server = self.get_server(hostname, CM_PORT, self.key_file, \
1069 self.cert_file, self.options.debug)
1070 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1071 self.logger.info("Success")
1072 except socket.gaierror:
1073 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1074 except Exception, e:
1075 self.logger.log_exc(e.message)
1078 # delete named slice
1079 def delete(self, opts, args):
1081 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1082 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1083 creds = [slice_cred]
1085 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1086 creds.append(delegated_cred)
1087 server = self.get_server_from_opts(opts)
1089 call_args = [slice_urn, creds]
1090 if self.server_supports_call_id_arg(server):
1091 call_args.append(unique_call_id())
1092 return server.DeleteSliver(*call_args)
1095 def start(self, opts, args):
1097 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1098 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1099 creds = [slice_cred]
1101 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1102 creds.append(delegated_cred)
1103 server = self.get_server_from_opts(opts)
1104 return server.Start(slice_urn, creds)
1107 def stop(self, opts, args):
1109 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1110 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1111 creds = [slice_cred]
1113 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1114 creds.append(delegated_cred)
1115 server = self.get_server_from_opts(opts)
1116 return server.Stop(slice_urn, creds)
1119 def reset(self, opts, args):
1121 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1122 server = self.get_server_from_opts(opts)
1123 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1124 creds = [slice_cred]
1126 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1127 creds.append(delegated_cred)
1128 return server.reset_slice(creds, slice_urn)
1130 def renew(self, opts, args):
1132 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1133 server = self.get_server_from_opts(opts)
1134 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1135 creds = [slice_cred]
1137 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1138 creds.append(delegated_cred)
1141 call_args = [slice_urn, creds, time]
1142 if self.server_supports_call_id_arg(server):
1143 call_args.append(unique_call_id())
1144 return server.RenewSliver(*call_args)
1147 def status(self, opts, args):
1149 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1150 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1151 creds = [slice_cred]
1153 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1154 creds.append(delegated_cred)
1155 server = self.get_server_from_opts(opts)
1156 call_args = [slice_urn, creds]
1157 if self.server_supports_call_id_arg(server):
1158 call_args.append(unique_call_id())
1159 print server.SliverStatus(*call_args)
1162 def shutdown(self, opts, args):
1164 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1165 slice_cred = self.get_slice_cred(slice_hrn).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)
1170 server = self.get_server_from_opts(opts)
1171 return server.Shutdown(slice_urn, creds)
1173 def print_help (self):
1174 self.sfi_parser.print_help()
1175 self.cmd_parser.print_help()
1178 # Main: parse arguments and dispatch to command
1181 self.sfi_parser = self.create_parser()
1182 (options, args) = self.sfi_parser.parse_args()
1183 self.options = options
1185 self.logger.setLevelFromOptVerbose(self.options.verbose)
1186 if options.hashrequest:
1187 self.hashrequest = True
1190 self.logger.critical("No command given. Use -h for help.")
1194 self.cmd_parser = self.create_cmd_parser(command)
1195 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1198 self.logger.info("Command=%s" % command)
1199 if command in ("resources"):
1200 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1201 elif command in ("list", "show", "remove"):
1202 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1203 self.logger.debug('cmd_args %s' % cmd_args)
1206 self.dispatch(command, cmd_opts, cmd_args)
1208 self.logger.critical ("Unknown command %s"%command)
1214 if __name__ == "__main__":