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]",
158 "get_trusted_certs": "cred",
160 "resources": "[name]",
161 "create": "name rspec",
162 "get_ticket": "name rspec",
163 "redeem_ticket": "ticket",
175 if additional_cmdargs:
176 cmdargs.update(additional_cmdargs)
178 if command not in cmdargs:
179 msg="Invalid command\n"
181 msg += ','.join(cmdargs.keys())
182 self.logger.critical(msg)
185 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
186 % (command, cmdargs[command]))
188 # user specifies remote aggregate/sm/component
189 if command in ("resources", "slices", "create", "delete", "start", "stop",
190 "restart", "shutdown", "get_ticket", "renew", "status"):
191 parser.add_option("-a", "--aggregate", dest="aggregate",
192 default=None, help="aggregate host")
193 parser.add_option("-p", "--port", dest="port",
194 default=AGGREGATE_PORT, help="aggregate port")
195 parser.add_option("-c", "--component", dest="component", default=None,
196 help="component hrn")
197 parser.add_option("-d", "--delegate", dest="delegate", default=None,
199 help="Include a credential delegated to the user's root"+\
200 "authority in set of credentials for this call")
202 # registy filter option
203 if command in ("list", "show", "remove"):
204 parser.add_option("-t", "--type", dest="type", type="choice",
205 help="type filter ([all]|user|slice|authority|node|aggregate)",
206 choices=("all", "user", "slice", "authority", "node", "aggregate"),
209 if command in ("resources"):
210 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
211 help="schema type and version of resulting RSpec")
212 parser.add_option("-f", "--format", dest="format", type="choice",
213 help="display format ([xml]|dns|ip)", default="xml",
214 choices=("xml", "dns", "ip"))
215 #panos: a new option to define the type of information about resources a user is interested in
216 parser.add_option("-i", "--info", dest="info",
217 help="optional component information", default=None)
220 if command in ("resources", "show", "list"):
221 parser.add_option("-o", "--output", dest="file",
222 help="output XML to file", metavar="FILE", default=None)
224 if command in ("show", "list"):
225 parser.add_option("-f", "--format", dest="format", type="choice",
226 help="display format ([text]|xml)", default="text",
227 choices=("text", "xml"))
229 if command in ("delegate"):
230 parser.add_option("-u", "--user",
231 action="store_true", dest="delegate_user", default=False,
232 help="delegate user credential")
233 parser.add_option("-s", "--slice", dest="delegate_slice",
234 help="delegate slice credential", metavar="HRN", default=None)
236 if command in ("version"):
237 parser.add_option("-a", "--aggregate", dest="aggregate",
238 default=None, help="aggregate host")
239 parser.add_option("-p", "--port", dest="port",
240 default=AGGREGATE_PORT, help="aggregate port")
241 parser.add_option("-R","--registry-version",
242 action="store_true", dest="version_registry", default=False,
243 help="probe registry version instead of slicemgr")
244 parser.add_option("-l","--local",
245 action="store_true", dest="version_local", default=False,
246 help="display version of the local client")
251 def create_parser(self):
253 # Generate command line parser
254 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
255 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
256 parser.add_option("-r", "--registry", dest="registry",
257 help="root registry", metavar="URL", default=None)
258 parser.add_option("-s", "--slicemgr", dest="sm",
259 help="slice manager", metavar="URL", default=None)
260 default_sfi_dir = os.path.expanduser("~/.sfi/")
261 parser.add_option("-d", "--dir", dest="sfi_dir",
262 help="config & working directory - default is " + default_sfi_dir,
263 metavar="PATH", default=default_sfi_dir)
264 parser.add_option("-u", "--user", dest="user",
265 help="user name", metavar="HRN", default=None)
266 parser.add_option("-a", "--auth", dest="auth",
267 help="authority name", metavar="HRN", default=None)
268 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
269 help="verbose mode - cumulative")
270 parser.add_option("-D", "--debug",
271 action="store_true", dest="debug", default=False,
272 help="Debug (xml-rpc) protocol messages")
273 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
274 help="RPC protocol (xmlrpc or soap)")
275 parser.add_option("-k", "--hashrequest",
276 action="store_true", dest="hashrequest", default=False,
277 help="Create a hash of the request that will be authenticated on the server")
278 parser.add_option("-t", "--timeout", dest="timeout", default=30,
279 help="Amout of time tom wait before timing out the request")
280 parser.disable_interspersed_args()
285 def read_config(self):
286 config_file = self.options.sfi_dir + os.sep + "sfi_config"
288 config = Config (config_file)
290 self.logger.critical("Failed to read configuration file %s"%config_file)
291 self.logger.info("Make sure to remove the export clauses and to add quotes")
292 if self.options.verbose==0:
293 self.logger.info("Re-run with -v for more details")
295 self.logger.log_exc("Could not read config file %s"%config_file)
300 if (self.options.sm is not None):
301 self.sm_url = self.options.sm
302 elif hasattr(config, "SFI_SM"):
303 self.sm_url = config.SFI_SM
305 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
309 if (self.options.registry is not None):
310 self.reg_url = self.options.registry
311 elif hasattr(config, "SFI_REGISTRY"):
312 self.reg_url = config.SFI_REGISTRY
314 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
319 if (self.options.user is not None):
320 self.user = self.options.user
321 elif hasattr(config, "SFI_USER"):
322 self.user = config.SFI_USER
324 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
328 if (self.options.auth is not None):
329 self.authority = self.options.auth
330 elif hasattr(config, "SFI_AUTH"):
331 self.authority = config.SFI_AUTH
333 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
341 # Establish Connection to SliceMgr and Registry Servers
343 def set_servers(self):
346 # Get key and certificate
347 key_file = self.get_key_file()
348 cert_file = self.get_cert_file(key_file)
349 self.key = Keypair(filename=key_file)
350 self.key_file = key_file
351 self.cert_file = cert_file
352 self.cert = GID(filename=cert_file)
353 self.logger.info("Contacting Registry at: %s"%self.reg_url)
354 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
355 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
356 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
359 def get_cached_server_version(self, server):
360 # check local cache first
363 cache_file = self.sfi_dir + os.path.sep + 'sfi_cache.dat'
364 cache_key = server.url + "-version"
366 cache = Cache(cache_file)
369 self.logger.info("Local cache not found at: %s" % cache_file)
372 version = cache.get(cache_key)
375 version = server.GetVersion()
376 # cache version for 24 hours
377 cache.add(cache_key, version, ttl= 60*60*24)
378 self.logger.info("Updating cache file %s" % cache_file)
379 cache.save_to_file(cache_file)
385 def server_supports_call_id_arg(self, server):
387 Returns true if server support the optional call_id arg, false otherwise.
389 server_version = self.get_cached_server_version(server)
390 if 'sfa' in server_version:
391 code_tag = server_version['code_tag']
392 code_tag_parts = code_tag.split("-")
394 version_parts = code_tag_parts[0].split(".")
395 major, minor = version_parts[0], version_parts[1]
396 rev = code_tag_parts[1]
398 if int(minor) > 0 or int(rev) > 20:
403 # Get various credential and spec files
405 # Establishes limiting conventions
406 # - conflates MAs and SAs
407 # - assumes last token in slice name is unique
409 # Bootstraps credentials
410 # - bootstrap user credential from self-signed certificate
411 # - bootstrap authority credential from user credential
412 # - bootstrap slice credential from user credential
416 def get_key_file(self):
417 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
418 if (os.path.isfile(file)):
421 self.logger.error("Key file %s does not exist"%file)
425 def get_cert_file(self, key_file):
427 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
428 if (os.path.isfile(cert_file)):
429 # we'd perfer to use Registry issued certs instead of self signed certs.
430 # if this is a Registry cert (GID) then we are done
431 gid = GID(filename=cert_file)
435 # generate self signed certificate
436 k = Keypair(filename=key_file)
437 cert = Certificate(subject=self.user)
439 cert.set_issuer(k, self.user)
441 self.logger.info("Writing self-signed certificate to %s"%cert_file)
442 cert.save_to_file(cert_file)
444 # try to get registry issued cert
446 self.logger.info("Getting Registry issued cert")
448 # *hack. need to set registyr before _get_gid() is called
449 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
450 gid = self._get_gid(type='user')
452 self.logger.info("Writing certificate to %s"%cert_file)
453 gid.save_to_file(cert_file)
455 self.logger.info("Failed to download Registry issued cert")
459 def get_cached_gid(self, file):
464 if (os.path.isfile(file)):
465 gid = GID(filename=file)
469 def get_gid(self, opts, args):
471 Get the specify gid and save it to file
476 gid = self._get_gid(hrn)
477 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
480 def _get_gid(self, hrn=None, type=None):
482 git_gid helper. Retrive the gid from the registry and save it to file.
488 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
490 gid = self.get_cached_gid(gidfile)
492 user_cred = self.get_user_cred()
493 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
495 raise RecordNotFound(args[0])
500 if type == rec['type']:
503 raise RecordNotFound(args[0])
505 gid = GID(string=record['gid'])
506 self.logger.info("Writing gid to %s"%gidfile)
507 gid.save_to_file(filename=gidfile)
511 def get_cached_credential(self, file):
513 Return a cached credential only if it hasn't expired.
515 if (os.path.isfile(file)):
516 credential = Credential(filename=file)
517 # make sure it isnt expired
518 if not credential.get_expiration or \
519 datetime.datetime.today() < credential.get_expiration():
523 def get_user_cred(self):
524 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
525 return self.get_cred(file, 'user', self.user)
527 def get_auth_cred(self):
528 if not self.authority:
529 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
531 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
532 return self.get_cred(file, 'authority', self.authority)
534 def get_slice_cred(self, name):
535 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
536 return self.get_cred(file, 'slice', name)
538 def get_cred(self, file, type, hrn):
539 # attempt to load a cached credential
540 cred = self.get_cached_credential(file)
543 cert_string = self.cert.save_to_string(save_parents=True)
544 user_name = self.user.replace(self.authority + ".", '')
545 if user_name.count(".") > 0:
546 user_name = user_name.replace(".", '_')
547 self.user = self.authority + "." + user_name
548 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
550 # bootstrap slice credential from user credential
551 user_cred = self.get_user_cred().save_to_string(save_parents=True)
552 cred_str = self.registry.GetCredential(user_cred, hrn, type)
555 self.logger.critical("Failed to get %s credential" % type)
558 cred = Credential(string=cred_str)
559 cred.save_to_file(file, save_parents=True)
560 self.logger.info("Writing %s credential to %s" %(type, file))
565 def get_rspec_file(self, rspec):
566 if (os.path.isabs(rspec)):
569 file = os.path.join(self.options.sfi_dir, rspec)
570 if (os.path.isfile(file)):
573 self.logger.critical("No such rspec file %s"%rspec)
576 def get_record_file(self, record):
577 if (os.path.isabs(record)):
580 file = os.path.join(self.options.sfi_dir, record)
581 if (os.path.isfile(file)):
584 self.logger.critical("No such registry record file %s"%record)
587 def load_publickey_string(self, fn):
589 key_string = f.read()
591 # if the filename is a private key file, then extract the public key
592 if "PRIVATE KEY" in key_string:
593 outfn = tempfile.mktemp()
594 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
597 key_string = f.read()
603 def get_component_server_from_hrn(self, hrn):
604 # direct connection to the nodes component manager interface
605 user_cred = self.get_user_cred().save_to_string(save_parents=True)
606 records = self.registry.Resolve(hrn, user_cred)
607 records = filter_records('node', records)
609 self.logger.warning("No such component:%r"% opts.component)
612 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
614 def get_server(self, host, port, keyfile, certfile):
616 Return an instance of an xmlrpc server connection
618 # port is appended onto the domain, before the path. Should look like:
619 # http://domain:port/path
620 host_parts = host.split('/')
621 host_parts[0] = host_parts[0] + ":" + str(port)
622 url = "http://%s" % "/".join(host_parts)
623 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
625 # xxx opts could be retrieved in self.options
626 def get_server_from_opts(self, opts):
628 Return instance of an xmlrpc connection to a slice manager, aggregate
629 or component server depending on the specified opts
631 server = self.slicemgr
632 # direct connection to an aggregate
633 if hasattr(opts, 'aggregate') and opts.aggregate:
634 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
635 # direct connection to the nodes component manager interface
636 if hasattr(opts, 'component') and opts.component:
637 server = self.get_component_server_from_hrn(opts.component)
640 #==========================================================================
641 # Following functions implement the commands
643 # Registry-related commands
644 #==========================================================================
646 def dispatch(self, command, cmd_opts, cmd_args):
647 return getattr(self, command)(cmd_opts, cmd_args)
649 # list entires in named authority registry
650 def list(self, opts, args):
655 user_cred = self.get_user_cred().save_to_string(save_parents=True)
657 list = self.registry.List(hrn, user_cred)
659 raise Exception, "Not enough parameters for the 'list' command"
661 # filter on person, slice, site, node, etc.
662 # THis really should be in the self.filter_records funct def comment...
663 list = filter_records(opts.type, list)
665 print "%s (%s)" % (record['hrn'], record['type'])
668 if not file.startswith(os.sep):
669 file = os.path.join(self.options.sfi_dir, file)
670 save_records_to_file(file, list)
673 # show named registry record
674 def show(self, opts, args):
679 user_cred = self.get_user_cred().save_to_string(save_parents=True)
680 records = self.registry.Resolve(hrn, user_cred)
681 records = filter_records(opts.type, records)
683 print "No record of type", opts.type
684 for record in records:
685 if record['type'] in ['user']:
686 record = UserRecord(dict=record)
687 elif record['type'] in ['slice']:
688 record = SliceRecord(dict=record)
689 elif record['type'] in ['node']:
690 record = NodeRecord(dict=record)
691 elif record['type'].startswith('authority'):
692 record = AuthorityRecord(dict=record)
694 record = SfaRecord(dict=record)
695 if (opts.format == "text"):
698 print record.save_to_string()
702 if not file.startswith(os.sep):
703 file = os.path.join(self.options.sfi_dir, file)
704 save_records_to_file(file, records)
707 def delegate(self, opts, args):
709 delegee_hrn = args[0]
710 if opts.delegate_user:
711 user_cred = self.get_user_cred()
712 cred = self.delegate_cred(user_cred, delegee_hrn)
713 elif opts.delegate_slice:
714 slice_cred = self.get_slice_cred(opts.delegate_slice)
715 cred = self.delegate_cred(slice_cred, delegee_hrn)
717 self.logger.warning("Must specify either --user or --slice <hrn>")
719 delegated_cred = Credential(string=cred)
720 object_hrn = delegated_cred.get_gid_object().get_hrn()
721 if opts.delegate_user:
722 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
723 + get_leaf(object_hrn) + ".cred")
724 elif opts.delegate_slice:
725 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
726 + get_leaf(object_hrn) + ".cred")
728 delegated_cred.save_to_file(dest_fn, save_parents=True)
730 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
732 def delegate_cred(self, object_cred, hrn):
733 # the gid and hrn of the object we are delegating
734 if isinstance(object_cred, str):
735 object_cred = Credential(string=object_cred)
736 object_gid = object_cred.get_gid_object()
737 object_hrn = object_gid.get_hrn()
739 if not object_cred.get_privileges().get_all_delegate():
740 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
743 # the delegating user's gid
744 caller_gid = self._get_gid(self.user)
745 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
747 # the gid of the user who will be delegated to
748 delegee_gid = self._get_gid(hrn)
749 delegee_hrn = delegee_gid.get_hrn()
750 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
751 delegee_gid.save_to_file(filename=delegee_gidfile)
752 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
753 return dcred.save_to_string(save_parents=True)
755 # removed named registry record
756 # - have to first retrieve the record to be removed
757 def remove(self, opts, args):
758 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
766 return self.registry.Remove(hrn, auth_cred, type)
768 # add named registry record
769 def add(self, opts, args):
770 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
774 record_filepath = args[0]
775 rec_file = self.get_record_file(record_filepath)
776 record = load_record_from_file(rec_file).as_dict()
777 return self.registry.Register(record, auth_cred)
779 # update named registry entry
780 def update(self, opts, args):
781 user_cred = self.get_user_cred()
785 rec_file = self.get_record_file(args[0])
786 record = load_record_from_file(rec_file)
787 if record['type'] == "user":
788 if record.get_name() == user_cred.get_gid_object().get_hrn():
789 cred = user_cred.save_to_string(save_parents=True)
791 cred = self.get_auth_cred().save_to_string(save_parents=True)
792 elif record['type'] in ["slice"]:
794 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
795 except xmlrpcprotocol.ServerException, e:
796 # XXX smbaker -- once we have better error return codes, update this
797 # to do something better than a string compare
798 if "Permission error" in e.args[0]:
799 cred = self.get_auth_cred().save_to_string(save_parents=True)
802 elif record.get_type() in ["authority"]:
803 cred = self.get_auth_cred().save_to_string(save_parents=True)
804 elif record.get_type() == 'node':
805 cred = self.get_auth_cred().save_to_string(save_parents=True)
807 raise "unknown record type" + record.get_type()
808 record = record.as_dict()
809 return self.registry.Update(record, cred)
811 def get_trusted_certs(self, opts, args):
813 return uhe trusted certs at this interface
815 trusted_certs = self.registry.get_trusted_certs()
816 for trusted_cert in trusted_certs:
817 gid = GID(string=trusted_cert)
819 cert = Certificate(string=trusted_cert)
820 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
823 def aggregates(self, opts, args):
825 return a list of details about known aggregates
827 user_cred = self.get_user_cred().save_to_string(save_parents=True)
832 result = self.registry.get_aggregates(user_cred, hrn)
836 def registries(self, opts, args):
838 return a list of details about known registries
840 user_cred = self.get_user_cred().save_to_string(save_parents=True)
844 result = self.registry.get_registries(user_cred, hrn)
849 # ==================================================================
850 # Slice-related commands
851 # ==================================================================
853 def version(self, opts, args):
854 if opts.version_local:
855 version=version_core()
857 if opts.version_registry:
860 server = self.get_server_from_opts(opts)
861 version=server.GetVersion()
862 for (k,v) in version.iteritems():
863 print "%-20s: %s"%(k,v)
865 # list instantiated slices
866 def slices(self, opts, args):
868 list instantiated slices
870 user_cred = self.get_user_cred().save_to_string(save_parents=True)
873 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
874 creds.append(delegated_cred)
875 server = self.get_server_from_opts(opts)
876 #results = server.ListSlices(creds, unique_call_id())
877 results = server.ListSlices(creds)
878 display_list(results)
881 # show rspec for named slice
882 def resources(self, opts, args):
883 user_cred = self.get_user_cred().save_to_string(save_parents=True)
884 server = self.slicemgr
886 server = self.get_server_from_opts(opts)
889 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
891 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
898 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
899 creds.append(delegated_cred)
900 if opts.rspec_version:
901 server_version = self.get_cached_server_version(server)
902 if 'sfa' in server_version:
903 # just request the version the client wants
904 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
906 # this must be a protogeni aggregate. We should request a v2 ad rspec
907 # regardless of what the client user requested
908 call_options['rspec_version'] = dict(pg_rspec_request_version)
909 #panos add info options
911 call_options['info'] = opts.info
913 call_args = [creds, call_options]
914 if self.server_supports_call_id_arg(server):
915 call_args.append(unique_call_id())
916 result = server.ListResources(*call_args)
918 if opts.file is None:
919 display_rspec(result, format)
922 if not file.startswith(os.sep):
923 file = os.path.join(self.options.sfi_dir, file)
924 save_rspec_to_file(result, file)
927 # created named slice with given rspec
928 def create(self, opts, args):
930 slice_urn = hrn_to_urn(slice_hrn, 'slice')
931 user_cred = self.get_user_cred()
932 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
935 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
936 creds.append(delegated_cred)
937 rspec_file = self.get_rspec_file(args[1])
938 rspec = open(rspec_file).read()
941 # { urn: urn:publicid:IDN+emulab.net+user+alice
942 # keys: [<ssh key A>, <ssh key B>]
945 server = self.get_server_from_opts(opts)
946 version = self.get_cached_server_version(server)
947 if 'sfa' not in version:
948 # need to pass along user keys if this request is going to a ProtoGENI aggregate
949 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
950 # request. So we will only pass in one user that contains the keys for all
952 user = {'urn': user_cred.get_gid_caller().get_urn(),
954 slice_record = self.registry.Resolve(slice_urn, creds)
955 if slice_record and 'researchers' in slice_record:
956 user_hrns = slice_record['researchers']
957 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
958 user_records = self.registry.Resolve(user_urns, creds)
959 for user_record in user_records:
960 if 'keys' in user_record:
961 user['keys'].extend(user_record['keys'])
964 call_args = [slice_urn, creds, rspec, users]
965 if self.server_supports_call_id_arg(server):
966 call_args.append(unique_call_id())
968 result = server.CreateSliver(*call_args)
972 # get a ticket for the specified slice
973 def get_ticket(self, opts, args):
974 slice_hrn, rspec_path = args[0], args[1]
975 slice_urn = hrn_to_urn(slice_hrn, 'slice')
976 user_cred = self.get_user_cred()
977 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
980 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
981 creds.append(delegated_cred)
982 rspec_file = self.get_rspec_file(rspec_path)
983 rspec = open(rspec_file).read()
984 server = self.get_server_from_opts(opts)
985 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
986 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
987 self.logger.info("writing ticket to %s"%file)
988 ticket = SfaTicket(string=ticket_string)
989 ticket.save_to_file(filename=file, save_parents=True)
991 def redeem_ticket(self, opts, args):
992 ticket_file = args[0]
994 # get slice hrn from the ticket
995 # use this to get the right slice credential
996 ticket = SfaTicket(filename=ticket_file)
998 slice_hrn = ticket.gidObject.get_hrn()
999 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1000 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1001 user_cred = self.get_user_cred()
1002 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1004 # get a list of node hostnames from the RSpec
1005 tree = etree.parse(StringIO(ticket.rspec))
1006 root = tree.getroot()
1007 hostnames = root.xpath("./network/site/node/hostname/text()")
1009 # create an xmlrpc connection to the component manager at each of these
1010 # components and gall redeem_ticket
1012 for hostname in hostnames:
1014 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1015 server = self.get_server(hostname, CM_PORT, self.key_file, \
1016 self.cert_file, self.options.debug)
1017 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1018 self.logger.info("Success")
1019 except socket.gaierror:
1020 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1021 except Exception, e:
1022 self.logger.log_exc(e.message)
1025 # delete named slice
1026 def delete(self, opts, args):
1028 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1029 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1030 creds = [slice_cred]
1032 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1033 creds.append(delegated_cred)
1034 server = self.get_server_from_opts(opts)
1036 call_args = [slice_urn, creds]
1037 if self.server_supports_call_id_arg(server):
1038 call_args.append(unique_call_id())
1039 return server.DeleteSliver(*call_args)
1042 def start(self, opts, args):
1044 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1045 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1046 creds = [slice_cred]
1048 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1049 creds.append(delegated_cred)
1050 server = self.get_server_from_opts(opts)
1051 return server.Start(slice_urn, creds)
1054 def stop(self, opts, args):
1056 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1057 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1058 creds = [slice_cred]
1060 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1061 creds.append(delegated_cred)
1062 server = self.get_server_from_opts(opts)
1063 return server.Stop(slice_urn, creds)
1066 def reset(self, opts, args):
1068 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1069 server = self.get_server_from_opts(opts)
1070 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1071 creds = [slice_cred]
1073 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1074 creds.append(delegated_cred)
1075 return server.reset_slice(creds, slice_urn)
1077 def renew(self, opts, args):
1079 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1080 server = self.get_server_from_opts(opts)
1081 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1082 creds = [slice_cred]
1084 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1085 creds.append(delegated_cred)
1088 call_args = [slice_urn, creds, time]
1089 if self.server_supports_call_id_arg(server):
1090 call_args.append(unique_call_id())
1091 return server.RenewSliver(*call_args)
1094 def status(self, opts, args):
1096 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1097 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1098 creds = [slice_cred]
1100 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1101 creds.append(delegated_cred)
1102 server = self.get_server_from_opts(opts)
1103 call_args = [slice_urn, creds]
1104 if self.server_supports_call_id_arg(server):
1105 call_args.append(unique_call_id())
1106 print server.SliverStatus(*call_args)
1109 def shutdown(self, opts, args):
1111 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1112 slice_cred = self.get_slice_cred(slice_hrn).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)
1117 server = self.get_server_from_opts(opts)
1118 return server.Shutdown(slice_urn, creds)
1120 def print_help (self):
1121 self.sfi_parser.print_help()
1122 self.cmd_parser.print_help()
1125 # Main: parse arguments and dispatch to command
1128 self.sfi_parser = self.create_parser()
1129 (options, args) = self.sfi_parser.parse_args()
1130 self.options = options
1132 self.logger.setLevelFromOptVerbose(self.options.verbose)
1133 if options.hashrequest:
1134 self.hashrequest = True
1137 self.logger.critical("No command given. Use -h for help.")
1141 self.cmd_parser = self.create_cmd_parser(command)
1142 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1145 self.logger.info("Command=%s" % command)
1146 if command in ("resources"):
1147 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1148 elif command in ("list", "show", "remove"):
1149 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1150 self.logger.debug('cmd_args %s' % cmd_args)
1153 self.dispatch(command, cmd_opts, cmd_args)
1155 self.logger.critical ("Unknown command %s"%command)
1160 if __name__ == "__main__":