Skip to content

Commit

Permalink
started with new structure
Browse files Browse the repository at this point in the history
  • Loading branch information
skyface753 committed Jan 27, 2024
1 parent 81f3705 commit fc03bff
Show file tree
Hide file tree
Showing 87 changed files with 1,174 additions and 22,510 deletions.
28 changes: 25 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
buildpush:
docker buildx build --platform linux/amd64,linux/arm64 -t registry.it-lab.cc/chest-system-server -f Dockerfile . --push
docker buildx build --platform linux/amd64,linux/arm64 -t registry.it-lab.cc/chest-system-client -f my-app/Dockerfile ./my-app/ --push
docker buildx build --platform linux/amd64,linux/arm64 -t registry.it-lab.cc/chest-system-proxy -f proxy/Dockerfile ./proxy --push
docker buildx build --platform linux/amd64,linux/arm64 -t skyface753/chest-system-server -f Dockerfile . --push
docker buildx build --platform linux/amd64,linux/arm64 -t skyface753/chest-system-client -f my-app/Dockerfile ./my-app/ --push
docker buildx build --platform linux/amd64,linux/arm64 -t skyface753/chest-system-proxy -f proxy/Dockerfile ./proxy --push



install-requirements:
pip install -r requirements.txt

dev-docker:
docker-compose -f docker-compose-dev.yaml up -d --build

run:
uvicorn main:app --host 127.0.0.1 --port 8000 --reload

clear-db:
docker-compose -f docker-compose-dev.yaml exec server alembic downgrade base

migrate-db:
docker-compose -f docker-compose-dev.yaml exec server alembic upgrade head

reinit-db: clear-db migrate-db

integration-test:
API_SERVER=localhost API_PORT=8000 PYTHONPATH=. pytest --pspec --verbose --color=yes --junitxml=report_service_tests.xml tests/service/
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,39 @@ sudo usermod -aG docker ${USER}

## Dev

### Use a python virtual environment

```bash
export KUBECONFIG="$(pwd)/minikube-config.yaml"
minikube start
python3 -m venv venv
source venv/bin/activate
```

### Install dependencies

docker-compose -f docker-compose-proxy.yaml config > docker-compose-resolved.yaml
kompose convert -f docker-compose-resolved.yaml -o kube
```bash
pip install -r requirements.txt
```

kubectl apply -f kube
### Start the dev database and phpmyadmin

```bash
docker-compose -f docker-compose-dev.yaml up -d
```

# Test
kubectl run test --rm --tty -i --restart='Never' --image alpine --namespace default --command -- /bin/sh
### Bring the dev database to the latest version

```bash
alembic upgrade head
```

### Start the dev server

```bash
uvicorn 'main:app' --host=127.0.0.1 --port=8000 --reload
```

Now you can access the server at http://127.0.0.1:8000

## Prod Build

The Images need to be in a public registry for the minikube to be able to pull them.
Expand Down
2 changes: 1 addition & 1 deletion alembic.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[alembic]
# path to migration scripts
script_location = migrations
script_location = app/database/migrations

# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time
Expand Down
66 changes: 66 additions & 0 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#
# Layers: Only the instructions RUN, COPY, ADD create layers.
#

ARG PYTHON_IMAGE_VERSION=3.10

#
### Target: development
#
FROM python:${PYTHON_IMAGE_VERSION}-slim as development

ENV USER_ID=1000
ENV GROUP_ID=1000

ENV USER=web
ENV HOME="/${USER}"

ENV \
POETRY_VERSION=1.0.10 \
POETRY_VIRTUALENVS_IN_PROJECT=1 \
# write messages immediately to stream
PYTHONUNBUFFERED=1 \
# don't write .pyc files
PYTHONDONTWRITEBYTECODE=1 \
# disable pip version check for speed reasons
PIP_DISABLE_PIP_VERSION_CHECK=1 \
# disable caching for installation and source files from pip
PIP_NO_CACHE_DIR=1 \
# virtual env path
VENV_PATH="${HOME}/.venv"

