Skip to content

Commit 5618fe6

Browse files
committed
Fix Review Notes
1 parent 3eafa59 commit 5618fe6

20 files changed

Lines changed: 223 additions & 211 deletions

File tree

SoftLayer/CLI/core.py

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,41 +34,30 @@
3434

3535

3636
class CommandLoader(click.MultiCommand):
37-
"""Loads commands for click."""
38-
def __init__(self, module=None, **attrs):
39-
click.MultiCommand.__init__(self, **attrs)
40-
self.module = module
41-
42-
def list_commands(self, ctx):
43-
"""Get module for click."""
44-
env = ctx.ensure_object(environment.Environment)
45-
return env.command_list(self.module)
46-
47-
def get_command(self, ctx, name):
48-
"""Get command for click."""
49-
env = ctx.ensure_object(environment.Environment)
50-
command = env.get_command(self.module, name)
51-
return command
52-
53-
54-
class ModuleLoader(click.MultiCommand):
5537
"""Loads module for click."""
5638

39+
def __init__(self, *path, **attrs):
40+
click.MultiCommand.__init__(self, **attrs)
41+
self.path = path
42+
5743
def list_commands(self, ctx):
5844
"""Get module for click."""
5945
env = ctx.ensure_object(environment.Environment)
60-
return sorted(env.module_list())
46+
return sorted(env.list_commands(*self.path))
6147

6248
def get_command(self, ctx, name):
6349
"""Get command for click."""
6450
env = ctx.ensure_object(environment.Environment)
6551

66-
# Do alias lookup
67-
module_name = env.get_module_name(name)
52+
# Do alias lookup (only available for root commands)
53+
if len(self.path) == 0:
54+
name = env.resolve_alias(name)
6855

69-
module = env.get_module(module_name)
56+
new_path = list(self.path)
57+
new_path.append(name)
58+
module = env.get_command(*new_path)
7059
if isinstance(module, types.ModuleType):
71-
return CommandLoader(module=module_name, help=module.__doc__)
60+
return CommandLoader(*new_path, help=module.__doc__)
7261
else:
7362
return module
7463

