Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ccaf3b902 | |||
| bcfcd7a134 | |||
| bf1276f767 | |||
| 9fa7a18351 | |||
| 50e8ee4549 | |||
| 3b5a1a8b9a |
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user