Skip to content

Commit

Permalink
Refactor code.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaraxal committed Jan 5, 2025
1 parent d10f18f commit 6983f58
Show file tree
Hide file tree
Showing 33 changed files with 1,230 additions and 906 deletions.
4 changes: 3 additions & 1 deletion app/.dockerignore → .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ venv/

# Secrets
**/secrets.toml
**/.secrets.toml

**/.DS_Store

**/sensors.db
# SQLite data files
**/sensors.db
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ cython_debug/

# Secrets
secrets.toml
.secrets.toml

# Apple .DS_Store files
.DS_Store
Expand Down
39 changes: 39 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# First, build the application in the `/app` directory.
FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim AS builder

ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy

WORKDIR /app

RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project --no-dev

ADD . /app

RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev


# Then, use a final image without uv
FROM python:3.11-slim-bookworm
# It is important to use the image that matches the builder, as the path to the
# Python executable must be the same, e.g., using `python:3.11-slim-bookworm`
# will fail.

# Configure Python to not buffer "stdout" or create .pyc files
ENV PYTHONBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

# Copy the application from the builder
COPY --from=builder --chown=app:app /app /app

# Place executables in the environment at the front of the path
ENV PATH="/app/.venv/bin:$PATH"

USER app
WORKDIR /app

# Run the app
CMD ["python3", "-u", "app.py"]
208 changes: 83 additions & 125 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,170 +1,128 @@
# Variables
SHELL:=/bin/bash
SHELL := /bin/bash
PROJECT := sensorpush
VERSION := 1.0.0
VERSION := 0.1.0
IMAGE_NAME := sensorpush-python
COMPOSE_FILE := compose.yml
GIT_HASH ?= $(shell git log --format="%h" -n 1)
VENV = .venv
UV_PYTHON = uv run python
UV_PIP = uv pip
UV_PIP_COMPILE = uv pip compile
UV_PIP_SYNC = uv pip sync

# Assume uv, uvx, and ruff are installed
UV := $(shell command -v uv)
UVX := $(shell command -v uvx)

# If uv is not found, print an error message and exit
ifeq ($(UV),)
$(error "uv is required but not found.")
endif

# If uvx is not found, print an error message and exit
ifeq ($(UVX),)
$(error "uvx is required but not found.")
endif

# Define color variables
GIT_HASH := $(shell git log --format="%h" -n 1)
VENV := .venv
UV_PYTHON := uv run python
UV_PIP := uv pip
UV_PIP_SYNC := uv pip sync
UV_PIP_COMPILE := uv pip compile
UV_SYNC := uv sync
DOCKER_COMPOSE := docker compose -f $(COMPOSE_FILE) -p $(PROJECT)

# Colors
GREEN := $(shell tput setaf 2)
CYAN := $(shell tput setaf 6)
RESET := $(shell tput sgr0)

# Requirements files
REQUIREMENTS_IN = ./app/requirements/prod.in
REQUIREMENTS_TXT = ./app/requirements/prod.txt
DEV_REQUIREMENTS_IN = ./app/requirements/dev.in
DEV_REQUIREMENTS_TXT = ./app/requirements/dev.txt

# Directories
TEST_DIR = tests
SRC_DIR = ./app

# Commands for testing and linting
TEST_CMD = ./$(VENV)/bin/pytest $(TEST_DIR)
#LINT_CMD = uvx ruff check --fix
LINT_CMD = uvx ruff check
FMT_CMD = uvx ruff format
TEST_DIR := ./app/tests
SRC_DIR := ./app

# Default Target
.DEFAULT_GOAL := help

.PHONY: help
help: ## Display help information about available rules
@echo "$(GREEN)Available rules:$(RESET)"
@grep -E '^[a-zA-Z0-9_-]+:.*##' $(MAKEFILE_LIST) | \
awk -v cyan="$(CYAN)" -v reset="$(RESET)" 'BEGIN {FS = ":.*##"}; {printf "- %s%s%s\n %s\n\n", cyan, $$1, reset, $$2}'

.PHONY: check-require
check-require: ## Check if required programs are installed
@echo "Project Name: $(PROJECT)"
@echo "Project Version: $(VERSION)"
@echo ""

