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)
702 records = filter_records(opts.type, records)
704 print "No record of type", opts.type
705 for record in records:
706 if record['type'] in ['user']:
707 record = UserRecord(dict=record)
708 elif record['type'] in ['slice']:
709 record = SliceRecord(dict=record)
710 elif record['type'] in ['node']:
711 record = NodeRecord(dict=record)
712 elif record['type'].startswith('authority'):
713 record = AuthorityRecord(dict=record)
715 record = SfaRecord(dict=record)
716 if (opts.format == "text"):
719 print record.save_to_string()
721 save_records_to_file(opts.file, records)
724 def delegate(self, opts, args):
726 delegee_hrn = args[0]
727 if opts.delegate_user:
728 user_cred = self.get_user_cred()
729 cred = self.delegate_cred(user_cred, delegee_hrn)
730 elif opts.delegate_slice:
731 slice_cred = self.get_slice_cred(opts.delegate_slice)
732 cred = self.delegate_cred(slice_cred, delegee_hrn)
734 self.logger.warning("Must specify either --user or --slice <hrn>")
736 delegated_cred = Credential(string=cred)
737 object_hrn = delegated_cred.get_gid_object().get_hrn()
738 if opts.delegate_user:
739 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
740 + get_leaf(object_hrn) + ".cred")
741 elif opts.delegate_slice:
742 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
743 + get_leaf(object_hrn) + ".cred")
745 delegated_cred.save_to_file(dest_fn, save_parents=True)
747 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
749 def delegate_cred(self, object_cred, hrn):
750 # the gid and hrn of the object we are delegating
751 if isinstance(object_cred, str):
752 object_cred = Credential(string=object_cred)
753 object_gid = object_cred.get_gid_object()
754 object_hrn = object_gid.get_hrn()
756 if not object_cred.get_privileges().get_all_delegate():
757 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
760 # the delegating user's gid
761 caller_gid = self._get_gid(self.user)
762 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
764 # the gid of the user who will be delegated to
765 delegee_gid = self._get_gid(hrn)
766 delegee_hrn = delegee_gid.get_hrn()
767 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
768 delegee_gid.save_to_file(filename=delegee_gidfile)
769 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
770 return dcred.save_to_string(save_parents=True)
772 # removed named registry record
773 # - have to first retrieve the record to be removed
774 def remove(self, opts, args):
775 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
783 return self.registry.Remove(hrn, auth_cred, type)
785 # add named registry record
786 def add(self, opts, args):
787 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
791 record_filepath = args[0]
792 rec_file = self.get_record_file(record_filepath)
793 record = load_record_from_file(rec_file).as_dict()
794 return self.registry.Register(record, auth_cred)
796 # update named registry entry
797 def update(self, opts, args):
798 user_cred = self.get_user_cred()
802 rec_file = self.get_record_file(args[0])
803 record = load_record_from_file(rec_file)
804 if record['type'] == "user":
805 if record.get_name() == user_cred.get_gid_object().get_hrn():
806 cred = user_cred.save_to_string(save_parents=True)
808 cred = self.get_auth_cred().save_to_string(save_parents=True)
809 elif record['type'] in ["slice"]:
811 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
812 except xmlrpcprotocol.ServerException, e:
813 # XXX smbaker -- once we have better error return codes, update this
814 # to do something better than a string compare
815 if "Permission error" in e.args[0]:
816 cred = self.get_auth_cred().save_to_string(save_parents=True)
819 elif record.get_type() in ["authority"]:
820 cred = self.get_auth_cred().save_to_string(save_parents=True)
821 elif record.get_type() == 'node':
822 cred = self.get_auth_cred().save_to_string(save_parents=True)
824 raise "unknown record type" + record.get_type()
825 record = record.as_dict()
826 return self.registry.Update(record, cred)
828 def get_trusted_certs(self, opts, args):
830 return uhe trusted certs at this interface
832 trusted_certs = self.registry.get_trusted_certs()
833 for trusted_cert in trusted_certs:
834 gid = GID(string=trusted_cert)
836 cert = Certificate(string=trusted_cert)
837 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
840 def aggregates(self, opts, args):
842 return a list of details about known aggregates
844 user_cred = self.get_user_cred().save_to_string(save_parents=True)
849 result = self.registry.get_aggregates(user_cred, hrn)
853 def registries(self, opts, args):
855 return a list of details about known registries
857 user_cred = self.get_user_cred().save_to_string(save_parents=True)
861 result = self.registry.get_registries(user_cred, hrn)
866 # ==================================================================
867 # Slice-related commands
868 # ==================================================================
870 def version(self, opts, args):
871 if opts.version_local:
872 version=version_core()
874 if opts.version_registry:
877 server = self.get_server_from_opts(opts)
878 version=server.GetVersion()
879 for (k,v) in version.iteritems():
880 print "%-20s: %s"%(k,v)
882 # list instantiated slices
883 def slices(self, opts, args):
885 list instantiated slices
887 user_cred = self.get_user_cred().save_to_string(save_parents=True)
890 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
891 creds.append(delegated_cred)
892 server = self.get_server_from_opts(opts)
893 #results = server.ListSlices(creds, unique_call_id())
894 results = server.ListSlices(creds)
895 display_list(results)
898 # show rspec for named slice
899 def resources(self, opts, args):
900 user_cred = self.get_user_cred().save_to_string(save_parents=True)
901 server = self.slicemgr
903 server = self.get_server_from_opts(opts)
906 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
908 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
915 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
916 creds.append(delegated_cred)
917 if opts.rspec_version:
918 server_version = self.get_cached_server_version(server)
919 if 'sfa' in server_version:
920 # just request the version the client wants
921 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
923 # this must be a protogeni aggregate. We should request a v2 ad rspec
924 # regardless of what the client user requested
925 call_options['rspec_version'] = dict(pg_rspec_request_version)
926 #panos add info options
928 call_options['info'] = opts.info
930 call_args = [creds, call_options]
931 if self.server_supports_call_id_arg(server):
932 call_args.append(unique_call_id())
933 result = server.ListResources(*call_args)
934 if opts.file is None:
935 display_rspec(result, opts.format)
937 save_rspec_to_file(result, opts.file)
940 # created named slice with given rspec
941 def create(self, opts, args):
942 server = self.get_server_from_opts(opts)
943 server_version = self.get_cached_server_version(server)
945 slice_urn = hrn_to_urn(slice_hrn, 'slice')
946 user_cred = self.get_user_cred()
947 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
950 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
951 creds.append(delegated_cred)
952 rspec_file = self.get_rspec_file(args[1])
953 rspec = open(rspec_file).read()
955 # need to pass along user keys to the aggregate.
957 # { urn: urn:publicid:IDN+emulab.net+user+alice
958 # keys: [<ssh key A>, <ssh key B>]
963 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
964 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
965 slice_record = slice_records[0]
966 user_hrns = slice_record['researcher']
967 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
968 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
969 for user_record in user_records:
970 if user_record['type'] != 'user':
972 #user = {'urn': user_cred.get_gid_caller().get_urn(),'keys': []}
973 user = {'urn': user_cred.get_gid_caller().get_urn(), #
974 'keys': user_record['keys'],
975 'email': user_record['email'], # needed for MyPLC
976 'person_id': user_record['person_id'], # needed for MyPLC
977 'first_name': user_record['first_name'], # needed for MyPLC
978 'last_name': user_record['last_name'], # needed for MyPLC
979 'slice_record': slice_record, # needed for legacy refresh peer
980 'key_ids': user_record['key_ids'] # needed for legacy refresh peer
983 all_keys.extend(user_record['keys'])
984 all_key_ids.extend(user_record['key_ids'])
985 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
986 # request. So we will add all to the current caller's list of keys
987 if 'sfa' not in server_version:
989 if user['urn'] == user_cred.get_gid_caller().get_urn():
990 user['keys'] = all_keys
992 call_args = [slice_urn, creds, rspec, users]
993 if self.server_supports_call_id_arg(server):
994 call_args.append(unique_call_id())
996 result = server.CreateSliver(*call_args)
997 if opts.file is None:
1000 save_rspec_to_file (result, opts.file)
1003 # get a ticket for the specified slice
1004 def get_ticket(self, opts, args):
1005 slice_hrn, rspec_path = args[0], args[1]
1006 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1007 user_cred = self.get_user_cred()
1008 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1009 creds = [slice_cred]
1011 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1012 creds.append(delegated_cred)
1013 rspec_file = self.get_rspec_file(rspec_path)
1014 rspec = open(rspec_file).read()
1015 server = self.get_server_from_opts(opts)
1016 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1017 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1018 self.logger.info("writing ticket to %s"%file)
1019 ticket = SfaTicket(string=ticket_string)
1020 ticket.save_to_file(filename=file, save_parents=True)
1022 def redeem_ticket(self, opts, args):
1023 ticket_file = args[0]
1025 # get slice hrn from the ticket
1026 # use this to get the right slice credential
1027 ticket = SfaTicket(filename=ticket_file)
1029 slice_hrn = ticket.gidObject.get_hrn()
1030 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1031 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1032 user_cred = self.get_user_cred()
1033 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1035 # get a list of node hostnames from the RSpec
1036 tree = etree.parse(StringIO(ticket.rspec))
1037 root = tree.getroot()
1038 hostnames = root.xpath("./network/site/node/hostname/text()")
1040 # create an xmlrpc connection to the component manager at each of these
1041 # components and gall redeem_ticket
1043 for hostname in hostnames:
1045 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1046 server = self.get_server(hostname, CM_PORT, self.key_file, \
1047 self.cert_file, self.options.debug)
1048 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1049 self.logger.info("Success")
1050 except socket.gaierror:
1051 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1052 except Exception, e:
1053 self.logger.log_exc(e.message)
1056 # delete named slice
1057 def delete(self, opts, args):
1059 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1060 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1061 creds = [slice_cred]
1063 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1064 creds.append(delegated_cred)
1065 server = self.get_server_from_opts(opts)
1067 call_args = [slice_urn, creds]
1068 if self.server_supports_call_id_arg(server):
1069 call_args.append(unique_call_id())
1070 return server.DeleteSliver(*call_args)
1073 def start(self, opts, args):
1075 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1076 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1077 creds = [slice_cred]
1079 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1080 creds.append(delegated_cred)
1081 server = self.get_server_from_opts(opts)
1082 return server.Start(slice_urn, creds)
1085 def stop(self, opts, args):
1087 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1088 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1089 creds = [slice_cred]
1091 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1092 creds.append(delegated_cred)
1093 server = self.get_server_from_opts(opts)
1094 return server.Stop(slice_urn, creds)
1097 def reset(self, opts, args):
1099 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1100 server = self.get_server_from_opts(opts)
1101 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1102 creds = [slice_cred]
1104 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1105 creds.append(delegated_cred)
1106 return server.reset_slice(creds, slice_urn)
1108 def renew(self, opts, args):
1110 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1111 server = self.get_server_from_opts(opts)
1112 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1113 creds = [slice_cred]
1115 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1116 creds.append(delegated_cred)
1119 call_args = [slice_urn, creds, time]
1120 if self.server_supports_call_id_arg(server):
1121 call_args.append(unique_call_id())
1122 return server.RenewSliver(*call_args)
1125 def status(self, opts, args):
1127 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1128 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1129 creds = [slice_cred]
1131 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1132 creds.append(delegated_cred)
1133 server = self.get_server_from_opts(opts)
1134 call_args = [slice_urn, creds]
1135 if self.server_supports_call_id_arg(server):
1136 call_args.append(unique_call_id())
1137 print server.SliverStatus(*call_args)
1140 def shutdown(self, opts, args):
1142 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1143 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1144 creds = [slice_cred]
1146 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1147 creds.append(delegated_cred)
1148 server = self.get_server_from_opts(opts)
1149 return server.Shutdown(slice_urn, creds)
1151 def print_help (self):
1152 self.sfi_parser.print_help()
1153 self.cmd_parser.print_help()
1156 # Main: parse arguments and dispatch to command
1159 self.sfi_parser = self.create_parser()
1160 (options, args) = self.sfi_parser.parse_args()
1161 self.options = options
1163 self.logger.setLevelFromOptVerbose(self.options.verbose)
1164 if options.hashrequest:
1165 self.hashrequest = True
1168 self.logger.critical("No command given. Use -h for help.")
1172 self.cmd_parser = self.create_cmd_parser(command)
1173 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1176 self.logger.info("Command=%s" % command)
1177 if command in ("resources"):
1178 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1179 elif command in ("list", "show", "remove"):
1180 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1181 self.logger.debug('cmd_args %s' % cmd_args)
1184 self.dispatch(command, cmd_opts, cmd_args)
1186 self.logger.critical ("Unknown command %s"%command)
1192 if __name__ == "__main__":