diff --git a/.env.TEMPLATE b/.env.TEMPLATE new file mode 100644 index 0000000..78b801f --- /dev/null +++ b/.env.TEMPLATE @@ -0,0 +1,5 @@ +# A comma separated list of actions to allow, default: .deploy +ACINT_ACTIONS= + +# The proxy path for the service, default: /acint +ACINT_PROXY_PATH= \ No newline at end of file diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml new file mode 100644 index 0000000..d4fb9b0 --- /dev/null +++ b/.github/workflows/default.yml @@ -0,0 +1,74 @@ +name: ci +on: + push: + branches: + - 'main' + tags: + - "v*" + +jobs: + docker: + runs-on: ubuntu-latest + name: Build and push Docker image + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + # list of Docker images to use as base name for tags + images: | + ethnexus/acint + # generate Docker tags based on the following events/attributes + tags: | + # type=schedule + type=ref,event=branch + type=ref,event=pr + # type=sha + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + - + name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - + name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ethnexus + password: ${{ secrets.DOCKER_PASS }} + - + name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + push: true + # tags: ethnexus/acint:latest,ethnexus/acint:1.0.0 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + + PushContainerReadme: + runs-on: ubuntu-latest + name: Push README to Docker Hub + steps: + - + name: git checkout + uses: actions/checkout@v3 + - + name: push README to Dockerhub + uses: christian-korneck/update-container-description-action@v1 + env: + DOCKER_USER: ethnexus + DOCKER_PASS: ${{ secrets.DOCKER_PASS }} + with: + destination_container_repo: ethnexus/acint + provider: dockerhub + short_description: 'Action Interface' + readme_file: 'README.md' \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..837ddcc --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +/data +Pipfile diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a96fb50 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": false + } + }, + "python.terminal.activateEnvironment": false, + "python.defaultInterpreterPath": "/Users/davmeyer/.local/share/virtualenvs/ldm-Z4I5MxeJ/bin/python", + "python.linting.enabled": true, + "python.linting.lintOnSave": true, + "python.linting.pycodestyleEnabled": false, + "python.linting.flake8Enabled": true, + "python.formatting.provider": "none" +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c50280f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.11-slim + +# Optimise python and debian in docker +ENV PYTHONUNBUFFERED 1 +ENV PIP_BREAK_SYSTEM_PACKAGES 1 +ENV PIP_DISABLE_PIP_VERSION_CHECK 1 +ENV DEBIAN_FRONTEND noninteractive + +COPY ./requirements.txt /requirements.txt +RUN pip install -r /requirements.txt + +COPY ./app /app +WORKDIR /app + +CMD [ "./acint.py" ] + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..c8b5909 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Action Interface (actint) + +The Action Interface (actint) is a simple service that touches a file for the called action. For example if the action `deploy` is called \ No newline at end of file diff --git a/app/acint.py b/app/acint.py new file mode 100755 index 0000000..d357394 --- /dev/null +++ b/app/acint.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +import cherrypy +import os + +DO_PATH = os.path.join(os.path.sep, "do") +os.makedirs(DO_PATH, exist_ok=True) + +allowed_actions_string = os.environ.get("ACINT_ALLOWED_ACTIONS", "").strip() +if len(allowed_actions_string) == 0: + allowed_actions = [".deploy"] +else: + allowed_actions = os.environ.get("ACINT_ALLOWED_ACTIONS", ".deploy").split(",") +proxy_path = os.environ.get("ACINT_PROXY_PATH", None) or "/acint" + + +def handle_an_exception(): + cherrypy.response.status = 500 + cherrypy.response.headers["content-type"] = "text/plain;charset=UTF-8" + cherrypy.response.body = b"Internal Server Error" + + +def handle_default(status=None, message=None, version=None, traceback=None): + cherrypy.response.headers["content-type"] = "text/plain;charset=UTF-8" + return f"{status}".encode("UTF-8") + + +@cherrypy.popargs("action") +class AcInt(object): + _cp_config = { + # handler for an unhandled exception + "request.error_response": handle_an_exception, + # default handler for any other HTTP error + "error_page.default": handle_default, + } + + @cherrypy.expose + def index(self, action=None): + if action not in allowed_actions: + raise cherrypy.HTTPError(403, "Forbidden") + os.close(os.open(os.path.join(DO_PATH, action), os.O_CREAT)) + return f"Triggerd action {action}." + + +if __name__ == "__main__": + print("Allowed actions:", allowed_actions) + print("Proxy path:", proxy_path) + cherrypy.config.update( + { + "server.socket_host": "0.0.0.0", + "server.socket_port": 80, + "engine.autoreload.on": False, + "checker.on": False, + "tools.log_headers.on": False, + "request.show_tracebacks": False, + "request.show_mismatched_params": False, + "log.screen": False, + } + ) + cherrypy.quickstart(AcInt(), proxy_path) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c2dae87 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3" +services: + acint: + build: + context: . + ports: + - 8088:80 + volumes: + - ./data:/do + env_file: .env diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ee5ef3a --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +CherryPy==18.8.0 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..ee202d1 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,7 @@ +[black] +line-length = 88 + +[flake8] +max-line-length = 88 +select = C,E,F,W,B,B950 +extend-ignore = E203, E501, W503 \ No newline at end of file