Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c12675ee1 | |||
| 76981d2037 | |||
| 075ecdac5b | |||
| 1dfae6829b |
+76
-6
@@ -51,6 +51,76 @@ commands:
|
||||
paths:
|
||||
- ~/.cache/uv
|
||||
|
||||
install-zfs-from-source:
|
||||
parameters:
|
||||
zfs_release:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Record kernel version for cache key
|
||||
command: uname -r > /tmp/kernel-version
|
||||
- restore_cache:
|
||||
name: Restore ZFS native debs cache
|
||||
keys:
|
||||
- zfs-debs-v2-<<parameters.zfs_release>>-{{ checksum "/tmp/kernel-version" }}
|
||||
- run:
|
||||
# https://openzfs.github.io/openzfs-docs/Developer%20Resources/Building%20ZFS.html
|
||||
name: Build ZFS <<parameters.zfs_release>> native debs (if not cached)
|
||||
no_output_timeout: 20m
|
||||
command: |
|
||||
# CircleCI machine images have pyenv Python 3.13 shadowing the system
|
||||
# Python 3.12. The apt python3-* packages (setuptools, cffi, etc.) only
|
||||
# install for the system Python, and ZFS's dpkg-buildpackage needs them
|
||||
# for --enable-pyzfs. Use the system Python so apt packages are visible.
|
||||
export PYENV_VERSION=system
|
||||
if [ -d /tmp/zfs-debs ]; then
|
||||
echo "ZFS debs cache hit, skipping build"
|
||||
exit 0
|
||||
fi
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
alien autoconf automake build-essential debhelper-compat dh-autoreconf \
|
||||
dh-dkms dh-python dkms fakeroot gawk git libaio-dev libattr1-dev \
|
||||
libblkid-dev libcurl4-openssl-dev libelf-dev libffi-dev libpam0g-dev \
|
||||
libssl-dev libtirpc-dev libtool libudev-dev linux-headers-$(uname -r) lsb-release \
|
||||
parallel po-debconf python3 python3-all-dev python3-cffi python3-dev \
|
||||
python3-packaging python3-setuptools python3-sphinx uuid-dev zlib1g-dev
|
||||
mkdir -p /tmp/zfs-build
|
||||
cd /tmp/zfs-build
|
||||
git clone --depth 1 --branch <<parameters.zfs_release>> https://github.com/openzfs/zfs.git zfs-src
|
||||
cd zfs-src
|
||||
sh autogen.sh
|
||||
./configure
|
||||
make native-deb
|
||||
mkdir -p /tmp/zfs-debs
|
||||
find /tmp/zfs-build -name '*.deb' -exec mv -t /tmp/zfs-debs/ {} +
|
||||
- save_cache:
|
||||
name: Save ZFS native debs cache
|
||||
key: zfs-debs-v2-<<parameters.zfs_release>>-{{ checksum "/tmp/kernel-version" }}
|
||||
paths:
|
||||
- /tmp/zfs-debs
|
||||
- run:
|
||||
name: Install ZFS <<parameters.zfs_release>>
|
||||
command: |
|
||||
ls /tmp/zfs-debs/
|
||||
# Only install the debs we need. Exclude dracut (conflicts with
|
||||
# initramfs-tools), dkms (we have prebuilt modules), and packages
|
||||
# we don't need (pyzfs, test, doc).
|
||||
sudo apt-get install -y $(find /tmp/zfs-debs -name '*.deb' \
|
||||
! -name '*dracut*' \
|
||||
! -name '*dkms*' \
|
||||
! -name '*initramfs*' \
|
||||
! -name '*pyzfs*' \
|
||||
! -name '*doc*' \
|
||||
! -name '*test*' \
|
||||
-print)
|
||||
sudo modprobe zfs
|
||||
- run:
|
||||
name: Verify ZFS version
|
||||
command: |
|
||||
sudo zfs version
|
||||
sudo zpool version
|
||||
|
||||
docs-publish-sh:
|
||||
parameters:
|
||||
push:
|
||||
@@ -135,7 +205,7 @@ workflows:
|
||||
goversion: [*latest-go-release]
|
||||
goos: ["linux"]
|
||||
goarch: ["amd64"]
|
||||
image: ["ubuntu-2204:current", "ubuntu-2404:current"]
|
||||
zfs_release: ["zfs-2.2.9", "zfs-2.3.5", "zfs-2.4.0"]
|
||||
requires:
|
||||
- test-go
|
||||
- quickcheck-go-<< matrix.goarch >>-<< matrix.goos >>-<< matrix.goversion >>
|
||||
@@ -239,10 +309,11 @@ jobs:
|
||||
type: string
|
||||
goarch:
|
||||
type: string
|
||||
image:
|
||||
zfs_release:
|
||||
type: string
|
||||
machine:
|
||||
image: <<parameters.image>>
|
||||
# pinned (not :current) to keep ZFS build cache valid across runs
|
||||
image: ubuntu-2404:2025.09.1
|
||||
resource_class: medium
|
||||
environment:
|
||||
GOOS: <<parameters.goos>>
|
||||
@@ -250,9 +321,8 @@ jobs:
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run: sudo apt-get update
|
||||
- run: sudo apt-get install -y zfsutils-linux
|
||||
- run: sudo zfs version
|
||||
- install-zfs-from-source:
|
||||
zfs_release: <<parameters.zfs_release>>
|
||||
- run: sudo make test-platform GOOS="$GOOS" GOARCH="$GOARCH"
|
||||
|
||||
test-go:
|
||||
|
||||
@@ -171,6 +171,8 @@ Run `make lint` and `make vet`.
|
||||
Update the CI configuration `.circleci/config.yml`:
|
||||
- Update Go version references (we reference the minimum and max supported version)
|
||||
- Set `Makefile` `RELEASE_GOVERSION` to the new Go version
|
||||
- Update the pinned ZFS release tags in the `platformtest` matrix (`zfs_release` parameter) to the latest patch releases of each OpenZFS branch (currently 2.2, 2.3, 2.4)
|
||||
- Update the pinned Ubuntu machine image for `platformtest` (e.g. `ubuntu-2404:2025.09.1`) — this is pinned rather than `current` so the ZFS build cache stays valid across runs
|
||||
|
||||
Update docs build tooling:
|
||||
- Update `uv` version in `.circleci/config.yml` (search for `astral.sh/uv/` and cache keys containing the version)
|
||||
|
||||
+30
-44
@@ -13,43 +13,36 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
The changelog summarizes bugfixes that are deemed relevant for users and package maintainers.
|
||||
Developers should consult the git commit log or GitHub issue tracker.
|
||||
0.7.0
|
||||
-----
|
||||
|
||||
Next Release
|
||||
------------
|
||||
* |feature| Config file inclusion using ``include`` directive.
|
||||
This allows distributing zrepl job definitions across multiple YAML files in a ``conf.d`` style directory.
|
||||
(:commit:`4d6583e`, thanks, `@ZeyadTamimi <https://github.com/zeyadtamimi>`_).
|
||||
* |feature| Add configurable timezone for snapshot name timestamps. The default remains UTC. (:commit:`b9b9ad1`, thanks, `@mjasnik <https://github.com/mjasnik>`_).
|
||||
* |feature| Improve Grafana dashboard with additional panels and refinements (:commit:`3f75127`, thanks, `@deajan <https://github.com/deajan>`_).
|
||||
* |bugfix| Fix replication of placeholder filesystems (:commit:`5615f49`).
|
||||
* |bugfix| Avoid using the word "error" in info-level log lines about ZFS command execution (:commit:`d3b2295`, thanks, `@bakhtiyarneyman <https://github.com/bakhtiyarneyman>`_).
|
||||
* |bugfix| Detect duplicate and internal job names at config parse time.
|
||||
zrepl will now refuse to load a config with duplicate or internally reserved job names, instead of failing later at daemon startup.
|
||||
(:commit:`860a9be`).
|
||||
* |docs| Add installation instructions for openSUSE (:commit:`40c4827`, thanks, `@findesgh <https://github.com/findesgh>`_).
|
||||
* |docs| Improve documentation on ``send_properties`` configuration and NFS/SMB considerations (:commit:`b5d8538`, thanks, `@Malvineous <https://github.com/Malvineous>`_).
|
||||
* |docs| Warn more prominently about the risks of the ``not_replicated`` keep rule (:commit:`affe00a`, thanks, `@wxiaoguang <https://github.com/wxiaoguang>`_).
|
||||
* |docs| Improve TLS/EasyRSA setup instructions (:commit:`e524b60`, thanks, `@alorimer <https://github.com/alorimer>`_).
|
||||
* |docs| ``zrepl.github.io``: auto-publish from ``master`` branch, retire ``stable`` branch (:commit:`4f950bb`).
|
||||
* |maint| ``zrepl status``: switch from the unmaintained ``cview`` fork back to the actively maintained ``tview`` library (:commit:`d7ede3f`).
|
||||
* |maint| Update to Go 1.25 toolchain with Go 1.24 language level & Go dependencies
|
||||
* |maint| Debian packages: proper bash completion placement (:commit:`2923009`)
|
||||
* |maint| RPM packages: AlmaLinux 8 for RPM builds (:commit:`27f4ad1`).
|
||||
* |maint| Improve build system & CI setup
|
||||
|
||||
The plan for the next release is to revisit how zrepl does snapshot management.
|
||||
High-level goals:
|
||||
|
||||
- Make it easy to decouple snapshot management (snapshotting, pruning) from replication.
|
||||
- Ability to include/exclude snapshots from replication.
|
||||
This is useful for aforementioned decoupling, e.g., separate snapshot prefixes for local & remote replication.
|
||||
Also, it makes explicit that by default, zrepl replicates all snapshots, and that
|
||||
replication has no concept of "zrepl-created snapshots", which is a common misconception.
|
||||
- Use of ``zfs snapshot`` comma syntax or channel programs to take snapshots of multiple
|
||||
datasets atomically.
|
||||
- Provide an alternative to the ``grid`` pruning policy.
|
||||
Most likely something based on hourly/daily/weekly/monthly "trains" plus a count.
|
||||
- Ability to prune at the granularity of the **group** of snapshots created at a given
|
||||
time, as opposed to the individual snapshots within a dataset.
|
||||
Maybe this will be addressed by the alternative to the ``grid`` pruning policy,
|
||||
as it will likely be more predictable.
|
||||
|
||||
Those changes will likely come with some breakage in the config.
|
||||
However, I want to avoid breaking **use cases** that are satisfied by the current design.
|
||||
There will be beta/RC releases to give users a chance to evaluate.
|
||||
|
||||
0.7.0 (unreleased)
|
||||
------------------
|
||||
|
||||
INCOMPLETE LIST OF CHANGES
|
||||
|
||||
* |maint| Update to Go 1.25 toolchain with Go 1.24 language level.
|
||||
* |maint| Fix deprecations exposed by the toolchain update.
|
||||
* |maint| Long-overdue update of all our dependencies & address deprecations.
|
||||
* |maint| Publish docs from ``master`` branch, retire ``stable`` branch.
|
||||
* |maint| The `make release-docker` in CircleCI produces executables that are bit-identical to my personal machine.
|
||||
.. NOTE::
|
||||
| zrepl is a spare-time project primarily developed by `Christian Schwarz <https://cschwarz.com>`_.
|
||||
| You can support maintenance and feature development through one of the following services:
|
||||
| |Donate via Patreon| |Donate via GitHub Sponsors| |Donate via Liberapay| |Donate via PayPal|
|
||||
| Note that PayPal processing fees are relatively high for small donations.
|
||||
| For SEPA wire transfer and **commercial support**, please `contact Christian directly <https://cschwarz.com>`_.
|
||||
|
||||
0.6.1
|
||||
-----
|
||||
@@ -65,13 +58,6 @@ INCOMPLETE LIST OF CHANGES
|
||||
* |maint| run platform tests as part of CI.
|
||||
* |maint| build: upgrade to Go 1.21 and update golangci-lint; minimum Go version for builds is now 1.20
|
||||
|
||||
.. NOTE::
|
||||
| zrepl is a spare-time project primarily developed by `Christian Schwarz <https://cschwarz.com>`_.
|
||||
| You can support maintenance and feature development through one of the following services:
|
||||
| |Donate via Patreon| |Donate via GitHub Sponsors| |Donate via Liberapay| |Donate via PayPal|
|
||||
| Note that PayPal processing fees are relatively high for small donations.
|
||||
| For SEPA wire transfer and **commercial support**, please `contact Christian directly <https://cschwarz.com>`_.
|
||||
|
||||
0.6
|
||||
---
|
||||
|
||||
@@ -258,7 +244,7 @@ Additional changelog:
|
||||
* |bugfix| systemd + ``ssh+stdinserver``: automatically create ``/var/run/zrepl/stdinserver``
|
||||
* |bugfix| crash if Prometheus listening socket cannot be opened
|
||||
|
||||
* [MAINTAINER NOTICE] ``Makefile`` refactoring, see :commit:`080f2c0`
|
||||
* [MAINTAINER NOTICE] ``Makefile`` refactoring, see commit :commit:`080f2c0`
|
||||
|
||||
0.2
|
||||
---
|
||||
@@ -288,7 +274,7 @@ Additional changelog:
|
||||
0.1.1
|
||||
-----
|
||||
|
||||
* |bugfix| :issue:`162` :commit:`d6304f4` : fix I/O timeout errors on variable receive rate
|
||||
* |bugfix| :issue:`162` commit :commit:`d6304f4` : fix I/O timeout errors on variable receive rate
|
||||
|
||||
* A significant reduction or sudden stall of the receive rate (e.g. recv pool has other I/O to do)
|
||||
would cause a ``writev I/O timeout`` error after approximately ten seconds.
|
||||
|
||||
+1
-1
@@ -182,6 +182,6 @@ extlinks = {
|
||||
'issue':('https://github.com/zrepl/zrepl/issues/%s', 'issue #%s'),
|
||||
'repomasterlink':('https://github.com/zrepl/zrepl/blob/master/%s', '%s'),
|
||||
'sampleconf':('https://github.com/zrepl/zrepl/blob/master/internal/config/samples%s', 'internal/config/samples%s'),
|
||||
'commit':('https://github.com/zrepl/zrepl/commit/%s', 'commit %s'),
|
||||
'commit':('https://github.com/zrepl/zrepl/commit/%s', '%s'),
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
.. include:: global.rst.inc
|
||||
|
||||
.. _future:
|
||||
|
||||
Future
|
||||
======
|
||||
|
||||
This page contains some notes about future plans for zrepl.
|
||||
Then again, Christian only has very limited time available for zrepl maintenance these days.
|
||||
So, don't count on any of this happening in the near future.
|
||||
|
||||
One big development that has happened in recent years is this fork of zrepl: https://github.com/dsh2dsh/zrepl
|
||||
We should figure out whether we can pull in features from there.
|
||||
|
||||
The next major step in terms of new feature development for zrepl would be to revise snapshot management:
|
||||
|
||||
- Make it easy to decouple snapshot management (snapshotting, pruning) from replication.
|
||||
- Ability to include/exclude snapshots from replication.
|
||||
This is useful for aforementioned decoupling, e.g., separate snapshot prefixes for local & remote replication.
|
||||
Also, it makes explicit that by default, zrepl replicates all snapshots, and that
|
||||
replication has no concept of "zrepl-created snapshots", which is a common misconception.
|
||||
- Use of ``zfs snapshot`` comma syntax or channel programs to take snapshots of multiple
|
||||
datasets atomically.
|
||||
- Provide an alternative to the ``grid`` pruning policy.
|
||||
Most likely something based on hourly/daily/weekly/monthly "trains" plus a count.
|
||||
- Ability to prune at the granularity of the **group** of snapshots created at a given
|
||||
time, as opposed to the individual snapshots within a dataset.
|
||||
Maybe this will be addressed by the alternative to the ``grid`` pruning policy,
|
||||
as it will likely be more predictable.
|
||||
|
||||
Those changes will likely come with some breakage in the config.
|
||||
However, I want to avoid breaking **use cases** that are satisfied by the current design.
|
||||
There will be beta/RC releases to give users a chance to evaluate.
|
||||
@@ -136,6 +136,7 @@ Table of Contents
|
||||
usage
|
||||
pr
|
||||
changelog
|
||||
future
|
||||
GitHub Repository & Issue Tracker <https://github.com/zrepl/zrepl>
|
||||
Chat: Matrix <https://matrix.to/#/#zrepl:matrix.org>
|
||||
supporters
|
||||
|
||||
@@ -573,8 +573,9 @@ func implReplicationIsResumableFullSend(ctx *platformtest.Context, setup replica
|
||||
// due to step holds
|
||||
if setup.expectDatasetIsBusyErrorWhenDestroySnapshotWhilePartiallyReplicated {
|
||||
ctx.Logf("i=%v", i)
|
||||
require.Error(ctx, err)
|
||||
require.Contains(ctx, err.Error(), "dataset is busy")
|
||||
dse, ok := err.(*zfs.DestroySnapshotsError)
|
||||
require.True(ctx, ok, "expected *zfs.DestroySnapshotsError, got %T: %s", err, err)
|
||||
require.True(ctx, dse.AllReasonIsHold(), "expected hold reason, got %v", dse.Reason)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,11 +757,13 @@ func ReplicationIncrementalDestroysStepHoldsIffIncrementalStepHoldsAreDisabledBu
|
||||
func ReplicationStepCompletedLostBehavior__GuaranteeResumability(ctx *platformtest.Context) {
|
||||
scenario := replicationStepCompletedLostBehavior_impl(ctx, pdu.ReplicationGuaranteeKind_GuaranteeResumability)
|
||||
|
||||
require.Error(ctx, scenario.deleteSfs1Err, "protected by holds")
|
||||
require.Contains(ctx, scenario.deleteSfs1Err.Error(), "dataset is busy")
|
||||
dse1, ok := scenario.deleteSfs1Err.(*zfs.DestroySnapshotsError)
|
||||
require.True(ctx, ok, "expected *zfs.DestroySnapshotsError, got %T: %s", scenario.deleteSfs1Err, scenario.deleteSfs1Err)
|
||||
require.True(ctx, dse1.AllReasonIsHold(), "expected hold reason, got %v", dse1.Reason)
|
||||
|
||||
require.Error(ctx, scenario.deleteSfs2Err, "protected by holds")
|
||||
require.Contains(ctx, scenario.deleteSfs2Err.Error(), "dataset is busy")
|
||||
dse2, ok := scenario.deleteSfs2Err.(*zfs.DestroySnapshotsError)
|
||||
require.True(ctx, ok, "expected *zfs.DestroySnapshotsError, got %T: %s", scenario.deleteSfs2Err, scenario.deleteSfs2Err)
|
||||
require.True(ctx, dse2.AllReasonIsHold(), "expected hold reason, got %v", dse2.Reason)
|
||||
|
||||
require.Nil(ctx, scenario.finalReport.Error())
|
||||
_ = fsversion(ctx, scenario.rfs, "@3") // @3 ade it to the other side
|
||||
|
||||
@@ -31,7 +31,7 @@ func UndestroyableSnapshotParsing(t *platformtest.Context) {
|
||||
panic(dse.Filesystem)
|
||||
}
|
||||
require.Equal(t, []string{"4 5 6"}, dse.Undestroyable)
|
||||
require.Equal(t, []string{"dataset is busy"}, dse.Reason)
|
||||
require.True(t, dse.AllReasonIsHold(), "expected hold reason, got %v", dse.Reason)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1723,6 +1723,20 @@ type DestroySnapshotsError struct {
|
||||
Reason []string
|
||||
}
|
||||
|
||||
var destroySnapshotsReasonHeldRegexp = regexp.MustCompile(`^it's being held\. Run 'zfs holds -r .+' to see holders\.$`)
|
||||
|
||||
// AllReasonIsHold returns true if every undestroyable snapshot failed because
|
||||
// it is held. ZFS < 2.4 reports "dataset is busy", ZFS >= 2.4 reports
|
||||
// "it's being held. Run 'zfs holds -r <snapshot>' to see holders."
|
||||
func (e *DestroySnapshotsError) AllReasonIsHold() bool {
|
||||
for _, r := range e.Reason {
|
||||
if r != "dataset is busy" && !destroySnapshotsReasonHeldRegexp.MatchString(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (e *DestroySnapshotsError) Error() string {
|
||||
if len(e.Undestroyable) != len(e.Reason) {
|
||||
panic(fmt.Sprintf("%v != %v", len(e.Undestroyable), len(e.Reason)))
|
||||
|
||||
Reference in New Issue
Block a user