Repository: softlayer/softlayer-python
Pull request #936 (2018-02-05 17:38:50)

Add boot mode option
Add the ability to specify the boot mode when ordering a virtual server.


Patch:
diff --git a/SoftLayer/CLI/order/package_list.py b/SoftLayer/CLI/order/package_list.py
index af3e3626..9a6b97e6 100644
--- a/SoftLayer/CLI/order/package_list.py
+++ b/SoftLayer/CLI/order/package_list.py
@@ -8,15 +8,14 @@
 from SoftLayer.managers import ordering
 
 COLUMNS = ['name',
-           'keyName',
-           'type']
+           'keyName', ]
 
 
 @click.command()
-@click.option('--keyword', help="A word (or string) used to filter package names.")
-@click.option('--package_type', help="The keyname for the type of package. BARE_METAL_CPU for example")
+@click.option('--keyword',
+              help="A word (or string) used to filter package names.")
 @environment.pass_env
-def cli(env, keyword, package_type):
+def cli(env, keyword):
     """List packages that can be ordered via the placeOrder API.
 
     \b
@@ -33,19 +32,13 @@ def cli(env, keyword, package_type):
         # List out all packages with "server" in the name
         slcli order package-list --keyword server
 
-    Package types can be used to remove unwanted packages
-    \b
-    Example:
-        slcli order package-list --package_type BARE_METAL_CPU
     """
     manager = ordering.OrderingManager(env.client)
     table = formatting.Table(COLUMNS)
 
-    _filter = {'type': {'keyName': {'operation': '!= BLUEMIX_SERVICE'}}}
+    _filter = {}
     if keyword:
-        _filter['name'] = {'operation': '*= %s' % keyword}
-    if package_type:
-        _filter['type'] = {'keyName': {'operation': package_type}}
+        _filter = {'name': {'operation': '*= %s' % keyword}}
 
     packages = manager.list_packages(filter=_filter)
 
@@ -53,6 +46,5 @@ def cli(env, keyword, package_type):
         table.add_row([
             package['name'],
             package['keyName'],
-            package['type']['keyName']
         ])
     env.fout(table)
diff --git a/SoftLayer/CLI/securitygroup/rule.py b/SoftLayer/CLI/securitygroup/rule.py
index 4f624308..dfbc93ed 100644
--- a/SoftLayer/CLI/securitygroup/rule.py
+++ b/SoftLayer/CLI/securitygroup/rule.py
@@ -67,35 +67,15 @@ def rule_list(env, securitygroup_id, sortby):
 @click.option('--ethertype', '-e',
               help='The ethertype (IPv4 or IPv6) to enforce')
 @click.option('--port-max', '-M', type=click.INT,
-              help=('The upper port bound to enforce. When the protocol is ICMP, '
-                    'this specifies the ICMP code to permit'))
+              help='The upper port bound to enforce')
 @click.option('--port-min', '-m', type=click.INT,
-              help=('The lower port bound to enforce. When the protocol is ICMP, '
-                    'this specifies the ICMP type to permit'))
+              help='The lower port bound to enforce')
 @click.option('--protocol', '-p',
               help='The protocol (icmp, tcp, udp) to enforce')
 @environment.pass_env
 def add(env, securitygroup_id, remote_ip, remote_group,
         direction, ethertype, port_max, port_min, protocol):
