3 # sfi -- slice-based facility interface
14 from lxml import etree
15 from StringIO import StringIO
16 from types import StringTypes, ListType
17 from optparse import OptionParser
18 from sfa.util.sfalogging import sfi_logger
19 from sfa.trust.certificate import Keypair, Certificate
20 from sfa.trust.gid import GID
21 from sfa.trust.credential import Credential
22 from sfa.util.sfaticket import SfaTicket
23 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
24 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
25 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
26 from sfa.util.config import Config
27 from sfa.util.version import version_core
28 from sfa.util.cache import Cache
29 from sfa.rspecs.rspec_version import RSpecVersion
30 from sfa.rspecs.pg_rspec import pg_rspec_request_version
35 # utility methods here
37 def display_rspec(rspec, format='rspec'):
39 tree = etree.parse(StringIO(rspec))
41 result = root.xpath("./network/site/node/hostname/text()")
42 elif format in ['ip']:
43 # The IP address is not yet part of the new RSpec
44 # so this doesn't do anything yet.
45 tree = etree.parse(StringIO(rspec))
47 result = root.xpath("./network/site/node/ipv4/text()")
54 def display_list(results):
55 for result in results:
58 def display_records(recordList, dump=False):
59 ''' Print all fields in the record'''
60 for record in recordList:
61 display_record(record, dump)
63 def display_record(record, dump=False):
67 info = record.getdict()
68 print "%s (%s)" % (info['hrn'], info['type'])
72 def filter_records(type, records):
74 for record in records:
75 if (record['type'] == type) or (type == "all"):
76 filtered_records.append(record)
77 return filtered_records
81 def save_rspec_to_file(rspec, filename):
82 if not filename.endswith(".rspec"):
83 filename = filename + ".rspec"
85 f = open(filename, 'w')
90 def save_records_to_file(filename, recordList):
92 for record in recordList:
94 save_record_to_file(filename + "." + str(index), record)
96 save_record_to_file(filename, record)
99 def save_record_to_file(filename, record):
100 if record['type'] in ['user']:
101 record = UserRecord(dict=record)
102 elif record['type'] in ['slice']:
103 record = SliceRecord(dict=record)
104 elif record['type'] in ['node']:
105 record = NodeRecord(dict=record)
106 elif record['type'] in ['authority', 'ma', 'sa']:
107 record = AuthorityRecord(dict=record)
109 record = SfaRecord(dict=record)
110 str = record.save_to_string()
111 file(filename, "w").write(str)
116 def load_record_from_file(filename):
117 str = file(filename, "r").read()
118 record = SfaRecord(string=str)
123 def unique_call_id(): return uuid.uuid4().urn
127 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
129 # dummy to meet Sfi's expectations for its 'options' field
130 # i.e. s/t we can do setattr on
134 def __init__ (self,options=None):
135 if options is None: options=Sfi.DummyOptions()
136 for opt in Sfi.required_options:
137 if not hasattr(options,opt): setattr(options,opt,None)
138 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
139 self.sfi_dir = options.sfi_dir
140 self.options = options
144 self.authority = None
145 self.hashrequest = False
146 self.logger = sfi_logger
147 self.logger.enable_console()
149 def create_cmd_parser(self, command, additional_cmdargs=None):
150 cmdargs = {"list": "authority",
155 "aggregates": "[name]",
156 "registries": "[name]",
157 "create_gid": "[name]",
159 "get_trusted_certs": "cred",
161 "resources": "[name]",
162 "create": "name rspec",
163 "get_ticket": "name rspec",
164 "redeem_ticket": "ticket",
176 if additional_cmdargs:
177 cmdargs.update(additional_cmdargs)
179 if command not in cmdargs:
180 msg="Invalid command\n"
182 msg += ','.join(cmdargs.keys())
183 self.logger.critical(msg)
186 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
187 % (command, cmdargs[command]))
189 # user specifies remote aggregate/sm/component
190 if command in ("resources", "slices", "create", "delete", "start", "stop",
191 "restart", "shutdown", "get_ticket", "renew", "status"):
192 parser.add_option("-a", "--aggregate", dest="aggregate",
193 default=None, help="aggregate host")
194 parser.add_option("-p", "--port", dest="port",
195 default=AGGREGATE_PORT, help="aggregate port")
196 parser.add_option("-c", "--component", dest="component", default=None,
197 help="component hrn")
198 parser.add_option("-d", "--delegate", dest="delegate", default=None,
200 help="Include a credential delegated to the user's root"+\
201 "authority in set of credentials for this call")
203 # registy filter option
204 if command in ("list", "show", "remove"):
205 parser.add_option("-t", "--type", dest="type", type="choice",
206 help="type filter ([all]|user|slice|authority|node|aggregate)",
207 choices=("all", "user", "slice", "authority", "node", "aggregate"),
210 if command in ("resources"):
211 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
212 help="schema type and version of resulting RSpec")
213 parser.add_option("-f", "--format", dest="format", type="choice",
214 help="display format ([xml]|dns|ip)", default="xml",
215 choices=("xml", "dns", "ip"))
216 #panos: a new option to define the type of information about resources a user is interested in
217 parser.add_option("-i", "--info", dest="info",
218 help="optional component information", default=None)
221 if command in ("resources", "show", "list", "create_gid"):
222 parser.add_option("-o", "--output", dest="file",
223 help="output XML to file", metavar="FILE", default=None)
225 if command in ("show", "list"):
226 parser.add_option("-f", "--format", dest="format", type="choice",
227 help="display format ([text]|xml)", default="text",
228 choices=("text", "xml"))
230 if command in ("delegate"):
231 parser.add_option("-u", "--user",
232 action="store_true", dest="delegate_user", default=False,
233 help="delegate user credential")
234 parser.add_option("-s", "--slice", dest="delegate_slice",
235 help="delegate slice credential", metavar="HRN", default=None)
237 if command in ("version"):
238 parser.add_option("-a", "--aggregate", dest="aggregate",
239 default=None, help="aggregate host")
240 parser.add_option("-p", "--port", dest="port",
241 default=AGGREGATE_PORT, help="aggregate port")
242 parser.add_option("-R","--registry-version",
243 action="store_true", dest="version_registry", default=False,
244 help="probe registry version instead of slicemgr")
245 parser.add_option("-l","--local",
246 action="store_true", dest="version_local", default=False,
247 help="display version of the local client")
252 def create_parser(self):
254 # Generate command line parser
255 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
256 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
257 parser.add_option("-r", "--registry", dest="registry",
258 help="root registry", metavar="URL", default=None)
259 parser.add_option("-s", "--slicemgr", dest="sm",
260 help="slice manager", metavar="URL", default=None)
261 default_sfi_dir = os.path.expanduser("~/.sfi/")
262 parser.add_option("-d", "--dir", dest="sfi_dir",
263 help="config & working directory - default is " + default_sfi_dir,
264 metavar="PATH", default=default_sfi_dir)
265 parser.add_option("-u", "--user", dest="user",
266 help="user name", metavar="HRN", default=None)
267 parser.add_option("-a", "--auth", dest="auth",
268 help="authority name", metavar="HRN", default=None)
269 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
270 help="verbose mode - cumulative")
271 parser.add_option("-D", "--debug",
272 action="store_true", dest="debug", default=False,
273 help="Debug (xml-rpc) protocol messages")
274 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
275 help="RPC protocol (xmlrpc or soap)")
276 parser.add_option("-k", "--hashrequest",
277 action="store_true", dest="hashrequest", default=False,
278 help="Create a hash of the request that will be authenticated on the server")
279 parser.add_option("-t", "--timeout", dest="timeout", default=None,
280 help="Amout of time tom wait before timing out the request")
281 parser.disable_interspersed_args()
286 def read_config(self):
287 config_file = self.options.sfi_dir + os.sep + "sfi_config"
289 config = Config (config_file)
291 self.logger.critical("Failed to read configuration file %s"%config_file)
292 self.logger.info("Make sure to remove the export clauses and to add quotes")
293 if self.options.verbose==0:
294 self.logger.info("Re-run with -v for more details")
296 self.logger.log_exc("Could not read config file %s"%config_file)
301 if (self.options.sm is not None):
302 self.sm_url = self.options.sm
303 elif hasattr(config, "SFI_SM"):
304 self.sm_url = config.SFI_SM
306 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
310 if (self.options.registry is not None):
311 self.reg_url = self.options.registry
312 elif hasattr(config, "SFI_REGISTRY"):
313 self.reg_url = config.SFI_REGISTRY
315 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
320 if (self.options.user is not None):
321 self.user = self.options.user
322 elif hasattr(config, "SFI_USER"):
323 self.user = config.SFI_USER
325 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
329 if (self.options.auth is not None):
330 self.authority = self.options.auth
331 elif hasattr(config, "SFI_AUTH"):
332 self.authority = config.SFI_AUTH
334 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
342 # Establish Connection to SliceMgr and Registry Servers
344 def set_servers(self):
347 # Get key and certificate
348 key_file = self.get_key_file()
349 cert_file = self.get_cert_file(key_file)
350 self.key = Keypair(filename=key_file)
351 self.key_file = key_file
352 self.cert_file = cert_file
353 self.cert = GID(filename=cert_file)
354 self.logger.info("Contacting Registry at: %s"%self.reg_url)
355 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
356 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
357 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
360 def get_cached_server_version(self, server):
361 # check local cache first
364 cache_file = self.sfi_dir + os.path.sep + 'sfi_cache.dat'
365 cache_key = server.url + "-version"
367 cache = Cache(cache_file)
370 self.logger.info("Local cache not found at: %s" % cache_file)
373 version = cache.get(cache_key)
376 version = server.GetVersion()
377 # cache version for 24 hours
378 cache.add(cache_key, version, ttl= 60*60*24)
379 self.logger.info("Updating cache file %s" % cache_file)
380 cache.save_to_file(cache_file)
386 def server_supports_call_id_arg(self, server):
388 Returns true if server support the optional call_id arg, false otherwise.
390 server_version = self.get_cached_server_version(server)
391 if 'sfa' in server_version:
392 code_tag = server_version['code_tag']
393 code_tag_parts = code_tag.split("-")
395 version_parts = code_tag_parts[0].split(".")
396 major, minor = version_parts[0], version_parts[1]
397 rev = code_tag_parts[1]
399 if int(minor) > 0 or int(rev) > 20:
404 # Get various credential and spec files
406 # Establishes limiting conventions
407 # - conflates MAs and SAs
408 # - assumes last token in slice name is unique
410 # Bootstraps credentials
411 # - bootstrap user credential from self-signed certificate
412 # - bootstrap authority credential from user credential
413 # - bootstrap slice credential from user credential
417 def get_key_file(self):
418 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
419 if (os.path.isfile(file)):
422 self.logger.error("Key file %s does not exist"%file)
426 def get_cert_file(self, key_file):
428 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
429 if (os.path.isfile(cert_file)):
430 # we'd perfer to use Registry issued certs instead of self signed certs.
431 # if this is a Registry cert (GID) then we are done
432 gid = GID(filename=cert_file)
436 # generate self signed certificate
437 k = Keypair(filename=key_file)
438 cert = Certificate(subject=self.user)
440 cert.set_issuer(k, self.user)
442 self.logger.info("Writing self-signed certificate to %s"%cert_file)
443 cert.save_to_file(cert_file)
445 # try to get registry issued cert
447 self.logger.info("Getting Registry issued cert")
449 # *hack. need to set registyr before _get_gid() is called
450 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
451 gid = self._get_gid(type='user')
453 self.logger.info("Writing certificate to %s"%cert_file)
454 gid.save_to_file(cert_file)
456 self.logger.info("Failed to download Registry issued cert")
460 def get_cached_gid(self, file):
465 if (os.path.isfile(file)):
466 gid = GID(filename=file)
470 def get_gid(self, opts, args):
472 Get the specify gid and save it to file
477 gid = self._get_gid(hrn)
478 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
481 def _get_gid(self, hrn=None, type=None):
483 git_gid helper. Retrive the gid from the registry and save it to file.
489 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
491 gid = self.get_cached_gid(gidfile)
493 user_cred = self.get_user_cred()
494 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
496 raise RecordNotFound(args[0])
501 if type == rec['type']:
504 raise RecordNotFound(args[0])
506 gid = GID(string=record['gid'])
507 self.logger.info("Writing gid to %s"%gidfile)
508 gid.save_to_file(filename=gidfile)
512 def get_cached_credential(self, file):
514 Return a cached credential only if it hasn't expired.
516 if (os.path.isfile(file)):
517 credential = Credential(filename=file)
518 # make sure it isnt expired
519 if not credential.get_expiration or \
520 datetime.datetime.today() < credential.get_expiration():
524 def get_user_cred(self):
525 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
526 return self.get_cred(file, 'user', self.user)
528 def get_auth_cred(self):
529 if not self.authority:
530 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
532 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
533 return self.get_cred(file, 'authority', self.authority)
535 def get_slice_cred(self, name):
536 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
537 return self.get_cred(file, 'slice', name)
539 def get_cred(self, file, type, hrn):
540 # attempt to load a cached credential
541 cred = self.get_cached_credential(file)
544 cert_string = self.cert.save_to_string(save_parents=True)
545 user_name = self.user.replace(self.authority + ".", '')
546 if user_name.count(".") > 0:
547 user_name = user_name.replace(".", '_')
548 self.user = self.authority + "." + user_name
549 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
551 # bootstrap slice credential from user credential
552 user_cred = self.get_user_cred().save_to_string(save_parents=True)
553 cred_str = self.registry.GetCredential(user_cred, hrn, type)
556 self.logger.critical("Failed to get %s credential" % type)
559 cred = Credential(string=cred_str)
560 cred.save_to_file(file, save_parents=True)
561 self.logger.info("Writing %s credential to %s" %(type, file))
566 def get_rspec_file(self, rspec):
567 if (os.path.isabs(rspec)):
570 file = os.path.join(self.options.sfi_dir, rspec)
571 if (os.path.isfile(file)):
574 self.logger.critical("No such rspec file %s"%rspec)
577 def get_record_file(self, record):
578 if (os.path.isabs(record)):
581 file = os.path.join(self.options.sfi_dir, record)
582 if (os.path.isfile(file)):
585 self.logger.critical("No such registry record file %s"%record)
588 def load_publickey_string(self, fn):
590 key_string = f.read()
592 # if the filename is a private key file, then extract the public key
593 if "PRIVATE KEY" in key_string:
594 outfn = tempfile.mktemp()
595 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
598 key_string = f.read()
604 def get_component_server_from_hrn(self, hrn):
605 # direct connection to the nodes component manager interface
606 user_cred = self.get_user_cred().save_to_string(save_parents=True)
607 records = self.registry.Resolve(hrn, user_cred)
608 records = filter_records('node', records)
610 self.logger.warning("No such component:%r"% opts.component)
613 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
615 def get_server(self, host, port, keyfile, certfile):
617 Return an instance of an xmlrpc server connection
619 # port is appended onto the domain, before the path. Should look like:
620 # http://domain:port/path
621 host_parts = host.split('/')
622 host_parts[0] = host_parts[0] + ":" + str(port)
623 url = "http://%s" % "/".join(host_parts)
624 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
626 # xxx opts could be retrieved in self.options
627 def get_server_from_opts(self, opts):
629 Return instance of an xmlrpc connection to a slice manager, aggregate
630 or component server depending on the specified opts
632 server = self.slicemgr
633 # direct connection to an aggregate
634 if hasattr(opts, 'aggregate') and opts.aggregate:
635 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
636 # direct connection to the nodes component manager interface
637 if hasattr(opts, 'component') and opts.component:
638 server = self.get_component_server_from_hrn(opts.component)
641 #==========================================================================
642 # Following functions implement the commands
644 # Registry-related commands
645 #==========================================================================
647 def dispatch(self, command, cmd_opts, cmd_args):
648 return getattr(self, command)(cmd_opts, cmd_args)
650 def create_gid(self, opts, args):
655 user_cred = self.get_user_cred().save_to_string(save_parents=True)
656 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
660 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
661 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
662 GID(string=gid).save_to_file(filename)
665 # list entires in named authority registry
666 def list(self, opts, args):
671 user_cred = self.get_user_cred().save_to_string(save_parents=True)
673 list = self.registry.List(hrn, user_cred)
675 raise Exception, "Not enough parameters for the 'list' command"
677 # filter on person, slice, site, node, etc.
678 # THis really should be in the self.filter_records funct def comment...
679 list = filter_records(opts.type, list)
681 print "%s (%s)" % (record['hrn'], record['type'])
684 if not file.startswith(os.sep):
685 file = os.path.join(self.options.sfi_dir, file)
686 save_records_to_file(file, list)
689 # show named registry record
690 def show(self, opts, args):
695 user_cred = self.get_user_cred().save_to_string(save_parents=True)
696 records = self.registry.Resolve(hrn, user_cred)
698 records = filter_records(opts.type, records)
700 print "No record of type", opts.type
701 for record in records:
702 if record['type'] in ['user']:
703 record = UserRecord(dict=record)
704 elif record['type'] in ['slice']:
705 record = SliceRecord(dict=record)
706 elif record['type'] in ['node']:
707 record = NodeRecord(dict=record)
708 elif record['type'].startswith('authority'):
709 record = AuthorityRecord(dict=record)
711 record = SfaRecord(dict=record)
712 if (opts.format == "text"):
715 print record.save_to_string()
718 if not file.startswith(os.sep):
719 file = os.path.join(self.options.sfi_dir, file)
720 save_records_to_file(file, records)
723 def delegate(self, opts, args):
725 delegee_hrn = args[0]
726 if opts.delegate_user:
727 user_cred = self.get_user_cred()
728 cred = self.delegate_cred(user_cred, delegee_hrn)
729 elif opts.delegate_slice:
730 slice_cred = self.get_slice_cred(opts.delegate_slice)
731 cred = self.delegate_cred(slice_cred, delegee_hrn)
733 self.logger.warning("Must specify either --user or --slice <hrn>")
735 delegated_cred = Credential(string=cred)
736 object_hrn = delegated_cred.get_gid_object().get_hrn()
737 if opts.delegate_user:
738 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
739 + get_leaf(object_hrn) + ".cred")
740 elif opts.delegate_slice:
741 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
742 + get_leaf(object_hrn) + ".cred")
744 delegated_cred.save_to_file(dest_fn, save_parents=True)
746 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
748 def delegate_cred(self, object_cred, hrn):
749 # the gid and hrn of the object we are delegating
750 if isinstance(object_cred, str):
751 object_cred = Credential(string=object_cred)
752 object_gid = object_cred.get_gid_object()
753 object_hrn = object_gid.get_hrn()
755 if not object_cred.get_privileges().get_all_delegate():
756 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
759 # the delegating user's gid
760 caller_gid = self._get_gid(self.user)
761 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
763 # the gid of the user who will be delegated to
764 delegee_gid = self._get_gid(hrn)
765 delegee_hrn = delegee_gid.get_hrn()
766 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
767 delegee_gid.save_to_file(filename=delegee_gidfile)
768 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
769 return dcred.save_to_string(save_parents=True)
771 # removed named registry record
772 # - have to first retrieve the record to be removed
773 def remove(self, opts, args):
774 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
782 return self.registry.Remove(hrn, auth_cred, type)
784 # add named registry record
785 def add(self, opts, args):
786 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
790 record_filepath = args[0]
791 rec_file = self.get_record_file(record_filepath)
792 record = load_record_from_file(rec_file).as_dict()
793 return self.registry.Register(record, auth_cred)
795 # update named registry entry
796 def update(self, opts, args):
797 user_cred = self.get_user_cred()
801 rec_file = self.get_record_file(args[0])
802 record = load_record_from_file(rec_file)
803 if record['type'] == "user":
804 if record.get_name() == user_cred.get_gid_object().get_hrn():
805 cred = user_cred.save_to_string(save_parents=True)
807 cred = self.get_auth_cred().save_to_string(save_parents=True)
808 elif record['type'] in ["slice"]:
810 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
811 except xmlrpcprotocol.ServerException, e:
812 # XXX smbaker -- once we have better error return codes, update this
813 # to do something better than a string compare
814 if "Permission error" in e.args[0]:
815 cred = self.get_auth_cred().save_to_string(save_parents=True)
818 elif record.get_type() in ["authority"]:
819 cred = self.get_auth_cred().save_to_string(save_parents=True)
820 elif record.get_type() == 'node':
821 cred = self.get_auth_cred().save_to_string(save_parents=True)
823 raise "unknown record type" + record.get_type()
824 record = record.as_dict()
825 return self.registry.Update(record, cred)
827 def get_trusted_certs(self, opts, args):
829 return uhe trusted certs at this interface
831 trusted_certs = self.registry.get_trusted_certs()
832 for trusted_cert in trusted_certs:
833 gid = GID(string=trusted_cert)
835 cert = Certificate(string=trusted_cert)
836 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
839 def aggregates(self, opts, args):
841 return a list of details about known aggregates
843 user_cred = self.get_user_cred().save_to_string(save_parents=True)
848 result = self.registry.get_aggregates(user_cred, hrn)
852 def registries(self, opts, args):
854 return a list of details about known registries
856 user_cred = self.get_user_cred().save_to_string(save_parents=True)
860 result = self.registry.get_registries(user_cred, hrn)
865 # ==================================================================
866 # Slice-related commands
867 # ==================================================================
869 def version(self, opts, args):
870 if opts.version_local:
871 version=version_core()
873 if opts.version_registry:
876 server = self.get_server_from_opts(opts)
877 version=server.GetVersion()
878 for (k,v) in version.iteritems():
879 print "%-20s: %s"%(k,v)
881 # list instantiated slices
882 def slices(self, opts, args):
884 list instantiated slices
886 user_cred = self.get_user_cred().save_to_string(save_parents=True)
889 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
890 creds.append(delegated_cred)
891 server = self.get_server_from_opts(opts)
892 #results = server.ListSlices(creds, unique_call_id())
893 results = server.ListSlices(creds)
894 display_list(results)
897 # show rspec for named slice
898 def resources(self, opts, args):
899 user_cred = self.get_user_cred().save_to_string(save_parents=True)
900 server = self.slicemgr
902 server = self.get_server_from_opts(opts)
905 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
907 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
914 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
915 creds.append(delegated_cred)
916 if opts.rspec_version:
917 server_version = self.get_cached_server_version(server)
918 if 'sfa' in server_version:
919 # just request the version the client wants
920 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
922 # this must be a protogeni aggregate. We should request a v2 ad rspec
923 # regardless of what the client user requested
924 call_options['rspec_version'] = dict(pg_rspec_request_version)
925 #panos add info options
927 call_options['info'] = opts.info
929 call_args = [creds, call_options]
930 if self.server_supports_call_id_arg(server):
931 call_args.append(unique_call_id())
932 result = server.ListResources(*call_args)
934 if opts.file is None:
935 display_rspec(result, format)
938 if not file.startswith(os.sep):
939 file = os.path.join(self.options.sfi_dir, file)
940 save_rspec_to_file(result, file)
943 # created named slice with given rspec
944 def create(self, opts, args):
945 server = self.get_server_from_opts(opts)
946 server_version = self.get_cached_server_version(server)
948 slice_urn = hrn_to_urn(slice_hrn, 'slice')
949 user_cred = self.get_user_cred()
950 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
953 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
954 creds.append(delegated_cred)
955 rspec_file = self.get_rspec_file(args[1])
956 rspec = open(rspec_file).read()
958 # need to pass along user keys to the aggregate.
960 # { urn: urn:publicid:IDN+emulab.net+user+alice
961 # keys: [<ssh key A>, <ssh key B>]
966 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
967 if slice_records and 'researcher' in slice_records[0]:
968 slice_record = slice_records[0]
969 user_hrns = slice_record['researcher']
970 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
971 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
972 for user_record in user_records:
973 if user_record['type'] != 'user':
975 #user = {'urn': user_cred.get_gid_caller().get_urn(),'keys': []}
976 user = {'urn': user_cred.get_gid_caller().get_urn(), #
977 'keys': user_record['keys'],
978 'email': user_record['email'], # needed for MyPLC
979 'person_id': user_record['person_id'], # needed for MyPLC
980 'first_name': user_record['first_name'], # needed for MyPLC
981 'last_name': user_record['last_name'], # needed for MyPLC
982 'slice_record': slice_record, # needed for legacy refresh peer
983 'key_ids': user_record['key_ids'] # needed for legacy refresh peer
986 all_keys.extend(user_record['keys'])
987 all_key_ids.extend(user_record['key_ids'])
988 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
989 # request. So we will add all to the current caller's list of keys
990 if 'sfa' not in server_version:
992 if user['urn'] == user_cred.get_gid_caller().get_urn():
993 user['keys'] = all_keys
995 call_args = [slice_urn, creds, rspec, users]
996 if self.server_supports_call_id_arg(server):
997 call_args.append(unique_call_id())
999 result = server.CreateSliver(*call_args)
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__":