7ec2401abfbb11dc27c2e1ab96b701a2f8482a18
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
23 from requests
.exceptions
import ConnectionError
25 class HttpException(Exception):
29 class NotFound(HttpException
):
33 class AuthError(HttpException
):
37 class DuplicateFound(HttpException
):
41 class ServiceUnavailableException(HttpException
):
45 class ContrailHttp(object):
47 def __init__(self
, auth_info
, logger
):
49 # default don't verify client cert
50 self
._ssl
_verify
= False
51 # auth info: must contain auth_url and auth_dict
52 self
.auth_url
= auth_info
["auth_url"]
53 self
.auth_dict
= auth_info
["auth_dict"]
57 # Default token timeout
58 self
.token_timeout
= 3500
60 # TODO - improve configuration timeouts
62 def get_cmd(self
, url
, headers
):
63 self
._logger
.debug("")
64 resp
= self
._request
("GET", url
, headers
)
67 def post_headers_cmd(self
, url
, headers
, post_fields_dict
=None):
68 self
._logger
.debug("")
69 # obfuscate password before logging dict
70 if post_fields_dict
.get('auth', {}).get('identity', {}).get('password', {}).get('user', {}).get('password'):
71 post_fields_dict_copy
= copy
.deepcopy(post_fields_dict
)
72 post_fields_dict
['auth']['identity']['password']['user']['password'] = '******'
73 json_data_log
= post_fields_dict_copy
75 json_data_log
= post_fields_dict
76 self
._logger
.debug("Request POSTFIELDS: {}".format(json
.dumps(json_data_log
)))
77 resp
= self
._request
("POST_HEADERS", url
, headers
, data
=post_fields_dict
)
80 def post_cmd(self
, url
, headers
, post_fields_dict
=None):
81 self
._logger
.debug("")
82 # obfuscate password before logging dict
83 if post_fields_dict
.get('auth', {}).get('identity', {}).get('password', {}).get('user', {}).get('password'):
84 post_fields_dict_copy
= copy
.deepcopy(post_fields_dict
)
85 post_fields_dict
['auth']['identity']['password']['user']['password'] = '******'
86 json_data_log
= post_fields_dict_copy
88 json_data_log
= post_fields_dict
89 self
._logger
.debug("Request POSTFIELDS: {}".format(json
.dumps(json_data_log
)))
90 resp
= self
._request
("POST", url
, headers
, data
=post_fields_dict
)
93 def delete_cmd(self
, url
, headers
):
94 self
._logger
.debug("")
95 resp
= self
._request
("DELETE", url
, headers
)
98 def _get_token(self
, headers
):
99 self
._logger
.debug('Current Token:'.format(self
.token
))
100 auth_url
= self
.auth_url
+ 'auth/tokens'
101 if self
.token
is None or self
._token
_expired
():
102 if not self
.auth_url
:
104 resp
= self
._request
_noauth
(url
=auth_url
, op
="POST", headers
=headers
,
106 self
.token
= resp
.headers
.get('x-subject-token')
107 self
.last_token_time
= time
.time()
108 self
._logger
.debug('Obtained token: '.format(self
.token
))
112 def _token_expired(self
):
113 current_time
= time
.time()
114 if self
.last_token_time
and (current_time
- self
.last_token_time
< self
.token_timeout
):
119 def _request(self
, op
, url
, http_headers
, data
=None, retry_auth_error
=True):
120 headers
= http_headers
.copy()
122 # Get authorization (include authentication headers)
123 # todo - aƱadir token de nuevo
124 #token = self._get_token(headers)
127 headers
['X-Auth-Token'] = token
129 return self
._request
_noauth
(op
, url
, headers
, data
)
131 # If there is an auth error retry just once
133 return self
._request
(self
, op
, url
, headers
, data
, retry_auth_error
=False)
135 def _request_noauth(self
, op
, url
, headers
, data
=None):
136 # Method to execute http requests with error control
137 # Authentication error, always make just one retry
138 # ConnectionError or ServiceUnavailable make configured retries with sleep between them
139 # Other errors to raise:
144 while retry
< self
.max_retries
:
149 self
._logger
.info("Request METHOD: {} URL: {}".format(op
, url
))
151 resp
= self
._http
_get
(url
, headers
, query_params
=data
)
153 resp
= self
._http
_post
(url
, headers
, json_data
=data
)
154 elif (op
== "POST_HEADERS"):
155 resp
= self
._http
_post
_headers
(url
, headers
, json_data
=data
)
156 elif (op
== "DELETE"):
157 resp
= self
._http
_delete
(url
, headers
, json_data
=data
)
159 raise HttpException("Unsupported operation: {}".format(op
))
160 self
._logger
.info("Response HTTPCODE: {}".format(resp
.status_code
))
162 # Check http return code
166 status_code
= resp
.status_code
167 if status_code
== 401:
168 # Auth Error - set token to None to reload it and raise AuthError
170 raise AuthError("Auth error executing operation")
171 elif status_code
== 409:
172 raise DuplicateFound("Duplicate resource url: {}, response: {}".format(url
, resp
.text
))
173 elif status_code
== 404:
174 raise NotFound("Not found resource url: {}, response: {}".format(url
, resp
.text
))
175 elif resp
.status_code
in [502, 503]:
176 if not self
.max_retries
or retry
>= self
.max_retries
:
177 raise ServiceUnavailableException("Service unavailable error url: {}".format(url
))
181 raise HttpException("Error status_code: {}, error_text: {}".format(resp
.status_code
, resp
.text
))
183 except ConnectionError
as e
:
184 self
._logger
.error("Connection error executing request: {}".format(repr(e
)))
185 if not self
.max_retries
or retry
>= self
.max_retries
:
186 raise ConnectionError
188 except Exception as e
:
189 self
._logger
.error("Error executing request: {}".format(repr(e
)))
192 def _http_get(self
, url
, headers
, query_params
=None):
193 return requests
.get(url
, headers
=headers
, params
=query_params
)
195 def _http_post_headers(self
, url
, headers
, json_data
=None):
196 return requests
.head(url
, json
=json_data
, headers
=headers
, verify
=False)
198 def _http_post(self
, url
, headers
, json_data
=None):
199 return requests
.post(url
, json
=json_data
, headers
=headers
, verify
=False)
201 def _http_delete(self
, url
, headers
, json_data
=None):
202 return requests
.delete(url
, json
=json_data
, headers
=headers
)