Skip to content

Commit

Permalink
New functions for testing HTTP endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
ssorj committed Jan 2, 2024
1 parent 43d3821 commit 2645962
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 18 deletions.
110 changes: 98 additions & 12 deletions python/skewer/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,39 +73,119 @@ def check_environment():
def await_resource(group, name, timeout=240):
start_time = get_time()

notice(f"Waiting for {group}/{name} to become available")
debug(f"Waiting for {group}/{name} to become available")

while True:
if run(f"kubectl get {group}/{name}", check=False).exit_code == 0:
if run(f"kubectl get {group}/{name}", check=False, quiet=True, stdout=DEVNULL).exit_code == 0:
break

if get_time() - start_time > timeout:
fail(f"Timed out waiting for {group}/{name}")

sleep(5)
sleep(5, quiet=True)

if group == "deployment":
try:
run(f"kubectl wait --for condition=available --timeout {timeout}s {group}/{name}")
run(f"kubectl wait --for condition=available --timeout {timeout}s {group}/{name}", quiet=True, stash=True)
except:
run(f"kubectl logs {group}/{name}")
raise

def await_external_ip(group, name, timeout=240):
start_time = get_time()

debug(f"Waiting for external IP from {group}/{name} to become available")

await_resource(group, name, timeout=timeout)

while True:
if call(f"kubectl get {group}/{name} -o jsonpath='{{.status.loadBalancer.ingress}}'") != "":
if call(f"kubectl get {group}/{name} -o jsonpath='{{.status.loadBalancer.ingress}}'", quiet=True) != "":
break

if get_time() - start_time > timeout:
fail(f"Timed out waiting for external IP for {group}/{name}")

sleep(5)
sleep(5, quiet=True)

return call(f"kubectl get {group}/{name} -o jsonpath='{{.status.loadBalancer.ingress[0].ip}}'", quiet=True)

# def parse_url(url):
# from urllib.parse import urlparse
# return urlparse(url)

# def emit_url(url_object):
# from urllib.parse import urlparse
# return urlparse(url)

def await_http_ok(service_name, url_template, user=None, password=None, timeout=240):
start_time = get_time()

ip = await_external_ip("service", service_name)
url = url_template.format(ip)
insecure = url.startswith("https")

debug(f"Waiting for an HTTP OK response to HTTP GET {url}")

return call(f"kubectl get {group}/{name} -o jsonpath='{{.status.loadBalancer.ingress[0].ip}}'")
while True:
try:
http_get(url, insecure=insecure, user=user, password=password)
except:
if get_time() - start_time > timeout:
fail(f"Timed out waiting for {url}")

sleep(5, quiet=True)
else:
break

def await_console_ok():
password = call("kubectl get secret/skupper-console-users -o jsonpath={.data.admin} | base64 -d", shell=True)
await_http_ok("skupper", "https://{}:8010/", user="admin", password=password)

def _run_curl(method, url, content=None, content_file=None, content_type=None, output_file=None, insecure=False,
user=None, password=None):
check_program("curl")

# XXX args

options = ["-sf"]

if method != "GET":
options.extend(("-X", method))

if content is not None:
assert content_file is None
options.extend(("-H", "Expect:"))
options.extend(("-d", "@-"))

if content_file is not None:
assert content is None, content
options.extend(("-H", "Expect:"))
options.extend(("-d", f"@{content_file}"))

if content_type is not None:
options.extend(("-H", f"'Content-Type: {content_type}'"))

if output_file is not None:
options.extend(("-o", output_file))

if insecure:
options.append("--insecure")

if user is not None:
assert password is not None
options.extend(("--user", f"{user}:{password}"))

options = " ".join(options)
command = "curl {} {}".format(options, url)

if output_file is None:
return call(command, input=content)
else:
make_parent_dir(output_file, quiet=True)
run(command, input=content)

def http_get(url, output_file=None, insecure=False, user=None, password=None):
return _run_curl("GET", url, output_file=output_file, insecure=insecure, user=user, password=password)

