diff --git a/SoftLayer/CLI/hardware/list.py b/SoftLayer/CLI/hardware/list.py index 734f379d4..65a95718e 100644 --- a/SoftLayer/CLI/hardware/list.py +++ b/SoftLayer/CLI/hardware/list.py @@ -22,7 +22,7 @@ lambda server: formatting.active_txn(server), mask='activeTransaction[id, transactionStatus[name, friendlyName]]'), column_helper.Column( - 'created_by', + 'owner', lambda created_by: utils.lookup(created_by, 'billingItem', 'orderItem', 'order', 'userRecord', 'username'), mask='billingItem[id,orderItem[id,order[id,userRecord[username]]]]'), column_helper.Column( @@ -38,6 +38,8 @@ 'backend_ip', 'datacenter', 'action', + 'owner', + 'tags', ] @@ -48,6 +50,9 @@ @click.option('--hostname', '-H', help='Filter by hostname') @click.option('--memory', '-m', help='Filter by memory in gigabytes') @click.option('--network', '-n', help='Filter by network port speed in Mbps') +@click.option('--owner', help='Filter by created_by username') +@click.option('--primary_ip', help='Filter by Primary Ip Address') +@click.option('--backend_ip', help='Filter by Backend Ip Address') @click.option('--search', is_flag=False, flag_value="", default=None, help="Use the more flexible Search API to list instances. See `slcli search --types` for list " + "of searchable fields.") @@ -63,29 +68,41 @@ default=100, show_default=True) @environment.pass_env -def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network, search, tag, columns, limit): +def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network, owner, primary_ip, backend_ip, + search, tag, columns, limit): """List hardware servers.""" if search is not None: object_mask = "mask[resource(SoftLayer_Hardware)]" search_manager = SoftLayer.SearchManager(env.client) - servers = search_manager.search_hadrware_instances(hostname=hostname, domain=domain, datacenter=datacenter, - tags=tag, search_string=search, mask=object_mask) + servers = search_manager.search_hadrware_instances( + hostname=hostname, + domain=domain, + datacenter=datacenter, + tags=tag, + search_string=search, + mask=object_mask) else: manager = SoftLayer.HardwareManager(env.client) - servers = manager.list_hardware(hostname=hostname, - domain=domain, - cpus=cpu, - memory=memory, - datacenter=datacenter, - nic_speed=network, - tags=tag, - mask="mask(SoftLayer_Hardware_Server)[%s]" % columns.mask(), - limit=limit) + servers = manager.list_hardware( + hostname=hostname, + domain=domain, + cpus=cpu, + memory=memory, + datacenter=datacenter, + nic_speed=network, + tags=tag, + owner=owner, + public_ip=primary_ip, + private_ip=backend_ip, + mask="mask(SoftLayer_Hardware_Server)[%s]" % columns.mask(), + limit=limit) table = formatting.Table(columns.columns) table.sortby = sortby + table.align['created_by'] = 'l' + table.align['tags'] = 'l' for server in servers: table.add_row([value or formatting.blank() diff --git a/SoftLayer/managers/hardware.py b/SoftLayer/managers/hardware.py index 6564fda0f..f791ec2f4 100644 --- a/SoftLayer/managers/hardware.py +++ b/SoftLayer/managers/hardware.py @@ -121,7 +121,7 @@ def cancel_hardware(self, hardware_id, reason='unneeded', comment='', immediate= @retry(logger=LOGGER) def list_hardware(self, tags=None, cpus=None, memory=None, hostname=None, - domain=None, datacenter=None, nic_speed=None, + domain=None, datacenter=None, nic_speed=None, owner=None, public_ip=None, private_ip=None, **kwargs): """List all hardware (servers and bare metal computing instances). @@ -169,6 +169,7 @@ def list_hardware(self, tags=None, cpus=None, memory=None, hostname=None, % (','.join(hw_items), ','.join(server_items))) _filter = utils.NestedDict(kwargs.get('filter') or {}) + _filter['id'] = utils.query_filter_orderby() if tags: _filter['hardware']['tagReferences']['tag']['name'] = { 'operation': 'in', @@ -176,8 +177,7 @@ def list_hardware(self, tags=None, cpus=None, memory=None, hostname=None, } if cpus: - _filter['hardware']['processorPhysicalCoreAmount'] = ( - utils.query_filter(cpus)) + _filter['hardware']['processorPhysicalCoreAmount'] = utils.query_filter(cpus) if memory: _filter['hardware']['memoryCapacity'] = utils.query_filter(memory) @@ -189,20 +189,20 @@ def list_hardware(self, tags=None, cpus=None, memory=None, hostname=None, _filter['hardware']['domain'] = utils.query_filter(domain) if datacenter: - _filter['hardware']['datacenter']['name'] = ( - utils.query_filter(datacenter)) + _filter['hardware']['datacenter']['name'] = utils.query_filter(datacenter) if nic_speed: - _filter['hardware']['networkComponents']['maxSpeed'] = ( - utils.query_filter(nic_speed)) + _filter['hardware']['networkComponents']['maxSpeed'] = utils.query_filter(nic_speed) if public_ip: - _filter['hardware']['primaryIpAddress'] = ( - utils.query_filter(public_ip)) + _filter['hardware']['primaryIpAddress'] = utils.query_filter(public_ip) if private_ip: - _filter['hardware']['primaryBackendIpAddress'] = ( - utils.query_filter(private_ip)) + _filter['hardware']['primaryBackendIpAddress'] = utils.query_filter(private_ip) + + if owner: + _filter['hardware']['billingItem']['orderItem']['order']['userRecord']['username'] = ( + utils.query_filter(owner)) kwargs['filter'] = _filter.to_dict() kwargs['iter'] = True diff --git a/tests/CLI/modules/hardware/hardware_basic_tests.py b/tests/CLI/modules/hardware/hardware_basic_tests.py index d7c2ca9b3..a5597872e 100644 --- a/tests/CLI/modules/hardware/hardware_basic_tests.py +++ b/tests/CLI/modules/hardware/hardware_basic_tests.py @@ -169,47 +169,6 @@ def test_detail_drives(self): self.assertEqual(output['drives'][0]['Name'], 'Seagate Constellation ES') self.assertEqual(output['drives'][0]['Serial #'], 'z1w4sdf') - def test_list_servers(self): - result = self.run_command(['server', 'list', '--tag=openstack']) - - expected = [ - { - 'datacenter': 'TEST00', - 'primary_ip': '172.16.1.100', - 'hostname': 'hardware-test1', - 'id': 1000, - 'backend_ip': '10.1.0.2', - 'action': 'TXN_NAME', - }, - { - 'datacenter': 'TEST00', - 'primary_ip': '172.16.4.94', - 'hostname': 'hardware-test2', - 'id': 1001, - 'backend_ip': '10.1.0.3', - 'action': None, - }, - { - 'datacenter': 'TEST00', - 'primary_ip': '172.16.4.95', - 'hostname': 'hardware-bad-memory', - 'id': 1002, - 'backend_ip': '10.1.0.4', - 'action': None, - }, - { - 'action': None, - 'backend_ip': None, - 'datacenter': None, - 'hostname': None, - 'id': 1003, - 'primary_ip': None, - }, - ] - - self.assert_no_fail(result) - self.assertEqual(expected, json.loads(result.output)) - @mock.patch('SoftLayer.CLI.formatting.no_going_back') @mock.patch('SoftLayer.HardwareManager.reload') def test_server_reload(self, reload_mock, ngb_mock): @@ -992,17 +951,6 @@ def test_create_credential(self): '--notes', 'test slcli', '--software', 'system']) self.assert_no_fail(result) - def test_list_hw_search_noargs(self): - result = self.run_command(['hw', 'list', '--search']) - self.assert_no_fail(result) - self.assert_called_with('SoftLayer_Search', 'advancedSearch', args=('_objectType:SoftLayer_Hardware ',)) - - def test_list_hw_search_noargs_domain(self): - result = self.run_command(['hw', 'list', '--search', '-Dtest']) - self.assert_no_fail(result) - self.assert_called_with('SoftLayer_Search', 'advancedSearch', - args=('_objectType:SoftLayer_Hardware domain: *test*',)) - @mock.patch('SoftLayer.CLI.formatting.confirm') def test_hardware_cancel_no_force(self, confirm_mock): confirm_mock.return_value = False diff --git a/tests/CLI/modules/hardware/hardware_list_tests.py b/tests/CLI/modules/hardware/hardware_list_tests.py new file mode 100644 index 000000000..6ef091eba --- /dev/null +++ b/tests/CLI/modules/hardware/hardware_list_tests.py @@ -0,0 +1,93 @@ +""" + SoftLayer.tests.CLI.modules.hardware.hardware_list_tests + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + These tests the `slcli hw list` command. Its complex enough to warrant its own file + + :license: MIT, see LICENSE for more details. +""" + +import json + +from SoftLayer import testing +from SoftLayer import utils + + +class HardwareListCLITests(testing.TestCase): + def test_list_servers(self): + colums = 'datacenter,primary_ip,hostname,id,backend_ip,action' + result = self.run_command(['server', 'list', '--tag=openstack', f'--columns={colums}']) + + expected = [ + { + 'datacenter': 'TEST00', + 'primary_ip': '172.16.1.100', + 'hostname': 'hardware-test1', + 'id': 1000, + 'backend_ip': '10.1.0.2', + 'action': 'TXN_NAME', + }, + { + 'datacenter': 'TEST00', + 'primary_ip': '172.16.4.94', + 'hostname': 'hardware-test2', + 'id': 1001, + 'backend_ip': '10.1.0.3', + 'action': None, + }, + { + 'datacenter': 'TEST00', + 'primary_ip': '172.16.4.95', + 'hostname': 'hardware-bad-memory', + 'id': 1002, + 'backend_ip': '10.1.0.4', + 'action': None, + }, + { + 'action': None, + 'backend_ip': None, + 'datacenter': None, + 'hostname': None, + 'id': 1003, + 'primary_ip': None, + }, + ] + + self.assert_no_fail(result) + self.assertEqual(expected, json.loads(result.output)) + + def test_list_hw_search_noargs(self): + result = self.run_command(['hw', 'list', '--search']) + self.assert_no_fail(result) + self.assert_called_with('SoftLayer_Search', 'advancedSearch', args=('_objectType:SoftLayer_Hardware ',)) + + def test_list_hw_search_noargs_domain(self): + result = self.run_command(['hw', 'list', '--search', '-Dtest']) + self.assert_no_fail(result) + self.assert_called_with('SoftLayer_Search', 'advancedSearch', + args=('_objectType:SoftLayer_Hardware domain: *test*',)) + + def test_list_by_owner(self): + result = self.run_command(['hw', 'list', '--owner=testUser']) + self.assert_no_fail(result) + expectedFilter = utils.NestedDict() + expectedFilter['id'] = utils.query_filter_orderby() + expectedFilter['hardware']['billingItem']['orderItem']['order']['userRecord']['username'] = ( + utils.query_filter('testUser')) + self.assert_called_with('SoftLayer_Account', 'getHardware', filter=expectedFilter) + + def test_list_by_pub_ip(self): + result = self.run_command(['hw', 'list', '--primary_ip=1.2.3.4']) + self.assert_no_fail(result) + expectedFilter = utils.NestedDict() + expectedFilter['id'] = utils.query_filter_orderby() + expectedFilter['hardware']['primaryIpAddress'] = utils.query_filter('1.2.3.4') + self.assert_called_with('SoftLayer_Account', 'getHardware', filter=expectedFilter) + + def test_list_by_pri_ip(self): + result = self.run_command(['hw', 'list', '--backend_ip=1.2.3.4']) + self.assert_no_fail(result) + expectedFilter = utils.NestedDict() + expectedFilter['id'] = utils.query_filter_orderby() + expectedFilter['hardware']['primaryBackendIpAddress'] = utils.query_filter('1.2.3.4') + self.assert_called_with('SoftLayer_Account', 'getHardware', filter=expectedFilter)