Compare commits

...

6 Commits

Author SHA1 Message Date
Christian Schwarz 6ccaf3b902 WIP: fix encrypt-on-recv
fixes https://github.com/zrepl/zrepl/issues/504
2021-08-07 19:14:45 +02:00
Christian Schwarz bcfcd7a134 docs / CI: stop creating churn with doc commits & commit as zreplbot@ 2021-07-08 17:07:24 +02:00
Matthias Freund bf1276f767 status: port status-v1 ETA calculation patch
Must have forgotten to integrate it into the status-v2 branch at the
time.

refs https://github.com/zrepl/zrepl/issues/98#issuecomment-872154091

cc @dcdamien
2021-07-08 15:00:26 +02:00
James W. Brinkerhoff IV 9fa7a18351 docs: quickstart: external_disk: fix typo in example 'derive -> drive'
closes #472
2021-04-19 23:36:03 +02:00
sre 50e8ee4549 docs: apt repo: use sudo in the snippet that sets up the repo
I generally like when snippets are provided in a way which could be used without running as root, and uses sudo when applicable. This change allows for this.

It will, however print out one extra line, which is possible to remove by adding '>/dev/null' after '/etc/apt/sources.list.d/zrepl.list'.

closes #461
2021-04-17 21:50:36 +02:00
Lapo Luchini 3b5a1a8b9a docs/monitoring: change suggested prometheus port to 9811
Change to 9811 as registered with the prometheus project now.