-    """Add a security group rule to a security group.
-
-    \b
-    Examples:
-        # Add an SSH rule (TCP port 22) to a security group
-        slcli sg rule-add 384727 \\
-            --direction ingress \\
-            --protocol tcp \\
-            --port-min 22 \\
-            --port-max 22
-
-    \b
-        # Add a ping rule (ICMP type 8 code 0) to a security group
-        slcli sg rule-add 384727 \\
-            --direction ingress \\
-            --protocol icmp \\
-            --port-min 8 \\
-            --port-max 0
-    """
+    """Add a security group rule to a security group."""
     mgr = SoftLayer.NetworkManager(env.client)
 
     ret = mgr.add_securitygroup_rule(securitygroup_id, remote_ip, remote_group,
diff --git a/SoftLayer/CLI/sshkey/add.py b/SoftLayer/CLI/sshkey/add.py
index a3a3c6cc..49920a07 100644
--- a/SoftLayer/CLI/sshkey/add.py
+++ b/SoftLayer/CLI/sshkey/add.py
@@ -6,7 +6,6 @@
 
 import SoftLayer
 from SoftLayer.CLI import environment
-from SoftLayer.CLI import exceptions
 
 
 @click.command()
@@ -20,16 +19,6 @@
 def cli(env, label, in_file, key, note):
     """Add a new SSH key."""
 
-    if in_file is None and key is None:
-        raise exceptions.ArgumentError(
-            'Either [-f | --in-file] or [-k | --key] arguments are required to add a key'
-        )
-
-    if in_file and key:
-        raise exceptions.ArgumentError(
-            '[-f | --in-file] is not allowed with [-k | --key]'
-        )
-
     if key:
         key_text = key
     else:
diff --git a/SoftLayer/CLI/virt/create.py b/SoftLayer/CLI/virt/create.py
index 0e721b46..4bb3427f 100644
--- a/SoftLayer/CLI/virt/create.py
+++ b/SoftLayer/CLI/virt/create.py
@@ -80,7 +80,8 @@ def _parse_create_args(client, args):
         "disks": args['disk'],
         "cpus": args.get('cpu', None),
         "memory": args.get('memory', None),
-        "flavor": args.get('flavor', None)
+        "flavor": args.get('flavor', None),
+        "boot_mode": args.get('boot_mode', None)
     }
 
     # The primary disk is included in the flavor and the local_disk flag is not needed
@@ -175,6 +176,9 @@ def _parse_create_args(client, args):
               help="OS install code. Tip: you can specify <OS>_LATEST")
 @click.option('--image',
               help="Image ID. See: 'slcli image list' for reference")
