Repository: softlayer/softlayer-python
Pull request #896 (2017-11-22 19:55:35)

Dedicate command


Patch:
diff --git a/SoftLayer/CLI/dedicatedhost/__init__.py b/SoftLayer/CLI/dedicatedhost/__init__.py
new file mode 100644
index 00000000..55d5d799
--- /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 00000000..491da211
--- /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 00000000..94727ce6
--- /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 00000000..e1c46b96
--- /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 00000000..56feefd9
--- /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 2ff3379a..4f246dfb 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 b8005e0e..0f3a0a6a 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 e458e0f7..f46176ad 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 926d84ed..ea1775eb 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 f404d7b9..044da5a5 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 00000000..80e0f375
--- /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)


Test patch:
diff --git a/tests/CLI/modules/dedicatedhost_tests.py b/tests/CLI/modules/dedicatedhost_tests.py
new file mode 100644
index 00000000..ab62063c
--- /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 00000000..a20fc634
--- /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