@echo "Checking the programs required for the build are installed..."
@uv run python --version >/dev/null 2>&1 || (echo "ERROR: python is required."; exit 1)
@uv --version >/dev/null 2>&1 || (echo "ERROR: uv is required."; exit 1)
@uvx --version >/dev/null 2>&1 || (echo "ERROR: uvx is required."; exit 1)
@uvx ruff --version >/dev/null 2>&1 || (echo "ERROR: ruff (uv tool) is required."; exit 1)
@echo ""

@echo "'python', 'uv', 'uvx', and 'ruff' are installed."
@echo ""
awk -v cyan="$(CYAN)" -v reset="$(RESET)" 'BEGIN {FS = ":.*##"}; {printf "%s%-25s%s %s\n", cyan, $$1, reset, $$2}'

@uv run python --version
@uv --version
@uvx --version
@uvx ruff --version


all: init compile-requirements sync-requirements build ## Setup environment and install dependencies
@echo "Running target: all"

init: check-require ## Create a virtual environment
@echo "Running target: init"
.PHONY: check-require
check-require: ## Verify required tools are installed
@echo "Checking required tools..."
@uv run python --version >/dev/null || (echo "ERROR: uv Python not found!" && exit 1)
@uv --version >/dev/null || (echo "ERROR: uv is required!" && exit 1)
@uvx --version >/dev/null || (echo "ERROR: uvx is required!" && exit 1)
@uvx ruff --version >/dev/null || (echo "ERROR: ruff is required!" && exit 1)
@echo "All required tools are installed."

.PHONY: init
init: check-require ## Initialize virtual environment using uv
@if [ ! -d $(VENV) ]; then \
echo "Virtual environment does not exist, creating new virtual environment ..."; \
echo "Creating virtual environment with uv..."; \
uv venv $(VENV); \
fi
@$(MAKE) sync
@echo "Virtual environment initialized."

@echo "Installing requirements into virtual environment..."
@$(MAKE) compile-requirements
@$(MAKE) sync-requirements
@echo "Virtual environment setup complete."

.PHONY: compile-requirements
compile-requirements: ## pip-compile Python requirement files
@echo "Running target: compile-requirements"
@$(UV_PIP_COMPILE) -o $(REQUIREMENTS_TXT) $(REQUIREMENTS_IN)
@$(UV_PIP_COMPILE) -o $(DEV_REQUIREMENTS_TXT) $(DEV_REQUIREMENTS_IN)

.PHONY: sync-requirements
sync-requirements: ## pip-sync Python modules with virtual environment
@echo "Running target: sync-requirements"
@$(UV_PIP_SYNC) $(DEV_REQUIREMENTS_TXT)
.PHONY: sync
sync: ## Synchronize Python dependencies
@echo "Synchronizing Python dependencies with uv sync..."
@$(UV_SYNC)

.PHONY: test
test: ## Run unit tests
@echo "Running target: test"
$(TEST_CMD)
test: ## Run tests with pytest
@echo "Running tests..."
@$(UV_PYTHON) -m pytest $(TEST_DIR)

.PHONY: lint
lint: ## Run linting to check code style
@echo "Running target: lint"
$(LINT_CMD)
lint: ## Run linting with ruff
@echo "Linting code..."
@uvx ruff check

.PHONY: fmt
fmt: ## Run linting to check code style
@echo "Running target: fmt"
$(FMT_CMD)
.PHONY: format
format: ## Format code with ruff
@echo "Formatting code..."
@uvx ruff format

.PHONY: build
build: init ## Build the Docker image
@echo "Running target: build"
docker build -t $(IMAGE_NAME) ./app
@echo "Building Docker image..."
@docker build -t $(IMAGE_NAME) -f Dockerfile .

.PHONY: run
run: ## Run the application locally
@echo "Running application..."
@$(UV_PYTHON) main.py

.PHONY: up
up: ## Create and start the Docker Compose services
@echo "Running target: up"
docker compose -f $(COMPOSE_FILE) -p $(PROJECT) up -d
up: ## Start Docker Compose services
@echo "Starting Docker Compose services..."
@$(DOCKER_COMPOSE) up -d

.PHONY: start
start: ## Start the Docker Compose services
@echo "Running target: start"
docker compose -f $(COMPOSE_FILE) -p $(PROJECT) start
start: ## Start Docker Compose services without recreating containers
@echo "Starting existing Docker Compose services..."
@$(DOCKER_COMPOSE) start

