3 # sfi -- slice-based facility interface
16 from lxml import etree
17 from StringIO import StringIO
18 from types import StringTypes, ListType
19 from optparse import OptionParser
21 from sfa.util.sfalogging import sfi_logger
22 from sfa.trust.certificate import Keypair, Certificate
23 from sfa.trust.gid import GID
24 from sfa.trust.credential import Credential
25 from sfa.util.sfaticket import SfaTicket
26 from sfa.util.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
27 from sfa.util.xrn import Xrn, get_leaf, get_authority, hrn_to_urn
28 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
29 from sfa.util.config import Config
30 from sfa.util.version import version_core
31 from sfa.util.cache import Cache
32 from sfa.rspecs.rspec_version import RSpecVersion
33 from sfa.rspecs.pg_rspec import pg_rspec_request_version
38 # utility methods here
40 def display_rspec(rspec, format='rspec'):
42 tree = etree.parse(StringIO(rspec))
44 result = root.xpath("./network/site/node/hostname/text()")
45 elif format in ['ip']:
46 # The IP address is not yet part of the new RSpec
47 # so this doesn't do anything yet.
48 tree = etree.parse(StringIO(rspec))
50 result = root.xpath("./network/site/node/ipv4/text()")
57 def display_list(results):
58 for result in results:
61 def display_records(recordList, dump=False):
62 ''' Print all fields in the record'''
63 for record in recordList:
64 display_record(record, dump)
66 def display_record(record, dump=False):
70 info = record.getdict()
71 print "%s (%s)" % (info['hrn'], info['type'])
75 def filter_records(type, records):
77 for record in records:
78 if (record['type'] == type) or (type == "all"):
79 filtered_records.append(record)
80 return filtered_records
84 def save_variable_to_file(var, filename, format="text"):
85 f = open(filename, "w")
88 elif format == "pickled":
89 f.write(pickle.dumps(var))
91 # this should never happen
92 print "unknown output format", format
95 def save_rspec_to_file(rspec, filename):
96 if not filename.endswith(".rspec"):
97 filename = filename + ".rspec"
98 f = open(filename, 'w')
103 def save_records_to_file(filename, recordList, format="xml"):
106 for record in recordList:
108 save_record_to_file(filename + "." + str(index), record)
110 save_record_to_file(filename, record)
112 elif format == "xmllist":
113 f = open(filename, "w")
114 f.write("<recordlist>\n")
115 for record in recordList:
116 record = SfaRecord(dict=record)
117 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
118 f.write("</recordlist>\n");
120 elif format == "hrnlist":
121 f = open(filename, "w")
122 for record in recordList:
123 record = SfaRecord(dict=record)
124 f.write(record.get_name() + "\n")
127 # this should never happen
128 print "unknown output format", format
130 def save_record_to_file(filename, record):
131 if record['type'] in ['user']:
132 record = UserRecord(dict=record)
133 elif record['type'] in ['slice']:
134 record = SliceRecord(dict=record)
135 elif record['type'] in ['node']:
136 record = NodeRecord(dict=record)
137 elif record['type'] in ['authority', 'ma', 'sa']:
138 record = AuthorityRecord(dict=record)
140 record = SfaRecord(dict=record)
141 str = record.save_to_string()
142 f=codecs.open(filename, encoding='utf-8',mode="w")
149 def load_record_from_file(filename):
150 f=codecs.open(filename, encoding="utf-8", mode="r")
153 record = SfaRecord(string=str)
158 def unique_call_id(): return uuid.uuid4().urn
162 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
164 # dummy to meet Sfi's expectations for its 'options' field
165 # i.e. s/t we can do setattr on
169 def __init__ (self,options=None):
170 if options is None: options=Sfi.DummyOptions()
171 for opt in Sfi.required_options:
172 if not hasattr(options,opt): setattr(options,opt,None)
173 if not hasattr(options,'sfi_dir'): options.sfi_dir=os.path.expanduser("~/.sfi/")
174 # xxx oops, this is dangerous, sounds like ww sometimes have discrepency
175 # would be safer to remove self.sfi_dir altogether
176 self.sfi_dir = options.sfi_dir
177 self.options = options
181 self.authority = None
182 self.hashrequest = False
183 self.logger = sfi_logger
184 self.logger.enable_console()
186 def create_cmd_parser(self, command, additional_cmdargs=None):
187 cmdargs = {"list": "authority",
192 "aggregates": "[name]",
193 "registries": "[name]",
194 "create_gid": "[name]",
196 "get_trusted_certs": "cred",
198 "resources": "[name]",
199 "create": "name rspec",
200 "get_ticket": "name rspec",
201 "redeem_ticket": "ticket",
213 if additional_cmdargs:
214 cmdargs.update(additional_cmdargs)
216 if command not in cmdargs:
217 msg="Invalid command\n"
219 msg += ','.join(cmdargs.keys())
220 self.logger.critical(msg)
223 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
224 % (command, cmdargs[command]))
226 # user specifies remote aggregate/sm/component
227 if command in ("resources", "slices", "create", "delete", "start", "stop",
228 "restart", "shutdown", "get_ticket", "renew", "status"):
229 parser.add_option("-a", "--aggregate", dest="aggregate",
230 default=None, help="aggregate host")
231 parser.add_option("-p", "--port", dest="port",
232 default=AGGREGATE_PORT, help="aggregate port")
233 parser.add_option("-c", "--component", dest="component", default=None,
234 help="component hrn")
235 parser.add_option("-d", "--delegate", dest="delegate", default=None,
237 help="Include a credential delegated to the user's root"+\
238 "authority in set of credentials for this call")
240 # registy filter option
241 if command in ("list", "show", "remove"):
242 parser.add_option("-t", "--type", dest="type", type="choice",
243 help="type filter ([all]|user|slice|authority|node|aggregate)",
244 choices=("all", "user", "slice", "authority", "node", "aggregate"),
247 if command in ("resources"):
248 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
249 help="schema type and version of resulting RSpec")
250 parser.add_option("-f", "--format", dest="format", type="choice",
251 help="display format ([xml]|dns|ip)", default="xml",
252 choices=("xml", "dns", "ip"))
253 #panos: a new option to define the type of information about resources a user is interested in
254 parser.add_option("-i", "--info", dest="info",
255 help="optional component information", default=None)
258 # 'create' does return the new rspec, makes sense to save that too
259 if command in ("resources", "show", "list", "create_gid", 'create'):
260 parser.add_option("-o", "--output", dest="file",
261 help="output XML to file", metavar="FILE", default=None)
263 if command in ("show", "list"):
264 parser.add_option("-f", "--format", dest="format", type="choice",
265 help="display format ([text]|xml)", default="text",
266 choices=("text", "xml"))
268 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
269 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
270 choices=("xml", "xmllist", "hrnlist"))
272 if command in ("status"):
273 parser.add_option("-o", "--output", dest="file",
274 help="output dictionary to file", metavar="FILE", default=None)
275 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
276 help="output file format ([text]|pickled)", default="text",
277 choices=("text","pickled"))
279 if command in ("delegate"):
280 parser.add_option("-u", "--user",
281 action="store_true", dest="delegate_user", default=False,
282 help="delegate user credential")
283 parser.add_option("-s", "--slice", dest="delegate_slice",
284 help="delegate slice credential", metavar="HRN", default=None)
286 if command in ("version"):
287 parser.add_option("-a", "--aggregate", dest="aggregate",
288 default=None, help="aggregate host")
289 parser.add_option("-p", "--port", dest="port",
290 default=AGGREGATE_PORT, help="aggregate port")
291 parser.add_option("-R","--registry-version",
292 action="store_true", dest="version_registry", default=False,
293 help="probe registry version instead of slicemgr")
294 parser.add_option("-l","--local",
295 action="store_true", dest="version_local", default=False,
296 help="display version of the local client")
301 def create_parser(self):
303 # Generate command line parser
304 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
305 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
306 parser.add_option("-r", "--registry", dest="registry",
307 help="root registry", metavar="URL", default=None)
308 parser.add_option("-s", "--slicemgr", dest="sm",
309 help="slice manager", metavar="URL", default=None)
310 default_sfi_dir = os.path.expanduser("~/.sfi/")
311 parser.add_option("-d", "--dir", dest="sfi_dir",
312 help="config & working directory - default is " + default_sfi_dir,
313 metavar="PATH", default=default_sfi_dir)
314 parser.add_option("-u", "--user", dest="user",
315 help="user name", metavar="HRN", default=None)
316 parser.add_option("-a", "--auth", dest="auth",
317 help="authority name", metavar="HRN", default=None)
318 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
319 help="verbose mode - cumulative")
320 parser.add_option("-D", "--debug",
321 action="store_true", dest="debug", default=False,
322 help="Debug (xml-rpc) protocol messages")
323 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
324 help="RPC protocol (xmlrpc or soap)")
325 parser.add_option("-k", "--hashrequest",
326 action="store_true", dest="hashrequest", default=False,
327 help="Create a hash of the request that will be authenticated on the server")
328 parser.add_option("-t", "--timeout", dest="timeout", default=None,
329 help="Amout of time tom wait before timing out the request")
330 parser.disable_interspersed_args()
335 def read_config(self):
336 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
338 config = Config (config_file)
340 self.logger.critical("Failed to read configuration file %s"%config_file)
341 self.logger.info("Make sure to remove the export clauses and to add quotes")
342 if self.options.verbose==0:
343 self.logger.info("Re-run with -v for more details")
345 self.logger.log_exc("Could not read config file %s"%config_file)
350 if (self.options.sm is not None):
351 self.sm_url = self.options.sm
352 elif hasattr(config, "SFI_SM"):
353 self.sm_url = config.SFI_SM
355 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
359 if (self.options.registry is not None):
360 self.reg_url = self.options.registry
361 elif hasattr(config, "SFI_REGISTRY"):
362 self.reg_url = config.SFI_REGISTRY
364 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
369 if (self.options.user is not None):
370 self.user = self.options.user
371 elif hasattr(config, "SFI_USER"):
372 self.user = config.SFI_USER
374 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
378 if (self.options.auth is not None):
379 self.authority = self.options.auth
380 elif hasattr(config, "SFI_AUTH"):
381 self.authority = config.SFI_AUTH
383 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
391 # Establish Connection to SliceMgr and Registry Servers
393 def set_servers(self):
396 # Get key and certificate
397 key_file = self.get_key_file()
398 cert_file = self.get_cert_file(key_file)
399 self.key = Keypair(filename=key_file)
400 self.key_file = key_file
401 self.cert_file = cert_file
402 self.cert = GID(filename=cert_file)
403 self.logger.info("Contacting Registry at: %s"%self.reg_url)
404 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
405 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
406 self.slicemgr = xmlrpcprotocol.get_server(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
409 def get_cached_server_version(self, server):
410 # check local cache first
413 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
414 cache_key = server.url + "-version"
416 cache = Cache(cache_file)
419 self.logger.info("Local cache not found at: %s" % cache_file)
422 version = cache.get(cache_key)
425 version = server.GetVersion()
426 # cache version for 24 hours
427 cache.add(cache_key, version, ttl= 60*60*24)
428 self.logger.info("Updating cache file %s" % cache_file)
429 cache.save_to_file(cache_file)
435 def server_supports_call_id_arg(self, server):
437 Returns true if server support the optional call_id arg, false otherwise.
439 server_version = self.get_cached_server_version(server)
440 if 'sfa' in server_version:
441 code_tag = server_version['code_tag']
442 code_tag_parts = code_tag.split("-")
444 version_parts = code_tag_parts[0].split(".")
445 major, minor = version_parts[0], version_parts[1]
446 rev = code_tag_parts[1]
448 if int(minor) > 0 or int(rev) > 20:
453 # Get various credential and spec files
455 # Establishes limiting conventions
456 # - conflates MAs and SAs
457 # - assumes last token in slice name is unique
459 # Bootstraps credentials
460 # - bootstrap user credential from self-signed certificate
461 # - bootstrap authority credential from user credential
462 # - bootstrap slice credential from user credential
466 def get_key_file(self):
467 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
468 if (os.path.isfile(file)):
471 self.logger.error("Key file %s does not exist"%file)
475 def get_cert_file(self, key_file):
477 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
478 if (os.path.isfile(cert_file)):
479 # we'd perfer to use Registry issued certs instead of self signed certs.
480 # if this is a Registry cert (GID) then we are done
481 gid = GID(filename=cert_file)
485 # generate self signed certificate
486 k = Keypair(filename=key_file)
487 cert = Certificate(subject=self.user)
489 cert.set_issuer(k, self.user)
491 self.logger.info("Writing self-signed certificate to %s"%cert_file)
492 cert.save_to_file(cert_file)
494 # try to get registry issued cert
496 self.logger.info("Getting Registry issued cert")
498 # *hack. need to set registyr before _get_gid() is called
499 self.registry = xmlrpcprotocol.get_server(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
500 gid = self._get_gid(type='user')
502 self.logger.info("Writing certificate to %s"%cert_file)
503 gid.save_to_file(cert_file)
505 self.logger.info("Failed to download Registry issued cert")
509 def get_cached_gid(self, file):
514 if (os.path.isfile(file)):
515 gid = GID(filename=file)
519 def get_gid(self, opts, args):
521 Get the specify gid and save it to file
526 gid = self._get_gid(hrn)
527 self.logger.debug("Sfi.get_gid-> %s",gid.save_to_string(save_parents=True))
530 def _get_gid(self, hrn=None, type=None):
532 git_gid helper. Retrive the gid from the registry and save it to file.
538 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
540 gid = self.get_cached_gid(gidfile)
542 user_cred = self.get_user_cred()
543 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
545 raise RecordNotFound(args[0])
550 if type == rec['type']:
553 raise RecordNotFound(args[0])
555 gid = GID(string=record['gid'])
556 self.logger.info("Writing gid to %s"%gidfile)
557 gid.save_to_file(filename=gidfile)
561 def get_cached_credential(self, file):
563 Return a cached credential only if it hasn't expired.
565 if (os.path.isfile(file)):
566 credential = Credential(filename=file)
567 # make sure it isnt expired
568 if not credential.get_expiration or \
569 datetime.datetime.today() < credential.get_expiration():
573 def get_user_cred(self):
574 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
575 return self.get_cred(file, 'user', self.user)
577 def get_auth_cred(self):
578 if not self.authority:
579 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
581 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
582 return self.get_cred(file, 'authority', self.authority)
584 def get_slice_cred(self, name):
585 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
586 return self.get_cred(file, 'slice', name)
588 def get_cred(self, file, type, hrn):
589 # attempt to load a cached credential
590 cred = self.get_cached_credential(file)
593 cert_string = self.cert.save_to_string(save_parents=True)
594 user_name = self.user.replace(self.authority + ".", '')
595 if user_name.count(".") > 0:
596 user_name = user_name.replace(".", '_')
597 self.user = self.authority + "." + user_name
598 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
600 # bootstrap slice credential from user credential
601 user_cred = self.get_user_cred().save_to_string(save_parents=True)
602 cred_str = self.registry.GetCredential(user_cred, hrn, type)
605 self.logger.critical("Failed to get %s credential" % type)
608 cred = Credential(string=cred_str)
609 cred.save_to_file(file, save_parents=True)
610 self.logger.info("Writing %s credential to %s" %(type, file))
615 def get_rspec_file(self, rspec):
616 if (os.path.isabs(rspec)):
619 file = os.path.join(self.options.sfi_dir, rspec)
620 if (os.path.isfile(file)):
623 self.logger.critical("No such rspec file %s"%rspec)
626 def get_record_file(self, record):
627 if (os.path.isabs(record)):
630 file = os.path.join(self.options.sfi_dir, record)
631 if (os.path.isfile(file)):
634 self.logger.critical("No such registry record file %s"%record)
637 def load_publickey_string(self, fn):
639 key_string = f.read()
641 # if the filename is a private key file, then extract the public key
642 if "PRIVATE KEY" in key_string:
643 outfn = tempfile.mktemp()
644 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
647 key_string = f.read()
653 def get_component_server_from_hrn(self, hrn):
654 # direct connection to the nodes component manager interface
655 user_cred = self.get_user_cred().save_to_string(save_parents=True)
656 records = self.registry.Resolve(hrn, user_cred)
657 records = filter_records('node', records)
659 self.logger.warning("No such component:%r"% opts.component)
662 return self.get_server(record['hostname'], CM_PORT, self.key_file, self.cert_file)
664 def get_server(self, host, port, keyfile, certfile):
666 Return an instance of an xmlrpc server connection
668 # port is appended onto the domain, before the path. Should look like:
669 # http://domain:port/path
670 host_parts = host.split('/')
671 host_parts[0] = host_parts[0] + ":" + str(port)
672 url = "http://%s" % "/".join(host_parts)
673 return xmlrpcprotocol.get_server(url, keyfile, certfile, timeout=self.options.timeout, verbose=self.options.debug)
675 # xxx opts could be retrieved in self.options
676 def get_server_from_opts(self, opts):
678 Return instance of an xmlrpc connection to a slice manager, aggregate
679 or component server depending on the specified opts
681 server = self.slicemgr
682 # direct connection to an aggregate
683 if hasattr(opts, 'aggregate') and opts.aggregate:
684 server = self.get_server(opts.aggregate, opts.port, self.key_file, self.cert_file)
685 # direct connection to the nodes component manager interface
686 if hasattr(opts, 'component') and opts.component:
687 server = self.get_component_server_from_hrn(opts.component)
690 #==========================================================================
691 # Following functions implement the commands
693 # Registry-related commands
694 #==========================================================================
696 def dispatch(self, command, cmd_opts, cmd_args):
697 return getattr(self, command)(cmd_opts, cmd_args)
699 def create_gid(self, opts, args):
704 user_cred = self.get_user_cred().save_to_string(save_parents=True)
705 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
709 filename = os.sep.join([self.sfi_dir, '%s.gid' % target_hrn])
710 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
711 GID(string=gid).save_to_file(filename)
714 # list entires in named authority registry
715 def list(self, opts, args):
720 user_cred = self.get_user_cred().save_to_string(save_parents=True)
722 list = self.registry.List(hrn, user_cred)
724 raise Exception, "Not enough parameters for the 'list' command"
726 # filter on person, slice, site, node, etc.
727 # THis really should be in the self.filter_records funct def comment...
728 list = filter_records(opts.type, list)
730 print "%s (%s)" % (record['hrn'], record['type'])
732 save_records_to_file(opts.file, list, opts.fileformat)
735 # show named registry record
736 def show(self, opts, args):
741 user_cred = self.get_user_cred().save_to_string(save_parents=True)
742 records = self.registry.Resolve(hrn, user_cred)
743 records = filter_records(opts.type, records)
745 print "No record of type", opts.type
746 for record in records:
747 if record['type'] in ['user']:
748 record = UserRecord(dict=record)
749 elif record['type'] in ['slice']:
750 record = SliceRecord(dict=record)
751 elif record['type'] in ['node']:
752 record = NodeRecord(dict=record)
753 elif record['type'].startswith('authority'):
754 record = AuthorityRecord(dict=record)
756 record = SfaRecord(dict=record)
757 if (opts.format == "text"):
760 print record.save_to_string()
762 save_records_to_file(opts.file, records, opts.fileformat)
765 def delegate(self, opts, args):
767 delegee_hrn = args[0]
768 if opts.delegate_user:
769 user_cred = self.get_user_cred()
770 cred = self.delegate_cred(user_cred, delegee_hrn)
771 elif opts.delegate_slice:
772 slice_cred = self.get_slice_cred(opts.delegate_slice)
773 cred = self.delegate_cred(slice_cred, delegee_hrn)
775 self.logger.warning("Must specify either --user or --slice <hrn>")
777 delegated_cred = Credential(string=cred)
778 object_hrn = delegated_cred.get_gid_object().get_hrn()
779 if opts.delegate_user:
780 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
781 + get_leaf(object_hrn) + ".cred")
782 elif opts.delegate_slice:
783 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
784 + get_leaf(object_hrn) + ".cred")
786 delegated_cred.save_to_file(dest_fn, save_parents=True)
788 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
790 def delegate_cred(self, object_cred, hrn):
791 # the gid and hrn of the object we are delegating
792 if isinstance(object_cred, str):
793 object_cred = Credential(string=object_cred)
794 object_gid = object_cred.get_gid_object()
795 object_hrn = object_gid.get_hrn()
797 if not object_cred.get_privileges().get_all_delegate():
798 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
801 # the delegating user's gid
802 caller_gid = self._get_gid(self.user)
803 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
805 # the gid of the user who will be delegated to
806 delegee_gid = self._get_gid(hrn)
807 delegee_hrn = delegee_gid.get_hrn()
808 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
809 delegee_gid.save_to_file(filename=delegee_gidfile)
810 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
811 return dcred.save_to_string(save_parents=True)
813 # removed named registry record
814 # - have to first retrieve the record to be removed
815 def remove(self, opts, args):
816 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
824 return self.registry.Remove(hrn, auth_cred, type)
826 # add named registry record
827 def add(self, opts, args):
828 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
832 record_filepath = args[0]
833 rec_file = self.get_record_file(record_filepath)
834 record = load_record_from_file(rec_file).as_dict()
835 return self.registry.Register(record, auth_cred)
837 # update named registry entry
838 def update(self, opts, args):
839 user_cred = self.get_user_cred()
843 rec_file = self.get_record_file(args[0])
844 record = load_record_from_file(rec_file)
845 if record['type'] == "user":
846 if record.get_name() == user_cred.get_gid_object().get_hrn():
847 cred = user_cred.save_to_string(save_parents=True)
849 cred = self.get_auth_cred().save_to_string(save_parents=True)
850 elif record['type'] in ["slice"]:
852 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
853 except xmlrpcprotocol.ServerException, e:
854 # XXX smbaker -- once we have better error return codes, update this
855 # to do something better than a string compare
856 if "Permission error" in e.args[0]:
857 cred = self.get_auth_cred().save_to_string(save_parents=True)
860 elif record.get_type() in ["authority"]:
861 cred = self.get_auth_cred().save_to_string(save_parents=True)
862 elif record.get_type() == 'node':
863 cred = self.get_auth_cred().save_to_string(save_parents=True)
865 raise "unknown record type" + record.get_type()
866 record = record.as_dict()
867 return self.registry.Update(record, cred)
869 def get_trusted_certs(self, opts, args):
871 return uhe trusted certs at this interface
873 trusted_certs = self.registry.get_trusted_certs()
874 for trusted_cert in trusted_certs:
875 gid = GID(string=trusted_cert)
877 cert = Certificate(string=trusted_cert)
878 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())
881 def aggregates(self, opts, args):
883 return a list of details about known aggregates
885 user_cred = self.get_user_cred().save_to_string(save_parents=True)
890 result = self.registry.get_aggregates(user_cred, hrn)
894 def registries(self, opts, args):
896 return a list of details about known registries
898 user_cred = self.get_user_cred().save_to_string(save_parents=True)
902 result = self.registry.get_registries(user_cred, hrn)
907 # ==================================================================
908 # Slice-related commands
909 # ==================================================================
911 def version(self, opts, args):
912 if opts.version_local:
913 version=version_core()
915 if opts.version_registry:
918 server = self.get_server_from_opts(opts)
919 version=server.GetVersion()
920 for (k,v) in version.iteritems():
921 print "%-20s: %s"%(k,v)
923 # list instantiated slices
924 def slices(self, opts, args):
926 list instantiated slices
928 user_cred = self.get_user_cred().save_to_string(save_parents=True)
931 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
932 creds.append(delegated_cred)
933 server = self.get_server_from_opts(opts)
934 #results = server.ListSlices(creds, unique_call_id())
935 results = server.ListSlices(creds)
936 display_list(results)
939 # show rspec for named slice
940 def resources(self, opts, args):
941 user_cred = self.get_user_cred().save_to_string(save_parents=True)
942 server = self.slicemgr
944 server = self.get_server_from_opts(opts)
947 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
949 call_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 server_version = self.get_cached_server_version(server)
960 if 'sfa' in server_version:
961 # just request the version the client wants
962 call_options['rspec_version'] = dict(RSpecVersion(opts.rspec_version))
964 # this must be a protogeni aggregate. We should request a v2 ad rspec
965 # regardless of what the client user requested
966 call_options['rspec_version'] = dict(pg_rspec_request_version)
967 #panos add info options
969 call_options['info'] = opts.info
971 call_args = [creds, call_options]
972 if self.server_supports_call_id_arg(server):
973 call_args.append(unique_call_id())
974 result = server.ListResources(*call_args)
975 if opts.file is None:
976 display_rspec(result, opts.format)
978 save_rspec_to_file(result, opts.file)
981 # created named slice with given rspec
982 def create(self, opts, args):
983 server = self.get_server_from_opts(opts)
984 server_version = self.get_cached_server_version(server)
986 slice_urn = hrn_to_urn(slice_hrn, 'slice')
987 user_cred = self.get_user_cred()
988 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
991 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
992 creds.append(delegated_cred)
993 rspec_file = self.get_rspec_file(args[1])
994 rspec = open(rspec_file).read()
996 # need to pass along user keys to the aggregate.
998 # { urn: urn:publicid:IDN+emulab.net+user+alice
999 # keys: [<ssh key A>, <ssh key B>]
1004 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
1005 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
1006 slice_record = slice_records[0]
1007 user_hrns = slice_record['researcher']
1008 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
1009 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
1010 for user_record in user_records:
1011 if user_record['type'] != 'user':
1013 #user = {'urn': user_cred.get_gid_caller().get_urn(),'keys': []}
1014 user = {'urn': user_cred.get_gid_caller().get_urn(), #
1015 'keys': user_record['keys'],
1016 'email': user_record['email'], # needed for MyPLC
1017 'person_id': user_record['person_id'], # needed for MyPLC
1018 'first_name': user_record['first_name'], # needed for MyPLC
1019 'last_name': user_record['last_name'], # needed for MyPLC
1020 'slice_record': slice_record, # needed for legacy refresh peer
1021 'key_ids': user_record['key_ids'] # needed for legacy refresh peer
1024 all_keys.extend(user_record['keys'])
1025 all_key_ids.extend(user_record['key_ids'])
1026 # ProtoGeni Aggregates will only install the keys of the user that is issuing the
1027 # request. So we will add all to the current caller's list of keys
1028 if 'sfa' not in server_version:
1030 if user['urn'] == user_cred.get_gid_caller().get_urn():
1031 user['keys'] = all_keys
1033 call_args = [slice_urn, creds, rspec, users]
1034 if self.server_supports_call_id_arg(server):
1035 call_args.append(unique_call_id())
1037 result = server.CreateSliver(*call_args)
1038 if opts.file is None:
1041 save_rspec_to_file (result, opts.file)
1044 # get a ticket for the specified slice
1045 def get_ticket(self, opts, args):
1046 slice_hrn, rspec_path = args[0], args[1]
1047 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1048 user_cred = self.get_user_cred()
1049 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1050 creds = [slice_cred]
1052 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1053 creds.append(delegated_cred)
1054 rspec_file = self.get_rspec_file(rspec_path)
1055 rspec = open(rspec_file).read()
1056 server = self.get_server_from_opts(opts)
1057 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1058 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1059 self.logger.info("writing ticket to %s"%file)
1060 ticket = SfaTicket(string=ticket_string)
1061 ticket.save_to_file(filename=file, save_parents=True)
1063 def redeem_ticket(self, opts, args):
1064 ticket_file = args[0]
1066 # get slice hrn from the ticket
1067 # use this to get the right slice credential
1068 ticket = SfaTicket(filename=ticket_file)
1070 slice_hrn = ticket.gidObject.get_hrn()
1071 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1072 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1073 user_cred = self.get_user_cred()
1074 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1076 # get a list of node hostnames from the RSpec
1077 tree = etree.parse(StringIO(ticket.rspec))
1078 root = tree.getroot()
1079 hostnames = root.xpath("./network/site/node/hostname/text()")
1081 # create an xmlrpc connection to the component manager at each of these
1082 # components and gall redeem_ticket
1084 for hostname in hostnames:
1086 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1087 server = self.get_server(hostname, CM_PORT, self.key_file, \
1088 self.cert_file, self.options.debug)
1089 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1090 self.logger.info("Success")
1091 except socket.gaierror:
1092 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1093 except Exception, e:
1094 self.logger.log_exc(e.message)
1097 # delete named slice
1098 def delete(self, opts, args):
1100 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1101 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1102 creds = [slice_cred]
1104 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1105 creds.append(delegated_cred)
1106 server = self.get_server_from_opts(opts)
1108 call_args = [slice_urn, creds]
1109 if self.server_supports_call_id_arg(server):
1110 call_args.append(unique_call_id())
1111 return server.DeleteSliver(*call_args)
1114 def start(self, opts, args):
1116 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1117 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1118 creds = [slice_cred]
1120 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1121 creds.append(delegated_cred)
1122 server = self.get_server_from_opts(opts)
1123 return server.Start(slice_urn, creds)
1126 def stop(self, opts, args):
1128 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1129 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1130 creds = [slice_cred]
1132 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1133 creds.append(delegated_cred)
1134 server = self.get_server_from_opts(opts)
1135 return server.Stop(slice_urn, creds)
1138 def reset(self, opts, args):
1140 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1141 server = self.get_server_from_opts(opts)
1142 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1143 creds = [slice_cred]
1145 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1146 creds.append(delegated_cred)
1147 return server.reset_slice(creds, slice_urn)
1149 def renew(self, opts, args):
1151 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1152 server = self.get_server_from_opts(opts)
1153 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1154 creds = [slice_cred]
1156 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1157 creds.append(delegated_cred)
1160 call_args = [slice_urn, creds, time]
1161 if self.server_supports_call_id_arg(server):
1162 call_args.append(unique_call_id())
1163 return server.RenewSliver(*call_args)
1166 def status(self, opts, args):
1168 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1169 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1170 creds = [slice_cred]
1172 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1173 creds.append(delegated_cred)
1174 server = self.get_server_from_opts(opts)
1175 call_args = [slice_urn, creds]
1176 if self.server_supports_call_id_arg(server):
1177 call_args.append(unique_call_id())
1178 result = server.SliverStatus(*call_args)
1181 save_variable_to_file(result, opts.file, opts.fileformat)
1184 def shutdown(self, opts, args):
1186 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1187 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1188 creds = [slice_cred]
1190 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1191 creds.append(delegated_cred)
1192 server = self.get_server_from_opts(opts)
1193 return server.Shutdown(slice_urn, creds)
1195 def print_help (self):
1196 self.sfi_parser.print_help()
1197 self.cmd_parser.print_help()
1200 # Main: parse arguments and dispatch to command
1203 self.sfi_parser = self.create_parser()
1204 (options, args) = self.sfi_parser.parse_args()
1205 self.options = options
1207 self.logger.setLevelFromOptVerbose(self.options.verbose)
1208 if options.hashrequest:
1209 self.hashrequest = True
1212 self.logger.critical("No command given. Use -h for help.")
1216 self.cmd_parser = self.create_cmd_parser(command)
1217 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
1220 self.logger.info("Command=%s" % command)
1221 if command in ("resources"):
1222 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
1223 elif command in ("list", "show", "remove"):
1224 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
1225 self.logger.debug('cmd_args %s' % cmd_args)
1228 self.dispatch(command, cmd_opts, cmd_args)
1230 self.logger.critical ("Unknown command %s"%command)
1236 if __name__ == "__main__":