From 0ab5a78d78249199cc25420fe80a2f8598022184 Mon Sep 17 00:00:00 2001 From: Louis Taylor Date: Thu, 5 Mar 2015 18:53:54 +0000 Subject: [PATCH] Fix leaking sockets after v2 list operation This fixes the same problem with leaking file descriptors after the port to requests I16a7b02f2b10e506e91719712cf34ef0aea1afc0 does, but for the v2 api client. The paginate function in the list method has been refactored from a recursive generator to a non-recursive generator, which avoids issues with garbage collection holding the socket open. Change-Id: Iaa7a421e8c1acafb7b23bb3f55e50b9d2a9d030a Closes-Bug: #1428797 --- glanceclient/v2/images.py | 58 +++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/glanceclient/v2/images.py b/glanceclient/v2/images.py index b1f3237f..7f1d8bce 100644 --- a/glanceclient/v2/images.py +++ b/glanceclient/v2/images.py @@ -54,40 +54,40 @@ class Controller(object): page_size = kwargs.get('page_size') or DEFAULT_PAGE_SIZE def paginate(url, page_size, limit=None): + next_url = url - if limit and page_size > limit: - # NOTE(flaper87): Avoid requesting 2000 images when limit is 1 - url = url.replace("limit=%s" % page_size, - "limit=%s" % limit) + while True: + if limit and page_size > limit: + # NOTE(flaper87): Avoid requesting 2000 images when limit + # is 1 + next_url = next_url.replace("limit=%s" % page_size, + "limit=%s" % limit) - resp, body = self.http_client.get(url) - for image in body['images']: - # NOTE(bcwaldon): remove 'self' for now until we have - # an elegant way to pass it into the model constructor - # without conflict. - image.pop('self', None) - yield self.model(**image) - # NOTE(zhiyan): In order to resolve the performance issue - # of JSON schema validation for image listing case, we - # don't validate each image entry but do it only on first - # image entry for each page. - self.model.validate = empty_fun + resp, body = self.http_client.get(next_url) + for image in body['images']: + # NOTE(bcwaldon): remove 'self' for now until we have + # an elegant way to pass it into the model constructor + # without conflict. + image.pop('self', None) + yield self.model(**image) + # NOTE(zhiyan): In order to resolve the performance issue + # of JSON schema validation for image listing case, we + # don't validate each image entry but do it only on first + # image entry for each page. + self.model.validate = empty_fun - if limit: - limit -= 1 - if limit <= 0: - raise StopIteration + if limit: + limit -= 1 + if limit <= 0: + raise StopIteration - # NOTE(zhiyan); Reset validation function. - self.model.validate = ori_validate_fun + # NOTE(zhiyan); Reset validation function. + self.model.validate = ori_validate_fun - try: - next_url = body['next'] - except KeyError: - return - else: - for image in paginate(next_url, page_size, limit): - yield image + try: + next_url = body['next'] + except KeyError: + return filters = kwargs.get('filters', {}) # NOTE(flaper87): We paginate in the client, hence we use