Skip to content

Commit 8be36f6

Browse files
committed
Docker container with flask + gunicorn
1 parent f9f5496 commit 8be36f6

File tree

11 files changed

+1192
-144
lines changed

11 files changed

+1192
-144
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: 'build dev images'
2+
3+
on:
4+
push:
5+
tags:
6+
- "[0-9]+.[0-9]+.[0-9]+-rc[0-9]+"
7+
8+
# TODO: only request needed permissions
9+
permissions: write-all
10+
11+
jobs:
12+
docker:
13+
runs-on: ubuntu-latest
14+
env:
15+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
16+
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
17+
# support dockerhub organizations. If none is present, use the dockerhub username
18+
DOCKERHUB_ORGANIZATION: ${{ secrets.DOCKERHUB_ORGANIZATION == null && secrets.DOCKERHUB_USERNAME || secrets.DOCKERHUB_ORGANIZATION }}
19+
steps:
20+
- uses: actions/checkout@v4
21+
- name: Set env
22+
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
23+
24+
- name: Set up QEMU
25+
uses: docker/setup-qemu-action@v3
26+
27+
- name: Set up Docker Buildx
28+
uses: docker/setup-buildx-action@v3
29+
30+
- name: Login to Docker Hub
31+
uses: docker/login-action@v3
32+
if: env.DOCKERHUB_USERNAME != null
33+
with:
34+
username: ${{ env.DOCKERHUB_USERNAME }}
35+
password: ${{ env.DOCKERHUB_PASSWORD }}
36+
37+
- name: Login to GitHub Container Registry
38+
uses: docker/login-action@v3
39+
with:
40+
registry: ghcr.io
41+
username: ${{ github.actor }}
42+
password: ${{ github.token }}
43+
44+
- id: lowercase-repository
45+
name: lowercase repository
46+
uses: ASzc/change-string-case-action@v6
47+
with:
48+
string: ${{ github.repository }}
49+
50+
- name: Build and push (GHCR only)
51+
uses: docker/build-push-action@v5
52+
if: env.DOCKERHUB_ORGANIZATION == null
53+
with:
54+
context: .
55+
platforms: linux/amd64,linux/arm64,linux/arm/v7
56+
push: true
57+
tags: |
58+
ghcr.io/${{ steps.lowercase-repository.outputs.lowercase }}/saic-python-api-proxy:dev
59+
ghcr.io/${{ steps.lowercase-repository.outputs.lowercase }}/saic-python-api-proxy:${{ env.RELEASE_VERSION }}
60+
61+
- name: Build and push (GHCR + DockerHub)
62+
uses: docker/build-push-action@v5
63+
if: env.DOCKERHUB_ORGANIZATION != null
64+
with:
65+
context: .
66+
platforms: linux/amd64,linux/arm64,linux/arm/v7
67+
push: true
68+
tags: |
69+
ghcr.io/${{ steps.lowercase-repository.outputs.lowercase }}/saic-python-api-proxy:dev
70+
ghcr.io/${{ steps.lowercase-repository.outputs.lowercase }}/saic-python-api-proxy:${{ env.RELEASE_VERSION }}
71+
${{ secrets.DOCKERHUB_ORGANIZATION != null && format('{0}/saic-python-api-proxy:dev', secrets.DOCKERHUB_ORGANIZATION)}}
72+
${{ secrets.DOCKERHUB_ORGANIZATION != null && format('{0}/saic-python-api-proxy:{1}', secrets.DOCKERHUB_ORGANIZATION, env.RELEASE_VERSION)}}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: 'build stable images'
2+
3+
on:
4+
push:
5+
tags:
6+
- "[0-9]+.[0-9]+.[0-9]+"
7+
8+
# TODO: only request needed permissions
9+
permissions: write-all
10+
11+
jobs:
12+
docker:
13+
runs-on: ubuntu-latest
14+
env:
15+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
16+
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
17+
# support dockerhub organizations. If none is present, use the dockerhub username
18+
DOCKERHUB_ORGANIZATION: ${{ secrets.DOCKERHUB_ORGANIZATION == null && secrets.DOCKERHUB_USERNAME || secrets.DOCKERHUB_ORGANIZATION }}
19+
steps:
20+
- uses: actions/checkout@v4
21+
- name: Set env
22+
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
23+
24+
- name: Set up QEMU
25+
uses: docker/setup-qemu-action@v3
26+
27+
- name: Set up Docker Buildx
28+
uses: docker/setup-buildx-action@v3
29+
30+
- name: Login to Docker Hub
31+
uses: docker/login-action@v3
32+
if: env.DOCKERHUB_USERNAME != null
33+
with:
34+
username: ${{ env.DOCKERHUB_USERNAME }}
35+
password: ${{ env.DOCKERHUB_PASSWORD }}
36+
37+
- name: Login to GitHub Container Registry
38+
uses: docker/login-action@v3
39+
with:
40+
registry: ghcr.io
41+
username: ${{ github.actor }}
42+
password: ${{ github.token }}
43+
44+
- id: lowercase-repository
45+
name: lowercase repository
46+
uses: ASzc/change-string-case-action@v6
47+
with:
48+
string: ${{ github.repository }}
49+
50+
- name: Build and push (GHCR only)
51+
uses: docker/build-push-action@v5
52+
if: env.DOCKERHUB_ORGANIZATION == null
53+
with:
54+
context: .
55+
platforms: linux/amd64,linux/arm64,linux/arm/v7
56+
push: true
57+
tags: |
58+
ghcr.io/${{ steps.lowercase-repository.outputs.lowercase }}/saic-python-api-proxy:latest
59+
ghcr.io/${{ steps.lowercase-repository.outputs.lowercase }}/saic-python-api-proxy:${{ env.RELEASE_VERSION }}
60+
61+
- name: Build and push (GHCR + DockerHub)
62+
uses: docker/build-push-action@v5
63+
if: env.DOCKERHUB_ORGANIZATION != null
64+
with:
65+
context: .
66+
platforms: linux/amd64,linux/arm64,linux/arm/v7
67+
push: true
68+
tags: |
69+
ghcr.io/${{ steps.lowercase-repository.outputs.lowercase }}/saic-python-api-proxy:latest
70+
ghcr.io/${{ steps.lowercase-repository.outputs.lowercase }}/saic-python-api-proxy:${{ env.RELEASE_VERSION }}
71+
${{ secrets.DOCKERHUB_ORGANIZATION != null && format('{0}/saic-python-api-proxy:latest', secrets.DOCKERHUB_ORGANIZATION)}}
72+
${{ secrets.DOCKERHUB_ORGANIZATION != null && format('{0}/saic-python-api-proxy:{1}', secrets.DOCKERHUB_ORGANIZATION, env.RELEASE_VERSION)}}