+@click.option('--boot-mode',
+              help="Specify the mode to boot the OS in. Supported modes are HVM and PV.",
+              type=click.STRING)
 @click.option('--billing',
               type=click.Choice(['hourly', 'monthly']),
               default='hourly',
diff --git a/SoftLayer/managers/network.py b/SoftLayer/managers/network.py
index af7937de..2513a912 100644
--- a/SoftLayer/managers/network.py
+++ b/SoftLayer/managers/network.py
@@ -76,9 +76,7 @@ def add_securitygroup_rule(self, group_id, remote_ip=None,
         :param str direction: The direction to enforce (egress or ingress)
         :param str ethertype: The ethertype to enforce (IPv4 or IPv6)
         :param int port_max: The upper port bound to enforce
-                             (icmp code if the protocol is icmp)
         :param int port_min: The lower port bound to enforce
-                             (icmp type if the protocol is icmp)
         :param str protocol: The protocol to enforce (icmp, udp, tcp)
         """
         rule = {'direction': direction}
@@ -320,19 +318,19 @@ def edit_securitygroup_rule(self, group_id, rule_id, remote_ip=None,
         """
         successful = False
         obj = {}
-        if remote_ip is not None:
+        if remote_ip:
             obj['remoteIp'] = remote_ip
-        if remote_group is not None:
+        if remote_group:
             obj['remoteGroupId'] = remote_group
-        if direction is not None:
+        if direction:
             obj['direction'] = direction
-        if ethertype is not None:
+        if ethertype:
             obj['ethertype'] = ethertype
-        if port_max is not None:
+        if port_max:
             obj['portRangeMax'] = port_max
-        if port_min is not None:
+        if port_min:
             obj['portRangeMin'] = port_min
-        if protocol is not None:
+        if protocol:
             obj['protocol'] = protocol
 
         if obj:
diff --git a/SoftLayer/managers/ordering.py b/SoftLayer/managers/ordering.py
index 4d8e94c1..51bf1810 100644
--- a/SoftLayer/managers/ordering.py
+++ b/SoftLayer/managers/ordering.py
@@ -16,7 +16,7 @@
 
 ITEM_MASK = '''id, keyName, description, itemCategory, categories'''
 
-PACKAGE_MASK = '''id, name, keyName, isActive, type'''
+PACKAGE_MASK = '''id, name, keyName, isActive'''
 
 PRESET_MASK = '''id, name, keyName, description'''
 
diff --git a/SoftLayer/managers/sshkey.py b/SoftLayer/managers/sshkey.py
index 8aac6347..a294d525 100644
--- a/SoftLayer/managers/sshkey.py
+++ b/SoftLayer/managers/sshkey.py
@@ -28,7 +28,6 @@ def add_key(self, key, label, notes=None):
 
         :param string key: The SSH key to add
         :param string label: The label for the key
-        :param string notes: Additional notes for the key
         :returns: A dictionary of the new key's information.
         """
         order = {
diff --git a/SoftLayer/managers/vs.py b/SoftLayer/managers/vs.py
index b98578ab..851c2b3f 100644
--- a/SoftLayer/managers/vs.py
+++ b/SoftLayer/managers/vs.py
@@ -307,7 +307,7 @@ def _generate_create_dict(
             dedicated=False, public_vlan=None, private_vlan=None,
             userdata=None, nic_speed=None, disks=None, post_uri=None,
             private=False, ssh_keys=None, public_security_groups=None,
-            private_security_groups=None, **kwargs):
+            private_security_groups=None, boot_mode=None, **kwargs):
         """Returns a dict appropriate to pass into Virtual_Guest::createObject
 
             See :func:`create_instance` for a list of available options.
@@ -339,11 +339,14 @@ def _generate_create_dict(
             "hostname": hostname,
             "domain": domain,
             "localDiskFlag": local_disk,
-            "hourlyBillingFlag": hourly
+            "hourlyBillingFlag": hourly,
+            "supplementalCreateObjectOptions": {
+                "bootMode": boot_mode
+            }
         }
 
         if flavor:
-            data["supplementalCreateObjectOptions"] = {"flavorKeyName": flavor}
+            data["supplementalCreateObjectOptions"]["flavorKeyName"] = flavor
 
         if dedicated and not host_id:
             data["dedicatedAccountHostOnlyFlag"] = dedicated


Test patch:
diff --git a/tests/CLI/modules/order_tests.py b/tests/CLI/modules/order_tests.py
index 3d049912..0f35af22 100644
--- a/tests/CLI/modules/order_tests.py
+++ b/tests/CLI/modules/order_tests.py
@@ -47,50 +47,17 @@ def test_item_list(self):
         self.assertEqual(expected_results, json.loads(result.output))
 
     def test_package_list(self):
-        item1 = {'name': 'package1', 'keyName': 'PACKAGE1', 'type': {'keyName': 'BARE_METAL_CPU'}, 'isActive': 1}
-        item2 = {'name': 'package2', 'keyName': 'PACKAGE2', 'type': {'keyName': 'BARE_METAL_CPU'}, 'isActive': 1}
-        item3 = {'name': 'package2', 'keyName': 'PACKAGE2', 'type': {'keyName': 'BARE_METAL_CPU'}, 'isActive': 0}
-        p_mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects')
-        p_mock.return_value = [item1, item2, item3]
-        _filter = {'type': {'keyName': {'operation': '!= BLUEMIX_SERVICE'}}}
-
-        result = self.run_command(['order', 'package-list'])
-
-        self.assert_no_fail(result)
-        self.assert_called_with('SoftLayer_Product_Package', 'getAllObjects', filter=_filter)
-        expected_results = [{'name': 'package1', 'keyName': 'PACKAGE1', 'type': 'BARE_METAL_CPU'},
-                            {'name': 'package2', 'keyName': 'PACKAGE2', 'type': 'BARE_METAL_CPU'}]
-        self.assertEqual(expected_results, json.loads(result.output))
-
-    def test_package_list_keyword(self):
-        item1 = {'name': 'package1', 'keyName': 'PACKAGE1', 'type': {'keyName': 'BARE_METAL_CPU'}, 'isActive': 1}
-        item2 = {'name': 'package2', 'keyName': 'PACKAGE2', 'type': {'keyName': 'BARE_METAL_CPU'}, 'isActive': 1}
+        item1 = {'name': 'package1', 'keyName': 'PACKAGE1', 'isActive': 1}
+        item2 = {'name': 'package2', 'keyName': 'PACKAGE2', 'isActive': 1}
         p_mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects')
         p_mock.return_value = [item1, item2]
 
-        _filter = {'type': {'keyName': {'operation': '!= BLUEMIX_SERVICE'}}}
-        _filter['name'] = {'operation': '*= package1'}
-        result = self.run_command(['order', 'package-list', '--keyword', 'package1'])
-
-        self.assert_no_fail(result)
-        self.assert_called_with('SoftLayer_Product_Package', 'getAllObjects', filter=_filter)
-        expected_results = [{'name': 'package1', 'keyName': 'PACKAGE1', 'type': 'BARE_METAL_CPU'},
-                            {'name': 'package2', 'keyName': 'PACKAGE2', 'type': 'BARE_METAL_CPU'}]
-        self.assertEqual(expected_results, json.loads(result.output))
-
-    def test_package_list_type(self):
-        item1 = {'name': 'package1', 'keyName': 'PACKAGE1', 'type': {'keyName': 'BARE_METAL_CPU'}, 'isActive': 1}
-        item2 = {'name': 'package2', 'keyName': 'PACKAGE2', 'type': {'keyName': 'BARE_METAL_CPU'}, 'isActive': 1}
-        p_mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects')
-        p_mock.return_value = [item1, item2]
-
-        _filter = {'type': {'keyName': {'operation': 'BARE_METAL_CPU'}}}
-        result = self.run_command(['order', 'package-list', '--package_type', 'BARE_METAL_CPU'])
+        result = self.run_command(['order', 'package-list'])
 
         self.assert_no_fail(result)
-        self.assert_called_with('SoftLayer_Product_Package', 'getAllObjects', filter=_filter)
-        expected_results = [{'name': 'package1', 'keyName': 'PACKAGE1', 'type': 'BARE_METAL_CPU'},
-                            {'name': 'package2', 'keyName': 'PACKAGE2', 'type': 'BARE_METAL_CPU'}]
+        self.assert_called_with('SoftLayer_Product_Package', 'getAllObjects')
+        expected_results = [{'name': 'package1', 'keyName': 'PACKAGE1'},
+                            {'name': 'package2', 'keyName': 'PACKAGE2'}]
         self.assertEqual(expected_results, json.loads(result.output))
 
     def test_place(self):
diff --git a/tests/CLI/modules/sshkey_tests.py b/tests/CLI/modules/sshkey_tests.py
index 253309c0..e0e79b4c 100644
--- a/tests/CLI/modules/sshkey_tests.py
+++ b/tests/CLI/modules/sshkey_tests.py
@@ -11,25 +11,10 @@
 
 import mock
 
-from SoftLayer.CLI import exceptions
 from SoftLayer import testing
 
 
 class SshKeyTests(testing.TestCase):
-    def test_add_without_key_errors(self):
-        result = self.run_command(['sshkey', 'add', 'key1'])
-
-        self.assertEqual(result.exit_code, 2)
-        self.assertIsInstance(result.exception, exceptions.ArgumentError)
-
-    def test_add_with_key_file_and_key_argument_errors(self):
-        path = os.path.join(testing.FIXTURE_PATH, 'id_rsa.pub')
-        result = self.run_command(['sshkey', 'add', 'key1',
-                                   '--key=some_key',
-                                   '--in-file=%s' % path])
-
-        self.assertEqual(result.exit_code, 2)
-        self.assertIsInstance(result.exception, exceptions.ArgumentError)
 
     def test_add_by_option(self):
         service = self.client['Security_Ssh_Key']
diff --git a/tests/CLI/modules/vs_tests.py b/tests/CLI/modules/vs_tests.py
index e9b8cf46..660860cd 100644
--- a/tests/CLI/modules/vs_tests.py
+++ b/tests/CLI/modules/vs_tests.py
@@ -161,7 +161,8 @@ def test_create(self, confirm_mock):
                  'hostname': 'host',
                  'startCpus': 2,
                  'operatingSystemReferenceCode': 'UBUNTU_LATEST',
-                 'networkComponents': [{'maxSpeed': '100'}]},)
+                 'networkComponents': [{'maxSpeed': '100'}],
+                 'supplementalCreateObjectOptions': {'bootMode': None}},)
         self.assert_called_with('SoftLayer_Virtual_Guest', 'createObject',
                                 args=args)
 
