3 # sfi -- slice-based facility interface
15 from lxml import etree
16 from StringIO import StringIO
17 from types import StringTypes, ListType
18 from optparse import OptionParser
20 from sfa.util.sfalogging import sfi_logger
21 from sfa.trust.certificate import Keypair, Certificate
22 from sfa.trust.gid import GID
23 from sfa.trust.credential import Credential
24 from sfa.util.sfaticket import SfaTicket
25 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
26 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
27 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
28 from sfa.util.config import Config
29 from sfa.util.version import version_core
30 from sfa.util.cache import Cache
31 from sfa.rspecs.rspec_version import RSpecVersion
32 from sfa.rspecs.pg_rspec import pg_rspec_request_version
37 # utility methods here
39 def display_rspec(rspec, format='rspec'):
41 tree = etree.parse(StringIO(rspec))
43 result = root.xpath("./network/site/node/hostname/text()")
44 elif format in ['ip']:
45 # The IP address is not yet part of the new RSpec
46 # so this doesn't do anything yet.
47 tree = etree.parse(StringIO(rspec))
49 result = root.xpath("./network/site/node/ipv4/text()")
56 def display_list(results):
57 for result in results:
60 def display_records(recordList, dump=False):
61 ''' Print all fields in the record'''
62 for record in recordList:
63 display_record(record, dump)
65 def display_record(record, dump=False):
69 info = record.getdict()
70 print "%s (%s)" % (info['hrn'], info['type'])
74 def filter_records(type, records):
76 for record in records:
77 if (record['type'] == type) or (type == "all"):
78 filtered_records.append(record)
79 return filtered_records
83 def save_rspec_to_file(rspec, filename):
84 if not filename.endswith(".rspec"):
85 filename = filename + ".rspec"
87 f = open(filename, 'w')
92 def save_records_to_file(filename, recordList):
94 for record in recordList:
96 save_record_to_file(filename + "." + str(index), record)
98 save_record_to_file(filename, record)
101 def save_record_to_file(filename, record):
102 if record['type'] in ['user']:
103 record = UserRecord(dict=record)
104 elif record['type'] in ['slice']:
105 record = SliceRecord(dict=record)
106 elif record['type'] in ['node']:
107 record = NodeRecord(dict=record)
108 elif record['type'] in ['authority', 'ma', 'sa']:
109 record = AuthorityRecord(dict=record)
111 record = SfaRecord(dict=record)
112 str = record.save_to_string()
113 f=codecs.open(filename, encoding='utf-8',mode="w")
120 def load_record_from_file(filename):
121 f=codecs.open(filename, encoding="utf-8", mode="r")
124 record = SfaRecord(string=str)
129 def unique_call_id(): return uuid.uuid4().urn
133 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
135 # dummy to meet Sfi's expectations for its 'options' field
136 # i.e. s/t we can do setattr on
140 def __init__ (self,options=None):
141 if options is None: options=Sfi.DummyOptions()
142 for opt in Sfi.required_options:
143 if not hasattr(options,opt): setattr(options,opt,None)
144 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
145 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
146 # would be safer to remove self.sfi_dir altogether
147 self.sfi_dir = options.sfi_dir
148 self.options = options
152 self.authority = None
153 self.hashrequest = False
154 self.logger = sfi_logger
155 self.logger.enable_console()
157 def create_cmd_parser(self, command, additional_cmdargs=None):
158 cmdargs = {"list": "authority",
163 "aggregates": "[name]",
164 "registries": "[name]",
165 "create_gid": "[name]",
167 "get_trusted_certs": "cred",
169 "resources": "[name]",
170 "create": "name rspec",
171 "get_ticket": "name rspec",
172 "redeem_ticket": "ticket",
184 if additional_cmdargs:
185 cmdargs.update(additional_cmdargs)
187 if command not in cmdargs:
188 msg="Invalid command\n"
190 msg += ','.join(cmdargs.keys())
191 self.logger.critical(msg)
194 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
195 % (command, cmdargs[command]))
197 # user specifies remote aggregate/sm/component
198 if command in ("resources", "slices", "create", "delete", "start", "stop",
199 "restart", "shutdown", "get_ticket", "renew", "status"):
200 parser.add_option("-a", "--aggregate", dest="aggregate",
201 default=None, help="aggregate host")
202 parser.add_option("-p", "--port", dest="port",
203 default=AGGREGATE_PORT, help="aggregate port")
204 parser.add_option("-c", "--component", dest="component", default=None,
205 help="component hrn")
206 parser.add_option("-d", "--delegate", dest="delegate", default=None,
208 help="Include a credential delegated to the user's root"+\
209 "authority in set of credentials for this call")
211 # registy filter option
212 if command in ("list", "show", "remove"):
213 parser.add_option("-t", "--type", dest="type", type="choice",
214 help="type filter ([all]|user|slice|authority|node|aggregate)",
215 choices=("all", "user", "slice", "authority", "node", "aggregate"),
218 if command in ("resources"):
219 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
220 help="schema type and version of resulting RSpec")
221 parser.add_option("-f", "--format", dest="format", type="choice",
222 help="display format ([xml]|dns|ip)", default="xml",
223 choices=("xml", "dns", "ip"))
224 #panos: a new option to define the type of information about resources a user is interested in
225 parser.add_option("-i", "--info", dest="info",
226 help="optional component information", default=None)
229 if command in ("resources", "show", "list", "create_gid"):
230 parser.add_option("-o", "--output", dest="file",
231 help="output XML to file", metavar="FILE", default=None)
233 if command in ("show", "list"):
234 parser.add_option("-f", "--format", dest="format", type="choice",
235 help="display format ([text]|xml)", default="text",
236 choices=("text", "xml"))
238 if command in ("delegate"):
239 parser.add_option("-u", "--user",
240 action="store_true", dest="delegate_user", default=False,
241 help="delegate user credential")
242 parser.add_option("-s", "--slice", dest="delegate_slice",
243 help="delegate slice credential", metavar="HRN", default=None)
245 if command in ("version"):
246 parser.add_option("-a", "--aggregate", dest="aggregate",
247 default=None, help="aggregate host")
248 parser.add_option("-p", "--port", dest="port",
249 default=AGGREGATE_PORT, help="aggregate port")
250 parser.add_option("-R","--registry-version",
251 action="store_true", dest="version_registry", default=False,
252 help="probe registry version instead of slicemgr")
253 parser.add_option("-l","--local",
254 action="store_true", dest="version_local", default=False,
255 help="display version of the local client")
260 def create_parser(self):
262 # Generate command line parser
263 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
264 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
265 parser.add_option("-r", "--registry", dest="registry",
266 help="root registry", metavar="URL", default=None)
267 parser.add_option("-s", "--slicemgr", dest="sm",
268 help="slice manager", metavar="URL", default=None)
269 default_sfi_dir = os.path.expanduser("~/.sfi/")
270 parser.add_option("-d", "--dir", dest="sfi_dir",
271 help="config & working directory - default is " + default_sfi_dir,
272 metavar="PATH", default=default_sfi_dir)
273 parser.add_option("-u", "--user", dest="user",
274 help="user name", metavar="HRN", default=None)
275 parser.add_option("-a", "--auth", dest="auth",
276 help="authority name", metavar="HRN", default=None)
277 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
278 help="verbose mode - cumulative")
279 parser.add_option("-D", "--debug",
280 action="store_true", dest="debug", default=False,
281 help="Debug (xml-rpc) protocol messages")
282 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
283 help="RPC protocol (xmlrpc or soap)")
284 parser.add_option("-k", "--hashrequest",
285 action="store_true", dest="hashrequest", default=False,
286 help="Create a hash of the request that will be authenticated on the server")
287 parser.add_option("-t", "--timeout", dest="timeout", default=None,
288 help="Amout of time tom wait before timing out the request")
289 parser.disable_interspersed_args()
294 def read_config(self):
295 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
297 config = Config (config_file)
299 self.logger.critical("Failed to read configuration file %s"%config_file)
300 self.logger.info("Make sure to remove the export clauses and to add quotes")
301 if self.options.verbose==0:
302 self.logger.info("Re-run with -v for more details")
304 self.logger.log_exc("Could not read config file %s"%config_file)
309 if (self.options.sm is not None):
310 self.sm_url = self.options.sm
311 elif hasattr(config, "SFI_SM"):
312 self.sm_url = config.SFI_SM
314 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
318 if (self.options.registry is not None):
319 self.reg_url = self.options.registry
320 elif hasattr(config, "SFI_REGISTRY"):
321 self.reg_url = config.SFI_REGISTRY
323 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
328 if (self.options.user is not None):
329 self.user = self.options.user
330 elif hasattr(config, "SFI_USER"):
331 self.user = config.SFI_USER
333 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
337 if (self.options.auth is not None):
338 self.authority = self.options.auth
339 elif hasattr(config, "SFI_AUTH"):
340 self.authority = config.SFI_AUTH
342 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
350 # Establish Connection to SliceMgr and Registry Servers
352 def set_servers(self):
355 # Get key and certificate
356 key_file = self.get_key_file()
357 cert_file = self.get_cert_file(key_file)
358 self.key = Keypair(filename=key_file)
359 self.key_file = key_file
360 self.cert_file = cert_file
361 self.cert = GID(filename=cert_file)
362 self.logger.info("Contacting Registry at: %s"%self.reg_url)
363 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
364 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
365 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
368 def get_cached_server_version(self, server):
369 # check local cache first
372 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
373 cache_key = server.url + "-version"
375 cache = Cache(cache_file)
378 self.logger.info("Local cache not found at: %s" % cache_file)
381 version = cache.get(cache_key)
384 version = server.GetVersion()
385 # cache version for 24 hours
386 cache.add(cache_key, version, ttl= 60*60*24)
387 self.logger.info("Updating cache file %s" % cache_file)
388 cache.save_to_file(cache_file)
394 def server_supports_call_id_arg(self, server):
396 Returns true if server support the optional call_id arg, false otherwise.
398 server_version = self.get_cached_server_version(server)
399 if 'sfa' in server_version:
400 code_tag = server_version['code_tag']
401 code_tag_parts = code_tag.split("-")
403 version_parts = code_tag_parts[0].split(".")
404 major, minor = version_parts[0], version_parts[1]
405 rev = code_tag_parts[1]
407 if int(minor) > 0 or int(rev) > 20:
412 # Get various credential and spec files
414 # Establishes limiting conventions
415 # - conflates MAs and SAs
416 # - assumes last token in slice name is unique
418 # Bootstraps credentials
419 # - bootstrap user credential from self-signed certificate
420 # - bootstrap authority credential from user credential
421 # - bootstrap slice credential from user credential
425 def get_key_file(self):
426 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
427 if (os.path.isfile(file)):
430 self.logger.error("Key file %s does not exist"%file)
434 def get_cert_file(self, key_file):
436 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
437 if (os.path.isfile(cert_file)):
438 # we'd perfer to use Registry issued certs instead of self signed certs.
439 # if this is a Registry cert (GID) then we are done
440 gid = GID(filename=cert_file)
444 # generate self signed certificate
445 k = Keypair(filename=key_file)
446 cert = Certificate(subject=self.user)
448 cert.set_issuer(k, self.user)
450 self.logger.info("Writing self-signed certificate to %s"%cert_file)
451 cert.save_to_file(cert_file)
453 # try to get registry issued cert
455 self.logger.info("Getting Registry issued cert")
457 # *hack. need to set registyr before _get_gid() is called
458 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
459 gid = self._get_gid(type='user')
461 self.logger.info("Writing certificate to %s"%cert_file)
462 gid.save_to_file(cert_file)
464 self.logger.info("Failed to download Registry issued cert")
468 def get_cached_gid(self, file):
473 if (os.path.isfile(file)):
474 gid = GID(filename=file)
478 def get_gid(self, opts, args):
480 Get the specify gid and save it to file
485 gid = self._get_gid(hrn)
486 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
489 def _get_gid(self, hrn=None, type=None):
491 git_gid helper. Retrive the gid from the registry and save it to file.
497 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
499 gid = self.get_cached_gid(gidfile)
501 user_cred = self.get_user_cred()
502 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
504 raise RecordNotFound(args[0])
509 if type == rec['type']:
512 raise RecordNotFound(args[0])
514 gid = GID(string=record['gid'])
515 self.logger.info("Writing gid to %s"%gidfile)
516 gid.save_to_file(filename=gidfile)
520 def get_cached_credential(self, file):
522 Return a cached credential only if it hasn't expired.
524 if (os.path.isfile(file)):
525 credential = Credential(filename=file)
526 # make sure it isnt expired
527 if not credential.get_expiration or \
528 datetime.datetime.today() < credential.get_expiration():
532 def get_user_cred(self):
533 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
534 return self.get_cred(file, 'user', self.user)
536 def get_auth_cred(self):
537 if not self.authority:
538 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
540 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
541 return self.get_cred(file, 'authority', self.authority)
543 def get_slice_cred(self, name):
544 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
545 return self.get_cred(file, 'slice', name)
547 def get_cred(self, file, type, hrn):
548 # attempt to load a cached credential
549 cred = self.get_cached_credential(file)
552 cert_string = self.cert.save_to_string(save_parents=True)
553 user_name = self.user.replace(self.authority + ".", '')
554 if user_name.count(".") > 0:
555 user_name = user_name.replace(".", '_')
556 self.user = self.authority + "." + user_name
557 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
559 # bootstrap slice credential from user credential
560 user_cred = self.get_user_cred().save_to_string(save_parents=True)
561 cred_str = self.registry.GetCredential(user_cred, hrn, type)
564 self.logger.critical("Failed to get %s credential" % type)
567 cred = Credential(string=cred_str)
568 cred.save_to_file(file, save_parents=True)
569 self.logger.info("Writing %s credential to %s" %(type, file))
574 def get_rspec_file(self, rspec):
575 if (os.path.isabs(rspec)):
578 file = os.path.join(self.options.sfi_dir, rspec)
579 if (os.path.isfile(file)):
582 self.logger.critical("No such rspec file %s"%rspec)
585 def get_record_file(self, record):
586 if (os.path.isabs(record)):
589 file = os.path.join(self.options.sfi_dir, record)
590 if (os.path.isfile(file)):
593 self.logger.critical("No such registry record file %s"%record)
596 def load_publickey_string(self, fn):
598 key_string = f.read()
600 # if the filename is a private key file, then extract the public key
601 if "PRIVATE KEY" in key_string:
602 outfn = tempfile.mktemp()
603 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
606 key_string = f.read()
612 def get_component_server_from_hrn(self, hrn):
613 # direct connection to the nodes component manager interface
614 user_cred = self.get_user_cred().save_to_string(save_parents=True)
615 records = self.registry.Resolve(hrn, user_cred)
616 records = filter_records('node', records)
618 self.logger.warning("No such component:%r"% opts.component)
621 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
623 def get_server(self, host, port, keyfile, certfile):
625 Return an instance of an xmlrpc server connection
627 # port is appended onto the domain, before the path. Should look like:
628 # http://domain:port/path
629 host_parts = host.split('/')
630 host_parts[0] = host_parts[0] + ":" + str(port)
631 url = "http://%s" % "/".join(host_parts)
632 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
634 # xxx opts could be retrieved in self.options
635 def get_server_from_opts(self, opts):
637 Return instance of an xmlrpc connection to a slice manager, aggregate
638 or component server depending on the specified opts
640 server = self.slicemgr
641 # direct connection to an aggregate
642 if hasattr(opts, 'aggregate') and opts.aggregate:
643 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
644 # direct connection to the nodes component manager interface
645 if hasattr(opts, 'component') and opts.component:
646 server = self.get_component_server_from_hrn(opts.component)
649 #==========================================================================
650 # Following functions implement the commands
652 # Registry-related commands
653 #==========================================================================
655 def dispatch(self, command, cmd_opts, cmd_args):
656 return getattr(self, command)(cmd_opts, cmd_args)
658 def create_gid(self, opts, args):
663 user_cred = self.get_user_cred().save_to_string(save_parents=True)
664 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
668 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
669 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
670 GID(string=gid).save_to_file(filename)
673 # list entires in named authority registry
674 def list(self, opts, args):
679 user_cred = self.get_user_cred().save_to_string(save_parents=True)
681 list = self.registry.List(hrn, user_cred)
683 raise Exception, "Not enough parameters for the 'list' command"
685 # filter on person, slice, site, node, etc.
686 # THis really should be in the self.filter_records funct def comment...
687 list = filter_records(opts.type, list)
689 print "%s (%s)" % (record['hrn'], record['type'])
692 if not file.startswith(os.sep):
693 file = os.path.join(self.options.sfi_dir, file)
694 save_records_to_file(file, list)
697 # show named registry record
698 def show(self, opts, args):
703 user_cred = self.get_user_cred().save_to_string(save_parents=True)
704 records = self.registry.Resolve(hrn, user_cred)
706 records = filter_records(opts.type, records)
708 print "No record of type", opts.type
709 for record in records:
710 if record['type'] in ['user']:
711 record = UserRecord(dict=record)
712 elif record['type'] in ['slice']:
713 record = SliceRecord(dict=record)
714 elif record['type'] in ['node']:
715 record = NodeRecord(dict=record)
716 elif record['type'].startswith('authority'):
717 record = AuthorityRecord(dict=record)
719 record = SfaRecord(dict=record)
720 if (opts.format == "text"):
723 print record.save_to_string()
726 if not file.startswith(os.sep):
727 file = os.path.join(self.options.sfi_dir, file)
728 save_records_to_file(file, records)
731 def delegate(self, opts, args):
733 delegee_hrn = args[0]
734 if opts.delegate_user:
735 user_cred = self.get_user_cred()
736 cred = self.delegate_cred(user_cred, delegee_hrn)
737 elif opts.delegate_slice:
738 slice_cred = self.get_slice_cred(opts.delegate_slice)
739 cred = self.delegate_cred(slice_cred, delegee_hrn)
741 self.logger.warning("Must specify either --user or --slice <hrn>")
743 delegated_cred = Credential(string=cred)
744 object_hrn = delegated_cred.get_gid_object().get_hrn()
745 if opts.delegate_user:
746 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
747 + get_leaf(object_hrn) + ".cred")
748 elif opts.delegate_slice:
749 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
750 + get_leaf(object_hrn) + ".cred")
752 delegated_cred.save_to_file(dest_fn, save_parents=True)
754 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
756 def delegate_cred(self, object_cred, hrn):
757 # the gid and hrn of the object we are delegating
758 if isinstance(object_cred, str):
759 object_cred = Credential(string=object_cred)
760 object_gid = object_cred.get_gid_object()
761 object_hrn = object_gid.get_hrn()
763 if not object_cred.get_privileges().get_all_delegate():
764 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
767 # the delegating user's gid
768 caller_gid = self._get_gid(self.user)
769 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
771 # the gid of the user who will be delegated to
772 delegee_gid = self._get_gid(hrn)
773 delegee_hrn = delegee_gid.get_hrn()
774 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
775 delegee_gid.save_to_file(filename=delegee_gidfile)
776 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
777 return dcred.save_to_string(save_parents=True)
779 # removed named registry record
780 # - have to first retrieve the record to be removed
781 def remove(self, opts, args):
782 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
790 return self.registry.Remove(hrn, auth_cred, type)
792 # add named registry record
793 def add(self, opts, args):
794 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
798 record_filepath = args[0]
799 rec_file = self.get_record_file(record_filepath)
800 record = load_record_from_file(rec_file).as_dict()
801 return self.registry.Register(record, auth_cred)
803 # update named registry entry
804 def update(self, opts, args):
805 user_cred = self.get_user_cred()
809 rec_file = self.get_record_file(args[0])
810 record = load_record_from_file(rec_file)
811 if record['type'] == "user":
812 if record.get_name() == user_cred.get_gid_object().get_hrn():
813 cred = user_cred.save_to_string(save_parents=True)
815 cred = self.get_auth_cred().save_to_string(save_parents=True)
816 elif record['type'] in ["slice"]:
818 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
819 except xmlrpcprotocol.ServerException, e:
820 # XXX smbaker -- once we have better error return codes, update this
821 # to do something better than a string compare
822 if "Permission error" in e.args[0]:
823 cred = self.get_auth_cred().save_to_string(save_parents=True)
826 elif record.get_type() in ["authority"]:
827 cred = self.get_auth_cred().save_to_string(save_parents=True)
828 elif record.get_type() == 'node':
829 cred = self.get_auth_cred().save_to_string(save_parents=True)
831 raise "unknown record type" + record.get_type()
832 record = record.as_dict()
833 return self.registry.Update(record, cred)
835 def get_trusted_certs(self, opts, args):
837 return uhe trusted certs at this interface
839 trusted_certs = self.registry.get_trusted_certs()
840 for trusted_cert in trusted_certs:
841 gid = GID(string=trusted_cert)
843 cert = Certificate(string=trusted_cert)
844 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
847 def aggregates(self, opts, args):
849 return a list of details about known aggregates
851 user_cred = self.get_user_cred().save_to_string(save_parents=True)
856 result = self.registry.get_aggregates(user_cred, hrn)
860 def registries(self, opts, args):
862 return a list of details about known registries
864 user_cred = self.get_user_cred().save_to_string(save_parents=True)
868 result = self.registry.get_registries(user_cred, hrn)
873 # ==================================================================
874 # Slice-related commands
875 # ==================================================================
877 def version(self, opts, args):
878 if opts.version_local:
879 version=version_core()
881 if opts.version_registry:
884 server = self.get_server_from_opts(opts)
885 version=server.GetVersion()
886 for (k,v) in version.iteritems():
887 print "%-20s: %s"%(k,v)
889 # list instantiated slices
890 def slices(self, opts, args):
892 list instantiated slices
894 user_cred = self.get_user_cred().save_to_string(save_parents=True)
897 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
898 creds.append(delegated_cred)
899 server = self.get_server_from_opts(opts)
900 #results = server.ListSlices(creds, unique_call_id())
901 results = server.ListSlices(creds)
902 display_list(results)
905 # show rspec for named slice
906 def resources(self, opts, args):
907 user_cred = self.get_user_cred().save_to_string(save_parents=True)
908 server = self.slicemgr
910 server = self.get_server_from_opts(opts)
913 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
915 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
922 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
923 creds.append(delegated_cred)
924 if opts.rspec_version:
925 server_version = self.get_cached_server_version(server)
926 if 'sfa' in server_version:
927 # just request the version the client wants
928 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
930 # this must be a protogeni aggregate. We should request a v2 ad rspec
931 # regardless of what the client user requested
932 call_options['rspec_version'] = dict(pg_rspec_request_version)
933 #panos add info options
935 call_options['info'] = opts.info
937 call_args = [creds, call_options]
938 if self.server_supports_call_id_arg(server):
939 call_args.append(unique_call_id())
940 result = server.ListResources(*call_args)
942 if opts.file is None:
943 display_rspec(result, format)
946 if not file.startswith(os.sep):
947 file = os.path.join(self.options.sfi_dir, file)
948 save_rspec_to_file(result, file)
951 # created named slice with given rspec
952 def create(self, opts, args):
953 server = self.get_server_from_opts(opts)
954 server_version = self.get_cached_server_version(server)
956 slice_urn = hrn_to_urn(slice_hrn, 'slice')
957 user_cred = self.get_user_cred()
958 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
961 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
962 creds.append(delegated_cred)
963 rspec_file = self.get_rspec_file(args[1])
964 rspec = open(rspec_file).read()
966 # need to pass along user keys to the aggregate.
968 # { urn: urn:publicid:IDN+emulab.net+user+alice
969 # keys: [<ssh key A>, <ssh key B>]
974 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
975 if slice_records and 'researcher' in slice_records[0]:
976 slice_record = slice_records[0]
977 user_hrns = slice_record['researcher']
978 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
979 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
980 for user_record in user_records:
981 if user_record['type'] != 'user':
983 #user = {'urn': user_cred.get_gid_caller().get_urn(),'keys': []}
984 user = {'urn': user_cred.get_gid_caller().get_urn(), #
985 'keys': user_record['keys'],
986 'email': user_record['email'], # needed for MyPLC
987 'person_id': user_record['person_id'], # needed for MyPLC
988 'first_name': user_record['first_name'], # needed for MyPLC
989 'last_name': user_record['last_name'], # needed for MyPLC
990 'slice_record': slice_record, # needed for legacy refresh peer
991 'key_ids': user_record['key_ids'] # needed for legacy refresh peer
994 all_keys.extend(user_record['keys'])
995 all_key_ids.extend(user_record['key_ids'])
996 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
997 # request. So we will add all to the current caller's list of keys
998 if 'sfa' not in server_version:
1000 if user['urn'] == user_cred.get_gid_caller().get_urn():
1001 user['keys'] = all_keys
1003 call_args = [slice_urn, creds, rspec, users]
1004 if self.server_supports_call_id_arg(server):
1005 call_args.append(unique_call_id())
1007 result = server.CreateSliver(*call_args)
1011 # get a ticket for the specified slice
1012 def get_ticket(self, opts, args):
1013 slice_hrn, rspec_path = args[0], args[1]
1014 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1015 user_cred = self.get_user_cred()
1016 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1017 creds = [slice_cred]
1019 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1020 creds.append(delegated_cred)
1021 rspec_file = self.get_rspec_file(rspec_path)
1022 rspec = open(rspec_file).read()
1023 server = self.get_server_from_opts(opts)
1024 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1025 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1026 self.logger.info("writing ticket to %s"%file)
1027 ticket = SfaTicket(string=ticket_string)
1028 ticket.save_to_file(filename=file, save_parents=True)
1030 def redeem_ticket(self, opts, args):
1031 ticket_file = args[0]
1033 # get slice hrn from the ticket
1034 # use this to get the right slice credential
1035 ticket = SfaTicket(filename=ticket_file)
1037 slice_hrn = ticket.gidObject.get_hrn()
1038 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1039 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1040 user_cred = self.get_user_cred()
1041 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1043 # get a list of node hostnames from the RSpec
1044 tree = etree.parse(StringIO(ticket.rspec))
1045 root = tree.getroot()
1046 hostnames = root.xpath("./network/site/node/hostname/text()")
1048 # create an xmlrpc connection to the component manager at each of these
1049 # components and gall redeem_ticket
1051 for hostname in hostnames:
1053 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1054 server = self.get_server(hostname, CM_PORT, self.key_file, \
1055 self.cert_file, self.options.debug)
1056 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1057 self.logger.info("Success")
1058 except socket.gaierror:
1059 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1060 except Exception, e:
1061 self.logger.log_exc(e.message)
1064 # delete named slice
1065 def delete(self, opts, args):
1067 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1068 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1069 creds = [slice_cred]
1071 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1072 creds.append(delegated_cred)
1073 server = self.get_server_from_opts(opts)
1075 call_args = [slice_urn, creds]
1076 if self.server_supports_call_id_arg(server):
1077 call_args.append(unique_call_id())
1078 return server.DeleteSliver(*call_args)
1081 def start(self, opts, args):
1083 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1084 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1085 creds = [slice_cred]
1087 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1088 creds.append(delegated_cred)
1089 server = self.get_server_from_opts(opts)
1090 return server.Start(slice_urn, creds)
1093 def stop(self, opts, args):
1095 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1096 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1097 creds = [slice_cred]
1099 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1100 creds.append(delegated_cred)
1101 server = self.get_server_from_opts(opts)
1102 return server.Stop(slice_urn, creds)
1105 def reset(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)
1114 return server.reset_slice(creds, slice_urn)
1116 def renew(self, opts, args):
1118 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1119 server = self.get_server_from_opts(opts)
1120 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1121 creds = [slice_cred]
1123 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1124 creds.append(delegated_cred)
1127 call_args = [slice_urn, creds, time]
1128 if self.server_supports_call_id_arg(server):
1129 call_args.append(unique_call_id())
1130 return server.RenewSliver(*call_args)
1133 def status(self, opts, args):
1135 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1136 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1137 creds = [slice_cred]
1139 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1140 creds.append(delegated_cred)
1141 server = self.get_server_from_opts(opts)
1142 call_args = [slice_urn, creds]
1143 if self.server_supports_call_id_arg(server):
1144 call_args.append(unique_call_id())
1145 print server.SliverStatus(*call_args)
1148 def shutdown(self, opts, args):
1150 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1151 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1152 creds = [slice_cred]
1154 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1155 creds.append(delegated_cred)
1156 server = self.get_server_from_opts(opts)
1157 return server.Shutdown(slice_urn, creds)
1159 def print_help (self):
1160 self.sfi_parser.print_help()
1161 self.cmd_parser.print_help()
1164 # Main: parse arguments and dispatch to command
1167 self.sfi_parser = self.create_parser()
1168 (options, args) = self.sfi_parser.parse_args()
1169 self.options = options
1171 self.logger.setLevelFromOptVerbose(self.options.verbose)
1172 if options.hashrequest:
1173 self.hashrequest = True
1176 self.logger.critical("No command given. Use -h for help.")
1180 self.cmd_parser = self.create_cmd_parser(command)
1181 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1184 self.logger.info("Command=%s" % command)
1185 if command in ("resources"):
1186 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1187 elif command in ("list", "show", "remove"):
1188 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1189 self.logger.debug('cmd_args %s' % cmd_args)
1192 self.dispatch(command, cmd_opts, cmd_args)
1194 self.logger.critical ("Unknown command %s"%command)
1200 if __name__ == "__main__":