Skip to content

Commit a1e984a

Browse files
Merge pull request #899 from rlrossiter/order-enhancements
Order enhancements. Adds an easier way to order hardware from the CLI directly using package and item keyNames ### Added to CLI + order + order:category-list + order:item-list + order:package-list + order:place + order:preset-list
2 parents 768b72a + 9d6c962 commit a1e984a

File tree

10 files changed

+1097
-14
lines changed

10 files changed

+1097
-14
lines changed

SoftLayer/CLI/order/__init__.py

Whitespace-only changes.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""List package categories."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
from SoftLayer.managers import ordering
9+
10+
COLUMNS = ['name', 'categoryCode', 'isRequired']
11+
12+
13+
@click.command()
14+
@click.argument('package_keyname')
15+
@click.option('--required',
16+
is_flag=True,
17+
help="List only the required categories for the package")
18+
@environment.pass_env
19+
def cli(env, package_keyname, required):
20+
"""List the categories of a package.
21+
22+
Package keynames can be retrieved from `slcli order package-list`
23+
24+
\b
25+
Example:
26+
# List the categories of Bare Metal servers
27+
slcli order category-list BARE_METAL_SERVER
28+
29+
When using the --required flag, it will list out only the categories
30+
that are required for ordering that package (see `slcli order item-list`)
31+
32+
\b
33+
Example:
34+
# List the required categories for Bare Metal servers
35+
slcli order category-list BARE_METAL_SERVER --required
36+
37+
"""
38+
client = env.client
39+
manager = ordering.OrderingManager(client)
40+
table = formatting.Table(COLUMNS)
41+
42+
categories = manager.list_categories(package_keyname)
43+
44+
if required:
45+
categories = [cat for cat in categories if cat['isRequired']]
46+
47+
for cat in categories:
48+
table.add_row([
49+
cat['itemCategory']['name'],
50+
cat['itemCategory']['categoryCode'],
51+
'Y' if cat['isRequired'] else 'N'
52+
])
53+
54+
env.fout(table)

