Skip to content

Commit 1d65b44

Browse files
Merge pull request #1023 from acamacho82/Issue1020
Adding slcli order place-quote feature
2 parents 922ae56 + 93c4036 commit 1d65b44

File tree

6 files changed

+183
-1
lines changed

6 files changed

+183
-1
lines changed

SoftLayer/CLI/order/place.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def cli(env, package_keyname, location, preset, verify, billing, complex_type,
4343
can then be converted to be made programmatically by calling
4444
SoftLayer.OrderingManager.place_order() with the same keynames.
4545
46-
Packages for ordering can be retrived from `slcli order package-list`
46+
Packages for ordering can be retrieved from `slcli order package-list`
4747
Presets for ordering can be retrieved from `slcli order preset-list` (not all packages
4848
have presets)
4949

SoftLayer/CLI/order/place_quote.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""Place quote"""
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 formatting
10+
from SoftLayer.managers import ordering
11+
12+
13+
@click.command()
14+
@click.argument('package_keyname')
15+
@click.argument('location')
16+
@click.option('--preset',
17+
help="The order preset (if required by the package)")
18+
@click.option('--name',
19+
help="A custom name to be assigned to the quote (optional)")
20+
@click.option('--send-email',
21+
is_flag=True,
22+
help="The quote will be sent to the email address associated.")
23+
@click.option('--complex-type', help=("The complex type of the order. This typically begins"
24+
" with 'SoftLayer_Container_Product_Order_'."))
25+
@click.option('--extras',
26+
help="JSON string denoting extra data that needs to be sent with the order")
27+
@click.argument('order_items', nargs=-1)
28+
@environment.pass_env
29+
def cli(env, package_keyname, location, preset, name, send_email, complex_type,
30+
extras, order_items):
31+
"""Place a quote.
32+
33+
This CLI command is used for placing a quote of the specified package in
34+
the given location (denoted by a datacenter's long name). Orders made via the CLI
35+
can then be converted to be made programmatically by calling
36+
SoftLayer.OrderingManager.place_quote() with the same keynames.
37+
38+
Packages for ordering can be retrieved from `slcli order package-list`
39+
Presets for ordering can be retrieved from `slcli order preset-list` (not all packages
40+
have presets)
41+
42+
Items can be retrieved from `slcli order item-list`. In order to find required
43+
items for the order, use `slcli order category-list`, and then provide the
44+
--category option for each category code in `slcli order item-list`.
45+
46+
\b
47+
Example:
48+
# Place quote a VSI with 4 CPU, 16 GB RAM, 100 GB SAN disk,
49+
# Ubuntu 16.04, and 1 Gbps public & private uplink in dal13
50+
slcli order place-quote --name "foobar" --send-email CLOUD_SERVER DALLAS13 \\
51+
GUEST_CORES_4 \\
52+
RAM_16_GB \\
53+
REBOOT_REMOTE_CONSOLE \\
54+
1_GBPS_PUBLIC_PRIVATE_NETWORK_UPLINKS \\
55+
BANDWIDTH_0_GB_2 \\
56+
1_IP_ADDRESS \\
57+
GUEST_DISK_100_GB_SAN \\
58+
OS_UBUNTU_16_04_LTS_XENIAL_XERUS_MINIMAL_64_BIT_FOR_VSI \\
59+
MONITORING_HOST_PING \\
60+
NOTIFICATION_EMAIL_AND_TICKET \\
61+
AUTOMATED_NOTIFICATION \\
62+
UNLIMITED_SSL_VPN_USERS_1_PPTP_VPN_USER_PER_ACCOUNT \\
63+
NESSUS_VULNERABILITY_ASSESSMENT_REPORTING \\
64+
--extras '{"virtualGuests": [{"hostname": "test", "domain": "softlayer.com"}]}' \\
65+
--complex-type SoftLayer_Container_Product_Order_Virtual_Guest
66+
67+
"""
68+
manager = ordering.OrderingManager(env.client)
69+
70+
if extras:
71+
extras = json.loads(extras)
72+
73+
args = (package_keyname, location, order_items)
74+
kwargs = {'preset_keyname': preset,
75+
'extras': extras,
76+
'quantity': 1,
77+
'quote_name': name,
78+
'send_email': send_email,
79+
'complex_type': complex_type}
80+
81+
order = manager.place_quote(*args, **kwargs)
82+
83+
table = formatting.KeyValueTable(['name', 'value'])
84+
table.align['name'] = 'r'
85+
table.align['value'] = 'l'
86+
table.add_row(['id', order['quote']['id']])
87+
table.add_row(['name', order['quote']['name']])
88+
table.add_row(['created', order['orderDate']])
89+
table.add_row(['expires', order['quote']['expirationDate']])
90+
table.add_row(['status', order['quote']['status']])
91+
env.fout(table)

SoftLayer/CLI/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@
210210
('order:place', 'SoftLayer.CLI.order.place:cli'),
211211
('order:preset-list', 'SoftLayer.CLI.order.preset_list:cli'),
212212
('order:package-locations', 'SoftLayer.CLI.order.package_locations:cli'),
213+
('order:place-quote', 'SoftLayer.CLI.order.place_quote:cli'),
213214

214215
('rwhois', 'SoftLayer.CLI.rwhois'),
215216
('rwhois:edit', 'SoftLayer.CLI.rwhois.edit:cli'),

SoftLayer/managers/ordering.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,40 @@ def place_order(self, package_keyname, location, item_keynames, complex_type=Non
430430
extras=extras, quantity=quantity)
431431
return self.order_svc.placeOrder(order)
432432

433+
def place_quote(self, package_keyname, location, item_keynames, complex_type=None,
434+
preset_keyname=None, extras=None, quantity=1, quote_name=None, send_email=False):
435+
436+
"""Place a quote with the given package and prices.
437+
438+
This function takes in parameters needed for an order and places the quote.
439+
440+
:param str package_keyname: The keyname for the package being ordered
441+
:param str location: The datacenter location string for ordering (Ex: DALLAS13)
442+
:param list item_keynames: The list of item keyname strings to order. To see list of
443+
possible keynames for a package, use list_items()
444+
(or `slcli order item-list`)
445+
:param str complex_type: The complex type to send with the order. Typically begins
446+
with `SoftLayer_Container_Product_Order_`.
447+
:param string preset_keyname: If needed, specifies a preset to use for that package.
448+
To see a list of possible keynames for a package, use
449+
list_preset() (or `slcli order preset-list`)
450+
:param dict extras: The extra data for the order in dictionary format.
451+
Example: A VSI order requires hostname and domain to be set, so
452+
extras will look like the following:
453+
{'virtualGuests': [{'hostname': 'test', domain': 'softlayer.com'}]}
454+
:param int quantity: The number of resources to order
455+
:param string quote_name: A custom name to be assigned to the quote (optional).
456+
:param bool send_email: This flag indicates that the quote should be sent to the email
457+
address associated with the account or order.
458+
"""
459+
order = self.generate_order(package_keyname, location, item_keynames, complex_type=complex_type,
460+
hourly=False, preset_keyname=preset_keyname, extras=extras, quantity=quantity)
461+
462+
order['quoteName'] = quote_name
463+
order['sendQuoteEmailFlag'] = send_email
464+
465+
return self.order_svc.placeQuote(order)
466+
433467
def generate_order(self, package_keyname, location, item_keynames, complex_type=None,
434468
hourly=True, preset_keyname=None, extras=None, quantity=1):
435469
"""Generates an order with the given package and prices.

tests/CLI/modules/order_tests.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,35 @@ def test_place(self):
114114
'status': 'APPROVED'},
115115
json.loads(result.output))
116116

117+
def test_place_quote(self):
118+
order_date = '2018-04-04 07:39:20'
119+
expiration_date = '2018-05-04 07:39:20'
120+
quote_name = 'foobar'
121+
order = {'orderDate': order_date,
122+
'quote': {
123+
'id': 1234,
124+
'name': quote_name,
125+
'expirationDate': expiration_date,
126+
'status': 'PENDING'
127+
}}
128+
place_quote_mock = self.set_mock('SoftLayer_Product_Order', 'placeQuote')
129+
items_mock = self.set_mock('SoftLayer_Product_Package', 'getItems')
130+
131+
place_quote_mock.return_value = order
132+
items_mock.return_value = self._get_order_items()
133+
134+
result = self.run_command(['order', 'place-quote', '--name', 'foobar', 'package', 'DALLAS13',
135+
'ITEM1', '--complex-type', 'SoftLayer_Container_Product_Order_Thing'])
136+
137+
self.assert_no_fail(result)
138+
self.assert_called_with('SoftLayer_Product_Order', 'placeQuote')
139+
self.assertEqual({'id': 1234,
140+
'name': quote_name,
141+
'created': order_date,
142+
'expires': expiration_date,
143+
'status': 'PENDING'},
144+
json.loads(result.output))
145+
117146
def test_verify_hourly(self):
118147
order_date = '2017-04-04 07:39:20'
119148
order = {'orderId': 1234, 'orderDate': order_date,

tests/managers/ordering_tests.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,33 @@ def test_place_order(self):
431431
extras=extras, quantity=quantity)
432432
self.assertEqual(ord_mock.return_value, order)
433433

434+
def test_place_quote(self):
435+
ord_mock = self.set_mock('SoftLayer_Product_Order', 'placeQuote')
436+
ord_mock.return_value = {'id': 1234}
437+
pkg = 'PACKAGE_KEYNAME'
438+
location = 'DALLAS13'
439+
items = ['ITEM1', 'ITEM2']
440+
hourly = False
441+
preset_keyname = 'PRESET'
442+
complex_type = 'Complex_Type'
443+
extras = {'foo': 'bar'}
444+
quantity = 1
445+
name = 'wombat'
446+
send_email = True
447+
448+
with mock.patch.object(self.ordering, 'generate_order') as gen_mock:
449+
gen_mock.return_value = {'order': {}}
450+
451+
order = self.ordering.place_quote(pkg, location, items, preset_keyname=preset_keyname,
452+
complex_type=complex_type, extras=extras, quantity=quantity,
453+
quote_name=name, send_email=send_email)
454+
455+
gen_mock.assert_called_once_with(pkg, location, items, hourly=hourly,
456+
preset_keyname=preset_keyname,
457+
complex_type=complex_type,
458+
extras=extras, quantity=quantity)
459+
self.assertEqual(ord_mock.return_value, order)
460+
434461
def test_locations(self):
435462
locations = self.ordering.package_locations('BARE_METAL_CPU')
436463
self.assertEqual('WASHINGTON07', locations[0]['keyname'])

0 commit comments

Comments
 (0)