From cd51c7f234e3acc2de85202040bea70ed7d5d69c Mon Sep 17 00:00:00 2001 From: Grant Gavares Date: Sat, 2 Mar 2013 17:27:09 -0800 Subject: [PATCH] Add socket timeout to uri module. The uri module can be configured to abort after a specified timeout if it cannot connect to the configured uri. This prevents a uri action from hanging indefinitely when the remote endpoint cannot be reached because it is unavailable, there is a firewall in place etc. The default behavior is left unchanged: timeout=None This change also introduces a new type for module_parameters: int Code was added to perform conversion from string -> int type in module_common.py. The new type was required in order to play nice with httplib2 which refuses to accept (and convert) anything other than a numeric type for the timeout value. --- lib/ansible/module_common.py | 6 ++++++ library/uri | 13 ++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/ansible/module_common.py b/lib/ansible/module_common.py index 0d425078f1..87839b9890 100644 --- a/lib/ansible/module_common.py +++ b/lib/ansible/module_common.py @@ -597,6 +597,12 @@ class AnsibleModule(object): self.params[k] = self.boolean(value) else: is_invalid = True + elif wanted == 'int': + if not isinstance(value, int): + if isinstance(value, basestring): + self.params[k] = int(value) + else: + is_invalid = True else: self.fail_json(msg="implementation error: unknown type %s requested for %s" % (wanted, k)) diff --git a/library/uri b/library/uri index 3c97f33dad..0399d57e9c 100644 --- a/library/uri +++ b/library/uri @@ -103,6 +103,11 @@ options: - A valid, numeric, HTTP status code that signifies success of the request. required: false default: 200 + timeout: + description: + - The socket level timeout in seconds + required: false + default: no timeout HEADER_: description: Any parameter starting with "HEADER_" is a sent with your request as a header. For example, HEADER_Content-Type="application/json" would send the header "Content-Type" along with your request with a value of "application/json". required: false @@ -217,12 +222,12 @@ def url_filename(url): return fn -def uri(module, url, dest, user, password, body, method, headers, redirects): +def uri(module, url, dest, user, password, body, method, headers, redirects, socket_timeout): # To debug #httplib2.debug = 4 # Create a Http object and set some default options. - h = httplib2.Http(disable_ssl_certificate_validation=True) + h = httplib2.Http(disable_ssl_certificate_validation=True, timeout=socket_timeout) h.follow_all_redirects = redirects h.forward_authorization_headers = True @@ -273,6 +278,7 @@ def main(): creates = dict(required=False, default=None), removes = dict(required=False, default=None), status_code = dict(required=False, default="200"), + timeout = dict(required=False, default=None, type='int'), ), check_invalid_arguments=False, add_file_common_args=True @@ -295,6 +301,7 @@ def main(): creates = module.params['creates'] removes = module.params['removes'] status_code = module.params['status_code'] + socket_timeout = module.params['timeout'] # Grab all the http headers. Need this hack since passing multi-values is currently a bit ugly. (e.g. headers='{"Content-Type":"application/json"}') dict_headers = {} @@ -340,7 +347,7 @@ def main(): dest = os.path.join(dest, url_filename(url)) # Make the request - resp, content = uri(module, url, dest, user, password, body, method, dict_headers, redirects) + resp, content = uri(module, url, dest, user, password, body, method, dict_headers, redirects, socket_timeout) # Write the file out if requested if dest is not None: