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.disable_interspersed_args()
283 def read_config(self):
284 config_file = self.options.sfi_dir + os.sep + "sfi_config"
286 config = Config (config_file)
288 self.logger.critical("Failed to read configuration file %s"%config_file)
289 self.logger.info("Make sure to remove the export clauses and to add quotes")
290 if self.options.verbose==0:
291 self.logger.info("Re-run with -v for more details")
293 self.logger.log_exc("Could not read config file %s"%config_file)
298 if (self.options.sm is not None):
299 self.sm_url = self.options.sm
300 elif hasattr(config, "SFI_SM"):
301 self.sm_url = config.SFI_SM
303 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
307 if (self.options.registry is not None):
308 self.reg_url = self.options.registry
309 elif hasattr(config, "SFI_REGISTRY"):
310 self.reg_url = config.SFI_REGISTRY
312 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
317 if (self.options.user is not None):
318 self.user = self.options.user
319 elif hasattr(config, "SFI_USER"):
320 self.user = config.SFI_USER
322 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
326 if (self.options.auth is not None):
327 self.authority = self.options.auth
328 elif hasattr(config, "SFI_AUTH"):
329 self.authority = config.SFI_AUTH
331 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
339 # Establish Connection to SliceMgr and Registry Servers
341 def set_servers(self):
344 # Get key and certificate
345 key_file = self.get_key_file()
346 cert_file = self.get_cert_file(key_file)
347 self.key = Keypair(filename=key_file)
348 self.key_file = key_file
349 self.cert_file = cert_file
350 self.cert = GID(filename=cert_file)
351 self.logger.info("Contacting Registry at: %s"%self.reg_url)
352 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
353 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
354 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, self.options)
357 def get_cached_server_version(self, server):
358 # check local cache first
361 cache_file = self.sfi_dir + os.path.sep + 'sfi_cache.dat'
362 cache_key = server.url + "-version"
364 cache = Cache(cache_file)
367 self.logger.info("Local cache not found at: %s" % cache_file)
370 version = cache.get(cache_key)
373 version = server.GetVersion()
374 # cache version for 24 hours
375 cache.add(cache_key, version, ttl= 60*60*24)
376 self.logger.info("Updating cache file %s" % cache_file)
377 cache.save_to_file(cache_file)
383 def server_supports_call_id_arg(self, server):
385 Returns true if server support the optional call_id arg, false otherwise.
387 server_version = self.get_cached_server_version(server)
388 if 'sfa' in server_version:
389 code_tag = server_version['code_tag']
390 code_tag_parts = code_tag.split("-")
392 version_parts = code_tag_parts[0].split(".")
393 major, minor = version_parts[0], version_parts[1]
394 rev = code_tag_parts[1]
396 if int(minor) > 0 or int(rev) > 20:
401 # Get various credential and spec files
403 # Establishes limiting conventions
404 # - conflates MAs and SAs
405 # - assumes last token in slice name is unique
407 # Bootstraps credentials
408 # - bootstrap user credential from self-signed certificate
409 # - bootstrap authority credential from user credential
410 # - bootstrap slice credential from user credential
414 def get_key_file(self):
415 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
416 if (os.path.isfile(file)):
419 self.logger.error("Key file %s does not exist"%file)
423 def get_cert_file(self, key_file):
425 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
426 if (os.path.isfile(cert_file)):
427 # we'd perfer to use Registry issued certs instead of self signed certs.
428 # if this is a Registry cert (GID) then we are done
429 gid = GID(filename=cert_file)
433 # generate self signed certificate
434 k = Keypair(filename=key_file)
435 cert = Certificate(subject=self.user)
437 cert.set_issuer(k, self.user)
439 self.logger.info("Writing self-signed certificate to %s"%cert_file)
440 cert.save_to_file(cert_file)
442 # try to get registry issued cert
444 self.logger.info("Getting Registry issued cert")
446 # *hack. need to set registyr before _get_gid() is called
447 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, self.options)
448 gid = self._get_gid(type='user')
450 self.logger.info("Writing certificate to %s"%cert_file)
451 gid.save_to_file(cert_file)
453 self.logger.info("Failed to download Registry issued cert")
457 def get_cached_gid(self, file):
462 if (os.path.isfile(file)):
463 gid = GID(filename=file)
467 def get_gid(self, opts, args):
469 Get the specify gid and save it to file
474 gid = self._get_gid(hrn)
475 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
478 def _get_gid(self, hrn=None, type=None):
480 git_gid helper. Retrive the gid from the registry and save it to file.
486 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
488 gid = self.get_cached_gid(gidfile)
490 user_cred = self.get_user_cred()
491 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
493 raise RecordNotFound(args[0])
498 if type == rec['type']:
501 raise RecordNotFound(args[0])
503 gid = GID(string=record['gid'])
504 self.logger.info("Writing gid to %s"%gidfile)
505 gid.save_to_file(filename=gidfile)
509 def get_cached_credential(self, file):
511 Return a cached credential only if it hasn't expired.
513 if (os.path.isfile(file)):
514 credential = Credential(filename=file)
515 # make sure it isnt expired
516 if not credential.get_expiration or \
517 datetime.datetime.today() < credential.get_expiration():
521 def get_user_cred(self):
522 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
523 return self.get_cred(file, 'user', self.user)
525 def get_auth_cred(self):
526 if not self.authority:
527 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
529 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
530 return self.get_cred(file, 'authority', self.authority)
532 def get_slice_cred(self, name):
533 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
534 return self.get_cred(file, 'slice', name)
536 def get_cred(self, file, type, hrn):
537 # attempt to load a cached credential
538 cred = self.get_cached_credential(file)
541 cert_string = self.cert.save_to_string(save_parents=True)
542 user_name = self.user.replace(self.authority + ".", '')
543 if user_name.count(".") > 0:
544 user_name = user_name.replace(".", '_')
545 self.user = self.authority + "." + user_name
546 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
548 # bootstrap slice credential from user credential
549 user_cred = self.get_user_cred().save_to_string(save_parents=True)
550 cred_str = self.registry.GetCredential(user_cred, hrn, type)
553 self.logger.critical("Failed to get %s credential" % type)
556 cred = Credential(string=cred_str)
557 cred.save_to_file(file, save_parents=True)
558 self.logger.info("Writing %s credential to %s" %(type, file))
563 def get_rspec_file(self, rspec):
564 if (os.path.isabs(rspec)):
567 file = os.path.join(self.options.sfi_dir, rspec)
568 if (os.path.isfile(file)):
571 self.logger.critical("No such rspec file %s"%rspec)
574 def get_record_file(self, record):
575 if (os.path.isabs(record)):
578 file = os.path.join(self.options.sfi_dir, record)
579 if (os.path.isfile(file)):
582 self.logger.critical("No such registry record file %s"%record)
585 def load_publickey_string(self, fn):
587 key_string = f.read()
589 # if the filename is a private key file, then extract the public key
590 if "PRIVATE KEY" in key_string:
591 outfn = tempfile.mktemp()
592 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
595 key_string = f.read()
601 def get_component_server_from_hrn(self, hrn):
602 # direct connection to the nodes component manager interface
603 user_cred = self.get_user_cred().save_to_string(save_parents=True)
604 records = self.registry.Resolve(hrn, user_cred)
605 records = filter_records('node', records)
607 self.logger.warning("No such component:%r"% opts.component)
610 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
612 def get_server(self, host, port, keyfile, certfile):
614 Return an instance of an xmlrpc server connection
616 # port is appended onto the domain, before the path. Should look like:
617 # http://domain:port/path
618 host_parts = host.split('/')
619 host_parts[0] = host_parts[0] + ":" + str(port)
620 url = "http://%s" % "/".join(host_parts)
621 return xmlrpcprotocol.get_server(url, keyfile, certfile, self.options)
623 # xxx opts could be retrieved in self.options
624 def get_server_from_opts(self, opts):
626 Return instance of an xmlrpc connection to a slice manager, aggregate
627 or component server depending on the specified opts
629 server = self.slicemgr
630 # direct connection to an aggregate
631 if hasattr(opts, 'aggregate') and opts.aggregate:
632 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
633 # direct connection to the nodes component manager interface
634 if hasattr(opts, 'component') and opts.component:
635 server = self.get_component_server_from_hrn(opts.component)
638 #==========================================================================
639 # Following functions implement the commands
641 # Registry-related commands
642 #==========================================================================
644 def dispatch(self, command, cmd_opts, cmd_args):
645 return getattr(self, command)(cmd_opts, cmd_args)
647 # list entires in named authority registry
648 def list(self, opts, args):
653 user_cred = self.get_user_cred().save_to_string(save_parents=True)
655 list = self.registry.List(hrn, user_cred)
657 raise Exception, "Not enough parameters for the 'list' command"
659 # filter on person, slice, site, node, etc.
660 # THis really should be in the self.filter_records funct def comment...
661 list = filter_records(opts.type, list)
663 print "%s (%s)" % (record['hrn'], record['type'])
666 if not file.startswith(os.sep):
667 file = os.path.join(self.options.sfi_dir, file)
668 save_records_to_file(file, list)
671 # show named registry record
672 def show(self, opts, args):
677 user_cred = self.get_user_cred().save_to_string(save_parents=True)
678 records = self.registry.Resolve(hrn, user_cred)
679 records = filter_records(opts.type, records)
681 print "No record of type", opts.type
682 for record in records:
683 if record['type'] in ['user']:
684 record = UserRecord(dict=record)
685 elif record['type'] in ['slice']:
686 record = SliceRecord(dict=record)
687 elif record['type'] in ['node']:
688 record = NodeRecord(dict=record)
689 elif record['type'].startswith('authority'):
690 record = AuthorityRecord(dict=record)
692 record = SfaRecord(dict=record)
693 if (opts.format == "text"):
696 print record.save_to_string()
700 if not file.startswith(os.sep):
701 file = os.path.join(self.options.sfi_dir, file)
702 save_records_to_file(file, records)
705 def delegate(self, opts, args):
707 delegee_hrn = args[0]
708 if opts.delegate_user:
709 user_cred = self.get_user_cred()
710 cred = self.delegate_cred(user_cred, delegee_hrn)
711 elif opts.delegate_slice:
712 slice_cred = self.get_slice_cred(opts.delegate_slice)
713 cred = self.delegate_cred(slice_cred, delegee_hrn)
715 self.logger.warning("Must specify either --user or --slice <hrn>")
717 delegated_cred = Credential(string=cred)
718 object_hrn = delegated_cred.get_gid_object().get_hrn()
719 if opts.delegate_user:
720 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
721 + get_leaf(object_hrn) + ".cred")
722 elif opts.delegate_slice:
723 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
724 + get_leaf(object_hrn) + ".cred")
726 delegated_cred.save_to_file(dest_fn, save_parents=True)
728 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
730 def delegate_cred(self, object_cred, hrn):
731 # the gid and hrn of the object we are delegating
732 if isinstance(object_cred, str):
733 object_cred = Credential(string=object_cred)
734 object_gid = object_cred.get_gid_object()
735 object_hrn = object_gid.get_hrn()
737 if not object_cred.get_privileges().get_all_delegate():
738 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
741 # the delegating user's gid
742 caller_gid = self._get_gid(self.user)
743 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
745 # the gid of the user who will be delegated to
746 delegee_gid = self._get_gid(hrn)
747 delegee_hrn = delegee_gid.get_hrn()
748 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
749 delegee_gid.save_to_file(filename=delegee_gidfile)
750 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
751 return dcred.save_to_string(save_parents=True)
753 # removed named registry record
754 # - have to first retrieve the record to be removed
755 def remove(self, opts, args):
756 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
764 return self.registry.Remove(hrn, auth_cred, type)
766 # add named registry record
767 def add(self, opts, args):
768 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
772 record_filepath = args[0]
773 rec_file = self.get_record_file(record_filepath)
774 record = load_record_from_file(rec_file).as_dict()
775 return self.registry.Register(record, auth_cred)
777 # update named registry entry
778 def update(self, opts, args):
779 user_cred = self.get_user_cred()
783 rec_file = self.get_record_file(args[0])
784 record = load_record_from_file(rec_file)
785 if record['type'] == "user":
786 if record.get_name() == user_cred.get_gid_object().get_hrn():
787 cred = user_cred.save_to_string(save_parents=True)
789 cred = self.get_auth_cred().save_to_string(save_parents=True)
790 elif record['type'] in ["slice"]:
792 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
793 except xmlrpcprotocol.ServerException, e:
794 # XXX smbaker -- once we have better error return codes, update this
795 # to do something better than a string compare
796 if "Permission error" in e.args[0]:
797 cred = self.get_auth_cred().save_to_string(save_parents=True)
800 elif record.get_type() in ["authority"]:
801 cred = self.get_auth_cred().save_to_string(save_parents=True)
802 elif record.get_type() == 'node':
803 cred = self.get_auth_cred().save_to_string(save_parents=True)
805 raise "unknown record type" + record.get_type()
806 record = record.as_dict()
807 return self.registry.Update(record, cred)
809 def get_trusted_certs(self, opts, args):
811 return uhe trusted certs at this interface
813 trusted_certs = self.registry.get_trusted_certs()
814 for trusted_cert in trusted_certs:
815 gid = GID(string=trusted_cert)
817 cert = Certificate(string=trusted_cert)
818 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
821 def aggregates(self, opts, args):
823 return a list of details about known aggregates
825 user_cred = self.get_user_cred().save_to_string(save_parents=True)
830 result = self.registry.get_aggregates(user_cred, hrn)
834 def registries(self, opts, args):
836 return a list of details about known registries
838 user_cred = self.get_user_cred().save_to_string(save_parents=True)
842 result = self.registry.get_registries(user_cred, hrn)
847 # ==================================================================
848 # Slice-related commands
849 # ==================================================================
851 def version(self, opts, args):
852 if opts.version_local:
853 version=version_core()
855 if opts.version_registry:
858 server = self.get_server_from_opts(opts)
859 version=server.GetVersion()
860 for (k,v) in version.iteritems():
861 print "%-20s: %s"%(k,v)
863 # list instantiated slices
864 def slices(self, opts, args):
866 list instantiated slices
868 user_cred = self.get_user_cred().save_to_string(save_parents=True)
871 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
872 creds.append(delegated_cred)
873 server = self.get_server_from_opts(opts)
874 #results = server.ListSlices(creds, unique_call_id())
875 results = server.ListSlices(creds)
876 display_list(results)
879 # show rspec for named slice
880 def resources(self, opts, args):
881 user_cred = self.get_user_cred().save_to_string(save_parents=True)
882 server = self.slicemgr
884 server = self.get_server_from_opts(opts)
887 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
889 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
896 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
897 creds.append(delegated_cred)
898 if opts.rspec_version:
899 server_version = self.get_cached_server_version(server)
900 if 'sfa' in server_version:
901 # just request the version the client wants
902 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
904 # this must be a protogeni aggregate. We should request a v2 ad rspec
905 # regardless of what the client user requested
906 call_options['rspec_version'] = dict(pg_rspec_request_version)
907 #panos add info options
909 call_options['info'] = opts.info
911 call_args = [creds, call_options]
912 if self.server_supports_call_id_arg(server):
913 call_args.append(unique_call_id())
914 result = server.ListResources(*call_args)
916 if opts.file is None:
917 display_rspec(result, format)
920 if not file.startswith(os.sep):
921 file = os.path.join(self.options.sfi_dir, file)
922 save_rspec_to_file(result, file)
925 # created named slice with given rspec
926 def create(self, opts, args):
928 slice_urn = hrn_to_urn(slice_hrn, 'slice')
929 user_cred = self.get_user_cred()
930 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
933 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
934 creds.append(delegated_cred)
935 rspec_file = self.get_rspec_file(args[1])
936 rspec = open(rspec_file).read()
939 # { urn: urn:publicid:IDN+emulab.net+user+alice
940 # keys: [<ssh key A>, <ssh key B>]
943 server = self.get_server_from_opts(opts)
944 version = self.get_cached_server_version(server)
945 if 'sfa' not in version:
946 # need to pass along user keys if this request is going to a ProtoGENI aggregate
947 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
948 # request. So we will only pass in one user that contains the keys for all
950 user = {'urn': user_cred.get_gid_caller().get_urn(),
952 slice_record = self.registry.Resolve(slice_urn, creds)
953 if slice_record and 'researchers' in slice_record:
954 user_hrns = slice_record['researchers']
955 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
956 user_records = self.registry.Resolve(user_urns, creds)
957 for user_record in user_records:
958 if 'keys' in user_record:
959 user['keys'].extend(user_record['keys'])
962 call_args = [slice_urn, creds, rspec, users]
963 if self.server_supports_call_id_arg(server):
964 call_args.append(unique_call_id())
966 result = server.CreateSliver(*call_args)
970 # get a ticket for the specified slice
971 def get_ticket(self, opts, args):
972 slice_hrn, rspec_path = args[0], args[1]
973 slice_urn = hrn_to_urn(slice_hrn, 'slice')
974 user_cred = self.get_user_cred()
975 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
978 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
979 creds.append(delegated_cred)
980 rspec_file = self.get_rspec_file(rspec_path)
981 rspec = open(rspec_file).read()
982 server = self.get_server_from_opts(opts)
983 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
984 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
985 self.logger.info("writing ticket to %s"%file)
986 ticket = SfaTicket(string=ticket_string)
987 ticket.save_to_file(filename=file, save_parents=True)
989 def redeem_ticket(self, opts, args):
990 ticket_file = args[0]
992 # get slice hrn from the ticket
993 # use this to get the right slice credential
994 ticket = SfaTicket(filename=ticket_file)
996 slice_hrn = ticket.gidObject.get_hrn()
997 slice_urn = hrn_to_urn(slice_hrn, 'slice')
998 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
999 user_cred = self.get_user_cred()
1000 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1002 # get a list of node hostnames from the RSpec
1003 tree = etree.parse(StringIO(ticket.rspec))
1004 root = tree.getroot()
1005 hostnames = root.xpath("./network/site/node/hostname/text()")
1007 # create an xmlrpc connection to the component manager at each of these
1008 # components and gall redeem_ticket
1010 for hostname in hostnames:
1012 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1013 server = self.get_server(hostname, CM_PORT, self.key_file, \
1014 self.cert_file, self.options.debug)
1015 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1016 self.logger.info("Success")
1017 except socket.gaierror:
1018 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1019 except Exception, e:
1020 self.logger.log_exc(e.message)
1023 # delete named slice
1024 def delete(self, opts, args):
1026 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1027 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1028 creds = [slice_cred]
1030 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1031 creds.append(delegated_cred)
1032 server = self.get_server_from_opts(opts)
1034 call_args = [slice_urn, creds]
1035 if self.server_supports_call_id_arg(server):
1036 call_args.append(unique_call_id())
1037 return server.DeleteSliver(*call_args)
1040 def start(self, opts, args):
1042 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1043 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1044 creds = [slice_cred]
1046 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1047 creds.append(delegated_cred)
1048 server = self.get_server_from_opts(opts)
1049 return server.Start(slice_urn, creds)
1052 def stop(self, opts, args):
1054 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1055 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1056 creds = [slice_cred]
1058 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1059 creds.append(delegated_cred)
1060 server = self.get_server_from_opts(opts)
1061 return server.Stop(slice_urn, creds)
1064 def reset(self, opts, args):
1066 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1067 server = self.get_server_from_opts(opts)
1068 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1069 creds = [slice_cred]
1071 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1072 creds.append(delegated_cred)
1073 return server.reset_slice(creds, slice_urn)
1075 def renew(self, opts, args):
1077 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1078 server = self.get_server_from_opts(opts)
1079 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1080 creds = [slice_cred]
1082 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1083 creds.append(delegated_cred)
1086 call_args = [slice_urn, creds, time]
1087 if self.server_supports_call_id_arg(server):
1088 call_args.append(unique_call_id())
1089 return server.RenewSliver(*call_args)
1092 def status(self, opts, args):
1094 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1095 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1096 creds = [slice_cred]
1098 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1099 creds.append(delegated_cred)
1100 server = self.get_server_from_opts(opts)
1101 call_args = [slice_urn, creds]
1102 if self.server_supports_call_id_arg(server):
1103 call_args.append(unique_call_id())
1104 print server.SliverStatus(*call_args)
1107 def shutdown(self, opts, args):
1109 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1110 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1111 creds = [slice_cred]
1113 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1114 creds.append(delegated_cred)
1115 server = self.get_server_from_opts(opts)
1116 return server.Shutdown(slice_urn, creds)
1118 def print_help (self):
1119 self.sfi_parser.print_help()
1120 self.cmd_parser.print_help()
1123 # Main: parse arguments and dispatch to command
1126 self.sfi_parser = self.create_parser()
1127 (options, args) = self.sfi_parser.parse_args()
1128 self.options = options
1130 self.logger.setLevelFromOptVerbose(self.options.verbose)
1131 if options.hashrequest:
1132 self.hashrequest = True
1135 self.logger.critical("No command given. Use -h for help.")
1139 self.cmd_parser = self.create_cmd_parser(command)
1140 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1143 self.logger.info("Command=%s" % command)
1144 if command in ("resources"):
1145 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1146 elif command in ("list", "show", "remove"):
1147 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1148 self.logger.debug('cmd_args %s' % cmd_args)
1151 self.dispatch(command, cmd_opts, cmd_args)
1153 self.logger.critical ("Unknown command %s"%command)
1158 if __name__ == "__main__":