SoftLayer/CLI/order/item_list.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""List package items."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
from SoftLayer.managers import ordering
9+
10+
COLUMNS = ['keyName',
11+
'description', ]
12+
13+
14+
@click.command()
15+
@click.argument('package_keyname')
16+
@click.option('--keyword',
17+
help="A word (or string) used to filter item names.")
18+
@click.option('--category',
19+
help="Category code to filter items by")
20+
@environment.pass_env
21+
def cli(env, package_keyname, keyword, category):
22+
"""List package items used for ordering.
23+
24+
The items listed can be used with `slcli order place` to specify
25+
the items that are being ordered in the package.
26+
27+
Package keynames can be retrieved using `slcli order package-list`
28+
29+
\b
30+
Example:
31+
# List all items in the VSI package
32+
slcli order item-list CLOUD_SERVER
33+
34+
The --keyword option is used to filter items by name.
35+
The --category option is used to filter items by category.
36+
Both --keyword and --category can be used together.
37+
38+
\b
39+
Example:
40+
# List Ubuntu OSes from the os category of the Bare Metal package
41+
slcli order item-list BARE_METAL_SERVER --category os --keyword ubuntu
42+
43+
"""
44+
table = formatting.Table(COLUMNS)
45+
manager = ordering.OrderingManager(env.client)
46+
47+
_filter = {'items': {}}
48+
if keyword:
49+
_filter['items']['description'] = {'operation': '*= %s' % keyword}
50+
if category:
51+
_filter['items']['categories'] = {'categoryCode': {'operation': '_= %s' % category}}
52+
53+
items = manager.list_items(package_keyname, filter=_filter)
54+
55+
for item in items:
56+
table.add_row([
57+
item['keyName'],
58+
item['description'],
59+
])
60+
env.fout(table)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"""List packages."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
from SoftLayer.managers import ordering
9+
10+
COLUMNS = ['name',
11+
'keyName', ]
12+
13+
14+
@click.command()
15+
@click.option('--keyword',
16+
help="A word (or string) used to filter package names.")
17+
@environment.pass_env
18+
def cli(env, keyword):
19+
"""List packages that can be ordered via the placeOrder API.
20+
21+
\b
22+
Example:
23+
# List out all packages for ordering
24+
slcli order package-list
25+
26+
27+
Keywords can also be used for some simple filtering functionality
28+
to help find a package easier.
29+
30+
\b
31+
Example:
32+
# List out all packages with "server" in the name
33+
slcli order package-list --keyword server
34+
35+
"""
36+
manager = ordering.OrderingManager(env.client)
37+
table = formatting.Table(COLUMNS)
38+
39+
_filter = {}
40+
if keyword:
41+
_filter = {'name': {'operation': '*= %s' % keyword}}
42+
43+
packages = manager.list_packages(filter=_filter)
44+
45+
for package in packages:
46+
table.add_row([
47+
package['name'],
48+
package['keyName'],
49+
])
50+
env.fout(table)

SoftLayer/CLI/order/place.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
"""Verify or place an order."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import json
5+
6+
import click
7+
8+
from SoftLayer.CLI import environment
9+
from SoftLayer.CLI import exceptions
10+
from SoftLayer.CLI import formatting
11+
from SoftLayer.managers import ordering
12+
13+
COLUMNS = ['keyName',
14+
'description',
15+
'cost', ]
16+
17+
18+
@click.command()
19+
@click.argument('package_keyname')
20+
@click.argument('location')
21+
@click.option('--preset',
22+
help="The order preset (if required by the package)")
23+
@click.option('--verify',
24+
is_flag=True,
25+
help="Flag denoting whether or not to only verify the order, not place it")
26+
@click.option('--billing',
27+
type=click.Choice(['hourly', 'monthly']),
28+
default='hourly',
29+
show_default=True,
30+
help="Billing rate")
31+
@click.option('--complex-type', help=("The complex type of the order. This typically begins"
32+
" with 'SoftLayer_Container_Product_Order_'."))
33+
@click.option('--extras',
34+
help="JSON string denoting extra data that needs to be sent with the order")
35+
@click.argument('order_items', nargs=-1)
36+
@environment.pass_env
37+
def cli(env, package_keyname, location, preset, verify, billing, complex_type,
38+
extras, order_items):
39+
"""Place or verify an order.
40+
41+
This CLI command is used for placing/verifying an order of the specified package in
42+
the given location (denoted by a datacenter's long name). Orders made via the CLI
43+
can then be converted to be made programmatically by calling
44+
SoftLayer.OrderingManager.place_order() with the same keynames.
45+
46+
Packages for ordering can be retrived from `slcli order package-list`
47+
Presets for ordering can be retrieved from `slcli order preset-list` (not all packages
48+
have presets)
49+
50+
Items can be retrieved from `slcli order item-list`. In order to find required
51+
items for the order, use `slcli order category-list`, and then provide the
52+
--category option for each category code in `slcli order item-list`.
53+
54+
\b
55+
Example:
56+
# Order an hourly VSI with 4 CPU, 16 GB RAM, 100 GB SAN disk,
57+
# Ubuntu 16.04, and 1 Gbps public & private uplink in dal13
58+
slcli order place --billing hourly CLOUD_SERVER DALLAS13 \\
59+
GUEST_CORES_4 \\
60+
RAM_16_GB \\
61+
REBOOT_REMOTE_CONSOLE \\
62+
1_GBPS_PUBLIC_PRIVATE_NETWORK_UPLINKS \\
63+
BANDWIDTH_0_GB_2 \\
64+
1_IP_ADDRESS \\
65+
GUEST_DISK_100_GB_SAN \\
66+
OS_UBUNTU_16_04_LTS_XENIAL_XERUS_MINIMAL_64_BIT_FOR_VSI \\
67+
MONITORING_HOST_PING \\
68+
NOTIFICATION_EMAIL_AND_TICKET \\
69+
AUTOMATED_NOTIFICATION \\
70+
UNLIMITED_SSL_VPN_USERS_1_PPTP_VPN_USER_PER_ACCOUNT \\
71+
NESSUS_VULNERABILITY_ASSESSMENT_REPORTING \\
72+
--extras '{"virtualGuests": [{"hostname": "test", "domain": "softlayer.com"}]}' \\
73+
--complex-type SoftLayer_Container_Product_Order_Virtual_Guest
74+
75+
"""
76+
manager = ordering.OrderingManager(env.client)
77+
78+
if extras:
79+
extras = json.loads(extras)
80+
81+
args = (package_keyname, location, order_items)
82+
kwargs = {'preset_keyname': preset,
83+
'extras': extras,
84+
'quantity': 1,
85+
'complex_type': complex_type,
86+
'hourly': True if billing == 'hourly' else False}
87+
88+
if verify:
89+
table = formatting.Table(COLUMNS)
90+
order_to_place = manager.verify_order(*args, **kwargs)
91+
for price in order_to_place['prices']:
92+
cost_key = 'hourlyRecurringFee' if billing == 'hourly' else 'recurringFee'
93+
table.add_row([
94+
price['item']['keyName'],
95+
price['item']['description'],
96+
price[cost_key] if cost_key in price else formatting.blank()
97+
])
98+
99+
else:
100+
if not (env.skip_confirmations or formatting.confirm(
101+
"This action will incur charges on your account. Continue?")):
102+
raise exceptions.CLIAbort("Aborting order.")
103+
104+
order = manager.place_order(*args, **kwargs)
105+
106+
table = formatting.KeyValueTable(['name', 'value'])
107+
table.align['name'] = 'r'
108+
table.align['value'] = 'l'
109+
table.add_row(['id', order['orderId']])
110+
table.add_row(['created', order['orderDate']])
111+
table.add_row(['status', order['placedOrder']['status']])
112+
env.fout(table)

