Skip to content

Commit 4ceef3b

Browse files
author
Dean Troyer
committed
Use cliff
1 parent 06f8230 commit 4ceef3b

3 files changed

Lines changed: 104 additions & 223 deletions

File tree

openstackclient/compute/v2/server.py

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
Server action implementations
2020
"""
2121

22+
import logging
23+
24+
from cliff.command import Command
25+
2226
from openstackclient.common import utils
2327

2428

@@ -53,9 +57,41 @@ def _print_server(cs, server):
5357

5458
utils.print_dict(info)
5559

56-
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
57-
def do_show_server(cs, args):
58-
"""Show details about the given server."""
59-
print "do_show_server(%s)" % args.server
60-
#s = _find_server(cs, args.server)
61-
#_print_server(cs, s)
60+
class List_Server(Command):
61+
"List server command."
62+
63+
log = logging.getLogger(__name__)
64+
65+
def get_parser(self, prog_name):
66+
parser = super(List_Server, self).get_parser(prog_name)
67+
parser.add_argument(
68+
'--long',
69+
action='store_true',
70+
default=False,
71+
help='Additional fields are listed in output')
72+
return parser
73+
74+
def run(self, parsed_args):
75+
self.log.info('List_Server()')
76+
self.log.info(' run(%s)' % parsed_args)
77+
self.app.stdout.write('hi!\n')
78+
79+
class Show_Server(Command):
80+
"Show server command."
81+
82+
log = logging.getLogger(__name__)
83+
84+
def get_parser(self, prog_name):
85+
parser = super(Show_Server, self).get_parser(prog_name)
86+
parser.add_argument(
87+
'server',
88+
metavar='<server>',
89+
help='Name or ID of server to display')
90+
return parser
91+
92+
def run(self, parsed_args):
93+
self.log.info('Show_Server()')
94+
self.log.info(' run(%s)' % parsed_args)
95+
self.app.stdout.write('hi!\n')
96+
#s = _find_server(cs, args.server)
97+
#_print_server(cs, s)

openstackclient/shell.py

Lines changed: 55 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,23 @@
1616
# vim: tabstop=4 shiftwidth=4 softtabstop=4
1717

1818
"""
19-
Command-line interface to the OpenStack Identity, Compute and Storage APIs
19+
Command-line interface to the OpenStack APIs
2020
"""
2121

22-
import argparse
23-
import httplib2
22+
import logging
23+
import optparse
2424
import os
2525
import sys
2626

27+
from cliff.app import App
28+
from cliff.commandmanager import CommandManager
29+
2730
from openstackclient.common import utils
2831

2932

33+
VERSION = '0.1'
34+
35+
3036
def env(*vars, **kwargs):
3137
"""Search for the first defined of possibly many env vars
3238
@@ -41,265 +47,98 @@ def env(*vars, **kwargs):
4147
return kwargs.get('default', '')
4248

4349

