Inital Commit
This commit is contained in:
commit
0203e73cd1
4
.flake8
Normal file
4
.flake8
Normal 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
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
*.pyc
|
||||
*/__pycache__/
|
||||
*.egg-info/
|
||||
dist/
|
||||
poetry.lock
|
29
.pre-commit-config.yaml
Normal file
29
.pre-commit-config.yaml
Normal 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
16
.vscode/launch.json
vendored
Normal 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
16
.vscode/settings.json
vendored
Normal 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
4
CHANGES.md
Normal file
@ -0,0 +1,4 @@
|
||||
0.0
|
||||
---
|
||||
|
||||
- Initial version
|
21
README.md
Normal file
21
README.md
Normal 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
31
deploy.sh
Executable 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
2
docker/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
app/package.json
|
||||
app/pyproject.toml
|
23
docker/app/Dockerfile
Normal file
23
docker/app/Dockerfile
Normal 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
3
docker/files/.env
Normal file
@ -0,0 +1,3 @@
|
||||
HOST=0.0.0.0
|
||||
PORT=80
|
||||
FILE_PATH=/data/readings.csv
|
13
docker/files/nginx.conf.j2
Normal file
13
docker/files/nginx.conf.j2
Normal 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
75
docker/playbook.yml
Executable 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
6
docker/vars/gru.yml
Normal 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"
|
0
gru/__init__.py
Normal file
0
gru/__init__.py
Normal file
4
gru/__main__.py
Normal file
4
gru/__main__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from gru.main import init
|
||||
|
||||
|
||||
init()
|
19
gru/config.py
Normal file
19
gru/config.py
Normal 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
33
gru/main.py
Normal 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
10
lint.sh
Executable 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
77
pyproject.toml
Normal 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
|
||||
)/
|
||||
'''
|
Loading…
Reference in New Issue
Block a user