diff --git a/SoftLayer/CLI/hardware/guests.py b/SoftLayer/CLI/hardware/guests.py new file mode 100644 index 000000000..238897e84 --- /dev/null +++ b/SoftLayer/CLI/hardware/guests.py @@ -0,0 +1,40 @@ +"""Lists the Virtual Guests running on this server.""" +# :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 helpers +from SoftLayer import utils + + +@click.command() +@click.argument('identifier') +@environment.pass_env +def cli(env, identifier): + """Lists the Virtual Guests running on this server.""" + + mgr = SoftLayer.HardwareManager(env.client) + hw_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'hardware') + hw_guests = mgr.get_hardware_guests(hw_id) + + if not hw_guests: + raise exceptions.CLIAbort("No Virtual Guests found.") + + table = formatting.Table(['id', 'hostname', 'CPU', 'Memory', 'Start Date', 'Status', 'powerState']) + table.sortby = 'hostname' + for guest in hw_guests: + table.add_row([ + guest['id'], + guest['hostname'], + '%i %s' % (guest['maxCpu'], guest['maxCpuUnits']), + guest['maxMemory'], + utils.clean_time(guest['createDate']), + guest['status']['keyName'], + guest['powerState']['keyName'] + ]) + + env.fout(table) diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py index 049b43c3b..a84de0157 100644 --- a/SoftLayer/CLI/routes.py +++ b/SoftLayer/CLI/routes.py @@ -236,6 +236,7 @@ ('hardware:detail', 'SoftLayer.CLI.hardware.detail:cli'), ('hardware:billing', 'SoftLayer.CLI.hardware.billing:cli'), ('hardware:edit', 'SoftLayer.CLI.hardware.edit:cli'), + ('hardware:guests', 'SoftLayer.CLI.hardware.guests:cli'), ('hardware:list', 'SoftLayer.CLI.hardware.list:cli'), ('hardware:power-cycle', 'SoftLayer.CLI.hardware.power:power_cycle'), ('hardware:power-off', 'SoftLayer.CLI.hardware.power:power_off'), diff --git a/SoftLayer/CLI/virt/list.py b/SoftLayer/CLI/virt/list.py index 6bf9e6bb6..1a3c4d545 100644 --- a/SoftLayer/CLI/virt/list.py +++ b/SoftLayer/CLI/virt/list.py @@ -8,7 +8,7 @@ from SoftLayer.CLI import environment from SoftLayer.CLI import formatting from SoftLayer.CLI import helpers - +from SoftLayer import utils # pylint: disable=unnecessary-lambda @@ -93,3 +93,22 @@ def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network, for value in columns.row(guest)]) env.fout(table) + + hardware_guests = vsi.get_hardware_guests() + for hardware in hardware_guests: + if hardware['virtualHost']['guests']: + title = "Hardware(id = {hardwareId}) guests associated".format(hardwareId=hardware['id']) + table_hardware_guest = formatting.Table(['id', 'hostname', 'CPU', 'Memory', 'Start Date', 'Status', + 'powerState'], title=title) + table_hardware_guest.sortby = 'hostname' + for guest in hardware['virtualHost']['guests']: + table_hardware_guest.add_row([ + guest['id'], + guest['hostname'], + '%i %s' % (guest['maxCpu'], guest['maxCpuUnits']), + guest['maxMemory'], + utils.clean_time(guest['createDate']), + guest['status']['keyName'], + guest['powerState']['keyName'] + ]) + env.fout(table_hardware_guest) diff --git a/SoftLayer/fixtures/SoftLayer_Account.py b/SoftLayer/fixtures/SoftLayer_Account.py index 95692ef00..dcb6d32f0 100644 --- a/SoftLayer/fixtures/SoftLayer_Account.py +++ b/SoftLayer/fixtures/SoftLayer_Account.py @@ -146,6 +146,28 @@ 'id': 6660 } }, + "virtualHost": { + "accountId": 11111, + "id": 22222, + "name": "vmware.chechu.com", + "guests": [ + { + "accountId": 11111, + "createDate": "2019-09-05T17:03:42-06:00", + "hostname": "NSX-T Manager", + "id": 33333, + "maxCpu": 16, + "maxCpuUnits": "CORE", + "maxMemory": 49152, + "powerState": { + "keyName": "RUNNING", + "name": "Running" + }, + "status": { + "keyName": "ACTIVE", + "name": "Active" + } + }]} }, { 'id': 1001, 'metricTrackingObject': {'id': 4}, @@ -190,7 +212,13 @@ 'vlanNumber': 3672, 'id': 19082 }, - ] + ], + "virtualHost": { + "accountId": 11111, + "id": 22222, + "name": "host14.vmware.chechu.com", + "guests": [] + } }, { 'id': 1002, 'metricTrackingObject': {'id': 5}, @@ -234,9 +262,21 @@ 'vlanNumber': 3672, 'id': 19082 }, - ] + ], + "virtualHost": { + "accountId": 11111, + "id": 22222, + "name": "host14.vmware.chechu.com", + "guests": [] + } }, { 'id': 1003, + "virtualHost": { + "accountId": 11111, + "id": 22222, + "name": "host14.vmware.chechu.com", + "guests": [] + } }] getDomains = [{'name': 'example.com', 'id': 12345, diff --git a/SoftLayer/fixtures/SoftLayer_Hardware_Server.py b/SoftLayer/fixtures/SoftLayer_Hardware_Server.py index e90288753..5c26d20da 100644 --- a/SoftLayer/fixtures/SoftLayer_Hardware_Server.py +++ b/SoftLayer/fixtures/SoftLayer_Hardware_Server.py @@ -242,3 +242,23 @@ } } ] + +getVirtualHost = { + "accountId": 11111, + "createDate": "2018-10-08T10:54:48-06:00", + "description": "host16.vmware.chechu.com", + "hardwareId": 22222, + "id": 33333, + "name": "host16.vmware.chechu.com", + "uuid": "00000000-0000-0000-0000-0cc11111", + "hardware": { + "accountId": 11111, + "domain": "chechu.com", + "hostname": "host16.vmware", + "id": 22222, + "hardwareStatus": { + "id": 5, + "status": "ACTIVE" + } + } +} diff --git a/SoftLayer/fixtures/SoftLayer_Virtual_Host.py b/SoftLayer/fixtures/SoftLayer_Virtual_Host.py new file mode 100644 index 000000000..c5b20a34b --- /dev/null +++ b/SoftLayer/fixtures/SoftLayer_Virtual_Host.py @@ -0,0 +1,40 @@ +getGuests = [ + { + "accountId": 11111, + "createDate": "2019-09-05T17:03:42-06:00", + "fullyQualifiedDomainName": "NSX-T Manager", + "hostname": "NSX-T Manager", + "id": 22222, + "maxCpu": 16, + "maxCpuUnits": "CORE", + "maxMemory": 49152, + "startCpus": 16, + "powerState": { + "keyName": "RUNNING", + "name": "Running" + }, + "status": { + "keyName": "ACTIVE", + "name": "Active" + } + }, + { + "accountId": 11111, + "createDate": "2019-09-23T06:00:53-06:00", + "hostname": "NSX-T Manager2", + "id": 33333, + "maxCpu": 12, + "maxCpuUnits": "CORE", + "maxMemory": 49152, + "startCpus": 12, + "statusId": 1001, + "powerState": { + "keyName": "RUNNING", + "name": "Running" + }, + "status": { + "keyName": "ACTIVE", + "name": "Active" + } + } +] diff --git a/SoftLayer/managers/hardware.py b/SoftLayer/managers/hardware.py index 956d33e3a..1c2a097f1 100644 --- a/SoftLayer/managers/hardware.py +++ b/SoftLayer/managers/hardware.py @@ -728,6 +728,18 @@ def get_hard_drives(self, instance_id): """ return self.hardware.getHardDrives(id=instance_id) + def get_hardware_guests(self, instance_id): + """Returns the hardware server guests. + + :param int instance_id: Id of the hardware server. + """ + mask = "mask[id]" + virtual_host = self.hardware.getVirtualHost(mask=mask, id=instance_id) + if virtual_host: + return self.client.call('SoftLayer_Virtual_Host', 'getGuests', mask='mask[powerState]', + id=virtual_host['id']) + return virtual_host + def _get_bandwidth_key(items, hourly=True, no_public=False, location=None): """Picks a valid Bandwidth Item, returns the KeyName""" diff --git a/SoftLayer/managers/vs.py b/SoftLayer/managers/vs.py index e63d7a80f..a322c78a1 100644 --- a/SoftLayer/managers/vs.py +++ b/SoftLayer/managers/vs.py @@ -1158,3 +1158,12 @@ def get_local_disks(self, instance_id): """ mask = 'mask[diskImage]' return self.guest.getBlockDevices(mask=mask, id=instance_id) + + def get_hardware_guests(self): + """Returns all virtualHost capable hardware objects and their guests. + + :return SoftLayer_Hardware[]. + """ + object_filter = {"hardware": {"virtualHost": {"id": {"operation": "not null"}}}} + mask = "mask[virtualHost[guests[powerState]]]" + return self.client.call('SoftLayer_Account', 'getHardware', mask=mask, filter=object_filter) diff --git a/docs/cli/hardware.rst b/docs/cli/hardware.rst index 5ca325cb7..f7691e700 100644 --- a/docs/cli/hardware.rst +++ b/docs/cli/hardware.rst @@ -115,3 +115,7 @@ This function updates the firmware of a server. If already at the latest version .. click:: SoftLayer.CLI.hardware.storage:cli :prog: hardware storage :show-nested: + +.. click:: SoftLayer.CLI.hardware.guests:cli + :prog: hardware guests + :show-nested: diff --git a/tests/CLI/modules/server_tests.py b/tests/CLI/modules/server_tests.py index f11d9d0a6..4ef1a7354 100644 --- a/tests/CLI/modules/server_tests.py +++ b/tests/CLI/modules/server_tests.py @@ -852,3 +852,15 @@ def test_create_hw_no_confirm(self, confirm_mock): '--network=TEST_NETWORK', '--os=UBUNTU_12_64']) self.assertEqual(result.exit_code, 2) + + def test_get_hardware_guests(self): + result = self.run_command(['hw', 'guests', '123456']) + self.assert_no_fail(result) + + def test_hardware_guests_empty(self): + mock = self.set_mock('SoftLayer_Virtual_Host', 'getGuests') + mock.return_value = None + + result = self.run_command(['hw', 'guests', '123456']) + self.assertEqual(result.exit_code, 2) + self.assertIsInstance(result.exception, exceptions.CLIAbort) diff --git a/tests/CLI/modules/vs/vs_tests.py b/tests/CLI/modules/vs/vs_tests.py index a4bf28509..783b52743 100644 --- a/tests/CLI/modules/vs/vs_tests.py +++ b/tests/CLI/modules/vs/vs_tests.py @@ -143,19 +143,6 @@ def test_list_vs(self): result = self.run_command(['vs', 'list', '--tag=tag']) self.assert_no_fail(result) - self.assertEqual(json.loads(result.output), - [{'datacenter': 'TEST00', - 'primary_ip': '172.16.240.2', - 'hostname': 'vs-test1', - 'action': None, - 'id': 100, - 'backend_ip': '10.45.19.37'}, - {'datacenter': 'TEST00', - 'primary_ip': '172.16.240.7', - 'hostname': 'vs-test2', - 'action': None, - 'id': 104, - 'backend_ip': '10.45.19.35'}]) @mock.patch('SoftLayer.utils.lookup') def test_detail_vs_empty_billing(self, mock_lookup): diff --git a/tests/managers/hardware_tests.py b/tests/managers/hardware_tests.py index a61aeece0..e98c57492 100644 --- a/tests/managers/hardware_tests.py +++ b/tests/managers/hardware_tests.py @@ -626,6 +626,38 @@ def test_get_hard_drive_empty(self): self.assertEqual([], result) + def test_get_hardware_guests_empty_virtualHost(self): + mock = self.set_mock('SoftLayer_Hardware_Server', 'getVirtualHost') + mock.return_value = None + + result = self.hardware.get_hardware_guests(1234) + + self.assertEqual(None, result) + + def test_get_hardware_guests(self): + mock = self.set_mock('SoftLayer_Virtual_Host', 'getGuests') + mock.return_value = [ + { + "accountId": 11111, + "hostname": "NSX-T Manager", + "id": 22222, + "maxCpu": 16, + "maxCpuUnits": "CORE", + "maxMemory": 49152, + "powerState": { + "keyName": "RUNNING", + "name": "Running" + }, + "status": { + "keyName": "ACTIVE", + "name": "Active" + } + }] + + result = self.hardware.get_hardware_guests(1234) + + self.assertEqual("NSX-T Manager", result[0]['hostname']) + class HardwareHelperTests(testing.TestCase): diff --git a/tests/managers/vs/vs_tests.py b/tests/managers/vs/vs_tests.py index 40fb3063f..34e07dd06 100644 --- a/tests/managers/vs/vs_tests.py +++ b/tests/managers/vs/vs_tests.py @@ -1132,3 +1132,36 @@ def test_get_local_disks_swap(self): } } ], result) + + def test_get_hardware_guests(self): + mock = self.set_mock('SoftLayer_Account', 'getHardware') + mock.return_value = [{ + "accountId": 11111, + "domain": "vmware.chechu.com", + "hostname": "host14", + "id": 22222, + "virtualHost": { + "accountId": 11111, + "id": 33333, + "name": "host14.vmware.chechu.com", + "guests": [ + { + "accountId": 11111, + "hostname": "NSX-T Manager", + "id": 44444, + "maxCpu": 16, + "maxCpuUnits": "CORE", + "maxMemory": 49152, + "powerState": { + "keyName": "RUNNING", + "name": "Running" + }, + "status": { + "keyName": "ACTIVE", + "name": "Active" + } + }]}}] + + result = self.vs.get_hardware_guests() + + self.assertEqual("NSX-T Manager", result[0]['virtualHost']['guests'][0]['hostname'])