Compare commits

..

1 Commits

Author SHA1 Message Date
Christian Schwarz 207c943fc6 build: hard-code zrepl v0.6.1 package release 2 2023-10-07 18:46:52 +00:00
392 changed files with 3770 additions and 2258 deletions
+45 -48
View File
@@ -1,8 +1,8 @@
version: 2.1 version: 2.1
orbs: orbs:
# NB: this is not the Go version, but the Orb version # NB: 1.7.2 is not the Go version, but the Orb version
# https://circleci.com/developer/orbs/orb/circleci/go#usage-go-modules-cache # https://circleci.com/developer/orbs/orb/circleci/go#usage-go-modules-cache
go: circleci/go@1.11.0 go: circleci/go@1.7.2
commands: commands:
setup-home-local-bin: setup-home-local-bin:
steps: steps:
@@ -15,6 +15,16 @@ commands:
echo "$line" >> $BASH_ENV echo "$line" >> $BASH_ENV
fi fi
invoke-lazy-sh:
parameters:
subcommand:
type: string
steps:
- run:
environment:
TERM: xterm
command: ./lazy.sh <<parameters.subcommand>>
apt-update-and-install-common-deps: apt-update-and-install-common-deps:
steps: steps:
- run: sudo apt-get update - run: sudo apt-get update
@@ -24,12 +34,18 @@ commands:
# The need for this was required for cimg/go:1.12, but let's future proof this here and now. # The need for this was required for cimg/go:1.12, but let's future proof this here and now.
- run: sudo apt-get install -y git ca-certificates - run: sudo apt-get install -y git ca-certificates
install-godep:
steps:
- apt-update-and-install-common-deps
- invoke-lazy-sh:
subcommand: godep
install-docdep: install-docdep:
steps: steps:
- apt-update-and-install-common-deps - apt-update-and-install-common-deps
- run: sudo apt install python3 python3-pip libgirepository1.0-dev - run: sudo apt install python3 python3-pip libgirepository1.0-dev
- run: pip3 install -r docs/requirements.txt - invoke-lazy-sh:
subcommand: docdep
docs-publish-sh: docs-publish-sh:
parameters: parameters:
@@ -42,13 +58,6 @@ commands:
git config --global user.email "zreplbot@cschwarz.com" git config --global user.email "zreplbot@cschwarz.com"
git config --global user.name "zrepl-github-io-ci" git config --global user.name "zrepl-github-io-ci"
# if we're pushing, we need to add the deploy key
# which is stored as "Additional SSH Keys" in the CircleCI project settings.
# We can't use the CircleCI-manage deploy key because we're pushing
# to a different repo than the one we're building.
- when:
condition: << parameters.push >>
steps:
# https://circleci.com/docs/2.0/add-ssh-key/#adding-multiple-keys-with-blank-hostnames # https://circleci.com/docs/2.0/add-ssh-key/#adding-multiple-keys-with-blank-hostnames
- run: ssh-add -D - run: ssh-add -D
# the default circleci ssh config only additional ssh keys for Host !github.com # the default circleci ssh config only additional ssh keys for Host !github.com
@@ -83,6 +92,10 @@ parameters:
type: boolean type: boolean
default: false default: false
release_docker_baseimage_tag:
type: string
default: "1.21"
workflows: workflows:
version: 2 version: 2
@@ -90,20 +103,20 @@ workflows:
when: << pipeline.parameters.do_ci >> when: << pipeline.parameters.do_ci >>
jobs: jobs:
- quickcheck-docs - quickcheck-docs
- quickcheck-go: - quickcheck-go: &quickcheck-go-smoketest
name: quickcheck-go-amd64-linux-1.23.1 name: quickcheck-go-amd64-linux-1.21
goversion: &latest-go-release "1.23.1" goversion: &latest-go-release "1.21"
goos: linux goos: linux
goarch: amd64 goarch: amd64
- test-go: - test-go-on-latest-go-release:
goversion: *latest-go-release goversion: *latest-go-release
- quickcheck-go: - quickcheck-go:
requires: requires:
- quickcheck-go-amd64-linux-1.23.1 #quickcheck-go-smoketest.name - quickcheck-go-amd64-linux-1.21 #quickcheck-go-smoketest.name
matrix: matrix: &quickcheck-go-matrix
alias: quickcheck-go-matrix alias: quickcheck-go-matrix
parameters: parameters:
goversion: [*latest-go-release, "1.22.7"] goversion: [*latest-go-release, "1.20"]
goos: ["linux", "freebsd"] goos: ["linux", "freebsd"]
goarch: ["amd64", "arm64"] goarch: ["amd64", "arm64"]
exclude: exclude:
@@ -118,7 +131,6 @@ workflows:
goos: ["linux"] goos: ["linux"]
goarch: ["amd64"] goarch: ["amd64"]
requires: requires:
- test-go
- quickcheck-go-<< matrix.goarch >>-<< matrix.goos >>-<< matrix.goversion >> - quickcheck-go-<< matrix.goarch >>-<< matrix.goos >>-<< matrix.goversion >>
release: release:
@@ -148,7 +160,7 @@ workflows:
jobs: jobs:
quickcheck-docs: quickcheck-docs:
docker: docker:
- image: cimg/base:2024.09 - image: cimg/base:2023.09
steps: steps:
- checkout - checkout
- install-docdep - install-docdep
@@ -167,41 +179,29 @@ jobs:
goarch: goarch:
type: string type: string
docker: docker:
# any toolchain >= 1.22 will auto-download GOTOOLCHAIN - image: cimg/go:<<parameters.goversion>>
- image: &cimg_with_modern_go cimg/go:1.22
environment: environment:
GOOS: <<parameters.goos>> GOOS: <<parameters.goos>>
GOARCH: <<parameters.goarch>> GOARCH: <<parameters.goarch>>
GOTOOLCHAIN: "go<<parameters.goversion>>"
steps: steps:
- checkout - checkout
- go/load-cache: - go/load-cache:
key: quickcheck-<<parameters.goversion>> key: quickcheck-<<parameters.goversion>>
- run: make build/install - install-godep
- run: go mod download - run: go mod download
- run: cd build && go mod download - run: cd build && go mod download
- go/save-cache: - go/save-cache:
key: quickcheck-<<parameters.goversion>> key: quickcheck-<<parameters.goversion>>
# ensure all code has been generated - run: make formatcheck
- run: make generate - run: make generate-platform-test-list
- run: |
if output=$(git status --porcelain) && [ -z "$output" ]; then
echo "Working directory clean"
else
echo "Uncommitted changes"
echo ""
echo "$output"
exit 1
fi
# other checks
- run: make zrepl-bin test-platform-bin - run: make zrepl-bin test-platform-bin
- run: make vet - run: make vet
- run: make lint - run: make lint
- run: rm -f artifacts/generate-platform-test-list
- store_artifacts: - store_artifacts:
path: artifacts path: artifacts
- persist_to_workspace: - persist_to_workspace:
@@ -230,14 +230,12 @@ jobs:
- run: sudo zfs version - run: sudo zfs version
- run: sudo make test-platform GOOS="$GOOS" GOARCH="$GOARCH" - run: sudo make test-platform GOOS="$GOOS" GOARCH="$GOARCH"
test-go: test-go-on-latest-go-release:
parameters: parameters:
goversion: goversion:
type: string type: string
docker: docker:
- image: *cimg_with_modern_go - image: cimg/go:<<parameters.goversion>>
environment:
GOTOOLCHAIN: "go<<parameters.goversion>>"
steps: steps:
- checkout - checkout
- go/load-cache: - go/load-cache:
@@ -248,17 +246,16 @@ jobs:
release-build: release-build:
machine: machine:
image: &release-vm-image "ubuntu-2404:current" image: ubuntu-2004:202201-02
resource_class: large
steps: steps:
- checkout - checkout
- run: make release-docker - run: make release-docker RELEASE_DOCKER_BASEIMAGE_TAG=<<pipeline.parameters.release_docker_baseimage_tag>>
- persist_to_workspace: - persist_to_workspace:
root: . root: .
paths: [.] paths: [.]
release-deb: release-deb:
machine: machine:
image: *release-vm-image image: ubuntu-2004:202201-02
steps: steps:
- attach_workspace: - attach_workspace:
at: . at: .
@@ -270,7 +267,7 @@ jobs:
release-rpm: release-rpm:
machine: machine:
image: *release-vm-image image: ubuntu-2004:202201-02
steps: steps:
- attach_workspace: - attach_workspace:
at: . at: .
@@ -282,17 +279,17 @@ jobs:
release-upload: release-upload:
docker: docker:
- image: cimg/base:2024.09 - image: cimg/base:2020.08
steps: steps:
- attach_workspace: - attach_workspace:
at: . at: .
- run: make wrapup-and-checksum - run: make wrapup-and-checksum
- store_artifacts: - store_artifacts:
path: artifacts/release path: artifacts
publish-zrepl-github-io: publish-zrepl-github-io:
docker: docker:
- image: cimg/base:2024.09 - image: cimg/base:2023.09
steps: steps:
- checkout - checkout
- install-docdep - install-docdep
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
COMMIT="$1"
GO_VERSION="$2"
curl -v -X POST https://api.github.com/repos/zrepl/debian-binary-packaging/dispatches \
-H 'Accept: application/vnd.github.v3+json' \
-H "Authorization: token $GITHUB_ACCESS_TOKEN" \
--data '{"event_type": "push", "client_payload": { "zrepl_main_repo_commit": "'"$COMMIT"'", "go_version": "'"$GO_VERSION"'" }}'
-9
View File
@@ -1,9 +0,0 @@
version: 2
updates:
# Docs use Python only for static site generation.
- package-ecosystem: "pip"
directory: /docs
schedule:
interval: "weekly"
ignore:
- dependency-name: "*"
-8
View File
@@ -1,14 +1,6 @@
linters: linters:
enable: enable:
- goimports - goimports
- revive
linters-settings:
goimports:
local-prefixes: github.com/zrepl/zrepl
revive:
rules:
- name: time-equal
issues: issues:
exclude-rules: exclude-rules:
+43 -74
View File
@@ -4,17 +4,8 @@
ARTIFACTDIR := artifacts ARTIFACTDIR := artifacts
ifdef ZREPL_VERSION _ZREPL_VERSION := v0.6.1
_ZREPL_VERSION := $(ZREPL_VERSION) ZREPL_PACKAGE_RELEASE := 2
endif
ifndef _ZREPL_VERSION
_ZREPL_VERSION := $(shell git describe --always --dirty 2>/dev/null || echo "ZREPL_BUILD_INVALID_VERSION" )
ifeq ($(_ZREPL_VERSION),ZREPL_BUILD_INVALID_VERSION) # can't use .SHELLSTATUS because Debian Stretch is still on gmake 4.1
$(error cannot infer variable ZREPL_VERSION using git and variable is not overriden by make invocation)
endif
endif
ZREPL_PACKAGE_RELEASE := 1
GO := go GO := go
GOOS ?= $(shell bash -c 'source <($(GO) env) && echo "$$GOOS"') GOOS ?= $(shell bash -c 'source <($(GO) env) && echo "$$GOOS"')
@@ -22,17 +13,16 @@ GOARCH ?= $(shell bash -c 'source <($(GO) env) && echo "$$GOARCH"')
GOARM ?= $(shell bash -c 'source <($(GO) env) && echo "$$GOARM"') GOARM ?= $(shell bash -c 'source <($(GO) env) && echo "$$GOARM"')
GOHOSTOS ?= $(shell bash -c 'source <($(GO) env) && echo "$$GOHOSTOS"') GOHOSTOS ?= $(shell bash -c 'source <($(GO) env) && echo "$$GOHOSTOS"')
GOHOSTARCH ?= $(shell bash -c 'source <($(GO) env) && echo "$$GOHOSTARCH"') GOHOSTARCH ?= $(shell bash -c 'source <($(GO) env) && echo "$$GOHOSTARCH"')
GO_ENV_VARS := CGO_ENABLED=0 GO_ENV_VARS := GO111MODULE=on CGO_ENABLED=0
GO_LDFLAGS := "-X github.com/zrepl/zrepl/version.zreplVersion=$(_ZREPL_VERSION)" GO_LDFLAGS := "-X github.com/zrepl/zrepl/version.zreplVersion=$(_ZREPL_VERSION)"
GO_MOD_READONLY := -mod=readonly GO_MOD_READONLY := -mod=readonly
GO_EXTRA_BUILDFLAGS := GO_EXTRA_BUILDFLAGS :=
GO_BUILDFLAGS := $(GO_MOD_READONLY) $(GO_EXTRA_BUILDFLAGS) GO_BUILDFLAGS := $(GO_MOD_READONLY) $(GO_EXTRA_BUILDFLAGS)
GO_BUILD := $(GO_ENV_VARS) $(GO) build $(GO_BUILDFLAGS) -ldflags $(GO_LDFLAGS) GO_BUILD := $(GO_ENV_VARS) $(GO) build $(GO_BUILDFLAGS) -ldflags $(GO_LDFLAGS)
GOLANGCI_LINT := golangci-lint
GOCOVMERGE := gocovmerge GOCOVMERGE := gocovmerge
RELEASE_GOVERSION ?= go1.23.1 RELEASE_DOCKER_BASEIMAGE_TAG ?= 1.21
STRIPPED_GOVERSION := $(subst go,,$(RELEASE_GOVERSION)) RELEASE_DOCKER_BASEIMAGE ?= golang:$(RELEASE_DOCKER_BASEIMAGE_TAG)
RELEASE_DOCKER_BASEIMAGE ?= golang:$(STRIPPED_GOVERSION)
RELEASE_DOCKER_CACHEMOUNT :=
ifneq ($(GOARM),) ifneq ($(GOARM),)
ZREPL_TARGET_TUPLE := $(GOOS)-$(GOARCH)v$(GOARM) ZREPL_TARGET_TUPLE := $(GOOS)-$(GOARCH)v$(GOARM)
@@ -40,46 +30,33 @@ else
ZREPL_TARGET_TUPLE := $(GOOS)-$(GOARCH) ZREPL_TARGET_TUPLE := $(GOOS)-$(GOARCH)
endif endif
.PHONY: printvars
printvars:
@echo GOOS=$(GOOS)
@echo GOARCH=$(GOARCH)
@echo GOARM=$(GOARM)
ifneq ($(RELEASE_DOCKER_CACHEMOUNT),)
_RELEASE_DOCKER_CACHEMOUNT := -v $(RELEASE_DOCKER_CACHEMOUNT)/mod:/go/pkg/mod -v $(RELEASE_DOCKER_CACHEMOUNT)/xdg-cache:/root/.cache/go-build
.PHONY: release-docker-mkcachemount
release-docker-mkcachemount:
mkdir -p $(RELEASE_DOCKER_CACHEMOUNT)
mkdir -p $(RELEASE_DOCKER_CACHEMOUNT)/mod
mkdir -p $(RELEASE_DOCKER_CACHEMOUNT)/xdg-cache
else
_RELEASE_DOCKER_CACHEMOUNT :=
.PHONY: release-docker-mkcachemount
release-docker-mkcachemount:
# nothing to do
endif
##################### PRODUCING A RELEASE ############# ##################### PRODUCING A RELEASE #############
.PHONY: release wrapup-and-checksum check-git-clean sign clean ensure-release-toolchain .PHONY: release wrapup-and-checksum check-git-clean sign clean
ensure-release-toolchain: release: clean
# ensure the toolchain is actually the one we expect # no cross-platform support for target test
test $(RELEASE_GOVERSION) = "$$($(GO_ENV_VARS) $(GO) env GOVERSION)" $(MAKE) test-go
release: ensure-release-toolchain
$(MAKE) _run_make_foreach_target_tuple RUN_MAKE_FOREACH_TARGET_TUPLE_ARG="vet" $(MAKE) _run_make_foreach_target_tuple RUN_MAKE_FOREACH_TARGET_TUPLE_ARG="vet"
$(MAKE) _run_make_foreach_target_tuple RUN_MAKE_FOREACH_TARGET_TUPLE_ARG="lint" $(MAKE) _run_make_foreach_target_tuple RUN_MAKE_FOREACH_TARGET_TUPLE_ARG="lint"
$(MAKE) _run_make_foreach_target_tuple RUN_MAKE_FOREACH_TARGET_TUPLE_ARG="zrepl-bin" $(MAKE) _run_make_foreach_target_tuple RUN_MAKE_FOREACH_TARGET_TUPLE_ARG="zrepl-bin"
$(MAKE) _run_make_foreach_target_tuple RUN_MAKE_FOREACH_TARGET_TUPLE_ARG="test-platform-bin" $(MAKE) _run_make_foreach_target_tuple RUN_MAKE_FOREACH_TARGET_TUPLE_ARG="test-platform-bin"
$(MAKE) noarch $(MAKE) noarch
release-docker: $(ARTIFACTDIR) release-docker-mkcachemount release-docker: $(ARTIFACTDIR)
sed 's/FROM.*!SUBSTITUTED_BY_MAKEFILE/FROM $(RELEASE_DOCKER_BASEIMAGE)/' build/build.Dockerfile > $(ARTIFACTDIR)/build.Dockerfile sed 's/FROM.*!SUBSTITUTED_BY_MAKEFILE/FROM $(RELEASE_DOCKER_BASEIMAGE)/' build.Dockerfile > artifacts/release-docker.Dockerfile
docker build -t zrepl_release --pull -f $(ARTIFACTDIR)/build.Dockerfile . docker build -t zrepl_release --pull -f artifacts/release-docker.Dockerfile .
docker run --rm -i \ docker run --rm -i -v $(CURDIR):/src -u $$(id -u):$$(id -g) \
$(_RELEASE_DOCKER_CACHEMOUNT) \
-v $(CURDIR):/src -u $$(id -u):$$(id -g) \
zrepl_release \ zrepl_release \
make release \ make release \
GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \ GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
ZREPL_VERSION=$(ZREPL_VERSION) ZREPL_PACKAGE_RELEASE=$(ZREPL_PACKAGE_RELEASE) \ ZREPL_VERSION=$(ZREPL_VERSION) ZREPL_PACKAGE_RELEASE=$(ZREPL_PACKAGE_RELEASE)
RELEASE_GOVERSION=$(RELEASE_GOVERSION)
debs-docker: debs-docker:
$(MAKE) _debs_or_rpms_docker _DEB_OR_RPM=deb $(MAKE) _debs_or_rpms_docker _DEB_OR_RPM=deb
@@ -176,14 +153,14 @@ wrapup-and-checksum:
tar --mtime='1970-01-01' --sort=name \ tar --mtime='1970-01-01' --sort=name \
--transform 's/$(ARTIFACTDIR)/zrepl-$(_ZREPL_VERSION)-noarch/' \ --transform 's/$(ARTIFACTDIR)/zrepl-$(_ZREPL_VERSION)-noarch/' \
--transform 's#dist#zrepl-$(_ZREPL_VERSION)-noarch/dist#' \ --transform 's#dist#zrepl-$(_ZREPL_VERSION)-noarch/dist#' \
--transform 's#internal/config/samples#zrepl-$(_ZREPL_VERSION)-noarch/config#' \ --transform 's#config/samples#zrepl-$(_ZREPL_VERSION)-noarch/config#' \
-acf $(NOARCH_TARBALL) \ -acf $(NOARCH_TARBALL) \
$(ARTIFACTDIR)/docs/html \ $(ARTIFACTDIR)/docs/html \
$(ARTIFACTDIR)/bash_completion \ $(ARTIFACTDIR)/bash_completion \
$(ARTIFACTDIR)/_zrepl.zsh_completion \ $(ARTIFACTDIR)/_zrepl.zsh_completion \
$(ARTIFACTDIR)/go_env.txt \ $(ARTIFACTDIR)/go_env.txt \
dist \ dist \
internal/config/samples config/samples
rm -rf "$(ARTIFACTDIR)/release" rm -rf "$(ARTIFACTDIR)/release"
mkdir -p "$(ARTIFACTDIR)/release" mkdir -p "$(ARTIFACTDIR)/release"
cp -l $(ARTIFACTDIR)/zrepl* \ cp -l $(ARTIFACTDIR)/zrepl* \
@@ -241,10 +218,10 @@ _run_make_foreach_target_tuple:
$(MAKE) $(RUN_MAKE_FOREACH_TARGET_TUPLE_ARG) GOOS=illumos GOARCH=amd64 $(MAKE) $(RUN_MAKE_FOREACH_TARGET_TUPLE_ARG) GOOS=illumos GOARCH=amd64
##################### REGULAR TARGETS ##################### ##################### REGULAR TARGETS #####################
.PHONY: lint test-go test-platform cover-merge cover-html vet zrepl-bin test-platform-bin .PHONY: lint test-go test-platform cover-merge cover-html vet zrepl-bin test-platform-bin generate-platform-test-list
lint: build/install lint:
$(GO_ENV_VARS) build/install/gobin/golangci-lint run ./... $(GO_ENV_VARS) $(GOLANGCI_LINT) run ./...
vet: vet:
$(GO_ENV_VARS) $(GO) vet $(GO_BUILDFLAGS) ./... $(GO_ENV_VARS) $(GO) vet $(GO_BUILDFLAGS) ./...
@@ -265,6 +242,9 @@ endif
zrepl-bin: zrepl-bin:
$(GO_BUILD) -o "$(ARTIFACTDIR)/zrepl-$(ZREPL_TARGET_TUPLE)" $(GO_BUILD) -o "$(ARTIFACTDIR)/zrepl-$(ZREPL_TARGET_TUPLE)"
generate-platform-test-list:
$(GO_BUILD) -o $(ARTIFACTDIR)/generate-platform-test-list ./platformtest/tests/gen
COVER_PLATFORM_BIN_PATH := $(ARTIFACTDIR)/platformtest-cover-$(ZREPL_TARGET_TUPLE) COVER_PLATFORM_BIN_PATH := $(ARTIFACTDIR)/platformtest-cover-$(ZREPL_TARGET_TUPLE)
cover-platform-bin: cover-platform-bin:
$(GO_ENV_VARS) $(GO) test $(GO_BUILDFLAGS) \ $(GO_ENV_VARS) $(GO) test $(GO_BUILDFLAGS) \
@@ -281,7 +261,7 @@ cover-platform:
TEST_PLATFORM_BIN_PATH := $(ARTIFACTDIR)/platformtest-$(ZREPL_TARGET_TUPLE) TEST_PLATFORM_BIN_PATH := $(ARTIFACTDIR)/platformtest-$(ZREPL_TARGET_TUPLE)
test-platform-bin: test-platform-bin:
$(GO_BUILD) -o "$(TEST_PLATFORM_BIN_PATH)" ./internal/platformtest/harness $(GO_BUILD) -o "$(TEST_PLATFORM_BIN_PATH)" ./platformtest/harness
test-platform: test-platform:
export _TEST_PLATFORM_CMD="\"$(TEST_PLATFORM_BIN_PATH)\""; \ export _TEST_PLATFORM_CMD="\"$(TEST_PLATFORM_BIN_PATH)\""; \
$(MAKE) _test-or-cover-platform-impl $(MAKE) _test-or-cover-platform-impl
@@ -298,7 +278,7 @@ ifndef _TEST_PLATFORM_CMD
endif endif
rm -f "$(ZREPL_PLATFORMTEST_ZFS_LOG)" rm -f "$(ZREPL_PLATFORMTEST_ZFS_LOG)"
rm -f "$(ARTIFACTDIR)/platformtest.cover" rm -f "$(ARTIFACTDIR)/platformtest.cover"
internal/platformtest/logmockzfs/logzfsenv "$(ZREPL_PLATFORMTEST_ZFS_LOG)" `which zfs` \ platformtest/logmockzfs/logzfsenv "$(ZREPL_PLATFORMTEST_ZFS_LOG)" `which zfs` \
$(_TEST_PLATFORM_CMD) \ $(_TEST_PLATFORM_CMD) \
-poolname "$(ZREPL_PLATFORMTEST_POOLNAME)" \ -poolname "$(ZREPL_PLATFORMTEST_POOLNAME)" \
-imagepath "$(ZREPL_PLATFORMTEST_IMAGEPATH)" \ -imagepath "$(ZREPL_PLATFORMTEST_IMAGEPATH)" \
@@ -320,34 +300,23 @@ cover-full:
##################### DEV TARGETS ##################### ##################### DEV TARGETS #####################
# not part of the build, must do that manually # not part of the build, must do that manually
.PHONY: generate format .PHONY: generate formatcheck format
build/install: generate: generate-platform-test-list
rm -rf build/install.tmp protoc -I=replication/logic/pdu --go_out=replication/logic/pdu --go-grpc_out=replication/logic/pdu replication/logic/pdu/pdu.proto
mkdir build/install.tmp protoc -I=rpc/grpcclientidentity/example --go_out=rpc/grpcclientidentity/example/pdu --go-grpc_out=rpc/grpcclientidentity/example/pdu rpc/grpcclientidentity/example/grpcauth.proto
$(GO_ENV_VARS) $(GO) generate $(GO_BUILDFLAGS) -x ./...
-echo "installing protoc"
mkdir build/install.tmp/protoc
bash -x build/get_protoc.bash build/install.tmp/protoc
-echo "installing go tools"
build/go_install_tools.bash build/install.tmp/gobin
mv build/install.tmp build/install
generate: build/install
# TODO: would be nice to run with a pure path here
PATH="$(CURDIR)/build/install/gobin:$(CURDIR)/build/install/protoc/bin:$$PATH" && \
build/install/protoc/bin/protoc -I=internal/replication/logic/pdu --go_out=internal/replication/logic/pdu --go-grpc_out=internal/replication/logic/pdu internal/replication/logic/pdu/pdu.proto && \
build/install/protoc/bin/protoc -I=internal/rpc/grpcclientidentity/example --go_out=internal/rpc/grpcclientidentity/example/pdu --go-grpc_out=internal/rpc/grpcclientidentity/example/pdu internal/rpc/grpcclientidentity/example/grpcauth.proto && \
$(GO) generate $(GO_BUILDFLAGS) -x ./... && \
true
GOIMPORTS := goimports -srcdir . -local 'github.com/zrepl/zrepl' GOIMPORTS := goimports -srcdir . -local 'github.com/zrepl/zrepl'
FINDSRCFILES := find . -type f -name '*.go' -not -path "./vendor/*" -not -name '*.pb.go' -not -name '*_enumer.go'
format: build/install formatcheck:
@ build/install/gobin/goimports -w -local 'github.com/zrepl/zrepl' $$(find . -type f -name '*.go' -not -path "./vendor/*" -not -name '*.pb.go' -not -name '*_enumer.go') @# goimports doesn't have a knob to exit with non-zero status code if formatting is needed
@# see https://go-review.googlesource.com/c/tools/+/237378
@ affectedfiles=$$($(GOIMPORTS) -l $(shell $(FINDSRCFILES)) | tee /dev/stderr | wc -l); test "$$affectedfiles" = 0
format:
@ $(GOIMPORTS) -w -d $(shell $(FINDSRCFILES))
##################### NOARCH ##################### ##################### NOARCH #####################
.PHONY: noarch $(ARTIFACTDIR)/bash_completion $(ARTIFACTDIR)/_zrepl.zsh_completion $(ARTIFACTDIR)/go_env.txt docs docs-clean .PHONY: noarch $(ARTIFACTDIR)/bash_completion $(ARTIFACTDIR)/_zrepl.zsh_completion $(ARTIFACTDIR)/go_env.txt docs docs-clean
+58 -61
View File
@@ -26,40 +26,24 @@ zrepl is a one-stop ZFS backup & replication solution.
If so, think of an expressive configuration example. If so, think of an expressive configuration example.
2. Think of at least one use case that generalizes from your concrete application. 2. Think of at least one use case that generalizes from your concrete application.
3. Open an issue on GitHub with example conf & use case attached. 3. Open an issue on GitHub with example conf & use case attached.
4. **Optional**: [Contact Christian Schwarz](https://cschwarz.com) for contract work. 4. **Optional**: [Post a bounty](https://www.bountysource.com/teams/zrepl) on the issue, or [contact Christian Schwarz](https://cschwarz.com) for contract work.
The above does not apply if you already implemented everything. The above does not apply if you already implemented everything.
Check out the *Coding Workflow* section below for details. Check out the *Coding Workflow* section below for details.
## Development ## Building, Releasing, Downstream-Packaging
This section provides an overview of the zrepl build & release process.
Check out `docs/installation/compile-from-source.rst` for build-from-source instructions.
### Overview
zrepl is written in [Go](https://golang.org) and uses [Go modules](https://github.com/golang/go/wiki/Modules) to manage dependencies. zrepl is written in [Go](https://golang.org) and uses [Go modules](https://github.com/golang/go/wiki/Modules) to manage dependencies.
The documentation is written in [ReStructured Text](http://docutils.sourceforge.net/rst.html) using the [Sphinx](https://www.sphinx-doc.org) framework. The documentation is written in [ReStructured Text](http://docutils.sourceforge.net/rst.html) using the [Sphinx](https://www.sphinx-doc.org) framework.
### Building Install **build dependencies** using `./lazy.sh devsetup`.
`lazy.sh` uses `python3-pip` to fetch the build dependencies for the docs - you might want to use a [venv](https://docs.python.org/3/library/venv.html).
#### Go Code If you just want to install the Go dependencies, run `./lazy.sh godep`.
Dependencies:
* Go 1.22 or newer
* GNU Make
* Git
* wget (`make generate`)
* unzip (`make generate`)
Some Go code is **generated**, and generated code is committed to the source tree.
Therefore, building does not require having code generation tools set up.
When making changes that require code to be (re-)generated, run `make generate`.
I downloads and installs pinned versions of the code generation tools into `./build/install`.
There is a CI check that ensures Git state is clean, i.e., code generation has been done by a PR and is deterministic.
#### Docs
Set up a Python environment that has `docs/requirements.txt` installed via `pip`.
Use a [venv](https://docs.python.org/3/library/venv.html) to avoid global state.
### Testing
The **test suite** is split into pure **Go tests** (`make test-go`) and **platform tests** that interact with ZFS and thus generally **require root privileges** (`sudo make test-platform`). The **test suite** is split into pure **Go tests** (`make test-go`) and **platform tests** that interact with ZFS and thus generally **require root privileges** (`sudo make test-platform`).
Platform tests run on their own pool with the name `zreplplatformtest`, which is created using the file vdev in `/tmp`. Platform tests run on their own pool with the name `zreplplatformtest`, which is created using the file vdev in `/tmp`.
@@ -67,28 +51,33 @@ Platform tests run on their own pool with the name `zreplplatformtest`, which is
For a full **code coverage** profile, run `make test-go COVER=1 && sudo make test-platform && make cover-merge`. For a full **code coverage** profile, run `make test-go COVER=1 && sudo make test-platform && make cover-merge`.
An HTML report can be generated using `make cover-html`. An HTML report can be generated using `make cover-html`.
### Circle CI **Code generation** is triggered by `make generate`. Generated code is committed to the source tree.
We use CircleCI for automated build & test pre- and post-merge. ### Build & Release Process
**The `Makefile` is catering to the needs of developers & CI, not distro packagers**.
It provides phony targets for
* local development (building, running tests, etc)
* building a release in Docker (used by the CI & release management)
* building .deb and .rpm packages out of the release artifacts.
**Build tooling & dependencies** are documented as code in `lazy.sh`.
Go dependencies are then fetched by the go command and pip dependencies are pinned through a `requirements.txt`.
**We use CircleCI for continuous integration**.
There are two workflows: There are two workflows:
* `ci` runs for every commit / branch / tag pushed to GitHub. * `ci` runs for every commit / branch / tag pushed to GitHub.
It is supposed to run very fast (<5min and provides quick feedback to developers). It is supposed to run very fast (<5min and provides quick feedback to developers).
It runs formatting checks, lints and tests on the most important OSes / architectures. It runs formatting checks, lints and tests on the most important OSes / architectures.
Artifacts are published to minio.cschwarz.com (see GitHub Commit Status).
* `release` runs * `release` runs
* on manual triggers through the CircleCI API (in order to produce a release) * on manual triggers through the CircleCI API (in order to produce a release)
* periodically on `master` * periodically on `master`
Artifacts are published to minio.cschwarz.com (see GitHub Commit Status).
Artifacts are stored in CircleCI. **Releases** are issued via Git tags + GitHub Releases feature.
### Releasing
All zrepl releases are git-tagged and then published as a GitHub Release.
There is a git tag for each zrepl release, usually `vMAJOR.MINOR.0`.
We don't move git tags once the release has been published.
The procedure to issue a release is as follows: The procedure to issue a release is as follows:
* Issue the source release: * Issue the source release:
* Git tag the release on the `master` branch. * Git tag the release on the `master` branch.
@@ -99,34 +88,14 @@ The procedure to issue a release is as follows:
* Download the artifacts to the release manager's machine. * Download the artifacts to the release manager's machine.
* Create a GitHub release, edit the changelog, upload all the release artifacts, including .rpm and .deb files. * Create a GitHub release, edit the changelog, upload all the release artifacts, including .rpm and .deb files.
* Issue the GitHub release. * Issue the GitHub release.
* Add the .rpm and .deb files to the official zrepl repos. * Add the .rpm and .deb files to the official zrepl repos, publish those.
* Code for management of these repos: https://github.com/zrepl/package-repo-ops (private repo at this time)
#### Patch releases, Go toolchain updates, APT/RPM Package rebuilds **Official binary releases are not re-built when Go receives an update. If the Go update is critical to zrepl (e.g. a Go security update that affects zrepl), we'd issue a new source release**.
The rationale for this is that whereas distros provide a mechanism for this (`$zrepl_source_release-$distro_package_revision`), GitHub Releases doesn't which means we'd need to update the existing GitHub release's assets, which nobody would notice (no RSS feed updates, etc.).
Downstream packagers can read the changelog to determine whether they want to push that minor release into their distro or simply skip it.
`vMAJOR.MINOR.0` is typically a tagged commit on `master`, because development velocity isn't high ### Additional Notes to Distro Package Maintainers
and thus release branches for stabilization aren't necessary.
Occasionally though there is a need for patch changes to a release, e.g.
- security issue in a dependency
- Go toolchain update (e.g. security issue in standard library)
The procedure for this is the following
- create a branch off the release tag we need to patch, named `releases/MAJOR.MINOR.X`
- that branch will never be merged into `master`, it'll be a dead-end for this specific patch
- make changes in that branch
- make the final commit that bumps version numbers
- create the git tag
- follow general procedure for publishing the release (previous sectino
For Go toolchain updates and package rebuilds with no source code changes, leverage the APT/RPM package revision field.
Control via the `ZREPL_PACKAGE_RELEASE` Makefile variable, see `origin/releases/0.6.1-2` for an example.
## Notes to Distro Package Maintainers
* The `Makefile` in this project is not suitable for builds in distros.
* Run the platform tests (Docs -> Usage -> Platform Tests) **on a test system** to validate that zrepl's abstractions on top of ZFS work with the system ZFS. * Run the platform tests (Docs -> Usage -> Platform Tests) **on a test system** to validate that zrepl's abstractions on top of ZFS work with the system ZFS.
* Ship a default config that adheres to your distro's `hier` and logging system. * Ship a default config that adheres to your distro's `hier` and logging system.
* Ship a service manager file and _please_ try to upstream it to this repository. * Ship a service manager file and _please_ try to upstream it to this repository.
@@ -136,3 +105,31 @@ Control via the `ZREPL_PACKAGE_RELEASE` Makefile variable, see `origin/releases/
This is how `zrepl version` knows what version number to show. This is how `zrepl version` knows what version number to show.
Your build system should set the `ldFlags` flags appropriately and add a prefix or suffix that indicates that the given zrepl binary is a distro build, not an official one. Your build system should set the `ldFlags` flags appropriately and add a prefix or suffix that indicates that the given zrepl binary is a distro build, not an official one.
* Make sure you are informed about new zrepl versions, e.g. by subscribing to GitHub's release RSS feed. * Make sure you are informed about new zrepl versions, e.g. by subscribing to GitHub's release RSS feed.
## Contributing Code
* Open an issue when starting to hack on a new feature
* Commits should reference the issue they are related to
* Docs improvements not documenting new features do not require an issue.
### Breaking Changes
Backward-incompatible changes must be documented in the git commit message and are listed in `docs/changelog.rst`.
### Glossary & Naming Inconsistencies
In ZFS, *dataset* refers to the objects *filesystem*, *ZVOL* and *snapshot*. <br />
However, we need a word for *filesystem* & *ZVOL* but not a snapshot, bookmark, etc.
Toward the user, the following terminology is used:
* **filesystem**: a ZFS filesystem or a ZVOL
* **filesystem version**: a ZFS snapshot or a bookmark
Sadly, the zrepl implementation is inconsistent in its use of these words:
variables and types are often named *dataset* when they in fact refer to a *filesystem*.
There will not be a big refactoring (an attempt was made, but it's destroying too much history without much gain).
However, new contributions & patches should fix naming without further notice in the commit message.
+36
View File
@@ -0,0 +1,36 @@
FROM !SUBSTITUTED_BY_MAKEFILE
RUN apt-get update && apt-get install -y \
python3-pip \
python3-venv \
unzip \
gawk
ADD build.installprotoc.bash ./
RUN bash build.installprotoc.bash
# setup venv
ENV VIRTUAL_ENV=/opt/venv
RUN python3 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
ADD lazy.sh /tmp/lazy.sh
ADD docs/requirements.txt /tmp/requirements.txt
ENV ZREPL_LAZY_DOCS_REQPATH=/tmp/requirements.txt
RUN /tmp/lazy.sh docdep
# prepare volume mount of git checkout to /zrepl
RUN mkdir -p /src/github.com/zrepl/zrepl
RUN mkdir -p /.cache && chmod -R 0777 /.cache
# $GOPATH is /go
# Go 1.12 doesn't use modules within GOPATH, but 1.13 and later do
# => store source outside of GOPATH
WORKDIR /src
# Install build tools (e.g. protobuf generator, stringer) into $GOPATH/bin
ADD build/ /tmp/build
RUN /tmp/lazy.sh godep
RUN chmod -R 0777 /go
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -euo pipefail
set -x
MACH=$(uname -m)
MACH="${MACH/aarch64/aarch_64}"
VERSION=3.6.1
FILENAME=protoc-"$VERSION"-linux-"$MACH".zip
if [ -e "$FILENAME" ]; then
echo "$FILENAME" already exists 1>&2
exit 1
fi
wget https://github.com/protocolbuffers/protobuf/releases/download/v"$VERSION"/"$FILENAME"
stat "$FILENAME"
sha256sum -c --ignore-missing <<EOF
6003de742ea3fcf703cfec1cd4a3380fd143081a2eb0e559065563496af27807 protoc-3.6.1-linux-x86_64.zip
af8e5aaaf39ddec62ec8dd2be1b8d9602c6da66564883a16393ade5f71170922 protoc-3.6.1-linux-aarch_64.zip
EOF
unzip -d /usr "$FILENAME"
-1
View File
@@ -1 +0,0 @@
install/
-22
View File
@@ -1,22 +0,0 @@
FROM !SUBSTITUTED_BY_MAKEFILE
RUN apt-get update && apt-get install -y \
python3-pip \
python3-venv \
unzip \
gawk
# setup venv for docs
ENV VIRTUAL_ENV=/opt/venv
RUN python3 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
ADD docs/requirements.txt /tmp/requirements.txt
RUN pip3 install -r /tmp/requirements.txt
# Go toolchain uses xdg-cache
RUN mkdir -p /.cache && chmod -R 0777 /.cache
# Go devtools are managed by Makefile
WORKDIR /src
-27
View File
@@ -1,27 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
set -x
cd "$1"
MACH=$(uname -m)
MACH="${MACH/aarch64/aarch_64}"
VERSION=28.0
FILENAME=protoc-"$VERSION"-linux-"$MACH".zip
if [ -e "$FILENAME" ]; then
echo "$FILENAME" already exists 1>&2
exit 1
fi
wget --continue https://github.com/protocolbuffers/protobuf/releases/download/v"$VERSION"/"$FILENAME"
stat "$FILENAME"
sha256sum -c --ignore-missing <<EOF
d622619dcbfb5ecb281cfb92c1a74d6a0f42e752d9a2774b197f475f7ab1c8c4 protoc-28.0-linux-aarch_64.zip
b2e187c8b9f2d97cd3ecae4926d1bb2cbebe3ab768e7c987cbc86bb17f319358 protoc-28.0-linux-x86_64.zip
EOF
unzip -d . "$FILENAME"
+30 -184
View File
@@ -1,194 +1,40 @@
module github.com/zrepl/zrepl/build module github.com/zrepl/zrepl/build
go 1.22.7 go 1.12
toolchain go1.23.1
require ( require (
github.com/alvaroloes/enumer v1.1.2 github.com/alvaroloes/enumer v1.1.1
github.com/golangci/golangci-lint v1.60.3 github.com/breml/bidichk v0.2.6 // indirect
github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad github.com/breml/errchkjson v0.3.5 // indirect
golang.org/x/tools v0.24.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1
google.golang.org/protobuf v1.34.2
)
require (
4d63.com/gocheckcompilerdirectives v1.2.1 // indirect
4d63.com/gochecknoglobals v0.2.1 // indirect
github.com/4meepo/tagalign v1.3.4 // indirect
github.com/Abirdcfly/dupword v0.1.1 // indirect
github.com/Antonboom/errname v0.1.13 // indirect
github.com/Antonboom/nilnil v0.1.9 // indirect
github.com/Antonboom/testifylint v1.4.3 // indirect
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/Crocmagnon/fatcontext v0.5.2 // indirect
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect
github.com/alecthomas/go-check-sumtype v0.1.4 // indirect
github.com/alexkohler/nakedret/v2 v2.0.4 // indirect
github.com/alexkohler/prealloc v1.0.0 // indirect
github.com/alingse/asasalint v0.0.11 // indirect
github.com/ashanbrown/forbidigo v1.6.0 // indirect
github.com/ashanbrown/makezero v1.1.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bkielbasa/cyclop v1.2.1 // indirect
github.com/blizzy78/varnamelen v0.8.0 // indirect
github.com/bombsimon/wsl/v4 v4.4.1 // indirect
github.com/breml/bidichk v0.2.7 // indirect
github.com/breml/errchkjson v0.3.6 // indirect
github.com/butuzov/ireturn v0.3.0 // indirect
github.com/butuzov/mirror v1.2.0 // indirect
github.com/catenacyber/perfsprint v0.7.1 // indirect
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charithe/durationcheck v0.0.10 // indirect
github.com/chavacava/garif v0.1.0 // indirect github.com/chavacava/garif v0.1.0 // indirect
github.com/ckaznocha/intrange v0.1.2 // indirect github.com/daixiang0/gci v0.11.1 // indirect
github.com/curioswitch/go-reassign v0.2.0 // indirect github.com/golangci/golangci-lint v1.54.2
github.com/daixiang0/gci v0.13.5 // indirect github.com/golangci/revgrep v0.5.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect github.com/jgautheron/goconst v1.6.0 // indirect
github.com/ettle/strcase v0.2.0 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/fatih/color v1.17.0 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/fatih/structtag v1.2.0 // indirect github.com/mgechev/revive v1.3.3 // indirect
github.com/firefart/nonamedreturns v1.0.5 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/polyfloyd/go-errorlint v1.4.5 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect github.com/prometheus/client_golang v1.16.0 // indirect
github.com/ghostiam/protogetter v0.3.6 // indirect github.com/prometheus/common v0.44.0 // indirect
github.com/go-critic/go-critic v0.11.4 // indirect github.com/prometheus/procfs v0.11.1 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect
github.com/go-toolsmith/astcopy v1.1.0 // indirect
github.com/go-toolsmith/astequal v1.2.0 // indirect
github.com/go-toolsmith/astfmt v1.1.0 // indirect
github.com/go-toolsmith/astp v1.1.0 // indirect
github.com/go-toolsmith/strparse v1.1.0 // indirect
github.com/go-toolsmith/typep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.1.0 // indirect
github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 // indirect
github.com/golangci/misspell v0.6.0 // indirect
github.com/golangci/modinfo v0.3.4 // indirect
github.com/golangci/plugin-module-register v0.1.1 // indirect
github.com/golangci/revgrep v0.5.3 // indirect
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/gordonklaus/ineffassign v0.1.0 // indirect
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
github.com/gostaticanalysis/comment v1.4.2 // indirect
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jgautheron/goconst v1.7.1 // indirect
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect
github.com/jjti/go-spancheck v0.6.2 // indirect
github.com/julz/importas v0.1.0 // indirect
github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect
github.com/kisielk/errcheck v1.7.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.5 // indirect
github.com/kulti/thelper v0.6.3 // indirect
github.com/kunwardeep/paralleltest v1.0.10 // indirect
github.com/kyoh86/exportloopref v0.1.11 // indirect
github.com/lasiar/canonicalheader v1.1.1 // indirect
github.com/ldez/gomoddirectives v0.2.4 // indirect
github.com/ldez/tagliatelle v0.5.0 // indirect
github.com/leonklingele/grouper v1.1.2 // indirect
github.com/lufeee/execinquery v1.2.1 // indirect
github.com/macabu/inamedparam v0.1.3 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/maratori/testableexamples v1.0.0 // indirect
github.com/maratori/testpackage v1.1.1 // indirect
github.com/matoous/godox v0.0.0-20240105082147-c5b5e0e7c0c0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mgechev/revive v1.3.9 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moricho/tparallel v0.3.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
github.com/nishanths/exhaustive v0.12.0 // indirect
github.com/nishanths/predeclared v0.2.2 // indirect
github.com/nunnatsa/ginkgolinter v0.16.2 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pascaldekloe/name v1.0.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/polyfloyd/go-errorlint v1.6.0 // indirect
github.com/prometheus/client_golang v1.20.3 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.59.1 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quasilyte/go-ruleguard v0.4.2 // indirect
github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect
github.com/quasilyte/gogrep v0.5.0 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/ryancurrah/gomodguard v1.3.5 // indirect
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/spf13/viper v1.16.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/stretchr/objx v0.5.1 // indirect
github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
github.com/sashamelentyev/usestdlibvars v1.27.0 // indirect
github.com/securego/gosec/v2 v2.21.1 // indirect
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/sivchari/tenv v1.10.0 // indirect
github.com/sonatard/noctx v0.0.2 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/sourcegraph/go-diff v0.7.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/tdakkota/asciicheck v0.2.0 // indirect github.com/tetafro/godot v1.4.15 // indirect
github.com/tetafro/godot v1.4.17 // indirect github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad
github.com/timakin/bodyclose v0.0.0-20240125160201-f835fa56326a // indirect
github.com/timonwong/loggercheck v0.9.4 // indirect
github.com/tomarrell/wrapcheck/v2 v2.9.0 // indirect
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
github.com/ultraware/funlen v0.1.0 // indirect
github.com/ultraware/whitespace v0.1.1 // indirect
github.com/uudashr/gocognit v1.1.3 // indirect
github.com/xen0n/gosmopolitan v1.2.2 // indirect github.com/xen0n/gosmopolitan v1.2.2 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect gitlab.com/bosi/decorder v0.4.1 // indirect
github.com/yeya24/promlinter v0.3.0 // indirect
github.com/ykadowak/zerologlint v0.1.5 // indirect
gitlab.com/bosi/decorder v0.4.2 // indirect
go-simpler.org/musttag v0.12.2 // indirect
go-simpler.org/sloglint v0.7.2 // indirect
go.uber.org/automaxprocs v1.5.3 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.25.0 // indirect
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/exp/typeparams v0.0.0-20240904232852-e7e105dedf7e // indirect golang.org/x/exp/typeparams v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.21.0 // indirect golang.org/x/tools v0.13.0
golang.org/x/sync v0.8.0 // indirect google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
golang.org/x/sys v0.25.0 // indirect google.golang.org/protobuf v1.31.0
golang.org/x/text v0.18.0 // indirect mvdan.cc/unparam v0.0.0-20230815095028-f7c6fb1088f0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.5.1 // indirect
mvdan.cc/gofumpt v0.7.0 // indirect
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect
) )
+2251 -266
View File
File diff suppressed because it is too large Load Diff
-6
View File
@@ -1,6 +0,0 @@
export GO111MODULE=on # otherwise, a checkout of this repo in GOPATH will disable modules on Go 1.12 and earlier
source <(go env)
# build tools for the host platform
export GOOS="$GOHOSTOS"
export GOARCH="$GOHOSTARCH"
# TODO GOARM=$GOHOSTARM?
-19
View File
@@ -1,19 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
set -x
OUTDIR="$(readlink -f "$1")"
if [ -e "$OUTDIR" ]; then
echo "$OUTDIR" already exists 1>&2
exit 1
fi
# go install command below will install tools to $GOBIN
export GOBIN="$OUTDIR"
cd "$(dirname "$0")"
source ./go_install_host_tool.source
cat tools.go | grep _ | awk -F'"' '{print $2}' | tee | xargs -tI '{}' go install '{}'
+2 -2
View File
@@ -8,9 +8,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/internal/daemon/logging/trace" "github.com/zrepl/zrepl/daemon/logging/trace"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
) )
var rootArgs struct { var rootArgs struct {
@@ -11,11 +11,11 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/yaml-config" "github.com/zrepl/yaml-config"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/job" "github.com/zrepl/zrepl/daemon/job"
"github.com/zrepl/zrepl/internal/daemon/logging" "github.com/zrepl/zrepl/daemon/logging"
"github.com/zrepl/zrepl/internal/logger" "github.com/zrepl/zrepl/logger"
) )
var configcheckArgs struct { var configcheckArgs struct {
@@ -9,12 +9,12 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/internal/daemon/job" "github.com/zrepl/zrepl/daemon/job"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
) )
var ( var (
+1 -1
View File
@@ -1,6 +1,6 @@
package client package client
import "github.com/zrepl/zrepl/internal/cli" import "github.com/zrepl/zrepl/cli"
var PprofCmd = &cli.Subcommand{ var PprofCmd = &cli.Subcommand{
Use: "pprof", Use: "pprof",
@@ -8,7 +8,7 @@ import (
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
) )
var pprofActivityTraceCmd = &cli.Subcommand{ var pprofActivityTraceCmd = &cli.Subcommand{
@@ -6,9 +6,9 @@ import (
"log" "log"
"os" "os"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon" "github.com/zrepl/zrepl/daemon"
) )
var pprofListenCmd struct { var pprofListenCmd struct {
@@ -5,9 +5,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon" "github.com/zrepl/zrepl/daemon"
) )
var SignalCmd = &cli.Subcommand{ var SignalCmd = &cli.Subcommand{
@@ -10,7 +10,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/internal/daemon" "github.com/zrepl/zrepl/daemon"
) )
type Client struct { type Client struct {
@@ -9,11 +9,11 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/client/status/client" "github.com/zrepl/zrepl/client/status/client"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon" "github.com/zrepl/zrepl/daemon"
"github.com/zrepl/zrepl/internal/util/choices" "github.com/zrepl/zrepl/util/choices"
) )
type Client interface { type Client interface {
@@ -5,11 +5,11 @@ import (
"os" "os"
"strings" "strings"
"github.com/gdamore/tcell/v2" "github.com/gdamore/tcell"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/internal/client/status/viewmodel" "github.com/zrepl/zrepl/client/status/viewmodel"
) )
func dump(c Client, job string) error { func dump(c Client, job string) error {
@@ -8,9 +8,9 @@ import (
"time" "time"
"github.com/gdamore/tcell/v2" "github.com/gdamore/tcell/v2"
"github.com/rivo/tview" tview "gitlab.com/tslocum/cview"
"github.com/zrepl/zrepl/internal/client/status/viewmodel" "github.com/zrepl/zrepl/client/status/viewmodel"
) )
func interactive(c Client, flag statusFlags) error { func interactive(c Client, flag statusFlags) error {
@@ -29,6 +29,7 @@ func interactive(c Client, flag statusFlags) error {
jobMenuRoot.SetSelectable(true) jobMenuRoot.SetSelectable(true)
jobMenu.SetRoot(jobMenuRoot) jobMenu.SetRoot(jobMenuRoot)
jobMenu.SetCurrentNode(jobMenuRoot) jobMenu.SetCurrentNode(jobMenuRoot)
jobMenu.SetSelectedTextColor(tcell.ColorGreen)
jobTextDetail := tview.NewTextView() jobTextDetail := tview.NewTextView()
jobTextDetail.SetWrap(false) jobTextDetail.SetWrap(false)
@@ -109,8 +110,10 @@ func interactive(c Client, flag statusFlags) error {
} }
app.SetRoot(toolbarSplit, true) app.SetRoot(toolbarSplit, true)
app.SetFocus(preModalFocus) app.SetFocus(preModalFocus)
app.Draw()
}) })
app.SetRoot(m, true) app.SetRoot(m, true)
app.Draw()
} }
app.SetRoot(toolbarSplit, true) app.SetRoot(toolbarSplit, true)
@@ -167,14 +170,12 @@ func interactive(c Client, flag statusFlags) error {
redrawJobsList = true redrawJobsList = true
} }
if redrawJobsList { if redrawJobsList {
selectedTextStyle := tcell.StyleDefault.Bold(true)
selectedJobN = nil selectedJobN = nil
children := make([]*tview.TreeNode, len(jobs)) children := make([]*tview.TreeNode, len(jobs))
for i := range jobs { for i := range jobs {
jobN := tview.NewTreeNode(jobs[i].JobTreeTitle()) jobN := tview.NewTreeNode(jobs[i].JobTreeTitle())
jobN.SetReference(jobs[i]) jobN.SetReference(jobs[i])
jobN.SetSelectable(true) jobN.SetSelectable(true)
jobN.SetSelectedTextStyle(selectedTextStyle)
children[i] = jobN children[i] = jobN
jobN.SetSelectedFunc(func() { jobN.SetSelectedFunc(func() {
viewmodelupdate(func(p *viewmodel.Params) { viewmodelupdate(func(p *viewmodel.Params) {
@@ -186,7 +187,6 @@ func interactive(c Client, flag statusFlags) error {
} }
} }
jobMenuRoot.SetChildren(children) jobMenuRoot.SetChildren(children)
jobMenuRoot.SetSelectedTextStyle(selectedTextStyle)
} }
if selectedJobN != nil && jobMenu.GetCurrentNode() != selectedJobN { if selectedJobN != nil && jobMenu.GetCurrentNode() != selectedJobN {
@@ -207,6 +207,9 @@ func interactive(c Client, flag statusFlags) error {
bottombar.ResizeItem(bottombarDateView, len(bottombardatestring), 0) bottombar.ResizeItem(bottombarDateView, len(bottombardatestring), 0)
bottomBarStatus.SetText(m.BottomBarStatus()) bottomBarStatus.SetText(m.BottomBarStatus())
app.Draw()
} }
go func() { go func() {
@@ -249,7 +252,6 @@ func interactive(c Client, flag statusFlags) error {
app.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey { app.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey {
if e.Key() == tcell.KeyTab { if e.Key() == tcell.KeyTab {
// TODO: only if there's no modal showing (long-time bug in zrepl status)
tabbableCycle() tabbableCycle()
return nil return nil
} }
@@ -282,8 +284,9 @@ func interactive(c Client, flag statusFlags) error {
signals := []string{"wakeup", "reset"} signals := []string{"wakeup", "reset"}
clientFuncs := []func(job string) error{c.SignalWakeup, c.SignalReset} clientFuncs := []func(job string) error{c.SignalWakeup, c.SignalReset}
sigMod := tview.NewModal() sigMod := tview.NewModal()
sigMod.SetBackgroundColor(tcell.ColorDefault)
sigMod.SetBorder(true) sigMod.SetBorder(true)
sigMod.SetButtonActivatedStyle(tcell.StyleDefault.Bold(true).Reverse(true)) sigMod.GetForm().SetButtonTextColorFocused(tcell.ColorGreen)
sigMod.AddButtons(signals) sigMod.AddButtons(signals)
sigMod.SetText(fmt.Sprintf("Send a signal to job %q", job.Name())) sigMod.SetText(fmt.Sprintf("Send a signal to job %q", job.Name()))
showModal(sigMod, func(idx int, _ string) { showModal(sigMod, func(idx int, _ string) {
@@ -10,9 +10,9 @@ import (
"github.com/gdamore/tcell/v2" "github.com/gdamore/tcell/v2"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/rivo/tview" tview "gitlab.com/tslocum/cview"
"github.com/zrepl/zrepl/internal/client/status/viewmodel" "github.com/zrepl/zrepl/client/status/viewmodel"
) )
func legacy(c Client, flag statusFlags) error { func legacy(c Client, flag statusFlags) error {
@@ -28,7 +28,7 @@ func legacy(c Client, flag statusFlags) error {
textView := tview.NewTextView() textView := tview.NewTextView()
textView.SetWrap(true) textView.SetWrap(true)
textView.SetScrollable(true) // so that it allows us to set scroll position textView.SetScrollable(true) // so that it allows us to set scroll position
// textView.SetScrollBarVisibility(tview.ScrollBarNever) textView.SetScrollBarVisibility(tview.ScrollBarNever)
app.SetRoot(textView, true) app.SetRoot(textView, true)
@@ -10,12 +10,12 @@ import (
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
yaml "github.com/zrepl/yaml-config" yaml "github.com/zrepl/yaml-config"
"github.com/zrepl/zrepl/internal/client/status/viewmodel/stringbuilder" "github.com/zrepl/zrepl/client/status/viewmodel/stringbuilder"
"github.com/zrepl/zrepl/internal/daemon" "github.com/zrepl/zrepl/daemon"
"github.com/zrepl/zrepl/internal/daemon/job" "github.com/zrepl/zrepl/daemon/job"
"github.com/zrepl/zrepl/internal/daemon/pruner" "github.com/zrepl/zrepl/daemon/pruner"
"github.com/zrepl/zrepl/internal/daemon/snapper" "github.com/zrepl/zrepl/daemon/snapper"
"github.com/zrepl/zrepl/internal/replication/report" "github.com/zrepl/zrepl/replication/report"
) )
type M struct { type M struct {
@@ -5,8 +5,8 @@ import (
"github.com/problame/go-netssh" "github.com/problame/go-netssh"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"context" "context"
"errors" "errors"
@@ -9,10 +9,10 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/filters" "github.com/zrepl/zrepl/daemon/filters"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
var TestCmd = &cli.Subcommand{ var TestCmd = &cli.Subcommand{
@@ -7,10 +7,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon" "github.com/zrepl/zrepl/daemon"
"github.com/zrepl/zrepl/internal/version" "github.com/zrepl/zrepl/version"
) )
var versionArgs struct { var versionArgs struct {
@@ -7,10 +7,10 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/daemon/filters" "github.com/zrepl/zrepl/daemon/filters"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
var ( var (
@@ -1,6 +1,6 @@
package client package client
import "github.com/zrepl/zrepl/internal/cli" import "github.com/zrepl/zrepl/cli"
var zabsCmdCreate = &cli.Subcommand{ var zabsCmdCreate = &cli.Subcommand{
Use: "create", Use: "create",
@@ -7,9 +7,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
var zabsCreateStepHoldFlags struct { var zabsCreateStepHoldFlags struct {
@@ -11,9 +11,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/util/chainlock" "github.com/zrepl/zrepl/util/chainlock"
) )
var zabsListFlags struct { var zabsListFlags struct {
@@ -10,8 +10,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/zrepl/zrepl/internal/cli" "github.com/zrepl/zrepl/cli"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
) )
// shared between release-all and release-step // shared between release-all and release-step
+20 -19
View File
@@ -2,16 +2,18 @@ package config
import ( import (
"fmt" "fmt"
"io/ioutil"
"log/syslog" "log/syslog"
"os" "os"
"reflect"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"github.com/zrepl/yaml-config" "github.com/zrepl/yaml-config"
"github.com/zrepl/zrepl/internal/util/datasizeunit" "github.com/zrepl/zrepl/util/datasizeunit"
zfsprop "github.com/zrepl/zrepl/internal/zfs/property" zfsprop "github.com/zrepl/zrepl/zfs/property"
) )
type ParseFlags uint type ParseFlags uint
@@ -22,7 +24,7 @@ const (
) )
type Config struct { type Config struct {
Jobs []JobEnum `yaml:"jobs,optional"` Jobs []JobEnum `yaml:"jobs"`
Global *Global `yaml:"global,optional,fromdefaults"` Global *Global `yaml:"global,optional,fromdefaults"`
} }
@@ -222,12 +224,7 @@ type SnapshottingPeriodic struct {
Prefix string `yaml:"prefix"` Prefix string `yaml:"prefix"`
Interval *PositiveDuration `yaml:"interval"` Interval *PositiveDuration `yaml:"interval"`
Hooks HookList `yaml:"hooks,optional"` Hooks HookList `yaml:"hooks,optional"`
TimestampFormattingSpec `yaml:",inline"`
}
type TimestampFormattingSpec struct {
TimestampFormat string `yaml:"timestamp_format,optional,default=dense"` TimestampFormat string `yaml:"timestamp_format,optional,default=dense"`
TimestampLocation string `yaml:"timestamp_location,optional,default=UTC"`
} }
type CronSpec struct { type CronSpec struct {
@@ -260,7 +257,7 @@ type SnapshottingCron struct {
Prefix string `yaml:"prefix"` Prefix string `yaml:"prefix"`
Cron CronSpec `yaml:"cron"` Cron CronSpec `yaml:"cron"`
Hooks HookList `yaml:"hooks,optional"` Hooks HookList `yaml:"hooks,optional"`
TimestampFormattingSpec `yaml:",inline"` TimestampFormat string `yaml:"timestamp_format,optional,default=dense"`
} }
type SnapshottingManual struct { type SnapshottingManual struct {
@@ -302,6 +299,18 @@ type Global struct {
Serve *GlobalServe `yaml:"serve,optional,fromdefaults"` Serve *GlobalServe `yaml:"serve,optional,fromdefaults"`
} }
func Default(i interface{}) {
v := reflect.ValueOf(i)
if v.Kind() != reflect.Ptr {
panic(v)
}
y := `{}`
err := yaml.Unmarshal([]byte(y), v.Interface())
if err != nil {
panic(err)
}
}
type ConnectEnum struct { type ConnectEnum struct {
Ret interface{} Ret interface{}
} }
@@ -675,7 +684,7 @@ func ParseConfig(path string) (i *Config, err error) {
var bytes []byte var bytes []byte
if bytes, err = os.ReadFile(path); err != nil { if bytes, err = ioutil.ReadFile(path); err != nil {
return return
} }
@@ -687,16 +696,8 @@ func ParseConfigBytes(bytes []byte) (*Config, error) {
if err := yaml.UnmarshalStrict(bytes, &c); err != nil { if err := yaml.UnmarshalStrict(bytes, &c); err != nil {
return nil, err return nil, err
} }
if c != nil {
return c, nil
}
// There was no yaml document in the file, deserialize from default.
// => See TestFromdefaultsEmptyDoc in yaml-config package.
if err := yaml.UnmarshalStrict([]byte("{}"), &c); err != nil {
return nil, err
}
if c == nil { if c == nil {
panic("the fallback to deserialize from `{}` should work") return nil, fmt.Errorf("config is empty or only consists of comments")
} }
return c, nil return c, nil
} }
@@ -2,8 +2,16 @@ package config
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestConfigEmptyFails(t *testing.T) {
conf, err := testConfig(t, "\n")
assert.Nil(t, conf)
assert.Error(t, err)
}
func TestJobsOnlyWorks(t *testing.T) { func TestJobsOnlyWorks(t *testing.T) {
testValidConfig(t, ` testValidConfig(t, `
jobs: jobs:
@@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
zfsprop "github.com/zrepl/zrepl/internal/zfs/property" zfsprop "github.com/zrepl/zrepl/zfs/property"
) )
func TestRecvOptions(t *testing.T) { func TestRecvOptions(t *testing.T) {
@@ -163,8 +163,7 @@ jobs:
assert.Equal(t, "periodic", snp.Type) assert.Equal(t, "periodic", snp.Type)
assert.Equal(t, 10*time.Minute, snp.Interval.Duration()) assert.Equal(t, 10*time.Minute, snp.Interval.Duration())
assert.Equal(t, "zrepl_", snp.Prefix) assert.Equal(t, "zrepl_", snp.Prefix)
assert.Equal(t, snp.TimestampFormat, "dense") assert.Equal(t, "dense", snp.TimestampFormat) // default was set correctly
assert.Equal(t, snp.TimestampLocation, "UTC")
}) })
t.Run("cron", func(t *testing.T) { t.Run("cron", func(t *testing.T) {
@@ -172,7 +171,6 @@ jobs:
snp := c.Jobs[0].Ret.(*PushJob).Snapshotting.Ret.(*SnapshottingCron) snp := c.Jobs[0].Ret.(*PushJob).Snapshotting.Ret.(*SnapshottingCron)
assert.Equal(t, "cron", snp.Type) assert.Equal(t, "cron", snp.Type)
assert.Equal(t, "zrepl_", snp.Prefix) assert.Equal(t, "zrepl_", snp.Prefix)
assert.Equal(t, snp.TimestampFormat, "dense") assert.Equal(t, "dense", snp.TimestampFormat) // default was set correctly
assert.Equal(t, snp.TimestampLocation, "UTC")
}) })
} }
@@ -22,8 +22,6 @@ func TestSampleConfigsAreParsedWithoutErrors(t *testing.T) {
t.Errorf("glob failed: %+v", err) t.Errorf("glob failed: %+v", err)
} }
paths = append(paths, "../../packaging/systemd-default-zrepl.yml")
for _, p := range paths { for _, p := range paths {
if path.Ext(p) != ".yml" { if path.Ext(p) != ".yml" {
@@ -140,18 +138,3 @@ func TestCronSpec(t *testing.T) {
} }
} }
func TestEmptyConfig(t *testing.T) {
cases := []string{
"",
"\n",
"---",
"---\n",
}
for _, input := range cases {
config := testValidConfig(t, input)
require.NotNil(t, config)
require.NotNil(t, config.Global)
require.Empty(t, config.Jobs)
}
}
@@ -14,14 +14,14 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/zrepl/zrepl/internal/daemon/job" "github.com/zrepl/zrepl/daemon/job"
"github.com/zrepl/zrepl/internal/daemon/nethelpers" "github.com/zrepl/zrepl/daemon/nethelpers"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/logger" "github.com/zrepl/zrepl/logger"
"github.com/zrepl/zrepl/internal/util/envconst" "github.com/zrepl/zrepl/util/envconst"
"github.com/zrepl/zrepl/internal/version" "github.com/zrepl/zrepl/version"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
"github.com/zrepl/zrepl/internal/zfs/zfscmd" "github.com/zrepl/zrepl/zfs/zfscmd"
) )
type controlJob struct { type controlJob struct {
+21 -39
View File
@@ -3,6 +3,7 @@ package daemon
import ( import (
"context" "context"
"fmt" "fmt"
"math/rand"
"os" "os"
"os/signal" "os/signal"
"strings" "strings"
@@ -13,18 +14,18 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/zrepl/zrepl/internal/daemon/logging/trace" "github.com/zrepl/zrepl/daemon/logging/trace"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/util/envconst" "github.com/zrepl/zrepl/util/envconst"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/job" "github.com/zrepl/zrepl/daemon/job"
"github.com/zrepl/zrepl/internal/daemon/job/reset" "github.com/zrepl/zrepl/daemon/job/reset"
"github.com/zrepl/zrepl/internal/daemon/job/wakeup" "github.com/zrepl/zrepl/daemon/job/wakeup"
"github.com/zrepl/zrepl/internal/daemon/logging" "github.com/zrepl/zrepl/daemon/logging"
"github.com/zrepl/zrepl/internal/logger" "github.com/zrepl/zrepl/logger"
"github.com/zrepl/zrepl/internal/version" "github.com/zrepl/zrepl/version"
"github.com/zrepl/zrepl/internal/zfs/zfscmd" "github.com/zrepl/zrepl/zfs/zfscmd"
) )
func Run(ctx context.Context, conf *config.Config) error { func Run(ctx context.Context, conf *config.Config) error {
@@ -38,6 +39,12 @@ func Run(ctx context.Context, conf *config.Config) error {
cancel() cancel()
}() }()
// The math/rand package is used presently for generating trace IDs, we
// seed it with the current time and pid so that the IDs are mostly
// unique.
rand.Seed(time.Now().UnixNano())
rand.Seed(int64(os.Getpid()))
outlets, err := logging.OutletsFromConfig(*conf.Global.Logging) outlets, err := logging.OutletsFromConfig(*conf.Global.Logging)
if err != nil { if err != nil {
return errors.Wrap(err, "cannot build logging from config") return errors.Wrap(err, "cannot build logging from config")
@@ -69,7 +76,7 @@ func Run(ctx context.Context, conf *config.Config) error {
} }
} }
jobs := newJobs(prometheus.DefaultRegisterer) jobs := newJobs()
// start control socket // start control socket
controlJob, err := newControlJob(conf.Global.Control.SockPath, jobs) controlJob, err := newControlJob(conf.Global.Control.SockPath, jobs)
@@ -123,8 +130,6 @@ func Run(ctx context.Context, conf *config.Config) error {
type jobs struct { type jobs struct {
wg sync.WaitGroup wg sync.WaitGroup
metrics metrics
// m protects all fields below it // m protects all fields below it
m sync.RWMutex m sync.RWMutex
wakeups map[string]wakeup.Func // by Job.Name wakeups map[string]wakeup.Func // by Job.Name
@@ -132,32 +137,12 @@ type jobs struct {
jobs map[string]job.Job jobs map[string]job.Job
} }
type metrics struct { func newJobs() *jobs {
running *prometheus.GaugeVec return &jobs{
}
func newJobs(registry prometheus.Registerer) *jobs {
jobs := &jobs{
metrics: metrics{
running: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: "zrepl",
Subsystem: "daemon",
Name: "job_up",
Help: `Each zrepl-level job starts its life with this metric =1.
It reamins =1 until the job leaves its Run() function.
The purpose of this metric is primarily for Prometheus to be aware of all job names.
The value will only transition to 0 during zrepl daemon shutdown or panics.
`,
}, []string{"zrepl_job", "internal"}),
},
wakeups: make(map[string]wakeup.Func), wakeups: make(map[string]wakeup.Func),
resets: make(map[string]reset.Func), resets: make(map[string]reset.Func),
jobs: make(map[string]job.Job), jobs: make(map[string]job.Job),
} }
registry.MustRegister(jobs.metrics.running)
return jobs
} }
func (s *jobs) wait() <-chan struct{} { func (s *jobs) wait() <-chan struct{} {
@@ -264,10 +249,7 @@ func (s *jobs) start(ctx context.Context, j job.Job, internal bool) {
s.resets[jobName] = resetFunc s.resets[jobName] = resetFunc
s.wg.Add(1) s.wg.Add(1)
runningJobsGauge := s.metrics.running.WithLabelValues(jobName, fmt.Sprintf("%v", internal))
runningJobsGauge.Inc()
go func() { go func() {
defer runningJobsGauge.Dec()
defer s.wg.Done() defer s.wg.Done()
job.GetLogger(ctx).Info("starting job") job.GetLogger(ctx).Info("starting job")
defer job.GetLogger(ctx).Info("job exited") defer job.GetLogger(ctx).Info("job exited")
@@ -6,8 +6,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
type DatasetMapFilter struct { type DatasetMapFilter struct {
@@ -3,7 +3,7 @@ package filters
import ( import (
"testing" "testing"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
func TestDatasetMapFilter(t *testing.T) { func TestDatasetMapFilter(t *testing.T) {
@@ -3,8 +3,8 @@ package hooks
import ( import (
"fmt" "fmt"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
type List []Hook type List []Hook
@@ -7,7 +7,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
// Re-export type here so that // Re-export type here so that
@@ -6,9 +6,9 @@ import (
"context" "context"
"sync" "sync"
"github.com/zrepl/zrepl/internal/daemon/logging" "github.com/zrepl/zrepl/daemon/logging"
"github.com/zrepl/zrepl/internal/logger" "github.com/zrepl/zrepl/logger"
"github.com/zrepl/zrepl/internal/util/envconst" "github.com/zrepl/zrepl/util/envconst"
) )
type Logger = logger.Logger type Logger = logger.Logger
@@ -4,8 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/zrepl/zrepl/internal/daemon/filters" "github.com/zrepl/zrepl/daemon/filters"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
type HookJobCallback func(ctx context.Context) error type HookJobCallback func(ctx context.Context) error
@@ -12,11 +12,11 @@ import (
"sync" "sync"
"time" "time"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/filters" "github.com/zrepl/zrepl/daemon/filters"
"github.com/zrepl/zrepl/internal/logger" "github.com/zrepl/zrepl/logger"
"github.com/zrepl/zrepl/internal/util/circlog" "github.com/zrepl/zrepl/util/circlog"
"github.com/zrepl/zrepl/internal/util/envconst" "github.com/zrepl/zrepl/util/envconst"
) )
type HookEnvVar string type HookEnvVar string
@@ -12,9 +12,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/filters" "github.com/zrepl/zrepl/daemon/filters"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
// Hook to implement the following recommmendation from MySQL docs // Hook to implement the following recommmendation from MySQL docs
@@ -10,9 +10,9 @@ import (
"github.com/lib/pq" "github.com/lib/pq"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/filters" "github.com/zrepl/zrepl/daemon/filters"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
type PgChkptHook struct { type PgChkptHook struct {
@@ -11,13 +11,13 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zrepl/zrepl/internal/daemon/logging/trace" "github.com/zrepl/zrepl/daemon/logging/trace"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/hooks" "github.com/zrepl/zrepl/daemon/hooks"
"github.com/zrepl/zrepl/internal/daemon/logging" "github.com/zrepl/zrepl/daemon/logging"
"github.com/zrepl/zrepl/internal/logger" "github.com/zrepl/zrepl/logger"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
type comparisonAssertionFunc func(require.TestingT, interface{}, interface{}, ...interface{}) type comparisonAssertionFunc func(require.TestingT, interface{}, interface{}, ...interface{})
@@ -1,5 +1,6 @@
// Code generated by "enumer -type=StepStatus -trimprefix=Step"; DO NOT EDIT. // Code generated by "enumer -type=StepStatus -trimprefix=Step"; DO NOT EDIT.
//
package hooks package hooks
import ( import (
@@ -8,24 +8,25 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log"
"github.com/zrepl/zrepl/internal/daemon/logging/trace" "github.com/zrepl/zrepl/daemon/logging/trace"
"github.com/zrepl/zrepl/internal/util/envconst" "github.com/zrepl/zrepl/util/envconst"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/job/reset" "github.com/zrepl/zrepl/daemon/job/reset"
"github.com/zrepl/zrepl/internal/daemon/job/wakeup" "github.com/zrepl/zrepl/daemon/job/wakeup"
"github.com/zrepl/zrepl/internal/daemon/pruner" "github.com/zrepl/zrepl/daemon/pruner"
"github.com/zrepl/zrepl/internal/daemon/snapper" "github.com/zrepl/zrepl/daemon/snapper"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/replication" "github.com/zrepl/zrepl/replication"
"github.com/zrepl/zrepl/internal/replication/driver" "github.com/zrepl/zrepl/replication/driver"
"github.com/zrepl/zrepl/internal/replication/logic" "github.com/zrepl/zrepl/replication/logic"
"github.com/zrepl/zrepl/internal/replication/report" "github.com/zrepl/zrepl/replication/report"
"github.com/zrepl/zrepl/internal/rpc" "github.com/zrepl/zrepl/rpc"
"github.com/zrepl/zrepl/internal/transport" "github.com/zrepl/zrepl/transport"
"github.com/zrepl/zrepl/internal/transport/fromconfig" "github.com/zrepl/zrepl/transport/fromconfig"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
type ActiveSide struct { type ActiveSide struct {
@@ -481,7 +482,7 @@ func (j *ActiveSide) do(ctx context.Context) {
go func() { go func() {
select { select {
case <-reset.Wait(ctx): case <-reset.Wait(ctx):
GetLogger(ctx).Info("reset received, cancelling current invocation") log.Info("reset received, cancelling current invocation")
cancelThisRun() cancelThisRun()
case <-ctx.Done(): case <-ctx.Done():
} }
@@ -6,8 +6,8 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/transport" "github.com/zrepl/zrepl/transport"
) )
func TestFakeActiveSideDirectMethodInvocationClientIdentityDoesNotPassValidityTest(t *testing.T) { func TestFakeActiveSideDirectMethodInvocationClientIdentityDoesNotPassValidityTest(t *testing.T) {
@@ -1,5 +1,6 @@
// Code generated by "enumer -type=ActiveSideState"; DO NOT EDIT. // Code generated by "enumer -type=ActiveSideState"; DO NOT EDIT.
//
package job package job
import ( import (
@@ -7,8 +7,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/util/bandwidthlimit" "github.com/zrepl/zrepl/util/bandwidthlimit"
) )
func JobsFromConfig(c *config.Config, parseFlags config.ParseFlags) ([]Job, error) { func JobsFromConfig(c *config.Config, parseFlags config.ParseFlags) ([]Job, error) {
@@ -24,6 +24,21 @@ func JobsFromConfig(c *config.Config, parseFlags config.ParseFlags) ([]Job, erro
js[i] = j js[i] = j
} }
// receiving-side root filesystems must not overlap
{
rfss := make([]string, 0, len(js))
for _, j := range js {
jrfs, ok := j.OwnedDatasetSubtreeRoot()
if !ok {
continue
}
rfss = append(rfss, jrfs.ToString())
}
if err := validateReceivingSidesDoNotOverlap(rfss); err != nil {
return nil, err
}
}
return js, nil return js, nil
} }
@@ -3,11 +3,11 @@ package job
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/filters" "github.com/zrepl/zrepl/daemon/filters"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/util/nodefault" "github.com/zrepl/zrepl/util/nodefault"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
type SendingJobConfig interface { type SendingJobConfig interface {
@@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
) )
func TestValidateReceivingSidesDoNotOverlap(t *testing.T) { func TestValidateReceivingSidesDoNotOverlap(t *testing.T) {
@@ -113,7 +113,7 @@ jobs:
} }
func TestSampleConfigsAreBuiltWithoutErrors(t *testing.T) { func TestSampleConfigsAreBuiltWithoutErrors(t *testing.T) {
paths, err := filepath.Glob("../../../internal/config/samples/*") paths, err := filepath.Glob("../../config/samples/*")
if err != nil { if err != nil {
t.Errorf("glob failed: %+v", err) t.Errorf("glob failed: %+v", err)
} }
@@ -7,10 +7,10 @@ import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/zrepl/zrepl/internal/daemon/logging" "github.com/zrepl/zrepl/daemon/logging"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/logger" "github.com/zrepl/zrepl/logger"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
type Logger = logger.Logger type Logger = logger.Logger
@@ -7,16 +7,16 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/zrepl/zrepl/internal/daemon/logging/trace" "github.com/zrepl/zrepl/daemon/logging/trace"
"github.com/zrepl/zrepl/internal/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/internal/daemon/logging" "github.com/zrepl/zrepl/daemon/logging"
"github.com/zrepl/zrepl/internal/daemon/snapper" "github.com/zrepl/zrepl/daemon/snapper"
"github.com/zrepl/zrepl/internal/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/internal/rpc" "github.com/zrepl/zrepl/rpc"
"github.com/zrepl/zrepl/internal/transport" "github.com/zrepl/zrepl/transport"
"github.com/zrepl/zrepl/internal/transport/fromconfig" "github.com/zrepl/zrepl/transport/fromconfig"
"github.com/zrepl/zrepl/internal/zfs" "github.com/zrepl/zrepl/zfs"
) )
type PassiveSide struct { type PassiveSide struct {

Some files were not shown because too many files have changed in this diff Show More