def run_steps_minikube(skewer_file, debug=False):
work_dir = make_temp_dir()
Expand Down Expand Up @@ -136,7 +216,6 @@ def run_steps_minikube(skewer_file, debug=False):
kubeconfig = ENV["KUBECONFIG"]

check_file(kubeconfig)
notice(f"Site '{site_name}' kubeconfig: export KUBECONFIG={kubeconfig}")

with open("/tmp/minikube-tunnel-output", "w") as tunnel_output_file:
with start("minikube -p skewer tunnel", output=tunnel_output_file):
Expand Down Expand Up @@ -204,11 +283,11 @@ def _pause_for_demo(work_dir, skewer_data):
with working_env(**first_site["env"]):
console_ip = await_external_ip("service", "skupper")
console_url = f"https://{console_ip}:8010/"
password_data = call("kubectl get secret skupper-console-users -o jsonpath='{.data.admin}'")
password_data = call("kubectl get secret skupper-console-users -o jsonpath='{.data.admin}'", quiet=True)
password = base64_decode(password_data).decode("ascii")

if run("kubectl get service/frontend", check=False, output=DEVNULL).exit_code == 0:
if call("kubectl get service/frontend -o jsonpath='{.spec.type}'") == "LoadBalancer":
if run("kubectl get service/frontend", check=False, output=DEVNULL, quiet=True).exit_code == 0:
if call("kubectl get service/frontend -o jsonpath='{.spec.type}'", quiet=True) == "LoadBalancer":
frontend_ip = await_external_ip("service", "frontend")
frontend_url = f"http://{frontend_ip}:8080/"

Expand Down Expand Up @@ -252,7 +331,7 @@ def _run_step(work_dir, skewer_data, step_data, check=True):
with working_env(**site["env"]):
if site["platform"] == "kubernetes":
namespace = site["namespace"]
run(f"kubectl config set-context --current --namespace {namespace}", quiet=True)
run(f"kubectl config set-context --current --namespace {namespace}", stdout=DEVNULL, quiet=True)

for command in commands:
if command.get("apply") == "readme":
Expand Down Expand Up @@ -281,6 +360,13 @@ def _run_step(work_dir, skewer_data, step_data, check=True):
group, name = resource.split("/", 1)
await_external_ip(group, name)

if "await_http_ok" in command:
service_name, url_template = command["await_http_ok"]
await_http_ok(service_name, url_template)

if "await_console_ok" in command:
await_console_ok()

def generate_readme(skewer_file, output_file):
notice("Generating the readme")
notice(" Skewer file: " + get_absolute_path(skewer_file))
Expand Down
8 changes: 2 additions & 6 deletions python/skewer/standardsteps.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,7 @@ test_the_application:
- run: curl http://<external-ip>:8080/api/health
apply: readme
output: OK
- await_external_ip: service/frontend
- run: curl --fail --verbose --retry 40 --retry-connrefused --retry-delay 5 $(kubectl get service/frontend -o jsonpath='http://{.status.loadBalancer.ingress[0].ip}:8080/api/health')
apply: test
- await_http_ok: [frontend, "http://{}:8080/api/health"]
postamble: |
If everything is in order, you can now access the web interface by
navigating to `http://<external-ip>:8080/` in your browser.
Expand Down Expand Up @@ -212,9 +210,7 @@ accessing_the_web_console:
- run: kubectl get secret/skupper-console-users -o jsonpath={.data.admin} | base64 -d
apply: readme
output: <password>
- await_external_ip: service/skupper
- run: curl --fail --insecure --verbose --retry 40 --retry-connrefused --retry-delay 5 $(kubectl get service/skupper -o jsonpath='https://{.status.loadBalancer.ingress[0].ip}:8010/') --user admin:$(kubectl get secret/skupper-console-users -o jsonpath={.data.admin} | base64 -d); echo
apply: test
- await_console_ok:
postamble: |
Navigate to `<console-url>` in your browser. When prompted, log
in as user `admin` and enter the password.
Expand Down

0 comments on commit 2645962

Please sign in to comment.