diff --git a/SoftLayer/CLI/dedicatedhost/__init__.py b/SoftLayer/CLI/dedicatedhost/__init__.py new file mode 100644 index 000000000..55d5d799a --- /dev/null +++ b/SoftLayer/CLI/dedicatedhost/__init__.py @@ -0,0 +1,2 @@ +"""Dedicated Host.""" +# :license: MIT, see LICENSE for more details. diff --git a/SoftLayer/CLI/dedicatedhost/create.py b/SoftLayer/CLI/dedicatedhost/create.py new file mode 100644 index 000000000..491da2110 --- /dev/null +++ b/SoftLayer/CLI/dedicatedhost/create.py @@ -0,0 +1,114 @@ +"""Order/create a dedicated Host.""" +# :license: MIT, see LICENSE for more details. + +import click + +import SoftLayer +from SoftLayer.CLI import environment +from SoftLayer.CLI import exceptions +from SoftLayer.CLI import formatting +from SoftLayer.CLI import template + + +@click.command( + epilog="See 'slcli dedicatedhost create-options' for valid options.") +@click.option('--hostname', '-H', + help="Host portion of the FQDN", + required=True, + prompt=True) +@click.option('--router', '-r', + help="Router hostname ex. fcr02a.dal13", + show_default=True) +@click.option('--domain', '-D', + help="Domain portion of the FQDN", + required=True, + prompt=True) +@click.option('--datacenter', '-d', help="Datacenter shortname", + required=True, + prompt=True) +@click.option('--flavor', '-f', help="Dedicated Virtual Host flavor", + required=True, + prompt=True) +@click.option('--billing', + type=click.Choice(['hourly', 'monthly']), + default='hourly', + show_default=True, + help="Billing rate") +@click.option('--verify', + is_flag=True, + help="Verify dedicatedhost without creating it.") +@click.option('--template', '-t', + is_eager=True, + callback=template.TemplateCallback(list_args=['key']), + help="A template file that defaults the command-line options", + type=click.Path(exists=True, readable=True, resolve_path=True)) +@click.option('--export', + type=click.Path(writable=True, resolve_path=True), + help="Exports options to a template file") +@environment.pass_env +def cli(env, **kwargs): + """Order/create a dedicated host.""" + mgr = SoftLayer.DedicatedHostManager(env.client) + + order = { + 'hostname': kwargs['hostname'], + 'domain': kwargs['domain'], + 'flavor': kwargs['flavor'], + 'location': kwargs['datacenter'], + 'hourly': kwargs.get('billing') == 'hourly', + } + + if kwargs['router']: + order['router'] = kwargs['router'] + + do_create = not (kwargs['export'] or kwargs['verify']) + + output = None + + result = mgr.verify_order(**order) + table = formatting.Table(['Item', 'cost']) + table.align['Item'] = 'r' + table.align['cost'] = 'r' + if len(result['prices']) != 1: + raise exceptions.ArgumentError("More than 1 price was found or no " + "prices found") + price = result['prices'] + if order['hourly']: + total = float(price[0].get('hourlyRecurringFee', 0.0)) + else: + total = float(price[0].get('recurringFee', 0.0)) + + if order['hourly']: + table.add_row(['Total hourly cost', "%.2f" % total]) + else: + table.add_row(['Total monthly cost', "%.2f" % total]) + + output = [] + output.append(table) + output.append(formatting.FormattedItem( + '', + ' -- ! Prices reflected here are retail and do not ' + 'take account level discounts and are not guaranteed.')) + + if kwargs['export']: + export_file = kwargs.pop('export') + template.export_to_template(export_file, kwargs, + exclude=['wait', 'verify']) + env.fout('Successfully exported options to a template file.') + + if do_create: + if not env.skip_confirmations and not formatting.confirm( + "This action will incur charges on your account. " + "Continue?"): + raise exceptions.CLIAbort('Aborting dedicated host order.') + + result = mgr.place_order(**order) + + table = formatting.KeyValueTable(['name', 'value']) + table.align['name'] = 'r' + table.align['value'] = 'l' + table.add_row(['id', result['orderId']]) + table.add_row(['created', result['orderDate']]) + output.append(table) + + env.fout(output) diff --git a/SoftLayer/CLI/dedicatedhost/create_options.py b/SoftLayer/CLI/dedicatedhost/create_options.py new file mode 100644 index 000000000..94727ce68 --- /dev/null +++ b/SoftLayer/CLI/dedicatedhost/create_options.py @@ -0,0 +1,61 @@ +"""Options for ordering a dedicated host""" +# :license: MIT, see LICENSE for more details. + +import click +import SoftLayer + +from SoftLayer.CLI import environment +from SoftLayer.CLI import exceptions +from SoftLayer.CLI import formatting + + +@click.command() +@click.option('--datacenter', '-d', + help="Router hostname (requires --flavor) " + "ex. ams01", + show_default=True) +@click.option('--flavor', '-f', + help="Dedicated Virtual Host flavor (requires --datacenter)" + " ex. 56_CORES_X_242_RAM_X_1_4_TB", + show_default=True) +@environment.pass_env +def cli(env, **kwargs): + """host order options for a given dedicated host. + + To get a list of available backend routers see example: + slcli dh create-options --datacenter dal05 --flavor 56_CORES_X_242_RAM_X_1_4_TB + """ + + mgr = SoftLayer.DedicatedHostManager(env.client) + tables = [] + + if not kwargs['flavor'] and not kwargs['datacenter']: + options = mgr.get_create_options() + + # Datacenters + dc_table = formatting.Table(['datacenter', 'value']) + dc_table.sortby = 'value' + for location in options['locations']: + dc_table.add_row([location['name'], location['key']]) + tables.append(dc_table) + + dh_table = formatting.Table(['Dedicated Virtual Host Flavor(s)', 'value']) + dh_table.sortby = 'value' + for item in options['dedicated_host']: + dh_table.add_row([item['name'], item['key']]) + tables.append(dh_table) + else: + if kwargs['flavor'] is None or kwargs['datacenter'] is None: + raise exceptions.ArgumentError('Both a flavor and datacenter need ' + 'to be passed as arguments ' + 'ex. slcli dh create-options -d ' + 'ams01 -f ' + '56_CORES_X_242_RAM_X_1_4_TB') + router_opt = mgr.get_router_options(kwargs['datacenter'], kwargs['flavor']) + br_table = formatting.Table( + ['Available Backend Routers']) + for router in router_opt: + br_table.add_row([router['hostname']]) + tables.append(br_table) + + env.fout(formatting.listing(tables, separator='\n')) diff --git a/SoftLayer/CLI/dedicatedhost/detail.py b/SoftLayer/CLI/dedicatedhost/detail.py new file mode 100644 index 000000000..e1c46b962 --- /dev/null +++ b/SoftLayer/CLI/dedicatedhost/detail.py @@ -0,0 +1,65 @@ +"""Get details for a dedicated host.""" +# :license: MIT, see LICENSE for more details. + +import logging + +import click + +import SoftLayer +from SoftLayer.CLI import environment +from SoftLayer.CLI import formatting +from SoftLayer import utils + +LOGGER = logging.getLogger(__name__) + + +@click.command() +@click.argument('identifier') +@click.option('--price', is_flag=True, help='Show associated prices') +@click.option('--guests', is_flag=True, help='Show guests on dedicated host') +@environment.pass_env +def cli(env, identifier, price=False, guests=False): + """Get details for a virtual server.""" + dhost = SoftLayer.DedicatedHostManager(env.client) + + table = formatting.KeyValueTable(['name', 'value']) + table.align['name'] = 'r' + table.align['value'] = 'l' + + result = dhost.get_host(identifier) + result = utils.NestedDict(result) + + table.add_row(['id', result['id']]) + table.add_row(['name', result['name']]) + table.add_row(['cpu count', result['cpuCount']]) + table.add_row(['memory capacity', result['memoryCapacity']]) + table.add_row(['disk capacity', result['diskCapacity']]) + table.add_row(['create date', result['createDate']]) + table.add_row(['modify date', result['modifyDate']]) + table.add_row(['router id', result['backendRouter']['id']]) + table.add_row(['router hostname', result['backendRouter']['hostname']]) + table.add_row(['owner', formatting.FormattedItem( + utils.lookup(result, 'billingItem', 'orderItem', 'order', 'userRecord', 'username') or formatting.blank(),)]) + + if price: + total_price = utils.lookup(result, + 'billingItem', + 'nextInvoiceTotalRecurringAmount') or 0 + total_price += sum(p['nextInvoiceTotalRecurringAmount'] + for p + in utils.lookup(result, + 'billingItem', + 'children') or []) + table.add_row(['price_rate', total_price]) + + table.add_row(['guest count', result['guestCount']]) + if guests: + guest_table = formatting.Table(['id', 'hostname', 'domain', 'uuid']) + for guest in result['guests']: + guest_table.add_row([ + guest['id'], guest['hostname'], guest['domain'], guest['uuid']]) + table.add_row(['guests', guest_table]) + + table.add_row(['datacenter', result['datacenter']['name']]) + + env.fout(table) diff --git a/SoftLayer/CLI/dedicatedhost/list.py b/SoftLayer/CLI/dedicatedhost/list.py new file mode 100644 index 000000000..56feefd9a --- /dev/null +++ b/SoftLayer/CLI/dedicatedhost/list.py @@ -0,0 +1,70 @@ +"""List dedicated servers.""" +# :license: MIT, see LICENSE for more details. + +import click + +import SoftLayer +from SoftLayer.CLI import columns as column_helper +from SoftLayer.CLI import environment +from SoftLayer.CLI import formatting +from SoftLayer.CLI import helpers + +COLUMNS = [ + column_helper.Column('datacenter', ('datacenter', 'name')), + column_helper.Column( + 'created_by', + ('billingItem', 'orderItem', 'order', 'userRecord', 'username')), + column_helper.Column( + 'tags', + lambda server: formatting.tags(server.get('tagReferences')), + mask="tagReferences.tag.name"), +] + +DEFAULT_COLUMNS = [ + 'id', + 'name', + 'cpuCount', + 'diskCapacity', + 'memoryCapacity', + 'datacenter', + 'guestCount', +] + + +@click.command() +@click.option('--cpu', '-c', help='Number of CPU cores', type=click.INT) +@helpers.multi_option('--tag', help='Filter by tags') +@click.option('--sortby', help='Column to sort by', + default='name', + show_default=True) +@click.option('--columns', + callback=column_helper.get_formatter(COLUMNS), + help='Columns to display. [options: %s]' + % ', '.join(column.name for column in COLUMNS), + default=','.join(DEFAULT_COLUMNS), + show_default=True) +@click.option('--datacenter', '-d', help='Datacenter shortname') +@click.option('--name', '-H', help='Host portion of the FQDN') +@click.option('--memory', '-m', help='Memory capacity in mebibytes', + type=click.INT) +@click.option('--disk', '-D', help='Disk capacity') +@environment.pass_env +def cli(env, sortby, cpu, columns, datacenter, name, memory, disk, tag): + """List dedicated host.""" + mgr = SoftLayer.DedicatedHostManager(env.client) + hosts = mgr.list_instances(cpus=cpu, + datacenter=datacenter, + hostname=name, + memory=memory, + disk=disk, + tags=tag, + mask=columns.mask()) + + table = formatting.Table(columns.columns) + table.sortby = sortby + + for host in hosts: + table.add_row([value or formatting.blank() + for value in columns.row(host)]) + + env.fout(table) diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py index 2ff3379ac..4f246dfbe 100644 --- a/SoftLayer/CLI/routes.py +++ b/SoftLayer/CLI/routes.py @@ -31,6 +31,12 @@ ('virtual:upgrade', 'SoftLayer.CLI.virt.upgrade:cli'), ('virtual:credentials', 'SoftLayer.CLI.virt.credentials:cli'), + ('dedicatedhost', 'SoftLayer.CLI.dedicatedhost'), + ('dedicatedhost:list', 'SoftLayer.CLI.dedicatedhost.list:cli'), + ('dedicatedhost:create', 'SoftLayer.CLI.dedicatedhost.create:cli'), + ('dedicatedhost:create-options', 'SoftLayer.CLI.dedicatedhost.create_options:cli'), + ('dedicatedhost:detail', 'SoftLayer.CLI.dedicatedhost.detail:cli'), + ('cdn', 'SoftLayer.CLI.cdn'), ('cdn:detail', 'SoftLayer.CLI.cdn.detail:cli'), ('cdn:list', 'SoftLayer.CLI.cdn.list:cli'), @@ -280,4 +286,5 @@ 'server': 'hardware', 'vm': 'virtual', 'vs': 'virtual', + 'dh': 'dedicatedhost', } diff --git a/SoftLayer/fixtures/SoftLayer_Account.py b/SoftLayer/fixtures/SoftLayer_Account.py index b8005e0ee..0f3a0a6a9 100644 --- a/SoftLayer/fixtures/SoftLayer_Account.py +++ b/SoftLayer/fixtures/SoftLayer_Account.py @@ -84,7 +84,6 @@ getHourlyVirtualGuests = [vs for vs in getVirtualGuests if vs['hourlyBillingFlag']] - getHardware = [{ 'id': 1000, 'metricTrackingObject': {'id': 3}, @@ -488,7 +487,6 @@ 'quoteKey': '1234test4321', }] - getOrders = [{ 'id': 1234, 'resourceType': '1 x 2.0 GHz Core', @@ -548,3 +546,15 @@ 'name': 'my first pool', 'metricTrackingObjectId': 10, }] + +getDedicatedHosts = [{ + 'datacenter': { + 'name': 'dal05' + }, + 'memoryCapacity': 242, + 'name': 'khnguyendh', + 'diskCapacity': 1200, + 'guestCount': 1, + 'cpuCount': 56, + 'id': 44701 +}] diff --git a/SoftLayer/fixtures/SoftLayer_Product_Package.py b/SoftLayer/fixtures/SoftLayer_Product_Package.py index e458e0f76..f46176ad4 100644 --- a/SoftLayer/fixtures/SoftLayer_Product_Package.py +++ b/SoftLayer/fixtures/SoftLayer_Product_Package.py @@ -155,7 +155,6 @@ 'setupFee': '0', 'sort': 99}]}] - ENTERPRISE_PACKAGE = { 'categories': [ {'categoryCode': 'storage_service_enterprise'} @@ -322,7 +321,6 @@ ] } - PERFORMANCE_PACKAGE = { 'categories': [ {'categoryCode': 'performance_storage_iscsi'}, @@ -419,7 +417,6 @@ ] } - SAAS_PACKAGE = { 'categories': [ {'categoryCode': 'storage_as_a_service'} @@ -669,7 +666,6 @@ ] } - getAllObjects = [{ 'activePresets': [{ 'description': 'Single Xeon 1270, 8GB Ram, 2x1TB SATA disks, Non-RAID', @@ -825,7 +821,6 @@ 'prices': [{'id': 611}], }] - getItemPrices = [ { 'currentPriceFlag': '', @@ -892,3 +887,237 @@ 'setupFee': '0', 'sort': 0 }] + +verifyOrderDH = { + 'preTaxSetup': '0', + 'storageGroups': [], + 'postTaxRecurring': '3.164', + 'billingOrderItemId': '', + 'presetId': '', + 'hardware': [ + { + 'domain': 't.com', + 'hostname': 't', + 'bareMetalInstanceFlag': '', + 'hardwareStatusId': '', + 'primaryBackendNetworkComponent': { + 'router': { + 'id': 51218 + }, + 'networkVlanId': '' + }, + 'accountId': '' + } + ], + 'prices': [ + { + 'itemId': 10195, + 'setupFee': '0', + 'recurringFee': '0', + 'hourlyRecurringFee': '3.164', + 'oneTimeFee': '0', + 'id': 200269, + 'item': { + 'thirdPartyPolicyAssignments': [], + 'capacity': '56', + 'description': '56 Cores X 242 RAM X 1.2 TB', + 'bundle': [ + { + 'category': { + 'categoryCode': 'dedicated_host_ram', + 'id': 850, + 'name': 'Dedicated Host RAM' + }, + 'itemPriceId': 200301, + 'itemPrice': { + 'itemId': 10199, + 'setupFee': '0', + 'recurringFee': '0', + 'hourlyRecurringFee': '0', + 'oneTimeFee': '0', + 'id': 200301, + 'laborFee': '0' + }, + 'bundleItemId': 10195, + 'bundleItem': { + 'units': 'CORE', + 'keyName': '56_CORES_X_242_RAM_X_1_4_TB', + 'capacity': '56', + 'description': '56 Cores X 242 RAM X 1.2 TB', + 'id': 10195 + }, + 'id': 41763 + }, + { + 'category': { + 'categoryCode': 'dedicated_host_disk', + 'id': 851, + 'name': 'Dedicated Host Disk' + }, + 'itemPriceId': 200299, + 'itemPrice': { + 'itemId': 10197, + 'setupFee': '0', + 'recurringFee': '0', + 'hourlyRecurringFee': '0', + 'oneTimeFee': '0', + 'id': 200299, + 'laborFee': '0' + }, + 'bundleItemId': 10195, + 'bundleItem': { + 'units': 'CORE', + 'keyName': '56_CORES_X_242_RAM_X_1_4_TB', + 'capacity': '56', + 'description': '56 Cores X 242 RAM X 1.2 TB', + 'id': 10195 + }, + 'id': 41761 + } + ], + 'keyName': '56_CORES_X_242_RAM_X_1_4_TB', + 'units': 'CORE', + 'id': 10195 + }, + 'laborFee': '0', + 'categories': [ + { + 'categoryCode': 'dedicated_virtual_hosts', + 'id': 848, + 'name': 'Dedicated Host' + } + ] + } + ], + 'sendQuoteEmailFlag': '', + 'packageId': 813, + 'useHourlyPricing': True, + 'preTaxRecurringMonthly': '0', + 'message': '', + 'preTaxRecurring': '3.164', + 'primaryDiskPartitionId': '', + 'locationObject': { + 'id': 138124, + 'name': 'dal05', + 'longName': 'Dallas 5' + }, + 'taxCompletedFlag': False, + 'isManagedOrder': '', + 'imageTemplateId': '', + 'postTaxRecurringMonthly': '0', + 'resourceGroupTemplateId': '', + 'postTaxSetup': '0', + 'sshKeys': [], + 'location': '138124', + 'stepId': '', + 'proratedInitialCharge': '0', + 'totalRecurringTax': '0', + 'paymentType': '', + 'resourceGroupId': '', + 'sourceVirtualGuestId': '', + 'bigDataOrderFlag': False, + 'extendedHardwareTesting': '', + 'preTaxRecurringHourly': '3.164', + 'postTaxRecurringHourly': '3.164', + 'currencyShortName': 'USD', + 'containerSplHash': '000000003699c54000007f38ef8b0102', + 'proratedOrderTotal': '0', + 'serverCoreCount': '', + 'privateCloudOrderFlag': False, + 'totalSetupTax': '0', + 'quantity': 1 +} + +getAllObjectsDH = [{ + "subDescription": "Dedicated Host", + "name": "Dedicated Host", + "items": [{ + "capacity": "56", + "description": "56 Cores X 242 RAM X 1.2 TB", + "bundleItems": [ + { + "capacity": "1200", + "categories": [{ + "categoryCode": "dedicated_host_disk" + }] + }, + { + "capacity": "242", + "categories": [{ + "categoryCode": "dedicated_host_ram" + }] + } + ], + "prices": [ + { + "itemId": 10195, + "setupFee": "0", + "recurringFee": "2099", + "tierMinimumThreshold": "", + "hourlyRecurringFee": "3.164", + "oneTimeFee": "0", + "currentPriceFlag": "", + "id": 200269, + "sort": 0, + "onSaleFlag": "", + "laborFee": "0", + "locationGroupId": "", + "quantity": "" + }, + { + "itemId": 10195, + "setupFee": "0", + "recurringFee": "2161.97", + "tierMinimumThreshold": "", + "hourlyRecurringFee": "3.258", + "oneTimeFee": "0", + "currentPriceFlag": "", + "id": 200271, + "sort": 0, + "onSaleFlag": "", + "laborFee": "0", + "locationGroupId": 503, + "quantity": "" + } + ], + "keyName": "56_CORES_X_242_RAM_X_1_4_TB", + "id": 10195, + "itemCategory": { + "categoryCode": "dedicated_virtual_hosts" + } + }], + "keyName": "DEDICATED_HOST", + "unitSize": "", + "regions": [{ + "location": { + "locationPackageDetails": [{ + "isAvailable": 1, + "locationId": 138124, + "packageId": 813 + }], + "location": { + "statusId": 2, + "priceGroups": [{ + "locationGroupTypeId": 82, + "description": "CDN - North America - Akamai", + "locationGroupType": { + "name": "PRICING" + }, + "securityLevelId": "", + "id": 1463, + "name": "NORTH-AMERICA-AKAMAI" + }], + "id": 138124, + "name": "dal05", + "longName": "Dallas 5" + } + }, + "keyname": "DALLAS05", + "description": "DAL05 - Dallas", + "sortOrder": 12 + }], + "firstOrderStepId": "", + "id": 813, + "isActive": 1, + "description": "Dedicated Host" +}] diff --git a/SoftLayer/fixtures/SoftLayer_Virtual_DedicatedHost.py b/SoftLayer/fixtures/SoftLayer_Virtual_DedicatedHost.py index 926d84ed9..ea1775eb9 100644 --- a/SoftLayer/fixtures/SoftLayer_Virtual_DedicatedHost.py +++ b/SoftLayer/fixtures/SoftLayer_Virtual_DedicatedHost.py @@ -8,3 +8,71 @@ 'cpuCount': 56, 'accountId': 1199911 } + + +getAvailableRouters = [ + {'hostname': 'bcr01a.dal05', 'id': 51218}, + {'hostname': 'bcr02a.dal05', 'id': 83361}, + {'hostname': 'bcr03a.dal05', 'id': 122762}, + {'hostname': 'bcr04a.dal05', 'id': 147566} +] + +getObjectById = { + 'datacenter': { + 'id': 138124, + 'name': 'dal05', + 'longName': 'Dallas 5' + }, + 'memoryCapacity': 242, + 'modifyDate': '2017-11-06T11:38:20-06:00', + 'name': 'khnguyendh', + 'diskCapacity': 1200, + 'backendRouter': { + 'domain': 'softlayer.com', + 'hostname': 'bcr01a.dal05', + 'id': 51218 + }, + 'guestCount': 1, + 'cpuCount': 56, + 'guests': [{ + 'domain': 'Softlayer.com', + 'hostname': 'khnguyenDHI', + 'id': 43546081, + 'uuid': '806a56ec-0383-4c2e-e6a9-7dc89c4b29a2' + }], + 'billingItem': { + 'nextInvoiceTotalRecurringAmount': 1515.556, + 'orderItem': { + 'id': 263060473, + 'order': { + 'status': 'APPROVED', + 'privateCloudOrderFlag': False, + 'modifyDate': '2017-11-02T11:42:50-07:00', + 'orderQuoteId': '', + 'userRecordId': 6908745, + 'createDate': '2017-11-02T11:40:56-07:00', + 'impersonatingUserRecordId': '', + 'orderTypeId': 7, + 'presaleEventId': '', + 'userRecord': { + 'username': '232298_khuong' + }, + 'id': 20093269, + 'accountId': 232298 + } + }, + 'id': 235379377, + 'children': [ + { + 'nextInvoiceTotalRecurringAmount': 0.0, + 'categoryCode': 'dedicated_host_ram' + }, + { + 'nextInvoiceTotalRecurringAmount': 0.0, + 'categoryCode': 'dedicated_host_disk' + } + ] + }, + 'id': 44701, + 'createDate': '2017-11-02T11:40:56-07:00' +} diff --git a/SoftLayer/managers/__init__.py b/SoftLayer/managers/__init__.py index f404d7b9b..044da5a50 100644 --- a/SoftLayer/managers/__init__.py +++ b/SoftLayer/managers/__init__.py @@ -9,6 +9,7 @@ """ from SoftLayer.managers.block import BlockStorageManager from SoftLayer.managers.cdn import CDNManager +from SoftLayer.managers.dedicated_host import DedicatedHostManager from SoftLayer.managers.dns import DNSManager from SoftLayer.managers.file import FileStorageManager from SoftLayer.managers.firewall import FirewallManager @@ -29,6 +30,7 @@ __all__ = [ 'BlockStorageManager', 'CDNManager', + 'DedicatedHostManager', 'DNSManager', 'FileStorageManager', 'FirewallManager', diff --git a/SoftLayer/managers/dedicated_host.py b/SoftLayer/managers/dedicated_host.py new file mode 100644 index 000000000..80e0f3759 --- /dev/null +++ b/SoftLayer/managers/dedicated_host.py @@ -0,0 +1,384 @@ +""" + SoftLayer.dedicatedhost + ~~~~~~~~~~~~ + DH Manager/helpers + + :license: MIT, see License for more details. +""" + +import logging +import SoftLayer + +from SoftLayer.managers import ordering +from SoftLayer import utils + +# Invalid names are ignored due to long method names and short argument names +# pylint: disable=invalid-name, no-self-use + +LOGGER = logging.getLogger(__name__) + + +class DedicatedHostManager(utils.IdentifierMixin, object): + """Manages SoftLayer Dedicated Hosts. + + See product information here https://www.ibm.com/cloud/dedicated + + Example:: + # Initialize the DedicatedHostManager. + # env variables. These can also be specified in ~/.softlayer, + # or passed directly to SoftLayer.Client() + # SL_USERNAME = YOUR_USERNAME + # SL_API_KEY = YOUR_API_KEY + import SoftLayer + client = SoftLayer.Client() + mgr = SoftLayer.DedicatedHostManager(client) + + :param SoftLayer.API.BaseClient client: the client instance + :param SoftLayer.managers.OrderingManager ordering_manager: an optional + manager to handle ordering. + If none is provided, one will be + auto initialized. + """ + + def __init__(self, client, ordering_manager=None): + self.client = client + self.account = client['Account'] + self.host = client['Virtual_DedicatedHost'] + + if ordering_manager is None: + self.ordering_manager = ordering.OrderingManager(client) + + def list_instances(self, tags=None, cpus=None, memory=None, hostname=None, + disk=None, datacenter=None, **kwargs): + """Retrieve a list of all dedicated hosts on the account + + Example:: + + :param list tags: filter based on list of tags + :param integer cpus: filter based on number of CPUS + :param integer memory: filter based on amount of memory + :param string hostname: filter based on hostname + :param string disk: filter based on disk + :param string datacenter: filter based on datacenter + :param dict \\*\\*kwargs: response-level options (mask, limit, etc.) + :returns: Returns a list of dictionaries representing the matching + dedicated host. + + + + """ + if 'mask' not in kwargs: + items = [ + 'id', + 'name', + 'cpuCount', + 'diskCapacity', + 'memoryCapacity', + 'datacenter', + 'guestCount', + ] + kwargs['mask'] = "mask[%s]" % ','.join(items) + + _filter = utils.NestedDict(kwargs.get('filter') or {}) + if tags: + _filter['dedicatedHosts']['tagReferences']['tag']['name'] = { + 'operation': 'in', + 'options': [{'name': 'data', 'value': tags}], + } + + if hostname: + _filter['dedicatedHosts']['name'] = ( + utils.query_filter(hostname) + ) + + if cpus: + _filter['dedicatedHosts']['cpuCount'] = utils.query_filter(cpus) + + if disk: + _filter['dedicatedHosts']['diskCapacity'] = ( + utils.query_filter(disk)) + + if memory: + _filter['dedicatedHosts']['memoryCapacity'] = ( + utils.query_filter(memory)) + + if datacenter: + _filter['dedicatedHosts']['datacenter']['name'] = ( + utils.query_filter(datacenter)) + + kwargs['filter'] = _filter.to_dict() + return self.account.getDedicatedHosts(**kwargs) + + def get_host(self, host_id, **kwargs): + """Get details about a dedicated host. + + :param integer : the host ID + :returns: A dictionary containing a large amount of information about + the specified instance. + + Example:: + + # Print out host ID 12345. + dh = mgr.get_host(12345) + print dh + + # Print out only name and backendRouter for instance 12345 + object_mask = "mask[name,backendRouter[id]]" + dh = mgr.get_host(12345, mask=mask) + print dh + + """ + if 'mask' not in kwargs: + kwargs['mask'] = (''' + id, + name, + cpuCount, + memoryCapacity, + diskCapacity, + createDate, + modifyDate, + backendRouter[ + id, + hostname, + domain + ], + billingItem[ + id, + nextInvoiceTotalRecurringAmount, + children[ + categoryCode, + nextInvoiceTotalRecurringAmount + ], + orderItem[ + id, + order.userRecord[ + username + ] + ] + ], + datacenter[ + id, + name, + longName + ], + guests[ + id, + hostname, + domain, + uuid + ], + guestCount + ''') + + return self.host.getObject(id=host_id, **kwargs) + + def place_order(self, hostname, domain, location, flavor, hourly, router=None): + """Places an order for a dedicated host. + + See get_create_options() for valid arguments. + + :param string hostname: server hostname + :param string domain: server domain name + :param string location: location (datacenter) name + :param boolean hourly: True if using hourly pricing (default). + False for monthly. + :param int router: an optional value for selecting a backend router + """ + create_options = self._generate_create_dict(hostname=hostname, + router=router, + domain=domain, + flavor=flavor, + datacenter=location, + hourly=hourly) + + return self.client['Product_Order'].placeOrder(create_options) + + def verify_order(self, hostname, domain, location, hourly, flavor, router=None): + """Verifies an order for a dedicated host. + + See :func:`place_order` for a list of available options. + """ + + create_options = self._generate_create_dict(hostname=hostname, + router=router, + domain=domain, + flavor=flavor, + datacenter=location, + hourly=hourly) + + return self.client['Product_Order'].verifyOrder(create_options) + + def _generate_create_dict(self, + hostname=None, + domain=None, + flavor=None, + router=None, + datacenter=None, + hourly=True): + """Translates args into a dictionary for creating a dedicated host.""" + package = self._get_package() + item = self._get_item(package, flavor) + + location = self._get_location(package['regions'], datacenter) + price = self._get_price(item) + + routers = self._get_backend_router( + location['location']['locationPackageDetails'], item) + + router = self._get_default_router(routers, router) + + hardware = { + 'hostname': hostname, + 'domain': domain, + 'primaryBackendNetworkComponent': { + 'router': { + 'id': router + } + } + } + + complex_type = "SoftLayer_Container_Product_Order_Virtual_DedicatedHost" + + order = { + "complexType": complex_type, + "quantity": 1, + 'location': location['keyname'], + 'packageId': package['id'], + 'prices': [{'id': price}], + 'hardware': [hardware], + 'useHourlyPricing': hourly, + } + return order + + def _get_package(self): + """Get the package related to simple dedicated host ordering.""" + mask = ''' + items[ + id, + description, + prices, + capacity, + keyName, + itemCategory[categoryCode], + bundleItems[capacity, categories[categoryCode]] + ], + regions[location[location[priceGroups]]] + ''' + + package_keyname = 'DEDICATED_HOST' + + package = self.ordering_manager.get_package_by_key(package_keyname, + mask=mask) + + if package is None: + raise SoftLayer.SoftLayerError("Ordering package not found") + return package + + def _get_location(self, regions, datacenter): + """Get the longer key with a short location(datacenter) name.""" + for region in regions: + # list of locations + if region['location']['location']['name'] == datacenter: + return region + + raise SoftLayer.SoftLayerError("Could not find valid location for: '%s'" + % datacenter) + + def get_create_options(self): + """Returns valid options for ordering a dedicated host.""" + package = self._get_package() + # Locations + locations = [] + for region in package['regions']: + locations.append({ + 'name': region['location']['location']['longName'], + 'key': region['location']['location']['name'], + }) + # flavors + dedicated_host = [] + for item in package['items']: + if item['itemCategory']['categoryCode'] == \ + 'dedicated_virtual_hosts': + dedicated_host.append({ + 'name': item['description'], + 'key': item['keyName'], + }) + + return { + 'locations': locations, + 'dedicated_host': dedicated_host, + } + + def _get_price(self, package): + """Returns valid price for ordering a dedicated host.""" + + for price in package['prices']: + if not price.get('locationGroupId'): + return price['id'] + + raise SoftLayer.SoftLayerError( + "Could not find valid price") + + def _get_item(self, package, flavor): + """Returns the item for ordering a dedicated host.""" + + for item in package['items']: + if item['keyName'] == flavor: + return item + + raise SoftLayer.SoftLayerError("Could not find valid item for: '%s'" + % flavor) + + def _get_backend_router(self, locations, item): + """Returns valid router options for ordering a dedicated host.""" + mask = ''' + id, + hostname + ''' + cpu_count = item['capacity'] + + for capacity in item['bundleItems']: + for category in capacity['categories']: + if category['categoryCode'] == 'dedicated_host_ram': + mem_capacity = capacity['capacity'] + if category['categoryCode'] == 'dedicated_host_disk': + disk_capacity = capacity['capacity'] + + if locations is not None: + for location in locations: + if location['locationId'] is not None: + loc_id = location['locationId'] + host = { + 'cpuCount': cpu_count, + 'memoryCapacity': mem_capacity, + 'diskCapacity': disk_capacity, + 'datacenter': { + 'id': loc_id + } + } + routers = self.host.getAvailableRouters(host, mask=mask) + return routers + + raise SoftLayer.SoftLayerError("Could not find available routers") + + def _get_default_router(self, routers, router_name=None): + """Returns the default router for ordering a dedicated host.""" + if router_name is None: + for router in routers: + if router['id'] is not None: + return router['id'] + else: + for router in routers: + if router['hostname'] == router_name: + return router['id'] + + raise SoftLayer.SoftLayerError("Could not find valid default router") + + def get_router_options(self, datacenter=None, flavor=None): + """Returns available backend routers for the dedicated host.""" + package = self._get_package() + + location = self._get_location(package['regions'], datacenter) + item = self._get_item(package, flavor) + + return self._get_backend_router(location['location']['locationPackageDetails'], item) diff --git a/tests/CLI/modules/dedicatedhost_tests.py b/tests/CLI/modules/dedicatedhost_tests.py new file mode 100644 index 000000000..ab62063c8 --- /dev/null +++ b/tests/CLI/modules/dedicatedhost_tests.py @@ -0,0 +1,327 @@ +""" + SoftLayer.tests.CLI.modules.dedicatedhosts_tests + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :license: MIT, see LICENSE for more details. +""" +import json +import mock +import os +import SoftLayer + +from SoftLayer.CLI import exceptions +from SoftLayer.fixtures import SoftLayer_Product_Package +from SoftLayer.fixtures import SoftLayer_Virtual_DedicatedHost +from SoftLayer import testing + + +class DedicatedHostsTests(testing.TestCase): + def set_up(self): + self.dedicated_host = SoftLayer.DedicatedHostManager(self.client) + + def test_list_dedicated_hosts(self): + result = self.run_command(['dedicatedhost', 'list']) + + self.assert_no_fail(result) + self.assertEqual(json.loads(result.output), + [{ + 'cpuCount': 56, + 'datacenter': 'dal05', + 'diskCapacity': 1200, + 'guestCount': 1, + 'id': 44701, + 'memoryCapacity': 242, + 'name': 'khnguyendh' + }] + ) + + def tear_down(self): + if os.path.exists("test.txt"): + os.remove("test.txt") + + def test_details(self): + mock = self.set_mock('SoftLayer_Virtual_DedicatedHost', 'getObject') + mock.return_value = SoftLayer_Virtual_DedicatedHost.getObjectById + + result = self.run_command(['dedicatedhost', 'detail', '44701', '--price', '--guests']) + self.assert_no_fail(result) + + self.assertEqual(json.loads(result.output), + { + 'cpu count': 56, + 'create date': '2017-11-02T11:40:56-07:00', + 'datacenter': 'dal05', + 'disk capacity': 1200, + 'guest count': 1, + 'guests': [{ + 'domain': 'Softlayer.com', + 'hostname': 'khnguyenDHI', + 'id': 43546081, + 'uuid': '806a56ec-0383-4c2e-e6a9-7dc89c4b29a2' + }], + 'id': 44701, + 'memory capacity': 242, + 'modify date': '2017-11-06T11:38:20-06:00', + 'name': 'khnguyendh', + 'owner': '232298_khuong', + 'price_rate': 1515.556, + 'router hostname': 'bcr01a.dal05', + 'router id': 51218} + ) + + def test_details_no_owner(self): + mock = self.set_mock('SoftLayer_Virtual_DedicatedHost', 'getObject') + retVal = SoftLayer_Virtual_DedicatedHost.getObjectById + retVal['billingItem'] = {} + mock.return_value = retVal + + result = self.run_command( + ['dedicatedhost', 'detail', '44701', '--price', '--guests']) + self.assert_no_fail(result) + + self.assertEqual(json.loads(result.output), {'cpu count': 56, + 'create date': '2017-11-02T11:40:56-07:00', + 'datacenter': 'dal05', + 'disk capacity': 1200, + 'guest count': 1, + 'guests': [{ + 'domain': 'Softlayer.com', + 'hostname': 'khnguyenDHI', + 'id': 43546081, + 'uuid': '806a56ec-0383-4c2e-e6a9-7dc89c4b29a2'}], + 'id': 44701, + 'memory capacity': 242, + 'modify date': '2017-11-06T11:38:20-06:00', + 'name': 'khnguyendh', + 'owner': None, + 'price_rate': 0, + 'router hostname': 'bcr01a.dal05', + 'router id': 51218} + ) + + def test_create_options(self): + mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock.return_value = SoftLayer_Product_Package.getAllObjectsDH + + result = self.run_command(['dh', 'create-options']) + self.assert_no_fail(result) + + self.assertEqual(json.loads(result.output), [[ + { + 'datacenter': 'Dallas 5', + 'value': 'dal05' + }], + [{ + 'Dedicated Virtual Host Flavor(s)': + '56 Cores X 242 RAM X 1.2 TB', + 'value': '56_CORES_X_242_RAM_X_1_4_TB' + } + ]] + ) + + def test_create_options_with_only_datacenter(self): + mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock.return_value = SoftLayer_Product_Package.getAllObjectsDH + + result = self.run_command(['dh', 'create-options', '-d=dal05']) + self.assertIsInstance(result.exception, exceptions.ArgumentError) + + def test_create_options_get_routers(self): + mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock.return_value = SoftLayer_Product_Package.getAllObjectsDH + + result = self.run_command(['dh', + 'create-options', + '--datacenter=dal05', + '--flavor=56_CORES_X_242_RAM_X_1_4_TB']) + self.assert_no_fail(result) + self.assertEqual(json.loads(result.output), [[ + { + "Available Backend Routers": "bcr01a.dal05" + }, + { + "Available Backend Routers": "bcr02a.dal05" + }, + { + "Available Backend Routers": "bcr03a.dal05" + }, + { + "Available Backend Routers": "bcr04a.dal05" + } + ]] + ) + + def test_create(self): + SoftLayer.CLI.formatting.confirm = mock.Mock() + SoftLayer.CLI.formatting.confirm.return_value = True + mock_package_obj = self.set_mock('SoftLayer_Product_Package', + 'getAllObjects') + mock_package_obj.return_value = SoftLayer_Product_Package.getAllObjectsDH + + result = self.run_command(['dedicatedhost', 'create', + '--hostname=host', + '--domain=example.com', + '--datacenter=dal05', + '--flavor=56_CORES_X_242_RAM_X_1_4_TB', + '--billing=hourly']) + self.assert_no_fail(result) + args = ({ + 'hardware': [{ + 'domain': 'example.com', + 'primaryBackendNetworkComponent': { + 'router': { + 'id': 51218 + } + }, + 'hostname': 'host' + }], + 'prices': [{ + 'id': 200269 + }], + 'location': 'DALLAS05', + 'packageId': 813, + 'complexType': + 'SoftLayer_Container_Product_Order_Virtual_DedicatedHost', + 'useHourlyPricing': True, + 'quantity': 1}, + ) + + self.assert_called_with('SoftLayer_Product_Order', 'placeOrder', + args=args) + + def test_create_verify(self): + SoftLayer.CLI.formatting.confirm = mock.Mock() + SoftLayer.CLI.formatting.confirm.return_value = True + mock_package_obj = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock_package_obj.return_value = SoftLayer_Product_Package.getAllObjectsDH + mock_package = self.set_mock('SoftLayer_Product_Order', 'verifyOrder') + mock_package.return_value = SoftLayer_Product_Package.verifyOrderDH + + result = self.run_command(['dedicatedhost', 'create', + '--verify', + '--hostname=host', + '--domain=example.com', + '--datacenter=dal05', + '--flavor=56_CORES_X_242_RAM_X_1_4_TB', + '--billing=hourly']) + self.assert_no_fail(result) + + args = ({ + 'useHourlyPricing': True, + 'hardware': [{ + + 'hostname': 'host', + 'domain': 'example.com', + + 'primaryBackendNetworkComponent': { + 'router': { + 'id': 51218 + } + } + }], + 'packageId': 813, 'prices': [{'id': 200269}], + 'location': 'DALLAS05', + 'complexType': 'SoftLayer_Container_Product_Order_Virtual_DedicatedHost', + 'quantity': 1},) + + self.assert_called_with('SoftLayer_Product_Order', 'verifyOrder', + args=args) + + result = self.run_command(['dh', 'create', + '--verify', + '--hostname=host', + '--domain=example.com', + '--datacenter=dal05', + '--flavor=56_CORES_X_242_RAM_X_1_4_TB', + '--billing=monthly']) + self.assert_no_fail(result) + + args = ({ + 'useHourlyPricing': True, + 'hardware': [{ + 'hostname': 'host', + 'domain': 'example.com', + 'primaryBackendNetworkComponent': { + 'router': { + 'id': 51218 + } + } + }], + 'packageId': 813, 'prices': [{'id': 200269}], + 'location': 'DALLAS05', + 'complexType': 'SoftLayer_Container_Product_Order_Virtual_DedicatedHost', + 'quantity': 1},) + + self.assert_called_with('SoftLayer_Product_Order', 'verifyOrder', + args=args) + + def test_create_aborted(self): + SoftLayer.CLI.formatting.confirm = mock.Mock() + SoftLayer.CLI.formatting.confirm.return_value = False + mock_package_obj = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock_package_obj.return_value = SoftLayer_Product_Package.getAllObjectsDH + + result = self.run_command(['dh', 'create', + '--hostname=host', + '--domain=example.com', + '--datacenter=dal05', + '--flavor=56_CORES_X_242_RAM_X_1_4_TB', + '--billing=monthly']) + + self.assertEqual(result.exit_code, 2) + self.assertIsInstance(result.exception, exceptions.CLIAbort) + + def test_create_export(self): + mock_package_obj = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock_package_obj.return_value = SoftLayer_Product_Package.getAllObjectsDH + mock_package = self.set_mock('SoftLayer_Product_Order', 'verifyOrder') + mock_package.return_value = SoftLayer_Product_Package.verifyOrderDH + + self.run_command(['dedicatedhost', 'create', + '--verify', + '--hostname=host', + '--domain=example.com', + '--datacenter=dal05', + '--flavor=56_CORES_X_242_RAM_X_1_4_TB', + '--billing=hourly', + '--export=test.txt']) + + self.assertEqual(os.path.exists("test.txt"), True) + + def test_create_verify_no_price_or_more_than_one(self): + mock_package_obj = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock_package_obj.return_value = SoftLayer_Product_Package.getAllObjectsDH + mock_package = self.set_mock('SoftLayer_Product_Order', 'verifyOrder') + ret_val = SoftLayer_Product_Package.verifyOrderDH + ret_val['prices'] = [] + mock_package.return_value = ret_val + + result = self.run_command(['dedicatedhost', 'create', + '--verify', + '--hostname=host', + '--domain=example.com', + '--datacenter=dal05', + '--flavor=56_CORES_X_242_RAM_X_1_4_TB', + '--billing=hourly']) + + self.assertIsInstance(result.exception, exceptions.ArgumentError) + args = ({ + 'hardware': [{ + 'domain': 'example.com', + 'primaryBackendNetworkComponent': { + 'router': { + 'id': 51218 + } + }, + 'hostname': 'host' + }], + 'prices': [{ + 'id': 200269 + }], + 'location': 'DALLAS05', + 'packageId': 813, + 'complexType': 'SoftLayer_Container_Product_Order_Virtual_DedicatedHost', + 'useHourlyPricing': True, + 'quantity': 1},) + + self.assert_called_with('SoftLayer_Product_Order', 'verifyOrder', args=args) diff --git a/tests/managers/dedicated_host_tests.py b/tests/managers/dedicated_host_tests.py new file mode 100644 index 000000000..a20fc6349 --- /dev/null +++ b/tests/managers/dedicated_host_tests.py @@ -0,0 +1,616 @@ +""" + SoftLayer.tests.managers.dedicated_host_tests + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + :license: MIT, see LICENSE for more details. +""" +import mock +import SoftLayer + +from SoftLayer import exceptions +from SoftLayer import fixtures +from SoftLayer import testing + + +class DedicatedHostTests(testing.TestCase): + def set_up(self): + self.dedicated_host = SoftLayer.DedicatedHostManager(self.client) + + def test_list_instances(self): + results = self.dedicated_host.list_instances() + + self.assertEqual(results, fixtures.SoftLayer_Account.getDedicatedHosts) + self.assert_called_with('SoftLayer_Account', 'getDedicatedHosts') + + def test_list_instances_with_filters(self): + results = self.dedicated_host.list_instances( + tags=['tag1', 'tag2'], + cpus=2, + memory=1, + hostname='hostname', + datacenter='dal05', + disk=1 + ) + self.assertEqual(results, fixtures.SoftLayer_Account.getDedicatedHosts) + + def test_get_host(self): + + self.dedicated_host.host = mock.Mock() + self.dedicated_host.host.getObject.return_value = 'test' + + self.dedicated_host.get_host(12345) + + mask = (''' + id, + name, + cpuCount, + memoryCapacity, + diskCapacity, + createDate, + modifyDate, + backendRouter[ + id, + hostname, + domain + ], + billingItem[ + id, + nextInvoiceTotalRecurringAmount, + children[ + categoryCode, + nextInvoiceTotalRecurringAmount + ], + orderItem[ + id, + order.userRecord[ + username + ] + ] + ], + datacenter[ + id, + name, + longName + ], + guests[ + id, + hostname, + domain, + uuid + ], + guestCount + ''') + self.dedicated_host.host.getObject.assert_called_once_with(id=12345, mask=mask) + + def test_place_order(self): + create_dict = self.dedicated_host._generate_create_dict = mock.Mock() + + values = { + 'hardware': [ + { + 'primaryBackendNetworkComponent': { + 'router': { + 'id': 51218 + } + }, + 'domain': u'test.com', + 'hostname': u'test' + } + ], + 'useHourlyPricing': True, + 'location': 'AMSTERDAM', + 'packageId': 813, + 'complexType': 'SoftLayer_Container_Product_Order_Virtual_DedicatedHost', + 'prices': [ + { + 'id': 200269 + } + ], + 'quantity': 1 + } + create_dict.return_value = values + + location = 'dal05' + hostname = 'test' + domain = 'test.com' + hourly = True + flavor = '56_CORES_X_242_RAM_X_1_4_TB' + + self.dedicated_host.place_order(hostname=hostname, + domain=domain, + location=location, + flavor=flavor, + hourly=hourly) + + create_dict.assert_called_once_with(hostname=hostname, + router=None, + domain=domain, + datacenter=location, + flavor=flavor, + hourly=True) + + self.assert_called_with('SoftLayer_Product_Order', + 'placeOrder', + args=(values,)) + + def test_verify_order(self): + create_dict = self.dedicated_host._generate_create_dict = mock.Mock() + + values = { + 'hardware': [ + { + 'primaryBackendNetworkComponent': { + 'router': { + 'id': 51218 + } + }, + 'domain': 'test.com', + 'hostname': 'test' + } + ], + 'useHourlyPricing': True, + 'location': 'AMSTERDAM', + 'packageId': 813, + 'complexType': 'SoftLayer_Container_Product_Order_Virtual_DedicatedHost', + 'prices': [ + { + 'id': 200269 + } + ], + 'quantity': 1 + } + create_dict.return_value = values + + location = 'dal05' + hostname = 'test' + domain = 'test.com' + hourly = True + flavor = '56_CORES_X_242_RAM_X_1_4_TB' + + self.dedicated_host.verify_order(hostname=hostname, + domain=domain, + location=location, + flavor=flavor, + hourly=hourly) + + create_dict.assert_called_once_with(hostname=hostname, + router=None, + domain=domain, + datacenter=location, + flavor=flavor, + hourly=True) + + self.assert_called_with('SoftLayer_Product_Order', + 'verifyOrder', + args=(values,)) + + def test_generate_create_dict_without_router(self): + self.dedicated_host._get_package = mock.MagicMock() + self.dedicated_host._get_package.return_value = self._get_package() + self.dedicated_host._get_backend_router = mock.Mock() + self.dedicated_host._get_backend_router.return_value = self \ + ._get_routers_sample() + + location = 'dal05' + hostname = 'test' + domain = 'test.com' + hourly = True + flavor = '56_CORES_X_242_RAM_X_1_4_TB' + + results = self.dedicated_host._generate_create_dict(hostname=hostname, + domain=domain, + datacenter=location, + flavor=flavor, + hourly=hourly) + + testResults = { + 'hardware': [ + { + 'primaryBackendNetworkComponent': { + 'router': { + 'id': 51218 + } + }, + 'domain': 'test.com', + 'hostname': 'test' + } + ], + 'useHourlyPricing': True, + 'location': 'DALLAS05', + 'packageId': 813, + 'complexType': 'SoftLayer_Container_Product_Order_Virtual_DedicatedHost', + 'prices': [ + { + 'id': 200269 + } + ], + 'quantity': 1 + } + + self.assertEqual(results, testResults) + + def test_generate_create_dict_with_router(self): + self.dedicated_host._get_package = mock.MagicMock() + self.dedicated_host._get_package.return_value = self._get_package() + self.dedicated_host._get_default_router = mock.Mock() + self.dedicated_host._get_default_router.return_value = 51218 + + location = 'dal05' + router = 51218 + hostname = 'test' + domain = 'test.com' + hourly = True + flavor = '56_CORES_X_242_RAM_X_1_4_TB' + + results = self.dedicated_host._generate_create_dict( + hostname=hostname, + router=router, + domain=domain, + datacenter=location, + flavor=flavor, + hourly=hourly) + + testResults = { + 'hardware': [ + { + 'primaryBackendNetworkComponent': { + 'router': { + 'id': 51218 + } + }, + 'domain': 'test.com', + 'hostname': 'test' + } + ], + 'useHourlyPricing': True, + 'location': 'DALLAS05', + 'packageId': 813, + 'complexType': + 'SoftLayer_Container_Product_Order_Virtual_DedicatedHost', + 'prices': [ + { + 'id': 200269 + } + ], + 'quantity': 1 + } + + self.assertEqual(results, testResults) + + def test_get_package(self): + mask = ''' + items[ + id, + description, + prices, + capacity, + keyName, + itemCategory[categoryCode], + bundleItems[capacity, categories[categoryCode]] + ], + regions[location[location[priceGroups]]] + ''' + self.dedicated_host.ordering_manager = mock.Mock() + + self.dedicated_host.ordering_manager.get_package_by_key.return_value = \ + "test" + + package = self.dedicated_host._get_package() + + package_keyname = 'DEDICATED_HOST' + + self.assertEqual('test', package) + self.dedicated_host.ordering_manager.get_package_by_key. \ + assert_called_once_with(package_keyname, mask=mask) + + def test_get_package_no_package_found(self): + mask = ''' + items[ + id, + description, + prices, + capacity, + keyName, + itemCategory[categoryCode], + bundleItems[capacity, categories[categoryCode]] + ], + regions[location[location[priceGroups]]] + ''' + self.dedicated_host.ordering_manager = mock.Mock() + + self.dedicated_host.ordering_manager.get_package_by_key.return_value = \ + None + + package_keyname = 'DEDICATED_HOST' + + self.assertRaises(exceptions.SoftLayerError, + self.dedicated_host._get_package) + + self.dedicated_host.ordering_manager.get_package_by_key. \ + assert_called_once_with(package_keyname, mask=mask) + + def test_get_location(self): + regions = [{ + "location": { + "location": { + "name": "dal05", + } + } + }] + + region = { + 'location': + { + 'location': { + 'name': 'dal05', + } + } + } + + testing = self.dedicated_host._get_location(regions, 'dal05') + + self.assertEqual(testing, region) + + def test_get_location_no_location_found(self): + regions = [{ + "location": { + "location": { + "name": "dal05", + } + } + }] + + self.assertRaises(exceptions.SoftLayerError, + self.dedicated_host._get_location, regions, 'dal10') + + def test_get_create_options(self): + self.dedicated_host._get_package = mock.MagicMock() + self.dedicated_host._get_package.return_value = self._get_package() + + results = { + 'dedicated_host': [{ + 'key': '56_CORES_X_242_RAM_X_1_4_TB', + 'name': '56 Cores X 242 RAM X 1.2 TB' + }], + 'locations': [ + { + 'key': 'ams01', + 'name': 'Amsterdam 1' + }, + { + 'key': 'dal05', + 'name': 'Dallas 5' + } + ] + } + + self.assertEqual(self.dedicated_host.get_create_options(), results) + + def test_get_price(self): + package = self._get_package() + item = package['items'][0] + price_id = 200269 + + self.assertEqual(self.dedicated_host._get_price(item), price_id) + + def test_get_price_no_price_found(self): + package = self._get_package() + package['items'][0]['prices'][0]['locationGroupId'] = 33 + item = package['items'][0] + + self.assertRaises(exceptions.SoftLayerError, + self.dedicated_host._get_price, item) + + def test_get_item(self): + """Returns the item for ordering a dedicated host.""" + package = self._get_package() + flavor = '56_CORES_X_242_RAM_X_1_4_TB' + + item = { + 'bundleItems': [{ + 'capacity': '1200', + 'categories': [{ + 'categoryCode': 'dedicated_host_disk' + }] + }, + { + 'capacity': '242', + 'categories': [{ + 'categoryCode': 'dedicated_host_ram' + }] + }], + 'capacity': '56', + 'description': '56 Cores X 242 RAM X 1.2 TB', + 'id': 10195, + 'itemCategory': { + 'categoryCode': 'dedicated_virtual_hosts' + }, + 'keyName': '56_CORES_X_242_RAM_X_1_4_TB', + 'prices': [{ + 'hourlyRecurringFee': '3.164', + 'id': 200269, + 'itemId': 10195, + 'recurringFee': '2099', + }] + } + + self.assertEqual(self.dedicated_host._get_item(package, flavor), item) + + def test_get_item_no_item_found(self): + package = self._get_package() + + flavor = '56_CORES_X_242_RAM_X_1_4_TB' + package['items'][0]['keyName'] = 'not found' + + self.assertRaises(exceptions.SoftLayerError, + self.dedicated_host._get_item, package, flavor) + + def test_get_backend_router(self): + location = [ + { + 'isAvailable': 1, + 'locationId': 138124, + 'packageId': 813 + } + ] + + locId = location[0]['locationId'] + + mask = ''' + id, + hostname + ''' + + host = { + 'cpuCount': '56', + 'memoryCapacity': '242', + 'diskCapacity': '1200', + 'datacenter': { + 'id': locId + } + } + + self.dedicated_host.host = mock.Mock() + + routers = self.dedicated_host.host.getAvailableRouters.return_value = \ + self._get_routers_sample() + + item = self._get_package()['items'][0] + + routers_test = self.dedicated_host._get_backend_router(location, item) + + self.assertEqual(routers, routers_test) + self.dedicated_host.host.getAvailableRouters. \ + assert_called_once_with(host, mask=mask) + + def test_get_backend_router_no_routers_found(self): + location = [] + + self.dedicated_host.host = mock.Mock() + + routers_test = self.dedicated_host._get_backend_router + + item = self._get_package()['items'][0] + + self.assertRaises(exceptions.SoftLayerError, routers_test, location, item) + + def test_get_default_router(self): + routers = self._get_routers_sample() + + router = 51218 + + router_test = self.dedicated_host._get_default_router(routers, 'bcr01a.dal05') + + self.assertEqual(router_test, router) + + def test_get_default_router_no_router_found(self): + routers = [] + + self.assertRaises(exceptions.SoftLayerError, + self.dedicated_host._get_default_router, routers, 'notFound') + + def _get_routers_sample(self): + routers = [ + { + 'hostname': 'bcr01a.dal05', + 'id': 51218 + }, + { + 'hostname': 'bcr02a.dal05', + 'id': 83361 + }, + { + 'hostname': 'bcr03a.dal05', + 'id': 122762 + }, + { + 'hostname': 'bcr04a.dal05', + 'id': 147566 + } + ] + + return routers + + def _get_package(self): + package = { + "items": [ + { + "capacity": "56", + "description": "56 Cores X 242 RAM X 1.2 TB", + "bundleItems": [ + { + "capacity": "1200", + "categories": [ + { + "categoryCode": "dedicated_host_disk" + } + ] + }, + { + "capacity": "242", + "categories": [ + { + "categoryCode": "dedicated_host_ram" + } + ] + } + ], + "prices": [ + { + "itemId": 10195, + "recurringFee": "2099", + "hourlyRecurringFee": "3.164", + "id": 200269, + } + ], + "keyName": "56_CORES_X_242_RAM_X_1_4_TB", + "id": 10195, + "itemCategory": { + "categoryCode": "dedicated_virtual_hosts" + }, + } + ], + "regions": [ + { + "location": { + "locationPackageDetails": [ + { + "locationId": 265592, + "packageId": 813 + } + ], + "location": { + "id": 265592, + "name": "ams01", + "longName": "Amsterdam 1" + } + }, + "keyname": "AMSTERDAM", + "description": "AMS01 - Amsterdam", + "sortOrder": 0 + }, + { + "location": { + "locationPackageDetails": [ + { + "isAvailable": 1, + "locationId": 138124, + "packageId": 813 + } + ], + "location": { + "id": 138124, + "name": "dal05", + "longName": "Dallas 5" + } + }, + "keyname": "DALLAS05", + "description": "DAL05 - Dallas", + } + + ], + "id": 813, + "description": "Dedicated Host" + } + + return package