Dockerfile

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# `python-base` sets up all our shared environment variables
2+
FROM python:3.12-slim as python-base
3+
4+
# python
5+
ENV PYTHONUNBUFFERED=1 \
6+
# prevents python creating .pyc files
7+
PYTHONDONTWRITEBYTECODE=1 \
8+
\
9+
# pip
10+
PIP_NO_CACHE_DIR=off \
11+
PIP_DISABLE_PIP_VERSION_CHECK=on \
12+
PIP_DEFAULT_TIMEOUT=100 \
13+
\
14+
# poetry
15+
# https://python-poetry.org/docs/configuration/#using-environment-variables
16+
POETRY_VERSION=1.8.3 \
17+
# make poetry install to this location
18+
POETRY_HOME="/opt/poetry" \
19+
# make poetry create the virtual environment in the project's root
20+
# it gets named `.venv`
21+
POETRY_VIRTUALENVS_IN_PROJECT=true \
22+
# do not ask any interactive question
23+
POETRY_NO_INTERACTION=1 \
24+
\
25+
# paths
26+
# this is where our requirements + virtual environment will live
27+
PYSETUP_PATH="/opt/pysetup" \
28+
VENV_PATH="/opt/pysetup/.venv"
29+
30+
31+
# prepend poetry and venv to path
32+
ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"
33+
34+
35+
# `builder-base` stage is used to build deps + create our virtual environment
36+
FROM python-base as builder-base
37+
RUN apt-get update \
38+
&& apt-get install --no-install-recommends -y \
39+
# deps for installing poetry
40+
curl \
41+
# deps for building python deps
42+
build-essential
43+
44+
# install poetry - respects $POETRY_VERSION & $POETRY_HOME
45+
RUN curl -sSL https://install.python-poetry.org | python
46+
47+
# copy project requirement files here to ensure they will be cached.
48+
WORKDIR $PYSETUP_PATH
49+
COPY poetry.lock pyproject.toml ./
50+
51+
# install runtime deps - uses $POETRY_VIRTUALENVS_IN_PROJECT internally
52+
RUN poetry install --no-dev
53+
54+
55+
FROM python-base as production
56+
ENV FLASK_ENV=production
57+
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
58+
COPY . /app/
59+
WORKDIR /app
60+
61+
EXPOSE 8080
62+
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "main:app"]

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
11
# saic-python-api-proxy
2+
23
A python based API proxy for the new SAIC API to allow sharing the same access token across multiple applications
4+
5+
## Configuration
6+
7+
| ENV variable | Description |
8+
|----------------|--------------------------------------------------------------------------------------------------------|
9+
| SAIC_REST_URI | SAIC API URI. Default is the European Production endpoint: https://gateway-mg-eu.soimt.com/api.app/v1/ |
10+
| SAIC_REGION | SAIC API region. Default is eu. |
11+
| SAIC_TENANT_ID | SAIC API tenant ID. Default is 459771. |

