3 # sfi -- slice-based facility interface
13 from lxml import etree
14 from StringIO import StringIO
15 from optparse import OptionParser
16 from sfa.client.client_helper import pg_users_arg, sfa_users_arg
17 from sfa.util.sfalogging import sfi_logger
18 from sfa.trust.certificate import Keypair, Certificate
19 from sfa.trust.gid import GID
20 from sfa.trust.credential import Credential
21 from sfa.trust.sfaticket import SfaTicket
22 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
23 from sfa.rspecs.rspec import RSpec
24 from sfa.rspecs.rspec_converter import RSpecConverter
25 from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn
26 import sfa.client.xmlrpcprotocol as xmlrpcprotocol
27 from sfa.util.config import Config
28 from sfa.util.version import version_core
29 from sfa.util.cache import Cache
30 from sfa.rspecs.version_manager import VersionManager
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_variable_to_file(var, filename, format="text"):
82 f = open(filename, "w")
85 elif format == "pickled":
86 f.write(pickle.dumps(var))
88 # this should never happen
89 print "unknown output format", format
92 def save_rspec_to_file(rspec, filename):
93 if not filename.endswith(".rspec"):
94 filename = filename + ".rspec"
95 f = open(filename, 'w')
100 def save_records_to_file(filename, recordList, format="xml"):
103 for record in recordList:
105 save_record_to_file(filename + "." + str(index), record)
107 save_record_to_file(filename, record)
109 elif format == "xmllist":
110 f = open(filename, "w")
111 f.write("<recordlist>\n")
112 for record in recordList:
113 record = SfaRecord(dict=record)
114 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
115 f.write("</recordlist>\n")
117 elif format == "hrnlist":
118 f = open(filename, "w")
119 for record in recordList:
120 record = SfaRecord(dict=record)
121 f.write(record.get_name() + "\n")
124 # this should never happen
125 print "unknown output format", format
127 def save_record_to_file(filename, record):
128 if record['type'] in ['user']:
129 record = UserRecord(dict=record)
130 elif record['type'] in ['slice']:
131 record = SliceRecord(dict=record)
132 elif record['type'] in ['node']:
133 record = NodeRecord(dict=record)
134 elif record['type'] in ['authority', 'ma', 'sa']:
135 record = AuthorityRecord(dict=record)
137 record = SfaRecord(dict=record)
138 str = record.save_to_string()
139 f=codecs.open(filename, encoding='utf-8',mode="w")
146 def load_record_from_file(filename):
147 f=codecs.open(filename, encoding="utf-8", mode="r")
150 record = SfaRecord(string=str)
155 def unique_call_id(): return uuid.uuid4().urn
159 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
161 # dummy to meet Sfi's expectations for its 'options' field
162 # i.e. s/t we can do setattr on
166 def __init__ (self,options=None):
167 if options is None: options=Sfi.DummyOptions()
168 for opt in Sfi.required_options:
169 if not hasattr(options,opt): setattr(options,opt,None)
170 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
171 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
172 # would be safer to remove self.sfi_dir altogether
173 self.sfi_dir = options.sfi_dir
174 self.options = options
178 self.authority = None
179 self.hashrequest = False
180 self.logger = sfi_logger
181 self.logger.enable_console()
183 def create_cmd_parser(self, command, additional_cmdargs=None):
184 cmdargs = {"list": "authority",
189 "aggregates": "[name]",
190 "registries": "[name]",
191 "create_gid": "[name]",
193 "get_trusted_certs": "cred",
195 "resources": "[name]",
196 "create": "name rspec",
197 "get_ticket": "name rspec",
198 "redeem_ticket": "ticket",
210 if additional_cmdargs:
211 cmdargs.update(additional_cmdargs)
213 if command not in cmdargs:
214 msg="Invalid command\n"
216 msg += ','.join(cmdargs.keys())
217 self.logger.critical(msg)
220 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
221 % (command, cmdargs[command]))
223 # user specifies remote aggregate/sm/component
224 if command in ("resources", "slices", "create", "delete", "start", "stop",
225 "restart", "shutdown", "get_ticket", "renew", "status"):
226 parser.add_option("-a", "--aggregate", dest="aggregate",
227 default=None, help="aggregate host")
228 parser.add_option("-p", "--port", dest="port",
229 default=AGGREGATE_PORT, help="aggregate port")
230 parser.add_option("-c", "--component", dest="component", default=None,
231 help="component hrn")
232 parser.add_option("-d", "--delegate", dest="delegate", default=None,
234 help="Include a credential delegated to the user's root"+\
235 "authority in set of credentials for this call")
237 # registy filter option
238 if command in ("list", "show", "remove"):
239 parser.add_option("-t", "--type", dest="type", type="choice",
240 help="type filter ([all]|user|slice|authority|node|aggregate)",
241 choices=("all", "user", "slice", "authority", "node", "aggregate"),
244 if command in ("resources"):
245 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
246 help="schema type and version of resulting RSpec")
247 parser.add_option("-f", "--format", dest="format", type="choice",
248 help="display format ([xml]|dns|ip)", default="xml",
249 choices=("xml", "dns", "ip"))
250 #panos: a new option to define the type of information about resources a user is interested in
251 parser.add_option("-i", "--info", dest="info",
252 help="optional component information", default=None)
255 # 'create' does return the new rspec, makes sense to save that too
256 if command in ("resources", "show", "list", "create_gid", 'create'):
257 parser.add_option("-o", "--output", dest="file",
258 help="output XML to file", metavar="FILE", default=None)
260 if command in ("show", "list"):
261 parser.add_option("-f", "--format", dest="format", type="choice",
262 help="display format ([text]|xml)", default="text",
263 choices=("text", "xml"))
265 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
266 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
267 choices=("xml", "xmllist", "hrnlist"))
269 if command in ("status", "version"):
270 parser.add_option("-o", "--output", dest="file",
271 help="output dictionary to file", metavar="FILE", default=None)
272 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
273 help="output file format ([text]|pickled)", default="text",
274 choices=("text","pickled"))
276 if command in ("delegate"):
277 parser.add_option("-u", "--user",
278 action="store_true", dest="delegate_user", default=False,
279 help="delegate user credential")
280 parser.add_option("-s", "--slice", dest="delegate_slice",
281 help="delegate slice credential", metavar="HRN", default=None)
283 if command in ("version"):
284 parser.add_option("-a", "--aggregate", dest="aggregate",
285 default=None, help="aggregate host")
286 parser.add_option("-p", "--port", dest="port",
287 default=AGGREGATE_PORT, help="aggregate port")
288 parser.add_option("-R","--registry-version",
289 action="store_true", dest="version_registry", default=False,
290 help="probe registry version instead of slicemgr")
291 parser.add_option("-l","--local",
292 action="store_true", dest="version_local", default=False,
293 help="display version of the local client")
298 def create_parser(self):
300 # Generate command line parser
301 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
302 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
303 parser.add_option("-r", "--registry", dest="registry",
304 help="root registry", metavar="URL", default=None)
305 parser.add_option("-s", "--slicemgr", dest="sm",
306 help="slice manager", metavar="URL", default=None)
307 default_sfi_dir = os.path.expanduser("~/.sfi/")
308 parser.add_option("-d", "--dir", dest="sfi_dir",
309 help="config & working directory - default is " + default_sfi_dir,
310 metavar="PATH", default=default_sfi_dir)
311 parser.add_option("-u", "--user", dest="user",
312 help="user name", metavar="HRN", default=None)
313 parser.add_option("-a", "--auth", dest="auth",
314 help="authority name", metavar="HRN", default=None)
315 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
316 help="verbose mode - cumulative")
317 parser.add_option("-D", "--debug",
318 action="store_true", dest="debug", default=False,
319 help="Debug (xml-rpc) protocol messages")
320 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
321 help="RPC protocol (xmlrpc or soap)")
322 parser.add_option("-k", "--hashrequest",
323 action="store_true", dest="hashrequest", default=False,
324 help="Create a hash of the request that will be authenticated on the server")
325 parser.add_option("-t", "--timeout", dest="timeout", default=None,
326 help="Amout of time tom wait before timing out the request")
327 parser.disable_interspersed_args()
332 def read_config(self):
333 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
335 config = Config (config_file)
337 self.logger.critical("Failed to read configuration file %s"%config_file)
338 self.logger.info("Make sure to remove the export clauses and to add quotes")
339 if self.options.verbose==0:
340 self.logger.info("Re-run with -v for more details")
342 self.logger.log_exc("Could not read config file %s"%config_file)
347 if (self.options.sm is not None):
348 self.sm_url = self.options.sm
349 elif hasattr(config, "SFI_SM"):
350 self.sm_url = config.SFI_SM
352 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
356 if (self.options.registry is not None):
357 self.reg_url = self.options.registry
358 elif hasattr(config, "SFI_REGISTRY"):
359 self.reg_url = config.SFI_REGISTRY
361 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
366 if (self.options.user is not None):
367 self.user = self.options.user
368 elif hasattr(config, "SFI_USER"):
369 self.user = config.SFI_USER
371 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
375 if (self.options.auth is not None):
376 self.authority = self.options.auth
377 elif hasattr(config, "SFI_AUTH"):
378 self.authority = config.SFI_AUTH
380 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
388 # Establish Connection to SliceMgr and Registry Servers
390 def set_servers(self):
393 # Get key and certificate
394 key_file = self.get_key_file()
395 cert_file = self.get_cert_file(key_file)
396 self.key = Keypair(filename=key_file)
397 self.key_file = key_file
398 self.cert_file = cert_file
399 self.cert = GID(filename=cert_file)
400 self.logger.info("Contacting Registry at: %s"%self.reg_url)
401 self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
402 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
403 self.slicemgr = xmlrpcprotocol.server_proxy(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
406 def get_cached_server_version(self, server):
407 # check local cache first
410 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
411 cache_key = server.url + "-version"
413 cache = Cache(cache_file)
416 self.logger.info("Local cache not found at: %s" % cache_file)
419 version = cache.get(cache_key)
422 version = server.GetVersion()
423 # cache version for 24 hours
424 cache.add(cache_key, version, ttl= 60*60*24)
425 self.logger.info("Updating cache file %s" % cache_file)
426 cache.save_to_file(cache_file)
432 def server_supports_options_arg(self, server):
434 Returns true if server support the optional call_id arg, false otherwise.
436 server_version = self.get_cached_server_version(server)
437 if 'sfa' in server_version and 'code_tag' in server_version:
438 code_tag = server_version['code_tag']
439 code_tag_parts = code_tag.split("-")
441 version_parts = code_tag_parts[0].split(".")
442 major, minor = version_parts[0], version_parts[1]
443 rev = code_tag_parts[1]
450 # Get various credential and spec files
452 # Establishes limiting conventions
453 # - conflates MAs and SAs
454 # - assumes last token in slice name is unique
456 # Bootstraps credentials
457 # - bootstrap user credential from self-signed certificate
458 # - bootstrap authority credential from user credential
459 # - bootstrap slice credential from user credential
463 def get_key_file(self):
464 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
465 if (os.path.isfile(file)):
468 self.logger.error("Key file %s does not exist"%file)
472 def get_cert_file(self, key_file):
474 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
475 if (os.path.isfile(cert_file)):
476 # we'd perfer to use Registry issued certs instead of self signed certs.
477 # if this is a Registry cert (GID) then we are done
478 gid = GID(filename=cert_file)
482 # generate self signed certificate
483 k = Keypair(filename=key_file)
484 cert = Certificate(subject=self.user)
486 cert.set_issuer(k, self.user)
488 self.logger.info("Writing self-signed certificate to %s"%cert_file)
489 cert.save_to_file(cert_file)
491 # try to get registry issued cert
493 self.logger.info("Getting Registry issued cert")
495 # *hack. need to set registyr before _get_gid() is called
496 self.registry = xmlrpcprotocol.server_proxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
497 gid = self._get_gid(type='user')
499 self.logger.info("Writing certificate to %s"%cert_file)
500 gid.save_to_file(cert_file)
502 self.logger.info("Failed to download Registry issued cert")
506 def get_cached_gid(self, file):
511 if (os.path.isfile(file)):
512 gid = GID(filename=file)
516 def get_gid(self, opts, args):
518 Get the specify gid and save it to file
523 gid = self._get_gid(hrn)
524 self.logger.debug("Sfi.get_gid-> %s" % gid.save_to_string(save_parents=True))
527 def _get_gid(self, hrn=None, type=None):
529 git_gid helper. Retrive the gid from the registry and save it to file.
535 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
536 gid = self.get_cached_gid(gidfile)
538 user_cred = self.get_user_cred()
539 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
541 raise RecordNotFound(args[0])
546 if type == rec['type']:
549 raise RecordNotFound(args[0])
551 gid = GID(string=record['gid'])
552 self.logger.info("Writing gid to %s"%gidfile)
553 gid.save_to_file(filename=gidfile)
557 def get_cached_credential(self, file):
559 Return a cached credential only if it hasn't expired.
561 if (os.path.isfile(file)):
562 credential = Credential(filename=file)
563 # make sure it isnt expired
564 if not credential.get_expiration or \
565 datetime.datetime.today() < credential.get_expiration():
569 def get_user_cred(self):
570 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
571 return self.get_cred(file, 'user', self.user)
573 def get_auth_cred(self):
574 if not self.authority:
575 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
577 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
578 return self.get_cred(file, 'authority', self.authority)
580 def get_slice_cred(self, name):
581 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
582 return self.get_cred(file, 'slice', name)
584 def get_cred(self, file, type, hrn):
585 # attempt to load a cached credential
586 cred = self.get_cached_credential(file)
589 cert_string = self.cert.save_to_string(save_parents=True)
590 user_name = self.user.replace(self.authority + ".", '')
591 if user_name.count(".") > 0:
592 user_name = user_name.replace(".", '_')
593 self.user = self.authority + "." + user_name
594 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
596 # bootstrap slice credential from user credential
597 user_cred = self.get_user_cred().save_to_string(save_parents=True)
598 cred_str = self.registry.GetCredential(user_cred, hrn, type)
601 self.logger.critical("Failed to get %s credential" % type)
604 cred = Credential(string=cred_str)
605 cred.save_to_file(file, save_parents=True)
606 self.logger.info("Writing %s credential to %s" %(type, file))
611 def get_rspec_file(self, rspec):
612 if (os.path.isabs(rspec)):
615 file = os.path.join(self.options.sfi_dir, rspec)
616 if (os.path.isfile(file)):
619 self.logger.critical("No such rspec file %s"%rspec)
622 def get_record_file(self, record):
623 if (os.path.isabs(record)):
626 file = os.path.join(self.options.sfi_dir, record)
627 if (os.path.isfile(file)):
630 self.logger.critical("No such registry record file %s"%record)
633 def load_publickey_string(self, fn):
635 key_string = f.read()
637 # if the filename is a private key file, then extract the public key
638 if "PRIVATE KEY" in key_string:
639 outfn = tempfile.mktemp()
640 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
643 key_string = f.read()
649 def get_component_proxy_from_hrn(self, hrn):
650 # direct connection to the nodes component manager interface
651 user_cred = self.get_user_cred().save_to_string(save_parents=True)
652 records = self.registry.Resolve(hrn, user_cred)
653 records = filter_records('node', records)
655 self.logger.warning("No such component:%r"% opts.component)
658 return self.server_proxy(record['hostname'], CM_PORT, self.key_file, self.cert_file)
660 def server_proxy(self, host, port, keyfile, certfile):
662 Return an instance of an xmlrpc server connection
664 # port is appended onto the domain, before the path. Should look like:
665 # http://domain:port/path
666 host_parts = host.split('/')
667 host_parts[0] = host_parts[0] + ":" + str(port)
668 url = "http://%s" % "/".join(host_parts)
669 return xmlrpcprotocol.server_proxy(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
671 # xxx opts could be retrieved in self.options
672 def server_proxy_from_opts(self, opts):
674 Return instance of an xmlrpc connection to a slice manager, aggregate
675 or component server depending on the specified opts
677 server = self.slicemgr
678 # direct connection to an aggregate
679 if hasattr(opts, 'aggregate') and opts.aggregate:
680 server = self.server_proxy(opts.aggregate, opts.port, self.key_file, self.cert_file)
681 # direct connection to the nodes component manager interface
682 if hasattr(opts, 'component') and opts.component:
683 server = self.get_component_proxy_from_hrn(opts.component)
686 #==========================================================================
687 # Following functions implement the commands
689 # Registry-related commands
690 #==========================================================================
692 def dispatch(self, command, cmd_opts, cmd_args):
693 return getattr(self, command)(cmd_opts, cmd_args)
695 def create_gid(self, opts, args):
700 user_cred = self.get_user_cred().save_to_string(save_parents=True)
701 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
705 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
706 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
707 GID(string=gid).save_to_file(filename)
710 # list entires in named authority registry
711 def list(self, opts, args):
716 user_cred = self.get_user_cred().save_to_string(save_parents=True)
718 list = self.registry.List(hrn, user_cred)
720 raise Exception, "Not enough parameters for the 'list' command"
722 # filter on person, slice, site, node, etc.
723 # THis really should be in the self.filter_records funct def comment...
724 list = filter_records(opts.type, list)
726 print "%s (%s)" % (record['hrn'], record['type'])
728 save_records_to_file(opts.file, list, opts.fileformat)
731 # show named registry record
732 def show(self, opts, args):
737 user_cred = self.get_user_cred().save_to_string(save_parents=True)
738 records = self.registry.Resolve(hrn, user_cred)
739 records = filter_records(opts.type, records)
741 print "No record of type", opts.type
742 for record in records:
743 if record['type'] in ['user']:
744 record = UserRecord(dict=record)
745 elif record['type'] in ['slice']:
746 record = SliceRecord(dict=record)
747 elif record['type'] in ['node']:
748 record = NodeRecord(dict=record)
749 elif record['type'].startswith('authority'):
750 record = AuthorityRecord(dict=record)
752 record = SfaRecord(dict=record)
753 if (opts.format == "text"):
756 print record.save_to_string()
758 save_records_to_file(opts.file, records, opts.fileformat)
761 def delegate(self, opts, args):
763 delegee_hrn = args[0]
764 if opts.delegate_user:
765 user_cred = self.get_user_cred()
766 cred = self.delegate_cred(user_cred, delegee_hrn)
767 elif opts.delegate_slice:
768 slice_cred = self.get_slice_cred(opts.delegate_slice)
769 cred = self.delegate_cred(slice_cred, delegee_hrn)
771 self.logger.warning("Must specify either --user or --slice <hrn>")
773 delegated_cred = Credential(string=cred)
774 object_hrn = delegated_cred.get_gid_object().get_hrn()
775 if opts.delegate_user:
776 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
777 + get_leaf(object_hrn) + ".cred")
778 elif opts.delegate_slice:
779 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
780 + get_leaf(object_hrn) + ".cred")
782 delegated_cred.save_to_file(dest_fn, save_parents=True)
784 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
786 def delegate_cred(self, object_cred, hrn):
787 # the gid and hrn of the object we are delegating
788 if isinstance(object_cred, str):
789 object_cred = Credential(string=object_cred)
790 object_gid = object_cred.get_gid_object()
791 object_hrn = object_gid.get_hrn()
793 if not object_cred.get_privileges().get_all_delegate():
794 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
797 # the delegating user's gid
798 caller_gid = self._get_gid(self.user)
799 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
801 # the gid of the user who will be delegated to
802 delegee_gid = self._get_gid(hrn)
803 delegee_hrn = delegee_gid.get_hrn()
804 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
805 delegee_gid.save_to_file(filename=delegee_gidfile)
806 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
807 return dcred.save_to_string(save_parents=True)
809 # removed named registry record
810 # - have to first retrieve the record to be removed
811 def remove(self, opts, args):
812 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
820 return self.registry.Remove(hrn, auth_cred, type)
822 # add named registry record
823 def add(self, opts, args):
824 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
828 record_filepath = args[0]
829 rec_file = self.get_record_file(record_filepath)
830 record = load_record_from_file(rec_file).as_dict()
831 return self.registry.Register(record, auth_cred)
833 # update named registry entry
834 def update(self, opts, args):
835 user_cred = self.get_user_cred()
839 rec_file = self.get_record_file(args[0])
840 record = load_record_from_file(rec_file)
841 if record['type'] == "user":
842 if record.get_name() == user_cred.get_gid_object().get_hrn():
843 cred = user_cred.save_to_string(save_parents=True)
845 cred = self.get_auth_cred().save_to_string(save_parents=True)
846 elif record['type'] in ["slice"]:
848 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
849 except xmlrpcprotocol.ServerException, e:
850 # XXX smbaker -- once we have better error return codes, update this
851 # to do something better than a string compare
852 if "Permission error" in e.args[0]:
853 cred = self.get_auth_cred().save_to_string(save_parents=True)
856 elif record.get_type() in ["authority"]:
857 cred = self.get_auth_cred().save_to_string(save_parents=True)
858 elif record.get_type() == 'node':
859 cred = self.get_auth_cred().save_to_string(save_parents=True)
861 raise "unknown record type" + record.get_type()
862 record = record.as_dict()
863 return self.registry.Update(record, cred)
865 def get_trusted_certs(self, opts, args):
867 return uhe trusted certs at this interface
869 trusted_certs = self.registry.get_trusted_certs()
870 for trusted_cert in trusted_certs:
871 gid = GID(string=trusted_cert)
873 cert = Certificate(string=trusted_cert)
874 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
877 def aggregates(self, opts, args):
879 return a list of details about known aggregates
881 user_cred = self.get_user_cred().save_to_string(save_parents=True)
886 result = self.registry.get_aggregates(user_cred, hrn)
890 def registries(self, opts, args):
892 return a list of details about known registries
894 user_cred = self.get_user_cred().save_to_string(save_parents=True)
898 result = self.registry.get_registries(user_cred, hrn)
903 # ==================================================================
904 # Slice-related commands
905 # ==================================================================
907 def version(self, opts, args):
908 if opts.version_local:
909 version=version_core()
911 if opts.version_registry:
914 server = self.server_proxy_from_opts(opts)
915 version=server.GetVersion()
916 for (k,v) in version.iteritems():
917 print "%-20s: %s"%(k,v)
919 save_variable_to_file(version, opts.file, opts.fileformat)
921 # list instantiated slices
922 def slices(self, opts, args):
924 list instantiated slices
926 user_cred = self.get_user_cred().save_to_string(save_parents=True)
929 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
930 creds.append(delegated_cred)
931 server = self.server_proxy_from_opts(opts)
933 if self.server_supports_options_arg(server):
934 options = {'call_id': unique_call_id()}
935 call_args.append(options)
936 results = server.ListSlices(*call_args)
937 display_list(results)
940 # show rspec for named slice
941 def resources(self, opts, args):
942 user_cred = self.get_user_cred().save_to_string(save_parents=True)
943 server = self.slicemgr
944 server = self.server_proxy_from_opts(opts)
947 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
949 options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
956 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
957 creds.append(delegated_cred)
958 if opts.rspec_version:
959 version_manager = VersionManager()
960 server_version = self.get_cached_server_version(server)
961 if 'sfa' in server_version:
962 # just request the version the client wants
963 options['rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
965 # this must be a protogeni aggregate. We should request a v2 ad rspec
966 # regardless of what the client user requested
967 options['rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
968 #panos add info options
970 options['info'] = opts.info
973 if self.server_supports_options_arg(server):
974 options = {'call_id': unique_call_id()}
975 call_args.append(options)
976 result = server.ListResources(*call_args)
977 if opts.file is None:
978 display_rspec(result, opts.format)
980 save_rspec_to_file(result, opts.file)
983 # created named slice with given rspec
984 def create(self, opts, args):
985 server = self.server_proxy_from_opts(opts)
986 server_version = self.get_cached_server_version(server)
988 slice_urn = hrn_to_urn(slice_hrn, 'slice')
989 user_cred = self.get_user_cred()
990 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
992 if hasattr(opts, 'aggregate') and opts.aggregate:
993 delegated_cred = None
995 # delegate the cred to the callers root authority
996 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority)+'.slicemanager')
997 #delegated_cred = self.delegate_cred(slice_cred, get_authority(slice_hrn))
998 #creds.append(delegated_cred)
1000 rspec_file = self.get_rspec_file(args[1])
1001 rspec = open(rspec_file).read()
1003 # need to pass along user keys to the aggregate.
1005 # { urn: urn:publicid:IDN+emulab.net+user+alice
1006 # keys: [<ssh key A>, <ssh key B>]
1009 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
1010 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
1011 slice_record = slice_records[0]
1012 user_hrns = slice_record['researcher']
1013 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
1014 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
1016 if 'sfa' not in server_version:
1017 users = pg_users_arg(user_records)
1018 rspec = RSpec(rspec)
1019 rspec.filter({'component_manager_id': server_version['urn']})
1020 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
1021 creds = [slice_cred]
1023 users = sfa_users_arg(user_records, slice_record)
1024 creds = [slice_cred]
1026 creds.append(delegated_cred)
1027 call_args = [slice_urn, creds, rspec, users]
1028 if self.server_supports_options_arg(server):
1029 options = {'call_id': unique_call_id()}
1030 call_args.append(options)
1031 result = server.CreateSliver(*call_args)
1032 if opts.file is None:
1035 save_rspec_to_file (result, opts.file)
1038 # get a ticket for the specified slice
1039 def get_ticket(self, opts, args):
1040 slice_hrn, rspec_path = args[0], args[1]
1041 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1042 user_cred = self.get_user_cred()
1043 slice_cred = self.get_slice_cred(slice_hrn).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 rspec_file = self.get_rspec_file(rspec_path)
1049 rspec = open(rspec_file).read()
1050 server = self.server_proxy_from_opts(opts)
1051 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1052 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1053 self.logger.info("writing ticket to %s"%file)
1054 ticket = SfaTicket(string=ticket_string)
1055 ticket.save_to_file(filename=file, save_parents=True)
1057 def redeem_ticket(self, opts, args):
1058 ticket_file = args[0]
1060 # get slice hrn from the ticket
1061 # use this to get the right slice credential
1062 ticket = SfaTicket(filename=ticket_file)
1064 slice_hrn = ticket.gidObject.get_hrn()
1065 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1066 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1067 user_cred = self.get_user_cred()
1068 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1070 # get a list of node hostnames from the RSpec
1071 tree = etree.parse(StringIO(ticket.rspec))
1072 root = tree.getroot()
1073 hostnames = root.xpath("./network/site/node/hostname/text()")
1075 # create an xmlrpc connection to the component manager at each of these
1076 # components and gall redeem_ticket
1078 for hostname in hostnames:
1080 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1081 server = self.server_proxy(hostname, CM_PORT, self.key_file, \
1082 self.cert_file, self.options.debug)
1083 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1084 self.logger.info("Success")
1085 except socket.gaierror:
1086 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1087 except Exception, e:
1088 self.logger.log_exc(e.message)
1091 # delete named slice
1092 def delete(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.server_proxy_from_opts(opts)
1101 call_args = [slice_urn, creds]
1102 if self.server_supports_options_arg(server):
1103 options = {'call_id': unique_call_id()}
1104 call_args.append(options)
1105 return server.DeleteSliver(*call_args)
1108 def start(self, opts, args):
1110 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1111 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1112 creds = [slice_cred]
1114 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1115 creds.append(delegated_cred)
1116 server = self.server_proxy_from_opts(opts)
1117 return server.Start(slice_urn, creds)
1120 def stop(self, opts, args):
1122 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1123 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1124 creds = [slice_cred]
1126 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1127 creds.append(delegated_cred)
1128 server = self.server_proxy_from_opts(opts)
1129 return server.Stop(slice_urn, creds)
1132 def reset(self, opts, args):
1134 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1135 server = self.server_proxy_from_opts(opts)
1136 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1137 creds = [slice_cred]
1139 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1140 creds.append(delegated_cred)
1141 return server.reset_slice(creds, slice_urn)
1143 def renew(self, opts, args):
1145 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1146 server = self.server_proxy_from_opts(opts)
1147 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1148 creds = [slice_cred]
1150 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1151 creds.append(delegated_cred)
1154 call_args = [slice_urn, creds, time]
1155 if self.server_supports_options_arg(server):
1156 options = {'call_id': unique_call_id()}
1157 call_args.append(options)
1158 return server.RenewSliver(*call_args)
1161 def status(self, opts, args):
1163 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1164 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1165 creds = [slice_cred]
1167 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1168 creds.append(delegated_cred)
1169 server = self.server_proxy_from_opts(opts)
1170 call_args = [slice_urn, creds]
1171 if self.server_supports_options_arg(server):
1172 options = {'call_id': unique_call_id()}
1173 call_args.append(options)
1174 result = server.SliverStatus(*call_args)
1177 save_variable_to_file(result, opts.file, opts.fileformat)
1180 def shutdown(self, opts, args):
1182 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1183 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1184 creds = [slice_cred]
1186 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1187 creds.append(delegated_cred)
1188 server = self.server_proxy_from_opts(opts)
1189 return server.Shutdown(slice_urn, creds)
1191 def print_help (self):
1192 self.sfi_parser.print_help()
1193 self.cmd_parser.print_help()
1196 # Main: parse arguments and dispatch to command
1199 self.sfi_parser = self.create_parser()
1200 (options, args) = self.sfi_parser.parse_args()
1201 self.options = options
1203 self.logger.setLevelFromOptVerbose(self.options.verbose)
1204 if options.hashrequest:
1205 self.hashrequest = True
1208 self.logger.critical("No command given. Use -h for help.")
1212 self.cmd_parser = self.create_cmd_parser(command)
1213 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1216 self.logger.info("Command=%s" % command)
1217 if command in ("resources"):
1218 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1219 elif command in ("list", "show", "remove"):
1220 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1221 self.logger.debug('cmd_args %s' % cmd_args)
1224 self.dispatch(command, cmd_opts, cmd_args)
1226 self.logger.critical ("Unknown command %s"%command)
1232 if __name__ == "__main__":