Ctrl K
ComunidadGuías…

Makefile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
GO_PROJECT_NAME := s3d
SHELL := /bin/bash

export GOFIPS140 := v1.0.0

# Quiet-mode filters (active when QUIET=1, set by preflight via recursive make)
# Note: grep pipelines use PIPESTATUS[0] so the exit status of `go test`
# propagates through the filter — otherwise a test failure is swallowed by
# grep's own (success) exit code and preflight prints "passed" on red.
ifdef QUIET
  _Q     = @
  _COVQ  = 2>&1 | { grep -Ev '^\s*(ok|PASS|\?|=== RUN|--- PASS:)\s' | grep -v 'coverage: 0\.0%' || true; }; exit $${PIPESTATUS[0]}
  _RACEQ = 2>&1 | { grep -Ev '^\s*(ok|PASS|\?|=== RUN|--- PASS:)\s' || true; }; exit $${PIPESTATUS[0]}
else
  _Q     =
  _COVQ  =
  _RACEQ =
endif

# Generate self-signed dev TLS certs (no-op if they already exist)
certs:
	@mkdir -p certs
	@test -f certs/server.pem || openssl req -x509 -newkey rsa:2048 -nodes \
		-keyout certs/server.key -out certs/server.pem \
		-days 3650 -subj '/CN=localhost' \
		-addext 'subjectAltName=DNS:localhost,IP:127.0.0.1,IP:10.11.12.1,IP:10.11.12.2,IP:10.11.12.3,IP:10.11.12.4,IP:10.11.12.5,IP:10.11.12.6,IP:10.11.12.7'

build:
	$(MAKE) go_build

# Container targets. The image is the compatibility loop: it starts in seconds
# and the smoke suite drives real S3 clients at it, which is how three of the
# open S3-compatibility defects were found in the first place.
DOCKER_IMAGE   ?= predastore:dev
COMPOSE_SINGLE := deploy/compose.single.yml
COMPOSE_CLUSTER:= deploy/compose.cluster.yml
COMPOSE_FILE   ?= $(COMPOSE_CLUSTER)
SMOKE_BASELINE ?= scripts/smoke-baseline.txt

docker-build:
	@echo -e "\n....Building $(DOCKER_IMAGE)"
	docker build -t $(DOCKER_IMAGE) .

# The cluster profile needs one keypair shared by every host: peers verify
# against the trust store, so hosts holding their own identities never elect a
# leader. The single profile generates its own and needs nothing here.
compose-up: docker-build
	@if [ "$(COMPOSE_FILE)" = "$(COMPOSE_CLUSTER)" ]; then deploy/docker/gen-certs.sh; fi
	PREDA_IMAGE=$(DOCKER_IMAGE) docker compose -f $(COMPOSE_FILE) up -d

compose-down:
	PREDA_IMAGE=$(DOCKER_IMAGE) docker compose -f $(COMPOSE_FILE) down -v

# Fails only on a regression against the baseline, since predastore does not
# pass every check today. SMOKE_SUITES narrows the run: `make docker-smoke
# SMOKE_SUITES=aws`.
SMOKE_SUITES ?=
docker-smoke:
	@PREDA_IMAGE=$(DOCKER_IMAGE) PREDA_BASELINE=$(SMOKE_BASELINE) \
		./scripts/smoke.sh $(SMOKE_SUITES)

# Fails on any failing check. This is the honest question — is predastore S3
# compatible — and it is red until the remaining gaps are closed. The
# regression form above is what a pull request runs, so a branch is not red
# for defects it did not introduce.
docker-smoke-strict:
	@PREDA_IMAGE=$(DOCKER_IMAGE) PREDA_BASELINE=$(SMOKE_BASELINE) PREDA_STRICT=1 \
		./scripts/smoke.sh $(SMOKE_SUITES)

# Re-record the baseline. Run it when a fix lands, in the same change.
docker-smoke-baseline:
	@PREDA_IMAGE=$(DOCKER_IMAGE) PREDA_WRITE_BASELINE=$(SMOKE_BASELINE) \
		./scripts/smoke.sh $(SMOKE_SUITES)

