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)
705 records = filter_records(opts.type, records)
707 print "No record of type", opts.type
708 for record in records:
709 if record['type'] in ['user']:
710 record = UserRecord(dict=record)
711 elif record['type'] in ['slice']:
712 record = SliceRecord(dict=record)
713 elif record['type'] in ['node']:
714 record = NodeRecord(dict=record)
715 elif record['type'].startswith('authority'):
716 record = AuthorityRecord(dict=record)
718 record = SfaRecord(dict=record)
719 if (opts.format == "text"):
722 print record.save_to_string()
725 if not file.startswith(os.sep):
726 file = os.path.join(self.options.sfi_dir, file)
727 save_records_to_file(file, records)
730 def delegate(self, opts, args):
732 delegee_hrn = args[0]
733 if opts.delegate_user:
734 user_cred = self.get_user_cred()
735 cred = self.delegate_cred(user_cred, delegee_hrn)
736 elif opts.delegate_slice:
737 slice_cred = self.get_slice_cred(opts.delegate_slice)
738 cred = self.delegate_cred(slice_cred, delegee_hrn)
740 self.logger.warning("Must specify either --user or --slice <hrn>")
742 delegated_cred = Credential(string=cred)
743 object_hrn = delegated_cred.get_gid_object().get_hrn()
744 if opts.delegate_user:
745 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
746 + get_leaf(object_hrn) + ".cred")
747 elif opts.delegate_slice:
748 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
749 + get_leaf(object_hrn) + ".cred")
751 delegated_cred.save_to_file(dest_fn, save_parents=True)
753 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
755 def delegate_cred(self, object_cred, hrn):
756 # the gid and hrn of the object we are delegating
757 if isinstance(object_cred, str):
758 object_cred = Credential(string=object_cred)
759 object_gid = object_cred.get_gid_object()
760 object_hrn = object_gid.get_hrn()
762 if not object_cred.get_privileges().get_all_delegate():
763 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
766 # the delegating user's gid
767 caller_gid = self._get_gid(self.user)
768 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
770 # the gid of the user who will be delegated to
771 delegee_gid = self._get_gid(hrn)
772 delegee_hrn = delegee_gid.get_hrn()
773 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
774 delegee_gid.save_to_file(filename=delegee_gidfile)
775 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
776 return dcred.save_to_string(save_parents=True)
778 # removed named registry record
779 # - have to first retrieve the record to be removed
780 def remove(self, opts, args):
781 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
789 return self.registry.Remove(hrn, auth_cred, type)
791 # add named registry record
792 def add(self, opts, args):
793 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
797 record_filepath = args[0]
798 rec_file = self.get_record_file(record_filepath)
799 record = load_record_from_file(rec_file).as_dict()
800 return self.registry.Register(record, auth_cred)
802 # update named registry entry
803 def update(self, opts, args):
804 user_cred = self.get_user_cred()
808 rec_file = self.get_record_file(args[0])
809 record = load_record_from_file(rec_file)
810 if record['type'] == "user":
811 if record.get_name() == user_cred.get_gid_object().get_hrn():
812 cred = user_cred.save_to_string(save_parents=True)
814 cred = self.get_auth_cred().save_to_string(save_parents=True)
815 elif record['type'] in ["slice"]:
817 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
818 except xmlrpcprotocol.ServerException, e:
819 # XXX smbaker -- once we have better error return codes, update this
820 # to do something better than a string compare
821 if "Permission error" in e.args[0]:
822 cred = self.get_auth_cred().save_to_string(save_parents=True)
825 elif record.get_type() in ["authority"]:
826 cred = self.get_auth_cred().save_to_string(save_parents=True)
827 elif record.get_type() == 'node':
828 cred = self.get_auth_cred().save_to_string(save_parents=True)
830 raise "unknown record type" + record.get_type()
831 record = record.as_dict()
832 return self.registry.Update(record, cred)
834 def get_trusted_certs(self, opts, args):
836 return uhe trusted certs at this interface
838 trusted_certs = self.registry.get_trusted_certs()
839 for trusted_cert in trusted_certs:
840 gid = GID(string=trusted_cert)
842 cert = Certificate(string=trusted_cert)
843 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
846 def aggregates(self, opts, args):
848 return a list of details about known aggregates
850 user_cred = self.get_user_cred().save_to_string(save_parents=True)
855 result = self.registry.get_aggregates(user_cred, hrn)
859 def registries(self, opts, args):
861 return a list of details about known registries
863 user_cred = self.get_user_cred().save_to_string(save_parents=True)
867 result = self.registry.get_registries(user_cred, hrn)
872 # ==================================================================
873 # Slice-related commands
874 # ==================================================================
876 def version(self, opts, args):
877 if opts.version_local:
878 version=version_core()
880 if opts.version_registry:
883 server = self.get_server_from_opts(opts)
884 version=server.GetVersion()
885 for (k,v) in version.iteritems():
886 print "%-20s: %s"%(k,v)
888 # list instantiated slices
889 def slices(self, opts, args):
891 list instantiated slices
893 user_cred = self.get_user_cred().save_to_string(save_parents=True)
896 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
897 creds.append(delegated_cred)
898 server = self.get_server_from_opts(opts)
899 #results = server.ListSlices(creds, unique_call_id())
900 results = server.ListSlices(creds)
901 display_list(results)
904 # show rspec for named slice
905 def resources(self, opts, args):
906 user_cred = self.get_user_cred().save_to_string(save_parents=True)
907 server = self.slicemgr
909 server = self.get_server_from_opts(opts)
912 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
914 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
921 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
922 creds.append(delegated_cred)
923 if opts.rspec_version:
924 server_version = self.get_cached_server_version(server)
925 if 'sfa' in server_version:
926 # just request the version the client wants
927 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
929 # this must be a protogeni aggregate. We should request a v2 ad rspec
930 # regardless of what the client user requested
931 call_options['rspec_version'] = dict(pg_rspec_request_version)
932 #panos add info options
934 call_options['info'] = opts.info
936 call_args = [creds, call_options]
937 if self.server_supports_call_id_arg(server):
938 call_args.append(unique_call_id())
939 result = server.ListResources(*call_args)
941 if opts.file is None:
942 display_rspec(result, format)
945 if not file.startswith(os.sep):
946 file = os.path.join(self.options.sfi_dir, file)
947 save_rspec_to_file(result, file)
950 # created named slice with given rspec
951 def create(self, opts, args):
952 server = self.get_server_from_opts(opts)
953 server_version = self.get_cached_server_version(server)
955 slice_urn = hrn_to_urn(slice_hrn, 'slice')
956 user_cred = self.get_user_cred()
957 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
960 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
961 creds.append(delegated_cred)
962 rspec_file = self.get_rspec_file(args[1])
963 rspec = open(rspec_file).read()
965 # need to pass along user keys to the aggregate.
967 # { urn: urn:publicid:IDN+emulab.net+user+alice
968 # keys: [<ssh key A>, <ssh key B>]
973 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
974 if slice_records and 'researcher' in slice_records[0]:
975 slice_record = slice_records[0]
976 user_hrns = slice_record['researcher']
977 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
978 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
979 for user_record in user_records:
980 #user = {'urn': user_cred.get_gid_caller().get_urn(),'keys': []}
981 user = {'urn': user_cred.get_gid_caller().get_urn(), #
982 'keys': user_record['keys'],
983 'email': user_record['email'], # needed for MyPLC
984 'person_id': user_record['person_id'], # needed for MyPLC
985 'first_name': user_record['first_name'], # needed for MyPLC
986 'last_name': user_record['last_name'], # needed for MyPLC
987 'slice_record': slice_record, # needed for legacy refresh peer
988 'key_ids': user_record['key_ids'] # needed for legacy refresh peer
991 all_keys.extend(user_record['keys'])
992 all_key_ids.extend(user_record['key_ids'])
993 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
994 # request. So we will add all to the current caller's list of keys
995 if 'sfa' not in server_version:
997 if user['urn'] == user_cred.get_gid_caller().get_urn():
998 user['keys'] = all_keys
1000 call_args = [slice_urn, creds, rspec, users]
1001 if self.server_supports_call_id_arg(server):
1002 call_args.append(unique_call_id())
1004 result = server.CreateSliver(*call_args)
1008 # get a ticket for the specified slice
1009 def get_ticket(self, opts, args):
1010 slice_hrn, rspec_path = args[0], args[1]
1011 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1012 user_cred = self.get_user_cred()
1013 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1014 creds = [slice_cred]
1016 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1017 creds.append(delegated_cred)
1018 rspec_file = self.get_rspec_file(rspec_path)
1019 rspec = open(rspec_file).read()
1020 server = self.get_server_from_opts(opts)
1021 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1022 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1023 self.logger.info("writing ticket to %s"%file)
1024 ticket = SfaTicket(string=ticket_string)
1025 ticket.save_to_file(filename=file, save_parents=True)
1027 def redeem_ticket(self, opts, args):
1028 ticket_file = args[0]
1030 # get slice hrn from the ticket
1031 # use this to get the right slice credential
1032 ticket = SfaTicket(filename=ticket_file)
1034 slice_hrn = ticket.gidObject.get_hrn()
1035 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1036 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1037 user_cred = self.get_user_cred()
1038 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1040 # get a list of node hostnames from the RSpec
1041 tree = etree.parse(StringIO(ticket.rspec))
1042 root = tree.getroot()
1043 hostnames = root.xpath("./network/site/node/hostname/text()")
1045 # create an xmlrpc connection to the component manager at each of these
1046 # components and gall redeem_ticket
1048 for hostname in hostnames:
1050 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1051 server = self.get_server(hostname, CM_PORT, self.key_file, \
1052 self.cert_file, self.options.debug)
1053 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1054 self.logger.info("Success")
1055 except socket.gaierror:
1056 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1057 except Exception, e:
1058 self.logger.log_exc(e.message)
1061 # delete named slice
1062 def delete(self, opts, args):
1064 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1065 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1066 creds = [slice_cred]
1068 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1069 creds.append(delegated_cred)
1070 server = self.get_server_from_opts(opts)
1072 call_args = [slice_urn, creds]
1073 if self.server_supports_call_id_arg(server):
1074 call_args.append(unique_call_id())
1075 return server.DeleteSliver(*call_args)
1078 def start(self, opts, args):
1080 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1081 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1082 creds = [slice_cred]
1084 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1085 creds.append(delegated_cred)
1086 server = self.get_server_from_opts(opts)
1087 return server.Start(slice_urn, creds)
1090 def stop(self, opts, args):
1092 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1093 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1094 creds = [slice_cred]
1096 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1097 creds.append(delegated_cred)
1098 server = self.get_server_from_opts(opts)
1099 return server.Stop(slice_urn, creds)
1102 def reset(self, opts, args):
1104 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1105 server = self.get_server_from_opts(opts)
1106 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1107 creds = [slice_cred]
1109 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1110 creds.append(delegated_cred)
1111 return server.reset_slice(creds, slice_urn)
1113 def renew(self, opts, args):
1115 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1116 server = self.get_server_from_opts(opts)
1117 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1118 creds = [slice_cred]
1120 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1121 creds.append(delegated_cred)
1124 call_args = [slice_urn, creds, time]
1125 if self.server_supports_call_id_arg(server):
1126 call_args.append(unique_call_id())
1127 return server.RenewSliver(*call_args)
1130 def status(self, opts, args):
1132 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1133 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1134 creds = [slice_cred]
1136 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1137 creds.append(delegated_cred)
1138 server = self.get_server_from_opts(opts)
1139 call_args = [slice_urn, creds]
1140 if self.server_supports_call_id_arg(server):
1141 call_args.append(unique_call_id())
1142 print server.SliverStatus(*call_args)
1145 def shutdown(self, opts, args):
1147 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1148 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1149 creds = [slice_cred]
1151 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1152 creds.append(delegated_cred)
1153 server = self.get_server_from_opts(opts)
1154 return server.Shutdown(slice_urn, creds)
1156 def print_help (self):
1157 self.sfi_parser.print_help()
1158 self.cmd_parser.print_help()
1161 # Main: parse arguments and dispatch to command
1164 self.sfi_parser = self.create_parser()
1165 (options, args) = self.sfi_parser.parse_args()
1166 self.options = options
1168 self.logger.setLevelFromOptVerbose(self.options.verbose)
1169 if options.hashrequest:
1170 self.hashrequest = True
1173 self.logger.critical("No command given. Use -h for help.")
1177 self.cmd_parser = self.create_cmd_parser(command)
1178 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1181 self.logger.info("Command=%s" % command)
1182 if command in ("resources"):
1183 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1184 elif command in ("list", "show", "remove"):
1185 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1186 self.logger.debug('cmd_args %s' % cmd_args)
1189 self.dispatch(command, cmd_opts, cmd_args)
1191 self.logger.critical ("Unknown command %s"%command)
1196 if __name__ == "__main__":