Skip to content

Commit fe8c6a8

Browse files
Merge pull request #1015 from allmightyspiff/1006
Pagination for vs list and others
2 parents b065939 + 7ba0fa0 commit fe8c6a8

File tree

17 files changed

+311
-243
lines changed

17 files changed

+311
-243
lines changed

CONTRIBUTING.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,18 @@ guidelines below.
1212
* Additional infomration can be found in our [contribution guide](http://softlayer-python.readthedocs.org/en/latest/dev/index.html)
1313

1414

15+
## Code style
16+
17+
Code is tested and style checked with tox, you can run the tox tests individually by doing `tox -e <TEST>`
18+
19+
* `autopep8 -r -v -i --max-line-length 119 SoftLayer/`
20+
* `autopep8 -r -v -i --max-line-length 119 tests/`
21+
* `tox -e analysis`
22+
* `tox -e py36`
23+
* `git commit --message="#<ISSUENUMBER> <whatever you did>`
24+
* `git push origin <issueBranch>`
25+
* create pull request
26+
27+
28+
29+

SoftLayer/API.py

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,9 @@ def call(self, service, method, *args, **kwargs):
214214
215215
"""
216216
if kwargs.pop('iter', False):
217-
return self.iter_call(service, method, *args, **kwargs)
217+
# Most of the codebase assumes a non-generator will be returned, so casting to list
218+
# keeps those sections working
219+
return list(self.iter_call(service, method, *args, **kwargs))
218220

219221
invalid_kwargs = set(kwargs.keys()) - VALID_CALL_ARGS
220222
if invalid_kwargs:
@@ -267,55 +269,51 @@ def iter_call(self, service, method, *args, **kwargs):
267269
268270
:param service: the name of the SoftLayer API service
269271
:param method: the method to call on the service
270-
:param integer chunk: result size for each API call (defaults to 100)
272+
:param integer limit: result size for each API call (defaults to 100)
271273
:param \\*args: same optional arguments that ``Service.call`` takes
272-
:param \\*\\*kwargs: same optional keyword arguments that
273-
``Service.call`` takes
274+
:param \\*\\*kwargs: same optional keyword arguments that ``Service.call`` takes
274275
275276
"""
276-
chunk = kwargs.pop('chunk', 100)
277-
limit = kwargs.pop('limit', None)
278-
offset = kwargs.pop('offset', 0)
279277

280-
if chunk <= 0:
281-
raise AttributeError("Chunk size should be greater than zero.")
278+
limit = kwargs.pop('limit', 100)
279+
offset = kwargs.pop('offset', 0)
282280

283-
if limit:
284-
chunk = min(chunk, limit)
281+
if limit <= 0:
282+
raise AttributeError("Limit size should be greater than zero.")
285283

286-
result_count = 0
284+
# Set to make unit tests, which call this function directly, play nice.
287285
kwargs['iter'] = False
288-
while True:
289-
if limit:
290-
# We've reached the end of the results
291-
if result_count >= limit:
292-
break
293-
294-
# Don't over-fetch past the given limit
295-
if chunk + result_count > limit:
296-
chunk = limit - result_count
297-
298-
results = self.call(service, method,
299-
offset=offset, limit=chunk, *args, **kwargs)
286+
result_count = 0
287+
keep_looping = True
300288

301-
# It looks like we ran out results
302-
if not results:
303-
break
289+
while keep_looping:
290+
# Get the next results
291+
results = self.call(service, method, offset=offset, limit=limit, *args, **kwargs)
304292

305293
# Apparently this method doesn't return a list.
306294
# Why are you even iterating over this?
307-
if not isinstance(results, list):
308-
yield results
309-
break
295+
if not isinstance(results, transports.SoftLayerListResult):
296+
if isinstance(results, list):
297+
# Close enough, this makes testing a lot easier
298+
results = transports.SoftLayerListResult(results, len(results))
299+
else:
300+
yield results
301+
raise StopIteration
310302

311303
for item in results:
312304
yield item
313305
result_count += 1
314306

315-
offset += chunk
307+
# Got less results than requested, we are at the end
308+
if len(results) < limit:
309+
keep_looping = False
310+
# Got all the needed items
311+
if result_count >= results.total_count:
312+
keep_looping = False
313+
314+
offset += limit
316315

317-
if len(results) < chunk:
318-
break
316+
raise StopIteration
319317

320318
def __repr__(self):
321319
return "Client(transport=%r, auth=%r)" % (self.transport, self.auth)

SoftLayer/CLI/hardware/list.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,12 @@
5555
help='Columns to display. [options: %s]' % ', '.join(column.name for column in COLUMNS),
5656
default=','.join(DEFAULT_COLUMNS),
5757
show_default=True)
58+
@click.option('--limit', '-l',
59+
help='How many results to get in one api call, default is 100',
60+
default=100,
61+
show_default=True)
5862
@environment.pass_env
59-
def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network, tag, columns):
63+
def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network, tag, columns, limit):
6064
"""List hardware servers."""
6165

6266
manager = SoftLayer.HardwareManager(env.client)
@@ -67,7 +71,8 @@ def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network, tag, co
6771
datacenter=datacenter,
6872
nic_speed=network,
6973
tags=tag,
70-
mask="mask(SoftLayer_Hardware_Server)[%s]" % columns.mask())
74+
mask="mask(SoftLayer_Hardware_Server)[%s]" % columns.mask(),
75+
limit=limit)
7176

7277
table = formatting.Table(columns.columns)
7378
table.sortby = sortby

