Skip to content

Commit 3eafa59

Browse files
committed
Conversion to click
This includes a mess of changes: * stricter option parsing (ex: global options are specified directly after sl) * no prefix-based option matching that doc-opt did * entrypoint-based loading * Several CLI cleanups: ** Remove help command ** Renames dns subcommands to include zone- and record- ** Renames --hourly and --billing for `sl vs create` and `sl hardware create` to --billing=hourly or --billing=monthly. ** Many other subtle changes
1 parent 20d9813 commit 3eafa59

File tree

226 files changed

+8327
-9219
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

226 files changed

+8327
-9219
lines changed

SoftLayer/CLI/cdn/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"""Content Delivery Network."""
2+
# :license: MIT, see LICENSE for more details.

SoftLayer/CLI/cdn/detail.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Detail a CDN Account."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import SoftLayer
5+
from SoftLayer.CLI import environment
6+
from SoftLayer.CLI import formatting
7+
8+
import click
9+
10+
11+
@click.command()
12+
@click.argument('account_id')
13+
@environment.pass_env
14+
def cli(env, account_id):
15+
"""Detail a CDN Account."""
16+
17+
manager = SoftLayer.CDNManager(env.client)
18+
account = manager.get_account(account_id)
19+
20+
table = formatting.KeyValueTable(['Name', 'Value'])
21+
table.align['Name'] = 'r'
22+
table.align['Value'] = 'l'
23+
24+
table.add_row(['id', account['id']])
25+
table.add_row(['account_name', account['cdnAccountName']])
26+
table.add_row(['type', account['cdnSolutionName']])
27+
table.add_row(['status', account['status']['name']])
28+
table.add_row(['created', account['createDate']])
29+
table.add_row(['notes',
30+
account.get('cdnAccountNote', formatting.blank())])
31+
32+
return table

SoftLayer/CLI/cdn/list.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""List CDN Accounts."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import SoftLayer
5+
from SoftLayer.CLI import environment
6+
from SoftLayer.CLI import formatting
7+
8+
import click
9+
10+
11+
@click.command()
12+
@click.option('--sortby',
13+
help='Column to sort by',
14+
type=click.Choice(['id',
15+
'datacenter',
16+
'host',
17+
'cores',
18+
'memory',
19+
'primary_ip',
20+
'backend_ip']))
21+
@environment.pass_env
22+
def cli(env, sortby):
23+
"""List all CDN accounts."""
24+
25+
manager = SoftLayer.CDNManager(env.client)
26+
accounts = manager.list_accounts()
27+
28+
table = formatting.Table(['id',
29+
'account_name',
30+
'type',
31+
'created',
32+
'notes'])
33+
for account in accounts:
34+
table.add_row([
35+
account['id'],
36+
account['cdnAccountName'],
37+
account['cdnSolutionName'],
38+
account['createDate'],
39+
account.get('cdnAccountNote', formatting.blank())
40+
])
41+
42+
table.sortby = sortby
43+
return table

SoftLayer/CLI/cdn/load.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Cache one or more files on all edge nodes."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import SoftLayer
5+
from SoftLayer.CLI import environment
6+
7+
import click
8+
9+
10+
@click.command()
11+
@click.argument('account_id')
12+
@click.argument('content_url', nargs=-1)
13+
@environment.pass_env
14+
def cli(env, account_id, content_url):
15+
"""Cache one or more files on all edge nodes."""
16+
17+
manager = SoftLayer.CDNManager(env.client)
18+
manager.load_content(account_id, content_url)

SoftLayer/CLI/cdn/origin_add.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Create an origin pull mapping."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import SoftLayer
5+
from SoftLayer.CLI import environment
6+
7+
import click
8+
# pylint: disable=redefined-builtin
9+
10+
11+
@click.command()
12+
@click.argument('account_id')
13+
@click.argument('content_url')
14+
@click.option('--type',
15+
help='The media type for this mapping (http, flash, wm, ...)',
16+
default='http')
17+
@click.option('--cname',
18+
help='An optional CNAME to attach to the mapping')
19+
@environment.pass_env
20+
def cli(env, account_id, content_url, type, cname):
21+
"""Create an origin pull mapping."""
22+
23+
manager = SoftLayer.CDNManager(env.client)
24+
manager.add_origin(account_id, type, content_url, cname)