ENV PATH="$HOME/.local/bin:$VENV_PATH/bin:$PATH"

ENV \
# Do not use randomization for python seed
PYTHONHASHSEED=1

# install pg_isready helper from postgres
RUN apt-get update \
&& apt-get install -y curl gnupg build-essential libpq-dev

RUN addgroup --gid ${GROUP_ID} ${USER}
RUN adduser --disabled-password --gecos '' --home "${HOME}" --uid "${USER_ID}" --gid "${GROUP_ID}" "${USER}"

USER ${USER}
WORKDIR ${HOME}

# RUN pip install --user poetry
COPY requirements.txt ${HOME}/
RUN pip install -r requirements.txt

# COPY --chown=${USER_ID}:${GROUP_ID} ./pyproject.toml ./poetry.lock ${HOME}/

# RUN poetry install
RUN pip uninstall psycopg2-binary -y
RUN pip install psycopg2

COPY --chown=${USER_ID}:${GROUP_ID} ./app ${HOME}/app/
COPY --chown=${USER_ID}:${GROUP_ID} ./entrypoint.sh ${HOME}/scripts/
COPY --chown=${USER_ID}:${GROUP_ID} ./alembic.ini ${HOME}/
COPY --chown=${USER_ID}:${GROUP_ID} ./tests ${HOME}/tests/
RUN chmod +x ${HOME}/scripts/entrypoint.sh

EXPOSE 8000

ENTRYPOINT ./scripts/entrypoint.sh
43 changes: 43 additions & 0 deletions app/api/v1/endpoints/chest/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import logging
import uuid

from sqlalchemy.orm import Session

from app.database.models import Kiste
from app.api.v1.endpoints.chest.schemas import ChestCreateSchema

def create_chest(schema: ChestCreateSchema, db: Session):
entity = Kiste(**schema.dict())
db.add(entity)
db.commit()
logging.debug('Chest {} created'.format(entity.name))
return entity

def get_chest_by_id(chest_id: uuid.UUID, db: Session):
entity = db.query(Kiste).filter(Kiste.id == chest_id).first()
return entity

def get_chest_by_name(chest_name: str, db: Session):
entity = db.query(Kiste).filter(Kiste.name == chest_name).first()
return entity

def get_all_chests(db: Session):
return db.query(Kiste).all()

def update_chest(chest: Kiste, changed_chest: ChestCreateSchema, db: Session):
for key, value in changed_chest.dict().items():
setattr(chest, key, value)

db.commit()
db.refresh(chest)
logging.debug('Chest {} updated'.format(chest.name))
return chest

def delete_chest_by_id(chest_id: uuid.UUID, db: Session):
entity = get_chest_by_id(chest_id, db)
if entity:
db.delete(entity)
db.commit()
logging.debug('Chest {} deleted'.format(entity.name))


100 changes: 100 additions & 0 deletions app/api/v1/endpoints/chest/router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import logging

from typing import List

from fastapi import APIRouter, Depends, Request, Response, status, HTTPException
from fastapi.responses import RedirectResponse
from sqlalchemy.orm import Session

import app.api.v1.endpoints.chest.crud as chest_crud
from app.api.v1.endpoints.chest.schemas import ChestSchema, ChestCreateSchema, ChestListItemSchema
from app.database.connection import SessionLocal

router = APIRouter()


def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()


@router.get('', response_model=List[ChestListItemSchema], tags=['chest'])
def get_all_chests(db: Session = Depends(get_db)):
return chest_crud.get_all_chests(db)


@router.post('', response_model=ChestSchema, status_code=status.HTTP_201_CREATED, tags=['chest'])
def create_chest(chest: ChestCreateSchema,
request: Request,
db: Session = Depends(get_db),
):
chest_found = chest_crud.get_chest_by_name(chest.name, db)
if chest_found:
logging.warning('Chest {} already exists'.format(chest.name))
url = request.url_for('get_chest', chest_id=chest_found.id)
return RedirectResponse(url=url, status_code=status.HTTP_303_SEE_OTHER)