SoftLayer/CLI/order/preset_list.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""List package presets."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
from SoftLayer.CLI import environment
7+
from SoftLayer.CLI import formatting
8+
from SoftLayer.managers import ordering
9+
10+
COLUMNS = ['name',
11+
'keyName',
12+
'description', ]
13+
14+
15+
@click.command()
16+
@click.argument('package_keyname')
17+
@click.option('--keyword',
18+
help="A word (or string) used to filter preset names.")
19+
@environment.pass_env
20+
def cli(env, package_keyname, keyword):
21+
"""List package presets.
22+
23+
Package keynames can be retrieved from `slcli order package-list`.
24+
Some packages do not have presets.
25+
26+
\b
27+
Example:
28+
# List the presets for Bare Metal servers
29+
slcli order preset-list BARE_METAL_SERVER
30+
31+
The --keyword option can also be used for additional filtering on
32+
the returned presets.
33+
34+
\b
35+
Example:
36+
# List the Bare Metal server presets that include a GPU
37+
slcli order preset-list BARE_METAL_SERVER --keyword gpu
38+
39+
"""
40+
table = formatting.Table(COLUMNS)
41+
manager = ordering.OrderingManager(env.client)
42+
43+
_filter = {}
44+
if keyword:
45+
_filter = {'activePresets': {'name': {'operation': '*= %s' % keyword}}}
46+
presets = manager.list_presets(package_keyname, filter=_filter)
47+
48+
for preset in presets:
49+
table.add_row([
50+
preset['name'],
51+
preset['keyName'],
52+
preset['description']
53+
])
54+
env.fout(table)

SoftLayer/CLI/routes.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,13 @@
203203
('object-storage:endpoints',
204204
'SoftLayer.CLI.object_storage.list_endpoints:cli'),
205205

206+
('order', 'SoftLayer.CLI.order'),
207+
('order:category-list', 'SoftLayer.CLI.order.category_list:cli'),
208+
('order:item-list', 'SoftLayer.CLI.order.item_list:cli'),
209+
('order:package-list', 'SoftLayer.CLI.order.package_list:cli'),
210+
('order:place', 'SoftLayer.CLI.order.place:cli'),
211+
('order:preset-list', 'SoftLayer.CLI.order.preset_list:cli'),
212+
206213
('rwhois', 'SoftLayer.CLI.rwhois'),
207214
('rwhois:edit', 'SoftLayer.CLI.rwhois.edit:cli'),
208215
('rwhois:show', 'SoftLayer.CLI.rwhois.show:cli'),

0 commit comments

Comments
 (0)