2 # xxx NOTE this will soon be reviewed to take advantage of sfaclientlib
12 from lxml import etree
13 from StringIO import StringIO
14 from optparse import OptionParser
16 from sfa.trust.certificate import Keypair, Certificate
17 from sfa.trust.gid import GID
18 from sfa.trust.credential import Credential
19 from sfa.trust.sfaticket import SfaTicket
21 from sfa.util.sfalogging import sfi_logger
22 from sfa.util.xrn import get_leaf, get_authority, hrn_to_urn
23 from sfa.util.config import Config
24 from sfa.util.version import version_core
25 from sfa.util.cache import Cache
27 from sfa.storage.record import SfaRecord, UserRecord, SliceRecord, NodeRecord, AuthorityRecord
29 from sfa.rspecs.rspec import RSpec
30 from sfa.rspecs.rspec_converter import RSpecConverter
31 from sfa.rspecs.version_manager import VersionManager
33 from sfa.client.sfaserverproxy import SfaServerProxy, ServerException
34 from sfa.client.client_helper import pg_users_arg, sfa_users_arg
35 from sfa.client.return_value import ReturnValue
40 # utility methods here
42 def display_rspec(rspec, format='rspec'):
44 tree = etree.parse(StringIO(rspec))
46 result = root.xpath("./network/site/node/hostname/text()")
47 elif format in ['ip']:
48 # The IP address is not yet part of the new RSpec
49 # so this doesn't do anything yet.
50 tree = etree.parse(StringIO(rspec))
52 result = root.xpath("./network/site/node/ipv4/text()")
59 def display_list(results):
60 for result in results:
63 def display_records(recordList, dump=False):
64 ''' Print all fields in the record'''
65 for record in recordList:
66 display_record(record, dump)
68 def display_record(record, dump=False):
72 info = record.getdict()
73 print "%s (%s)" % (info['hrn'], info['type'])
77 def filter_records(type, records):
79 for record in records:
80 if (record['type'] == type) or (type == "all"):
81 filtered_records.append(record)
82 return filtered_records
86 def save_variable_to_file(var, filename, format="text"):
87 f = open(filename, "w")
90 elif format == "pickled":
91 f.write(pickle.dumps(var))
93 # this should never happen
94 print "unknown output format", format
97 def save_rspec_to_file(rspec, filename):
98 if not filename.endswith(".rspec"):
99 filename = filename + ".rspec"
100 f = open(filename, 'w')
105 def save_records_to_file(filename, recordList, format="xml"):
108 for record in recordList:
110 save_record_to_file(filename + "." + str(index), record)
112 save_record_to_file(filename, record)
114 elif format == "xmllist":
115 f = open(filename, "w")
116 f.write("<recordlist>\n")
117 for record in recordList:
118 record = SfaRecord(dict=record)
119 f.write('<record hrn="' + record.get_name() + '" type="' + record.get_type() + '" />\n')
120 f.write("</recordlist>\n")
122 elif format == "hrnlist":
123 f = open(filename, "w")
124 for record in recordList:
125 record = SfaRecord(dict=record)
126 f.write(record.get_name() + "\n")
129 # this should never happen
130 print "unknown output format", format
132 def save_record_to_file(filename, record):
133 if record['type'] in ['user']:
134 record = UserRecord(dict=record)
135 elif record['type'] in ['slice']:
136 record = SliceRecord(dict=record)
137 elif record['type'] in ['node']:
138 record = NodeRecord(dict=record)
139 elif record['type'] in ['authority', 'ma', 'sa']:
140 record = AuthorityRecord(dict=record)
142 record = SfaRecord(dict=record)
143 str = record.save_to_string()
144 f=codecs.open(filename, encoding='utf-8',mode="w")
151 def load_record_from_file(filename):
152 f=codecs.open(filename, encoding="utf-8", mode="r")
155 record = SfaRecord(string=str)
160 def unique_call_id(): return uuid.uuid4().urn
164 required_options=['verbose', 'debug', 'registry', 'sm', 'auth', 'user']
167 def default_sfi_dir ():
168 if os.path.isfile("./sfi_config"):
171 return os.path.expanduser("~/.sfi/")
173 # dummy to meet Sfi's expectations for its 'options' field
174 # i.e. s/t we can do setattr on
178 def __init__ (self,options=None):
179 if options is None: options=Sfi.DummyOptions()
180 for opt in Sfi.required_options:
181 if not hasattr(options,opt): setattr(options,opt,None)
182 if not hasattr(options,'sfi_dir'): options.sfi_dir=Sfi.default_sfi_dir()
183 self.options = options
187 self.authority = None
188 self.hashrequest = False
189 self.logger = sfi_logger
190 self.logger.enable_console()
191 self.available_names = [ tuple[0] for tuple in Sfi.available ]
192 self.available_dict = dict (Sfi.available)
194 # tuples command-name expected-args in the order in which they should appear in the help
197 ("list", "authority"),
200 ("update", "record"),
203 ("resources", "[slice_hrn]"),
204 ("create", "slice_hrn rspec"),
205 ("delete", "slice_hrn"),
206 ("status", "slice_hrn"),
207 ("start", "slice_hrn"),
208 ("stop", "slice_hrn"),
209 ("reset", "slice_hrn"),
210 ("renew", "slice_hrn time"),
211 ("shutdown", "slice_hrn"),
212 ("get_ticket", "slice_hrn rspec"),
213 ("redeem_ticket", "ticket"),
214 ("delegate", "name"),
215 ("create_gid", "[name]"),
216 ("get_trusted_certs", "cred"),
219 def print_command_help (self, options):
220 verbose=getattr(options,'verbose')
221 format3="%18s %-15s %s"
224 print format3%("command","cmd_args","description")
228 self.create_parser().print_help()
229 for command in self.available_names:
230 args=self.available_dict[command]
231 method=getattr(self,command,None)
233 if method: doc=getattr(method,'__doc__',"")
234 if not doc: doc="*** no doc found ***"
235 doc=doc.strip(" \t\n")
236 doc=doc.replace("\n","\n"+35*' ')
239 print format3%(command,args,doc)
241 self.create_cmd_parser(command).print_help()
243 def create_cmd_parser(self, command):
244 if command not in self.available_dict:
245 msg="Invalid command\n"
247 msg += ','.join(self.available_names)
248 self.logger.critical(msg)
251 parser = OptionParser(usage="sfi [sfi_options] %s [cmd_options] %s" \
252 % (command, self.available_dict[command]))
254 # user specifies remote aggregate/sm/component
255 if command in ("resources", "slices", "create", "delete", "start", "stop",
256 "restart", "shutdown", "get_ticket", "renew", "status"):
257 parser.add_option("-a", "--aggregate", dest="aggregate",
258 default=None, help="aggregate host")
259 parser.add_option("-p", "--port", dest="port",
260 default=AGGREGATE_PORT, help="aggregate port")
261 parser.add_option("-c", "--component", dest="component", default=None,
262 help="component hrn")
263 parser.add_option("-d", "--delegate", dest="delegate", default=None,
265 help="Include a credential delegated to the user's root"+\
266 "authority in set of credentials for this call")
268 # registy filter option
269 if command in ("list", "show", "remove"):
270 parser.add_option("-t", "--type", dest="type", type="choice",
271 help="type filter ([all]|user|slice|authority|node|aggregate)",
272 choices=("all", "user", "slice", "authority", "node", "aggregate"),
275 if command in ("resources"):
276 parser.add_option("-r", "--rspec-version", dest="rspec_version", default="SFA 1",
277 help="schema type and version of resulting RSpec")
278 parser.add_option("-f", "--format", dest="format", type="choice",
279 help="display format ([xml]|dns|ip)", default="xml",
280 choices=("xml", "dns", "ip"))
281 #panos: a new option to define the type of information about resources a user is interested in
282 parser.add_option("-i", "--info", dest="info",
283 help="optional component information", default=None)
286 # 'create' does return the new rspec, makes sense to save that too
287 if command in ("resources", "show", "list", "create_gid", 'create'):
288 parser.add_option("-o", "--output", dest="file",
289 help="output XML to file", metavar="FILE", default=None)
291 if command in ("show", "list"):
292 parser.add_option("-f", "--format", dest="format", type="choice",
293 help="display format ([text]|xml)", default="text",
294 choices=("text", "xml"))
296 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
297 help="output file format ([xml]|xmllist|hrnlist)", default="xml",
298 choices=("xml", "xmllist", "hrnlist"))
300 if command in ("status", "version"):
301 parser.add_option("-o", "--output", dest="file",
302 help="output dictionary to file", metavar="FILE", default=None)
303 parser.add_option("-F", "--fileformat", dest="fileformat", type="choice",
304 help="output file format ([text]|pickled)", default="text",
305 choices=("text","pickled"))
307 if command in ("delegate"):
308 parser.add_option("-u", "--user",
309 action="store_true", dest="delegate_user", default=False,
310 help="delegate user credential")
311 parser.add_option("-s", "--slice", dest="delegate_slice",
312 help="delegate slice credential", metavar="HRN", default=None)
314 if command in ("version"):
315 parser.add_option("-a", "--aggregate", dest="aggregate",
316 default=None, help="aggregate host")
317 parser.add_option("-p", "--port", dest="port",
318 default=AGGREGATE_PORT, help="aggregate port")
319 parser.add_option("-R","--registry-version",
320 action="store_true", dest="version_registry", default=False,
321 help="probe registry version instead of slicemgr")
322 parser.add_option("-l","--local",
323 action="store_true", dest="version_local", default=False,
324 help="display version of the local client")
329 def create_parser(self):
331 # Generate command line parser
332 parser = OptionParser(usage="sfi [sfi_options] command [cmd_options] [cmd_args]",
333 description="Commands: %s"%(" ".join(self.available_names)))
334 parser.add_option("-r", "--registry", dest="registry",
335 help="root registry", metavar="URL", default=None)
336 parser.add_option("-s", "--slicemgr", dest="sm",
337 help="slice manager", metavar="URL", default=None)
338 parser.add_option("-d", "--dir", dest="sfi_dir",
339 help="config & working directory - default is %default",
340 metavar="PATH", default=Sfi.default_sfi_dir())
341 parser.add_option("-u", "--user", dest="user",
342 help="user name", metavar="HRN", default=None)
343 parser.add_option("-a", "--auth", dest="auth",
344 help="authority name", metavar="HRN", default=None)
345 parser.add_option("-v", "--verbose", action="count", dest="verbose", default=0,
346 help="verbose mode - cumulative")
347 parser.add_option("-D", "--debug",
348 action="store_true", dest="debug", default=False,
349 help="Debug (xml-rpc) protocol messages")
350 parser.add_option("-p", "--protocol", dest="protocol", default="xmlrpc",
351 help="RPC protocol (xmlrpc or soap)")
352 parser.add_option("-k", "--hashrequest",
353 action="store_true", dest="hashrequest", default=False,
354 help="Create a hash of the request that will be authenticated on the server")
355 parser.add_option("-t", "--timeout", dest="timeout", default=None,
356 help="Amout of time to wait before timing out the request")
357 parser.add_option("-?", "--commands",
358 action="store_true", dest="command_help", default=False,
359 help="one page summary on commands & exit")
360 parser.disable_interspersed_args()
365 def print_help (self):
366 self.sfi_parser.print_help()
367 self.cmd_parser.print_help()
370 # Main: parse arguments and dispatch to command
372 def dispatch(self, command, cmd_opts, cmd_args):
373 return getattr(self, command)(cmd_opts, cmd_args)
376 self.sfi_parser = self.create_parser()
377 (options, args) = self.sfi_parser.parse_args()
378 if options.command_help:
379 self.print_command_help(options)
381 self.options = options
383 self.logger.setLevelFromOptVerbose(self.options.verbose)
384 if options.hashrequest:
385 self.hashrequest = True
388 self.logger.critical("No command given. Use -h for help.")
389 self.print_command_help(options)
393 self.cmd_parser = self.create_cmd_parser(command)
394 (cmd_opts, cmd_args) = self.cmd_parser.parse_args(args[1:])
397 self.logger.info("Command=%s" % command)
398 if command in ("resources"):
399 self.logger.debug("resources cmd_opts %s" % cmd_opts.format)
400 elif command in ("list", "show", "remove"):
401 self.logger.debug("cmd_opts.type %s" % cmd_opts.type)
402 self.logger.debug('cmd_args %s' % cmd_args)
405 self.dispatch(command, cmd_opts, cmd_args)
407 self.logger.critical ("Unknown command %s"%command)
414 def read_config(self):
415 config_file = os.path.join(self.options.sfi_dir,"sfi_config")
417 config = Config (config_file)
419 self.logger.critical("Failed to read configuration file %s"%config_file)
420 self.logger.info("Make sure to remove the export clauses and to add quotes")
421 if self.options.verbose==0:
422 self.logger.info("Re-run with -v for more details")
424 self.logger.log_exc("Could not read config file %s"%config_file)
429 if (self.options.sm is not None):
430 self.sm_url = self.options.sm
431 elif hasattr(config, "SFI_SM"):
432 self.sm_url = config.SFI_SM
434 self.logger.error("You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file)
438 if (self.options.registry is not None):
439 self.reg_url = self.options.registry
440 elif hasattr(config, "SFI_REGISTRY"):
441 self.reg_url = config.SFI_REGISTRY
443 self.logger.errors("You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file)
448 if (self.options.user is not None):
449 self.user = self.options.user
450 elif hasattr(config, "SFI_USER"):
451 self.user = config.SFI_USER
453 self.logger.errors("You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file)
457 if (self.options.auth is not None):
458 self.authority = self.options.auth
459 elif hasattr(config, "SFI_AUTH"):
460 self.authority = config.SFI_AUTH
462 self.logger.error("You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file)
470 # Establish Connection to SliceMgr and Registry Servers
472 def set_servers(self):
475 # Get key and certificate
476 key_file = self.get_key_file()
477 cert_file = self.get_cert_file(key_file)
478 self.key_file = key_file
479 self.cert_file = cert_file
480 self.cert = GID(filename=cert_file)
481 self.logger.info("Contacting Registry at: %s"%self.reg_url)
482 self.registry = SfaServerProxy(self.reg_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
483 self.logger.info("Contacting Slice Manager at: %s"%self.sm_url)
484 self.slicemgr = SfaServerProxy(self.sm_url, key_file, cert_file, timeout=self.options.timeout, verbose=self.options.debug)
487 def get_cached_server_version(self, server):
488 # check local cache first
491 cache_file = os.path.join(self.options.sfi_dir,'sfi_cache.dat')
492 cache_key = server.url + "-version"
494 cache = Cache(cache_file)
497 self.logger.info("Local cache not found at: %s" % cache_file)
500 version = cache.get(cache_key)
503 result = server.GetVersion()
504 version= ReturnValue.get_value(result)
505 # cache version for 24 hours
506 cache.add(cache_key, version, ttl= 60*60*24)
507 self.logger.info("Updating cache file %s" % cache_file)
508 cache.save_to_file(cache_file)
514 # Get various credential and spec files
516 # Establishes limiting conventions
517 # - conflates MAs and SAs
518 # - assumes last token in slice name is unique
520 # Bootstraps credentials
521 # - bootstrap user credential from self-signed certificate
522 # - bootstrap authority credential from user credential
523 # - bootstrap slice credential from user credential
527 def get_key_file(self):
528 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
529 if (os.path.isfile(file)):
532 self.logger.error("Key file %s does not exist"%file)
536 def get_cert_file(self, key_file):
538 cert_file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
539 if (os.path.isfile(cert_file)):
540 # we'd perfer to use Registry issued certs instead of self signed certs.
541 # if this is a Registry cert (GID) then we are done
542 gid = GID(filename=cert_file)
546 # generate self signed certificate
547 k = Keypair(filename=key_file)
548 cert = Certificate(subject=self.user)
550 cert.set_issuer(k, self.user)
552 self.logger.info("Writing self-signed certificate to %s"%cert_file)
553 cert.save_to_file(cert_file)
555 # try to get registry issued cert
557 self.logger.info("Getting Registry issued cert")
559 # *hack. need to set registry before _get_gid() is called
560 self.registry = SfaServerProxy(self.reg_url, key_file, cert_file,
561 timeout=self.options.timeout, verbose=self.options.debug)
562 gid = self._get_gid(type='user')
564 self.logger.info("Writing certificate to %s"%cert_file)
565 gid.save_to_file(cert_file)
567 self.logger.info("Failed to download Registry issued cert")
571 def get_cached_gid(self, file):
576 if (os.path.isfile(file)):
577 gid = GID(filename=file)
582 # def get_gid(self, opts, args):
583 # """ Get the specify gid and save it to file """
587 # gid = self._get_gid(hrn)
588 # self.logger.debug("Sfi.get_gid-> %s" % gid.save_to_string(save_parents=True))
591 def _get_gid(self, hrn=None, type=None):
593 git_gid helper. Retrive the gid from the registry and save it to file.
599 gidfile = os.path.join(self.options.sfi_dir, hrn + ".gid")
600 gid = self.get_cached_gid(gidfile)
602 user_cred = self.get_user_cred()
603 records = self.registry.Resolve(hrn, user_cred.save_to_string(save_parents=True))
605 raise RecordNotFound(args[0])
610 if type == rec['type']:
613 raise RecordNotFound(args[0])
615 gid = GID(string=record['gid'])
616 self.logger.info("Writing gid to %s"%gidfile)
617 gid.save_to_file(filename=gidfile)
621 def get_cached_credential(self, file):
623 Return a cached credential only if it hasn't expired.
625 if (os.path.isfile(file)):
626 credential = Credential(filename=file)
627 # make sure it isnt expired
628 if not credential.get_expiration or \
629 datetime.datetime.today() < credential.get_expiration():
633 def get_user_cred(self):
634 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
635 return self.get_cred(file, 'user', self.user)
637 def get_auth_cred(self):
638 if not self.authority:
639 self.logger.critical("no authority specified. Use -a or set SF_AUTH")
641 file = os.path.join(self.options.sfi_dir, self.authority + ".cred")
642 return self.get_cred(file, 'authority', self.authority)
644 def get_slice_cred(self, name):
645 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
646 return self.get_cred(file, 'slice', name)
648 def get_cred(self, file, type, hrn):
649 # attempt to load a cached credential
650 cred = self.get_cached_credential(file)
653 cert_string = self.cert.save_to_string(save_parents=True)
654 user_name = self.user.replace(self.authority + ".", '')
655 if user_name.count(".") > 0:
656 user_name = user_name.replace(".", '_')
657 self.user = self.authority + "." + user_name
658 cred_str = self.registry.GetSelfCredential(cert_string, hrn, "user")
660 # bootstrap slice credential from user credential
661 user_cred = self.get_user_cred().save_to_string(save_parents=True)
662 cred_str = self.registry.GetCredential(user_cred, hrn, type)
665 self.logger.critical("Failed to get %s credential" % type)
668 cred = Credential(string=cred_str)
669 cred.save_to_file(file, save_parents=True)
670 self.logger.info("Writing %s credential to %s" %(type, file))
675 def delegate_cred(self, object_cred, hrn):
676 # the gid and hrn of the object we are delegating
677 if isinstance(object_cred, str):
678 object_cred = Credential(string=object_cred)
679 object_gid = object_cred.get_gid_object()
680 object_hrn = object_gid.get_hrn()
682 if not object_cred.get_privileges().get_all_delegate():
683 self.logger.error("Object credential %s does not have delegate bit set"%object_hrn)
686 # the delegating user's gid
687 caller_gid = self._get_gid(self.user)
688 caller_gidfile = os.path.join(self.options.sfi_dir, self.user + ".gid")
690 # the gid of the user who will be delegated to
691 delegee_gid = self._get_gid(hrn)
692 delegee_hrn = delegee_gid.get_hrn()
693 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
694 delegee_gid.save_to_file(filename=delegee_gidfile)
695 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file(), caller_gidfile)
696 return dcred.save_to_string(save_parents=True)
698 ######################################## miscell utilities
699 def get_rspec_file(self, rspec):
700 if (os.path.isabs(rspec)):
703 file = os.path.join(self.options.sfi_dir, rspec)
704 if (os.path.isfile(file)):
707 self.logger.critical("No such rspec file %s"%rspec)
710 def get_record_file(self, record):
711 if (os.path.isabs(record)):
714 file = os.path.join(self.options.sfi_dir, record)
715 if (os.path.isfile(file)):
718 self.logger.critical("No such registry record file %s"%record)
722 def get_component_proxy_from_hrn(self, hrn):
723 # direct connection to the nodes component manager interface
724 user_cred = self.get_user_cred().save_to_string(save_parents=True)
725 records = self.registry.Resolve(hrn, user_cred)
726 records = filter_records('node', records)
728 self.logger.warning("No such component:%r"% opts.component)
731 return self.server_proxy(record['hostname'], CM_PORT, self.key_file, self.cert_file)
733 def server_proxy(self, host, port, keyfile, certfile):
735 Return an instance of an xmlrpc server connection
737 # port is appended onto the domain, before the path. Should look like:
738 # http://domain:port/path
739 host_parts = host.split('/')
740 host_parts[0] = host_parts[0] + ":" + str(port)
741 url = "http://%s" % "/".join(host_parts)
742 return SfaServerProxy(url, keyfile, certfile, timeout=self.options.timeout,
743 verbose=self.options.debug)
745 # xxx opts could be retrieved in self.options
746 def server_proxy_from_opts(self, opts):
748 Return instance of an xmlrpc connection to a slice manager, aggregate
749 or component server depending on the specified opts
751 server = self.slicemgr
752 # direct connection to an aggregate
753 if hasattr(opts, 'aggregate') and opts.aggregate:
754 server = self.server_proxy(opts.aggregate, opts.port, self.key_file, self.cert_file)
755 # direct connection to the nodes component manager interface
756 if hasattr(opts, 'component') and opts.component:
757 server = self.get_component_proxy_from_hrn(opts.component)
760 #==========================================================================
761 # Following functions implement the commands
763 # Registry-related commands
764 #==========================================================================
766 def version(self, opts, args):
768 display an SFA server version (GetVersion)
769 or version information about sfi itself
771 if opts.version_local:
772 version=version_core()
774 if opts.version_registry:
777 server = self.server_proxy_from_opts(opts)
778 result = server.GetVersion()
779 version = ReturnValue.get_value(result)
780 for (k,v) in version.iteritems():
781 print "%-20s: %s"%(k,v)
783 save_variable_to_file(version, opts.file, opts.fileformat)
785 def list(self, opts, args):
787 list entries in named authority registry (List)
793 user_cred = self.get_user_cred().save_to_string(save_parents=True)
795 list = self.registry.List(hrn, user_cred)
797 raise Exception, "Not enough parameters for the 'list' command"
799 # filter on person, slice, site, node, etc.
800 # THis really should be in the self.filter_records funct def comment...
801 list = filter_records(opts.type, list)
803 print "%s (%s)" % (record['hrn'], record['type'])
805 save_records_to_file(opts.file, list, opts.fileformat)
808 def show(self, opts, args):
810 show details about named registry record (Resolve)
816 user_cred = self.get_user_cred().save_to_string(save_parents=True)
817 records = self.registry.Resolve(hrn, user_cred)
818 records = filter_records(opts.type, records)
820 self.logger.error("No record of type %s"% opts.type)
821 for record in records:
822 if record['type'] in ['user']:
823 record = UserRecord(dict=record)
824 elif record['type'] in ['slice']:
825 record = SliceRecord(dict=record)
826 elif record['type'] in ['node']:
827 record = NodeRecord(dict=record)
828 elif record['type'].startswith('authority'):
829 record = AuthorityRecord(dict=record)
831 record = SfaRecord(dict=record)
832 if (opts.format == "text"):
835 print record.save_to_string()
837 save_records_to_file(opts.file, records, opts.fileformat)
840 def add(self, opts, args):
841 "add record into registry from xml file (Register)"
842 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
846 record_filepath = args[0]
847 rec_file = self.get_record_file(record_filepath)
848 record = load_record_from_file(rec_file).as_dict()
849 return self.registry.Register(record, auth_cred)
851 def update(self, opts, args):
852 "update record into registry from xml file (Update)"
853 user_cred = self.get_user_cred()
857 rec_file = self.get_record_file(args[0])
858 record = load_record_from_file(rec_file)
859 if record['type'] == "user":
860 if record.get_name() == user_cred.get_gid_object().get_hrn():
861 cred = user_cred.save_to_string(save_parents=True)
863 cred = self.get_auth_cred().save_to_string(save_parents=True)
864 elif record['type'] in ["slice"]:
866 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
867 except ServerException, e:
868 # XXX smbaker -- once we have better error return codes, update this
869 # to do something better than a string compare
870 if "Permission error" in e.args[0]:
871 cred = self.get_auth_cred().save_to_string(save_parents=True)
874 elif record.get_type() in ["authority"]:
875 cred = self.get_auth_cred().save_to_string(save_parents=True)
876 elif record.get_type() == 'node':
877 cred = self.get_auth_cred().save_to_string(save_parents=True)
879 raise "unknown record type" + record.get_type()
880 record = record.as_dict()
881 return self.registry.Update(record, cred)
883 def remove(self, opts, args):
884 "remove registry record by name (Remove)"
885 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
893 return self.registry.Remove(hrn, auth_cred, type)
895 # ==================================================================
896 # Slice-related commands
897 # ==================================================================
899 def slices(self, opts, args):
900 "list instantiated slices (ListSlices) - returns urn's"
901 user_cred = self.get_user_cred().save_to_string(save_parents=True)
904 delegated_cred = self.delegate_cred(user_cred, get_authority(self.authority))
905 creds.append(delegated_cred)
906 server = self.server_proxy_from_opts(opts)
908 api_options ['call_id'] = unique_call_id()
909 result = server.ListSlices(creds, api_options)
910 value = ReturnValue.get_value(result)
914 # show rspec for named slice
915 def resources(self, opts, args):
917 with no arg, discover available resources,
918 or currently provisioned resources (ListResources)
920 user_cred = self.get_user_cred().save_to_string(save_parents=True)
921 server = self.server_proxy_from_opts(opts)
924 api_options ['call_id'] = unique_call_id()
925 #panos add info api_options
927 api_options['info'] = opts.info
930 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
932 api_options['geni_slice_urn'] = hrn_to_urn(hrn, 'slice')
938 delegated_cred = self.delegate_cred(cred, get_authority(self.authority))
939 creds.append(delegated_cred)
940 if opts.rspec_version:
941 version_manager = VersionManager()
942 server_version = self.get_cached_server_version(server)
943 if 'sfa' in server_version:
944 # just request the version the client wants
945 api_options['geni_rspec_version'] = version_manager.get_version(opts.rspec_version).to_dict()
947 # this must be a protogeni aggregate. We should request a v2 ad rspec
948 # regardless of what the client user requested
949 api_options['geni_rspec_version'] = version_manager.get_version('ProtoGENI 2').to_dict()
951 api_options['geni_rspec_version'] = {'type': 'geni', 'version': '3.0'}
953 result = server.ListResources(creds, api_options)
954 value = ReturnValue.get_value(result)
955 if opts.file is None:
956 display_rspec(value, opts.format)
958 save_rspec_to_file(value, opts.file)
961 def create(self, opts, args):
963 create or update named slice with given rspec
965 server = self.server_proxy_from_opts(opts)
966 server_version = self.get_cached_server_version(server)
968 slice_urn = hrn_to_urn(slice_hrn, 'slice')
969 user_cred = self.get_user_cred()
970 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
971 delegated_cred = None
972 if server_version.get('interface') == 'slicemgr':
973 # delegate our cred to the slice manager
974 # do not delegate cred to slicemgr...not working at the moment
976 #if server_version.get('hrn'):
977 # delegated_cred = self.delegate_cred(slice_cred, server_version['hrn'])
978 #elif server_version.get('urn'):
979 # delegated_cred = self.delegate_cred(slice_cred, urn_to_hrn(server_version['urn']))
981 rspec_file = self.get_rspec_file(args[1])
982 rspec = open(rspec_file).read()
984 # need to pass along user keys to the aggregate.
986 # { urn: urn:publicid:IDN+emulab.net+user+alice
987 # keys: [<ssh key A>, <ssh key B>]
990 slice_records = self.registry.Resolve(slice_urn, [user_cred.save_to_string(save_parents=True)])
991 if slice_records and 'researcher' in slice_records[0] and slice_records[0]['researcher']!=[]:
992 slice_record = slice_records[0]
993 user_hrns = slice_record['researcher']
994 user_urns = [hrn_to_urn(hrn, 'user') for hrn in user_hrns]
995 user_records = self.registry.Resolve(user_urns, [user_cred.save_to_string(save_parents=True)])
997 if 'sfa' not in server_version:
998 users = pg_users_arg(user_records)
1000 rspec.filter({'component_manager_id': server_version['urn']})
1001 rspec = RSpecConverter.to_pg_rspec(rspec.toxml(), content_type='request')
1002 creds = [slice_cred]
1004 users = sfa_users_arg(user_records, slice_record)
1005 creds = [slice_cred]
1007 creds.append(delegated_cred)
1008 # do not append users, keys, or slice tags. Anything
1009 # not contained in this request will be removed from the slice
1011 api_options ['append'] = False
1012 api_options ['call_id'] = unique_call_id()
1013 result = server.CreateSliver(slice_urn, creds, rspec, users, api_options)
1014 value = ReturnValue.get_value(result)
1015 if opts.file is None:
1018 save_rspec_to_file (value, opts.file)
1021 def delete(self, opts, args):
1023 delete named slice (DeleteSliver)
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.server_proxy_from_opts(opts)
1034 api_options ['call_id'] = unique_call_id()
1035 return server.DeleteSliver(slice_urn, creds, api_options)
1037 def status(self, opts, args):
1039 retrieve slice status (SliverStatus)
1042 slice_urn = hrn_to_urn(slice_hrn, 'slice')
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 server = self.server_proxy_from_opts(opts)
1050 api_options ['call_id'] = unique_call_id()
1051 result = server.SliverStatus(slice_urn, creds, api_options)
1052 value = ReturnValue.get_value(result)
1055 save_variable_to_file(value, opts.file, opts.fileformat)
1057 def start(self, opts, args):
1059 start named slice (Start)
1062 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1063 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1064 creds = [slice_cred]
1066 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1067 creds.append(delegated_cred)
1068 server = self.server_proxy_from_opts(opts)
1069 return server.Start(slice_urn, creds)
1071 def stop(self, opts, args):
1073 stop named slice (Stop)
1076 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1077 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1078 creds = [slice_cred]
1080 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1081 creds.append(delegated_cred)
1082 server = self.server_proxy_from_opts(opts)
1083 return server.Stop(slice_urn, creds)
1086 def reset(self, opts, args):
1088 reset named slice (reset_slice)
1091 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1092 server = self.server_proxy_from_opts(opts)
1093 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1094 creds = [slice_cred]
1096 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1097 creds.append(delegated_cred)
1098 return server.reset_slice(creds, slice_urn)
1100 def renew(self, opts, args):
1102 renew slice (RenewSliver)
1105 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1106 server = self.server_proxy_from_opts(opts)
1107 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
1108 creds = [slice_cred]
1110 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1111 creds.append(delegated_cred)
1114 api_options ['call_id'] = unique_call_id()
1115 result = server.RenewSliver(slice_urn, creds, time, api_options)
1116 value = ReturnValue.get_value(result)
1120 def shutdown(self, opts, args):
1122 shutdown named slice (Shutdown)
1125 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1126 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1127 creds = [slice_cred]
1129 delegated_cred = self.delegate_cred(slice_cred, get_authority(self.authority))
1130 creds.append(delegated_cred)
1131 server = self.server_proxy_from_opts(opts)
1132 return server.Shutdown(slice_urn, creds)
1135 def get_ticket(self, opts, args):
1137 get a ticket for the specified slice
1139 slice_hrn, rspec_path = args[0], args[1]
1140 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1141 user_cred = self.get_user_cred()
1142 slice_cred = self.get_slice_cred(slice_hrn).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 rspec_file = self.get_rspec_file(rspec_path)
1148 rspec = open(rspec_file).read()
1149 server = self.server_proxy_from_opts(opts)
1150 ticket_string = server.GetTicket(slice_urn, creds, rspec, [])
1151 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
1152 self.logger.info("writing ticket to %s"%file)
1153 ticket = SfaTicket(string=ticket_string)
1154 ticket.save_to_file(filename=file, save_parents=True)
1156 def redeem_ticket(self, opts, args):
1158 Connects to nodes in a slice and redeems a ticket
1159 (slice hrn is retrieved from the ticket)
1161 ticket_file = args[0]
1163 # get slice hrn from the ticket
1164 # use this to get the right slice credential
1165 ticket = SfaTicket(filename=ticket_file)
1167 slice_hrn = ticket.gidObject.get_hrn()
1168 slice_urn = hrn_to_urn(slice_hrn, 'slice')
1169 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
1170 user_cred = self.get_user_cred()
1171 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
1173 # get a list of node hostnames from the RSpec
1174 tree = etree.parse(StringIO(ticket.rspec))
1175 root = tree.getroot()
1176 hostnames = root.xpath("./network/site/node/hostname/text()")
1178 # create an xmlrpc connection to the component manager at each of these
1179 # components and gall redeem_ticket
1181 for hostname in hostnames:
1183 self.logger.info("Calling redeem_ticket at %(hostname)s " % locals())
1184 server = self.server_proxy(hostname, CM_PORT, self.key_file, \
1185 self.cert_file, self.options.debug)
1186 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
1187 self.logger.info("Success")
1188 except socket.gaierror:
1189 self.logger.error("redeem_ticket failed: Component Manager not accepting requests")
1190 except Exception, e:
1191 self.logger.log_exc(e.message)
1194 def create_gid(self, opts, args):
1196 Create a GID (CreateGid)
1201 target_hrn = args[0]
1202 user_cred = self.get_user_cred().save_to_string(save_parents=True)
1203 gid = self.registry.CreateGid(user_cred, target_hrn, self.cert.save_to_string())
1205 filename = opts.file
1207 filename = os.sep.join([self.options.sfi_dir, '%s.gid' % target_hrn])
1208 self.logger.info("writing %s gid to %s" % (target_hrn, filename))
1209 GID(string=gid).save_to_file(filename)
1212 def delegate(self, opts, args):
1214 (locally) create delegate credential for use by given hrn
1216 delegee_hrn = args[0]
1217 if opts.delegate_user:
1218 user_cred = self.get_user_cred()
1219 cred = self.delegate_cred(user_cred, delegee_hrn)
1220 elif opts.delegate_slice:
1221 slice_cred = self.get_slice_cred(opts.delegate_slice)
1222 cred = self.delegate_cred(slice_cred, delegee_hrn)
1224 self.logger.warning("Must specify either --user or --slice <hrn>")
1226 delegated_cred = Credential(string=cred)
1227 object_hrn = delegated_cred.get_gid_object().get_hrn()
1228 if opts.delegate_user:
1229 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
1230 + get_leaf(object_hrn) + ".cred")
1231 elif opts.delegate_slice:
1232 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
1233 + get_leaf(object_hrn) + ".cred")
1235 delegated_cred.save_to_file(dest_fn, save_parents=True)
1237 self.logger.info("delegated credential for %s to %s and wrote to %s"%(object_hrn, delegee_hrn,dest_fn))
1239 def get_trusted_certs(self, opts, args):
1241 return uhe trusted certs at this interface (get_trusted_certs)
1243 trusted_certs = self.registry.get_trusted_certs()
1244 for trusted_cert in trusted_certs:
1245 gid = GID(string=trusted_cert)
1247 cert = Certificate(string=trusted_cert)
1248 self.logger.debug('Sfi.get_trusted_certs -> %r'%cert.get_subject())