diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..ffee3b8 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,22 @@ +name: Build + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.x" + - name: Build package + run: | + python -m pip install --upgrade pip + pip install build + python -m build + - name: Build example container + run: | + make build IMG=kuberhealthy-client:test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..6252b4f --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,28 @@ +name: Publish + +on: + release: + types: [published] + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "3.x" + - name: Build package + run: | + python -m pip install --upgrade pip + pip install build + python -m build + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} + - name: Attach artifacts to release + uses: softprops/action-gh-release@v1 + with: + files: dist/* diff --git a/Dockerfile b/Dockerfile index 9511043..eadedb4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM python:3.11-alpine WORKDIR /app -COPY client.py . +COPY kuberhealthy_client kuberhealthy_client +COPY example example -CMD ["python3", "/app/client.py"] +CMD ["python3", "/app/example/client.py"] diff --git a/README.md b/README.md index bc85cc2..cbc2ac9 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,34 @@ # Python Kuberhealthy Client -This directory contains a minimal Python application that demonstrates how to -report status back to [Kuberhealthy](https://github.com/kuberhealthy/kuberhealthy). -The example loads the `KH_REPORTING_URL` and `KH_RUN_UUID` environment variables -provided to checker pods and includes commented calls to `report_ok` and -`report_error`. +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. + +## Installing + +Install the client into your own project: + +```bash +pip install kuberhealthy-client +``` + +The library exposes two helpers: + +```python +from kuberhealthy_client import report_ok, report_error + +# Environment variables KH_REPORTING_URL and KH_RUN_UUID are read automatically. +report_ok() +report_error("something went wrong") +``` + +Both functions accept optional `url` and `run_uuid` keyword arguments if you prefer to supply values directly. ## Running the example Set the `KH_REPORTING_URL` and `KH_RUN_UUID` environment variables, add your -check logic to `client.py`, and then run: +check logic to `example/client.py`, and then run: ```bash -python3 client.py +python3 example/client.py ``` Within the `main` function, uncomment either `report_ok()` or @@ -30,9 +46,8 @@ make push IMG=myrepo/example-check:latest ## Using in your own checks -1. Add your check logic to `client.py` by replacing the placeholder in `main`. - Call `report_ok()` when the check succeeds or `report_error("message")` - when it fails. +1. Add your check logic to `example/client.py` or your own script. Call `report_ok()` + when the check succeeds or `report_error("message")` when it fails. 2. Build and push your image as shown above. 3. Create a `KuberhealthyCheck` resource pointing at your image and apply it to any cluster where Kuberhealthy runs: diff --git a/example/client.py b/example/client.py new file mode 100644 index 0000000..61934ce --- /dev/null +++ b/example/client.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +"""Example Kuberhealthy client using the :mod:`kuberhealthy_client` package.""" + +from kuberhealthy_client import report_ok, report_error + + +def main() -> None: + """Run the example client.""" + # INSERT YOUR CHECK LOGIC HERE + # report_ok() + # report_error("something went wrong") + pass + + +if __name__ == "__main__": + main() diff --git a/client.py b/kuberhealthy_client/__init__.py similarity index 52% rename from client.py rename to kuberhealthy_client/__init__.py index a046107..3955cd7 100644 --- a/client.py +++ b/kuberhealthy_client/__init__.py @@ -1,15 +1,15 @@ -#!/usr/bin/env python3 -"""Example Kuberhealthy client in Python.""" +"""Lightweight client for reporting check results to Kuberhealthy.""" + +from __future__ import annotations import json import os import urllib.request - +from typing import Optional KH_REPORTING_URL = "KH_REPORTING_URL" KH_RUN_UUID = "KH_RUN_UUID" - def _get_env(name: str) -> str: """Return the value of the environment variable *name* or raise an error.""" value = os.getenv(name) @@ -17,11 +17,10 @@ def _get_env(name: str) -> str: raise EnvironmentError(f"{name} must be set") return value - -def _post_status(payload: dict) -> None: +def _post_status(payload: dict, *, url: Optional[str] = None, run_uuid: Optional[str] = None) -> None: """Send *payload* to the Kuberhealthy reporting URL.""" - url = _get_env(KH_REPORTING_URL) - run_uuid = _get_env(KH_RUN_UUID) + url = url or _get_env(KH_REPORTING_URL) + run_uuid = run_uuid or _get_env(KH_RUN_UUID) data = json.dumps(payload).encode("utf-8") request = urllib.request.Request( url, @@ -31,24 +30,12 @@ def _post_status(payload: dict) -> None: with urllib.request.urlopen(request, timeout=10) as response: # nosec B310 response.read() - -def report_ok() -> None: +def report_ok(*, url: Optional[str] = None, run_uuid: Optional[str] = None) -> None: """Report a successful check to Kuberhealthy.""" - _post_status({"OK": True, "Errors": []}) + _post_status({"OK": True, "Errors": []}, url=url, run_uuid=run_uuid) - -def report_error(message: str) -> None: +def report_error(message: str, *, url: Optional[str] = None, run_uuid: Optional[str] = None) -> None: """Report a failure to Kuberhealthy with *message* as the error.""" - _post_status({"OK": False, "Errors": [message]}) - - -def main() -> None: - """Run the example client.""" - # INSERT YOUR CHECK LOGIC HERE - # report_ok() - # report_error("something went wrong") - pass - + _post_status({"OK": False, "Errors": [message]}, url=url, run_uuid=run_uuid) -if __name__ == "__main__": - main() +__all__ = ["report_ok", "report_error", "KH_REPORTING_URL", "KH_RUN_UUID"] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..36ab018 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "kuberhealthy-client" +version = "0.1.0" +description = "Python client for reporting check results to Kuberhealthy" +readme = "README.md" +authors = [{name = "Kuberhealthy"}] +license = {text = "Apache-2.0"} +requires-python = ">=3.8" + +[tool.setuptools.packages.find] +where = ["."] +include = ["kuberhealthy_client"]