new_chest = chest_crud.create_chest(chest, db)
logging.info('Chest {} created'.format(chest.name))
return new_chest


@router.put('/{chest_id}', response_model=ChestSchema, tags=['chest'])
def update_chest(
chest_id: int,
changed_chest: ChestCreateSchema,
request: Request,
response: Response,
db: Session = Depends(get_db),
):
chest_found = chest_crud.get_chest_by_id(chest_id, db)
updated_chest = None

if chest_found:
if chest_found.name == changed_chest.name:
logging.debug('Chest {} found. Keeping name'.format(chest_id))
chest_crud.update_chest(chest_found, changed_chest, db)
return Response(status_code=status.HTTP_204_NO_CONTENT)
else:
chest_name_found = chest_crud.get_chest_by_name(changed_chest.name, db)
if chest_name_found:
logging.warning('Chest {} already exists'.format(changed_chest.name))
url = request.url_for('get_chest', chest_id=chest_name_found.id)
return RedirectResponse(url=url, status_code=status.HTTP_303_SEE_OTHER)
else:
logging.debug('Chest {} name changed'.format(chest_found.name))
updated_chest = chest_crud.create_chest(changed_chest, db)
response.status_code = status.HTTP_201_CREATED
else:
logging.warning('Update: Chest {} not found'.format(chest_id))
raise HTTPException(status_code=404)

return updated_chest


@router.get('/{chest_id}', response_model=ChestSchema, tags=['chest'])
def get_chest(chest_id: int,
db: Session = Depends(get_db),
):
chest = chest_crud.get_chest_by_id(chest_id, db)

if not chest:
logging.warning('Get: Chest {} not found'.format(chest_id))
raise HTTPException(status_code=404)
return chest


@router.delete('/{chest_id}', response_model=None, tags=['chest'])
def delete_chest(chest_id: int, db: Session = Depends(get_db)):
chest = chest_crud.get_chest_by_id(chest_id, db)

if not chest:
logging.error('Delete: Chest {} not found'.format(chest_id))
raise HTTPException(status_code=404)

chest_crud.delete_chest_by_id(chest_id, db)
logging.info('Chest {} deleted'.format(chest.name))
return Response(status_code=status.HTTP_204_NO_CONTENT)
25 changes: 25 additions & 0 deletions app/api/v1/endpoints/chest/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

from pydantic import BaseModel


class ChestBaseSchema(BaseModel):
name: str

class Config:
orm_mode = True

class ChestCreateSchema(ChestBaseSchema):
pass

class ChestSchema(ChestBaseSchema):
id: int

class ChestUpdateSchema(ChestBaseSchema):
pass

class ChestListItemSchema(BaseModel):
id: int
name: str

class Config:
orm_mode = True
42 changes: 42 additions & 0 deletions app/api/v1/endpoints/item/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import logging

from sqlalchemy.orm import Session

from app.database.models import Item
from app.api.v1.endpoints.item.schemas import ItemCreateSchema

def create_item(schema: ItemCreateSchema, db: Session):
entity = Item(**schema.dict())
db.add(entity)
db.commit()
logging.debug('Item {} created'.format(entity.name))
return entity

def get_item_by_id(item_id: int, db: Session):
entity = db.query(Item).filter(Item.id == item_id).first()
return entity

def get_item_by_name(item_name: str, db: Session):
entity = db.query(Item).filter(Item.name == item_name).first()
return entity

def get_all_items(db: Session):
return db.query(Item).all()

def update_item(item: Item, changed_item: ItemCreateSchema, db: Session):
for key, value in changed_item.dict().items():
setattr(item, key, value)

db.commit()
db.refresh(item)
logging.debug('Item {} updated'.format(item.name))
return item

def delete_item_by_id(item_id: int, db: Session):
entity = get_item_by_id(item_id, db)
if entity:
db.delete(entity)
db.commit()
logging.debug('Item {} deleted'.format(entity.name))


Loading

0 comments on commit fc03bff

Please sign in to comment.