# ceph/s3-tests conformance. The smoke suite asks whether real clients work;
# this asks whether the operations match the specification. It needs a cluster
# on the s3tests profile, the only one carrying the three accounts and the
# us-east-1 region the suite requires:
#
#   ./scripts/start.sh -w s3tests
#   make s3-tests
S3TESTS_BASELINE ?= scripts/s3-tests-baseline.txt

s3-tests:
	@PREDA_BASELINE=$(S3TESTS_BASELINE) ./scripts/s3-tests.sh

# Fails on any failing case. Predastore is a long way from passing s3-tests, so
# this is red by design: it exists to be read, not to gate anything.
s3-tests-strict:
	@PREDA_BASELINE=$(S3TESTS_BASELINE) PREDA_STRICT=1 ./scripts/s3-tests.sh

# Re-record the baseline. Run it when a fix lands, in the same change.
s3-tests-baseline:
	@PREDA_WRITE_BASELINE=$(S3TESTS_BASELINE) ./scripts/s3-tests.sh

# GO commands
go_build:
	@echo -e "\n....Building $(GO_PROJECT_NAME)"
	go build -ldflags "-s -w" -o ./bin/s3d ./cmd/s3d

# Standalone install, for a host running predastore as a systemd service rather
# than under Spinifex or in a container. DESTDIR and PREFIX are honoured so a
# package build can stage into a buildroot.
#
# It installs files and nothing else. daemon-reload, systemd-sysusers,
# systemd-tmpfiles, `sysctl --system` and `systemctl enable` are activation, and
# a target that performed them could not be used by a package build.
PREFIX      ?= /usr/local
DESTDIR     ?=
SYSCONFDIR  ?= /etc
# The vendor directory, not /etc/systemd/system: that one is the operator's, and
# writing there would collide with a local override and survive uninstall.
UNITDIR     ?= /usr/lib/systemd/system
SYSUSERSDIR ?= /usr/lib/sysusers.d
TMPFILESDIR ?= /usr/lib/tmpfiles.d
# /etc/sysctl.d rather than /usr/lib/sysctl.d, because the value is a property
# of the machine's NICs and workload and operators do edit it.
SYSCTLDIR   ?= $(SYSCONFDIR)/sysctl.d

SYSTEMD_SRC := deploy/systemd

# A file prerequisite, not the phony `build`: an existing binary is left alone,
# so `sudo make install` works without `go` on root's PATH. Run `make build`
# first to pick up source changes.
./bin/s3d:
	$(MAKE) go_build

install: ./bin/s3d
	@echo -e "\n....Installing $(GO_PROJECT_NAME) to $(DESTDIR)$(PREFIX)"
	install -D -m 0755 ./bin/s3d '$(DESTDIR)$(PREFIX)/bin/s3d'
	install -D -m 0755 scripts/predastore-keygen.sh '$(DESTDIR)$(PREFIX)/bin/predastore-keygen'
	install -D -m 0644 $(SYSTEMD_SRC)/predastore.service '$(DESTDIR)$(UNITDIR)/predastore.service'
	install -D -m 0644 $(SYSTEMD_SRC)/predastore.sysusers.conf '$(DESTDIR)$(SYSUSERSDIR)/predastore.conf'
	install -D -m 0644 $(SYSTEMD_SRC)/predastore.tmpfiles.conf '$(DESTDIR)$(TMPFILESDIR)/predastore.conf'
	install -D -m 0644 $(SYSTEMD_SRC)/99-predastore-net.conf '$(DESTDIR)$(SYSCTLDIR)/99-predastore-net.conf'
# Both land as examples. Installing them as the live config would clobber an
# operator's credentials and topology on every upgrade, and the unit carries
# in-unit defaults so a host with neither file still starts.
	install -D -m 0644 $(SYSTEMD_SRC)/predastore.toml.example '$(DESTDIR)$(SYSCONFDIR)/predastore/predastore.toml.example'
	install -D -m 0644 $(SYSTEMD_SRC)/predastore.env '$(DESTDIR)$(SYSCONFDIR)/predastore/predastore.env.example'
