3 # sfi -- slice-based facility interface
13 from lxml import etree
14 from StringIO import StringIO
15 from types import StringTypes, ListType
16 from optparse import OptionParser
17 from sfa.trust.certificate import Keypair, Certificate
18 from sfa.trust.credential import Credential
19 from sfa.util.sfaticket import SfaTicket
20 from sfa.util.record import *
21 from sfa.util.namespace import *
22 from sfa.util.xmlrpcprotocol import ServerException
23 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
24 from sfa.util.config import Config
30 # utility methods here
32 def display_rspec(rspec, format='rspec'):
34 tree = etree.parse(StringIO(rspec))
36 result = root.xpath("./network/site/node/hostname/text()")
37 elif format in ['ip']:
38 # The IP address is not yet part of the new RSpec
39 # so this doesn't do anything yet.
40 tree = etree.parse(StringIO(rspec))
42 result = root.xpath("./network/site/node/ipv4/text()")
49 def display_list(results):
50 for result in results:
53 def display_records(recordList, dump=False):
54 ''' Print all fields in the record'''
55 for record in recordList:
56 display_record(record, dump)
58 def display_record(record, dump=False):
62 info = record.getdict()
63 print "%s (%s)" % (info['hrn'], info['type'])
67 def filter_records(type, records):
69 for record in records:
70 if (record['type'] == type) or (type == "all"):
71 filtered_records.append(record)
72 return filtered_records
76 def save_rspec_to_file(rspec, filename):
77 if not filename.endswith(".rspec"):
78 filename = filename + ".rspec"
80 f = open(filename, 'w')
85 def save_records_to_file(filename, recordList):
87 for record in recordList:
89 save_record_to_file(filename + "." + str(index), record)
91 save_record_to_file(filename, record)
94 def save_record_to_file(filename, record):
95 if record['type'] in ['user']:
96 record = UserRecord(dict=record)
97 elif record['type'] in ['slice']:
98 record = SliceRecord(dict=record)
99 elif record['type'] in ['node']:
100 record = NodeRecord(dict=record)
101 elif record['type'] in ['authority', 'ma', 'sa']:
102 record = AuthorityRecord(dict=record)
104 record = SfaRecord(dict=record)
105 str = record.save_to_string()
106 file(filename, "w").write(str)
111 def load_record_from_file(filename):
112 str = file(filename, "r").read()
113 record = SfaRecord(string=str)
127 def create_cmd_parser(self, command, additional_cmdargs=None):
128 cmdargs = {"list": "name",
133 "aggregates": "[name]",
134 "registries": "[name]",
135 "get_trusted_certs": "cred",
137 "resources": "[name]",
138 "create": "name rspec",
139 "get_ticket": "name rspec",
140 "redeem_ticket": "ticket",
152 if additional_cmdargs:
153 cmdargs.update(additional_cmdargs)
155 if command not in cmdargs:
156 print "Invalid command\n"
158 for key in cmdargs.keys():
163 parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
164 % (command, cmdargs[command]))
166 # user specifies remote aggregate/sm/component
167 if command in ("resources", "slices", "create", "delete", "start", "stop", "restart", "get_ticket", "redeem_ticket"):
168 parser.add_option("-a", "--aggregate", dest="aggregate",
169 default=None, help="aggregate host")
170 parser.add_option("-p", "--port", dest="port",
171 default=AGGREGATE_PORT, help="aggregate port")
172 parser.add_option("-c", "--component", dest="component", default=None,
173 help="component hrn")
175 # registy filter option
176 if command in ("list", "show", "remove"):
177 parser.add_option("-t", "--type", dest="type", type="choice",
178 help="type filter ([all]|user|slice|authority|node|aggregate)",
179 choices=("all", "user", "slice", "authority", "node", "aggregate"),
182 if command in ("resources"):
183 parser.add_option("-f", "--format", dest="format", type="choice",
184 help="display format ([xml]|dns|ip)", default="xml",
185 choices=("xml", "dns", "ip"))
187 if command in ("resources", "show", "list"):
188 parser.add_option("-o", "--output", dest="file",
189 help="output XML to file", metavar="FILE", default=None)
191 if command in ("show", "list"):
192 parser.add_option("-f", "--format", dest="format", type="choice",
193 help="display format ([text]|xml)", default="text",
194 choices=("text", "xml"))
196 if command in ("delegate"):
197 parser.add_option("-u", "--user",
198 action="store_true", dest="delegate_user", default=False,
199 help="delegate user credential")
200 parser.add_option("-s", "--slice", dest="delegate_slice",
201 help="delegate slice credential", metavar="HRN", default=None)
206 def create_parser(self):
208 # Generate command line parser
209 parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
210 description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
211 parser.add_option("-r", "--registry", dest="registry",
212 help="root registry", metavar="URL", default=None)
213 parser.add_option("-s", "--slicemgr", dest="sm",
214 help="slice manager", metavar="URL", default=None)
215 default_sfi_dir = os.path.expanduser("~/.sfi/")
216 parser.add_option("-d", "--dir", dest="sfi_dir",
217 help="config & working directory - default is " + default_sfi_dir,
218 metavar="PATH", default=default_sfi_dir)
219 parser.add_option("-u", "--user", dest="user",
220 help="user name", metavar="HRN", default=None)
221 parser.add_option("-a", "--auth", dest="auth",
222 help="authority name", metavar="HRN", default=None)
223 parser.add_option("-v", "--verbose",
224 action="store_true", dest="verbose", default=False,
226 parser.add_option("-D", "--debug",
227 action="store_true", dest="debug", default=False,
228 help="Debug (xml-rpc) protocol messages")
229 parser.add_option("-p", "--protocol",
230 dest="protocol", default="xmlrpc",
231 help="RPC protocol (xmlrpc or soap)")
232 parser.add_option("-k", "--hashrequest",
233 action="store_true", dest="hashrequest", default=False,
234 help="Create a hash of the request that will be authenticated on the server")
235 parser.disable_interspersed_args()
241 # Establish Connection to SliceMgr and Registry Servers
243 def set_servers(self):
244 config_file = self.options.sfi_dir + os.sep + "sfi_config"
246 config = Config (config_file)
248 print "Failed to read configuration file", config_file
249 print "Make sure to remove the export clauses and to add quotes"
250 if not self.options.verbose:
251 print "Re-run with -v for more details"
253 traceback.print_exc()
258 if (self.options.sm is not None):
259 sm_url = self.options.sm
260 elif hasattr(config, "SFI_SM"):
261 sm_url = config.SFI_SM
263 print "You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file
267 if (self.options.registry is not None):
268 reg_url = self.options.registry
269 elif hasattr(config, "SFI_REGISTRY"):
270 reg_url = config.SFI_REGISTRY
272 print "You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file
277 if (self.options.user is not None):
278 self.user = self.options.user
279 elif hasattr(config, "SFI_USER"):
280 self.user = config.SFI_USER
282 print "You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file
286 if (self.options.auth is not None):
287 self.authority = self.options.auth
288 elif hasattr(config, "SFI_AUTH"):
289 self.authority = config.SFI_AUTH
291 print "You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file
297 if self.options.verbose :
298 print "Contacting Slice Manager at:", sm_url
299 print "Contacting Registry at:", reg_url
301 # Get key and certificate
302 key_file = self.get_key_file()
303 cert_file = self.get_cert_file(key_file)
304 self.key = Keypair(filename=key_file)
305 self.key_file = key_file
306 self.cert_file = cert_file
307 self.cert = Certificate(filename=cert_file)
308 # Establish connection to server(s)
309 self.registry = xmlrpcprotocol.get_server(reg_url, key_file, cert_file, self.options.debug)
310 self.slicemgr = xmlrpcprotocol.get_server(sm_url, key_file, cert_file, self.options.debug)
315 # Get various credential and spec files
317 # Establishes limiting conventions
318 # - conflates MAs and SAs
319 # - assumes last token in slice name is unique
321 # Bootstraps credentials
322 # - bootstrap user credential from self-signed certificate
323 # - bootstrap authority credential from user credential
324 # - bootstrap slice credential from user credential
328 def get_key_file(self):
329 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
330 #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".pkey")
331 if (os.path.isfile(file)):
334 print "Key file", file, "does not exist"
338 def get_cert_file(self, key_file):
340 #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cert")
341 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
342 if (os.path.isfile(file)):
345 k = Keypair(filename=key_file)
346 cert = Certificate(subject=self.user)
348 cert.set_issuer(k, self.user)
350 if self.options.verbose :
351 print "Writing self-signed certificate to", file
352 cert.save_to_file(file)
355 def get_cached_credential(self, file):
357 Return a cached credential only if it hasn't expired.
359 if (os.path.isfile(file)):
360 credential = Credential(filename=file)
361 # make sure it isnt expired
362 if not credential.get_lifetime or \
363 datetime.datetime.today() < credential.get_lifetime():
367 def get_user_cred(self):
368 #file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
369 file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
370 return self.get_cred(file, 'user', self.user)
372 def get_auth_cred(self):
373 if not self.authority:
374 print "no authority specified. Use -a or set SF_AUTH"
376 file = os.path.join(self.options.sfi_dir, get_leaf("authority") + ".cred")
377 return self.get_cred(file, 'authority', self.authority)
379 def get_slice_cred(self, name):
380 file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
381 return self.get_cred(file, 'slice', name)
383 def get_cred(self, file, type, hrn):
384 # attempt to load a cached credential
385 cred = self.get_cached_credential(file)
388 cert_string = self.cert.save_to_string(save_parents=True)
389 user_name = self.user.replace(self.authority + ".", '')
390 if user_name.count(".") > 0:
391 user_name = user_name.replace(".", '_')
392 self.user = self.authority + "." + user_name
393 cred_str = self.registry.get_self_credential(cert_string, "user", hrn)
395 # bootstrap slice credential from user credential
396 user_cred = self.get_user_cred().save_to_string(save_parents=True)
397 cred_str = self.registry.get_credential(user_cred, type, hrn)
400 print "Failed to get %s credential" % (type)
403 cred = Credential(string=cred_str)
404 cred.save_to_file(file, save_parents=True)
405 if self.options.verbose:
406 print "Writing %s credential to %s" %(type, file)
411 def get_rspec_file(self, rspec):
412 if (os.path.isabs(rspec)):
415 file = os.path.join(self.options.sfi_dir, rspec)
416 if (os.path.isfile(file)):
419 print "No such rspec file", rspec
422 def get_record_file(self, record):
423 if (os.path.isabs(record)):
426 file = os.path.join(self.options.sfi_dir, record)
427 if (os.path.isfile(file)):
430 print "No such registry record file", record
433 def load_publickey_string(self, fn):
435 key_string = f.read()
437 # if the filename is a private key file, then extract the public key
438 if "PRIVATE KEY" in key_string:
439 outfn = tempfile.mktemp()
440 cmd = "openssl rsa -in " + fn + " -pubout -outform PEM -out " + outfn
443 key_string = f.read()
448 def get_component_server_from_hrn(self, hrn):
449 # direct connection to the nodes component manager interface
450 user_cred = self.get_user_cred().save_to_string(save_parents=True)
451 records = self.registry.Resolve(hrn, user_cred)
452 records = filter_records('node', records)
454 print "No such component:", opts.component
457 return self.get_server(record['hostname'], CM_PORT, self.key_file, \
458 self.cert_file, self.options.debug)
460 def get_server(self, host, port, keyfile, certfile, debug):
462 Return an instnace of an xmlrpc server connection
464 url = "http://%s:%s" % (host, port)
465 return xmlrpcprotocol.get_server(url, keyfile, certfile, debug)
467 def get_server_from_opts(self, opts):
469 Return instance of an xmlrpc connection to a slice manager, aggregate
470 or component server depending on the specified opts
472 server = self.slicemgr
473 # direct connection to an aggregate
474 if hasattr(opts, 'aggregate') and opts.aggregate:
475 server = self.get_server(opts.aggregate, opts.port, self.key_file, \
476 self.cert_file, self.options.debug)
477 # direct connection to the nodes component manager interface
478 if hasattr(opts, 'component') and opts.component:
479 server = self.get_component_server_from_hrn(opts.component)
482 #==========================================================================
483 # Following functions implement the commands
485 # Registry-related commands
486 #==========================================================================
488 def dispatch(self, command, cmd_opts, cmd_args):
489 getattr(self, command)(cmd_opts, cmd_args)
491 # list entires in named authority registry
492 def list(self, opts, args):
493 user_cred = self.get_user_cred().save_to_string(save_parents=True)
496 list = self.registry.List(hrn, user_cred)
498 raise Exception, "Not enough parameters for the 'list' command"
500 # filter on person, slice, site, node, etc.
501 # THis really should be in the self.filter_records funct def comment...
502 list = filter_records(opts.type, list)
504 print "%s (%s)" % (record['hrn'], record['type'])
507 if not file.startswith(os.sep):
508 file = os.path.join(self.options.sfi_dir, file)
509 save_records_to_file(file, list)
512 # show named registry record
513 def show(self, opts, args):
514 user_cred = self.get_user_cred().save_to_string(save_parents=True)
516 records = self.registry.Resolve(hrn, user_cred)
517 records = filter_records(opts.type, records)
519 print "No record of type", opts.type
520 for record in records:
521 if record['type'] in ['user']:
522 record = UserRecord(dict=record)
523 elif record['type'] in ['slice']:
524 record = SliceRecord(dict=record)
525 elif record['type'] in ['node']:
526 record = NodeRecord(dict=record)
527 elif record['type'] in ['authority', 'ma', 'sa']:
528 record = AuthorityRecord(dict=record)
530 record = SfaRecord(dict=record)
531 if (opts.format == "text"):
534 print record.save_to_string()
538 if not file.startswith(os.sep):
539 file = os.path.join(self.options.sfi_dir, file)
540 save_records_to_file(file, records)
543 def delegate(self, opts, args):
544 user_cred = self.get_user_cred()
545 if opts.delegate_user:
546 object_cred = user_cred
547 elif opts.delegate_slice:
548 object_cred = self.get_slice_cred(opts.delegate_slice)
550 print "Must specify either --user or --slice <hrn>"
553 # the gid and hrn of the object we are delegating
554 object_gid = object_cred.get_gid_object()
555 object_hrn = object_gid.get_hrn()
557 if not object_cred.get_privileges().get_all_delegate():
558 print "Error: Object credential", object_hrn, "does not have delegate bit set"
561 records = self.registry.Resolve(args[0], user_cred.save_to_string(save_parents=True))
563 raise RecordNotFound(args[0])
564 # the gid of the user who will be delegated to
565 delegee_gid = GID(string=records[0]['gid'])
566 delegee_hrn = delegee_gid.get_hrn()
567 delegee_gidfile = os.path.join(self.options.sfi_dir, delegee_hrn + ".gid")
568 delegee_gid.save_to_file(filename=delegee_gidfile)
569 dcred = object_cred.delegate(delegee_gidfile, self.get_key_file())
571 if opts.delegate_user:
572 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_"
573 + get_leaf(object_hrn) + ".cred")
574 elif opts.delegate_slice:
575 dest_fn = os.path.join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
576 + get_leaf(object_hrn) + ".cred")
578 dcred.save_to_file(dest_fn, save_parents=True)
580 print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
582 # removed named registry record
583 # - have to first retrieve the record to be removed
584 def remove(self, opts, args):
585 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
590 return self.registry.Remove(hrn, auth_cred, type)
592 # add named registry record
593 def add(self, opts, args):
594 auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
595 record_filepath = args[0]
596 rec_file = self.get_record_file(record_filepath)
597 record = load_record_from_file(rec_file).as_dict()
598 return self.registry.Register(record, auth_cred)
600 # update named registry entry
601 def update(self, opts, args):
602 user_cred = self.get_user_cred()
603 rec_file = self.get_record_file(args[0])
604 record = load_record_from_file(rec_file)
605 if record['type'] == "user":
606 if record.get_name() == user_cred.get_gid_object().get_hrn():
607 cred = user_cred.save_to_string(save_parents=True)
609 cred = self.get_auth_cred().save_to_string(save_parents=True)
610 elif record['type'] in ["slice"]:
612 cred = self.get_slice_cred(record.get_name()).save_to_string(save_parents=True)
613 except ServerException, e:
614 # XXX smbaker -- once we have better error return codes, update this
615 # to do something better than a string compare
616 if "Permission error" in e.args[0]:
617 cred = self.get_auth_cred().save_to_string(save_parents=True)
620 elif record.get_type() in ["authority"]:
621 cred = self.get_auth_cred().save_to_string(save_parents=True)
622 elif record.get_type() == 'node':
623 cred = self.get_auth_cred().save_to_string(save_parents=True)
625 raise "unknown record type" + record.get_type()
626 record = record.as_dict()
627 return self.registry.Update(record, cred)
629 def get_trusted_certs(self, opts, args):
631 return uhe trusted certs at this interface
633 trusted_certs = self.registry.get_trusted_certs()
634 for trusted_cert in trusted_certs:
635 cert = Certificate(string=trusted_cert)
636 print cert.get_subject()
639 def aggregates(self, opts, args):
641 return a list of details about known aggregates
643 user_cred = self.get_user_cred().save_to_string(save_parents=True)
648 result = self.registry.get_aggregates(user_cred, hrn)
652 def registries(self, opts, args):
654 return a list of details about known registries
656 user_cred = self.get_user_cred().save_to_string(save_parents=True)
660 result = self.registry.get_registries(user_cred, hrn)
665 # ==================================================================
666 # Slice-related commands
667 # ==================================================================
670 def version(self, opts, args):
671 server = self.get_server_from_opts(opts)
673 print server.GetVersion()
675 # list instantiated slices
676 def slices(self, opts, args):
678 list instantiated slices
680 user_cred = self.get_user_cred().save_to_string(save_parents=True)
681 server = self.get_server_from_opts(opts)
682 results = server.ListSlices([user_cred])
683 display_list(results)
686 # show rspec for named slice
687 def resources(self, opts, args):
688 user_cred = self.get_user_cred().save_to_string(save_parents=True)
689 server = self.slicemgr
691 server = self.get_server_from_opts(opts)
694 cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
696 call_options = {'geni_slice_urn': hrn_to_urn(hrn, 'slice')}
701 result = server.ListResources([cred], call_options)
703 display_rspec(result, format)
704 if (opts.file is not None):
706 if not file.startswith(os.sep):
707 file = os.path.join(self.options.sfi_dir, file)
708 save_rspec_to_file(result, file)
711 # created named slice with given rspec
712 def create(self, opts, args):
714 slice_urn = hrn_to_urn(slice_hrn, 'slice')
715 user_cred = self.get_user_cred()
716 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
717 rspec_file = self.get_rspec_file(args[1])
718 rspec = open(rspec_file).read()
719 server = self.get_server_from_opts(opts)
720 result = server.CreateSliver(slice_urn, [slice_cred], rspec, [])
724 # get a ticket for the specified slice
725 def get_ticket(self, opts, args):
726 slice_hrn, rspec_path = args[0], args[1]
727 slice_urn = hrn_to_urn(slice_hrn, 'slice')
728 user_cred = self.get_user_cred()
729 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
730 rspec_file = self.get_rspec_file(rspec_path)
731 rspec = open(rspec_file).read()
732 server = self.get_server_from_opts(opts)
733 ticket_string = server.GetTicket(slice_urn, [slice_cred], rspec, [])
734 file = os.path.join(self.options.sfi_dir, get_leaf(slice_hrn) + ".ticket")
735 print "writing ticket to ", file
736 ticket = SfaTicket(string=ticket_string)
737 ticket.save_to_file(filename=file, save_parents=True)
739 def redeem_ticket(self, opts, args):
740 ticket_file = args[0]
742 # get slice hrn from the ticket
743 # use this to get the right slice credential
744 ticket = SfaTicket(filename=ticket_file)
746 slice_hrn = ticket.gidObject.get_hrn()
747 slice_urn = hrn_to_urn(slice_hrn, 'slice')
748 #slice_hrn = ticket.attributes['slivers'][0]['hrn']
749 user_cred = self.get_user_cred()
750 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
752 # get a list of node hostnames from the RSpec
753 tree = etree.parse(StringIO(ticket.rspec))
754 root = tree.getroot()
755 hostnames = root.xpath("./network/site/node/hostname/text()")
757 # create an xmlrpc connection to the component manager at each of these
758 # components and gall redeem_ticket
760 for hostname in hostnames:
762 print "Calling redeem_ticket at %(hostname)s " % locals(),
763 server = self.get_server(hostname, CM_PORT, self.key_file, \
764 self.cert_file, self.options.debug)
765 server.RedeemTicket(ticket.save_to_string(save_parents=True), slice_cred)
767 except socket.gaierror:
769 print "Componet Manager not accepting requests"
771 print "Failed:", e.message
775 def delete(self, opts, args):
777 slice_urn = hrn_to_urn(slice_hrn, 'slice')
778 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
779 server = self.get_server_from_opts(opts)
780 return server.DeleteSliver(slice_urn, [slice_cred])
783 def start(self, opts, args):
785 slice_urn = hrn_to_urn(slice_hrn, 'slice')
786 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
787 server = self.get_server_from_opts(opts)
788 return server.Start(slice_urn, [slice_cred])
791 def stop(self, opts, args):
793 slice_urn = hrn_to_urn(slice_hrn, 'slice')
794 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
795 server = self.get_server_from_opts(opts)
796 return server.Stop(slice_urn, [slice_cred])
799 def reset(self, opts, args):
801 slice_urn = hrn_to_urn(slice_hrn, 'slice')
802 server = self.get_server_from_opts(opts)
803 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
804 return server.reset_slice(slice_cred, slice_urn)
806 def renew(self, opts, args):
808 slice_urn = hrn_to_urn(slice_hrn, 'slice')
809 server = self.get_server_from_opts(opts)
810 slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
812 return server.RenewSliver(slice_urn, [slice_cred], time)
815 def status(self, opts, args):
817 slice_urn = hrn_to_urn(slice_hrn, 'slice')
818 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
819 server = self.get_server_from_opts(opts)
820 print server.SliverStatus(slice_urn, [slice_cred])
823 def shutdown(self, opts, args):
825 slice_urn = hrn_to_urn(slice_hrn, 'slice')
826 slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
827 server = self.get_server_from_opts(opts)
828 return server.Shutdown(slice_urn, [slice_cred])
831 # Main: parse arguments and dispatch to command
834 parser = self.create_parser()
835 (options, args) = parser.parse_args()
836 self.options = options
838 if options.hashrequest:
839 self.hashrequest = True
842 print "No command given. Use -h for help."
846 (cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
847 if self.options.verbose :
848 print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
849 options.sfi_dir, options.user,
851 print "Command %s" % command
852 if command in ("resources"):
853 print "resources cmd_opts %s" % cmd_opts.format
854 elif command in ("list", "show", "remove"):
855 print "cmd_opts.type %s" % cmd_opts.type
856 print "cmd_args %s" % cmd_args
861 self.dispatch(command, cmd_opts, cmd_args)
864 print "Command not found:", command
869 if __name__ == "__main__":