@@ -195,7 +196,8 @@ def test_create_with_integer_image_id(self, confirm_mock):
             'blockDeviceTemplateGroup': {
                 'globalIdentifier': '0B5DEAF4-643D-46CA-A695-CECBE8832C9D',
             },
-            'networkComponents': [{'maxSpeed': '100'}]
+            'networkComponents': [{'maxSpeed': '100'}],
+            'supplementalCreateObjectOptions': {'bootMode': None}
         },)
         self.assert_called_with('SoftLayer_Virtual_Guest', 'createObject',
                                 args=args)
@@ -225,7 +227,9 @@ def test_create_with_flavor(self, confirm_mock):
                  'startCpus': None,
                  'maxMemory': None,
                  'localDiskFlag': None,
-                 'supplementalCreateObjectOptions': {'flavorKeyName': 'B1_1X2X25'},
+                 'supplementalCreateObjectOptions': {
+                     'bootMode': None,
+                     'flavorKeyName': 'B1_1X2X25'},
                  'operatingSystemReferenceCode': 'UBUNTU_LATEST',
                  'networkComponents': [{'maxSpeed': '100'}]},)
         self.assert_called_with('SoftLayer_Virtual_Guest', 'createObject',
@@ -261,7 +265,8 @@ def test_create_with_host_id(self, confirm_mock):
                  'startCpus': 2,
                  'operatingSystemReferenceCode': 'UBUNTU_LATEST',
                  'networkComponents': [{'maxSpeed': '100'}],
-                 'dedicatedHost': {'id': 123}},)
+                 'dedicatedHost': {'id': 123},
+                 'supplementalCreateObjectOptions': {'bootMode': None}},)
         self.assert_called_with('SoftLayer_Virtual_Guest', 'createObject',
                                 args=args)
 
