Inital Commit

This commit is contained in:
Amritanshu Agrawal 2023-07-07 06:38:14 +05:30
commit 0203e73cd1
21 changed files with 394 additions and 0 deletions

4
.flake8 Normal file
View File

@ -0,0 +1,4 @@
[flake8]
ignore = E203, W503, E501
max-line-length = 120
exclude = .git,__pycache__,__init__.py,.mypy_cache,.pytest_cache

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.pyc
*/__pycache__/
*.egg-info/
dist/
poetry.lock

29
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,29 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8
args: ['--config=brewman/.flake8']
- repo: https://github.com/timothycrosley/isort
rev: 5.12.0
hooks:
- id: isort
additional_dependencies: [toml]
exclude: ^.*/?setup\.py$
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: debug-statements

16
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: FastAPI",
"type": "python",
"request": "launch",
"module": "gru",
"args": [],
"justMyCode": true
}
]
}

16
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
"python.defaultInterpreterPath": "/home/tanshu/.cache/pypoetry/virtualenvs/gru-uwCeNnAP-py3.11/bin/python",
"files.exclude": {
"**/__pycache__": true,
"**/.mypy_cache": true,
".idea": true,
"**/node_modules": true,
},
"search.exclude": {
"**/__pycache__": true,
"**/.mypy_cache": true,
".idea": true,
"**/node_modules": true,
"**/package-lock.json": true,
}
}

4
CHANGES.md Normal file
View File

@ -0,0 +1,4 @@
0.0
---
- Initial version

21
README.md Normal file
View File

@ -0,0 +1,21 @@
## Prettier - to format typescript files
```npx prettier --write src/app/```
## Eslint - to lint typescript files
```shell script
eslint src/app/
```
Optional to fix the errors as well
```
eslint src/app/ --fix
```
### Poerty remove environment
```sh
rm -rf `poetry env info -p`
```
### Poerty install
```sh
poetry install
```

31
deploy.sh Executable file
View File

@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" || exit ; pwd -P )
cd "$parent_path" || exit
#./lint.sh
# if [ 1 -eq "$#" ]
# then
# ./version_bump.sh "$1"
# else
# ./version_bump.sh
# fi
# Download the package.json for caching
curl --silent 'https://git.tanshu.com/tanshu/gru/raw/tag/latest/pyproject.toml' \
| sed 's/version = \"[0-9\.]*\"/version = "0.0.0"/g' \
> "$parent_path/docker/app/pyproject.toml"
cd "$parent_path/docker/app" || exit
docker build --tag gru:latest .
if [ 1 -eq "$#" ]
then
docker tag gru:latest "$1"
else
echo "No version bump"
fi
cd "$parent_path/docker" || exit
docker save gru:latest | bzip2 | pv | ssh beacon 'bunzip2 | sudo docker load'
ansible-playbook --limit=beacon playbook.yml

2
docker/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
app/package.json
app/pyproject.toml

23
docker/app/Dockerfile Normal file
View File

@ -0,0 +1,23 @@
FROM python:3.11
LABEL maintainer="Amritanshu <docker@tanshu.com>"
ADD https://git.tanshu.com/api/v1/repos/tanshu/gru/tags /tags.json
RUN git clone --single-branch --depth 1 --branch latest https://git.tanshu.com/tanshu/gru.git /app
# Install Poetry
RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | POETRY_HOME=/opt/poetry python && \
cd /usr/local/bin && \
ln -s /opt/poetry/bin/poetry && \
poetry config virtualenvs.create false
WORKDIR /app
# Allow installing dev dependencies to run tests
ARG INSTALL_DEV=false
RUN bash -c "if [ $INSTALL_DEV == 'true' ] ; then poetry install --no-root ; else poetry install --no-root --only main ; fi"
ENV PYTHONPATH=/app
EXPOSE 80
VOLUME /data
CMD ["poetry", "run", "python", "-m", "gru"]

3
docker/files/.env Normal file
View File

@ -0,0 +1,3 @@
HOST=0.0.0.0
PORT=80
FILE_PATH=/data/readings.csv

View File

@ -0,0 +1,13 @@
server {
listen 80;
server_name {{ http_host }};
location / {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://localhost:{{ host_port }};
}
}

75
docker/playbook.yml Executable file
View File

