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 self.sfi_dir = options.sfi_dir
140 self.options = options
144 self.authority = None
145 self.hashrequest = False
146 self.logger = sfi_logger
147 self.logger.enable_console()
149 def create_cmd_parser(self, command, additional_cmdargs=None):
150 cmdargs = {"list": "authority",
155 "aggregates": "[name]",
156 "registries": "[name]",
157 "create_gid": "[name]",
159 "get_trusted_certs": "cred",
161 "resources": "[name]",
162 "create": "name rspec",
163 "get_ticket": "name rspec",
164 "redeem_ticket": "ticket",
176 if additional_cmdargs:
177 cmdargs.update(additional_cmdargs)
179 if command not in cmdargs:
180 msg="Invalid command\n"
182 msg += ','.join(cmdargs.keys())
183 self.logger.critical(msg)
186 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
187 % (command, cmdargs[command]))
189 # user specifies remote aggregate/sm/component
190 if command in ("resources", "slices", "create", "delete", "start", "stop",
191 "restart", "shutdown", "get_ticket", "renew", "status"):
192 parser.add_option("-a", "--aggregate", dest="aggregate",
193 default=None, help="aggregate host")
194 parser.add_option("-p", "--port", dest="port",
195 default=AGGREGATE_PORT, help="aggregate port")
196 parser.add_option("-c", "--component", dest="component", default=None,
197 help="component hrn")
198 parser.add_option("-d", "--delegate", dest="delegate", default=None,
200 help="Include a credential delegated to the user's root"+\
201 "authority in set of credentials for this call")
203 # registy filter option
204 if command in ("list", "show", "remove"):
205 parser.add_option("-t", "--type", dest="type", type="choice",
206 help="type filter ([all]|user|slice|authority|node|aggregate)",
207 choices=("all", "user", "slice", "authority", "node", "aggregate"),
210 if command in ("resources"):
211 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
212 help="schema type and version of resulting RSpec")
213 parser.add_option("-f", "--format", dest="format", type="choice",
214 help="display format ([xml]|dns|ip)", default="xml",
215 choices=("xml", "dns", "ip"))
216 #panos: a new option to define the type of information about resources a user is interested in
217 parser.add_option("-i", "--info", dest="info",
218 help="optional component information", default=None)
221 if command in ("resources", "show", "list", "create_gid"):
222 parser.add_option("-o", "--output", dest="file",
223 help="output XML to file", metavar="FILE", default=None)
225 if command in ("show", "list"):
226 parser.add_option("-f", "--format", dest="format", type="choice",
227 help="display format ([text]|xml)", default="text",
228 choices=("text", "xml"))
230 if command in ("delegate"):
231 parser.add_option("-u", "--user",
232 action="store_true", dest="delegate_user", default=False,
233 help="delegate user credential")
234 parser.add_option("-s", "--slice", dest="delegate_slice",
235 help="delegate slice credential", metavar="HRN", default=None)
237 if command in ("version"):
238 parser.add_option("-a", "--aggregate", dest="aggregate",
239 default=None, help="aggregate host")
240 parser.add_option("-p", "--port", dest="port",
241 default=AGGREGATE_PORT, help="aggregate port")
242 parser.add_option("-R","--registry-version",
243 action="store_true", dest="version_registry", default=False,
244 help="probe registry version instead of slicemgr")
245 parser.add_option("-l","--local",
246 action="store_true", dest="version_local", default=False,
247 help="display version of the local client")
252 def create_parser(self):
254 # Generate command line parser
255 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
256 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
257 parser.add_option("-r", "--registry", dest="registry",
258 help="root registry", metavar="URL", default=None)
259 parser.add_option("-s", "--slicemgr", dest="sm",
260 help="slice manager", metavar="URL", default=None)
261 default_sfi_dir = os.path.expanduser("~/.sfi/")
262 parser.add_option("-d", "--dir", dest="sfi_dir",
263 help="config & working directory - default is " + default_sfi_dir,
264 metavar="PATH", default=default_sfi_dir)
265 parser.add_option("-u", "--user", dest="user",
266 help="user name", metavar="HRN", default=None)
267 parser.add_option("-a", "--auth", dest="auth",
268 help="authority name", metavar="HRN", default=None)
269 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
270 help="verbose mode - cumulative")
271 parser.add_option("-D", "--debug",
272 action="store_true", dest="debug", default=False,
273 help="Debug (xml-rpc) protocol messages")
274 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
275 help="RPC protocol (xmlrpc or soap)")
276 parser.add_option("-k", "--hashrequest",
277 action="store_true", dest="hashrequest", default=False,
278 help="Create a hash of the request that will be authenticated on the server")
279 parser.add_option("-t", "--timeout", dest="timeout", default=None,
280 help="Amout of time tom wait before timing out the request")
281 parser.disable_interspersed_args()
286 def read_config(self):
287 config_file = self.options.sfi_dir + os.sep + "sfi_config"
289 config = Config (config_file)
291 self.logger.critical("Failed to read configuration file %s"%config_file)
292 self.logger.info("Make sure to remove the export clauses and to add quotes")
293 if self.options.verbose==0:
294 self.logger.info("Re-run with -v for more details")
296 self.logger.log_exc("Could not read config file %s"%config_file)
301 if (self.options.sm is not None):
302 self.sm_url = self.options.sm
303 elif hasattr(config, "SFI_SM"):
304 self.sm_url = config.SFI_SM
306 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
310 if (self.options.registry is not None):
311 self.reg_url = self.options.registry
312 elif hasattr(config, "SFI_REGISTRY"):
313 self.reg_url = config.SFI_REGISTRY
315 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
320 if (self.options.user is not None):
321 self.user = self.options.user
322 elif hasattr(config, "SFI_USER"):
323 self.user = config.SFI_USER
325 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
329 if (self.options.auth is not None):
330 self.authority = self.options.auth
331 elif hasattr(config, "SFI_AUTH"):
332 self.authority = config.SFI_AUTH
334 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
342 # Establish Connection to SliceMgr and Registry Servers
344 def set_servers(self):
347 # Get key and certificate
348 key_file = self.get_key_file()
349 cert_file = self.get_cert_file(key_file)
350 self.key = Keypair(filename=key_file)
351 self.key_file = key_file
352 self.cert_file = cert_file
353 self.cert = GID(filename=cert_file)
354 self.logger.info("Contacting Registry at: %s"%self.reg_url)
355 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
356 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
357 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
360 def get_cached_server_version(self, server):
361 # check local cache first
364 cache_file = self.sfi_dir + os.path.sep + 'sfi_cache.dat'
365 cache_key = server.url + "-version"
367 cache = Cache(cache_file)
370 self.logger.info("Local cache not found at: %s" % cache_file)
373 version = cache.get(cache_key)
376 version = server.GetVersion()
377 # cache version for 24 hours
378 cache.add(cache_key, version, ttl= 60*60*24)
379 self.logger.info("Updating cache file %s" % cache_file)
380 cache.save_to_file(cache_file)
386 def server_supports_call_id_arg(self, server):
388 Returns true if server support the optional call_id arg, false otherwise.
390 server_version = self.get_cached_server_version(server)
391 if 'sfa' in server_version:
392 code_tag = server_version['code_tag']
393 code_tag_parts = code_tag.split("-")
395 version_parts = code_tag_parts[0].split(".")
396 major, minor = version_parts[0], version_parts[1]
397 rev = code_tag_parts[1]
399 if int(minor) > 0 or int(rev) > 20:
404 # Get various credential and spec files
406 # Establishes limiting conventions
407 # - conflates MAs and SAs
408 # - assumes last token in slice name is unique
410 # Bootstraps credentials
411 # - bootstrap user credential from self-signed certificate
412 # - bootstrap authority credential from user credential
413 # - bootstrap slice credential from user credential
417 def get_key_file(self):
418 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
419 if (os.path.isfile(file)):
422 self.logger.error("Key file %s does not exist"%file)
426 def get_cert_file(self, key_file):
428 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
429 if (os.path.isfile(cert_file)):
430 # we'd perfer to use Registry issued certs instead of self signed certs.
431 # if this is a Registry cert (GID) then we are done
432 gid = GID(filename=cert_file)
436 # generate self signed certificate
437 k = Keypair(filename=key_file)
438 cert = Certificate(subject=self.user)
440 cert.set_issuer(k, self.user)
442 self.logger.info("Writing self-signed certificate to %s"%cert_file)
443 cert.save_to_file(cert_file)
445 # try to get registry issued cert
447 self.logger.info("Getting Registry issued cert")
449 # *hack. need to set registyr before _get_gid() is called
450 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
451 gid = self._get_gid(type='user')
453 self.logger.info("Writing certificate to %s"%cert_file)
454 gid.save_to_file(cert_file)
456 self.logger.info("Failed to download Registry issued cert")
460 def get_cached_gid(self, file):
465 if (os.path.isfile(file)):
466 gid = GID(filename=file)
470 def get_gid(self, opts, args):
472 Get the specify gid and save it to file
477 gid = self._get_gid(hrn)
478 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
481 def _get_gid(self, hrn=None, type=None):
483 git_gid helper. Retrive the gid from the registry and save it to file.
489 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
491 gid = self.get_cached_gid(gidfile)
493 user_cred = self.get_user_cred()
494 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
496 raise RecordNotFound(args[0])
501 if type == rec['type']:
504 raise RecordNotFound(args[0])
506 gid = GID(string=record['gid'])
507 self.logger.info("Writing gid to %s"%gidfile)
508 gid.save_to_file(filename=gidfile)
512 def get_cached_credential(self, file):
514 Return a cached credential only if it hasn't expired.
516 if (os.path.isfile(file)):
517 credential = Credential(filename=file)
518 # make sure it isnt expired
519 if not credential.get_expiration or \
520 datetime.datetime.today() < credential.get_expiration():
524 def get_user_cred(self):
525 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
526 return self.get_cred(file, 'user', self.user)
528 def get_auth_cred(self):
529 if not self.authority:
530 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
532 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
533 return self.get_cred(file, 'authority', self.authority)
535 def get_slice_cred(self, name):
536 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
537 return self.get_cred(file, 'slice', name)
539 def get_cred(self, file, type, hrn):
540 # attempt to load a cached credential
541 cred = self.get_cached_credential(file)
544 cert_string = self.cert.save_to_string(save_parents=True)
545 user_name = self.user.replace(self.authority + ".", '')
546 if user_name.count(".") > 0:
547 user_name = user_name.replace(".", '_')
548 self.user = self.authority + "." + user_name
549 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
551 # bootstrap slice credential from user credential
552 user_cred = self.get_user_cred().save_to_string(save_parents=True)
553 cred_str = self.registry.GetCredential(user_cred, hrn, type)
556 self.logger.critical("Failed to get %s credential" % type)
559 cred = Credential(string=cred_str)
560 cred.save_to_file(file, save_parents=True)
561 self.logger.info("Writing %s credential to %s" %(type, file))
566 def get_rspec_file(self, rspec):
567 if (os.path.isabs(rspec)):
570 file = os.path.join(self.options.sfi_dir, rspec)
571 if (os.path.isfile(file)):
574 self.logger.critical("No such rspec file %s"%rspec)
577 def get_record_file(self, record):
578 if (os.path.isabs(record)):
581 file = os.path.join(self.options.sfi_dir, record)
582 if (os.path.isfile(file)):
585 self.logger.critical("No such registry record file %s"%record)
588 def load_publickey_string(self, fn):
590 key_string = f.read()
592 # if the filename is a private key file, then extract the public key
593 if "PRIVATE KEY" in key_string:
594 outfn = tempfile.mktemp()
595 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
598 key_string = f.read()
604 def get_component_server_from_hrn(self, hrn):
605 # direct connection to the nodes component manager interface
606 user_cred = self.get_user_cred().save_to_string(save_parents=True)
607 records = self.registry.Resolve(hrn, user_cred)
608 records = filter_records('node', records)
610 self.logger.warning("No such component:%r"% opts.component)
613 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
615 def get_server(self, host, port, keyfile, certfile):
617 Return an instance of an xmlrpc server connection
619 # port is appended onto the domain, before the path. Should look like:
620 # http://domain:port/path
621 host_parts = host.split('/')
622 host_parts[0] = host_parts[0] + ":" + str(port)
623 url = "http://%s" % "/".join(host_parts)
624 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
626 # xxx opts could be retrieved in self.options
627 def get_server_from_opts(self, opts):
629 Return instance of an xmlrpc connection to a slice manager, aggregate
630 or component server depending on the specified opts
632 server = self.slicemgr
633 # direct connection to an aggregate
634 if hasattr(opts, 'aggregate') and opts.aggregate:
635 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
636 # direct connection to the nodes component manager interface
637 if hasattr(opts, 'component') and opts.component:
638 server = self.get_component_server_from_hrn(opts.component)
641 #==========================================================================
642 # Following functions implement the commands
644 # Registry-related commands
645 #==========================================================================
647 def dispatch(self, command, cmd_opts, cmd_args):
648 return getattr(self, command)(cmd_opts, cmd_args)
650 def create_gid(self, opts, args):
655 user_cred = self.get_user_cred().save_to_string(save_parents=True)
656 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
660 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
661 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
662 GID(string=gid).save_to_file(filename)
665 # list entires in named authority registry
666 def list(self, opts, args):
671 user_cred = self.get_user_cred().save_to_string(save_parents=True)
673 list = self.registry.List(hrn, user_cred)
675 raise Exception, "Not enough parameters for the 'list' command"
677 # filter on person, slice, site, node, etc.
678 # THis really should be in the self.filter_records funct def comment...
679 list = filter_records(opts.type, list)
681 print "%s (%s)" % (record['hrn'], record['type'])
684 if not file.startswith(os.sep):
685 file = os.path.join(self.options.sfi_dir, file)
686 save_records_to_file(file, list)
689 # show named registry record
690 def show(self, opts, args):
695 user_cred = self.get_user_cred().save_to_string(save_parents=True)
696 records = self.registry.Resolve(hrn, user_cred)
697 records = filter_records(opts.type, records)
699 print "No record of type", opts.type
700 for record in records:
701 if record['type'] in ['user']:
702 record = UserRecord(dict=record)
703 elif record['type'] in ['slice']:
704 record = SliceRecord(dict=record)
705 elif record['type'] in ['node']:
706 record = NodeRecord(dict=record)
707 elif record['type'].startswith('authority'):
708 record = AuthorityRecord(dict=record)
710 record = SfaRecord(dict=record)
711 if (opts.format == "text"):
714 print record.save_to_string()
717 if not file.startswith(os.sep):
718 file = os.path.join(self.options.sfi_dir, file)
719 save_records_to_file(file, records)
722 def delegate(self, opts, args):
724 delegee_hrn = args[0]
725 if opts.delegate_user:
726 user_cred = self.get_user_cred()
727 cred = self.delegate_cred(user_cred, delegee_hrn)
728 elif opts.delegate_slice:
729 slice_cred = self.get_slice_cred(opts.delegate_slice)
730 cred = self.delegate_cred(slice_cred, delegee_hrn)
732 self.logger.warning("Must specify either --user or --slice <hrn>")
734 delegated_cred = Credential(string=cred)
735 object_hrn = delegated_cred.get_gid_object().get_hrn()
736 if opts.delegate_user:
737 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
738 + get_leaf(object_hrn) + ".cred")
739 elif opts.delegate_slice:
740 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
741 + get_leaf(object_hrn) + ".cred")
743 delegated_cred.save_to_file(dest_fn, save_parents=True)
745 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
747 def delegate_cred(self, object_cred, hrn):
748 # the gid and hrn of the object we are delegating
749 if isinstance(object_cred, str):
750 object_cred = Credential(string=object_cred)
751 object_gid = object_cred.get_gid_object()
752 object_hrn = object_gid.get_hrn()
754 if not object_cred.get_privileges().get_all_delegate():
755 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
758 # the delegating user's gid
759 caller_gid = self._get_gid(self.user)
760 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
762 # the gid of the user who will be delegated to
763 delegee_gid = self._get_gid(hrn)
764 delegee_hrn = delegee_gid.get_hrn()
765 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
766 delegee_gid.save_to_file(filename=delegee_gidfile)
767 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
768 return dcred.save_to_string(save_parents=True)
770 # removed named registry record
771 # - have to first retrieve the record to be removed
772 def remove(self, opts, args):
773 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
781 return self.registry.Remove(hrn, auth_cred, type)
783 # add named registry record
784 def add(self, opts, args):
785 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
789 record_filepath = args[0]
790 rec_file = self.get_record_file(record_filepath)
791 record = load_record_from_file(rec_file).as_dict()
792 return self.registry.Register(record, auth_cred)
794 # update named registry entry
795 def update(self, opts, args):
796 user_cred = self.get_user_cred()
800 rec_file = self.get_record_file(args[0])
801 record = load_record_from_file(rec_file)
802 if record['type'] == "user":
803 if record.get_name() == user_cred.get_gid_object().get_hrn():
804 cred = user_cred.save_to_string(save_parents=True)
806 cred = self.get_auth_cred().save_to_string(save_parents=True)
807 elif record['type'] in ["slice"]:
809 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
810 except xmlrpcprotocol.ServerException, e:
811 # XXX smbaker -- once we have better error return codes, update this
812 # to do something better than a string compare
813 if "Permission error" in e.args[0]:
814 cred = self.get_auth_cred().save_to_string(save_parents=True)
817 elif record.get_type() in ["authority"]:
818 cred = self.get_auth_cred().save_to_string(save_parents=True)
819 elif record.get_type() == 'node':
820 cred = self.get_auth_cred().save_to_string(save_parents=True)
822 raise "unknown record type" + record.get_type()
823 record = record.as_dict()
824 return self.registry.Update(record, cred)
826 def get_trusted_certs(self, opts, args):
828 return uhe trusted certs at this interface
830 trusted_certs = self.registry.get_trusted_certs()
831 for trusted_cert in trusted_certs:
832 gid = GID(string=trusted_cert)
834 cert = Certificate(string=trusted_cert)
835 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
838 def aggregates(self, opts, args):
840 return a list of details about known aggregates
842 user_cred = self.get_user_cred().save_to_string(save_parents=True)
847 result = self.registry.get_aggregates(user_cred, hrn)
851 def registries(self, opts, args):
853 return a list of details about known registries
855 user_cred = self.get_user_cred().save_to_string(save_parents=True)
859 result = self.registry.get_registries(user_cred, hrn)
864 # ==================================================================
865 # Slice-related commands
866 # ==================================================================
868 def version(self, opts, args):
869 if opts.version_local:
870 version=version_core()
872 if opts.version_registry:
875 server = self.get_server_from_opts(opts)
876 version=server.GetVersion()
877 for (k,v) in version.iteritems():
878 print "%-20s: %s"%(k,v)
880 # list instantiated slices
881 def slices(self, opts, args):
883 list instantiated slices
885 user_cred = self.get_user_cred().save_to_string(save_parents=True)
888 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
889 creds.append(delegated_cred)
890 server = self.get_server_from_opts(opts)
891 #results = server.ListSlices(creds, unique_call_id())
892 results = server.ListSlices(creds)
893 display_list(results)
896 # show rspec for named slice
897 def resources(self, opts, args):
898 user_cred = self.get_user_cred().save_to_string(save_parents=True)
899 server = self.slicemgr
901 server = self.get_server_from_opts(opts)
904 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
906 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
913 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
914 creds.append(delegated_cred)
915 if opts.rspec_version:
916 server_version = self.get_cached_server_version(server)
917 if 'sfa' in server_version:
918 # just request the version the client wants
919 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
921 # this must be a protogeni aggregate. We should request a v2 ad rspec
922 # regardless of what the client user requested
923 call_options['rspec_version'] = dict(pg_rspec_request_version)
924 #panos add info options
926 call_options['info'] = opts.info
928 call_args = [creds, call_options]
929 if self.server_supports_call_id_arg(server):
930 call_args.append(unique_call_id())
931 result = server.ListResources(*call_args)
933 if opts.file is None:
934 display_rspec(result, format)
937 if not file.startswith(os.sep):
938 file = os.path.join(self.options.sfi_dir, file)
939 save_rspec_to_file(result, file)
942 # created named slice with given rspec
943 def create(self, opts, args):
944 server = self.get_server_from_opts(opts)
945 server_version = self.get_cached_server_version(server)
947 slice_urn = hrn_to_urn(slice_hrn, 'slice')
948 user_cred = self.get_user_cred()
949 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
952 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
953 creds.append(delegated_cred)
954 rspec_file = self.get_rspec_file(args[1])
955 rspec = open(rspec_file).read()
957 # need to pass along user keys to the aggregate.
959 # { urn: urn:publicid:IDN+emulab.net+user+alice
960 # keys: [<ssh key A>, <ssh key B>]
965 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
966 if slice_records and 'researcher' in slice_records[0]:
967 slice_record = slice_records[0]
968 user_hrns = slice_record['researcher']
969 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
970 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
971 for user_record in user_records:
972 #user = {'urn': user_cred.get_gid_caller().get_urn(),'keys': []}
973 user = {'urn': user_cred.get_gid_caller().get_urn(), #
974 'keys': user_record['keys'],
975 'email': user_record['email'], # needed for MyPLC
976 'person_id': user_record['person_id'], # needed for MyPLC
977 'first_name': user_record['first_name'], # needed for MyPLC
978 'last_name': user_record['last_name'], # needed for MyPLC
979 'slice_record': slice_record, # needed for legacy refresh peer
980 'key_ids': user_record['key_ids'] # needed for legacy refresh peer
983 all_keys.extend(user_record['keys'])
984 all_key_ids.extend(user_record['key_ids'])
985 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
986 # request. So we will add all to the current caller's list of keys
987 if 'sfa' not in server_version:
989 if user['urn'] == user_cred.get_gid_caller().get_urn():
990 user['keys'] = all_keys
992 call_args = [slice_urn, creds, rspec, users]
993 if self.server_supports_call_id_arg(server):
994 call_args.append(unique_call_id())
996 result = server.CreateSliver(*call_args)
1000 # get a ticket for the specified slice
1001 def get_ticket(self, opts, args):
1002 slice_hrn, rspec_path = args[0], args[1]
1003 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1004 user_cred = self.get_user_cred()
1005 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1006 creds = [slice_cred]
1008 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1009 creds.append(delegated_cred)
1010 rspec_file = self.get_rspec_file(rspec_path)
1011 rspec = open(rspec_file).read()
1012 server = self.get_server_from_opts(opts)
1013 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1014 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1015 self.logger.info("writing ticket to %s"%file)
1016 ticket = SfaTicket(string=ticket_string)
1017 ticket.save_to_file(filename=file, save_parents=True)
1019 def redeem_ticket(self, opts, args):
1020 ticket_file = args[0]
1022 # get slice hrn from the ticket
1023 # use this to get the right slice credential
1024 ticket = SfaTicket(filename=ticket_file)
1026 slice_hrn = ticket.gidObject.get_hrn()
1027 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1028 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1029 user_cred = self.get_user_cred()
1030 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1032 # get a list of node hostnames from the RSpec
1033 tree = etree.parse(StringIO(ticket.rspec))
1034 root = tree.getroot()
1035 hostnames = root.xpath("./network/site/node/hostname/text()")
1037 # create an xmlrpc connection to the component manager at each of these
1038 # components and gall redeem_ticket
1040 for hostname in hostnames:
1042 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1043 server = self.get_server(hostname, CM_PORT, self.key_file, \
1044 self.cert_file, self.options.debug)
1045 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1046 self.logger.info("Success")
1047 except socket.gaierror:
1048 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1049 except Exception, e:
1050 self.logger.log_exc(e.message)
1053 # delete named slice
1054 def delete(self, opts, args):
1056 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1057 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1058 creds = [slice_cred]
1060 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1061 creds.append(delegated_cred)
1062 server = self.get_server_from_opts(opts)
1064 call_args = [slice_urn, creds]
1065 if self.server_supports_call_id_arg(server):
1066 call_args.append(unique_call_id())
1067 return server.DeleteSliver(*call_args)
1070 def start(self, opts, args):
1072 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1073 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1074 creds = [slice_cred]
1076 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1077 creds.append(delegated_cred)
1078 server = self.get_server_from_opts(opts)
1079 return server.Start(slice_urn, creds)
1082 def stop(self, opts, args):
1084 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1085 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1086 creds = [slice_cred]
1088 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1089 creds.append(delegated_cred)
1090 server = self.get_server_from_opts(opts)
1091 return server.Stop(slice_urn, creds)
1094 def reset(self, opts, args):
1096 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1097 server = self.get_server_from_opts(opts)
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 return server.reset_slice(creds, slice_urn)
1105 def renew(self, opts, args):
1107 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1108 server = self.get_server_from_opts(opts)
1109 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1110 creds = [slice_cred]
1112 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1113 creds.append(delegated_cred)
1116 call_args = [slice_urn, creds, time]
1117 if self.server_supports_call_id_arg(server):
1118 call_args.append(unique_call_id())
1119 return server.RenewSliver(*call_args)
1122 def status(self, opts, args):
1124 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1125 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1126 creds = [slice_cred]
1128 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1129 creds.append(delegated_cred)
1130 server = self.get_server_from_opts(opts)
1131 call_args = [slice_urn, creds]
1132 if self.server_supports_call_id_arg(server):
1133 call_args.append(unique_call_id())
1134 print server.SliverStatus(*call_args)
1137 def shutdown(self, opts, args):
1139 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1140 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1141 creds = [slice_cred]
1143 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1144 creds.append(delegated_cred)
1145 server = self.get_server_from_opts(opts)
1146 return server.Shutdown(slice_urn, creds)
1148 def print_help (self):
1149 self.sfi_parser.print_help()
1150 self.cmd_parser.print_help()
1153 # Main: parse arguments and dispatch to command
1156 self.sfi_parser = self.create_parser()
1157 (options, args) = self.sfi_parser.parse_args()
1158 self.options = options
1160 self.logger.setLevelFromOptVerbose(self.options.verbose)
1161 if options.hashrequest:
1162 self.hashrequest = True
1165 self.logger.critical("No command given. Use -h for help.")
1169 self.cmd_parser = self.create_cmd_parser(command)
1170 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1173 self.logger.info("Command=%s" % command)
1174 if command in ("resources"):
1175 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1176 elif command in ("list", "show", "remove"):
1177 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1178 self.logger.debug('cmd_args %s' % cmd_args)
1181 self.dispatch(command, cmd_opts, cmd_args)
1183 self.logger.critical ("Unknown command %s"%command)
1188 if __name__ == "__main__":