Skip to content

Commit e03d17b

Browse files
Merge pull request #1868 from allmightyspiff/issues1862
`vs list --search` functionality
2 parents 18ecf58 + e1e5c77 commit e03d17b

File tree

7 files changed

+87
-94
lines changed

7 files changed

+87
-94
lines changed

SoftLayer/CLI/virt/list.py

Lines changed: 22 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from SoftLayer.CLI import environment
1010
from SoftLayer.CLI import formatting
1111
from SoftLayer.CLI import helpers
12-
from SoftLayer import utils
1312

1413
# pylint: disable=unnecessary-lambda
1514

@@ -56,67 +55,41 @@
5655
@click.option('--hourly', is_flag=True, help='Show only hourly instances')
5756
@click.option('--monthly', is_flag=True, help='Show only monthly instances')
5857
@click.option('--transient', help='Filter by transient instances', type=click.BOOL)
59-
@click.option('--hardware', is_flag=True, default=False, help='Show the all VSI related to hardware')
60-
@click.option('--all-guests', is_flag=True, default=False, help='Show the all VSI and hardware VSIs')
58+
@click.option('--search', is_flag=False, flag_value="", default=None,
59+
help="Use the more flexible Search API to list instances. See `slcli search --types` for list " +
60+
"of searchable fields.")
6161
@helpers.multi_option('--tag', help='Filter by tags')
62-
@click.option('--sortby',
63-
help='Column to sort by',
64-
default='hostname',
65-
show_default=True)
62+
@click.option('--sortby', default='hostname', show_default=True, help='Column to sort by')
6663
@click.option('--columns',
6764
callback=column_helper.get_formatter(COLUMNS),
6865
help='Columns to display. [options: %s]'
6966
% ', '.join(column.name for column in COLUMNS),
7067
default=','.join(DEFAULT_COLUMNS),
7168
show_default=True)
72-
@click.option('--limit', '-l',
73-
help='How many results to get in one api call, default is 100',
74-
default=100,
75-
show_default=True)
69+
@click.option('--limit', '-l', default=100, show_default=True,
70+
help='How many results to get in one api call, default is 100')
7671
@environment.pass_env
7772
def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network,
78-
hourly, monthly, tag, columns, limit, transient, hardware, all_guests):
73+
hourly, monthly, tag, columns, limit, transient, search):
7974
"""List virtual servers."""
8075

81-
vsi = SoftLayer.VSManager(env.client)
82-
guests = vsi.list_instances(hourly=hourly,
83-
monthly=monthly,
84-
hostname=hostname,
85-
domain=domain,
86-
cpus=cpu,
87-
memory=memory,
88-
datacenter=datacenter,
89-
nic_speed=network,
90-
transient=transient,
91-
tags=tag,
92-
mask=columns.mask(),
93-
limit=limit)
76+
guests = []
77+
if search is not None:
78+
object_mask = f"mask[resource(SoftLayer_Virtual_Guest)[{columns.mask()}]]"
79+
search_manager = SoftLayer.SearchManager(env.client)
80+
guests = search_manager.search_instances(hostname=hostname, domain=domain, datacenter=datacenter,
81+
tags=tag, search_string=search, mask=object_mask)
82+
else:
83+
vsi = SoftLayer.VSManager(env.client)
84+
guests = vsi.list_instances(hourly=hourly, monthly=monthly, hostname=hostname, domain=domain,
85+
cpus=cpu, memory=memory, datacenter=datacenter, nic_speed=network,
86+
transient=transient, tags=tag, mask=columns.mask(), limit=limit)
9487

9588
table = formatting.Table(columns.columns)
9689
table.sortby = sortby
97-
if not hardware or all_guests:
98-
for guest in guests:
99-
table.add_row([value or formatting.blank()
100-
for value in columns.row(guest)])
10190

102-
env.fout(table)
91+
for guest in guests:
92+
table.add_row([value or formatting.blank()
93+
for value in columns.row(guest)])
10394

