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"
86 f = open(filename, 'w')
91 def save_records_to_file(filename, recordList):
93 for record in recordList:
95 save_record_to_file(filename + "." + str(index), record)
97 save_record_to_file(filename, record)
100 def save_record_to_file(filename, record):
101 if record['type'] in ['user']:
102 record = UserRecord(dict=record)
103 elif record['type'] in ['slice']:
104 record = SliceRecord(dict=record)
105 elif record['type'] in ['node']:
106 record = NodeRecord(dict=record)
107 elif record['type'] in ['authority', 'ma', 'sa']:
108 record = AuthorityRecord(dict=record)
110 record = SfaRecord(dict=record)
111 str = record.save_to_string()
112 f=codecs.open(filename, encoding='utf-8',mode="w")
119 def load_record_from_file(filename):
120 f=codecs.open(filename, encoding="utf-8", mode="r")
123 record = SfaRecord(string=str)
128 def unique_call_id(): return uuid.uuid4().urn
132 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
134 # dummy to meet Sfi's expectations for its 'options' field
135 # i.e. s/t we can do setattr on
139 def __init__ (self,options=None):
140 if options is None: options=Sfi.DummyOptions()
141 for opt in Sfi.required_options:
142 if not hasattr(options,opt): setattr(options,opt,None)
143 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
144 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
145 # would be safer to remove self.sfi_dir altogether
146 self.sfi_dir = options.sfi_dir
147 self.options = options
151 self.authority = None
152 self.hashrequest = False
153 self.logger = sfi_logger
154 self.logger.enable_console()
156 def create_cmd_parser(self, command, additional_cmdargs=None):
157 cmdargs = {"list": "authority",
162 "aggregates": "[name]",
163 "registries": "[name]",
164 "create_gid": "[name]",
166 "get_trusted_certs": "cred",
168 "resources": "[name]",
169 "create": "name rspec",
170 "get_ticket": "name rspec",
171 "redeem_ticket": "ticket",
183 if additional_cmdargs:
184 cmdargs.update(additional_cmdargs)
186 if command not in cmdargs:
187 msg="Invalid command\n"
189 msg += ','.join(cmdargs.keys())
190 self.logger.critical(msg)
193 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
194 % (command, cmdargs[command]))
196 # user specifies remote aggregate/sm/component
197 if command in ("resources", "slices", "create", "delete", "start", "stop",
198 "restart", "shutdown", "get_ticket", "renew", "status"):
199 parser.add_option("-a", "--aggregate", dest="aggregate",
200 default=None, help="aggregate host")
201 parser.add_option("-p", "--port", dest="port",
202 default=AGGREGATE_PORT, help="aggregate port")
203 parser.add_option("-c", "--component", dest="component", default=None,
204 help="component hrn")
205 parser.add_option("-d", "--delegate", dest="delegate", default=None,
207 help="Include a credential delegated to the user's root"+\
208 "authority in set of credentials for this call")
210 # registy filter option
211 if command in ("list", "show", "remove"):
212 parser.add_option("-t", "--type", dest="type", type="choice",
213 help="type filter ([all]|user|slice|authority|node|aggregate)",
214 choices=("all", "user", "slice", "authority", "node", "aggregate"),
217 if command in ("resources"):
218 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
219 help="schema type and version of resulting RSpec")
220 parser.add_option("-f", "--format", dest="format", type="choice",
221 help="display format ([xml]|dns|ip)", default="xml",
222 choices=("xml", "dns", "ip"))
223 #panos: a new option to define the type of information about resources a user is interested in
224 parser.add_option("-i", "--info", dest="info",
225 help="optional component information", default=None)
228 # 'create' does return the new rspec, makes sense to save that too
229 if command in ("resources", "show", "list", "create_gid", 'create'):
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'])
691 save_records_to_file(opts.file, list)
694 # show named registry record
695 def show(self, opts, args):
700 user_cred = self.get_user_cred().save_to_string(save_parents=True)
701 records = self.registry.Resolve(hrn, user_cred)
703 records = filter_records(opts.type, records)
705 print "No record of type", opts.type
706 for record in records:
707 if record['type'] in ['user']:
708 record = UserRecord(dict=record)
709 elif record['type'] in ['slice']:
710 record = SliceRecord(dict=record)
711 elif record['type'] in ['node']:
712 record = NodeRecord(dict=record)
713 elif record['type'].startswith('authority'):
714 record = AuthorityRecord(dict=record)
716 record = SfaRecord(dict=record)
717 if (opts.format == "text"):
720 print record.save_to_string()
722 save_records_to_file(opts.file, records)
725 def delegate(self, opts, args):
727 delegee_hrn = args[0]
728 if opts.delegate_user:
729 user_cred = self.get_user_cred()
730 cred = self.delegate_cred(user_cred, delegee_hrn)
731 elif opts.delegate_slice:
732 slice_cred = self.get_slice_cred(opts.delegate_slice)
733 cred = self.delegate_cred(slice_cred, delegee_hrn)
735 self.logger.warning("Must specify either --user or --slice <hrn>")
737 delegated_cred = Credential(string=cred)
738 object_hrn = delegated_cred.get_gid_object().get_hrn()
739 if opts.delegate_user:
740 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
741 + get_leaf(object_hrn) + ".cred")
742 elif opts.delegate_slice:
743 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
744 + get_leaf(object_hrn) + ".cred")
746 delegated_cred.save_to_file(dest_fn, save_parents=True)
748 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
750 def delegate_cred(self, object_cred, hrn):
751 # the gid and hrn of the object we are delegating
752 if isinstance(object_cred, str):
753 object_cred = Credential(string=object_cred)
754 object_gid = object_cred.get_gid_object()
755 object_hrn = object_gid.get_hrn()
757 if not object_cred.get_privileges().get_all_delegate():
758 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
761 # the delegating user's gid
762 caller_gid = self._get_gid(self.user)
763 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
765 # the gid of the user who will be delegated to
766 delegee_gid = self._get_gid(hrn)
767 delegee_hrn = delegee_gid.get_hrn()
768 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
769 delegee_gid.save_to_file(filename=delegee_gidfile)
770 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
771 return dcred.save_to_string(save_parents=True)
773 # removed named registry record
774 # - have to first retrieve the record to be removed
775 def remove(self, opts, args):
776 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
784 return self.registry.Remove(hrn, auth_cred, type)
786 # add named registry record
787 def add(self, opts, args):
788 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
792 record_filepath = args[0]
793 rec_file = self.get_record_file(record_filepath)
794 record = load_record_from_file(rec_file).as_dict()
795 return self.registry.Register(record, auth_cred)
797 # update named registry entry
798 def update(self, opts, args):
799 user_cred = self.get_user_cred()
803 rec_file = self.get_record_file(args[0])
804 record = load_record_from_file(rec_file)
805 if record['type'] == "user":
806 if record.get_name() == user_cred.get_gid_object().get_hrn():
807 cred = user_cred.save_to_string(save_parents=True)
809 cred = self.get_auth_cred().save_to_string(save_parents=True)
810 elif record['type'] in ["slice"]:
812 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
813 except xmlrpcprotocol.ServerException, e:
814 # XXX smbaker -- once we have better error return codes, update this
815 # to do something better than a string compare
816 if "Permission error" in e.args[0]:
817 cred = self.get_auth_cred().save_to_string(save_parents=True)
820 elif record.get_type() in ["authority"]:
821 cred = self.get_auth_cred().save_to_string(save_parents=True)
822 elif record.get_type() == 'node':
823 cred = self.get_auth_cred().save_to_string(save_parents=True)
825 raise "unknown record type" + record.get_type()
826 record = record.as_dict()
827 return self.registry.Update(record, cred)
829 def get_trusted_certs(self, opts, args):
831 return uhe trusted certs at this interface
833 trusted_certs = self.registry.get_trusted_certs()
834 for trusted_cert in trusted_certs:
835 gid = GID(string=trusted_cert)
837 cert = Certificate(string=trusted_cert)
838 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
841 def aggregates(self, opts, args):
843 return a list of details about known aggregates
845 user_cred = self.get_user_cred().save_to_string(save_parents=True)
850 result = self.registry.get_aggregates(user_cred, hrn)
854 def registries(self, opts, args):
856 return a list of details about known registries
858 user_cred = self.get_user_cred().save_to_string(save_parents=True)
862 result = self.registry.get_registries(user_cred, hrn)
867 # ==================================================================
868 # Slice-related commands
869 # ==================================================================
871 def version(self, opts, args):
872 if opts.version_local:
873 version=version_core()
875 if opts.version_registry:
878 server = self.get_server_from_opts(opts)
879 version=server.GetVersion()
880 for (k,v) in version.iteritems():
881 print "%-20s: %s"%(k,v)
883 # list instantiated slices
884 def slices(self, opts, args):
886 list instantiated slices
888 user_cred = self.get_user_cred().save_to_string(save_parents=True)
891 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
892 creds.append(delegated_cred)
893 server = self.get_server_from_opts(opts)
894 #results = server.ListSlices(creds, unique_call_id())
895 results = server.ListSlices(creds)
896 display_list(results)
899 # show rspec for named slice
900 def resources(self, opts, args):
901 user_cred = self.get_user_cred().save_to_string(save_parents=True)
902 server = self.slicemgr
904 server = self.get_server_from_opts(opts)
907 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
909 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
916 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
917 creds.append(delegated_cred)
918 if opts.rspec_version:
919 server_version = self.get_cached_server_version(server)
920 if 'sfa' in server_version:
921 # just request the version the client wants
922 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
924 # this must be a protogeni aggregate. We should request a v2 ad rspec
925 # regardless of what the client user requested
926 call_options['rspec_version'] = dict(pg_rspec_request_version)
927 #panos add info options
929 call_options['info'] = opts.info
931 call_args = [creds, call_options]
932 if self.server_supports_call_id_arg(server):
933 call_args.append(unique_call_id())
934 result = server.ListResources(*call_args)
935 if opts.file is None:
936 display_rspec(result, opts.format)
938 save_rspec_to_file(result, opts.file)
941 # created named slice with given rspec
942 def create(self, opts, args):
943 server = self.get_server_from_opts(opts)
944 server_version = self.get_cached_server_version(server)
946 slice_urn = hrn_to_urn(slice_hrn, 'slice')
947 user_cred = self.get_user_cred()
948 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
951 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
952 creds.append(delegated_cred)
953 rspec_file = self.get_rspec_file(args[1])
954 rspec = open(rspec_file).read()
956 # need to pass along user keys to the aggregate.
958 # { urn: urn:publicid:IDN+emulab.net+user+alice
959 # keys: [<ssh key A>, <ssh key B>]
964 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
965 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
966 slice_record = slice_records[0]
967 user_hrns = slice_record['researcher']
968 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
969 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
970 for user_record in user_records:
971 if user_record['type'] != 'user':
973 #user = {'urn': user_cred.get_gid_caller().get_urn(),'keys': []}
974 user = {'urn': user_cred.get_gid_caller().get_urn(), #
975 'keys': user_record['keys'],
976 'email': user_record['email'], # needed for MyPLC
977 'person_id': user_record['person_id'], # needed for MyPLC
978 'first_name': user_record['first_name'], # needed for MyPLC
979 'last_name': user_record['last_name'], # needed for MyPLC
980 'slice_record': slice_record, # needed for legacy refresh peer
981 'key_ids': user_record['key_ids'] # needed for legacy refresh peer
984 all_keys.extend(user_record['keys'])
985 all_key_ids.extend(user_record['key_ids'])
986 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
987 # request. So we will add all to the current caller's list of keys
988 if 'sfa' not in server_version:
990 if user['urn'] == user_cred.get_gid_caller().get_urn():
991 user['keys'] = all_keys
993 call_args = [slice_urn, creds, rspec, users]
994 if self.server_supports_call_id_arg(server):
995 call_args.append(unique_call_id())
997 result = server.CreateSliver(*call_args)
998 if opts.file is None:
1001 save_rspec_to_file (result, opts.file)
1004 # get a ticket for the specified slice
1005 def get_ticket(self, opts, args):
1006 slice_hrn, rspec_path = args[0], args[1]
1007 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1008 user_cred = self.get_user_cred()
1009 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1010 creds = [slice_cred]
1012 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1013 creds.append(delegated_cred)
1014 rspec_file = self.get_rspec_file(rspec_path)
1015 rspec = open(rspec_file).read()
1016 server = self.get_server_from_opts(opts)
1017 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1018 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1019 self.logger.info("writing ticket to %s"%file)
1020 ticket = SfaTicket(string=ticket_string)
1021 ticket.save_to_file(filename=file, save_parents=True)
1023 def redeem_ticket(self, opts, args):
1024 ticket_file = args[0]
1026 # get slice hrn from the ticket
1027 # use this to get the right slice credential
1028 ticket = SfaTicket(filename=ticket_file)
1030 slice_hrn = ticket.gidObject.get_hrn()
1031 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1032 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1033 user_cred = self.get_user_cred()
1034 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1036 # get a list of node hostnames from the RSpec
1037 tree = etree.parse(StringIO(ticket.rspec))
1038 root = tree.getroot()
1039 hostnames = root.xpath("./network/site/node/hostname/text()")
1041 # create an xmlrpc connection to the component manager at each of these
1042 # components and gall redeem_ticket
1044 for hostname in hostnames:
1046 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1047 server = self.get_server(hostname, CM_PORT, self.key_file, \
1048 self.cert_file, self.options.debug)
1049 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1050 self.logger.info("Success")
1051 except socket.gaierror:
1052 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1053 except Exception, e:
1054 self.logger.log_exc(e.message)
1057 # delete named slice
1058 def delete(self, opts, args):
1060 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1061 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1062 creds = [slice_cred]
1064 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1065 creds.append(delegated_cred)
1066 server = self.get_server_from_opts(opts)
1068 call_args = [slice_urn, creds]
1069 if self.server_supports_call_id_arg(server):
1070 call_args.append(unique_call_id())
1071 return server.DeleteSliver(*call_args)
1074 def start(self, opts, args):
1076 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1077 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1078 creds = [slice_cred]
1080 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1081 creds.append(delegated_cred)
1082 server = self.get_server_from_opts(opts)
1083 return server.Start(slice_urn, creds)
1086 def stop(self, opts, args):
1088 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1089 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1090 creds = [slice_cred]
1092 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1093 creds.append(delegated_cred)
1094 server = self.get_server_from_opts(opts)
1095 return server.Stop(slice_urn, creds)
1098 def reset(self, opts, args):
1100 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1101 server = self.get_server_from_opts(opts)
1102 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1103 creds = [slice_cred]
1105 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1106 creds.append(delegated_cred)
1107 return server.reset_slice(creds, slice_urn)
1109 def renew(self, opts, args):
1111 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1112 server = self.get_server_from_opts(opts)
1113 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1114 creds = [slice_cred]
1116 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1117 creds.append(delegated_cred)
1120 call_args = [slice_urn, creds, time]
1121 if self.server_supports_call_id_arg(server):
1122 call_args.append(unique_call_id())
1123 return server.RenewSliver(*call_args)
1126 def status(self, opts, args):
1128 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1129 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1130 creds = [slice_cred]
1132 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1133 creds.append(delegated_cred)
1134 server = self.get_server_from_opts(opts)
1135 call_args = [slice_urn, creds]
1136 if self.server_supports_call_id_arg(server):
1137 call_args.append(unique_call_id())
1138 print server.SliverStatus(*call_args)
1141 def shutdown(self, opts, args):
1143 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1144 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1145 creds = [slice_cred]
1147 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1148 creds.append(delegated_cred)
1149 server = self.get_server_from_opts(opts)
1150 return server.Shutdown(slice_urn, creds)
1152 def print_help (self):
1153 self.sfi_parser.print_help()
1154 self.cmd_parser.print_help()
1157 # Main: parse arguments and dispatch to command
1160 self.sfi_parser = self.create_parser()
1161 (options, args) = self.sfi_parser.parse_args()
1162 self.options = options
1164 self.logger.setLevelFromOptVerbose(self.options.verbose)
1165 if options.hashrequest:
1166 self.hashrequest = True
1169 self.logger.critical("No command given. Use -h for help.")
1173 self.cmd_parser = self.create_cmd_parser(command)
1174 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1177 self.logger.info("Command=%s" % command)
1178 if command in ("resources"):
1179 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1180 elif command in ("list", "show", "remove"):
1181 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1182 self.logger.debug('cmd_args %s' % cmd_args)
1185 self.dispatch(command, cmd_opts, cmd_args)
1187 self.logger.critical ("Unknown command %s"%command)
1193 if __name__ == "__main__":