Skip to content

Commit

Permalink
add support for HTTP POST to a pod
Browse files Browse the repository at this point in the history
  • Loading branch information
edaniszewski committed Jul 26, 2019
1 parent a2052de commit ed7e154
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 14 deletions.
13 changes: 5 additions & 8 deletions examples/configs/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ spec:
spec:
terminationGracePeriodSeconds: 3
containers:
- name: synse-server
image: vaporio/synse-server:latest
- name: http-listener
image: mendhak/http-https-echo
ports:
- name: http
containerPort: 5000
args: [ 'enable-emulator' ]
env:
# Enable debug logging via ENV config
- name: SYNSE_LOGGING
value: debug
containerPort: 80
- name: https
containerPort: 443
resources:
requests:
cpu: 25m
Expand Down
2 changes: 1 addition & 1 deletion examples/configs/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ spec:
app: test
ports:
- protocol: TCP
port: 5000
port: 8080
targetPort: http
name: http
37 changes: 37 additions & 0 deletions examples/test_deployment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import os

import time


def test_deployment(kube):

Expand All @@ -24,6 +26,41 @@ def test_deployment(kube):
p = pods[0]
p.wait_until_ready(timeout=10)

# Issue an HTTP GET against the Pod. The deployment
# is an http echo server, so we should get back data
# about the request.
r = p.http_proxy_get(
'/test/get',
query_params={'abc': 123},
)
get_data = r.json()
assert get_data['path'] == '/test/get'
assert get_data['method'] == 'GET'
assert get_data['body'] == ''
# fixme (etd): I would expect this to be {'abc': 123}, matching
# the input data types (e.g. value not a string). Need to determine
# where this issue lies..
# This may be an issue with the image reflecting the request back.
assert get_data['query'] == {'abc': '123'}

# Issue an HTTP POST against the Pod. The deployment
# is an http echo server, so we should get back data
# about the request.
r = p.http_proxy_post(
'/test/post',
query_params={'abc': 123},
data='foobar',
)
post_data = r.json()
assert post_data['path'] == '/test/post'
assert post_data['method'] == 'POST'
assert post_data['body'] == '"foobar"'
# fixme (etd): I would expect this to be {'abc': 123}, matching
# the input data types (e.g. value not a string). Need to determine
# where this issue lies..
# This may be an issue with the image reflecting the request back.
assert post_data['query'] == {'abc': '123'}

containers = p.get_containers()
c = containers[0]
assert len(c.get_logs()) != 0
Expand Down
6 changes: 3 additions & 3 deletions examples/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ def test_service(kube):
endpoints = svc.get_endpoints()
assert len(endpoints) == 1

resp = svc.proxy_http_get("synse/test")
resp = svc.proxy_http_get("test/get")
assert len(resp) != 0

d = ast.literal_eval(resp)
assert d.get("status") == "ok"
assert d.get("timestamp") is not None
assert d.get("path") == "/test/get"
assert d.get("method") == "GET"

kube.delete(svc)
kube.delete(dep)
Expand Down
73 changes: 71 additions & 2 deletions kubetest/objects/pod.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def http_proxy_get(self, path, query_params=None):
This function does not use the kubernetes
``connect_get_namespaced_pod_proxy_with_path`` function because there
appears to be lack of support for custom query parameters (as of
the ``kubernetes==7.0.0`` package version). To bypass this, parts of
the ``kubernetes==9.0.0`` package version). To bypass this, parts of
the core functionality from the aforementioned function are used here with
the modification of allowing user-defined query parameters to be
passed along.
Expand Down Expand Up @@ -224,7 +224,76 @@ def http_proxy_get(self, path, query_params=None):
response_type='str',
auth_settings=auth_settings,
_return_http_data_only=False, # we want all info, not just data
_preload_content=True,
_preload_content=False,
_request_timeout=None,
collection_formats={}
))
except ApiException as e:
# if the ApiException does not have a body or headers, that
# means the raised exception did not get a response (even if
# it were 404, 500, etc), so we want to continue to raise in
# that case. if there is a body and headers, we will not raise
# and just take the data out that we need from the exception.
if e.body is None and e.headers is None:
raise

resp = response.Response(
data=e.body,
status=e.status,
headers=e.headers,
)

return resp

def http_proxy_post(self, path, query_params=None, data=None):
"""Issue a POST request to a proxy for the Pod.
Notes:
This function does not use the kubernetes
``connect_post_namespaced_pod_proxy_with_path`` function because there
appears to be lack of support for custom query parameters (as of
the ``kubernetes==9.0.0`` package version). To bypass this, parts of
the core functionality from the aforementioned function are used here with
the modification of allowing user-defined query parameters to be
passed along.
Args:
path (str): The URI path for the request.
query_params (dict[str, str]): Any query parameters for
the request. (default: None)
data: The data to POST.
Returns:
response.Response: The response data.
"""
c = client.CoreV1Api()

if query_params is None:
query_params = {}

path_params = {
'name': self.name,
'namespace': self.namespace
}
header_params = {
'Accept': c.api_client.select_header_accept(['*/*']),
'Content-Type': c.api_client.select_header_content_type(['*/*'])
}
auth_settings = ['BearerToken']

try:
resp = response.Response(*c.api_client.call_api(
'/api/v1/namespaces/{namespace}/pods/{name}/proxy/' + path, 'POST',
path_params=path_params,
query_params=query_params,
header_params=header_params,
body=data,
post_params=[],
files={},
response_type='str',
auth_settings=auth_settings,
_return_http_data_only=False, # we want all info, not just data
_preload_content=False,
_request_timeout=None,
collection_formats={}
))
Expand Down
17 changes: 17 additions & 0 deletions kubetest/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import json

import urllib3


class Response:
"""Response is a wrapper around the Kubernetes API's response data
Expand Down Expand Up @@ -35,6 +37,21 @@ def json(self):
Returns:
dict: The JSON data.
"""
# This should generally be the case, since the primary source of Response
# instances are the HTTP methods on Pods (e.g. http_proxy_get), where
# `_preload_content=False`. Should that be set to True, it will not return
# the HTTPResponse but will instead return the response data formatted as
# the type specified in the `response_type` param.
#
# Note that I have found setting _preload_content to True (the default value
# for the Kubernetes client) to be difficult to deal with from a generic interface
# because it requires you to know the expected output ("str", "dict", ...)
# and pass that in as a param, where that could really be abstracted away from
# the user. For that reason, it is currently set to False -- this may change
# in the future if desired.
if isinstance(self.data, urllib3.HTTPResponse):
return json.loads(self.data.data)

# the response data comes back as a string formatted as a python
# dictionary might be, where the inner quotes are single quotes
# (') instead of the double quotes (") expected by JSON standard.
Expand Down

0 comments on commit ed7e154

Please sign in to comment.