Files
vmware-api-simulator/Makefile
T
inecs f8d3cbdd59 Initial commit: VMware vSphere API simulator scaffold.
Add the FastAPI app, PostgreSQL migrations, Docker/Helm packaging, API
contracts, docs, client examples, and the unit/integration/compatibility
test suite for local client and tooling labs without a real vCenter.
2026-07-18 04:42:11 +03:00

257 lines
11 KiB
Makefile
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
COMPOSE ?= docker compose
SERVICE_DEV := dev
SERVICE_SIM := simulator
PYTEST_OFFLINE := -m "not integration and not compatibility and not pve_stub"
# Docker Hub release image (runtime target only — not the local bind-mount "dev" image).
DOCKERHUB_USER ?= inecs
IMAGE_NAME ?= vmware-api-simulator
VERSION ?= $(shell sed -n 's/^version = "\(.*\)"/\1/p' pyproject.toml)
DOCKER_IMAGE ?= $(DOCKERHUB_USER)/$(IMAGE_NAME)
PUSH_LATEST ?= 1
COMPOSE_RELEASE ?= $(COMPOSE) -f docker-compose.release.yml
HELM_CHART ?= ./helm/vmware-api-simulator
.PHONY: help install format lint typecheck test test-unit test-integration test-contract test-compatibility test-surface evidence coverage run dev up down restart logs docker-build docker-up docker-down docker-logs docker-restart db-up db-down db-migrate db-reset api-import api-diff seed clean ci ci-all shell release release-build release-up release-down release-seed helm-deps helm-template \
pulumi-tests pulumi-tests-smoke test-pulumi-smoke test-pulumi test-smoke-all test-all clean-test-resources
help: ## Show available commands
@awk 'BEGIN {FS = ":.*## "}; /^[a-zA-Z0-9_-]+:.*## / {printf "%-22s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
install: ## Build runtime and development images
@test -f .env || cp .env.example .env
$(COMPOSE) build simulator $(SERVICE_DEV)
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 .
typecheck: ## Run strict mypy checks
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) mypy
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
test-integration: ## Run tests that require PostgreSQL
@test -f .env || cp .env.example .env
$(COMPOSE) up -d postgres
$(COMPOSE) run --rm $(SERVICE_DEV) pytest -m integration
test-contract: ## Run offline API contract tests
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) pytest -m contract
test-compatibility: ## Run client smoke flow against the Compose stack
@test -f .env || cp .env.example .env
$(COMPOSE) up -d --build --wait
$(COMPOSE) run --rm --entrypoint python $(SERVICE_SIM) -m app.simulation.seed_cli
$(COMPOSE) run --rm $(SERVICE_DEV) pytest -m compatibility
test-surface: ## Probe every declared method on majors 6-9 (0x501 / 0xexception)
@test -f .env || cp .env.example .env
$(COMPOSE) up -d postgres
$(COMPOSE) run --rm $(SERVICE_DEV) pytest tests/compatibility/test_api_surface_probe.py -q
vsphere-surface: ## Probe native vSphere REST coverage registry against running gateway
@test -f .env || cp .env.example .env
$(COMPOSE) up -d --wait
# From the tools container, hit the simulator service (not host-mapped :443).
$(COMPOSE) run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 $(SERVICE_DEV) \
python scripts/vsphere_surface_probe.py
vsphere-matrix: ## Full REST matrix: all verbs × majors 69 (no 5xx)
@test -f .env || cp .env.example .env
$(COMPOSE) up -d --wait
$(COMPOSE) run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 $(SERVICE_DEV) \
python scripts/vsphere_full_matrix_probe.py
vsphere-universe: ## Regenerate Broadcom Automation API universe.json from operations index
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) python scripts/generate_vsphere_universe.py
vsphere-bundles: ## Regenerate stub OpenAPI matrices + evidence ledgers
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) python scripts/write_vsphere_bundles.py
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) python scripts/write_vsphere_evidence.py
test-vsphere: ## Native vSphere unit + integration + surface + majors matrix
@test -f .env || cp .env.example .env
$(COMPOSE) up -d --wait
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) pytest \
tests/unit/test_vsphere_profiles.py \
tests/unit/test_vsphere_catalog.py \
tests/unit/test_vsphere_matrix.py \
tests/unit/test_vsphere_compatibility.py \
tests/unit/test_vsphere_universe.py \
tests/unit/test_vsphere_mappers.py \
tests/unit/test_property_collector.py \
tests/unit/test_web_assets.py \
tests/unit/test_web_console.py \
tests/integration/test_vsphere_api.py \
tests/integration/test_vsphere_api_surface_data.py \
tests/integration/test_vsphere_soap_depth.py \
tests/integration/test_vsphere_soap_create_vm.py \
tests/integration/test_vsphere_full_api.py -q
$(COMPOSE) run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 $(SERVICE_DEV) \
python scripts/vsphere_surface_probe.py
$(COMPOSE) run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 $(SERVICE_DEV) \
python scripts/vsphere_full_matrix_probe.py
$(COMPOSE) run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 $(SERVICE_DEV) \
python scripts/vsphere_real_data_spotcheck.py
$(COMPOSE) run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 $(SERVICE_DEV) \
python scripts/vsphere_nonempty_probe.py
$(COMPOSE) run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 $(SERVICE_DEV) \
python scripts/run_client_cookbooks.py
client-cookbooks: ## Python/Ansible/Terraform/Pulumi-style cookbooks against gateway or simulator
@test -f .env || cp .env.example .env
$(COMPOSE) up -d --wait
$(COMPOSE) run --rm --entrypoint python $(SERVICE_SIM) -m app.simulation.seed_cli
$(COMPOSE) run --rm --no-deps -e VSPHERE_BASE=http://simulator:8080 $(SERVICE_DEV) \
python scripts/run_client_cookbooks.py
# Hybrid pulumi-tests suite (pulumi-vsphere + REST matrix + CRUD + SOAP)
pulumi-tests: ## Run full hybrid suite (provider + REST×6-9 + CRUD + SOAP)
@$(MAKE) -C pulumi-tests test-pulumi
pulumi-tests-smoke: ## PU-INV + one-major REST smoke (no VM/tags/CRUD/SOAP)
@$(MAKE) -C pulumi-tests test-pulumi-smoke
test-pulumi-smoke test-pulumi test-smoke-all test-all clean-test-resources: ## Aliases → pulumi-tests/
@$(MAKE) -C pulumi-tests $@
evidence: ## Regenerate per-major verified surface evidence ledgers
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) python -m app.evidence_gen
coverage: ## Run offline tests with coverage enforcement
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) pytest $(PYTEST_OFFLINE) --cov=app --cov-report=term-missing --cov-report=xml
run: ## Run the application in the foreground
@test -f .env || cp .env.example .env
$(COMPOSE) up --build
up: ## Start PostgreSQL, simulator, and TLS gateway
@test -f .env || cp .env.example .env
$(COMPOSE) up -d --build --wait
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 from all services
$(COMPOSE) logs -f
dev: ## Run the application with auto-reload in Docker
@test -f .env || cp .env.example .env
$(COMPOSE) up -d postgres migrate
$(COMPOSE) up simulator
docker-build: ## Build runtime and development images
$(MAKE) install
docker-up: up ## Alias for up
docker-restart: ## Rebuild and recreate simulator and TLS gateway only
$(COMPOSE) up -d --build --force-recreate simulator api-gateway
docker-down: down ## Alias for down
docker-logs: ## Follow simulator logs only
$(COMPOSE) logs -f simulator
db-up: ## Start PostgreSQL only
@test -f .env || cp .env.example .env
$(COMPOSE) up -d postgres
db-down: ## Stop PostgreSQL
$(COMPOSE) stop postgres
db-migrate: ## Apply database migrations
@test -f .env || cp .env.example .env
$(COMPOSE) run --rm migrate
db-reset: ## Recreate the local database volume
$(COMPOSE) down -v
$(COMPOSE) up -d postgres
$(COMPOSE) run --rm migrate
api-import: ## Import an API snapshot
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) vmware-api-contract import $(ARGS)
api-diff: ## Compare API snapshots
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) vmware-api-contract diff $(ARGS)
seed: ## Seed simulation data (vSphere; PROFILE= / VSPHERE_PROFILE=small|large|demo-cluster)
@test -f .env || cp .env.example .env
SEED_PROFILE="$${PROFILE:-small}" \
SEED_VSPHERE_PROFILE="$${VSPHERE_PROFILE:-$${PROFILE:-large}}" \
SEED_VSPHERE_LARGE_VMS="$${VSPHERE_VMS:-1000}" \
SEED_VSPHERE_LARGE_HOSTS="$${VSPHERE_HOSTS:-10}" \
$(COMPOSE) run --rm --entrypoint python $(SERVICE_SIM) -m app.simulation.seed_cli
shell: ## Open an interactive shell in the development container
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) bash
clean: ## Remove generated local artifacts
rm -rf .coverage coverage.xml htmlcov .mypy_cache .pytest_cache .ruff_cache
ci: ## Offline quality gate + full API surface probe (Postgres)
$(COMPOSE) run --rm --no-deps $(SERVICE_DEV) sh -c '\
ruff format --check . && \
ruff check . && \
mypy && \
pytest $(PYTEST_OFFLINE) --cov=app --cov-report=term-missing --cov-report=xml'
$(MAKE) test-surface
ci-all: ## Full CI: offline + surface + remaining integration + client compatibility
$(MAKE) ci
$(MAKE) test-integration
$(MAKE) test-compatibility
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=small by default)
SEED_PROFILE="$${PROFILE:-small}" \
SEED_VSPHERE_PROFILE="$${VSPHERE_PROFILE:-$${PROFILE:-small}}" \
IMAGE_TAG="$${IMAGE_TAG:-$(VERSION)}" DOCKER_IMAGE="$(DOCKER_IMAGE)" \
$(COMPOSE_RELEASE) run --rm --entrypoint python simulator -m app.simulation.seed_cli
helm-deps: ## No-op placeholder (chart has no OCI dependencies)
@echo "Chart $(HELM_CHART) vendors PostgreSQL templates; no helm dependency update required."
helm-template: ## Render Helm manifests locally (requires helm)
helm template vmware-sim $(HELM_CHART) \
-f $(HELM_CHART)/values-ingress-example.yaml \
--set certManager.email=docs@example.com \
--set secret.ticketSigningKey=docs-only-signing-key