540675597a
Ship Harbor/Hub push with latest+version tags, deploy to ovirt.devops.org.ru, and show the package version badge in Help → About.
263 lines
10 KiB
Makefile
263 lines
10 KiB
Makefile
COMPOSE ?= docker compose
|
||
SERVICE_DEV := dev
|
||
SERVICE_SIM := simulator
|
||
PYTEST_OFFLINE := -m "not integration and not compatibility"
|
||
|
||
# Docker Hub release image (runtime target only — not the local bind-mount "dev" image).
|
||
DOCKERHUB_USER ?= inecs
|
||
IMAGE_NAME ?= ovirt-api-simulator
|
||
VERSION ?= $(shell cat VERSION 2>/dev/null || echo 0.1.0)
|
||
DOCKER_IMAGE ?= $(DOCKERHUB_USER)/$(IMAGE_NAME)
|
||
PUSH_LATEST ?= 1
|
||
|
||
COMPOSE_RELEASE ?= $(COMPOSE) -f docker-compose.release.yml
|
||
HELM_CHART ?= ./helm/ovirt-api-simulator
|
||
LAB ?= ./pulumi-tests
|
||
# Remotes used by `make push` (GitHub + antropoff).
|
||
GIT_REMOTES ?= origin antropoff
|
||
# Preferred host ports for `make up-local` (override / .env stay gitignored).
|
||
LOCAL_ENGINE_PORT ?= 6443
|
||
LOCAL_UI_PORT ?= 6080
|
||
|
||
.PHONY: bump-patch bump-minor version-commit help install format lint typecheck test test-unit test-integration test-contract \
|
||
test-surface test-versions coverage up down restart logs seed seed-small seed-large seed-big seed-demo \
|
||
audit-seed-dump smoke clean ci shell \
|
||
helm-template generate-packs \
|
||
release release-build release-up release-down release-seed \
|
||
test-pulumi-smoke test-pulumi pulumi-tests \
|
||
test-smoke-all test-all clean-test-resources push up-local down-local
|
||
|
||
help: ## Show available commands
|
||
@awk 'BEGIN {FS = ":.*## "}; /^[a-zA-Z0-9_-]+:.*## / {printf "%-22s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||
@echo
|
||
@echo "Version: $$(cat VERSION 2>/dev/null || echo 0.1.0) (make bump-patch | bump-minor)"
|
||
|
||
install: ## Build runtime and development images
|
||
@test -f .env || cp .env.example .env
|
||
$(COMPOSE) build simulator $(SERVICE_DEV)
|
||
|
||
generate-packs: ## Regenerate contracts/ovirt series packs
|
||
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) python tools/ovirt_api_inventory/generate_packs.py
|
||
|
||
format: ## Format Python sources
|
||
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) ruff format .
|
||
|
||
lint: ## Run Ruff lint checks
|
||
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) ruff check app tests
|
||
|
||
typecheck: ## Run strict mypy checks
|
||
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) mypy app/ovirt app/web/routes.py app/main.py app/config.py app/lifespan.py
|
||
|
||
test: ## Run offline unit and contract tests
|
||
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) pytest $(PYTEST_OFFLINE)
|
||
|
||
test-unit: ## Run unit tests
|
||
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) pytest tests/unit tests/ovirt -q
|
||
|
||
test-integration: ## Run tests that require PostgreSQL
|
||
@test -f .env || cp .env.example .env
|
||
$(COMPOSE) up -d postgres migrate
|
||
$(COMPOSE) run --rm $(SERVICE_DEV) pytest -m integration tests/ovirt -q
|
||
|
||
test-contract: ## Validate oVirt contract packs
|
||
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) pytest -m contract tests/ovirt -q
|
||
|
||
test-surface: ## Probe Engine API surface across series
|
||
@test -f .env || cp .env.example .env
|
||
$(COMPOSE) up -d --wait
|
||
$(COMPOSE) run --rm --no-deps --entrypoint python $(SERVICE_SIM) -m pytest tests/ovirt -q --tb=line
|
||
|
||
test-versions: ## All Engine series packs with seeded inventory assertions
|
||
@test -f .env || cp .env.example .env
|
||
$(COMPOSE) up -d --wait
|
||
$(COMPOSE) run --rm --entrypoint python $(SERVICE_SIM) -m app.ovirt.seed_cli --profile minimal
|
||
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) pytest -m integration tests/ovirt/test_api_versions.py -q --tb=short
|
||
|
||
coverage: ## Offline coverage
|
||
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) pytest $(PYTEST_OFFLINE) --cov=app/ovirt --cov-report=term-missing
|
||
|
||
up: ## Start PostgreSQL, simulator, and Engine gateway
|
||
@test -f .env || cp .env.example .env
|
||
$(COMPOSE) up -d --build --wait
|
||
|
||
# Writes gitignored docker-compose.override.yml (+ syncs ports into .env) when
|
||
# default 443/5000 are busy (common on macOS). Compose auto-merges the override.
|
||
up-local: ## Start stack with local port override (not committed)
|
||
@set -e; \
|
||
test -f .env || cp .env.example .env; \
|
||
pick_port() { \
|
||
preferred="$$1"; shift; \
|
||
for p in "$$preferred" "$$@"; do \
|
||
if ! lsof -nP -iTCP:"$$p" -sTCP:LISTEN >/dev/null 2>&1; then \
|
||
echo "$$p"; return 0; \
|
||
fi; \
|
||
done; \
|
||
echo "No free port among: $$preferred $$*" >&2; exit 1; \
|
||
}; \
|
||
engine_port=$$(pick_port "$(LOCAL_ENGINE_PORT)" 6443 7443 8443 16443); \
|
||
ui_port=$$(pick_port "$(LOCAL_UI_PORT)" 6080 7080 8080 16080); \
|
||
printf '%s\n' \
|
||
'# Generated by `make up-local` — gitignored, do not commit.' \
|
||
'services:' \
|
||
' api-gateway:' \
|
||
' ports:' \
|
||
" - \"$${engine_port}:443\"" \
|
||
" - \"$${ui_port}:5000\"" \
|
||
> docker-compose.override.yml; \
|
||
if grep -q '^OVIRT_ENGINE_PORT=' .env; then \
|
||
sed -i.bak -e "s/^OVIRT_ENGINE_PORT=.*/OVIRT_ENGINE_PORT=$${engine_port}/" \
|
||
-e "s/^OVIRT_UI_PORT=.*/OVIRT_UI_PORT=$${ui_port}/" .env && rm -f .env.bak; \
|
||
else \
|
||
printf '\nOVIRT_ENGINE_PORT=%s\nOVIRT_UI_PORT=%s\n' "$$engine_port" "$$ui_port" >> .env; \
|
||
fi; \
|
||
echo "Local ports → Engine https://127.0.0.1:$${engine_port} UI http://127.0.0.1:$${ui_port}"; \
|
||
echo "Wrote docker-compose.override.yml (gitignored)"; \
|
||
$(COMPOSE) up -d --build --wait; \
|
||
echo "up-local ok"
|
||
|
||
down-local: ## Stop stack and remove gitignored local port override
|
||
@$(COMPOSE) down
|
||
@rm -f docker-compose.override.yml
|
||
@if [ -f .env ]; then \
|
||
if grep -q '^OVIRT_ENGINE_PORT=' .env; then \
|
||
sed -i.bak -e 's/^OVIRT_ENGINE_PORT=.*/OVIRT_ENGINE_PORT=443/' \
|
||
-e 's/^OVIRT_UI_PORT=.*/OVIRT_UI_PORT=5000/' .env && rm -f .env.bak; \
|
||
fi; \
|
||
fi
|
||
@echo "down-local ok (removed docker-compose.override.yml)"
|
||
|
||
down: ## Stop local services
|
||
$(COMPOSE) down
|
||
|
||
restart: ## Rebuild and restart the stack
|
||
@test -f .env || cp .env.example .env
|
||
$(COMPOSE) up -d --build --force-recreate --wait
|
||
|
||
logs: ## Follow logs
|
||
$(COMPOSE) logs -f
|
||
|
||
seed: ## Seed minimal lab
|
||
$(COMPOSE) run --rm --entrypoint python $(SERVICE_SIM) -m app.ovirt.seed_cli --profile minimal
|
||
|
||
seed-small: ## Seed small cluster (3 hosts · 50 VMs)
|
||
$(COMPOSE) run --rm --entrypoint python $(SERVICE_SIM) -m app.ovirt.seed_cli --profile small
|
||
|
||
seed-large: ## Seed large cluster (10 hosts · 1000 VMs)
|
||
$(COMPOSE) run --rm --entrypoint python $(SERVICE_SIM) -m app.ovirt.seed_cli --profile large
|
||
|
||
seed-big: ## Seed big cluster (30 hosts · 2000 VMs)
|
||
$(COMPOSE) run --rm --entrypoint python $(SERVICE_SIM) -m app.ovirt.seed_cli --profile big
|
||
|
||
seed-demo: seed-large ## Alias: large cluster (legacy name)
|
||
|
||
audit-seed-dump: ## Contract dump audit (collections+entities) vs live Engine
|
||
@set -a; [ -f .env ] && . ./.env; set +a; \
|
||
python3 tools/audit_seed_dump.py \
|
||
"https://127.0.0.1:$${OVIRT_ENGINE_PORT:-443}" \
|
||
"$${OVIRT_SERIES:-4.5}"
|
||
|
||
smoke: ## Quick Engine auth + list VMs smoke
|
||
@set -a; [ -f .env ] && . ./.env; set +a; \
|
||
curl -skf -u 'admin@internal:secret' -H 'Accept: application/json' -H 'Version: 4' \
|
||
"https://127.0.0.1:$${OVIRT_ENGINE_PORT:-443}/ovirt-engine/api/vms" >/dev/null
|
||
@echo "smoke ok"
|
||
|
||
helm-template: ## Render Helm chart
|
||
helm template ovirt-sim $(HELM_CHART)
|
||
|
||
clean: ## Remove caches
|
||
rm -rf .pytest_cache .mypy_cache .ruff_cache .coverage coverage.xml
|
||
find . -type d -name __pycache__ -prune -exec rm -rf {} +
|
||
|
||
ci: format lint test-unit ## Local CI gate
|
||
|
||
shell: ## Dev shell in container
|
||
$(COMPOSE) run --rm $(SERVICE_DEV) bash
|
||
|
||
release-build: ## Build the runtime image tagged for Docker Hub (no push)
|
||
@test -n "$(VERSION)" || (echo "VERSION is empty; set VERSION=... or version in pyproject.toml" >&2; exit 1)
|
||
@echo "Building $(DOCKER_IMAGE):$(VERSION) (target=runtime)"
|
||
docker build \
|
||
--target runtime \
|
||
--build-arg APP_VERSION=$(VERSION) \
|
||
-t $(DOCKER_IMAGE):$(VERSION) \
|
||
$(if $(filter 1 true yes,$(PUSH_LATEST)),-t $(DOCKER_IMAGE):latest,) \
|
||
.
|
||
|
||
release: release-build ## Build and push the runtime image to Docker Hub
|
||
@echo "Pushing $(DOCKER_IMAGE):$(VERSION)"
|
||
@docker push $(DOCKER_IMAGE):$(VERSION)
|
||
@if [ "$(PUSH_LATEST)" = "1" ] || [ "$(PUSH_LATEST)" = "true" ] || [ "$(PUSH_LATEST)" = "yes" ]; then \
|
||
echo "Pushing $(DOCKER_IMAGE):latest"; \
|
||
docker push $(DOCKER_IMAGE):latest; \
|
||
fi
|
||
@echo "Released $(DOCKER_IMAGE):$(VERSION)$(if $(filter 1 true yes,$(PUSH_LATEST)), and $(DOCKER_IMAGE):latest,)"
|
||
|
||
release-up: ## Pull and start the published Hub stack (docker-compose.release.yml)
|
||
IMAGE_TAG="$${IMAGE_TAG:-$(VERSION)}" DOCKER_IMAGE="$(DOCKER_IMAGE)" $(COMPOSE_RELEASE) pull
|
||
IMAGE_TAG="$${IMAGE_TAG:-$(VERSION)}" DOCKER_IMAGE="$(DOCKER_IMAGE)" $(COMPOSE_RELEASE) up -d --wait
|
||
|
||
release-down: ## Stop the published Hub stack
|
||
$(COMPOSE_RELEASE) down
|
||
|
||
release-seed: ## Seed the published Hub stack (PROFILE=minimal by default)
|
||
SEED_PROFILE="$${PROFILE:-minimal}" IMAGE_TAG="$${IMAGE_TAG:-$(VERSION)}" DOCKER_IMAGE="$(DOCKER_IMAGE)" \
|
||
$(COMPOSE_RELEASE) run --rm --entrypoint python simulator -m app.ovirt.seed_cli --profile "$${PROFILE:-minimal}"
|
||
|
||
# --- Pulumi contract-coverage lab (pulumi-tests) ---
|
||
test-pulumi-smoke: ## Pulumi contract-coverage smoke
|
||
$(MAKE) -C $(LAB) test-pulumi-smoke
|
||
|
||
test-pulumi: ## Pulumi full contract coverage (all series × all ops)
|
||
$(MAKE) -C $(LAB) test-pulumi
|
||
|
||
pulumi-tests: test-pulumi ## Alias: full Pulumi contract coverage suite
|
||
|
||
test-smoke-all: ## Client lab smoke
|
||
$(MAKE) -C $(LAB) test-smoke-all
|
||
|
||
test-all: ## Client lab full suite (Pulumi contract coverage)
|
||
$(MAKE) -C $(LAB) test-all
|
||
|
||
clean-test-resources: ## Cleanup lab-created resources
|
||
$(MAKE) -C $(LAB) clean-test-resources
|
||
|
||
# --- Git: stage, commit (prompt), push to both remotes ---
|
||
# Multi-line commit: paste message, then Ctrl-D (same UX as proxmox-api-simulator).
|
||
# Optional: make push MSG='one-line message'
|
||
bump-patch: ## VERSION +0.0.1 (pyproject + Helm)
|
||
@PYTHONPATH=. python3 scripts/bump_version.py patch
|
||
@echo "VERSION → $$(cat VERSION)"
|
||
|
||
bump-minor: ## VERSION +0.1.0 (pyproject + Helm)
|
||
@PYTHONPATH=. python3 scripts/bump_version.py minor
|
||
@echo "VERSION → $$(cat VERSION)"
|
||
|
||
version-commit: ## Stage version files and commit "Bump version to …"
|
||
@git add VERSION pyproject.toml helm/ovirt-api-simulator/Chart.yaml helm/ovirt-api-simulator/values.yaml
|
||
@if git diff --cached --quiet; then \
|
||
echo "Nothing to commit for version files."; \
|
||
else \
|
||
git commit -m "Bump version to $$(cat VERSION)."; \
|
||
fi
|
||
|
||
push: ## bump-patch + commit version + push origin
|
||
@$(MAKE) bump-patch
|
||
@$(MAKE) version-commit
|
||
@set -e; \
|
||
git add .; \
|
||
echo "=== staged ==="; \
|
||
git status --short; \
|
||
echo; \
|
||
if git diff --cached --quiet; then \
|
||
echo "Nothing else to commit — pushing current branch."; \
|
||
else \
|
||
echo "Enter commit message for remaining changes, then Ctrl-D:"; \
|
||
msg=$$(cat </dev/tty); \
|
||
if [ -z "$$msg" ]; then echo "Empty commit message, aborting." >&2; exit 1; fi; \
|
||
git commit -m "$$msg"; \
|
||
fi; \
|
||
echo "Pushing to both remotes:"; \
|
||
git remote get-url --push --all origin | sed 's/^/ - /'; \
|
||
git push origin HEAD
|