Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SoftLayer/CLI/order/place.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def cli(env, package_keyname, location, preset, verify, billing, complex_type,
can then be converted to be made programmatically by calling
SoftLayer.OrderingManager.place_order() with the same keynames.

Packages for ordering can be retrived from `slcli order package-list`
Packages for ordering can be retrieved from `slcli order package-list`
Presets for ordering can be retrieved from `slcli order preset-list` (not all packages
have presets)

Expand Down
91 changes: 91 additions & 0 deletions SoftLayer/CLI/order/place_quote.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""Place quote"""
# :license: MIT, see LICENSE for more details.

import json

import click

from SoftLayer.CLI import environment
from SoftLayer.CLI import formatting
from SoftLayer.managers import ordering


@click.command()
@click.argument('package_keyname')
@click.argument('location')
@click.option('--preset',
help="The order preset (if required by the package)")
@click.option('--name',
help="A custom name to be assigned to the quote (optional)")
@click.option('--send-email',
is_flag=True,
help="The quote will be sent to the email address associated.")
@click.option('--complex-type', help=("The complex type of the order. This typically begins"
" with 'SoftLayer_Container_Product_Order_'."))
@click.option('--extras',
help="JSON string denoting extra data that needs to be sent with the order")
@click.argument('order_items', nargs=-1)
@environment.pass_env
def cli(env, package_keyname, location, preset, name, send_email, complex_type,
extras, order_items):
"""Place a quote.

This CLI command is used for placing a quote of the specified package in
the given location (denoted by a datacenter's long name). Orders made via the CLI
can then be converted to be made programmatically by calling
SoftLayer.OrderingManager.place_quote() with the same keynames.

Packages for ordering can be retrieved from `slcli order package-list`
Presets for ordering can be retrieved from `slcli order preset-list` (not all packages
have presets)

Items can be retrieved from `slcli order item-list`. In order to find required
items for the order, use `slcli order category-list`, and then provide the
--category option for each category code in `slcli order item-list`.

\b
Example:
# Place quote a VSI with 4 CPU, 16 GB RAM, 100 GB SAN disk,
# Ubuntu 16.04, and 1 Gbps public & private uplink in dal13
slcli order place-quote --name "foobar" --send-email CLOUD_SERVER DALLAS13 \\
GUEST_CORES_4 \\
RAM_16_GB \\
REBOOT_REMOTE_CONSOLE \\
1_GBPS_PUBLIC_PRIVATE_NETWORK_UPLINKS \\
BANDWIDTH_0_GB_2 \\
1_IP_ADDRESS \\
GUEST_DISK_100_GB_SAN \\
OS_UBUNTU_16_04_LTS_XENIAL_XERUS_MINIMAL_64_BIT_FOR_VSI \\
MONITORING_HOST_PING \\
NOTIFICATION_EMAIL_AND_TICKET \\
AUTOMATED_NOTIFICATION \\
UNLIMITED_SSL_VPN_USERS_1_PPTP_VPN_USER_PER_ACCOUNT \\
NESSUS_VULNERABILITY_ASSESSMENT_REPORTING \\
--extras '{"virtualGuests": [{"hostname": "test", "domain": "softlayer.com"}]}' \\
--complex-type SoftLayer_Container_Product_Order_Virtual_Guest

"""
manager = ordering.OrderingManager(env.client)

if extras:
extras = json.loads(extras)

args = (package_keyname, location, order_items)
kwargs = {'preset_keyname': preset,
'extras': extras,
'quantity': 1,
'quote_name': name,
'send_email': send_email,
'complex_type': complex_type}

order = manager.place_quote(*args, **kwargs)

table = formatting.KeyValueTable(['name', 'value'])
table.align['name'] = 'r'
table.align['value'] = 'l'
table.add_row(['id', order['quote']['id']])
table.add_row(['name', order['quote']['name']])
table.add_row(['created', order['orderDate']])
table.add_row(['expires', order['quote']['expirationDate']])
table.add_row(['status', order['quote']['status']])
env.fout(table)
1 change: 1 addition & 0 deletions SoftLayer/CLI/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@
('order:place', 'SoftLayer.CLI.order.place:cli'),
('order:preset-list', 'SoftLayer.CLI.order.preset_list:cli'),
('order:package-locations', 'SoftLayer.CLI.order.package_locations:cli'),
('order:place-quote', 'SoftLayer.CLI.order.place_quote:cli'),

('rwhois', 'SoftLayer.CLI.rwhois'),
('rwhois:edit', 'SoftLayer.CLI.rwhois.edit:cli'),
Expand Down
34 changes: 34 additions & 0 deletions SoftLayer/managers/ordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,40 @@ def place_order(self, package_keyname, location, item_keynames, complex_type=Non
extras=extras, quantity=quantity)
return self.order_svc.placeOrder(order)

def place_quote(self, package_keyname, location, item_keynames, complex_type=None,
preset_keyname=None, extras=None, quantity=1, quote_name=None, send_email=False):

"""Place a quote with the given package and prices.

This function takes in parameters needed for an order and places the quote.

:param str package_keyname: The keyname for the package being ordered
:param str location: The datacenter location string for ordering (Ex: DALLAS13)
:param list item_keynames: The list of item keyname strings to order. To see list of
possible keynames for a package, use list_items()
(or `slcli order item-list`)
:param str complex_type: The complex type to send with the order. Typically begins
with `SoftLayer_Container_Product_Order_`.
:param string preset_keyname: If needed, specifies a preset to use for that package.
To see a list of possible keynames for a package, use
list_preset() (or `slcli order preset-list`)
:param dict extras: The extra data for the order in dictionary format.
Example: A VSI order requires hostname and domain to be set, so
extras will look like the following:
{'virtualGuests': [{'hostname': 'test', domain': 'softlayer.com'}]}
:param int quantity: The number of resources to order
:param string quote_name: A custom name to be assigned to the quote (optional).
:param bool send_email: This flag indicates that the quote should be sent to the email
address associated with the account or order.
"""
order = self.generate_order(package_keyname, location, item_keynames, complex_type=complex_type,
hourly=False, preset_keyname=preset_keyname, extras=extras, quantity=quantity)

order['quoteName'] = quote_name
order['sendQuoteEmailFlag'] = send_email

return self.order_svc.placeQuote(order)

def generate_order(self, package_keyname, location, item_keynames, complex_type=None,
hourly=True, preset_keyname=None, extras=None, quantity=1):
"""Generates an order with the given package and prices.
Expand Down
29 changes: 29 additions & 0 deletions tests/CLI/modules/order_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,35 @@ def test_place(self):
'status': 'APPROVED'},
json.loads(result.output))

def test_place_quote(self):
order_date = '2018-04-04 07:39:20'
expiration_date = '2018-05-04 07:39:20'
quote_name = 'foobar'
order = {'orderDate': order_date,
'quote': {
'id': 1234,
'name': quote_name,
'expirationDate': expiration_date,
'status': 'PENDING'
}}
place_quote_mock = self.set_mock('SoftLayer_Product_Order', 'placeQuote')
items_mock = self.set_mock('SoftLayer_Product_Package', 'getItems')

place_quote_mock.return_value = order
items_mock.return_value = self._get_order_items()

result = self.run_command(['order', 'place-quote', '--name', 'foobar', 'package', 'DALLAS13',
'ITEM1', '--complex-type', 'SoftLayer_Container_Product_Order_Thing'])

self.assert_no_fail(result)
self.assert_called_with('SoftLayer_Product_Order', 'placeQuote')
self.assertEqual({'id': 1234,
'name': quote_name,
'created': order_date,
'expires': expiration_date,
'status': 'PENDING'},
json.loads(result.output))

def test_verify_hourly(self):
order_date = '2017-04-04 07:39:20'
order = {'orderId': 1234, 'orderDate': order_date,
Expand Down
27 changes: 27 additions & 0 deletions tests/managers/ordering_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,33 @@ def test_place_order(self):
extras=extras, quantity=quantity)
self.assertEqual(ord_mock.return_value, order)

def test_place_quote(self):
ord_mock = self.set_mock('SoftLayer_Product_Order', 'placeQuote')
ord_mock.return_value = {'id': 1234}
pkg = 'PACKAGE_KEYNAME'
location = 'DALLAS13'
items = ['ITEM1', 'ITEM2']
hourly = False
preset_keyname = 'PRESET'
complex_type = 'Complex_Type'
extras = {'foo': 'bar'}
quantity = 1
name = 'wombat'
send_email = True

with mock.patch.object(self.ordering, 'generate_order') as gen_mock:
gen_mock.return_value = {'order': {}}

order = self.ordering.place_quote(pkg, location, items, preset_keyname=preset_keyname,
complex_type=complex_type, extras=extras, quantity=quantity,
quote_name=name, send_email=send_email)

gen_mock.assert_called_once_with(pkg, location, items, hourly=hourly,
preset_keyname=preset_keyname,
complex_type=complex_type,
extras=extras, quantity=quantity)
self.assertEqual(ord_mock.return_value, order)

def test_locations(self):
locations = self.ordering.package_locations('BARE_METAL_CPU')
self.assertEqual('WASHINGTON07', locations[0]['keyname'])
Expand Down