@@ -306,7 +311,8 @@ def test_create_like(self, confirm_mock):
                  'maxMemory': 1024,
                  'localDiskFlag': False,
                  'operatingSystemReferenceCode': 'UBUNTU_LATEST',
-                 'networkComponents': [{'maxSpeed': 100}]},)
+                 'networkComponents': [{'maxSpeed': 100}],
+                 'supplementalCreateObjectOptions': {'bootMode': None}},)
         self.assert_called_with('SoftLayer_Virtual_Guest', 'createObject',
                                 args=args)
 
@@ -347,7 +353,9 @@ def test_create_like_flavor(self, confirm_mock):
                  'startCpus': None,
                  'maxMemory': None,
                  'localDiskFlag': None,
-                 'supplementalCreateObjectOptions': {'flavorKeyName': 'B1_1X2X25'},
+                 'supplementalCreateObjectOptions': {
+                     'bootMode': None,
+                     'flavorKeyName': 'B1_1X2X25'},
                  'operatingSystemReferenceCode': 'UBUNTU_LATEST',
                  'networkComponents': [{'maxSpeed': 100}]},)
         self.assert_called_with('SoftLayer_Virtual_Guest', 'createObject',
diff --git a/tests/managers/network_tests.py b/tests/managers/network_tests.py
index 7a84beba..cf38e730 100644
--- a/tests/managers/network_tests.py
+++ b/tests/managers/network_tests.py
@@ -244,23 +244,6 @@ def test_edit_securitygroup_rule(self):
                                 args=([{'id': 500,
                                         'direction': 'ingress'}],))
 
-    def test_edit_securitygroup_rule_unset(self):
-        # Test calling edit rule with falsy values, which are used
-        # to unset those values in the API
-        result = self.network.edit_securitygroup_rule(100, 500,
-                                                      protocol='',
-                                                      port_min=-1,
-                                                      port_max=-1,
-                                                      ethertype='',
-                                                      remote_ip='')
-
-        self.assertTrue(result)
-        self.assert_called_with('SoftLayer_Network_SecurityGroup',
-                                'editRules', identifier=100,
-                                args=([{'id': 500, 'protocol': '',
-                                        'portRangeMin': -1, 'portRangeMax': -1,
-                                        'ethertype': '', 'remoteIp': ''}],))
-
     def test_get_rwhois(self):
         result = self.network.get_rwhois()
 
diff --git a/tests/managers/vs_tests.py b/tests/managers/vs_tests.py
index e36de7ac..b3b57eb3 100644
--- a/tests/managers/vs_tests.py
+++ b/tests/managers/vs_tests.py
@@ -192,7 +192,8 @@ def test_create_instances(self):
                   'localDiskFlag': True,
                   'maxMemory': 1024,
                   'hostname': 'server',