@ -0,0 +1,75 @@
#################################################
# DO Community Playbooks: Docker
#################################################
---
- hosts: gru
become: true
vars_files:
- "vars/gru.yml"
tasks:
- name: Copy dockerfile
synchronize:
src: app
dest: "/tmp/{{ host_directory }}"
- name: Build gru image
docker_image:
name: brewman:latest
build:
path: "/tmp/{{ host_directory }}/"
dockerfile: "/tmp/{{ host_directory }}/Dockerfile"
pull: yes
state: present
source: build
- name: Ensure Host Directory exists
file:
path: "/var/lib/{{ host_directory }}"
state: directory
- name: Upload the .env file
template:
src: "{{ env_file }}"
dest: "/var/lib/{{ host_directory }}/.env"
- name: Create gru container
docker_container:
name: "{{ host_directory }}"
image: gru:latest
state: started
restart_policy: "unless-stopped"
env_file: "/var/lib/{{ host_directory }}/.env"
published_ports:
- "127.0.0.1:{{ host_port }}:80"
volumes:
- "/var/lib/{{ host_directory }}:/data"
- name: Check if Nginx conf file exists
stat: path="/etc/nginx/sites-available/{{ http_conf }}"
register: status
- name: No need to reload Nginx
debug: msg= {{ "No need to reload Nginx as sites-available entries have already been created" }}
- name: Set Nginx conf file
when: status.stat.exists == false
template:
src: "files/nginx.conf.j2"
dest: "/etc/nginx/sites-available/{{ http_conf }}"
- name: Enable new site
when: status.stat.exists == false
file:
src: "/etc/nginx/sites-available/{{ http_conf }}"
dest: "/etc/nginx/sites-enabled/{{ http_conf }}"
state: link
notify: Reload Nginx
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded

6
docker/vars/gru.yml Normal file
View File

@ -0,0 +1,6 @@
---
http_host: "sensors.tanshu.com"
http_conf: "sensors.tanshu.com.conf"
host_port: "8745"
host_directory: "sensors"
env_file: "files/.env"

3
gru/.env Normal file
View File

@ -0,0 +1,3 @@
HOST=0.0.0.0
PORT=7458
FILE_PATH=readings.csv

0
gru/__init__.py Normal file
View File

4
gru/__main__.py Normal file
View File

@ -0,0 +1,4 @@
from gru.main import init
init()

19
gru/config.py Normal file
View File

@ -0,0 +1,19 @@
from typing import Any
from dotenv import load_dotenv
from pydantic import BaseSettings
class Settings(BaseSettings):
# openssl rand -hex 32
FILE_PATH: str = "/data/readings.csv"
HOST: str = "0.0.0.0"
PORT: int = 80
class Config:
case_sensitive = True
env_file = ".env"
load_dotenv()
settings = Settings()

33
gru/main.py Normal file
View File

@ -0,0 +1,33 @@
from typing import Annotated
import csv
import uvicorn
import datetime
from fastapi import FastAPI, Form
from .core.config import settings
from pydantic import BaseModel
app = FastAPI()
class Reading(BaseModel):
temperature: float
humidity: float
age: int
@app.post("/upload", response_model=Reading)
def add_reading(temp: Annotated[float, Form()], humidity: Annotated[float, Form()], age: Annotated[int, Form()], device: Annotated[str, Form()]):
current_datetime = datetime.datetime.now()
deducted_datetime = current_datetime - datetime.timedelta(milliseconds=age)
append_to_csv(settings.FILE_PATH, temp, humidity, deducted_datetime)
return Reading(temperature=temp,humidity=humidity,age=age)
def append_to_csv(filename, temperature, humidity, datetime_var):
with open(filename, 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow([temperature, humidity, datetime_var])
def init():
uvicorn.run(app, host=settings.HOST, port=settings.PORT)

10
lint.sh Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -eEu -o pipefail
shopt -s extdebug
IFS=$'\n\t'
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" || exit ; pwd -P )
cd "$parent_path" || exit
isort gru
black gru
flake8 gru

77
pyproject.toml Normal file
View File

@ -0,0 +1,77 @@
[tool.poetry]
name = "gru"
version = "1.0.0"
description = "Sensor manager."
authors = ["tanshu <git@tanshu.com>"]
[tool.poetry.dependencies]
python = "^3.11"
uvicorn = {extras = ["standard"], version = "^0.22.0"}
fastapi = "^0.99.1"
python-jose = {extras = ["cryptography"], version = "^3.3.0"}
passlib = {extras = ["bcrypt"], version = "^1.7.4"}
python-multipart = "^0.0.6"
itsdangerous = "^2.1.2"
python-dotenv = "^1.0.0"
openpyxl = "^3.1.2"
[tool.poetry.dev-dependencies]
flake8 = "^6.0.0"
black = "^23.3.0"
ruff = "^0.0.277"
pre-commit = "^3.3.3"
mypy = "^1.4.1"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.mypy]
# --strict
disallow_any_generics = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_return_any = true
warn_unused_configs = true
strict_equality = true
plugins = ["sqlalchemy.ext.mypy.plugin"]
# --strict end
[tool.isort]
profile = "black"
atomic = true
include_trailing_comma = true
lines_after_imports = 2
lines_between_types = 1
use_parentheses = true
src_paths = ["poetry", "tests"]
skip_glob = ["*/setup.py"]
filter_files = true
known_first_party = "poetry"
[tool.black]
line-length = 120
include = '\.pyi?$'
exclude = '''
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
| tests/.*/setup.py
)/
'''