44-
class OpenStackShell(object):
45-
46-
def _find_actions(self, subparsers, actions_module):
47-
if self.debug:
48-
print "_find_actions(module: %s)" % actions_module
49-
for attr in (a for a in dir(actions_module) if a.startswith('do_')):
50-
# I prefer to be hypen-separated instead of underscores.
51-
command = attr[3:].replace('_', '-')
52-
cmd = command.split('-', 1)
53-
action = cmd[0]
54-
if len(cmd) > 1:
55-
subject = cmd[1]
56-
else:
57-
subject = ''
58-
callback = getattr(actions_module, attr)
59-
desc = callback.__doc__ or ''
60-
help = desc.strip().split('\n')[0]
61-
arguments = getattr(callback, 'arguments', [])
62-
63-
if self.debug:
64-
print " command: %s" % command
65-
print " action: %s" % action
66-
print " subject: %s" % subject
67-
print " arguments: %s" % arguments
68-
69-
subparser = subparsers.add_parser(command,
70-
help=help,
71-
description=desc,
72-
add_help=False,
73-
formatter_class=OpenStackHelpFormatter
50+
class OpenStackShell(App):
51+
52+
log = logging.getLogger(__name__)
53+
54+
def __init__(self):
55+
super(OpenStackShell, self).__init__(
56+
description=__doc__.strip(),
57+
version=VERSION,
58+
command_manager=CommandManager('openstack.cli'),
7459
)
75-
subparser.add_argument('-h', '--help',
76-
action='help',
77-
help=argparse.SUPPRESS,
60+
61+
def build_option_parser(self, description, version):
62+
parser = super(OpenStackShell, self).build_option_parser(
63+
description,
64+
version,
7865
)
79-
self.subcommands[command] = subparser
80-
for (args, kwargs) in arguments:
81-
subparser.add_argument(*args, **kwargs)
82-
subparser.set_defaults(func=callback)
83-
84-
@utils.arg('command', metavar='<subcommand>', nargs='?',
85-
help='Display help for <subcommand>')
86-
def do_help(self, args):
87-
"""
88-
Display help about this program or one of its subcommands.
89-
"""
90-
if getattr(args, 'command', None):
91-
if args.command in self.subcommands:
92-
self.subcommands[args.command].print_help()
93-
else:
94-
raise exc.CommandError("'%s' is not a valid subcommand" %
95-
args.command)
96-
else:
97-
self.parser.print_help()
98-
99-
def get_base_parser(self):
100-
parser = argparse.ArgumentParser(
101-
prog='stack',
102-
description=__doc__.strip(),
103-
epilog='See "stack help COMMAND" '
104-
'for help on a specific command.',
105-
add_help=False,
106-
formatter_class=OpenStackHelpFormatter,
107-
)
10866

10967
# Global arguments
110-
parser.add_argument('-h', '--help',
111-
action='store_true',
112-
help=argparse.SUPPRESS,
113-
)
114-
115-
parser.add_argument('--os-auth-url', metavar='<auth-url>',
68+
parser.add_option('--os-auth-url', metavar='<auth-url>',
11669
default=env('OS_AUTH_URL'),
11770
help='Authentication URL (Env: OS_AUTH_URL)')
11871

119-
parser.add_argument('--os-tenant-name', metavar='<auth-tenant-name>',
72+
parser.add_option('--os-tenant-name', metavar='<auth-tenant-name>',
12073
default=env('OS_TENANT_NAME'),
12174
help='Authentication tenant name (Env: OS_TENANT_NAME)')
12275

123-
parser.add_argument('--os-tenant-id', metavar='<auth-tenant-id>',
76+
parser.add_option('--os-tenant-id', metavar='<auth-tenant-id>',
12477
default=env('OS_TENANT_ID'),
12578
help='Authentication tenant ID (Env: OS_TENANT_ID)')
12679

127-
parser.add_argument('--os-username', metavar='<auth-username>',
80+
parser.add_option('--os-username', metavar='<auth-username>',
12881
default=utils.env('OS_USERNAME'),
12982
help='Authentication username (Env: OS_USERNAME)')
13083

131-
parser.add_argument('--os-password', metavar='<auth-password>',
84+
parser.add_option('--os-password', metavar='<auth-password>',
13285
default=utils.env('OS_PASSWORD'),
13386
help='Authentication password (Env: OS_PASSWORD)')
13487

135-
parser.add_argument('--os-region-name', metavar='<auth-region-name>',
88+
parser.add_option('--os-region-name', metavar='<auth-region-name>',
13689
default=env('OS_REGION_NAME'),
13790
help='Authentication region name (Env: OS_REGION_NAME)')
13891

139-
parser.add_argument('--debug',
140-
default=False,
141-
action='store_true',
142-
help=argparse.SUPPRESS)
143-
144-
parser.add_argument('--os-identity-api-version',
92+
parser.add_option('--os-identity-api-version',
14593
metavar='<identity-api-version>',
14694
default=env('OS_IDENTITY_API_VERSION', default='2.0'),
14795
help='Identity API version, default=2.0 (Env: OS_IDENTITY_API_VERSION)')
14896

149-
parser.add_argument('--os-compute-api-version',
97+
parser.add_option('--os-compute-api-version',
15098
metavar='<compute-api-version>',
15199
default=env('OS_COMPUTE_API_VERSION', default='2'),
152100
help='Compute API version, default=2.0 (Env: OS_COMPUTE_API_VERSION)')
153101

154-
parser.add_argument('--os-image-api-version',
102+
parser.add_option('--os-image-api-version',
155103
metavar='<image-api-version>',
156104
default=env('OS_IMAGE_API_VERSION', default='1.0'),
157105
help='Image API version, default=1.0 (Env: OS_IMAGE_API_VERSION)')
158106

159-
parser.add_argument('--service-token', metavar='<service-token>',
107+
parser.add_option('--service-token', metavar='<service-token>',
160108
default=env('SERVICE_TOKEN'),
161-
help=argparse.SUPPRESS)
109+
help='deprecated')
162110

163-
parser.add_argument('--service-endpoint', metavar='<service-endpoint>',
111+
parser.add_option('--service-endpoint', metavar='<service-endpoint>',
164112
default=env('SERVICE_ENDPOINT'),
165-
help=argparse.SUPPRESS)
166-
167-
parser.add_argument('action', metavar='<action>',
168-
default='help',
169-
help=argparse.SUPPRESS)
170-
171-
parser.add_argument('subject', metavar='<subject>',
172-
default='', nargs='?',
173-
help=argparse.SUPPRESS)
113+
help='deprecated')
174114

175115
return parser
176116

177-
def get_subcommand_parser(self, cmd_subject):
178-
parser = self.get_base_parser()
179-
180-
self.subcommands = {}
181-
subparsers = parser.add_subparsers(metavar='<subcommand>')
182-
183-
if cmd_subject is None or cmd_subject == '':
184-
# TODO(dtroyer): iterate over all known subjects to produce
185-
# the complete help list
186-
print "Get all subjects here - exit"
187-
exit(1)
188-
189-
(module, version) = self._map_subject(cmd_subject)
190-
if module is None or cmd_subject is None:
191-
print "Module %s not found - exit" % cmd_subject
192-
exit(1)
193-
if self.debug:
194-
print "module: %s" % module
195-
exec("from %s.v%s import %s as cmd" % (module, self.api_version[module], cmd_subject))
196-
self._find_actions(subparsers, cmd)
197-
198-
self._find_actions(subparsers, self)
199-
200-
return parser
201-
202-
def _map_subject(self, cmd_subject):
203-
'''Convert from subject to the module that implements it'''
204-
COMPUTE = ['server']
205-
IDENTITY = ['key']
206-
IMAGE = ['image']
207-
if cmd_subject in COMPUTE:
208-
version = self.api_version['compute'].replace('.', '_')
209-
return ('compute', version)
210-
elif cmd_subject in IDENTITY:
211-
version = self.api_version['identity'].replace('.', '_')
212-
return ('identity', version)
213-
elif cmd_subject in IMAGE:
214-
version = self.api_version['imade'].replace('.', '_')
215-
return ('image', version)
216-
else:
217-
return None
218-
219-
def main(self, argv):
220-
'''
221-
- get api version
222-
- get version command set
223-
- import version-subject module
224-
- is verb-subject supported?
225-
'''
226-
# Parse global args to find version
227-
parser = self.get_base_parser()
228-
(options, args) = parser.parse_known_args(argv)
117+
def prepare_to_run_command(self, cmd):
118+
"""Set up auth and API versions"""
119+
self.log.debug('prepare_to_run_command %s', cmd.__class__.__name__)
229120

230121
# stash selected API versions for later
231122
# TODO(dtroyer): how do extenstions add their version requirements?
232123
self.api_version = {
233-
'compute': options.os_compute_api_version,
234-
'identity': options.os_identity_api_version,
235-
'image': options.os_image_api_version,
124+
'compute': self.options.os_compute_api_version,
125+
'identity': self.options.os_identity_api_version,
126+
'image': self.options.os_image_api_version,
236127
}
237128

238-
# Setup debugging
239-
if getattr(options, 'debug', None):
240-
self.debug = 1
241-
else:
242-
self.debug = 0
243-
244-
if self.debug:
129+
if self.options.debug:
245130
print "API: Identity=%s Compute=%s Image=%s" % (self.api_version['identity'], self.api_version['compute'], self.api_version['image'])
246-
print "Action: %s" % options.action
247-
print "subject: %s" % getattr(options, 'subject', '')
248-
print "args: %s" % args
249-
250-
# Handle top-level --help/-h before attempting to parse
251-
# a command off the command line
252-
if getattr(options, 'help', None) or getattr(options, 'action', None) == 'help':
253-
print "top-level help"
254-
# Build available subcommands
255-
self.parser = self.get_subcommand_parser(options.subject)
256-
self.do_help(options)
257-
return 0
258-
259-
# Build selected subcommands
260-
self.parser = self.get_subcommand_parser(options.subject)
261-
262-
# Parse args again and call whatever callback was selected
263-
args.insert(0, '%s-%s' % (options.action, options.subject))
264-
if self.debug:
265-
print "args: %s" % args
266-
args = self.parser.parse_args(args)
267-
268-
if self.debug:
269-
print "Testing command parsing"
270-
print "Auth username: %s" % options.os_username
271-
#print "Action: %s" % options.action
272-
#print "Subject: %s" % options.subject
273-
print "args: %s" % args
274-
275-
class OpenStackHelpFormatter(argparse.HelpFormatter):
276-
def start_section(self, heading):
277-
# Title-case the headings
278-
heading = '%s%s' % (heading[0].upper(), heading[1:])
279-
super(OpenStackHelpFormatter, self).start_section(heading)
280-
281-
282-
def main():
283-
try:
284-
OpenStackShell().main(sys.argv[1:])
285-
286-
except Exception, e:
287-
if httplib2.debuglevel == 1:
288-
raise # dump stack.
289-
else:
290-
print >> sys.stderr, e
291-
sys.exit(1)
292-
293-
def test_main(argv):
294-
# The argparse/optparse/cmd2 modules muck about with sys.argv
295-
# so we save it and restore at the end to let the tests
296-
# run repeatedly without concatenating the args on each run
297-
save_argv = sys.argv
298-
299-
main()
300-
301-
# Put it back so the next test has a clean copy
302-
sys.argv = save_argv
131+
print "cmd: %s" % cmd
132+
133+
def clean_up(self, cmd, result, err):
134+
self.log.debug('clean_up %s', cmd.__class__.__name__)
135+
if err:
136+
self.log.debug('got an error: %s', err)
137+
138+
139+
def main(argv=sys.argv[1:]):
140+
return OpenStackShell().run(argv)
141+
303142

304143
if __name__ == "__main__":
305-
main()
144+
sys.exit(main(sys.argv[1:]))

0 commit comments

Comments
 (0)