# Modes only, no owner: the predastore account does not exist during a package
# build. systemd-sysusers creates it and systemd-tmpfiles takes the ownership.
	install -d -m 0750 '$(DESTDIR)$(SYSCONFDIR)/predastore'
	install -d -m 0700 '$(DESTDIR)/var/lib/predastore'
	@echo -e "\n ✅ Installed. To activate:"
	@echo "      systemd-sysusers && systemd-tmpfiles --create"
	@echo "      sysctl --system                                 # required for multi-host"
	@echo "      cp $(SYSCONFDIR)/predastore/predastore.toml.example $(SYSCONFDIR)/predastore/predastore.toml"
	@echo "      \$$EDITOR $(SYSCONFDIR)/predastore/predastore.toml   # replace every CHANGEME"
	@echo "      $(PREFIX)/bin/predastore-keygen $(SYSCONFDIR)/predastore"
	@echo "      systemctl daemon-reload && systemctl enable --now predastore"

# Preflight — runs the same checks as GitHub Actions (lint + security + tests).
# Use this before committing to catch CI failures locally.
preflight:
	@$(MAKE) --no-print-directory QUIET=1 lint govulncheck test-cover diff-coverage test-integration
	@echo -e "\n ✅ Preflight passed — safe to commit."

# Run unit tests
test:
	@echo -e "\n....Running tests for $(GO_PROJECT_NAME)...."
	LOG_IGNORE=1 go test -timeout 120s ./...

# Run unit tests with coverage profile
COVERPROFILE ?= coverage.out
test-cover:
	@echo -e "\n....Running tests with coverage for $(GO_PROJECT_NAME)...."
	$(_Q)LOG_IGNORE=1 go test -timeout 120s -coverprofile=$(COVERPROFILE) -covermode=atomic ./... $(_COVQ)
	@scripts/check-coverage.sh $(COVERPROFILE) $(QUIET)

# Run unit tests with race detector
test-race:
	@echo -e "\n....Running tests with race detector for $(GO_PROJECT_NAME)...."
	$(_Q)LOG_IGNORE=1 go test -race -timeout 300s ./... $(_RACEQ)

# Run tests behind the 'integration' build tag, for suites that bind real
# network ports. No file carries the tag at present, so this currently runs
# the same set as `test`. certs is a prerequisite: tagged suites serve TLS,
# and certs/ is gitignored, so a fresh worktree has none.
test-integration: certs
	@echo -e "\n....Running integration tests for $(GO_PROJECT_NAME)...."
	$(_Q)LOG_IGNORE=1 go test -tags=integration -timeout 300s ./... $(_RACEQ)

# Check that new/changed code meets coverage threshold (runs tests first)
diff-coverage: test-cover
	@QUIET=$(QUIET) scripts/diff-coverage.sh $(COVERPROFILE)

clean:
	rm -f ./bin/s3d

lint:
	golangci-lint run ./...

fix:
	golangci-lint run --fix ./...

govulncheck:
	go tool govulncheck ./...

# Warp is pinned so a before/after comparison is not measuring a client change.
TOOLS_DIR    := $(CURDIR)/bin/tools
WARP_VERSION ?= v1.1.4
WARP         ?= $(TOOLS_DIR)/warp

warp-install:
	@if [ ! -x "$(WARP)" ]; then \
		echo -e "\n....Installing warp $(WARP_VERSION)"; \
		mkdir -p "$(TOOLS_DIR)"; \
		GOBIN="$(TOOLS_DIR)" go install github.com/minio/warp@$(WARP_VERSION); \
	fi

# Local, self-contained correctness and performance run. The default smoke
# preset records every request for 30 seconds per workload; PERF_PRESET=compare
# uses two-minute samples for before/after decisions.
PERF_PRESET  ?= smoke
PERF_CONFIGS ?= 1host 3host
e2e-performance: build certs warp-install
	@PERF_PRESET="$(PERF_PRESET)" PERF_CONFIGS="$(PERF_CONFIGS)" WARP="$(WARP)" \
		WARP_VERSION="$(WARP_VERSION)" \
		./scripts/bench/e2e-performance.sh