Closes #444.
2021-03-28 18:18:02 +02:00
8 changed files with 89 additions and 20 deletions
+1 -1
View File
@@ -358,7 +358,7 @@ jobs:
subcommand: docdep subcommand: docdep
- run: - run:
command: | command: |
git config --global user.email "me@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"
# 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
+32
View File
@@ -356,9 +356,17 @@ func renderReplicationReport(t *stringbuilder.B, rep *report.Report, history *by
// Progress: [---------------] // Progress: [---------------]
expected, replicated, containsInvalidSizeEstimates := latest.BytesSum() expected, replicated, containsInvalidSizeEstimates := latest.BytesSum()
rate, changeCount := history.Update(replicated) rate, changeCount := history.Update(replicated)
eta := time.Duration(0)
if rate > 0 {
eta = time.Duration((expected-replicated)/rate) * time.Second
}
t.Write("Progress: ") t.Write("Progress: ")
t.DrawBar(50, replicated, expected, changeCount) t.DrawBar(50, replicated, expected, changeCount)
t.Write(fmt.Sprintf(" %s / %s @ %s/s", ByteCountBinary(replicated), ByteCountBinary(expected), ByteCountBinary(rate))) t.Write(fmt.Sprintf(" %s / %s @ %s/s", ByteCountBinary(replicated), ByteCountBinary(expected), ByteCountBinary(rate)))
if eta != 0 {
t.Write(fmt.Sprintf(" (%s remaining)", humanizeDuration(eta)))
}
t.Newline() t.Newline()
if containsInvalidSizeEstimates { if containsInvalidSizeEstimates {
t.Write("NOTE: not all steps could be size-estimated, total estimate is likely imprecise!") t.Write("NOTE: not all steps could be size-estimated, total estimate is likely imprecise!")
@@ -383,6 +391,30 @@ func renderReplicationReport(t *stringbuilder.B, rep *report.Report, history *by
} }
} }
func humanizeDuration(duration time.Duration) string {
days := int64(duration.Hours() / 24)
hours := int64(math.Mod(duration.Hours(), 24))
minutes := int64(math.Mod(duration.Minutes(), 60))
seconds := int64(math.Mod(duration.Seconds(), 60))
var parts []string
force := false
chunks := []int64{days, hours, minutes, seconds}
for i, chunk := range chunks {
if force || chunk > 0 {
padding := 0
if force {
padding = 2
}
parts = append(parts, fmt.Sprintf("%*d%c", padding, chunk, "dhms"[i]))
force = true
}
}
return strings.Join(parts, " ")
}
func renderPrunerReport(t *stringbuilder.B, r *pruner.Report, fsfilter FilterFunc) { func renderPrunerReport(t *stringbuilder.B, r *pruner.Report, fsfilter FilterFunc) {
if r == nil { if r == nil {
t.Printf("...\n") t.Printf("...\n")
+2 -2
View File
@@ -70,9 +70,9 @@ func TestPrometheusMonitoring(t *testing.T) {
global: global:
monitoring: monitoring:
- type: prometheus - type: prometheus
listen: ':9091' listen: ':9811'
`) `)
assert.Equal(t, ":9091", conf.Global.Monitoring[0].Ret.(*PrometheusMonitoring).Listen) assert.Equal(t, ":9811", conf.Global.Monitoring[0].Ret.(*PrometheusMonitoring).Listen)
} }
func TestSyslogLoggingOutletFacility(t *testing.T) { func TestSyslogLoggingOutletFacility(t *testing.T) {
@@ -5,7 +5,7 @@
# quick start section which inlines this example. # quick start section which inlines this example.
# #
# CUSTOMIZATIONS YOU WILL LIKELY WANT TO APPLY: # CUSTOMIZATIONS YOU WILL LIKELY WANT TO APPLY:
# - adjust the name of the production pool `system` in the `filesystems` filter of jobs `snapjob` and `push_to_derive` # - adjust the name of the production pool `system` in the `filesystems` filter of jobs `snapjob` and `push_to_drive`
# - adjust the name of the backup pool `backuppool` in the `backuppool_sink` job # - adjust the name of the backup pool `backuppool` in the `backuppool_sink` job
# - adjust the occurences of `myhostname` to the name of the system you are backing up (cannot be easily changed once you start replicating) # - adjust the occurences of `myhostname` to the name of the system you are backing up (cannot be easily changed once you start replicating)
# - make sure the `zrepl_` prefix is not being used by any other zfs tools you might have installed (it likely isn't) # - make sure the `zrepl_` prefix is not being used by any other zfs tools you might have installed (it likely isn't)
@@ -85,4 +85,4 @@ jobs:
root_fs: "backuppool/zrepl/sink" root_fs: "backuppool/zrepl/sink"
serve: serve:
type: local type: local
listener_name: backuppool_sink listener_name: backuppool_sink
+2 -2
View File
@@ -13,7 +13,7 @@ Prometheus & Grafana
-------------------- --------------------
zrepl can expose `Prometheus metrics <https://prometheus.io/docs/instrumenting/exposition_formats/>`_ via HTTP. zrepl can expose `Prometheus metrics <https://prometheus.io/docs/instrumenting/exposition_formats/>`_ via HTTP.
The ``listen`` attribute is a `net.Listen <https://golang.org/pkg/net/#Listen>`_ string for tcp, e.g. ``:9091`` or ``127.0.0.1:9091``. The ``listen`` attribute is a `net.Listen <https://golang.org/pkg/net/#Listen>`_ string for tcp, e.g. ``:9811`` or ``127.0.0.1:9811`` (port 9811 was reserved to zrepl `on the official list <https://github.com/prometheus/prometheus/wiki/Default-port-allocations/_compare/43e495dd251ee328ac0d08b58084665b5c0f7a7e...459195059b55b414193ebeb80c5ba463d2606951>`_).
The ``listen_freebind`` attribute is :ref:`explained here <listen-freebind-explanation>`. The ``listen_freebind`` attribute is :ref:`explained here <listen-freebind-explanation>`.
The Prometheus monitoring job appears in the ``zrepl control`` job list and may be specified **at most once**. The Prometheus monitoring job appears in the ``zrepl control`` job list and may be specified **at most once**.
@@ -30,7 +30,7 @@ The dashboard also contains some advice on which metrics are important to monito
global: global:
monitoring: monitoring:
- type: prometheus - type: prometheus
listen: ':9091' listen: ':9811'
listen_freebind: true # optional, default false listen_freebind: true # optional, default false
+4 -4
View File
@@ -13,13 +13,13 @@ The following snippet configure the repository for your Debian or Ubuntu release
:: ::
apt update && apt install curl gnupg lsb-release; \ sudo apt update && sudo apt install curl gnupg lsb-release; \
ARCH="$(dpkg --print-architecture)"; \ ARCH="$(dpkg --print-architecture)"; \
CODENAME="$(lsb_release -i -s | tr '[:upper:]' '[:lower:]') $(lsb_release -c -s | tr '[:upper:]' '[:lower:]')"; \ CODENAME="$(lsb_release -i -s | tr '[:upper:]' '[:lower:]') $(lsb_release -c -s | tr '[:upper:]' '[:lower:]')"; \
echo "Using Distro and Codename: $CODENAME"; \ echo "Using Distro and Codename: $CODENAME"; \
(curl https://zrepl.cschwarz.com/apt/apt-key.asc | apt-key add -) && \ (curl https://zrepl.cschwarz.com/apt/apt-key.asc | sudo apt-key add -) && \
(echo "deb [arch=$ARCH] https://zrepl.cschwarz.com/apt/$CODENAME main" > /etc/apt/sources.list.d/zrepl.list) && \ (echo "deb [arch=$ARCH] https://zrepl.cschwarz.com/apt/$CODENAME main" | sudo tee /etc/apt/sources.list.d/zrepl.list) && \
apt update sudo apt update
.. NOTE:: .. NOTE::
+12 -9
View File
@@ -1,6 +1,5 @@
#!/bin/bash #!/bin/bash
set -eo pipefail set -euo pipefail
NON_INTERACTIVE=false NON_INTERACTIVE=false
DO_CLONE=false DO_CLONE=false
@@ -13,7 +12,7 @@ while getopts "ca" arg; do
DO_CLONE=true DO_CLONE=true
;; ;;
*) *)
echo invalid option echo "invalid option '-$arg'"
exit 1 exit 1
;; ;;
esac esac
@@ -27,11 +26,6 @@ checkout_repo_msg() {
echo "clone ${GHPAGESREPO} to ${PUBLICDIR}:" echo "clone ${GHPAGESREPO} to ${PUBLICDIR}:"
} }
exit_msg() {
echo "error, exiting..."
}
trap exit_msg EXIT
if ! type sphinx-versioning >/dev/null; then if ! type sphinx-versioning >/dev/null; then
echo "install sphinx-versioning and come back" echo "install sphinx-versioning and come back"
exit 1 exit 1
@@ -71,6 +65,9 @@ git reset --hard origin/master
echo "cleaning GitHub pages repo" echo "cleaning GitHub pages repo"
git rm -rf . git rm -rf .
cat > .gitignore <<EOF
**/.doctrees
EOF
popd popd
@@ -96,7 +93,13 @@ COMMIT_MSG="sphinx-versioning render from publish.sh - $(date -u) - ${CURRENT_CO
pushd "$PUBLICDIR" pushd "$PUBLICDIR"
echo "adding and commiting all changes in GitHub pages repo" echo "adding and commiting all changes in GitHub pages repo"
git add .gitignore
git add -A git add -A
git commit -m "$COMMIT_MSG" if [ "$(git status --porcelain)" != "" ]; then
git commit -m "$COMMIT_MSG"
else
echo "nothing to commit"
fi
echo "pushing to GitHub pages repo"
git push origin master git push origin master
+34
View File
@@ -90,6 +90,40 @@ func ZFSCreatePlaceholderFilesystem(ctx context.Context, fs *DatasetPath, parent
"-o", fmt.Sprintf("%s=%s", PlaceholderPropertyName, placeholderPropertyOn), "-o", fmt.Sprintf("%s=%s", PlaceholderPropertyName, placeholderPropertyOn),
"-o", "mountpoint=none", "-o", "mountpoint=none",
} }
// xxx handle encryption not supported
props, err := zfsGet(ctx, parent.ToString(), []string{"keystatus"}, SourceAny)
if err != nil {
return errors.Wrap(err, "cannot determine key status")
}
keystatus := props.Get("keystatus") // xxx ability to distringuish `-` from ``
if keystatus == "" {
// parent is unencrypted => placeholder inherits encryption
} else if keystatus == "available" {
// parent is encrypted but since the key is loaded we can create an encrypted placeholder dataset
// without `-o encryption=off`
} else if keystatus == "unavailable" {
// parent is encrypted but keys are not loaded, either because
// 1) it's a send-encrypted dataset, or because
// 2) the user forgot to zfs load-key the root_fs or above
// In both cases we can't create an encrypted placeholder dataset.
// In case 1), we want to create an unencrypted placeholder through `-o encryption=off`.
// In case 2), `-o encryption=off` is harmful security-wise because it breaks the encrypt-on-receiver use case (https://github.com/zrepl/zrepl/issues/504)
// I.e., all children of the placeholder won't be encrypted because they inherit encryption=off
//
// => we could attempt to distinguish the cases by being more context sensitive
// (i.e., check whether the encryption root is root_fs or a parent thereof)
// However, that's always going to be imprecise, and a wrong decision there is harmful security-wise.
//
// => thus the safe choice is to never use `-o encryption=off` by default
// only if we know for sure that the stream is encrypted should we create placeholders with `-o encryption=off`
// => this knowledge can be achieved through one of the following means:
// a) have the sender indicate it to us in the RPC request (it's ok to trust them in this particular case since lying only hurts _their_ data's confidentiality)
// b) have the user acknowledge it in the receiver config
} else {
return errors.Errorf("unknown keystatus value %q for dataset %q", keystatus, parent.ToString())
}
if parentEncrypted, err := ZFSGetEncryptionEnabled(ctx, parent.ToString()); err != nil { if parentEncrypted, err := ZFSGetEncryptionEnabled(ctx, parent.ToString()); err != nil {
return errors.Wrap(err, "cannot determine encryption support") return errors.Wrap(err, "cannot determine encryption support")
} else if parentEncrypted { } else if parentEncrypted {