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
19 from sfa.client.client_helper import pg_users_arg, sfa_users_arg, sfa_to_pg_users_arg
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.rspecs.rspec import RSpec
27 from sfa.rspecs.rspec_converter import RSpecConverter
28 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
29 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
30 from sfa.util.config import Config
31 from sfa.util.version import version_core
32 from sfa.util.cache import Cache
33 from sfa.rspecs.version_manager import VersionManager
38 # utility methods here
40 def display_rspec(rspec, format='rspec'):
42 tree = etree.parse(StringIO(rspec))
44 result = root.xpath("./network/site/node/hostname/text()")
45 elif format in ['ip']:
46 # The IP address is not yet part of the new RSpec
47 # so this doesn't do anything yet.
48 tree = etree.parse(StringIO(rspec))
50 result = root.xpath("./network/site/node/ipv4/text()")
57 def display_list(results):
58 for result in results:
61 def display_records(recordList, dump=False):
62 ''' Print all fields in the record'''
63 for record in recordList:
64 display_record(record, dump)
66 def display_record(record, dump=False):
70 info = record.getdict()
71 print "%s (%s)" % (info['hrn'], info['type'])
75 def filter_records(type, records):
77 for record in records:
78 if (record['type'] == type) or (type == "all"):
79 filtered_records.append(record)
80 return filtered_records
84 def save_rspec_to_file(rspec, filename):
85 if not filename.endswith(".rspec"):
86 filename = filename + ".rspec"
87 f = open(filename, 'w')
92 def save_records_to_file(filename, recordList, format="xml"):
95 for record in recordList:
97 save_record_to_file(filename + "." + str(index), record)
99 save_record_to_file(filename, record)
101 elif format == "xmllist":
102 f = open(filename, "w")
103 f.write("<recordlist>\n")
104 for record in recordList:
105 record = SfaRecord(dict=record)
106 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
107 f.write("</recordlist>\n");
109 elif format == "hrnlist":
110 f = open(filename, "w")
111 for record in recordList:
112 record = SfaRecord(dict=record)
113 f.write(record.get_name() + "\n")
116 # this should never happen
117 print "unknown output format", format
119 def save_record_to_file(filename, record):
120 if record['type'] in ['user']:
121 record = UserRecord(dict=record)
122 elif record['type'] in ['slice']:
123 record = SliceRecord(dict=record)
124 elif record['type'] in ['node']:
125 record = NodeRecord(dict=record)
126 elif record['type'] in ['authority', 'ma', 'sa']:
127 record = AuthorityRecord(dict=record)
129 record = SfaRecord(dict=record)
130 str = record.save_to_string()
131 f=codecs.open(filename, encoding='utf-8',mode="w")
138 def load_record_from_file(filename):
139 f=codecs.open(filename, encoding="utf-8", mode="r")
142 record = SfaRecord(string=str)
147 def unique_call_id(): return uuid.uuid4().urn
151 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
153 # dummy to meet Sfi's expectations for its 'options' field
154 # i.e. s/t we can do setattr on
158 def __init__ (self,options=None):
159 if options is None: options=Sfi.DummyOptions()
160 for opt in Sfi.required_options:
161 if not hasattr(options,opt): setattr(options,opt,None)
162 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
163 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
164 # would be safer to remove self.sfi_dir altogether
165 self.sfi_dir = options.sfi_dir
166 self.options = options
170 self.authority = None
171 self.hashrequest = False
172 self.logger = sfi_logger
173 self.logger.enable_console()
175 def create_cmd_parser(self, command, additional_cmdargs=None):
176 cmdargs = {"list": "authority",
181 "aggregates": "[name]",
182 "registries": "[name]",
183 "create_gid": "[name]",
185 "get_trusted_certs": "cred",
187 "resources": "[name]",
188 "create": "name rspec",
189 "get_ticket": "name rspec",
190 "redeem_ticket": "ticket",
202 if additional_cmdargs:
203 cmdargs.update(additional_cmdargs)
205 if command not in cmdargs:
206 msg="Invalid command\n"
208 msg += ','.join(cmdargs.keys())
209 self.logger.critical(msg)
212 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
213 % (command, cmdargs[command]))
215 # user specifies remote aggregate/sm/component
216 if command in ("resources", "slices", "create", "delete", "start", "stop",
217 "restart", "shutdown", "get_ticket", "renew", "status"):
218 parser.add_option("-a", "--aggregate", dest="aggregate",
219 default=None, help="aggregate host")
220 parser.add_option("-p", "--port", dest="port",
221 default=AGGREGATE_PORT, help="aggregate port")
222 parser.add_option("-c", "--component", dest="component", default=None,
223 help="component hrn")
224 parser.add_option("-d", "--delegate", dest="delegate", default=None,
226 help="Include a credential delegated to the user's root"+\
227 "authority in set of credentials for this call")
229 # registy filter option
230 if command in ("list", "show", "remove"):
231 parser.add_option("-t", "--type", dest="type", type="choice",
232 help="type filter ([all]|user|slice|authority|node|aggregate)",
233 choices=("all", "user", "slice", "authority", "node", "aggregate"),
236 if command in ("resources"):
237 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
238 help="schema type and version of resulting RSpec")
239 parser.add_option("-f", "--format", dest="format", type="choice",
240 help="display format ([xml]|dns|ip)", default="xml",
241 choices=("xml", "dns", "ip"))
242 #panos: a new option to define the type of information about resources a user is interested in
243 parser.add_option("-i", "--info", dest="info",
244 help="optional component information", default=None)
247 # 'create' does return the new rspec, makes sense to save that too
248 if command in ("resources", "show", "list", "create_gid", 'create'):
249 parser.add_option("-o", "--output", dest="file",
250 help="output XML to file", metavar="FILE", default=None)
252 if command in ("show", "list"):
253 parser.add_option("-f", "--format", dest="format", type="choice",
254 help="display format ([text]|xml)", default="text",
255 choices=("text", "xml"))
257 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
258 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
259 choices=("xml", "xmllist", "hrnlist"))
261 if command in ("delegate"):
262 parser.add_option("-u", "--user",
263 action="store_true", dest="delegate_user", default=False,
264 help="delegate user credential")
265 parser.add_option("-s", "--slice", dest="delegate_slice",
266 help="delegate slice credential", metavar="HRN", default=None)
268 if command in ("version"):
269 parser.add_option("-a", "--aggregate", dest="aggregate",
270 default=None, help="aggregate host")
271 parser.add_option("-p", "--port", dest="port",
272 default=AGGREGATE_PORT, help="aggregate port")
273 parser.add_option("-R","--registry-version",
274 action="store_true", dest="version_registry", default=False,
275 help="probe registry version instead of slicemgr")
276 parser.add_option("-l","--local",
277 action="store_true", dest="version_local", default=False,
278 help="display version of the local client")
283 def create_parser(self):
285 # Generate command line parser
286 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
287 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
288 parser.add_option("-r", "--registry", dest="registry",
289 help="root registry", metavar="URL", default=None)
290 parser.add_option("-s", "--slicemgr", dest="sm",
291 help="slice manager", metavar="URL", default=None)
292 default_sfi_dir = os.path.expanduser("~/.sfi/")
293 parser.add_option("-d", "--dir", dest="sfi_dir",
294 help="config & working directory - default is " + default_sfi_dir,
295 metavar="PATH", default=default_sfi_dir)
296 parser.add_option("-u", "--user", dest="user",
297 help="user name", metavar="HRN", default=None)
298 parser.add_option("-a", "--auth", dest="auth",
299 help="authority name", metavar="HRN", default=None)
300 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
301 help="verbose mode - cumulative")
302 parser.add_option("-D", "--debug",
303 action="store_true", dest="debug", default=False,
304 help="Debug (xml-rpc) protocol messages")
305 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
306 help="RPC protocol (xmlrpc or soap)")
307 parser.add_option("-k", "--hashrequest",
308 action="store_true", dest="hashrequest", default=False,
309 help="Create a hash of the request that will be authenticated on the server")
310 parser.add_option("-t", "--timeout", dest="timeout", default=None,
311 help="Amout of time tom wait before timing out the request")
312 parser.disable_interspersed_args()
317 def read_config(self):
318 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
320 config = Config (config_file)
322 self.logger.critical("Failed to read configuration file %s"%config_file)
323 self.logger.info("Make sure to remove the export clauses and to add quotes")
324 if self.options.verbose==0:
325 self.logger.info("Re-run with -v for more details")
327 self.logger.log_exc("Could not read config file %s"%config_file)
332 if (self.options.sm is not None):
333 self.sm_url = self.options.sm
334 elif hasattr(config, "SFI_SM"):
335 self.sm_url = config.SFI_SM
337 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
341 if (self.options.registry is not None):
342 self.reg_url = self.options.registry
343 elif hasattr(config, "SFI_REGISTRY"):
344 self.reg_url = config.SFI_REGISTRY
346 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
351 if (self.options.user is not None):
352 self.user = self.options.user
353 elif hasattr(config, "SFI_USER"):
354 self.user = config.SFI_USER
356 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
360 if (self.options.auth is not None):
361 self.authority = self.options.auth
362 elif hasattr(config, "SFI_AUTH"):
363 self.authority = config.SFI_AUTH
365 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
373 # Establish Connection to SliceMgr and Registry Servers
375 def set_servers(self):
378 # Get key and certificate
379 key_file = self.get_key_file()
380 cert_file = self.get_cert_file(key_file)
381 self.key = Keypair(filename=key_file)
382 self.key_file = key_file
383 self.cert_file = cert_file
384 self.cert = GID(filename=cert_file)
385 self.logger.info("Contacting Registry at: %s"%self.reg_url)
386 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
387 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
388 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
391 def get_cached_server_version(self, server):
392 # check local cache first
395 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
396 cache_key = server.url + "-version"
398 cache = Cache(cache_file)
401 self.logger.info("Local cache not found at: %s" % cache_file)
404 version = cache.get(cache_key)
407 version = server.GetVersion()
408 # cache version for 24 hours
409 cache.add(cache_key, version, ttl= 60*60*24)
410 self.logger.info("Updating cache file %s" % cache_file)
411 cache.save_to_file(cache_file)
417 def server_supports_call_id_arg(self, server):
419 Returns true if server support the optional call_id arg, false otherwise.
421 server_version = self.get_cached_server_version(server)
422 if 'sfa' in server_version and 'code_tag' in server_version:
423 code_tag = server_version['code_tag']
424 code_tag_parts = code_tag.split("-")
426 version_parts = code_tag_parts[0].split(".")
427 major, minor = version_parts[0], version_parts[1]
428 rev = code_tag_parts[1]
430 if int(minor) > 0 or int(rev) > 20:
435 # Get various credential and spec files
437 # Establishes limiting conventions
438 # - conflates MAs and SAs
439 # - assumes last token in slice name is unique
441 # Bootstraps credentials
442 # - bootstrap user credential from self-signed certificate
443 # - bootstrap authority credential from user credential
444 # - bootstrap slice credential from user credential
448 def get_key_file(self):
449 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
450 if (os.path.isfile(file)):
453 self.logger.error("Key file %s does not exist"%file)
457 def get_cert_file(self, key_file):
459 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
460 if (os.path.isfile(cert_file)):
461 # we'd perfer to use Registry issued certs instead of self signed certs.
462 # if this is a Registry cert (GID) then we are done
463 gid = GID(filename=cert_file)
467 # generate self signed certificate
468 k = Keypair(filename=key_file)
469 cert = Certificate(subject=self.user)
471 cert.set_issuer(k, self.user)
473 self.logger.info("Writing self-signed certificate to %s"%cert_file)
474 cert.save_to_file(cert_file)
476 # try to get registry issued cert
478 self.logger.info("Getting Registry issued cert")
480 # *hack. need to set registyr before _get_gid() is called
481 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
482 gid = self._get_gid(type='user')
484 self.logger.info("Writing certificate to %s"%cert_file)
485 gid.save_to_file(cert_file)
487 self.logger.info("Failed to download Registry issued cert")
491 def get_cached_gid(self, file):
496 if (os.path.isfile(file)):
497 gid = GID(filename=file)
501 def get_gid(self, opts, args):
503 Get the specify gid and save it to file
508 gid = self._get_gid(hrn)
509 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
512 def _get_gid(self, hrn=None, type=None):
514 git_gid helper. Retrive the gid from the registry and save it to file.
520 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
522 gid = self.get_cached_gid(gidfile)
524 user_cred = self.get_user_cred()
525 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
527 raise RecordNotFound(args[0])
532 if type == rec['type']:
535 raise RecordNotFound(args[0])
537 gid = GID(string=record['gid'])
538 self.logger.info("Writing gid to %s"%gidfile)
539 gid.save_to_file(filename=gidfile)
543 def get_cached_credential(self, file):
545 Return a cached credential only if it hasn't expired.
547 if (os.path.isfile(file)):
548 credential = Credential(filename=file)
549 # make sure it isnt expired
550 if not credential.get_expiration or \
551 datetime.datetime.today() < credential.get_expiration():
555 def get_user_cred(self):
556 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
557 return self.get_cred(file, 'user', self.user)
559 def get_auth_cred(self):
560 if not self.authority:
561 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
563 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
564 return self.get_cred(file, 'authority', self.authority)
566 def get_slice_cred(self, name):
567 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
568 return self.get_cred(file, 'slice', name)
570 def get_cred(self, file, type, hrn):
571 # attempt to load a cached credential
572 cred = self.get_cached_credential(file)
575 cert_string = self.cert.save_to_string(save_parents=True)
576 user_name = self.user.replace(self.authority + ".", '')
577 if user_name.count(".") > 0:
578 user_name = user_name.replace(".", '_')
579 self.user = self.authority + "." + user_name
580 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
582 # bootstrap slice credential from user credential
583 user_cred = self.get_user_cred().save_to_string(save_parents=True)
584 cred_str = self.registry.GetCredential(user_cred, hrn, type)
587 self.logger.critical("Failed to get %s credential" % type)
590 cred = Credential(string=cred_str)
591 cred.save_to_file(file, save_parents=True)
592 self.logger.info("Writing %s credential to %s" %(type, file))
597 def get_rspec_file(self, rspec):
598 if (os.path.isabs(rspec)):
601 file = os.path.join(self.options.sfi_dir, rspec)
602 if (os.path.isfile(file)):
605 self.logger.critical("No such rspec file %s"%rspec)
608 def get_record_file(self, record):
609 if (os.path.isabs(record)):
612 file = os.path.join(self.options.sfi_dir, record)
613 if (os.path.isfile(file)):
616 self.logger.critical("No such registry record file %s"%record)
619 def load_publickey_string(self, fn):
621 key_string = f.read()
623 # if the filename is a private key file, then extract the public key
624 if "PRIVATE KEY" in key_string:
625 outfn = tempfile.mktemp()
626 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
629 key_string = f.read()
635 def get_component_server_from_hrn(self, hrn):
636 # direct connection to the nodes component manager interface
637 user_cred = self.get_user_cred().save_to_string(save_parents=True)
638 records = self.registry.Resolve(hrn, user_cred)
639 records = filter_records('node', records)
641 self.logger.warning("No such component:%r"% opts.component)
644 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
646 def get_server(self, host, port, keyfile, certfile):
648 Return an instance of an xmlrpc server connection
650 # port is appended onto the domain, before the path. Should look like:
651 # http://domain:port/path
652 host_parts = host.split('/')
653 host_parts[0] = host_parts[0] + ":" + str(port)
654 url = "http://%s" % "/".join(host_parts)
655 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
657 # xxx opts could be retrieved in self.options
658 def get_server_from_opts(self, opts):
660 Return instance of an xmlrpc connection to a slice manager, aggregate
661 or component server depending on the specified opts
663 server = self.slicemgr
664 # direct connection to an aggregate
665 if hasattr(opts, 'aggregate') and opts.aggregate:
666 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
667 # direct connection to the nodes component manager interface
668 if hasattr(opts, 'component') and opts.component:
669 server = self.get_component_server_from_hrn(opts.component)
672 #==========================================================================
673 # Following functions implement the commands
675 # Registry-related commands
676 #==========================================================================
678 def dispatch(self, command, cmd_opts, cmd_args):
679 return getattr(self, command)(cmd_opts, cmd_args)
681 def create_gid(self, opts, args):
686 user_cred = self.get_user_cred().save_to_string(save_parents=True)
687 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
691 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
692 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
693 GID(string=gid).save_to_file(filename)
696 # list entires in named authority registry
697 def list(self, opts, args):
702 user_cred = self.get_user_cred().save_to_string(save_parents=True)
704 list = self.registry.List(hrn, user_cred)
706 raise Exception, "Not enough parameters for the 'list' command"
708 # filter on person, slice, site, node, etc.
709 # THis really should be in the self.filter_records funct def comment...
710 list = filter_records(opts.type, list)
712 print "%s (%s)" % (record['hrn'], record['type'])
714 save_records_to_file(opts.file, list, opts.fileformat)
717 # show named registry record
718 def show(self, opts, args):
723 user_cred = self.get_user_cred().save_to_string(save_parents=True)
724 records = self.registry.Resolve(hrn, user_cred)
725 records = filter_records(opts.type, records)
727 print "No record of type", opts.type
728 for record in records:
729 if record['type'] in ['user']:
730 record = UserRecord(dict=record)
731 elif record['type'] in ['slice']:
732 record = SliceRecord(dict=record)
733 elif record['type'] in ['node']:
734 record = NodeRecord(dict=record)
735 elif record['type'].startswith('authority'):
736 record = AuthorityRecord(dict=record)
738 record = SfaRecord(dict=record)
739 if (opts.format == "text"):
742 print record.save_to_string()
744 save_records_to_file(opts.file, records, opts.fileformat)
747 def delegate(self, opts, args):
749 delegee_hrn = args[0]
750 if opts.delegate_user:
751 user_cred = self.get_user_cred()
752 cred = self.delegate_cred(user_cred, delegee_hrn)
753 elif opts.delegate_slice:
754 slice_cred = self.get_slice_cred(opts.delegate_slice)
755 cred = self.delegate_cred(slice_cred, delegee_hrn)
757 self.logger.warning("Must specify either --user or --slice <hrn>")
759 delegated_cred = Credential(string=cred)
760 object_hrn = delegated_cred.get_gid_object().get_hrn()
761 if opts.delegate_user:
762 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
763 + get_leaf(object_hrn) + ".cred")
764 elif opts.delegate_slice:
765 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
766 + get_leaf(object_hrn) + ".cred")
768 delegated_cred.save_to_file(dest_fn, save_parents=True)
770 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
772 def delegate_cred(self, object_cred, hrn):
773 # the gid and hrn of the object we are delegating
774 if isinstance(object_cred, str):
775 object_cred = Credential(string=object_cred)
776 object_gid = object_cred.get_gid_object()
777 object_hrn = object_gid.get_hrn()
779 if not object_cred.get_privileges().get_all_delegate():
780 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
783 # the delegating user's gid
784 caller_gid = self._get_gid(self.user)
785 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
787 # the gid of the user who will be delegated to
788 delegee_gid = self._get_gid(hrn)
789 delegee_hrn = delegee_gid.get_hrn()
790 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
791 delegee_gid.save_to_file(filename=delegee_gidfile)
792 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
793 return dcred.save_to_string(save_parents=True)
795 # removed named registry record
796 # - have to first retrieve the record to be removed
797 def remove(self, opts, args):
798 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
806 return self.registry.Remove(hrn, auth_cred, type)
808 # add named registry record
809 def add(self, opts, args):
810 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
814 record_filepath = args[0]
815 rec_file = self.get_record_file(record_filepath)
816 record = load_record_from_file(rec_file).as_dict()
817 return self.registry.Register(record, auth_cred)
819 # update named registry entry
820 def update(self, opts, args):
821 user_cred = self.get_user_cred()
825 rec_file = self.get_record_file(args[0])
826 record = load_record_from_file(rec_file)
827 if record['type'] == "user":
828 if record.get_name() == user_cred.get_gid_object().get_hrn():
829 cred = user_cred.save_to_string(save_parents=True)
831 cred = self.get_auth_cred().save_to_string(save_parents=True)
832 elif record['type'] in ["slice"]:
834 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
835 except xmlrpcprotocol.ServerException, e:
836 # XXX smbaker -- once we have better error return codes, update this
837 # to do something better than a string compare
838 if "Permission error" in e.args[0]:
839 cred = self.get_auth_cred().save_to_string(save_parents=True)
842 elif record.get_type() in ["authority"]:
843 cred = self.get_auth_cred().save_to_string(save_parents=True)
844 elif record.get_type() == 'node':
845 cred = self.get_auth_cred().save_to_string(save_parents=True)
847 raise "unknown record type" + record.get_type()
848 record = record.as_dict()
849 return self.registry.Update(record, cred)
851 def get_trusted_certs(self, opts, args):
853 return uhe trusted certs at this interface
855 trusted_certs = self.registry.get_trusted_certs()
856 for trusted_cert in trusted_certs:
857 gid = GID(string=trusted_cert)
859 cert = Certificate(string=trusted_cert)
860 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
863 def aggregates(self, opts, args):
865 return a list of details about known aggregates
867 user_cred = self.get_user_cred().save_to_string(save_parents=True)
872 result = self.registry.get_aggregates(user_cred, hrn)
876 def registries(self, opts, args):
878 return a list of details about known registries
880 user_cred = self.get_user_cred().save_to_string(save_parents=True)
884 result = self.registry.get_registries(user_cred, hrn)
889 # ==================================================================
890 # Slice-related commands
891 # ==================================================================
893 def version(self, opts, args):
894 if opts.version_local:
895 version=version_core()
897 if opts.version_registry:
900 server = self.get_server_from_opts(opts)
901 version=server.GetVersion()
902 for (k,v) in version.iteritems():
903 print "%-20s: %s"%(k,v)
905 # list instantiated slices
906 def slices(self, opts, args):
908 list instantiated slices
910 user_cred = self.get_user_cred().save_to_string(save_parents=True)
913 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
914 creds.append(delegated_cred)
915 server = self.get_server_from_opts(opts)
916 #results = server.ListSlices(creds, unique_call_id())
917 results = server.ListSlices(creds)
918 display_list(results)
921 # show rspec for named slice
922 def resources(self, opts, args):
923 user_cred = self.get_user_cred().save_to_string(save_parents=True)
924 server = self.slicemgr
926 server = self.get_server_from_opts(opts)
929 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
931 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
938 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
939 creds.append(delegated_cred)
940 if opts.rspec_version:
941 version_manager = VersionManager()
942 server_version = self.get_cached_server_version(server)
943 if 'sfa' in server_version:
944 # just request the version the client wants
945 call_options['rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
947 # this must be a protogeni aggregate. We should request a v2 ad rspec
948 # regardless of what the client user requested
949 call_options['rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
950 #panos add info options
952 call_options['info'] = opts.info
954 call_args = [creds, call_options]
955 if self.server_supports_call_id_arg(server):
956 call_args.append(unique_call_id())
957 result = server.ListResources(*call_args)
958 if opts.file is None:
959 display_rspec(result, opts.format)
961 save_rspec_to_file(result, opts.file)
964 # created named slice with given rspec
965 def create(self, opts, args):
966 server = self.get_server_from_opts(opts)
967 server_version = self.get_cached_server_version(server)
969 slice_urn = hrn_to_urn(slice_hrn, 'slice')
970 user_cred = self.get_user_cred()
971 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
974 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
975 creds.append(delegated_cred)
976 rspec_file = self.get_rspec_file(args[1])
977 rspec = open(rspec_file).read()
979 # need to pass along user keys to the aggregate.
981 # { urn: urn:publicid:IDN+emulab.net+user+alice
982 # 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)])
992 if 'sfa' not in server_version:
993 users = pg_users_arg(user_records)
995 rspec.filter({'component_manager_id': server_version['urn']})
996 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
998 users = sfa_users_arg(user_records, slice_record)
999 call_args = [slice_urn, creds, rspec, users]
1000 if self.server_supports_call_id_arg(server):
1001 call_args.append(unique_call_id())
1003 result = server.CreateSliver(*call_args)
1004 if opts.file is None:
1007 save_rspec_to_file (result, opts.file)
1010 # get a ticket for the specified slice
1011 def get_ticket(self, opts, args):
1012 slice_hrn, rspec_path = args[0], args[1]
1013 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1014 user_cred = self.get_user_cred()
1015 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1016 creds = [slice_cred]
1018 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1019 creds.append(delegated_cred)
1020 rspec_file = self.get_rspec_file(rspec_path)
1021 rspec = open(rspec_file).read()
1022 server = self.get_server_from_opts(opts)
1023 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1024 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1025 self.logger.info("writing ticket to %s"%file)
1026 ticket = SfaTicket(string=ticket_string)
1027 ticket.save_to_file(filename=file, save_parents=True)
1029 def redeem_ticket(self, opts, args):
1030 ticket_file = args[0]
1032 # get slice hrn from the ticket
1033 # use this to get the right slice credential
1034 ticket = SfaTicket(filename=ticket_file)
1036 slice_hrn = ticket.gidObject.get_hrn()
1037 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1038 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1039 user_cred = self.get_user_cred()
1040 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1042 # get a list of node hostnames from the RSpec
1043 tree = etree.parse(StringIO(ticket.rspec))
1044 root = tree.getroot()
1045 hostnames = root.xpath("./network/site/node/hostname/text()")
1047 # create an xmlrpc connection to the component manager at each of these
1048 # components and gall redeem_ticket
1050 for hostname in hostnames:
1052 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1053 server = self.get_server(hostname, CM_PORT, self.key_file, \
1054 self.cert_file, self.options.debug)
1055 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1056 self.logger.info("Success")
1057 except socket.gaierror:
1058 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1059 except Exception, e:
1060 self.logger.log_exc(e.message)
1063 # delete named slice
1064 def delete(self, opts, args):
1066 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1067 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1068 creds = [slice_cred]
1070 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1071 creds.append(delegated_cred)
1072 server = self.get_server_from_opts(opts)
1074 call_args = [slice_urn, creds]
1075 if self.server_supports_call_id_arg(server):
1076 call_args.append(unique_call_id())
1077 return server.DeleteSliver(*call_args)
1080 def start(self, opts, args):
1082 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1083 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1084 creds = [slice_cred]
1086 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1087 creds.append(delegated_cred)
1088 server = self.get_server_from_opts(opts)
1089 return server.Start(slice_urn, creds)
1092 def stop(self, opts, args):
1094 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1095 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1096 creds = [slice_cred]
1098 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1099 creds.append(delegated_cred)
1100 server = self.get_server_from_opts(opts)
1101 return server.Stop(slice_urn, creds)
1104 def reset(self, opts, args):
1106 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1107 server = self.get_server_from_opts(opts)
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 return server.reset_slice(creds, slice_urn)
1115 def renew(self, opts, args):
1117 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1118 server = self.get_server_from_opts(opts)
1119 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1120 creds = [slice_cred]
1122 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1123 creds.append(delegated_cred)
1126 call_args = [slice_urn, creds, time]
1127 if self.server_supports_call_id_arg(server):
1128 call_args.append(unique_call_id())
1129 return server.RenewSliver(*call_args)
1132 def status(self, opts, args):
1134 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1135 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1136 creds = [slice_cred]
1138 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1139 creds.append(delegated_cred)
1140 server = self.get_server_from_opts(opts)
1141 call_args = [slice_urn, creds]
1142 if self.server_supports_call_id_arg(server):
1143 call_args.append(unique_call_id())
1144 print server.SliverStatus(*call_args)
1147 def shutdown(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 return server.Shutdown(slice_urn, creds)
1158 def print_help (self):
1159 self.sfi_parser.print_help()
1160 self.cmd_parser.print_help()
1163 # Main: parse arguments and dispatch to command
1166 self.sfi_parser = self.create_parser()
1167 (options, args) = self.sfi_parser.parse_args()
1168 self.options = options
1170 self.logger.setLevelFromOptVerbose(self.options.verbose)
1171 if options.hashrequest:
1172 self.hashrequest = True
1175 self.logger.critical("No command given. Use -h for help.")
1179 self.cmd_parser = self.create_cmd_parser(command)
1180 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1183 self.logger.info("Command=%s" % command)
1184 if command in ("resources"):
1185 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1186 elif command in ("list", "show", "remove"):
1187 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1188 self.logger.debug('cmd_args %s' % cmd_args)
1191 self.dispatch(command, cmd_opts, cmd_args)
1193 self.logger.critical ("Unknown command %s"%command)
1199 if __name__ == "__main__":