Skip to content

Commit a845722

Browse files
Added a thread capable client.cf_call() function
1 parent 60b4f84 commit a845722

File tree

3 files changed

+58
-38
lines changed

3 files changed

+58
-38
lines changed

SoftLayer/API.py

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
:license: MIT, see LICENSE for more details.
77
"""
88
# pylint: disable=invalid-name
9-
import time
10-
import warnings
11-
9+
import concurrent.futures as cf
1210
import json
1311
import logging
12+
import math
1413
import requests
14+
import time
15+
import warnings
1516

1617

1718
from SoftLayer import auth as slauth
@@ -289,13 +290,6 @@ def call(self, service, method, *args, **kwargs):
289290
request.verify = kwargs.get('verify')
290291

291292
if self.auth:
292-
extra_headers = self.auth.get_headers()
293-
if extra_headers:
294-
warnings.warn("auth.get_headers() is deprecated and will be "
295-
"removed in the next major version",
296-
DeprecationWarning)
297-
request.headers.update(extra_headers)
298-
299293
request = self.auth.get_request(request)
300294

301295
request.headers.update(kwargs.get('headers', {}))
@@ -352,6 +346,45 @@ def iter_call(self, service, method, *args, **kwargs):
352346

353347
offset += limit
354348

349+
def cf_call(self, service, method, *args, **kwargs):
350+
"""Uses threads to iterate through API calls.
351+
352+
:param service: the name of the SoftLayer API service
353+
:param method: the method to call on the service
354+
:param integer limit: result size for each API call (defaults to 100)
355+
:param \\*args: same optional arguments that ``Service.call`` takes
356+
:param \\*\\*kwargs: same optional keyword arguments that ``Service.call`` takes
357+
"""
358+
limit = kwargs.pop('limit', 100)
359+
offset = kwargs.pop('offset', 0)
360+
361+
if limit <= 0:
362+
raise AttributeError("Limit size should be greater than zero.")
363+
# This initial API call is to determine how many API calls we need to make after this first one.
364+
first_call = self.call(service, method, offset=offset, limit=limit, *args, **kwargs)
365+
366+
# This was not a list result, just return it.
367+
if not isinstance(first_call, transports.SoftLayerListResult):
368+
return first_call
369+
# How many more API calls we have to make
370+
api_calls = math.ceil((first_call.total_count - limit) / limit)
371+
372+
373+
def this_api(offset):
374+
"""Used to easily call executor.map() on this fuction"""
375+
return self.call(service, method, offset=offset, limit=limit, *args, **kwargs)
376+
377+
with cf.ThreadPoolExecutor(max_workers=10) as executor:
378+
future_results = {}
379+
offset_map = [x * limit for x in range(1, api_calls)]
380+
future_results = list(executor.map(this_api, offset_map))
381+
# Append the results in the order they were called
382+
for call_result in future_results:
383+
first_call = first_call + call_result
384+
return first_call
385+
386+
387+
355388
def __repr__(self):
356389
return "Client(transport=%r, auth=%r)" % (self.transport, self.auth)
357390

SoftLayer/CLI/vlan/list.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,13 @@
2525

2626

2727
@click.command(cls=SoftLayer.CLI.command.SLCommand, )
28-
@click.option('--sortby',
29-
help='Column to sort by',
30-
type=click.Choice(COLUMNS))
28+
@click.option('--sortby', help='Column to sort by', type=click.Choice(COLUMNS))
3129
@click.option('--datacenter', '-d',
3230
help='Filter by datacenter shortname (sng01, dal05, ...)')
3331
@click.option('--number', '-n', help='Filter by VLAN number')
3432
@click.option('--name', help='Filter by VLAN name')
35-
@click.option('--limit', '-l',
36-
help='How many results to get in one api call, default is 100',
37-
default=100,
38-
show_default=True)
33+
@click.option('--limit', '-l', default=100, show_default=True,
34+
help='How many results to get in one api call, default is 100')
3935
@environment.pass_env
4036
def cli(env, sortby, datacenter, number, name, limit):
4137
"""List VLANs.

SoftLayer/managers/network.py

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -515,46 +515,37 @@ def list_subnets(self, identifier=None, datacenter=None, version=0,
515515
kwargs['iter'] = True
516516
return self.client.call('Account', 'getSubnets', **kwargs)
517517

518-
def list_vlans(self, datacenter=None, vlan_number=None, name=None, limit=100, **kwargs):
518+
def list_vlans(self, datacenter=None, vlan_number=None, name=None, limit=100, mask=None, _filter={}):
519519
"""Display a list of all VLANs on the account.
520520
521521
This provides a quick overview of all VLANs including information about
522522
data center residence and the number of devices attached.
523523
524-
:param string datacenter: If specified, the list will only contain
525-
VLANs in the specified data center.
526-
:param int vlan_number: If specified, the list will only contain the
527-
VLAN matching this VLAN number.
528-
:param int name: If specified, the list will only contain the
529-
VLAN matching this VLAN name.
524+
:param string datacenter: If specified, the list will only contain VLANs in the specified data center.
525+
:param int vlan_number: If specified, the list will only contain the VLAN matching this VLAN number.
526+
:param int name: If specified, the list will only contain the VLAN matching this VLAN name.
530527
:param dict \\*\\*kwargs: response-level options (mask, limit, etc.)
531528
532529
"""
533-
_filter = utils.NestedDict(kwargs.get('filter') or {})
530+
_filter = utils.NestedDict(_filter)
534531

535532
_filter['networkVlans']['id'] = utils.query_filter_orderby()
536533

537534
if vlan_number:
538-
_filter['networkVlans']['vlanNumber'] = (
539-
utils.query_filter(vlan_number))
535+
_filter['networkVlans']['vlanNumber'] = (utils.query_filter(vlan_number))
540536

541537
if name:
542538
_filter['networkVlans']['name'] = utils.query_filter(name)
543539

544540
if datacenter:
545-
_filter['networkVlans']['primaryRouter']['datacenter']['name'] = (
546-
utils.query_filter(datacenter))
547-
548-
kwargs['filter'] = _filter.to_dict()
541+
_filter['networkVlans']['primaryRouter']['datacenter']['name'] = (utils.query_filter(datacenter))
549542

550-
if 'mask' not in kwargs:
551-
kwargs['mask'] = DEFAULT_VLAN_MASK
543+
if mask is None:
544+
mask = DEFAULT_VLAN_MASK
552545

553-
kwargs['iter'] = True
554-
if limit > 0:
555-
return self.account.getNetworkVlans(mask=kwargs['mask'], filter=_filter.to_dict(), limit=limit, iter=True)
556-
else:
557-
return self.account.getNetworkVlans(mask=kwargs['mask'], filter=_filter.to_dict(), iter=True)
546+
# cf_call uses threads to get all results.
547+
return self.client.cf_call('SoftLayer_Account', 'getNetworkVlans',
548+
mask=mask, filter=_filter.to_dict(), limit=limit)
558549

559550
def list_securitygroups(self, **kwargs):
560551
"""List security groups."""

0 commit comments

Comments
 (0)