SoftLayer/CLI/cdn/origin_list.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""List origin pull mappings."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import SoftLayer
5+
from SoftLayer.CLI import environment
6+
from SoftLayer.CLI import formatting
7+
8+
import click
9+
10+
11+
@click.command()
12+
@click.argument('account_id')
13+
@environment.pass_env
14+
def cli(env, account_id):
15+
"""List origin pull mappings."""
16+
17+
manager = SoftLayer.CDNManager(env.client)
18+
origins = manager.get_origins(account_id)
19+
20+
table = formatting.Table(['id', 'media_type', 'cname', 'origin_url'])
21+
22+
for origin in origins:
23+
table.add_row([origin['id'],
24+
origin['mediaType'],
25+
origin.get('cname', formatting.blank()),
26+
origin['originUrl']])
27+
28+
return table

SoftLayer/CLI/cdn/origin_remove.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Remove an origin pull mapping."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import SoftLayer
5+
from SoftLayer.CLI import environment
6+
7+
import click
8+
9+
10+
@click.command()
11+
@click.argument('account_id')
12+
@click.argument('origin_id')
13+
@environment.pass_env
14+
def cli(env, account_id, origin_id):
15+
"""Remove an origin pull mapping."""
16+
17+
manager = SoftLayer.CDNManager(env.client)
18+
manager.remove_origin(account_id, origin_id)

SoftLayer/CLI/cdn/purge.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Purge cached files from all edge nodes."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import SoftLayer
5+
from SoftLayer.CLI import environment
6+
7+
import click
8+
9+
10+
@click.command()
11+
@click.argument('account_id')
12+
@click.argument('content_url', nargs=-1)
13+
@environment.pass_env
14+
def cli(env, account_id, content_url):
15+
"""Purge cached files from all edge nodes."""
16+
17+
manager = SoftLayer.CDNManager(env.client)
18+
manager.purge_content(account_id, content_url)

SoftLayer/CLI/config/__init__.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""CLI configuration."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
from SoftLayer.CLI import formatting
5+
6+
7+
def get_settings_from_client(client):
8+
"""Pull out settings from a SoftLayer.Client instance.
9+
10+
:param client: SoftLayer.Client instance
11+
"""
12+
settings = {
13+
'username': '',
14+
'api_key': '',
15+
'timeout': client.timeout or '',
16+
'endpoint_url': client.endpoint_url,
17+
}
18+
try:
19+
settings['username'] = client.auth.username
20+
settings['api_key'] = client.auth.api_key
21+
except AttributeError:
22+
pass
23+
24+
return settings
25+
26+
27+
def config_table(settings):
28+
"""Returns a config table."""
29+
table = formatting.KeyValueTable(['Name', 'Value'])
30+
table.align['Name'] = 'r'
31+
table.align['Value'] = 'l'
32+
table.add_row(['Username', settings['username'] or 'not set'])
33+
table.add_row(['API Key', settings['api_key'] or 'not set'])
34+
table.add_row(['Endpoint URL', settings['endpoint_url'] or 'not set'])
35+
table.add_row(['Timeout', settings['timeout'] or 'not set'])
36+
return table

