Skip to content

Commit 3e1f9d6

Browse files
author
Matthew Fisher
authored
ref(scheduler): add HTTP functions in KubeHTTPClient (#1019)
these functions properly handle connection errors and clean up some of the child/parent class relations when making a request.
1 parent 13de6e6 commit 3e1f9d6

13 files changed

Lines changed: 224 additions & 35 deletions

rootfs/scheduler/__init__.py

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
from datetime import datetime
33
import logging
44
import requests
5+
import requests.exceptions
56
from requests_toolbelt import user_agent
67
import time
8+
from urllib.parse import urljoin
79

810
from api import __version__ as deis_version
911
from scheduler.exceptions import KubeException, KubeHTTPException # noqa
@@ -73,7 +75,7 @@ def __getattr__(self, name):
7375

7476
def version(self):
7577
"""Get Kubernetes version as a float"""
76-
response = self.session.get(self.url + '/version')
78+
response = self.http_get('/version')
7779
if self.unhealthy(response.status_code):
7880
raise KubeHTTPException(response, 'fetching Kubernetes version')
7981

@@ -139,6 +141,89 @@ def log(namespace, message, level='INFO'):
139141
lvl = getattr(logging, level.upper()) if hasattr(logging, level.upper()) else logging.INFO
140142
logger.log(lvl, "[{}]: {}".format(namespace, message))
141143

144+
def http_head(self, path, **kwargs):
145+
"""
146+
Make a HEAD request to the k8s server.
147+
"""
148+
try:
149+
150+
url = urljoin(self.url, path)
151+
response = self.session.head(url, **kwargs)
152+
except requests.exceptions.ConnectionError as err:
153+
# reraise as KubeException, but log stacktrace.
154+
message = "There was a problem retrieving headers from " \
155+
"the Kubernetes API server. URL: {}".format(url)
156+
logger.error(message)
157+
raise KubeException(message) from err
158+
159+
return response
160+
161+
def http_get(self, path, params=None, **kwargs):
162+
"""
163+
Make a GET request to the k8s server.
164+
"""
165+
try:
166+
url = urljoin(self.url, path)
167+
response = self.session.get(url, params=params, **kwargs)
168+
except requests.exceptions.ConnectionError as err:
169+
# reraise as KubeException, but log stacktrace.
170+
message = "There was a problem retrieving data from " \
171+
"the Kubernetes API server. URL: {}, params: {}".format(url, params)
172+
logger.error(message)
173+
raise KubeException(message) from err
174+
175+
return response
176+
177+
def http_post(self, path, data=None, json=None, **kwargs):
178+
"""
179+
Make a POST request to the k8s server.
180+
"""
181+
try:
182+
url = urljoin(self.url, path)
183+
response = self.session.post(url, data=data, json=json, **kwargs)
184+
except requests.exceptions.ConnectionError as err:
185+
# reraise as KubeException, but log stacktrace.
186+
message = "There was a problem posting data to " \
187+
"the Kubernetes API server. URL: {}, " \
188+
"data: {}, json: {}".format(url, data, json)
189+
logger.error(message)
190+
raise KubeException(message) from err
191+
192+
return response
193+
194+
def http_put(self, path, data=None, **kwargs):
195+
"""
196+
Make a PUT request to the k8s server.
197+
"""
198+
try:
199+
url = urljoin(self.url, path)
200+
response = self.session.put(url, data=data, **kwargs)
201+
except requests.exceptions.ConnectionError as err:
202+
# reraise as KubeException, but log stacktrace.
203+
message = "There was a problem putting data to " \
204+
"the Kubernetes API server. URL: {}, " \
205+
"data: {}".format(url, data)
206+
logger.error(message)
207+
raise KubeException(message) from err
208+
209+
return response
210+
211+
def http_delete(self, path, **kwargs):
212+
"""
213+
Make a DELETE request to the k8s server.
214+
"""
215+
try:
216+
url = urljoin(self.url, path)
217+
response = self.session.delete(url, **kwargs)
218+
except requests.exceptions.ConnectionError as err:
219+
# reraise as KubeException, but log stacktrace.
220+
message = "There was a problem deleting data from " \
221+
"the Kubernetes API server. URL: {}".format(url)
222+
logger.error(message)
223+
raise KubeException(message) from err
224+
225+
return response
226+
142227
def deploy(self, namespace, name, image, entrypoint, command, **kwargs): # noqa
143228
"""Deploy Deployment depending on what's requested"""
144229
app_type = kwargs.get('app_type')
@@ -226,7 +311,7 @@ def run(self, namespace, name, image, entrypoint, command, **kwargs):
226311
manifest = self.pod.manifest(namespace, name, image, **kwargs)
227312

228313
url = self.pods.api("/namespaces/{}/pods", namespace)
229-
response = self.session.post(url, json=manifest)
314+
response = self.http_post(url, json=manifest)
230315
if self.unhealthy(response.status_code):
231316
raise KubeHTTPException(response, 'create Pod in Namespace "{}"', namespace)
232317

rootfs/scheduler/resources/__resource.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from urllib.parse import urljoin
21
from .. import KubeHTTPClient
32

43

@@ -26,5 +25,4 @@ class Resource(KubeHTTPClient, metaclass=ResourceRegistry):
2625

2726
def api(self, tmpl, *args):
2827
"""Return a fully-qualified Kubernetes API URL from a string template with args."""
29-
url = "/{}/{}".format(self.api_prefix, self.api_version) + tmpl.format(*args)
30-
return urljoin(self.url, url)
28+
return "/{}/{}".format(self.api_prefix, self.api_version) + tmpl.format(*args)

rootfs/scheduler/resources/deployment.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def get(self, namespace, name=None, **kwargs):
2323
message = 'get Deployments in Namespace "{}"'
2424

2525
url = self.api(url, *args)
26-
response = self.session.get(url, params=self.query_params(**kwargs))
26+
response = self.http_get(url, params=self.query_params(**kwargs))
2727
if self.unhealthy(response.status_code):
2828
args.reverse() # error msg is in reverse order
2929
raise KubeHTTPException(response, message, *args)
@@ -111,7 +111,7 @@ def create(self, namespace, name, image, entrypoint, command, **kwargs):
111111
entrypoint, command, **kwargs)
112112