.PHONY: stop
stop: ## Stop the Docker Compose services
@echo "Running target: stop"
docker compose -f $(COMPOSE_FILE) -p $(PROJECT) stop
stop: ## Stop Docker Compose services without removing containers
@echo "Stopping Docker Compose services..."
@$(DOCKER_COMPOSE) stop

.PHONY: down
down: ## Stop and remove the Docker Compose services
@echo "Running target: down"
docker compose -f $(COMPOSE_FILE) -p $(PROJECT) down

.PHONY: create-k8s-deployment
create-k8s-deployment: ## Create k8s deployment
@echo "Running target: create-k8s-deployment"
$(UV_PYTHON) ./annotate_elastic_apm.py -m "Created application deployment"
#kubectl apply -f sensorpush_deployment.yaml

.PHONY: delete-k8s-deployment
delete-k8s-deployment: ## Delete k8s deployment
@echo "Running target: delete-k8s-deployment"
@$(UV_PYTHON) ./annotate_elastic_apm.py -m "Deleted application deployment"
#kubectl delete -f sensorpush_deployment.yaml
down: ## Stop and remove Docker Compose services
@echo "Stopping and removing Docker Compose services..."
@$(DOCKER_COMPOSE) down

.PHONY: clean
clean: ## Clean up virtual environment and other generated files
@echo "Running target: clean"
@echo "Cleaning up environment..."
@if [ -d $(VENV) ]; then \
echo "Removing existing virtual environment ..."; \
echo "Removing virtual environment..."; \
rm -rf $(VENV); \
fi

@echo "Removing generated files..."
@find . -type d -name '__pycache__' -exec rm -r {} +
@find . -type f -name '*.pyc' -exec rm -f {} +
@find . -type f -name '*.pyo' -exec rm -f {} +
@find . -type f -name '*.log' -exec rm -f {} +
@find . -type d -name '__pycache__' -exec rm -rf {} +
@find . -type f -name '*.pyc' -delete
@find . -type f -name '*.pyo' -delete
@find . -type f -name '*.log' -delete
@find . -type f -name '*.egg-info' -exec rm -rf {} +
@find . -type f -name '*.dist-info' -exec rm -rf {} +
@echo "Clean-up complete."

.PHONY: create-k8s-deployment
create-k8s-deployment: ## Create Kubernetes deployment
@echo "Creating Kubernetes deployment..."
@$(UV_PYTHON) annotate-elastic-apm.py -m "Created application deployment"
# kubectl apply -f sensorpush_deployment.yaml

.PHONY: delete-k8s-deployment
delete-k8s-deployment: ## Delete Kubernetes deployment
@echo "Deleting Kubernetes deployment..."
@$(UV_PYTHON) annotate-elastic-apm.py -m "Deleted application deployment"
# kubectl delete -f sensorpush_deployment.yaml
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ Example Python application that uses the SensorPush API, Elastic Cloud with Elas

## Configuration

Before running the app you must update the `app/config/settings.toml` and `app/config/secrets.toml` configuration files.
Before running the app you must update the `config/settings.toml` and `aonfig/.secrets.toml` configuration files.

### app/config/settings.toml
### config/settings.toml

The `settings.toml` configuration file should have the following configuration settings defined, as appropriate, for your
environment.

```toml
[SETTINGS]
# Elastic configuration
INDEX_NAME = "sensorpush"
DELETE_INDEX = false
Expand All @@ -39,7 +38,7 @@ name = "sensor1"
description = "Back Outdoor Sensor"
```

For each SensorPush sensor you have, you should add them to `app/config/settings.toml`. For example, two sensors would look
For each SensorPush sensor you have, you should add them to `config/settings.toml`. For example, two sensors would look
like this in the configuration.

```toml
Expand All @@ -55,13 +54,12 @@ name = "sensor2"
description = "Office Sensor"
```

### app/config/secrets.toml
### config/.secrets.toml

The `secrets.toml` configuration file should have the following configuration settings defined, as appropriate, for your
The `.secrets.toml` configuration file should have the following configuration settings defined, as appropriate, for your
environment.

```toml
[SECRETS]
# Elastic Server Configuration
ES_USERNAME = "YOUR ELASTICSEARCH USERNAME"
ES_PASSWORD = "YOUR ELASTICSEARCH PASSWORD"
Expand Down
Loading

0 comments on commit 6983f58

Please sign in to comment.