SoftLayer/CLI/config/setup.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
"""Setup CLI configuration."""
2+
# :license: MIT, see LICENSE for more details.
3+
import os.path
4+
5+
import SoftLayer
6+
from SoftLayer import auth
7+
from SoftLayer.CLI import config
8+
from SoftLayer.CLI import environment
9+
from SoftLayer.CLI import exceptions
10+
from SoftLayer.CLI import formatting
11+
from SoftLayer import utils
12+
13+
import click
14+
15+
16+
def get_api_key(client, username, secret, endpoint_url=None):
17+
"""Attempts API-Key and password auth to get an API key.
18+
19+
This will also generate an API key if one doesn't exist
20+
"""
21+
22+
client.endpoint_url = endpoint_url
23+
client.auth = None
24+
# Try to use a client with username/api key
25+
if len(secret) == 64:
26+
try:
27+
client.auth = auth.BasicAuthentication(username, secret)
28+
client['Account'].getCurrentUser()
29+
return secret
30+
except SoftLayer.SoftLayerAPIError as ex:
31+
if 'invalid api token' not in ex.faultString.lower():
32+
raise
33+
else:
34+
# Try to use a client with username/password
35+
client.authenticate_with_password(username, secret)
36+
37+
user_record = client['Account'].getCurrentUser(
38+
mask='id, apiAuthenticationKeys')
39+
api_keys = user_record['apiAuthenticationKeys']
40+
if len(api_keys) == 0:
41+
return client['User_Customer'].addApiAuthenticationKey(
42+
id=user_record['id'])
43+
return api_keys[0]['authenticationKey']
44+
45+
46+
@click.command()
47+
@environment.pass_env
48+
def cli(env):
49+
"""Edit configuration."""
50+
51+
username, secret, endpoint_url, timeout = get_user_input(env)
52+
53+
api_key = get_api_key(env.client, username, secret,
54+
endpoint_url=endpoint_url)
55+
56+
path = '~/.softlayer'
57+
if env.config_file:
58+
path = env.config_file
59+
config_path = os.path.expanduser(path)
60+
61+
env.out(env.fmt(config.config_table({'username': username,
62+
'api_key': api_key,
63+
'endpoint_url': endpoint_url,
64+
'timeout': timeout})))
65+
66+
if not formatting.confirm('Are you sure you want to write settings '
67+
'to "%s"?' % config_path, default=True):
68+
raise exceptions.CLIAbort('Aborted.')
69+
70+
# Persist the config file. Read the target config file in before
71+
# setting the values to avoid clobbering settings
72+
parsed_config = utils.configparser.RawConfigParser()
73+
parsed_config.read(config_path)
74+
try:
75+
parsed_config.add_section('softlayer')
76+
except utils.configparser.DuplicateSectionError:
77+
pass
78+
79+
parsed_config.set('softlayer', 'username', username)
80+
parsed_config.set('softlayer', 'api_key', api_key)
81+
parsed_config.set('softlayer', 'endpoint_url', endpoint_url)
82+
83+
config_fd = os.fdopen(os.open(config_path,
84+
(os.O_WRONLY | os.O_CREAT | os.O_TRUNC),
85+
0o600),
86+
'w')
87+
try:
88+
parsed_config.write(config_fd)
89+
finally:
90+
config_fd.close()
91+
92+
return "Configuration Updated Successfully"
93+
94+
95+
def get_user_input(env):
96+
"""Ask for username, secret (api_key or password) and endpoint_url."""
97+
98+
defaults = config.get_settings_from_client(env.client.real_client)
99+
timeout = defaults['timeout']
100+
101+
# Ask for username
102+
for _ in range(3):
103+
username = (env.input('Username [%s]: ' % defaults['username'])
104+
or defaults['username'])
105+
if username:
106+
break
107+
else:
108+
raise exceptions.CLIAbort('Aborted after 3 attempts')
109+
110+
# Ask for 'secret' which can be api_key or their password
111+
for _ in range(3):
112+
secret = (env.getpass('API Key or Password [%s]: '
113+
% defaults['api_key'])
114+
or defaults['api_key'])
115+
if secret:
116+
break
117+
else:
118+
raise exceptions.CLIAbort('Aborted after 3 attempts')
119+
120+
# Ask for which endpoint they want to use
121+
for _ in range(3):
122+
endpoint_type = env.input(
123+
'Endpoint (public|private|custom): ')
124+
endpoint_type = endpoint_type.lower()
125+
if not endpoint_type:
126+
endpoint_url = SoftLayer.API_PUBLIC_ENDPOINT
127+
break
128+
if endpoint_type == 'public':
129+
endpoint_url = SoftLayer.API_PUBLIC_ENDPOINT
130+
break
131+
elif endpoint_type == 'private':
132+
endpoint_url = SoftLayer.API_PRIVATE_ENDPOINT
133+
break
134+
elif endpoint_type == 'custom':
135+
endpoint_url = env.input(
136+
'Endpoint URL [%s]: ' % defaults['endpoint_url']
137+
) or defaults['endpoint_url']
138+
break
139+
else:
140+
raise exceptions.CLIAbort('Aborted after 3 attempts')
141+
142+
return username, secret, endpoint_url, timeout

0 commit comments

Comments
 (0)