-                  'startCpus': 1}],)
+                  'startCpus': 1,
+                  'supplementalCreateObjectOptions': {'bootMode': None}}],)
         self.assert_called_with('SoftLayer_Virtual_Guest', 'createObjects',
                                 args=args)
         self.assert_called_with('SoftLayer_Virtual_Guest', 'setTags',
@@ -232,6 +233,7 @@ def test_generate_basic(self):
             'localDiskFlag': True,
             'operatingSystemReferenceCode': "STRING",
             'hourlyBillingFlag': True,
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -254,6 +256,7 @@ def test_generate_monthly(self):
             'domain': 'example.com',
             'localDiskFlag': True,
             'operatingSystemReferenceCode': "STRING",
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -275,6 +278,7 @@ def test_generate_image_id(self):
             'localDiskFlag': True,
             'blockDeviceTemplateGroup': {"globalIdentifier": "45"},
             'hourlyBillingFlag': True,
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -298,6 +302,7 @@ def test_generate_dedicated(self):
             'operatingSystemReferenceCode': "STRING",
             'hourlyBillingFlag': True,
             'dedicatedAccountHostOnlyFlag': True,
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -321,6 +326,7 @@ def test_generate_datacenter(self):
             'operatingSystemReferenceCode': "STRING",
             'hourlyBillingFlag': True,
             'datacenter': {"name": 'sng01'},
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -344,6 +350,7 @@ def test_generate_public_vlan(self):
             'operatingSystemReferenceCode': "STRING",
             'hourlyBillingFlag': True,
             'primaryNetworkComponent': {"networkVlan": {"id": 1}},
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -367,6 +374,7 @@ def test_generate_private_vlan(self):
             'operatingSystemReferenceCode': "STRING",
             'hourlyBillingFlag': True,
             'primaryBackendNetworkComponent': {"networkVlan": {"id": 1}},
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -390,6 +398,7 @@ def test_generate_userdata(self):
             'operatingSystemReferenceCode': "STRING",
             'hourlyBillingFlag': True,
             'userData': [{'value': "ICANHAZVSI"}],
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -413,6 +422,7 @@ def test_generate_network(self):
             'operatingSystemReferenceCode': "STRING",
             'hourlyBillingFlag': True,
             'networkComponents': [{'maxSpeed': 9001}],
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -438,6 +448,7 @@ def test_generate_private_network_only(self):
             'privateNetworkOnlyFlag': True,
             'hourlyBillingFlag': True,
             'networkComponents': [{'maxSpeed': 9001}],
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -461,6 +472,7 @@ def test_generate_post_uri(self):
             'operatingSystemReferenceCode': "STRING",
             'hourlyBillingFlag': True,
             'postInstallScriptUri': 'https://example.com/boostrap.sh',
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -484,6 +496,7 @@ def test_generate_sshkey(self):
             'operatingSystemReferenceCode': "STRING",
             'hourlyBillingFlag': True,
             'sshKeys': [{'id': 543}],
+            'supplementalCreateObjectOptions': {'bootMode': None},
         }
 
         self.assertEqual(data, assert_data)
@@ -537,6 +550,29 @@ def test_generate_multi_disk(self):
         self.assertTrue(data.get('blockDevices'))
         self.assertEqual(data['blockDevices'], assert_data['blockDevices'])
 
+    def test_generate_boot_mode(self):
+        data = self.vs._generate_create_dict(
+            cpus=1,
+            memory=1,
+            hostname='test',
+            domain='example.com',
+            os_code="STRING",
+            boot_mode="HVM"
+        )
+
+        assert_data = {
+            'startCpus': 1,
+            'maxMemory': 1,
+            'hostname': 'test',
+            'domain': 'example.com',
+            'localDiskFlag': True,
+            'operatingSystemReferenceCode': "STRING",
+            'hourlyBillingFlag': True,
+            'supplementalCreateObjectOptions': {'bootMode': 'HVM'},
+        }
+
+        self.assertEqual(data, assert_data)
+
     def test_change_port_speed_public(self):
         result = self.vs.change_port_speed(1, True, 100)