Skip to content

Commit

Permalink
Improve tests and docs (#12)
Browse files Browse the repository at this point in the history
- Removed example folders and updated readme with clearer explanation
- Docker images get tagged with {ref_name}-py{version} and latest-py{version}
- Added new tests folder with projects: flask, fastapi, simple, simple_async. All follow the same pattern to store, retrieve and delete items from a dict.
- Fixed issues encountered thanks to new tests added.
- Validating WSGI implementation with wsgiref.
  • Loading branch information
mliezun authored May 4, 2024
1 parent 0e35fa5 commit 828c0c6
Show file tree
Hide file tree
Showing 29 changed files with 783 additions and 236 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Docker

on:
push:
branches: [ "main" ]
# branches: [ "main" ]
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]
pull_request:
Expand Down Expand Up @@ -74,7 +74,7 @@ jobs:
context: .
push: ${{ github.event_name != 'pull_request' }}
build-args: PY_VERSION=${{ matrix.python-version }}
tags: ${{ steps.meta.outputs.tags }}-py${{ matrix.python-version }}
tags: ${{ github.ref_name }}-py${{ matrix.python-version }},latest-py${{ matrix.python-version }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
Expand Down
41 changes: 41 additions & 0 deletions .github/workflows/go_tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
name: Go Tests
on:
pull_request:
branches:
- main
push:
branches:
- main
jobs:
tests:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12']
env:
GOEXPERIMENT: cgocheck2
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.21'
cache: false
- name: Install Xcaddy
run: go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
- name: Set up Python ${{ matrix.python-version }}
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update -yyqq
sudo apt-get install -yyqq software-properties-common
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt-get install -yyqq python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv
sudo mv /usr/lib/x86_64-linux-gnu/pkgconfig/python-${{ matrix.python-version }}-embed.pc /usr/lib/x86_64-linux-gnu/pkgconfig/python3-embed.pc
- name: Install global python dependencies
run: sudo pip install requests
- name: Run module tests
run: go test -race -v ./...
- name: Build the server
run: CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake=.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
name: Tests
name: Integration Tests
on:
pull_request:
branches:
Expand All @@ -13,6 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
tool-name: ['flask', 'fastapi', 'simple', 'simple_async']
python-version: ['3.9', '3.10', '3.11', '3.12']
env:
GOEXPERIMENT: cgocheck2
Expand All @@ -25,26 +26,23 @@ jobs:
- name: Install Xcaddy
run: go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
- name: Set up Python ${{ matrix.python-version }}
working-directory: tests/${{ matrix.tool-name }}/
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update -yyqq
sudo apt-get install -yyqq software-properties-common
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt-get install -yyqq python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv
sudo mv /usr/lib/x86_64-linux-gnu/pkgconfig/python-${{ matrix.python-version }}-embed.pc /usr/lib/x86_64-linux-gnu/pkgconfig/python3-embed.pc
python${{ matrix.python-version }} -m venv examples/venv
source examples/venv/bin/activate
pip install -r examples/requirements.txt
- name: Install global python dependencies
run: sudo pip install requests
- name: Run module tests
run: go test -race -v ./...
python${{ matrix.python-version }} -m venv venv
source venv/bin/activate
pip install -r requirements.txt
- name: Build the server
working-directory: examples/
run: CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake=..
working-directory: tests/${{ matrix.tool-name }}/
run: CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake=../..
- name: Run integration tests
working-directory: examples/
working-directory: tests/${{ matrix.tool-name }}/
run: |
./caddy run --config Caddyfile &
sleep 10
python ../examples_test.py
./caddy run --config Caddyfile 2>/dev/null &
sleep 2
python main_test.py
187 changes: 93 additions & 94 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,145 +6,143 @@ This plugin provides native support for Python apps.

It embeds the Python interpreter inside Caddy and serves requests directly without going through a reverse proxy.

It supports both WSGI and ASGI, which means you can run all types of frameworks like Flask, Django and FastAPI.
Supports both WSGI and ASGI, which means you can run all types of frameworks like Flask, Django and FastAPI.

## Docker image
## Quickstart

There's a docker image available, it ships Python 3.12 and can be used as follows:
#### Requirements

```Dockerfile
FROM ghcr.io/mliezun/caddy-snake:main

WORKDIR /app
- Python >= 3.9 + dev files
- C compiler and build tools
- Go >= 1.21 and [Xcaddy](https://github.com/caddyserver/xcaddy)

# Copy your project into app
COPY . /app
Install requirements on Ubuntu 24.04:

# Caddy snake is already installed and has support for Python 3.12
CMD ["caddy", "run", "--config", "/app/Caddyfile"]
```
$ sudo apt-get install python3-dev build-essential pkg-config golang
$ go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
```

## Build from source
You can also [build with Docker](#build-with-docker-or-podman).

Go 1.21 and Python 3.9 or later is required, with development files to embed the interpreter.
#### Example usage: Flask

To install in Ubuntu do:
`main.py`

```bash
sudo apt-get update
sudo apt-get install -y python3-dev
```
```python
from flask import Flask

To install in macOS do:
app = Flask(__name__)

```bash
brew install python@3
@app.route("/hello-world")
def hello():
return "Hello world!"
```

### Bundling with Caddy

Build this module using [xcaddy](https://github.com/caddyserver/xcaddy):
`Caddyfile`

```bash
CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake@v0.0.5
```Caddyfile
localhost:9080 {
route {
python {
module_wsgi "main:app"
}
}
}
```

### Build with Docker (or Podman)
Run:

There's a template file in the project: [builder.Dockerfile](/builder.Dockerfile). It supports build arguments to configure which Python or Go version is desired for the build.

```Dockerfile
FROM ubuntu:22.04

ARG GO_VERSION=1.22.1
ARG PY_VERSION=3.12

RUN export DEBIAN_FRONTEND=noninteractive &&\
apt-get update -yyqq &&\
apt-get install -yyqq wget tar software-properties-common gcc pkgconf &&\
add-apt-repository -y ppa:deadsnakes/ppa &&\
apt-get update -yyqq &&\
apt-get install -yyqq python${PY_VERSION}-dev &&\
mv /usr/lib/x86_64-linux-gnu/pkgconfig/python-${PY_VERSION}-embed.pc /usr/lib/x86_64-linux-gnu/pkgconfig/python3-embed.pc &&\
rm -rf /var/lib/apt/lists/* &&\
wget https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz && \
tar -C /usr/local -xzf go*.linux-amd64.tar.gz && \
rm go*.linux-amd64.tar.gz

ENV PATH=$PATH:/usr/local/go/bin

RUN go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest &&\
cd /usr/local/bin &&\
CGO_ENABLED=1 /root/go/bin/xcaddy build --with github.com/mliezun/caddy-snake &&\
rm -rf /build
```
$ pip install Flask
$ CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake
$ ./caddy run --config Caddyfile
```

CMD ["cp", "/usr/local/bin/caddy", "/output/caddy"]
```
$ curl http://localhost:9080/hello-world
Hello world!
```

You can copy the contents of the builder Dockerfile and execute the following commands to get your Caddy binary:
#### Example usage: FastAPI

```bash
docker build -f builder.Dockerfile --build-arg PY_VERSION=3.9 -t caddy-snake .
```
`main.py`

```bash
docker run --rm -v $(pwd):/output caddy-snake
```python
from fastapi import FastAPI

@app.get("/hello-world")
def hello():
return "Hello world!"
```

## Example Caddyfile
`Caddyfile`

```Caddyfile
{
http_port 9080
https_port 9443
log {
level error
}
}
localhost:9080 {
route {
python "simple_app:main"
python {
module_asgi "main:app"
}
}
}
```

The `python` rule is an HTTP handler that expects a WSGI app as an argument.
Run:

If you want to use an ASGI app, like FastAPI or other async frameworks you can use the following config:
```
$ pip install fastapi
$ CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake
$ ./caddy run --config Caddyfile
```

```Caddyfile
{
http_port 9080
https_port 9443
log {
level error
}
}
localhost:9080 {
route {
python {
module_asgi "example_fastapi:app"
}
}
}
```
$ curl http://localhost:9080/hello-world
Hello world!
```

## Use docker image

There are docker images available with the following Python versions: `3.9`, `3.10`, `3.11`, `3.12`

## Examples
Example usage:

- [simple_app](/examples/simple_app.py). WSGI App that returns the standard hello world message and a UUID.
- [simple_exception](/examples/simple_exception.py). WSGI App that always raises an exception.
- [example_flask](/examples/example_flask.py). Flask application that also returns hello world message and a UUID.
- [example_fastapi](/examples/example_fastapi.py). FastAPI application that also returns hello world message and a UUID.
- [Caddyfile](/examples/Caddyfile). Caddy config that uses all of the example apps.
```Dockerfile
FROM ghcr.io/mliezun/caddy-snake:latest-py3.12

WORKDIR /app

# Copy your project into app
COPY . /app

# Caddy snake is already installed and has support for Python 3.12
CMD ["caddy", "run", "--config", "/app/Caddyfile"]
```

### Build with Docker

There's a template file in the project: [builder.Dockerfile](/builder.Dockerfile). It supports build arguments to configure which Python or Go version is desired for the build.

Make sure to use the same Python version as you have installed in your system.

You can copy the contents of the builder Dockerfile and execute the following commands to get your Caddy binary:

```bash
docker build -f builder.Dockerfile --build-arg PY_VERSION=3.9 -t caddy-snake .
```

```bash
docker run --rm -v $(pwd):/output caddy-snake
```

**NOTE**

It's also possible to provide virtual environments with the following syntax:

```Caddyfile
python {
module_wsgi "simple_app:main"
venv_path "./venv"
module_wsgi "main:app"
venv "./venv"
}
```

Expand All @@ -163,6 +161,7 @@ What it does behind the scenes is to append `venv/lib/python3.x/site-packages` t
- [Apache mod_wsgi](https://github.com/GrahamDumpleton/mod_wsgi)
- [FrankenPHP](https://github.com/dunglas/frankenphp)
- [WSGI Standard PEP 3333](https://peps.python.org/pep-3333/)
- [ASGI Spec](https://asgi.readthedocs.io/en/latest/index.html)

## LICENSE

Expand Down
Loading

0 comments on commit 828c0c6

Please sign in to comment.