def test_mock(self): # It's likely that clean will be called with a mock during testing. # It shouldn't blow up m = mock.MagicMock() str(m) target.clean(m)
def _http(self, method, api_url, payload): self.protocol = 'http' self.port = 80 if self.protocol == 'https': http = httplib.HTTPSConnection(self.host, self.port, timeout=self.timeout) http.connect = lambda: force_tlsv1_connect(http) else: http = httplib.HTTPConnection(self.host, self.port, timeout=self.timeout) LOG.debug("axapi_http: url: %s", api_url) LOG.debug("axapi_http: method: %s", method) LOG.debug("axapi_http: headers: %s", logutils.clean(self.HEADERS)) LOG.debug("axapi_http: payload: %s", logutils.clean(payload)) http.request(method, api_url, body=payload, headers=self.headers) r = http.getresponse() r_data = r.read() # Workaround for zero length response def handle_empty_response(data): if not data: raise EmptyHttpResponse(r) return data http.close() return handle_empty_response(r_data)
def test_list_dict(self): actual = target.clean( [{'credentials': { 'username': '******', 'password': '******'}}]) expected = [{'credentials': { 'username': target.REPLACEMENT, 'password': target.REPLACEMENT} }] self.assertEqual(expected, actual)
def test_tuple_dict(self): actual = target.clean( (1, {'credentials': { 'username': '******', 'password': '******'} })) expected = (1, {'credentials': { 'username': target.REPLACEMENT, 'password': target.REPLACEMENT} }) self.assertEqual(expected, actual)
def test_tuple_dict(self): actual = target.clean((1, { 'credentials': { 'username': '******', 'password': '******' } })) expected = (1, { 'credentials': { 'username': target.REPLACEMENT, 'password': target.REPLACEMENT } }) self.assertEqual(expected, actual)
def test_list_dict(self): actual = target.clean([{ 'credentials': { 'username': '******', 'password': '******' } }]) expected = [{ 'credentials': { 'username': target.REPLACEMENT, 'password': target.REPLACEMENT } }] self.assertEqual(expected, actual)
def _http(self, method, api_url, payload): if self.protocol == 'https': http = httplib.HTTPSConnection(self.host, self.port, timeout=self.timeout) http.connect = lambda: force_tlsv1_connect(http) else: http = httplib.HTTPConnection(self.host, self.port, timeout=self.timeout) LOG.debug("axapi_http: url: %s", api_url) LOG.debug("axapi_http: method: %s", method) LOG.debug("axapi_http: headers: %s", logutils.clean(self.HEADERS)) LOG.debug("axapi_http: payload: %s", logutils.clean(payload)) http.request(method, api_url, body=payload, headers=self.headers) r = http.getresponse() # Workaround for zero length response def handle_empty_response(data): if not data: raise EmptyHttpResponse(r) return data return handle_empty_response(r.read())
def test_obj_flat(self): actual = target.clean(self.obj_flat) self.assertEqual(target.REPLACEMENT, actual.username) self.assertEqual(target.REPLACEMENT, actual.password)
def test_obj_onelevel(self): actual = target.clean(self.obj_onelevel).credentials self.assertEqual(target.REPLACEMENT, actual.username) self.assertEqual(target.REPLACEMENT, actual.password)
def test_none(self): actual = target.clean(None) self.assertEqual(None, actual)
def test_clean_twolevel_dict(self): actual = target.clean(self.dict_twolevel).get("credentials").get("inside_secret") self.assertEqual(target.REPLACEMENT, actual["username"]) self.assertEqual(target.REPLACEMENT, actual["password"])
def test_clean_flat_dict(self): actual = target.clean(self.flat_dict) self.assertEqual(target.REPLACEMENT, actual["username"]) self.assertEqual(target.REPLACEMENT, actual["password"]) self.assertEqual(self.flat_dict["a"], actual["a"])
def test_clean_twolevel_dict(self): actual = target.clean( self.dict_twolevel).get("credentials").get("inside_secret") self.assertEqual(target.REPLACEMENT, actual["username"]) self.assertEqual(target.REPLACEMENT, actual["password"])
def test_float(self): actual = target.clean(3.7) self.assertEqual(3.7, actual)
def test_ustring(self): actual = target.clean('sometext') self.assertEqual('sometext', actual)
def request(self, method, api_url, params={}, headers=None, file_name=None, file_content=None, axapi_args=None, **kwargs): LOG.debug("axapi_http: full url = %s", self.url_base + api_url) LOG.debug("axapi_http: %s url = %s", method, api_url) LOG.debug("axapi_http: params = %s", json.dumps(logutils.clean(params), indent=4)) valid_http_codes = [200, 204] # Update params with axapi_args for currently unsupported configuration of objects if axapi_args is not None: formatted_axapi_args = dict( [(k.replace('_', '-'), v) for k, v in six.iteritems(axapi_args)] ) params = acos_client.v21.axapi_http.merge_dicts(params, formatted_axapi_args) # Set data" variable for the request if params: params_copy = params.copy() LOG.debug("axapi_http: params_all = %s", logutils.clean(params_copy)) payload = json.dumps(params_copy) else: payload = None if (file_name is None and file_content is not None) or \ (file_name is not None and file_content is None): raise ValueError("file_name and file_content must both be populated if one is") max_retries = kwargs.get('max_retries', self.max_retries) timeout = kwargs.get('timeout', self.timeout) # Set "headers" variable for the request request_headers = self.HEADERS.copy() if headers: request_headers.update(headers) LOG.debug("axapi_http: headers = %s", json.dumps(logutils.clean(request_headers), indent=4)) # Process files if passed as a parameter if file_name is not None: files = { 'file': (file_name, file_content, "application/octet-stream"), 'json': ('blob', payload, "application/json") } request_headers.pop("Content-type", None) request_headers.pop("Content-Type", None) # Create session to set HTTPAdapter or SSLAdapter and set max_retries session = Session() if self.port == 443: session.mount('https://', HTTPAdapter(max_retries=max_retries)) else: session.mount('http://', HTTPAdapter(max_retries=max_retries)) session_request = getattr(session, method.lower()) # Make actual request and handle any errors try: if file_name is not None: device_response = session_request( self.url_base + api_url, verify=False, files=files, headers=request_headers, timeout=timeout ) else: device_response = session_request( self.url_base + api_url, verify=False, data=payload, headers=request_headers, timeout=timeout ) except (Exception) as e: LOG.error("acos_client failing with error %s after %s retries", e.__class__.__name__, max_retries) raise e finally: session.close() # Validate json response try: json_response = device_response.json() LOG.debug("axapi_http: data = %s", json.dumps(logutils.clean(json_response), indent=4)) except ValueError as e: # The response is not JSON but it still succeeded. if device_response.status_code in valid_http_codes: return device_response.text else: raise e # Handle "fail" responses returned by AXAPI if 'response' in json_response and 'status' in json_response['response']: if json_response['response']['status'] == 'fail': acos_responses.raise_axapi_ex(json_response, method, api_url) # Handle "authorizationschema" responses returned by AXAPI if 'authorizationschema' in json_response: acos_responses.raise_axapi_auth_error(json_response, method, api_url, headers) return json_response
def request(self, method, api_url, params={}, headers=None, file_name=None, file_content=None, axapi_args=None, **kwargs): LOG.debug("axapi_http: full url = %s", self.url_base + api_url) LOG.debug("axapi_http: %s url = %s", method, api_url) LOG.debug("axapi_http: params = %s", json.dumps(logutils.clean(params), indent=4)) # Update params with axapi_args for currently unsupported configuration of objects if axapi_args is not None: formatted_axapi_args = dict([(k.replace('_', '-'), v) for k, v in axapi_args.iteritems()]) params = acos_client.v21.axapi_http.merge_dicts( params, formatted_axapi_args) if (file_name is None and file_content is not None) or \ (file_name is not None and file_content is None): raise ValueError("file_name and file_content must both be " "populated if one is") hdrs = self.HEADERS.copy() if headers: hdrs.update(headers) if params: params_copy = params.copy() # params_copy.update(extra_params) LOG.debug("axapi_http: params_all = %s", logutils.clean(params_copy)) payload = json.dumps(params_copy, encoding='utf-8') else: payload = None LOG.debug("axapi_http: headers = %s", json.dumps(logutils.clean(hdrs), indent=4)) if file_name is not None: files = { 'file': (file_name, file_content, "application/octet-stream"), 'json': ('blob', payload, "application/json") } hdrs.pop("Content-type", None) hdrs.pop("Content-Type", None) last_e = None for i in xrange(0, 1500): try: last_e = None if file_name is not None: z = requests.request(method, self.url_base + api_url, verify=False, files=files, headers=hdrs) else: #requests.packages.urllib3.disable_warnings() z = requests.request(method, self.url_base + api_url, verify=False, data=payload, headers=hdrs) break except (socket.error, requests.exceptions.ConnectionError) as e: # Workaround some bogosity in the API if e.errno in self.retry_errnos or \ any(s in str(e) for s in self.retry_err_strings): time.sleep(0.1) last_e = e continue raise e LOG.debug("acos_client retried %s %s times", self.url_base + api_url, i) if last_e is not None: LOG.error( "acos_client failing with error %s after %s retries ignoring %s", last_e, i, self.retry_err_strings) raise e if z.status_code == 204: return None try: r = z.json() except ValueError as e: # The response is not JSON but it still succeeded. if z.status_code == 200: return {} else: raise e LOG.debug("axapi_http: data = %s", json.dumps(logutils.clean(r), indent=4)) if 'response' in r and 'status' in r['response']: if r['response']['status'] == 'fail': acos_responses.raise_axapi_ex(r, method, api_url) if 'authorizationschema' in r: acos_responses.raise_axapi_auth_error(r, method, api_url, headers) return r
def test_int(self): actual = target.clean(1) self.assertEqual(1, actual)
def test_ustring(self): actual = target.clean(u'sometext') self.assertEqual(u'sometext', actual)
def test_obj_twolevel(self): actual = target.clean(self.obj_twolevel).credentials.inside_secret self.assertEqual(target.REPLACEMENT, actual.username) self.assertEqual(target.REPLACEMENT, actual.password)
def request(self, method, api_url, params={}, headers=None, file_name=None, file_content=None, axapi_args=None, **kwargs): LOG.debug("axapi_http: full url = %s", self.url_base + api_url) LOG.debug("axapi_http: %s url = %s", method, api_url) LOG.debug("axapi_http: params = %s", json.dumps(logutils.clean(params), indent=4)) # Update params with axapi_args for currently unsupported configuration of objects if axapi_args is not None: formatted_axapi_args = dict([(k.replace('_', '-'), v) for k, v in axapi_args.iteritems()]) params = acos_client.v21.axapi_http.merge_dicts(params, formatted_axapi_args) if (file_name is None and file_content is not None) or \ (file_name is not None and file_content is None): raise ValueError("file_name and file_content must both be " "populated if one is") hdrs = self.HEADERS.copy() if headers: hdrs.update(headers) if params: params_copy = params.copy() # params_copy.update(extra_params) LOG.debug("axapi_http: params_all = %s", logutils.clean(params_copy)) payload = json.dumps(params_copy, encoding='utf-8') else: payload = None LOG.debug("axapi_http: headers = %s", json.dumps(logutils.clean(hdrs), indent=4)) if file_name is not None: files = { 'file': (file_name, file_content, "application/octet-stream"), 'json': ('blob', payload, "application/json") } hdrs.pop("Content-type", None) hdrs.pop("Content-Type", None) z = requests.request(method, self.url_base + api_url, verify=False, files=files, headers=hdrs) else: z = requests.request(method, self.url_base + api_url, verify=False, data=payload, headers=hdrs) if z.status_code == 204: return None try: r = z.json() except ValueError as e: # The response is not JSON but it still succeeded. if z.status_code == 200: return {} else: raise e LOG.debug("axapi_http: data = %s", json.dumps(logutils.clean(r), indent=4)) if 'response' in r and 'status' in r['response']: if r['response']['status'] == 'fail': acos_responses.raise_axapi_ex(r, method, api_url) if 'authorizationschema' in r: acos_responses.raise_axapi_auth_error( r, method, api_url, headers) return r
def request(self, method, api_url, params={}, **kwargs): LOG.debug("axapi_http: url = %s", api_url) LOG.debug("axapi_http: params = %s", logutils.clean(params)) self.headers = self.HEADERS if params: extra_params = kwargs.get('axapi_args', {}) params_copy = merge_dicts(params, extra_params) LOG.debug("axapi_http: params_all = %s", logutils.clean(params_copy)) payload = json.dumps(params_copy, encoding='utf-8') else: try: payload = kwargs.pop('payload', None) self.headers = dict(self.headers, **kwargs.pop('headers', {})) LOG.debug("axapi_http: headers_all = %s", logutils.clean(self.headers)) except KeyError: payload = None last_e = None for i in xrange(0, 600): try: last_e = None data = self._http(method, api_url, payload) break except socket.error as e: # Workaround some bogosity in the API if (e.errno == errno.ECONNRESET or e.errno == errno.ECONNREFUSED): time.sleep(0.1) last_e = e continue raise e except httplib.BadStatusLine as e: time.sleep(0.1) last_e = e continue except EmptyHttpResponse as e: if e.response.status != httplib.OK: msg = dict(e.response.msg.items()) data = json.dumps({"response": {'status': 'fail', 'err': {'code': e.response.status, 'msg': msg}}}) else: data = json.dumps({"response": {"status": "OK"}}) break if last_e is not None: raise e LOG.debug("axapi_http: data = %s", logutils.clean(data)) # Fixup some broken stuff in an earlier version of the axapi # xmlok = ('<?xml version="1.0" encoding="utf-8" ?>' # '<response status="ok"></response>') # if data == xmlok: # return {'response': {'status': 'OK'}} # TODO() if data in broken_replies: data = broken_replies[data] LOG.debug("axapi_http: broken reply, new response: %s", logutils.clean(data)) try: r = json.loads(data, encoding='utf-8') except ValueError as e: # Handle non json response LOG.debug("axapi_http: json = %s", e) return data if 'response' in r and 'status' in r['response']: if r['response']['status'] == 'fail': acos_responses.raise_axapi_ex( r, action=extract_method(api_url)) return r
def test_clean_onelevel_dict(self): actual = target.clean(self.dict_onelevel).get("credentials") self.assertEqual(target.REPLACEMENT, actual["username"]) self.assertEqual(target.REPLACEMENT, actual["password"]) self.assertEqual(1, self.dict_onelevel["a"])
def request(self, method, api_url, params={}, **kwargs): LOG.debug("axapi_http: url = %s", api_url) LOG.debug("axapi_http: params = %s", logutils.clean(params)) self.headers = self.HEADERS if params: extra_params = kwargs.get('axapi_args', {}) params_copy = merge_dicts(params, extra_params) LOG.debug("axapi_http: params_all = %s", logutils.clean(params_copy)) payload = json.dumps(params_copy, encoding='utf-8') else: try: payload = kwargs.pop('payload', None) self.headers = dict(self.headers, **kwargs.pop('headers', {})) LOG.debug("axapi_http: headers_all = %s", logutils.clean(self.headers)) except KeyError: payload = None last_e = None for i in xrange(0, 10): try: last_e = None data = self._http(method, api_url, payload) break except socket.error as e: # Workaround some bogosity in the API if e.errno in self.retry_errnos: time.sleep(0.01) last_e = e continue raise e except httplib.BadStatusLine as e: time.sleep(0.01) last_e = e continue except EmptyHttpResponse as e: if e.response.status != httplib.OK: msg = dict(e.response.msg.items()) data = json.dumps({ "response": { 'status': 'fail', 'err': { 'code': e.response.status, 'msg': msg } } }) else: data = json.dumps({"response": {"status": "OK"}}) break if last_e is not None: raise e LOG.debug("axapi_http: data = %s", logutils.clean(data)) # Fixup some broken stuff in an earlier version of the axapi # xmlok = ('<?xml version="1.0" encoding="utf-8" ?>' # '<response status="ok"></response>') # if data == xmlok: # return {'response': {'status': 'OK'}} # TODO() if data in broken_replies: data = broken_replies[data] LOG.debug("axapi_http: broken reply, new response: %s", logutils.clean(data)) try: r = json.loads(data, encoding='utf-8') except ValueError as e: # Handle non json response LOG.debug("axapi_http: json = %s", e) return data if 'response' in r and 'status' in r['response']: if r['response']['status'] == 'fail': acos_responses.raise_axapi_ex(r, action=extract_method(api_url)) return r
def request(self, method, api_url, params={}, **kwargs): """Generate the API call to the device.""" LOG.debug("axapi_http: full url = %s", self.url_base + api_url) LOG.debug("axapi_http: %s url = %s", method, api_url) LOG.debug("axapi_http: params = %s", json.dumps(logutils.clean(params), indent=4)) # Set "data" variable for the request if params: extra_params = kwargs.get('axapi_args', {}) params_copy = merge_dicts(params, extra_params) LOG.debug("axapi_http: params_all = %s", logutils.clean(params_copy)) payload = json.dumps(params_copy) else: try: payload = kwargs.pop('payload', None) self.headers = dict(self.HEADERS, **kwargs.pop('headers', {})) LOG.debug("axapi_http: headers_all = %s", logutils.clean(self.headers)) except KeyError: payload = None max_retries = kwargs.get('max_retries', self.max_retries) timeout = kwargs.get('timeout', self.timeout) # Create session to set HTTPAdapter or SSLAdapter session = Session() if self.port == 443: # Add adapter for any https session to force TLS1_0 connection for v21 of AXAPI session.mount('https://', SSLAdapter(max_retries=max_retries)) else: session.mount('http://', HTTPAdapter(max_retries=max_retries)) session_request = getattr(session, method.lower()) # Make actual request and handle any errors try: device_response = session_request(self.url_base + api_url, verify=False, data=payload, headers=self.HEADERS, timeout=timeout) except (Exception) as e: LOG.error("acos_client failing with error %s after %s retries", e.__class__.__name__, max_retries) raise e finally: session.close() # Log if the reponse is one of the known broken response if device_response in broken_replies: device_response = broken_replies[device_response] LOG.debug("axapi_http: broken reply, new response: %s", logutils.clean(device_response)) # Validate json response try: json_response = device_response.json() LOG.debug("axapi_http: data = %s", json.dumps(logutils.clean(json_response), indent=4)) except ValueError as e: # The response is not JSON but it still succeeded. LOG.debug("axapi_http: json = %s", e) return device_response # Handle "fail" responses returned by AXAPI if 'response' in json_response and 'status' in json_response[ 'response']: if json_response['response']['status'] == 'fail': acos_responses.raise_axapi_ex(json_response, action=extract_method(api_url)) # Return json portion of response return json_response
def request(self, method, api_url, params={}, **kwargs): """Generate the API call to the device.""" LOG.debug("axapi_http: full url = %s", self.url_base + api_url) LOG.debug("axapi_http: %s url = %s", method, api_url) LOG.debug("axapi_http: params = %s", json.dumps(logutils.clean(params), indent=4)) # Set "data" variable for the request if params: extra_params = kwargs.get('axapi_args', {}) params_copy = merge_dicts(params, extra_params) LOG.debug("axapi_http: params_all = %s", logutils.clean(params_copy)) payload = json.dumps(params_copy) else: try: payload = kwargs.pop('payload', None) self.headers = dict(self.HEADERS, **kwargs.pop('headers', {})) LOG.debug("axapi_http: headers_all = %s", logutils.clean(self.headers)) except KeyError: payload = None max_retries = kwargs.get('max_retries', self.max_retries) timeout = kwargs.get('timeout', self.timeout) # Create session to set HTTPAdapter or SSLAdapter session = Session() if self.port == 443: # Add adapter for any https session to force TLS1_0 connection for v21 of AXAPI session.mount('https://', SSLAdapter(max_retries=max_retries)) else: session.mount('http://', HTTPAdapter(max_retries=max_retries)) session_request = getattr(session, method.lower()) # Make actual request and handle any errors try: device_response = session_request( self.url_base + api_url, verify=False, data=payload, headers=self.HEADERS, timeout=timeout ) except (Exception) as e: LOG.error("acos_client failing with error %s after %s retries", e.__class__.__name__, max_retries) raise e finally: session.close() # Log if the reponse is one of the known broken response if device_response in broken_replies: device_response = broken_replies[device_response] LOG.debug("axapi_http: broken reply, new response: %s", logutils.clean(device_response)) # Validate json response try: json_response = device_response.json() LOG.debug("axapi_http: data = %s", json.dumps(logutils.clean(json_response), indent=4)) except ValueError as e: # The response is not JSON but it still succeeded. LOG.debug("axapi_http: json = %s", e) return device_response # Handle "fail" responses returned by AXAPI if 'response' in json_response and 'status' in json_response['response']: if json_response['response']['status'] == 'fail': acos_responses.raise_axapi_ex(json_response, action=extract_method(api_url)) # Return json portion of response return json_response