104-
if hardware or all_guests:
105-
hardware_guests = vsi.get_hardware_guests()
106-
for hd_guest in hardware_guests:
107-
if hd_guest['virtualHost']['guests']:
108-
title = "Hardware(id = {hardwareId}) guests associated".format(hardwareId=hd_guest['id'])
109-
table_hardware_guest = formatting.Table(['id', 'hostname', 'CPU', 'Memory', 'Start Date', 'Status',
110-
'powerState'], title=title)
111-
table_hardware_guest.sortby = 'hostname'
112-
for guest in hd_guest['virtualHost']['guests']:
113-
table_hardware_guest.add_row([
114-
guest['id'],
115-
guest['hostname'],
116-
'%i %s' % (guest['maxCpu'], guest['maxCpuUnits']),
117-
guest['maxMemory'],
118-
utils.clean_time(guest['createDate']),
119-
guest['status']['keyName'],
120-
guest['powerState']['keyName']
121-
])
122-
env.fout(table_hardware_guest)
95+
env.fout(table)

SoftLayer/managers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from SoftLayer.managers.network import NetworkManager
2525
from SoftLayer.managers.object_storage import ObjectStorageManager
2626
from SoftLayer.managers.ordering import OrderingManager
27+
from SoftLayer.managers.search import SearchManager
2728
from SoftLayer.managers.sshkey import SshKeyManager
2829
from SoftLayer.managers.ssl import SSLManager
2930
from SoftLayer.managers.tags import TagManager
@@ -53,6 +54,7 @@
5354
'ObjectStorageManager',
5455
'OrderingManager',
5556
'PlacementManager',
57+
'SearchManager',
5658
'SshKeyManager',
5759
'SSLManager',
5860
'TagManager',

SoftLayer/managers/search.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,30 @@ def advanced(self, search_string):
3434
3535
"""
3636
return self.search_manager.advancedSearch(search_string)
37+
38+
def search_instances(self, search_string, mask=None, **kwargs):
39+
"""Lists VSIs based in the search_string.
40+
41+
Also takes in a few search terms as **kwargs. such as hostname, datacenter, domain and tags
42+
"""
43+
44+
# This forces the Search API to do a fuzzy search on our term, kinda. Not sure why the ** are
45+
# Required but it will do an exact search without them.
46+
if search_string:
47+
search_string = f"*{search_string}*"
48+
search_string = f"_objectType:SoftLayer_Virtual_Guest {search_string}"
49+
if kwargs.get('hostname'):
50+
search_string = f"{search_string} hostname: *{kwargs.get('hostname')}*"
51+
if kwargs.get('domain'):
52+
search_string = f"{search_string} domain: *{kwargs.get('domain')}*"
53+
if kwargs.get('datacenter'):
54+
search_string = f"{search_string} datacenter.longName: *{kwargs.get('datacenter')}*"
55+
if kwargs.get('tags'):
56+
tags = " ".join(kwargs.get("tags", []))
57+
search_string = f"{search_string} internalTagReferences.tag.name: {tags}"
58+
result = self.search_manager.advancedSearch(search_string, mask=mask)
59+
guests = []
60+
for resource in result:
61+
guests.append(resource.get('resource'))
62+
63+
return guests

SoftLayer/managers/vs.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,15 +1441,6 @@ def migrate_dedicated(self, instance_id, host_id):
14411441
"""
14421442
return self.guest.migrateDedicatedHost(host_id, id=instance_id)
14431443

1444-
def get_hardware_guests(self):
1445-
"""Returns all virtualHost capable hardware objects and their guests.
1446-
1447-
:return SoftLayer_Hardware[].
1448-
"""
1449-
object_filter = {"hardware": {"virtualHost": {"id": {"operation": "not null"}}}}
1450-
mask = "mask[virtualHost[guests[powerState]]]"
1451-
return self.client.call('SoftLayer_Account', 'getHardware', mask=mask, filter=object_filter)
1452-
14531444
def authorize_storage(self, vs_id, username_storage):
14541445
"""Authorize File or Block Storage to a Virtual Server.
14551446

tests/CLI/modules/vs/vs_tests.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,23 @@ def test_list_vs(self):
145145

146146
self.assert_no_fail(result)
147147

148+
def test_list_vs_search_noargs(self):
149+
result = self.run_command(['vs', 'list', '--search'])
150+
self.assert_no_fail(result)
151+
self.assert_called_with('SoftLayer_Search', 'advancedSearch', args=('_objectType:SoftLayer_Virtual_Guest ',))
152+
153+
def test_list_vs_search_noargs_domain(self):
154+
result = self.run_command(['vs', 'list', '--search', '-Dtest'])
155+
self.assert_no_fail(result)
156+
self.assert_called_with('SoftLayer_Search', 'advancedSearch',
157+
args=('_objectType:SoftLayer_Virtual_Guest domain: *test*',))
158+
159+
def test_list_vs_search_args(self):
160+
result = self.run_command(['vs', 'list', '--search=thisTerm'])
161+
self.assert_no_fail(result)
162+
self.assert_called_with('SoftLayer_Search', 'advancedSearch',
163+
args=('_objectType:SoftLayer_Virtual_Guest *thisTerm*',))
164+
148165
@mock.patch('SoftLayer.utils.lookup')
149166
def test_detail_vs_empty_billing(self, mock_lookup):
150167
def mock_lookup_func(dic, key, *keys):
@@ -919,10 +936,6 @@ def test_vs_migrate_exception(self):
919936
self.assert_called_with('SoftLayer_Virtual_Guest', 'migrate', identifier=100)
920937
self.assert_not_called_with('SoftLayer_Virtual_Guest', 'migrateDedicatedHost', args=(999), identifier=100)
921938

922-
def test_list_vsi(self):
923-
result = self.run_command(['vs', 'list', '--hardware'])
924-
self.assert_no_fail(result)
925-
926939
def test_credentail(self):
927940
result = self.run_command(['vs', 'credentials', '100'])
928941
self.assert_no_fail(result)

tests/managers/search_tests.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,22 @@ def test_search(self):
2525
def test_search_advanced(self):
2626
self.search.advanced('SoftLayer_Hardware')
2727
self.assert_called_with('SoftLayer_Search', 'advancedSearch')
28+
29+
def test_search_instances_basic(self):
30+
search_string = "TEST_STRING"
31+
expected = f"_objectType:SoftLayer_Virtual_Guest *{search_string}*"
32+
self.search.search_instances(search_string)
33+
self.assert_called_with('SoftLayer_Search', 'advancedSearch',
34+
args=(expected,))
35+
self.search.search_instances(search_string, hostname="thisHostname")
36+
self.assert_called_with('SoftLayer_Search', 'advancedSearch',
37+
args=(f"{expected} hostname: *thisHostname*",))
38+
self.search.search_instances(search_string, domain="thisDomain")
39+
self.assert_called_with('SoftLayer_Search', 'advancedSearch',
40+
args=(f"{expected} domain: *thisDomain*",))
41+
self.search.search_instances(search_string, datacenter="dal13")
42+
self.assert_called_with('SoftLayer_Search', 'advancedSearch',
43+
args=(f"{expected} datacenter.longName: *dal13*",))
44+
self.search.search_instances(search_string, tags=["thisTag"])
45+
self.assert_called_with('SoftLayer_Search', 'advancedSearch',
46+
args=(f"{expected} internalTagReferences.tag.name: thisTag",))

tests/managers/vs/vs_tests.py

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,38 +1278,6 @@ def test_migrate_dedicated(self):
12781278
self.assertTrue(result)
12791279
self.assert_called_with('SoftLayer_Virtual_Guest', 'migrateDedicatedHost', args=(5555,), identifier=1234)
12801280

1281-
def test_get_hardware_guests(self):
1282-
mock = self.set_mock('SoftLayer_Account', 'getHardware')
1283-
mock.return_value = [{
1284-
"accountId": 11111,
1285-
"domain": "vmware.chechu.com",
1286-
"hostname": "host14",
1287-
"id": 22222,
1288-
"virtualHost": {
1289-
"accountId": 11111,
1290-
"id": 33333,
1291-
"name": "host14.vmware.chechu.com",
1292-
"guests": [
1293-
{
1294-
"accountId": 11111,
1295-
"hostname": "NSX-T Manager",
1296-
"id": 44444,
1297-
"maxCpu": 16,
1298-
"maxCpuUnits": "CORE",
1299-
"maxMemory": 49152,
1300-
"powerState": {
1301-
"keyName": "RUNNING",
1302-
"name": "Running"
1303-
},
1304-
"status": {
1305-
"keyName": "ACTIVE",
1306-
"name": "Active"
1307-
}
1308-
}]}}]
1309-
1310-
result = self.vs.get_hardware_guests()
1311-
self.assertEqual("NSX-T Manager", result[0]['virtualHost']['guests'][0]['hostname'])
1312-
13131281
def test_authorize_storage(self):
13141282
options = self.vs.authorize_storage(1234, "SL01SEL301234-11")
13151283

0 commit comments

Comments
 (0)