SoftLayer/CLI/securitygroup/list.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,20 @@
1616
@click.option('--sortby',
1717
help='Column to sort by',
1818
type=click.Choice(COLUMNS))
19+
@click.option('--limit', '-l',
20+
help='How many results to get in one api call, default is 100',
21+
default=100,
22+
show_default=True)
1923
@environment.pass_env
20-
def cli(env, sortby):
24+
def cli(env, sortby, limit):
2125
"""List security groups."""
2226

2327
mgr = SoftLayer.NetworkManager(env.client)
2428

2529
table = formatting.Table(COLUMNS)
2630
table.sortby = sortby
2731

28-
sgs = mgr.list_securitygroups()
32+
sgs = mgr.list_securitygroups(limit=limit)
2933
for secgroup in sgs:
3034
table.add_row([
3135
secgroup['id'],

SoftLayer/CLI/virt/list.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,13 @@
6262
% ', '.join(column.name for column in COLUMNS),
6363
default=','.join(DEFAULT_COLUMNS),
6464
show_default=True)
65+
@click.option('--limit', '-l',
66+
help='How many results to get in one api call, default is 100',
67+
default=100,
68+
show_default=True)
6569
@environment.pass_env
6670
def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network,
67-
hourly, monthly, tag, columns):
71+
hourly, monthly, tag, columns, limit):
6872
"""List virtual servers."""
6973

7074
vsi = SoftLayer.VSManager(env.client)
@@ -77,11 +81,11 @@ def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network,
7781
datacenter=datacenter,
7882
nic_speed=network,
7983
tags=tag,
80-
mask=columns.mask())
84+
mask=columns.mask(),
85+
limit=limit)
8186

8287
table = formatting.Table(columns.columns)
8388
table.sortby = sortby
84-
8589
for guest in guests:
8690
table.add_row([value or formatting.blank()
8791
for value in columns.row(guest)])

SoftLayer/CLI/vlan/list.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@
2626
help='Filter by datacenter shortname (sng01, dal05, ...)')
2727
@click.option('--number', '-n', help='Filter by VLAN number')
2828
@click.option('--name', help='Filter by VLAN name')
29+
@click.option('--limit', '-l',
30+
help='How many results to get in one api call, default is 100',
31+
default=100,
32+
show_default=True)
2933
@environment.pass_env
30-
def cli(env, sortby, datacenter, number, name):
34+
def cli(env, sortby, datacenter, number, name, limit):
3135
"""List VLANs."""
3236

3337
mgr = SoftLayer.NetworkManager(env.client)
@@ -37,7 +41,8 @@ def cli(env, sortby, datacenter, number, name):
3741

3842
vlans = mgr.list_vlans(datacenter=datacenter,
3943
vlan_number=number,
40-
name=name)
44+
name=name,
45+
limit=limit)
4146
for vlan in vlans:
4247
table.add_row([
4348
vlan['id'],

SoftLayer/managers/hardware.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ def list_hardware(self, tags=None, cpus=None, memory=None, hostname=None,
197197
utils.query_filter(private_ip))
198198

199199
kwargs['filter'] = _filter.to_dict()
200-
return self.account.getHardware(**kwargs)
200+
kwargs['iter'] = True
201+
return self.client.call('Account', 'getHardware', **kwargs)
201202

202203
@retry(logger=LOGGER)
203204
def get_hardware(self, hardware_id, **kwargs):

SoftLayer/managers/network.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -477,11 +477,10 @@ def list_subnets(self, identifier=None, datacenter=None, version=0,
477477
utils.query_filter(network_space))
478478

479479
kwargs['filter'] = _filter.to_dict()
480+
kwargs['iter'] = True
481+
return self.client.call('Account', 'getSubnets', **kwargs)
480482

481-
return self.account.getSubnets(**kwargs)
482-
483-
def list_vlans(self, datacenter=None, vlan_number=None, name=None,
484-
**kwargs):
483+
def list_vlans(self, datacenter=None, vlan_number=None, name=None, **kwargs):
485484
"""Display a list of all VLANs on the account.
486485
487486
This provides a quick overview of all VLANs including information about
@@ -514,18 +513,20 @@ def list_vlans(self, datacenter=None, vlan_number=None, name=None,
514513
if 'mask' not in kwargs:
515514
kwargs['mask'] = DEFAULT_VLAN_MASK
516515

516+
kwargs['iter'] = True
517517
return self.account.getNetworkVlans(**kwargs)
518518

519519
def list_securitygroups(self, **kwargs):
520520
"""List security groups."""
521+
kwargs['iter'] = True
521522
return self.security_group.getAllObjects(**kwargs)
522523

523524
def list_securitygroup_rules(self, group_id):
524525
"""List security group rules associated with a security group.
525526
526527
:param int group_id: The security group to list rules for
527528
"""
528-
return self.security_group.getRules(id=group_id)
529+
return self.security_group.getRules(id=group_id, iter=True)
529530

530531
def remove_securitygroup_rule(self, group_id, rule_id):
531532
"""Remove a rule from a security group.

SoftLayer/managers/vs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ def list_instances(self, hourly=True, monthly=True, tags=None, cpus=None,
158158
utils.query_filter(private_ip))
159159

160160
kwargs['filter'] = _filter.to_dict()
161-
func = getattr(self.account, call)
162-
return func(**kwargs)
161+
kwargs['iter'] = True
162+
return self.client.call('Account', call, **kwargs)
163163

164164
@retry(logger=LOGGER)
165165
def get_instance(self, instance_id, **kwargs):

SoftLayer/testing/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from SoftLayer.CLI import environment
2020
from SoftLayer.testing import xmlrpc
2121

22-
2322
FIXTURE_PATH = os.path.abspath(os.path.join(__file__, '..', '..', 'fixtures'))
2423

2524

0 commit comments

Comments
 (0)