Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ccaf3b902 | |||
| bcfcd7a134 | |||
| bf1276f767 | |||
| 9fa7a18351 |
@@ -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")
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
+11
-8
@@ -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
|
||||||
|
if [ "$(git status --porcelain)" != "" ]; then
|
||||||
git commit -m "$COMMIT_MSG"
|
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