3 # sfi -- slice-based facility interface
14 from lxml import etree
15 from StringIO import StringIO
16 from types import StringTypes, ListType
17 from optparse import OptionParser
18 from sfa.util.sfalogging import sfi_logger
19 from sfa.trust.certificate import Keypair, Certificate
20 from sfa.trust.gid import GID
21 from sfa.trust.credential import Credential
22 from sfa.util.sfaticket import SfaTicket
23 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
24 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
25 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
26 from sfa.util.config import Config
27 from sfa.util.version import version_core
28 from sfa.util.cache import Cache
29 from sfa.rspecs.rspec_version import RSpecVersion
30 from sfa.rspecs.pg_rspec import pg_rspec_request_version
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_rspec_to_file(rspec, filename):
82 if not filename.endswith(".rspec"):
83 filename = filename + ".rspec"
85 f = open(filename, 'w')
90 def save_records_to_file(filename, recordList):
92 for record in recordList:
94 save_record_to_file(filename + "." + str(index), record)
96 save_record_to_file(filename, record)
99 def save_record_to_file(filename, record):
100 if record['type'] in ['user']:
101 record = UserRecord(dict=record)
102 elif record['type'] in ['slice']:
103 record = SliceRecord(dict=record)
104 elif record['type'] in ['node']:
105 record = NodeRecord(dict=record)
106 elif record['type'] in ['authority', 'ma', 'sa']:
107 record = AuthorityRecord(dict=record)
109 record = SfaRecord(dict=record)
110 str = record.save_to_string()
111 file(filename, "w").write(str)
116 def load_record_from_file(filename):
117 str = file(filename, "r").read()
118 record = SfaRecord(string=str)
123 def unique_call_id(): return uuid.uuid4().urn
127 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
129 # dummy to meet Sfi's expectations for its 'options' field
130 # i.e. s/t we can do setattr on
134 def __init__ (self,options=None):
135 if options is None: options=Sfi.DummyOptions()
136 for opt in Sfi.required_options:
137 if not hasattr(options,opt): setattr(options,opt,None)
138 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
139 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
140 # would be safer to remove self.sfi_dir altogether
141 self.sfi_dir = options.sfi_dir
142 self.options = options
146 self.authority = None
147 self.hashrequest = False
148 self.logger = sfi_logger
149 self.logger.enable_console()
151 def create_cmd_parser(self, command, additional_cmdargs=None):
152 cmdargs = {"list": "authority",
157 "aggregates": "[name]",
158 "registries": "[name]",
159 "create_gid": "[name]",
161 "get_trusted_certs": "cred",
163 "resources": "[name]",
164 "create": "name rspec",
165 "get_ticket": "name rspec",
166 "redeem_ticket": "ticket",
178 if additional_cmdargs:
179 cmdargs.update(additional_cmdargs)
181 if command not in cmdargs:
182 msg="Invalid command\n"
184 msg += ','.join(cmdargs.keys())
185 self.logger.critical(msg)
188 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
189 % (command, cmdargs[command]))
191 # user specifies remote aggregate/sm/component
192 if command in ("resources", "slices", "create", "delete", "start", "stop",
193 "restart", "shutdown", "get_ticket", "renew", "status"):
194 parser.add_option("-a", "--aggregate", dest="aggregate",
195 default=None, help="aggregate host")
196 parser.add_option("-p", "--port", dest="port",
197 default=AGGREGATE_PORT, help="aggregate port")
198 parser.add_option("-c", "--component", dest="component", default=None,
199 help="component hrn")
200 parser.add_option("-d", "--delegate", dest="delegate", default=None,
202 help="Include a credential delegated to the user's root"+\
203 "authority in set of credentials for this call")
205 # registy filter option
206 if command in ("list", "show", "remove"):
207 parser.add_option("-t", "--type", dest="type", type="choice",
208 help="type filter ([all]|user|slice|authority|node|aggregate)",
209 choices=("all", "user", "slice", "authority", "node", "aggregate"),
212 if command in ("resources"):
213 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
214 help="schema type and version of resulting RSpec")
215 parser.add_option("-f", "--format", dest="format", type="choice",
216 help="display format ([xml]|dns|ip)", default="xml",
217 choices=("xml", "dns", "ip"))
218 #panos: a new option to define the type of information about resources a user is interested in
219 parser.add_option("-i", "--info", dest="info",
220 help="optional component information", default=None)
223 if command in ("resources", "show", "list", "create_gid"):
224 parser.add_option("-o", "--output", dest="file",
225 help="output XML to file", metavar="FILE", default=None)
227 if command in ("show", "list"):
228 parser.add_option("-f", "--format", dest="format", type="choice",
229 help="display format ([text]|xml)", default="text",
230 choices=("text", "xml"))
232 if command in ("delegate"):
233 parser.add_option("-u", "--user",
234 action="store_true", dest="delegate_user", default=False,
235 help="delegate user credential")
236 parser.add_option("-s", "--slice", dest="delegate_slice",
237 help="delegate slice credential", metavar="HRN", default=None)
239 if command in ("version"):
240 parser.add_option("-a", "--aggregate", dest="aggregate",
241 default=None, help="aggregate host")
242 parser.add_option("-p", "--port", dest="port",
243 default=AGGREGATE_PORT, help="aggregate port")
244 parser.add_option("-R","--registry-version",
245 action="store_true", dest="version_registry", default=False,
246 help="probe registry version instead of slicemgr")
247 parser.add_option("-l","--local",
248 action="store_true", dest="version_local", default=False,
249 help="display version of the local client")
254 def create_parser(self):
256 # Generate command line parser
257 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
258 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
259 parser.add_option("-r", "--registry", dest="registry",
260 help="root registry", metavar="URL", default=None)
261 parser.add_option("-s", "--slicemgr", dest="sm",
262 help="slice manager", metavar="URL", default=None)
263 default_sfi_dir = os.path.expanduser("~/.sfi/")
264 parser.add_option("-d", "--dir", dest="sfi_dir",
265 help="config & working directory - default is " + default_sfi_dir,
266 metavar="PATH", default=default_sfi_dir)
267 parser.add_option("-u", "--user", dest="user",
268 help="user name", metavar="HRN", default=None)
269 parser.add_option("-a", "--auth", dest="auth",
270 help="authority name", metavar="HRN", default=None)
271 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
272 help="verbose mode - cumulative")
273 parser.add_option("-D", "--debug",
274 action="store_true", dest="debug", default=False,
275 help="Debug (xml-rpc) protocol messages")
276 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
277 help="RPC protocol (xmlrpc or soap)")
278 parser.add_option("-k", "--hashrequest",
279 action="store_true", dest="hashrequest", default=False,
280 help="Create a hash of the request that will be authenticated on the server")
281 parser.add_option("-t", "--timeout", dest="timeout", default=None,
282 help="Amout of time tom wait before timing out the request")
283 parser.disable_interspersed_args()
288 def read_config(self):
289 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
291 config = Config (config_file)
293 self.logger.critical("Failed to read configuration file %s"%config_file)
294 self.logger.info("Make sure to remove the export clauses and to add quotes")
295 if self.options.verbose==0:
296 self.logger.info("Re-run with -v for more details")
298 self.logger.log_exc("Could not read config file %s"%config_file)
303 if (self.options.sm is not None):
304 self.sm_url = self.options.sm
305 elif hasattr(config, "SFI_SM"):
306 self.sm_url = config.SFI_SM
308 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
312 if (self.options.registry is not None):
313 self.reg_url = self.options.registry
314 elif hasattr(config, "SFI_REGISTRY"):
315 self.reg_url = config.SFI_REGISTRY
317 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
322 if (self.options.user is not None):
323 self.user = self.options.user
324 elif hasattr(config, "SFI_USER"):
325 self.user = config.SFI_USER
327 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
331 if (self.options.auth is not None):
332 self.authority = self.options.auth
333 elif hasattr(config, "SFI_AUTH"):
334 self.authority = config.SFI_AUTH
336 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
344 # Establish Connection to SliceMgr and Registry Servers
346 def set_servers(self):
349 # Get key and certificate
350 key_file = self.get_key_file()
351 cert_file = self.get_cert_file(key_file)
352 self.key = Keypair(filename=key_file)
353 self.key_file = key_file
354 self.cert_file = cert_file
355 self.cert = GID(filename=cert_file)
356 self.logger.info("Contacting Registry at: %s"%self.reg_url)
357 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
358 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
359 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
362 def get_cached_server_version(self, server):
363 # check local cache first
366 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
367 cache_key = server.url + "-version"
369 cache = Cache(cache_file)
372 self.logger.info("Local cache not found at: %s" % cache_file)
375 version = cache.get(cache_key)
378 version = server.GetVersion()
379 # cache version for 24 hours
380 cache.add(cache_key, version, ttl= 60*60*24)
381 self.logger.info("Updating cache file %s" % cache_file)
382 cache.save_to_file(cache_file)
388 def server_supports_call_id_arg(self, server):
390 Returns true if server support the optional call_id arg, false otherwise.
392 server_version = self.get_cached_server_version(server)
393 if 'sfa' in server_version:
394 code_tag = server_version['code_tag']
395 code_tag_parts = code_tag.split("-")
397 version_parts = code_tag_parts[0].split(".")
398 major, minor = version_parts[0], version_parts[1]
399 rev = code_tag_parts[1]
401 if int(minor) > 0 or int(rev) > 20:
406 # Get various credential and spec files
408 # Establishes limiting conventions
409 # - conflates MAs and SAs
410 # - assumes last token in slice name is unique
412 # Bootstraps credentials
413 # - bootstrap user credential from self-signed certificate
414 # - bootstrap authority credential from user credential
415 # - bootstrap slice credential from user credential
419 def get_key_file(self):
420 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
421 if (os.path.isfile(file)):
424 self.logger.error("Key file %s does not exist"%file)
428 def get_cert_file(self, key_file):
430 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
431 if (os.path.isfile(cert_file)):
432 # we'd perfer to use Registry issued certs instead of self signed certs.
433 # if this is a Registry cert (GID) then we are done
434 gid = GID(filename=cert_file)
438 # generate self signed certificate
439 k = Keypair(filename=key_file)
440 cert = Certificate(subject=self.user)
442 cert.set_issuer(k, self.user)
444 self.logger.info("Writing self-signed certificate to %s"%cert_file)
445 cert.save_to_file(cert_file)
447 # try to get registry issued cert
449 self.logger.info("Getting Registry issued cert")
451 # *hack. need to set registyr before _get_gid() is called
452 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
453 gid = self._get_gid(type='user')
455 self.logger.info("Writing certificate to %s"%cert_file)
456 gid.save_to_file(cert_file)
458 self.logger.info("Failed to download Registry issued cert")
462 def get_cached_gid(self, file):
467 if (os.path.isfile(file)):
468 gid = GID(filename=file)
472 def get_gid(self, opts, args):
474 Get the specify gid and save it to file
479 gid = self._get_gid(hrn)
480 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
483 def _get_gid(self, hrn=None, type=None):
485 git_gid helper. Retrive the gid from the registry and save it to file.
491 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
493 gid = self.get_cached_gid(gidfile)
495 user_cred = self.get_user_cred()
496 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
498 raise RecordNotFound(args[0])
503 if type == rec['type']:
506 raise RecordNotFound(args[0])
508 gid = GID(string=record['gid'])
509 self.logger.info("Writing gid to %s"%gidfile)
510 gid.save_to_file(filename=gidfile)
514 def get_cached_credential(self, file):
516 Return a cached credential only if it hasn't expired.
518 if (os.path.isfile(file)):
519 credential = Credential(filename=file)
520 # make sure it isnt expired
521 if not credential.get_expiration or \
522 datetime.datetime.today() < credential.get_expiration():
526 def get_user_cred(self):
527 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
528 return self.get_cred(file, 'user', self.user)
530 def get_auth_cred(self):
531 if not self.authority:
532 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
534 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
535 return self.get_cred(file, 'authority', self.authority)
537 def get_slice_cred(self, name):
538 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
539 return self.get_cred(file, 'slice', name)
541 def get_cred(self, file, type, hrn):
542 # attempt to load a cached credential
543 cred = self.get_cached_credential(file)
546 cert_string = self.cert.save_to_string(save_parents=True)
547 user_name = self.user.replace(self.authority + ".", '')
548 if user_name.count(".") > 0:
549 user_name = user_name.replace(".", '_')
550 self.user = self.authority + "." + user_name
551 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
553 # bootstrap slice credential from user credential
554 user_cred = self.get_user_cred().save_to_string(save_parents=True)
555 cred_str = self.registry.GetCredential(user_cred, hrn, type)
558 self.logger.critical("Failed to get %s credential" % type)
561 cred = Credential(string=cred_str)
562 cred.save_to_file(file, save_parents=True)
563 self.logger.info("Writing %s credential to %s" %(type, file))
568 def get_rspec_file(self, rspec):
569 if (os.path.isabs(rspec)):
572 file = os.path.join(self.options.sfi_dir, rspec)
573 if (os.path.isfile(file)):
576 self.logger.critical("No such rspec file %s"%rspec)
579 def get_record_file(self, record):
580 if (os.path.isabs(record)):
583 file = os.path.join(self.options.sfi_dir, record)
584 if (os.path.isfile(file)):
587 self.logger.critical("No such registry record file %s"%record)
590 def load_publickey_string(self, fn):
592 key_string = f.read()
594 # if the filename is a private key file, then extract the public key
595 if "PRIVATE KEY" in key_string:
596 outfn = tempfile.mktemp()
597 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
600 key_string = f.read()
606 def get_component_server_from_hrn(self, hrn):
607 # direct connection to the nodes component manager interface
608 user_cred = self.get_user_cred().save_to_string(save_parents=True)
609 records = self.registry.Resolve(hrn, user_cred)
610 records = filter_records('node', records)
612 self.logger.warning("No such component:%r"% opts.component)
615 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
617 def get_server(self, host, port, keyfile, certfile):
619 Return an instance of an xmlrpc server connection
621 # port is appended onto the domain, before the path. Should look like:
622 # http://domain:port/path
623 host_parts = host.split('/')
624 host_parts[0] = host_parts[0] + ":" + str(port)
625 url = "http://%s" % "/".join(host_parts)
626 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
628 # xxx opts could be retrieved in self.options
629 def get_server_from_opts(self, opts):
631 Return instance of an xmlrpc connection to a slice manager, aggregate
632 or component server depending on the specified opts
634 server = self.slicemgr
635 # direct connection to an aggregate
636 if hasattr(opts, 'aggregate') and opts.aggregate:
637 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
638 # direct connection to the nodes component manager interface
639 if hasattr(opts, 'component') and opts.component:
640 server = self.get_component_server_from_hrn(opts.component)
643 #==========================================================================
644 # Following functions implement the commands
646 # Registry-related commands
647 #==========================================================================
649 def dispatch(self, command, cmd_opts, cmd_args):
650 return getattr(self, command)(cmd_opts, cmd_args)
652 def create_gid(self, opts, args):
657 user_cred = self.get_user_cred().save_to_string(save_parents=True)
658 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
662 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
663 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
664 GID(string=gid).save_to_file(filename)
667 # list entires in named authority registry
668 def list(self, opts, args):
673 user_cred = self.get_user_cred().save_to_string(save_parents=True)
675 list = self.registry.List(hrn, user_cred)
677 raise Exception, "Not enough parameters for the 'list' command"
679 # filter on person, slice, site, node, etc.
680 # THis really should be in the self.filter_records funct def comment...
681 list = filter_records(opts.type, list)
683 print "%s (%s)" % (record['hrn'], record['type'])
686 if not file.startswith(os.sep):
687 file = os.path.join(self.options.sfi_dir, file)
688 save_records_to_file(file, list)
691 # show named registry record
692 def show(self, opts, args):
697 user_cred = self.get_user_cred().save_to_string(save_parents=True)
698 records = self.registry.Resolve(hrn, user_cred)
699 records = filter_records(opts.type, records)
701 print "No record of type", opts.type
702 for record in records:
703 if record['type'] in ['user']:
704 record = UserRecord(dict=record)
705 elif record['type'] in ['slice']:
706 record = SliceRecord(dict=record)
707 elif record['type'] in ['node']:
708 record = NodeRecord(dict=record)
709 elif record['type'].startswith('authority'):
710 record = AuthorityRecord(dict=record)
712 record = SfaRecord(dict=record)
713 if (opts.format == "text"):
716 print record.save_to_string()
719 if not file.startswith(os.sep):
720 file = os.path.join(self.options.sfi_dir, file)
721 save_records_to_file(file, records)
724 def delegate(self, opts, args):
726 delegee_hrn = args[0]
727 if opts.delegate_user:
728 user_cred = self.get_user_cred()
729 cred = self.delegate_cred(user_cred, delegee_hrn)
730 elif opts.delegate_slice:
731 slice_cred = self.get_slice_cred(opts.delegate_slice)
732 cred = self.delegate_cred(slice_cred, delegee_hrn)
734 self.logger.warning("Must specify either --user or --slice <hrn>")
736 delegated_cred = Credential(string=cred)
737 object_hrn = delegated_cred.get_gid_object().get_hrn()
738 if opts.delegate_user:
739 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
740 + get_leaf(object_hrn) + ".cred")
741 elif opts.delegate_slice:
742 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
743 + get_leaf(object_hrn) + ".cred")
745 delegated_cred.save_to_file(dest_fn, save_parents=True)
747 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
749 def delegate_cred(self, object_cred, hrn):
750 # the gid and hrn of the object we are delegating
751 if isinstance(object_cred, str):
752 object_cred = Credential(string=object_cred)
753 object_gid = object_cred.get_gid_object()
754 object_hrn = object_gid.get_hrn()
756 if not object_cred.get_privileges().get_all_delegate():
757 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
760 # the delegating user's gid
761 caller_gid = self._get_gid(self.user)
762 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
764 # the gid of the user who will be delegated to
765 delegee_gid = self._get_gid(hrn)
766 delegee_hrn = delegee_gid.get_hrn()
767 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
768 delegee_gid.save_to_file(filename=delegee_gidfile)
769 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
770 return dcred.save_to_string(save_parents=True)
772 # removed named registry record
773 # - have to first retrieve the record to be removed
774 def remove(self, opts, args):
775 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
783 return self.registry.Remove(hrn, auth_cred, type)
785 # add named registry record
786 def add(self, opts, args):
787 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
791 record_filepath = args[0]
792 rec_file = self.get_record_file(record_filepath)
793 record = load_record_from_file(rec_file).as_dict()
794 return self.registry.Register(record, auth_cred)
796 # update named registry entry
797 def update(self, opts, args):
798 user_cred = self.get_user_cred()
802 rec_file = self.get_record_file(args[0])
803 record = load_record_from_file(rec_file)
804 if record['type'] == "user":
805 if record.get_name() == user_cred.get_gid_object().get_hrn():
806 cred = user_cred.save_to_string(save_parents=True)
808 cred = self.get_auth_cred().save_to_string(save_parents=True)
809 elif record['type'] in ["slice"]:
811 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
812 except xmlrpcprotocol.ServerException, e:
813 # XXX smbaker -- once we have better error return codes, update this
814 # to do something better than a string compare
815 if "Permission error" in e.args[0]:
816 cred = self.get_auth_cred().save_to_string(save_parents=True)
819 elif record.get_type() in ["authority"]:
820 cred = self.get_auth_cred().save_to_string(save_parents=True)
821 elif record.get_type() == 'node':
822 cred = self.get_auth_cred().save_to_string(save_parents=True)
824 raise "unknown record type" + record.get_type()
825 record = record.as_dict()
826 return self.registry.Update(record, cred)
828 def get_trusted_certs(self, opts, args):
830 return uhe trusted certs at this interface
832 trusted_certs = self.registry.get_trusted_certs()
833 for trusted_cert in trusted_certs:
834 gid = GID(string=trusted_cert)
836 cert = Certificate(string=trusted_cert)
837 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
840 def aggregates(self, opts, args):
842 return a list of details about known aggregates
844 user_cred = self.get_user_cred().save_to_string(save_parents=True)
849 result = self.registry.get_aggregates(user_cred, hrn)
853 def registries(self, opts, args):
855 return a list of details about known registries
857 user_cred = self.get_user_cred().save_to_string(save_parents=True)
861 result = self.registry.get_registries(user_cred, hrn)
866 # ==================================================================
867 # Slice-related commands
868 # ==================================================================
870 def version(self, opts, args):
871 if opts.version_local:
872 version=version_core()
874 if opts.version_registry:
877 server = self.get_server_from_opts(opts)
878 version=server.GetVersion()
879 for (k,v) in version.iteritems():
880 print "%-20s: %s"%(k,v)
882 # list instantiated slices
883 def slices(self, opts, args):
885 list instantiated slices
887 user_cred = self.get_user_cred().save_to_string(save_parents=True)
890 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
891 creds.append(delegated_cred)
892 server = self.get_server_from_opts(opts)
893 #results = server.ListSlices(creds, unique_call_id())
894 results = server.ListSlices(creds)
895 display_list(results)
898 # show rspec for named slice
899 def resources(self, opts, args):
900 user_cred = self.get_user_cred().save_to_string(save_parents=True)
901 server = self.slicemgr
903 server = self.get_server_from_opts(opts)
906 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
908 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
915 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
916 creds.append(delegated_cred)
917 if opts.rspec_version:
918 server_version = self.get_cached_server_version(server)
919 if 'sfa' in server_version:
920 # just request the version the client wants
921 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
923 # this must be a protogeni aggregate. We should request a v2 ad rspec
924 # regardless of what the client user requested
925 call_options['rspec_version'] = dict(pg_rspec_request_version)
926 #panos add info options
928 call_options['info'] = opts.info
930 call_args = [creds, call_options]
931 if self.server_supports_call_id_arg(server):
932 call_args.append(unique_call_id())
933 result = server.ListResources(*call_args)
935 if opts.file is None:
936 display_rspec(result, format)
939 if not file.startswith(os.sep):
940 file = os.path.join(self.options.sfi_dir, file)
941 save_rspec_to_file(result, file)
944 # created named slice with given rspec
945 def create(self, opts, args):
946 server = self.get_server_from_opts(opts)
947 server_version = self.get_cached_server_version(server)
949 slice_urn = hrn_to_urn(slice_hrn, 'slice')
950 user_cred = self.get_user_cred()
951 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
954 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
955 creds.append(delegated_cred)
956 rspec_file = self.get_rspec_file(args[1])
957 rspec = open(rspec_file).read()
959 # need to pass along user keys to the aggregate.
961 # { urn: urn:publicid:IDN+emulab.net+user+alice
962 # keys: [<ssh key A>, <ssh key B>]
967 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
968 if slice_records and 'researcher' in slice_records[0]:
969 slice_record = slice_records[0]
970 user_hrns = slice_record['researcher']
971 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
972 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
973 for user_record in user_records:
974 #user = {'urn': user_cred.get_gid_caller().get_urn(),'keys': []}
975 user = {'urn': user_cred.get_gid_caller().get_urn(), #
976 'keys': user_record['keys'],
977 'email': user_record['email'], # needed for MyPLC
978 'person_id': user_record['person_id'], # needed for MyPLC
979 'first_name': user_record['first_name'], # needed for MyPLC
980 'last_name': user_record['last_name'], # needed for MyPLC
981 'slice_record': slice_record, # needed for legacy refresh peer
982 'key_ids': user_record['key_ids'] # needed for legacy refresh peer
985 all_keys.extend(user_record['keys'])
986 all_key_ids.extend(user_record['key_ids'])
987 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
988 # request. So we will add all to the current caller's list of keys
989 if 'sfa' not in server_version:
991 if user['urn'] == user_cred.get_gid_caller().get_urn():
992 user['keys'] = all_keys
994 call_args = [slice_urn, creds, rspec, users]
995 if self.server_supports_call_id_arg(server):
996 call_args.append(unique_call_id())
998 result = server.CreateSliver(*call_args)
1002 # get a ticket for the specified slice
1003 def get_ticket(self, opts, args):
1004 slice_hrn, rspec_path = args[0], args[1]
1005 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1006 user_cred = self.get_user_cred()
1007 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1008 creds = [slice_cred]
1010 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1011 creds.append(delegated_cred)
1012 rspec_file = self.get_rspec_file(rspec_path)
1013 rspec = open(rspec_file).read()
1014 server = self.get_server_from_opts(opts)
1015 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1016 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1017 self.logger.info("writing ticket to %s"%file)
1018 ticket = SfaTicket(string=ticket_string)
1019 ticket.save_to_file(filename=file, save_parents=True)
1021 def redeem_ticket(self, opts, args):
1022 ticket_file = args[0]
1024 # get slice hrn from the ticket
1025 # use this to get the right slice credential
1026 ticket = SfaTicket(filename=ticket_file)
1028 slice_hrn = ticket.gidObject.get_hrn()
1029 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1030 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1031 user_cred = self.get_user_cred()
1032 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1034 # get a list of node hostnames from the RSpec
1035 tree = etree.parse(StringIO(ticket.rspec))
1036 root = tree.getroot()
1037 hostnames = root.xpath("./network/site/node/hostname/text()")
1039 # create an xmlrpc connection to the component manager at each of these
1040 # components and gall redeem_ticket
1042 for hostname in hostnames:
1044 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1045 server = self.get_server(hostname, CM_PORT, self.key_file, \
1046 self.cert_file, self.options.debug)
1047 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1048 self.logger.info("Success")
1049 except socket.gaierror:
1050 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1051 except Exception, e:
1052 self.logger.log_exc(e.message)
1055 # delete named slice
1056 def delete(self, opts, args):
1058 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1059 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1060 creds = [slice_cred]
1062 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1063 creds.append(delegated_cred)
1064 server = self.get_server_from_opts(opts)
1066 call_args = [slice_urn, creds]
1067 if self.server_supports_call_id_arg(server):
1068 call_args.append(unique_call_id())
1069 return server.DeleteSliver(*call_args)
1072 def start(self, opts, args):
1074 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1075 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1076 creds = [slice_cred]
1078 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1079 creds.append(delegated_cred)
1080 server = self.get_server_from_opts(opts)
1081 return server.Start(slice_urn, creds)
1084 def stop(self, opts, args):
1086 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1087 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1088 creds = [slice_cred]
1090 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1091 creds.append(delegated_cred)
1092 server = self.get_server_from_opts(opts)
1093 return server.Stop(slice_urn, creds)
1096 def reset(self, opts, args):
1098 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1099 server = self.get_server_from_opts(opts)
1100 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1101 creds = [slice_cred]
1103 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1104 creds.append(delegated_cred)
1105 return server.reset_slice(creds, slice_urn)
1107 def renew(self, opts, args):
1109 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1110 server = self.get_server_from_opts(opts)
1111 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1112 creds = [slice_cred]
1114 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1115 creds.append(delegated_cred)
1118 call_args = [slice_urn, creds, time]
1119 if self.server_supports_call_id_arg(server):
1120 call_args.append(unique_call_id())
1121 return server.RenewSliver(*call_args)
1124 def status(self, opts, args):
1126 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1127 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1128 creds = [slice_cred]
1130 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1131 creds.append(delegated_cred)
1132 server = self.get_server_from_opts(opts)
1133 call_args = [slice_urn, creds]
1134 if self.server_supports_call_id_arg(server):
1135 call_args.append(unique_call_id())
1136 print server.SliverStatus(*call_args)
1139 def shutdown(self, opts, args):
1141 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1142 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1143 creds = [slice_cred]
1145 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1146 creds.append(delegated_cred)
1147 server = self.get_server_from_opts(opts)
1148 return server.Shutdown(slice_urn, creds)
1150 def print_help (self):
1151 self.sfi_parser.print_help()
1152 self.cmd_parser.print_help()
1155 # Main: parse arguments and dispatch to command
1158 self.sfi_parser = self.create_parser()
1159 (options, args) = self.sfi_parser.parse_args()
1160 self.options = options
1162 self.logger.setLevelFromOptVerbose(self.options.verbose)
1163 if options.hashrequest:
1164 self.hashrequest = True
1167 self.logger.critical("No command given. Use -h for help.")
1171 self.cmd_parser = self.create_cmd_parser(command)
1172 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1175 self.logger.info("Command=%s" % command)
1176 if command in ("resources"):
1177 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1178 elif command in ("list", "show", "remove"):
1179 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1180 self.logger.debug('cmd_args %s' % cmd_args)
1183 self.dispatch(command, cmd_opts, cmd_args)
1185 self.logger.critical ("Unknown command %s"%command)
1190 if __name__ == "__main__":