Files
abrown38andClaude Opus 5.5 3c0808591f Steward 0.1.0 (in development): a DHCPv4 server with a web UI, API and CLI
Subnets served per interface, pools, reservations, options at three
levels, leases in SQLite saved before the ACK, ping and decline conflict
checks, validated changes with history and undo, users and tokens, an
audit log, a Kea importer, a sandboxed systemd unit and Debian packages.
Tested with real udhcpc and dhcpcd clients in Docker (scripts/e2e.sh).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:14:07 +01:00

146 lines
7.1 KiB
Makefile

# Steward build and install.
#
# make build bin/stewardd and bin/steward (and their bash completion)
# make test vet, gofmt check and unit tests
# make e2e end-to-end test with real DHCP clients in Docker (scripts/e2e.sh)
# sudo make install install binaries, bash completion, systemd units,
# sysusers/tmpfiles files and an example /etc/steward/steward.yaml
# make deb Debian packages in dist/ (DEB_ARCH=arm64 for another
# architecture): steward (the server) and steward-cli (the CLI,
# which steward depends on); 'sudo apt install ./dist/steward*_amd64.deb'
# make dist static binaries for linux/amd64 and linux/arm64 in dist/
# make cli-dist the CLI alone for Linux, macOS and Windows in dist/
# (steward-cli-<version>-<os>-<arch>[.exe])
VERSION ?= $(shell cat VERSION 2>/dev/null || echo 0.0.0-dev)
# RELEASE_TAG marks a build of a release (the web UI then shows and links
# the release rather than the commit): set when HEAD is tagged v$(VERSION)
# and no tracked file is changed.
RELEASE_TAG ?= $(shell t=v$(VERSION); git tag --points-at HEAD 2>/dev/null | grep -qx "$$t" && git diff --quiet HEAD 2>/dev/null && echo $$t)
# DESCRIBE places other builds relative to the last tag ("3 commits after
# v0.2.0-rc.1").
DESCRIBE ?= $(shell git describe --tags --long --match 'v[0-9]*' --abbrev=12 HEAD 2>/dev/null)
LDFLAGS := -s -w -X steward/internal/version.Version=$(VERSION) -X steward/internal/version.Tag=$(RELEASE_TAG) \
-X steward/internal/version.Describe=$(DESCRIBE)
GOFLAGS := -trimpath
export CGO_ENABLED := 0
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
DOCDIR ?= $(PREFIX)/share/doc/steward
# bash-completion also looks in /usr/local/share (XDG_DATA_DIRS).
BASHCOMPDIR ?= $(PREFIX)/share/bash-completion/completions
UNITDIR ?= /etc/systemd/system
SYSUSERSDIR ?= /usr/lib/sysusers.d
TMPFILESDIR ?= /usr/lib/tmpfiles.d
DESTDIR ?=
# The binaries install-files copies (make deb points these at other
# architectures' builds).
STEWARDD_BIN ?= bin/stewardd
STEWARD_BIN ?= bin/steward
# make deb: the package's architecture (Debian name) and version. A
# release is VERSION with ~ for - (0.2.0-rc.1 -> 0.2.0~rc.1, which apt
# sorts before 0.2.0). A development build is versioned after the last
# tag: 3 commits past v0.2.0-rc.1 is 0.2.0~rc.1+git3.gca0f148, which apt
# sorts after that RC and before 0.2.0, so installing it upgrades without
# --reinstall. Uncommitted changes add the build time (.m20261009153000),
# so each such build is newer than the last.
DEB_ARCH ?= $(shell dpkg --print-architecture 2>/dev/null || go env GOARCH)
DEB_DEV_VERSION := $(shell [ -n '$(DESCRIBE)' ] || exit 0; \
m=; git diff --quiet HEAD 2>/dev/null || m=.m$$(date -u +%Y%m%d%H%M%S); \
echo '$(DESCRIBE)' | sed -E 's/^v(.*)-([0-9]+)-g([0-9a-f]{7})[0-9a-f]*$$/\1+git\2.g\3/' | tr - '~' | sed "s/$$/$$m/")
DEB_VERSION ?= $(if $(RELEASE_TAG),$(subst -,~,$(VERSION)),$(or $(DEB_DEV_VERSION),$(subst -,~,$(VERSION))))
.PHONY: all build completion test vet e2e install install-files uninstall deb dist cli-dist clean
all: build
build:
go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o bin/stewardd ./cmd/stewardd
go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o bin/steward ./cmd/steward
$(MAKE) --no-print-directory completion
# Bash completion scripts, generated by the binaries themselves.
completion:
@mkdir -p bin/completion
bin/steward completion bash > bin/completion/steward
bin/stewardd completion bash > bin/completion/stewardd
vet:
go vet ./...
@test -z "$$(gofmt -l cmd internal)" || { echo "gofmt needed:"; gofmt -l cmd internal; exit 1; }
test: vet
go test ./...
e2e:
scripts/e2e.sh
install: build install-files
@if [ ! -e $(DESTDIR)/etc/steward/steward.yaml ]; then \
install -d -m 0750 $(DESTDIR)/etc/steward; \
bin/stewardd config --example > $(DESTDIR)/etc/steward/steward.yaml; \
chmod 0640 $(DESTDIR)/etc/steward/steward.yaml; \
echo "wrote $(DESTDIR)/etc/steward/steward.yaml"; \
fi
@echo
@echo "Next (as root): systemd-sysusers steward.conf && systemd-tmpfiles --create steward.conf"
@echo " chgrp steward /etc/steward /etc/steward/steward.yaml && systemctl daemon-reload"
@echo "Then follow docs/install.md (init, start, add subnets or import Kea), and turn on the daily"
@echo "database backup: systemctl enable --now steward-backup.timer"
# Everything but /etc/steward/steward.yaml (shared by install and deb).
install-files:
install -D -m 0755 $(STEWARDD_BIN) $(DESTDIR)$(BINDIR)/stewardd
install -D -m 0755 $(STEWARD_BIN) $(DESTDIR)$(BINDIR)/steward
install -D -m 0644 bin/completion/steward $(DESTDIR)$(BASHCOMPDIR)/steward
install -D -m 0644 bin/completion/stewardd $(DESTDIR)$(BASHCOMPDIR)/stewardd
for u in steward.service steward-backup.service steward-backup.timer; do \
install -D -m 0644 deploy/systemd/$$u $(DESTDIR)$(UNITDIR)/$$u && \
sed -i 's#/usr/local/bin/stewardd#$(BINDIR)/stewardd#; s#/usr/local/share/doc/steward#$(DOCDIR)#' $(DESTDIR)$(UNITDIR)/$$u || exit 1; \
done
install -D -m 0644 deploy/sysusers.d/steward.conf $(DESTDIR)$(SYSUSERSDIR)/steward.conf
install -D -m 0644 deploy/tmpfiles.d/steward.conf $(DESTDIR)$(TMPFILESDIR)/steward.conf
install -D -m 0644 README.md $(DESTDIR)$(DOCDIR)/README.md
install -D -m 0644 LICENSE $(DESTDIR)$(DOCDIR)/LICENSE
install -D -m 0644 CHANGELOG.md $(DESTDIR)$(DOCDIR)/CHANGELOG.md
install -d $(DESTDIR)$(DOCDIR)/docs
install -m 0644 docs/*.md $(DESTDIR)$(DOCDIR)/docs/
uninstall:
rm -f $(DESTDIR)$(BINDIR)/stewardd $(DESTDIR)$(BINDIR)/steward $(DESTDIR)$(UNITDIR)/steward.service \
$(DESTDIR)$(UNITDIR)/stewardd.service \
$(DESTDIR)$(UNITDIR)/steward-backup.service $(DESTDIR)$(UNITDIR)/steward-backup.timer \
$(DESTDIR)$(BASHCOMPDIR)/steward $(DESTDIR)$(BASHCOMPDIR)/stewardd \
$(DESTDIR)$(SYSUSERSDIR)/steward.conf $(DESTDIR)$(TMPFILESDIR)/steward.conf
rm -rf $(DESTDIR)$(DOCDIR)
@echo "Kept /etc/steward, /var/lib/steward and /var/backups/steward."
# A Debian package, built with dpkg-deb (no root needed). The package's
# scripts are in deploy/debian; scripts/mkdeb.sh explains the layout.
deb: build
DEB_ARCH='$(DEB_ARCH)' DEB_VERSION='$(DEB_VERSION)' VERSION='$(VERSION)' \
LDFLAGS='$(LDFLAGS)' GOFLAGS='$(GOFLAGS)' scripts/mkdeb.sh
dist: build
for arch in amd64 arm64; do \
GOOS=linux GOARCH=$$arch go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o dist/steward-$(VERSION)-linux-$$arch/stewardd ./cmd/stewardd && \
GOOS=linux GOARCH=$$arch go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o dist/steward-$(VERSION)-linux-$$arch/steward ./cmd/steward && \
tar -C dist -czf dist/steward-$(VERSION)-linux-$$arch.tar.gz steward-$(VERSION)-linux-$$arch || exit 1; \
done
# The platforms cli-dist builds the CLI for.
CLI_PLATFORMS ?= linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64 windows/arm64
cli-dist:
@mkdir -p dist
for p in $(CLI_PLATFORMS); do \
os=$${p%/*} arch=$${p#*/} ext=; [ $$os = windows ] && ext=.exe; \
GOOS=$$os GOARCH=$$arch go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o dist/steward-cli-$(VERSION)-$$os-$$arch$$ext ./cmd/steward || exit 1; \
done
clean:
rm -rf bin dist