api.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from flask import Blueprint
2+
3+
from proxy import passthrough, proxy_login
4+
5+
api = Blueprint('api', __name__, url_prefix='/api.app/v1')
6+
7+
8+
@api.route('/', defaults={'path': ''})
9+
@api.route('/<path:path>', methods=['GET'])
10+
async def do_get(path):
11+
return await passthrough(path=path)
12+
13+
14+
@api.route('/', defaults={'path': ''}, methods=['POST'])
15+
@api.route('/<path:path>', methods=['POST'])
16+
async def do_post(path):
17+
if path == 'oauth/token':
18+
return await proxy_login(path=path)
19+
else:
20+
return await passthrough(path=path)
21+
22+
23+
@api.route('/', defaults={'path': ''}, methods=['DELETE'])
24+
@api.route('/<path:path>', methods=['DELETE'])
25+
async def do_delete(path):
26+
return await passthrough(path=path)
27+
28+
29+
@api.route('/', defaults={'path': ''}, methods=['PUT'])
30+
@api.route('/<path:path>', methods=['PUT'])
31+
async def do_put(path):
32+
return await passthrough(path=path)

default_settings.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from flask import Config
2+
3+
SAIC_REST_URI = 'https://gateway-mg-eu.soimt.com/api.app/v1/'
4+
SAIC_REGION = 'eu'
5+
SAIC_TENANT_ID = '459771'
6+
7+
8+
def get_api_uri(config: Config) -> str:
9+
return config.get('SAIC_REST_URI')
10+
11+
12+
def get_region(config: Config) -> str:
13+
return config.get('SAIC_REGION')
14+
15+
16+
def get_tenant_id(config: Config) -> str:
17+
return config.get('SAIC_TENANT_ID')

docker-compose.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
services:
2+
saic-python-api-proxy:
3+
build:
4+
context: .
5+
image: "saicismartapi/saic-python-api-proxy:latest"
6+
container_name: "saic-python-api-proxy"
7+
ports:
8+
- "8080:8080"
9+
environment:
10+
- SAIC_REST_URI=${SAIC_REST_URI}
11+
- SAIC_REGION=${SAIC_REGION}
12+
- SAIC_TENANT_ID=${SAIC_TENANT_ID}

0 commit comments

Comments
 (0)