# Usage: make e2e-performance-compare PERF_BEFORE=/path/to/before PERF_AFTER=/path/to/after
e2e-performance-compare: warp-install
	@test -n "$(PERF_BEFORE)" || { echo "PERF_BEFORE is required" >&2; exit 2; }
	@test -n "$(PERF_AFTER)" || { echo "PERF_AFTER is required" >&2; exit 2; }
	@WARP="$(WARP)" ./scripts/bench/compare-performance.sh "$(PERF_BEFORE)" "$(PERF_AFTER)"

# Fault injection on a four-host cluster. Thirteen scenarios, all run by
# default, and none is a benchmark: the run is mostly deliberate waiting, so it
# takes about the same wall clock regardless of how fast the machine is.
#
# They cover shard repair and handoff, the three node re-entry paths, object
# size and timestamp semantics, concurrent and torn overwrites, stale shards, a
# frozen host under load, multipart upload, and a client that stops sending
# mid-body. STRESS_HOST=leader freezes whichever host raft elected instead,
# which still fails: a gate keeps the frozen node first in its meta read order
# and pays the full client timeout per key, so listing slows in proportion to
# the number of objects.
#
# STRESS_SCENARIO narrows a run to one of them.
STRESS_CONFIG   ?= 4host
STRESS_FREEZE   ?= 90
STRESS_HOST     ?= follower
STRESS_SCENARIO ?=
e2e-stress: build certs warp-install
	@STRESS_CONFIG="$(STRESS_CONFIG)" STRESS_FREEZE="$(STRESS_FREEZE)" \
		STRESS_HOST="$(STRESS_HOST)" STRESS_SCENARIO="$(STRESS_SCENARIO)" \
		WARP="$(WARP)" \
		./scripts/bench/e2e-stress.sh

# CI gates on a regression against scripts/stress-baseline.txt rather than on a
# clean run, so a branch is not red for a gap it did not introduce.
# STRESS_SCENARIOS narrows it: `make e2e-stress-gate STRESS_SCENARIOS=freeze`.
STRESS_BASELINE  ?= scripts/stress-baseline.txt
STRESS_SCENARIOS ?=
e2e-stress-gate: build certs warp-install
	@STRESS_CONFIG="$(STRESS_CONFIG)" STRESS_FREEZE="$(STRESS_FREEZE)" \
		STRESS_HOST="$(STRESS_HOST)" STRESS_BASELINE="$(STRESS_BASELINE)" \
		WARP="$(WARP)" \
		./scripts/bench/stress-gate.sh $(STRESS_SCENARIOS)

# Fails on any failing scenario, which is what CI runs. The baseline records
# every scenario green, so this and the gate above currently agree.
e2e-stress-strict: build certs warp-install
	@STRESS_CONFIG="$(STRESS_CONFIG)" STRESS_FREEZE="$(STRESS_FREEZE)" \
		STRESS_HOST="$(STRESS_HOST)" STRESS_BASELINE="$(STRESS_BASELINE)" \
		STRESS_STRICT=1 WARP="$(WARP)" \
		./scripts/bench/stress-gate.sh $(STRESS_SCENARIOS)

# Re-record the baseline. Run it when a fix lands, in the same change.
e2e-stress-baseline: build certs warp-install
	@STRESS_CONFIG="$(STRESS_CONFIG)" STRESS_FREEZE="$(STRESS_FREEZE)" \
		STRESS_HOST="$(STRESS_HOST)" STRESS_WRITE_BASELINE="$(STRESS_BASELINE)" \
		WARP="$(WARP)" \
		./scripts/bench/stress-gate.sh $(STRESS_SCENARIOS)

# NilAway — advisory nil-panic analysis. Not in preflight: it has a known
# false-positive rate, so findings are triaged by hand rather than gating commits.
nilaway:
	go tool nilaway -include-pkgs=github.com/mulgadc/predastore -exclude-test-files ./...

.PHONY: certs build go_build install preflight test test-cover test-race test-integration diff-coverage \
	clean lint fix govulncheck nilaway warp-install e2e-performance e2e-performance-compare \
	e2e-stress e2e-stress-gate e2e-stress-strict e2e-stress-baseline \
	docker-build docker-smoke docker-smoke-strict docker-smoke-baseline \
	s3-tests s3-tests-strict s3-tests-baseline \
	compose-up compose-down