Skip to content

Commit e58fce3

Browse files
committed
feat: add Python client package and CI
1 parent 52cf1cd commit e58fce3

File tree

7 files changed

+133
-48
lines changed

7 files changed

+133
-48
lines changed

.github/workflows/build.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Build
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v3
12+
- uses: actions/setup-python@v4
13+
with:
14+
python-version: "3.x"
15+
- name: Build package
16+
run: |
17+
python -m pip install --upgrade pip
18+
pip install build
19+
python -m build
20+
- name: Build example container
21+
run: |
22+
make build IMG=kuberhealthy-client:test

.github/workflows/publish.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Publish
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
jobs:
8+
publish:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v3
12+
- uses: actions/setup-python@v4
13+
with:
14+
python-version: "3.x"
15+
- name: Build package
16+
run: |
17+
python -m pip install --upgrade pip
18+
pip install build
19+
python -m build
20+
- name: Publish to PyPI
21+
uses: pypa/gh-action-pypi-publish@release/v1
22+
with:
23+
user: __token__
24+
password: ${{ secrets.PYPI_API_TOKEN }}
25+
- name: Attach artifacts to release
26+
uses: softprops/action-gh-release@v1
27+
with:
28+
files: dist/*

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
FROM python:3.11-alpine
22

33
WORKDIR /app
4+
COPY kuberhealthy_client kuberhealthy_client
45
COPY client.py .
56

67
CMD ["python3", "/app/client.py"]

README.md

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
# Python Kuberhealthy Client
22

3-
This directory contains a minimal Python application that demonstrates how to
4-
report status back to [Kuberhealthy](https://github.com/kuberhealthy/kuberhealthy).
5-
The example loads the `KH_REPORTING_URL` and `KH_RUN_UUID` environment variables
6-
provided to checker pods and includes commented calls to `report_ok` and
7-
`report_error`.
3+
This repository provides a small Python library for reporting check results back to [Kuberhealthy](https://github.com/kuberhealthy/kuberhealthy). It also includes a runnable example program and container configuration.
4+
5+
## Installing
6+
7+
Install the client into your own project:
8+
9+
```bash
10+
pip install kuberhealthy-client
11+
```
12+
13+
The library exposes two helpers:
14+
15+
```python
16+
from kuberhealthy_client import report_ok, report_error
17+
18+
# Environment variables KH_REPORTING_URL and KH_RUN_UUID are read automatically.
19+
report_ok()
20+
report_error("something went wrong")
21+
```
22+
23+
Both functions accept optional `url` and `run_uuid` keyword arguments if you prefer to supply values directly.
824

925
## Running the example
1026

@@ -30,9 +46,8 @@ make push IMG=myrepo/example-check:latest
3046

3147
## Using in your own checks
3248

33-
1. Add your check logic to `client.py` by replacing the placeholder in `main`.
34-
Call `report_ok()` when the check succeeds or `report_error("message")`
35-
when it fails.
49+
1. Add your check logic to `client.py` or your own script. Call `report_ok()`
50+
when the check succeeds or `report_error("message")` when it fails.
3651
2. Build and push your image as shown above.
3752
3. Create a `KuberhealthyCheck` resource pointing at your image and apply it to any
3853
cluster where Kuberhealthy runs:

client.py

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,7 @@
11
#!/usr/bin/env python3
2-
"""Example Kuberhealthy client in Python."""
2+
"""Example Kuberhealthy client using the :mod:`kuberhealthy_client` package."""
33

4-
import json
5-
import os
6-
import urllib.request
7-
8-
9-
KH_REPORTING_URL = "KH_REPORTING_URL"
10-
KH_RUN_UUID = "KH_RUN_UUID"
11-
12-
13-
def _get_env(name: str) -> str:
14-
"""Return the value of the environment variable *name* or raise an error."""
15-
value = os.getenv(name)
16-
if not value:
17-
raise EnvironmentError(f"{name} must be set")
18-
return value
19-
20-
21-
def _post_status(payload: dict) -> None:
22-
"""Send *payload* to the Kuberhealthy reporting URL."""
23-
url = _get_env(KH_REPORTING_URL)
24-
run_uuid = _get_env(KH_RUN_UUID)
25-
data = json.dumps(payload).encode("utf-8")
26-
request = urllib.request.Request(
27-
url,
28-
data=data,
29-
headers={"content-type": "application/json", "kh-run-uuid": run_uuid},
30-
)
31-
with urllib.request.urlopen(request, timeout=10) as response: # nosec B310
32-
response.read()
33-
34-
35-
def report_ok() -> None:
36-
"""Report a successful check to Kuberhealthy."""
37-
_post_status({"OK": True, "Errors": []})
38-
39-
40-
def report_error(message: str) -> None:
41-
"""Report a failure to Kuberhealthy with *message* as the error."""
42-
_post_status({"OK": False, "Errors": [message]})
4+
from kuberhealthy_client import report_ok, report_error
435

446

457
def main() -> None:

kuberhealthy_client/__init__.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""Lightweight client for reporting check results to Kuberhealthy."""
2+
3+
from __future__ import annotations
4+
5+
import json
6+
import os
7+
import urllib.request
8+
from typing import Optional
9+
10+
KH_REPORTING_URL = "KH_REPORTING_URL"
11+
KH_RUN_UUID = "KH_RUN_UUID"
12+
13+
def _get_env(name: str) -> str:
14+
"""Return the value of the environment variable *name* or raise an error."""
15+
value = os.getenv(name)
16+
if not value:
17+
raise EnvironmentError(f"{name} must be set")
18+
return value
19+
20+
def _post_status(payload: dict, *, url: Optional[str] = None, run_uuid: Optional[str] = None) -> None:
21+
"""Send *payload* to the Kuberhealthy reporting URL."""
22+
url = url or _get_env(KH_REPORTING_URL)
23+
run_uuid = run_uuid or _get_env(KH_RUN_UUID)
24+
data = json.dumps(payload).encode("utf-8")
25+
request = urllib.request.Request(
26+
url,
27+
data=data,
28+
headers={"content-type": "application/json", "kh-run-uuid": run_uuid},
29+
)
30+
with urllib.request.urlopen(request, timeout=10) as response: # nosec B310
31+
response.read()
32+
33+
def report_ok(*, url: Optional[str] = None, run_uuid: Optional[str] = None) -> None:
34+
"""Report a successful check to Kuberhealthy."""
35+
_post_status({"OK": True, "Errors": []}, url=url, run_uuid=run_uuid)
36+
37+
def report_error(message: str, *, url: Optional[str] = None, run_uuid: Optional[str] = None) -> None:
38+
"""Report a failure to Kuberhealthy with *message* as the error."""
39+
_post_status({"OK": False, "Errors": [message]}, url=url, run_uuid=run_uuid)
40+
41+
__all__ = ["report_ok", "report_error", "KH_REPORTING_URL", "KH_RUN_UUID"]

pyproject.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "kuberhealthy-client"
7+
version = "0.1.0"
8+
description = "Python client for reporting check results to Kuberhealthy"
9+
readme = "README.md"
10+
authors = [{name = "Kuberhealthy"}]
11+
license = {text = "Apache-2.0"}
12+
requires-python = ">=3.8"
13+
14+
[tool.setuptools.packages.find]
15+
where = ["."]
16+
include = ["kuberhealthy_client"]

0 commit comments

Comments
 (0)