@@ -102,7 +91,7 @@ def call(self, service, method, *args, **kwargs):
10291
epilog="""To use most commands your SoftLayer
10392
username and api_key need to be configured. The easiest way to do that is to
10493
use: 'sl config setup'""",
105-
cls=ModuleLoader)
94+
cls=CommandLoader)
10695
@click.pass_context
10796
@click.option('--format',
10897
default=DEFAULT_FORMAT,

SoftLayer/CLI/dns/record_edit.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,33 @@
33

44
import SoftLayer
55
from SoftLayer.CLI import environment
6+
from SoftLayer.CLI import helpers
67

78
import click
89
# pylint: disable=redefined-builtin
910

1011

1112
@click.command()
12-
@click.argument('record_id')
13-
@click.option('--record', help='Host record, such as www')
13+
@click.argument('zone-id')
14+
@click.option('--by-record', help='Edit by host record, such as www')
15+
@click.option('--by-id', help='Edit a single record by its ID')
1416
@click.option('--data', help='Record data, such as an IP address')
1517
@click.option('--ttl',
1618
type=click.INT,
1719
help='TTL value in seconds, such as 86400')
18-
@click.option('--type', help='Record type, such as A or CNAME')
1920
@environment.pass_env
20-
def cli(env, record_id, record, data, ttl, type):
21+
def cli(env, zone_id, by_record, by_id, data, ttl):
2122
"""Update DNS record."""
2223
manager = SoftLayer.DNSManager(env.client)
23-
result = manager.get_record(record_id)
24-
result['host'] = record or result['record']
25-
result['ttl'] = ttl or result['ttl']
26-
result['type'] = type or result['type']
27-
result['data'] = data or result['data']
28-
manager.edit_record(result)
24+
zone_id = helpers.resolve_id(manager.resolve_ids, zone_id, name='zone')
25+
26+
results = manager.get_records(zone_id, host=by_record)
27+
28+
for result in results:
29+
if by_id and str(result['id']) != by_id:
30+
continue
31+
print result
32+
result['data'] = data or result['data']
33+
result['ttl'] = ttl or result['ttl']
34+
print result
35+
manager.edit_record(result)

SoftLayer/CLI/dns/record_list.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ def cli(env, zone, data, record, ttl, type):
2323
"""List all records in a zone."""
2424

2525
manager = SoftLayer.DNSManager(env.client)
26-
table = formatting.Table(['id', 'record', 'type', 'ttl', 'value'])
26+
table = formatting.Table(['id', 'record', 'type', 'ttl', 'data'])
2727

2828
table.align['ttl'] = 'l'
2929
table.align['record'] = 'r'
30-
table.align['value'] = 'l'
30+
table.align['data'] = 'l'
3131

3232
zone_id = helpers.resolve_id(manager.resolve_ids, zone, name='zone')
3333

SoftLayer/CLI/environment.py

Lines changed: 47 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
class Environment(object):
2323
"""Provides access to the current CLI environment."""
2424
def __init__(self):
25-
# {'module_name': {'action': plugin_loader}}
26-
self.plugins = {}
25+
# {'path:to:command': ModuleLoader()}
26+
# {'vs:list': ModuleLoader()}
27+
self.commands = {}
2728
self.aliases = {
2829
'meta': 'metadata',
2930
'my': 'metadata',
@@ -41,39 +42,57 @@ def __init__(self):
4142
self._modules_loaded = False
4243
self.config_file = None
4344

44-
def command_list(self, module_name):
45-
"""Command listing."""
45+
def out(self, output, newline=True):
46+
"""Outputs a string to the console (stdout)."""
47+
click.echo(output, nl=newline)
4648

47-
self._load_modules()
48-
# Filter commands registered as None. These are the bases.
49-
return sorted([m for m in self.plugins[module_name].keys()
50-
if m is not None])
49+
def err(self, output, newline=True):
50+
"""Outputs an error string to the console (stderr)."""
51+
click.echo(output, nl=newline, err=True)
5152

52-
def module_list(self):
53-
"""Returns the list of modules in SoftLayer.CLI.modules."""
54-
self._load_modules()
55-
return sorted(list(self.plugins.keys()))
53+
def fmt(self, output):
54+
"""Format output based on current the environment format."""
55+
return formatting.format_output(output, fmt=self.format)
5656

57-
def get_command(self, module_name, command_name):
58-
"""Based on the loaded modules, return a command."""
57+
def input(self, prompt):
58+
"""Provide a command prompt."""
59+
return utils.console_input(prompt)
60+
61+
def getpass(self, prompt):
62+
"""Provide a password prompt."""
63+
return getpass.getpass(prompt)
64+
65+
# Command loading methods
66+
def list_commands(self, *path):
67+
"""Command listing."""
5968
self._load_modules()
60-
actions = self.plugins.get(module_name) or {}
69+
path_str = self.resolve_alias(':'.join(path))
6170

62-
if command_name in actions:
63-
return actions[command_name].load()
71+
commands = []
72+
for command in self.commands.keys():
73+
# Filter based on prefix and the segment length
74+
if all([command.startswith(path_str),
75+
len(path) == command.count(":")]):
76+
offset = len(path_str)+1 if path_str else 0
77+
commands.append(command[offset:])
6478

65-
raise exceptions.InvalidCommand(module_name, command_name)
79+
return sorted(commands)
6680

67-
def get_module(self, module_name):
68-
"""Returns the module."""
81+
def get_command(self, *path):
82+
"""Return command at the given path or raise error."""
6983
self._load_modules()
70-
return self.get_command(module_name, None)
84+
path_str = self.resolve_alias(':'.join(path))
7185

72-
def get_module_name(self, module_name):
73-
"""Returns the actual module name. Uses the alias mapping."""
74-
if module_name in self.aliases:
75-
return self.aliases[module_name]
76-
return module_name
86+
if path_str in self.commands:
87+
return self.commands[path_str].load()
88+
89+
raise exceptions.InvalidCommand(path)
90+
91+
def resolve_alias(self, path_str):
92+
"""Returns the actual command name. Uses the alias mapping."""
93+
if path_str in self.aliases:
94+
return self.aliases[path_str]
95+
return path_str
7796

7897
def _load_modules(self):
7998
"""Loads all modules."""
@@ -88,45 +107,17 @@ def _load_modules(self):
88107
def _load_modules_from_python(self):
89108
"""Load modules from the native python source."""
90109
for name, modpath in routes.ALL_ROUTES:
91-
module, subcommand = _parse_name(name)
92-
if module not in self.plugins:
93-
self.plugins[module] = {}
94-
95110
if ':' in modpath:
96111
path, attr = modpath.split(':', 1)
97112
else:
98113
path, attr = modpath, None
99-
self.plugins[module][subcommand] = ModuleLoader(path, attr=attr)
114+
self.commands[name] = ModuleLoader(path, attr=attr)
100115

101116
def _load_modules_from_entry_points(self):
102117
"""Load modules from the entry_points (slower)."""
103118
for obj in pkg_resources.iter_entry_points(group='softlayer.cli',
104119
name=None):
105-
106-
module, subcommand = _parse_name(obj.name)
107-
if module not in self.plugins:
108-
self.plugins[module] = {}
109-
self.plugins[module][subcommand] = obj
110-
111-
def out(self, output, newline=True):
112-
"""Outputs a string to the console (stdout)."""
113-
click.echo(output, nl=newline)
114-
115-
def err(self, output, newline=True):
116-
"""Outputs an error string to the console (stderr)."""
117-
click.echo(output, nl=newline, err=True)
118-
119-
def fmt(self, output):
120-
"""Format output based on current the environment format."""
121-
return formatting.format_output(output, fmt=self.format)
122-
123-
def input(self, prompt):
124-
"""Provide a command prompt."""
125-
return utils.console_input(prompt)
126-
127-
def getpass(self, prompt):
128-
"""Provide a password prompt."""
129-
return getpass.getpass(prompt)
120+
self.commands[obj.name] = obj
130121

131122

132123
class ModuleLoader(object):
@@ -144,14 +135,4 @@ def load(self):
144135
return module
145136

146137

147-
def _parse_name(name):
148-
"""Parse command name and path from the given name."""
149-
if ':' in name:
150-
module, subcommand = name.split(':', 1)
151-
else:
152-
module, subcommand = name, None
153-
154-
return module, subcommand
155-
156-
157138
pass_env = click.make_pass_decorator(Environment, ensure=True)

SoftLayer/CLI/exceptions.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@ def __init__(self, msg, *args):
3838

3939
class InvalidCommand(SoftLayer.SoftLayerError):
4040
"""Raised when trying to use a command that does not exist."""
41-
def __init__(self, module_name, command_name, *args):
42-
self.module_name = module_name
43-
self.command_name = command_name
44-
cmd_str = module_name
45-
if command_name is not None:
46-
cmd_str = '%s %s' % (module_name, command_name)
47-
SoftLayer.SoftLayerError.__init__(self,
48-
'Invalid command: "%s"' % cmd_str,
49-
*args)
41+
def __init__(self, path, *args):
42+
msg = 'Invalid command: "%s"' % ' '.join(path)
43+
SoftLayer.SoftLayerError.__init__(self, msg, *args)

SoftLayer/CLI/routes.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717
('vs:edit', 'SoftLayer.CLI.virt.edit:cli'),
1818
('vs:list', 'SoftLayer.CLI.virt.list:cli'),
1919
('vs:network', 'SoftLayer.CLI.virt.network:cli'),
20-
('vs:rescue', 'SoftLayer.CLI.virt.power:rescue'),
20+
('vs:pause', 'SoftLayer.CLI.virt.power:pause'),
2121
('vs:power_off', 'SoftLayer.CLI.virt.power:power_off'),
2222
('vs:power_on', 'SoftLayer.CLI.virt.power:power_on'),
23-
('vs:pause', 'SoftLayer.CLI.virt.power:pause'),
23+
('vs:rescue', 'SoftLayer.CLI.virt.power:rescue'),
2424
('vs:resume', 'SoftLayer.CLI.virt.power:resume'),
2525
('vs:ready', 'SoftLayer.CLI.virt.ready:cli'),
26+
('vs:reboot', 'SoftLayer.CLI.virt.power:reboot'),
2627
('vs:reload', 'SoftLayer.CLI.virt.reload:cli'),
2728
('vs:upgrade', 'SoftLayer.CLI.virt.upgrade:cli'),
2829

SoftLayer/CLI/server/create.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
@click.option('--billing',
3232
type=click.Choice(['hourly', 'monthly']),
3333
default='monthly',
34-
help="""Billing rate. The hourly rate is only available on the
35-
bare metal instances""")
34+
help="""Billing rate.
35+
The hourly rate is only available on bare metal instances""")
3636
@click.option('--datacenter', '-d', help="Datacenter shortname")
3737
@click.option('--dedicated/--public',
3838
is_flag=True,
@@ -58,9 +58,6 @@
5858
@click.option('--private',
5959
is_flag=True,
6060
help="Forces the VS to only have access the private network")
61-
@click.option('--like',
62-
is_flag=True,
63-
help="Use the configuration from an existing VS")
6461
@click.option('--network', '-n', help="Network port speed in Mbps")
6562
@click.option('--tag', '-g', multiple=True, help="Tags to add to the instance")
6663
@click.option('--template', '-t',

SoftLayer/CLI/sshkey/add.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
type=click.Path(exists=True),
1515
help="The id_rsa.pub file to import for this key")
1616
@click.option('--key', '-k', help="The actual SSH key")
17-
@click.option('--note', help="Extra note that will be associated to this key")
17+
@click.option('--note', help="Extra note that will be associated with key")
1818
@environment.pass_env
1919
def cli(env, label, in_file, key, note):
2020
"""Add a new SSH key."""

SoftLayer/CLI/subnet/create.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
@click.argument('network', type=click.Choice(['public', 'private']))
1515
@click.argument('quantity', type=click.INT)
1616
@click.argument('vlan-id')
17-
@click.option('--v6', '--ipv6', is_flag=True, help="Order v6 IP Addresses")
17+
@click.option('--v6', '--ipv6', is_flag=True, help="Order IPv6 Addresses")
1818
@click.option('--test',
1919
is_flag=True,
2020
help="Do not order the subnet; just get a quote")

SoftLayer/CLI/ticket/list.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010

1111

1212
@click.command()
13-
@click.option('--open / --closed', 'is_open', help="Display closed tickets")
13+
@click.option('--open / --closed', 'is_open',
14+
help="Display only open or closed tickets")
1415
@environment.pass_env
1516
def cli(env, is_open):
1617
"""List tickets."""

0 commit comments

Comments
 (0)