113113
url = self.api("/namespaces/{}/deployments", namespace)
114-
response = self.session.post(url, json=manifest)
114+
response = self.http_post(url, json=manifest)
115115
if self.unhealthy(response.status_code):
116116
raise KubeHTTPException(
117117
response,
@@ -129,7 +129,7 @@ def update(self, namespace, name, image, entrypoint, command, **kwargs):
129129
entrypoint, command, **kwargs)
130130

131131
url = self.api("/namespaces/{}/deployments/{}", namespace, name)
132-
response = self.session.put(url, json=manifest)
132+
response = self.http_put(url, json=manifest)
133133
if self.unhealthy(response.status_code):
134134
self.log(namespace, 'template used: {}'.format(json.dumps(manifest, indent=4)), 'DEBUG') # noqa
135135
raise KubeHTTPException(response, 'update Deployment "{}"', name)
@@ -141,7 +141,7 @@ def update(self, namespace, name, image, entrypoint, command, **kwargs):
141141

142142
def delete(self, namespace, name):
143143
url = self.api("/namespaces/{}/deployments/{}", namespace, name)
144-
response = self.session.delete(url)
144+
response = self.http_delete(url)
145145
if self.unhealthy(response.status_code):
146146
raise KubeHTTPException(
147147
response,

rootfs/scheduler/resources/horizontalpodautoscaler.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def get(self, namespace, name=None, **kwargs):
3131
message = 'get HorizontalPodAutoscalers in Namespace "{}"'
3232

3333
url = self.api(url, *args)
34-
response = self.session.get(url, params=self.query_params(**kwargs))
34+
response = self.http_get(url, params=self.query_params(**kwargs))
3535
if self.unhealthy(response.status_code):
3636
args.reverse() # error msg is in reverse order
3737
raise KubeHTTPException(response, message, *args)
@@ -97,7 +97,7 @@ def create(self, namespace, name, app_type, target, **kwargs):
9797
manifest = self.manifest(namespace, name, app_type, target, **kwargs)
9898

9999
url = self.api("/namespaces/{}/horizontalpodautoscalers", namespace)
100-
response = self.session.post(url, json=manifest)
100+
response = self.http_post(url, json=manifest)
101101
if self.unhealthy(response.status_code):
102102
self.log(namespace, 'template used: {}'.format(json.dumps(manifest, indent=4)), 'DEBUG') # noqa
103103
raise KubeHTTPException(
@@ -115,7 +115,7 @@ def update(self, namespace, name, app_type, target, **kwargs):
115115
manifest = self.manifest(namespace, name, app_type, target, **kwargs)
116116

117117
url = self.api("/namespaces/{}/horizontalpodautoscalers/{}", namespace, name)
118-
response = self.session.put(url, json=manifest)
118+
response = self.http_put(url, json=manifest)
119119
if self.unhealthy(response.status_code):
120120
self.log(namespace, 'template used: {}'.format(json.dumps(manifest, indent=4)), 'DEBUG') # noqa
121121
raise KubeHTTPException(response, 'update HorizontalPodAutoscaler "{}"', name)
@@ -128,7 +128,7 @@ def update(self, namespace, name, app_type, target, **kwargs):
128128

129129
def delete(self, namespace, name):
130130
url = self.api("/namespaces/{}/horizontalpodautoscalers/{}", namespace, name)
131-
response = self.session.delete(url)
131+
response = self.http_delete(url)
132132
if self.unhealthy(response.status_code):
133133
raise KubeHTTPException(
134134
response,

rootfs/scheduler/resources/namespace.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def get(self, name=None, **kwargs):
1919
message = 'get Namespaces'
2020

2121
url = self.api(url, *args)
22-
response = self.session.get(url, params=self.query_params(**kwargs))
22+
response = self.http_get(url, params=self.query_params(**kwargs))
2323
if self.unhealthy(response.status_code):
2424
args.reverse() # error msg is in reverse order
2525
raise KubeHTTPException(response, message, *args)
@@ -39,23 +39,23 @@ def create(self, namespace):
3939
}
4040
}
4141

42-
response = self.session.post(url, json=data)
42+
response = self.http_post(url, json=data)
4343
if not response.status_code == 201:
4444
raise KubeHTTPException(response, "create Namespace {}".format(namespace))
4545

4646
return response
4747

4848
def delete(self, namespace):
4949
url = self.api("/namespaces/{}", namespace)
50-
response = self.session.delete(url)
50+
response = self.http_delete(url)
5151
if self.unhealthy(response.status_code):
5252
raise KubeHTTPException(response, 'delete Namespace "{}"', namespace)
5353

5454
return response
5555

5656
def events(self, namespace, **kwargs):
5757
url = self.api("/namespaces/{}/events", namespace)
58-
response = self.session.get(url, params=self.query_params(**kwargs))
58+
response = self.http_get(url, params=self.query_params(**kwargs))
5959
if self.unhealthy(response.status_code):
6060
raise KubeHTTPException(response, "get Events in Namespace {}", namespace)
6161

rootfs/scheduler/resources/node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def get(self, name=None, **kwargs):
1919
message = 'get Nodes'
2020

2121
url = self.api(url, *args)
22-
response = self.session.get(url, params=self.query_params(**kwargs))
22+
response = self.http_get(url, params=self.query_params(**kwargs))
2323
if self.unhealthy(response.status_code):
2424
args.reverse() # error msg is in reverse order
2525
raise KubeHTTPException(response, message, *args)

rootfs/scheduler/resources/pod.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def get(self, namespace, name=None, **kwargs):
2626
message = 'get Pods in Namespace "{}"'
2727

2828
url = self.api(url, *args)
29-
response = self.session.get(url, params=self.query_params(**kwargs))
29+
response = self.http_get(url, params=self.query_params(**kwargs))
3030
if self.unhealthy(response.status_code):
3131
args.reverse() # error msg is in reverse order
3232
raise KubeHTTPException(response, message, *args)
@@ -324,7 +324,7 @@ def delete(self, namespace, name):
324324

325325
# delete pod
326326
url = self.api("/namespaces/{}/pods/{}", namespace, name)
327-
resp = self.session.delete(url)
327+
resp = self.http_delete(url)
328328
if self.unhealthy(resp.status_code):
329329
raise KubeHTTPException(resp, 'delete Pod "{}" in Namespace "{}"', name, namespace)
330330

@@ -344,7 +344,7 @@ def delete(self, namespace, name):
344344

345345
def logs(self, namespace, name):
346346
url = self.api("/namespaces/{}/pods/{}/log", namespace, name)
347-
response = self.session.get(url)
347+
response = self.http_get(url)
348348
if self.unhealthy(response.status_code):
349349
raise KubeHTTPException(
350350
response,

rootfs/scheduler/resources/replicaset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def get(self, namespace, name=None, **kwargs):
2121
message = 'get ReplicaSets in Namespace "{}"'
2222

2323
url = self.api(url, *args)
24-
response = self.session.get(url, params=self.query_params(**kwargs))
24+
response = self.http_get(url, params=self.query_params(**kwargs))
2525
if self.unhealthy(response.status_code):
2626
args.reverse() # error msg is in reverse order
2727
raise KubeHTTPException(response, message, *args)

rootfs/scheduler/resources/replicationcontroller.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def get(self, namespace, name=None, **kwargs):
2121
message = 'get ReplicationControllers in Namespace "{}"'
2222

2323
url = self.api(url, *args)
24-
response = self.session.get(url, params=self.query_params(**kwargs))
24+
response = self.http_get(url, params=self.query_params(**kwargs))
2525
if self.unhealthy(response.status_code):
2626
args.reverse() # error msg is in reverse order
2727
raise KubeHTTPException(response, message, *args)
@@ -54,7 +54,7 @@ def create(self, namespace, name, image, entrypoint, command, **kwargs):
5454
manifest['spec']['template'] = self.pod.manifest(namespace, name, image, **kwargs)
5555

5656
url = self.api("/namespaces/{}/replicationcontrollers", namespace)
57-
resp = self.session.post(url, json=manifest)
57+
resp = self.http_post(url, json=manifest)
5858
if self.unhealthy(resp.status_code):
5959
raise KubeHTTPException(
6060
resp,
@@ -68,15 +68,15 @@ def create(self, namespace, name, image, entrypoint, command, **kwargs):
6868

6969
def update(self, namespace, name, data):
7070
url = self.api("/namespaces/{}/replicationcontrollers/{}", namespace, name)
71-
response = self.session.put(url, json=data)
71+
response = self.http_put(url, json=data)
7272
if self.unhealthy(response.status_code):
7373
raise KubeHTTPException(response, 'scale ReplicationController "{}"', name)
7474

7575
return response
7676

7777
def delete(self, namespace, name):
7878
url = self.api("/namespaces/{}/replicationcontrollers/{}", namespace, name)
79-
response = self.session.delete(url)
79+
response = self.http_delete(url)
8080
if self.unhealthy(response.status_code):
8181
raise KubeHTTPException(
8282
response,

rootfs/scheduler/resources/scale.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def update(self, namespace, name, replicas, target):
2626

2727
manifest = self.manifest(namespace, name, replicas)
2828
url = self.api("/namespaces/{}/{}/{}/scale", namespace, resource_type, name)
29-
response = self.session.put(url, json=manifest)
29+
response = self.http_put(url, json=manifest)
3030
if self.unhealthy(response.status_code):
3131
raise KubeHTTPException(
3232
response,

0 commit comments

Comments
 (0)