diff --git a/SoftLayer/CLI/virt/create.py b/SoftLayer/CLI/virt/create.py index 4bb3427f0..a0997704e 100644 --- a/SoftLayer/CLI/virt/create.py +++ b/SoftLayer/CLI/virt/create.py @@ -133,6 +133,10 @@ def _parse_create_args(client, args): if args.get('vlan_private'): data['private_vlan'] = args['vlan_private'] + data['public_subnet'] = args.get('subnet_public', None) + + data['private_subnet'] = args.get('subnet_private', None) + if args.get('public_security_group'): pub_groups = args.get('public_security_group') data['public_security_groups'] = [group for group in pub_groups] @@ -225,12 +229,18 @@ def _parse_create_args(client, args): type=click.Path(exists=True, readable=True, resolve_path=True)) @click.option('--vlan-public', help="The ID of the public VLAN on which you want the virtual " - "server placed", + "server placed", type=click.INT) @click.option('--vlan-private', help="The ID of the private VLAN on which you want the virtual " "server placed", type=click.INT) +@click.option('--subnet-public', + help="The ID of the public SUBNET on which you want the virtual server placed", + type=click.INT) +@click.option('--subnet-private', + help="The ID of the private SUBNET on which you want the virtual server placed", + type=click.INT) @helpers.multi_option('--public-security-group', '-S', help=('Security group ID to associate with ' diff --git a/SoftLayer/managers/vs.py b/SoftLayer/managers/vs.py index 7f9e56abe..eed533a02 100644 --- a/SoftLayer/managers/vs.py +++ b/SoftLayer/managers/vs.py @@ -16,8 +16,9 @@ from SoftLayer.managers import ordering from SoftLayer import utils - LOGGER = logging.getLogger(__name__) + + # pylint: disable=no-self-use @@ -305,6 +306,7 @@ def _generate_create_dict( hostname=None, domain=None, local_disk=True, datacenter=None, os_code=None, image_id=None, dedicated=False, public_vlan=None, private_vlan=None, + private_subnet=None, public_subnet=None, userdata=None, nic_speed=None, disks=None, post_uri=None, private=False, ssh_keys=None, public_security_groups=None, private_security_groups=None, boot_mode=None, **kwargs): @@ -365,14 +367,10 @@ def _generate_create_dict( if datacenter: data["datacenter"] = {"name": datacenter} - if public_vlan: - data.update({ - 'primaryNetworkComponent': { - "networkVlan": {"id": int(public_vlan)}}}) - if private_vlan: - data.update({ - "primaryBackendNetworkComponent": { - "networkVlan": {"id": int(private_vlan)}}}) + if private_vlan or public_vlan or private_subnet or public_subnet: + network_components = self._create_network_components(public_vlan, private_vlan, + private_subnet, public_subnet) + data.update(network_components) if public_security_groups: secgroups = [{'securityGroup': {'id': int(sg)}} @@ -415,6 +413,29 @@ def _generate_create_dict( return data + def _create_network_components( + self, public_vlan=None, private_vlan=None, + private_subnet=None, public_subnet=None): + + parameters = {} + if private_vlan: + parameters['primaryBackendNetworkComponent'] = {"networkVlan": {"id": int(private_vlan)}} + if public_vlan: + parameters['primaryNetworkComponent'] = {"networkVlan": {"id": int(public_vlan)}} + if public_subnet: + if public_vlan is None: + raise exceptions.SoftLayerError("You need to specify a public_vlan with public_subnet") + else: + parameters['primaryNetworkComponent']['networkVlan']['primarySubnet'] = {'id': int(public_subnet)} + if private_subnet: + if private_vlan is None: + raise exceptions.SoftLayerError("You need to specify a private_vlan with private_subnet") + else: + parameters['primaryBackendNetworkComponent']['networkVlan']['primarySubnet'] = { + "id": int(private_subnet)} + + return parameters + @retry(logger=LOGGER) def wait_for_transaction(self, instance_id, limit, delay=10): """Waits on a VS transaction for the specified amount of time. diff --git a/tests/CLI/modules/vs_tests.py b/tests/CLI/modules/vs_tests.py index c7ce60be8..ae643c834 100644 --- a/tests/CLI/modules/vs_tests.py +++ b/tests/CLI/modules/vs_tests.py @@ -337,6 +337,31 @@ def test_create(self, confirm_mock): self.assert_called_with('SoftLayer_Virtual_Guest', 'createObject', args=args) + @mock.patch('SoftLayer.CLI.formatting.confirm') + def test_create_vlan_subnet(self, confirm_mock): + confirm_mock.return_value = True + + result = self.run_command(['vs', 'create', + '--cpu=2', + '--domain=example.com', + '--hostname=host', + '--os=UBUNTU_LATEST', + '--memory=1', + '--billing=hourly', + '--datacenter=dal05', + '--vlan-private=577940', + '--subnet-private=478700', + '--vlan-public=1639255', + '--subnet-public=297614', + '--tag=dev', + '--tag=green']) + + self.assert_no_fail(result) + self.assertEqual(json.loads(result.output), + {'guid': '1a2b3c-1701', + 'id': 100, + 'created': '2013-08-01 15:23:45'}) + @mock.patch('SoftLayer.CLI.formatting.confirm') def test_create_with_wait_ready(self, confirm_mock): mock = self.set_mock('SoftLayer_Virtual_Guest', 'getObject') diff --git a/tests/managers/vs_tests.py b/tests/managers/vs_tests.py index 7f4592ea1..456b5cbc3 100644 --- a/tests/managers/vs_tests.py +++ b/tests/managers/vs_tests.py @@ -355,6 +355,116 @@ def test_generate_public_vlan(self): self.assertEqual(data, assert_data) + def test_generate_public_vlan_with_public_subnet(self): + data = self.vs._generate_create_dict( + cpus=1, + memory=1, + hostname='test', + domain='example.com', + os_code="STRING", + public_vlan=1, + public_subnet=1 + ) + + assert_data = { + 'startCpus': 1, + 'maxMemory': 1, + 'hostname': 'test', + 'domain': 'example.com', + 'localDiskFlag': True, + 'operatingSystemReferenceCode': "STRING", + 'hourlyBillingFlag': True, + 'primaryNetworkComponent': {'networkVlan': {'id': 1, + 'primarySubnet': {'id': 1}}}, + 'supplementalCreateObjectOptions': {'bootMode': None}, + } + + self.assertEqual(data, assert_data) + + def test_generate_private_vlan_with_private_subnet(self): + data = self.vs._generate_create_dict( + cpus=1, + memory=1, + hostname='test', + domain='example.com', + os_code="STRING", + private_vlan=1, + private_subnet=1 + ) + + assert_data = { + 'startCpus': 1, + 'maxMemory': 1, + 'hostname': 'test', + 'domain': 'example.com', + 'localDiskFlag': True, + 'operatingSystemReferenceCode': "STRING", + 'hourlyBillingFlag': True, + 'primaryBackendNetworkComponent': {'networkVlan': {'id': 1, + 'primarySubnet': {'id': 1}}}, + 'supplementalCreateObjectOptions': {'bootMode': None}, + } + + self.assertEqual(data, assert_data) + + def test_generate_private_vlan_subnet_public_vlan_subnet(self): + data = self.vs._generate_create_dict( + cpus=1, + memory=1, + hostname='test', + domain='example.com', + os_code="STRING", + private_vlan=1, + private_subnet=1, + public_vlan=1, + public_subnet=1, + ) + + assert_data = { + 'startCpus': 1, + 'maxMemory': 1, + 'hostname': 'test', + 'domain': 'example.com', + 'localDiskFlag': True, + 'operatingSystemReferenceCode': "STRING", + 'hourlyBillingFlag': True, + 'primaryBackendNetworkComponent': {'networkVlan': {'id': 1, + 'primarySubnet': {'id': 1}}}, + 'primaryNetworkComponent': {'networkVlan': {'id': 1, + 'primarySubnet': {'id': 1}}}, + 'supplementalCreateObjectOptions': {'bootMode': None}, + } + + self.assertEqual(data, assert_data) + + def test_generate_private_subnet(self): + actual = self.assertRaises( + exceptions.SoftLayerError, + self.vs._generate_create_dict, + cpus=1, + memory=1, + hostname='test', + domain='example.com', + os_code="STRING", + private_subnet=1, + ) + + self.assertEqual(str(actual), "You need to specify a private_vlan with private_subnet") + + def test_generate_public_subnet(self): + actual = self.assertRaises( + exceptions.SoftLayerError, + self.vs._generate_create_dict, + cpus=1, + memory=1, + hostname='test', + domain='example.com', + os_code="STRING", + public_subnet=1, + ) + + self.assertEqual(str(actual), "You need to specify a public_vlan with public_subnet") + def test_generate_private_vlan(self): data = self.vs._generate_create_dict( cpus=1, @@ -373,12 +483,73 @@ def test_generate_private_vlan(self): 'localDiskFlag': True, 'operatingSystemReferenceCode': "STRING", 'hourlyBillingFlag': True, - 'primaryBackendNetworkComponent': {"networkVlan": {"id": 1}}, + 'primaryBackendNetworkComponent': {'networkVlan': {'id': 1}}, 'supplementalCreateObjectOptions': {'bootMode': None}, } self.assertEqual(data, assert_data) + def test_create_network_components_vlan_subnet_private_vlan_subnet_public(self): + data = self.vs._create_network_components( + private_vlan=1, + private_subnet=1, + public_vlan=1, + public_subnet=1, + ) + + assert_data = { + 'primaryBackendNetworkComponent': {'networkVlan': {'id': 1, + 'primarySubnet': {'id': 1}}}, + 'primaryNetworkComponent': {'networkVlan': {'id': 1, + 'primarySubnet': {'id': 1}}}, + } + + self.assertEqual(data, assert_data) + + def test_create_network_components_vlan_subnet_private(self): + data = self.vs._create_network_components( + private_vlan=1, + private_subnet=1, + ) + + assert_data = { + 'primaryBackendNetworkComponent': {'networkVlan': {'id': 1, + 'primarySubnet': {'id': 1}}}, + } + + self.assertEqual(data, assert_data) + + def test_create_network_components_vlan_subnet_public(self): + data = self.vs._create_network_components( + public_vlan=1, + public_subnet=1, + ) + + assert_data = { + 'primaryNetworkComponent': {'networkVlan': {'id': 1, + 'primarySubnet': {'id': 1}}}, + } + + self.assertEqual(data, assert_data) + + def test_create_network_components_private_subnet(self): + actual = self.assertRaises( + exceptions.SoftLayerError, + self.vs._create_network_components, + private_subnet=1, + ) + + self.assertEqual(str(actual), "You need to specify a private_vlan with private_subnet") + + def test_create_network_components_public_subnet(self): + actual = self.assertRaises( + exceptions.SoftLayerError, + self.vs._create_network_components, + public_subnet=1, + ) + + self.assertEqual(str(actual), "You need to specify a public_vlan with public_subnet") + def test_generate_userdata(self): data = self.vs._generate_create_dict( cpus=1, @@ -621,10 +792,10 @@ def test_edit_full(self): self.assertEqual(result, True) args = ({ - 'hostname': 'new-host', - 'domain': 'new.sftlyr.ws', - 'notes': 'random notes', - },) + 'hostname': 'new-host', + 'domain': 'new.sftlyr.ws', + 'notes': 'random notes', + },) self.assert_called_with('SoftLayer_Virtual_Guest', 'editObject', identifier=100, args=args)