diff --git a/Makefile b/Makefile index 41c4f3ef5..ce752cb16 100644 --- a/Makefile +++ b/Makefile @@ -74,8 +74,18 @@ else GCR_IMAGE_TAGS ?= $(GCR_IMAGE):$(VERSION) endif +# check buildx is enabled +# macOS/Windows docker cli without Docker Desktop license: https://github.com/abiosoft/colima +# To add buildx to docker cli: https://github.com/abiosoft/colima/discussions/273#discussioncomment-2684502 ifeq ($(shell docker buildx inspect 2>/dev/null | awk '/Status/ { print $$2 }'), running) BUILDX_ENABLED ?= true +# if emulated docker cli from podman, assume enabled +# emulated docker cli from podman: https://podman-desktop.io/docs/migrating-from-docker/emulating-docker-cli-with-podman +# podman known issues: +# - on remote podman, such as on macOS, +# --output issue: https://github.com/containers/podman/issues/15922 +else ifeq ($(shell cat $(shell which docker) | grep -c "exec podman"), 1) + BUILDX_ENABLED ?= true else BUILDX_ENABLED ?= false endif diff --git a/changelogs/unreleased/7438-Lyndon-Li b/changelogs/unreleased/7438-Lyndon-Li new file mode 100644 index 000000000..9c1a7e3f8 --- /dev/null +++ b/changelogs/unreleased/7438-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #7281, batch delete snapshots in the same repo \ No newline at end of file diff --git a/changelogs/unreleased/7549-ywk253100 b/changelogs/unreleased/7549-ywk253100 new file mode 100644 index 000000000..898680103 --- /dev/null +++ b/changelogs/unreleased/7549-ywk253100 @@ -0,0 +1 @@ +Support certificate-based authentication for Azure \ No newline at end of file diff --git a/changelogs/unreleased/7559-Lyndon-Li b/changelogs/unreleased/7559-Lyndon-Li new file mode 100644 index 000000000..6ee380f6f --- /dev/null +++ b/changelogs/unreleased/7559-Lyndon-Li @@ -0,0 +1 @@ +Bump up Kopia to v0.16.0 and open kopia repo with no index change \ No newline at end of file diff --git a/go.mod b/go.mod index 82e08a8b5..418ae44c9 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,13 @@ go 1.21 toolchain go1.21.3 require ( - cloud.google.com/go/storage v1.33.0 + cloud.google.com/go/storage v1.39.1 github.com/Azure/azure-pipeline-go v0.2.3 github.com/Azure/azure-sdk-for-go v67.2.0+incompatible - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.3.0 - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 github.com/Azure/azure-storage-blob-go v0.15.0 github.com/Azure/go-autorest/autorest v0.11.27 github.com/Azure/go-autorest/autorest/azure/auth v0.5.8 @@ -25,35 +25,35 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 github.com/bombsimon/logrusr/v3 v3.0.0 github.com/evanphx/json-patch v5.6.0+incompatible - github.com/fatih/color v1.15.0 + github.com/fatih/color v1.16.0 github.com/gobwas/glob v0.2.3 - github.com/golang/protobuf v1.5.3 + github.com/golang/protobuf v1.5.4 github.com/google/go-cmp v0.6.0 - github.com/google/uuid v1.3.1 + github.com/google/uuid v1.6.0 github.com/hashicorp/go-hclog v0.14.1 github.com/hashicorp/go-plugin v1.6.0 github.com/joho/godotenv v1.3.0 - github.com/kopia/kopia v0.14.1 + github.com/kopia/kopia v0.16.0 github.com/kubernetes-csi/external-snapshotter/client/v7 v7.0.0 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.30.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.18.0 + github.com/prometheus/client_golang v1.19.0 github.com/robfig/cron v1.1.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/afero v1.6.0 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/vmware-tanzu/crash-diagnostics v0.3.7 - go.uber.org/zap v1.26.0 + go.uber.org/zap v1.27.0 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 - golang.org/x/mod v0.13.0 - golang.org/x/net v0.19.0 - golang.org/x/oauth2 v0.13.0 + golang.org/x/mod v0.16.0 + golang.org/x/net v0.22.0 + golang.org/x/oauth2 v0.18.0 golang.org/x/text v0.14.0 - google.golang.org/api v0.146.0 - google.golang.org/grpc v1.58.3 + google.golang.org/api v0.170.0 + google.golang.org/grpc v1.62.1 google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.29.0 @@ -71,11 +71,11 @@ require ( ) require ( - cloud.google.com/go v0.110.7 // indirect - cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute v1.24.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 // indirect @@ -83,7 +83,7 @@ require ( github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect @@ -106,23 +106,25 @@ require ( github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.8.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.2 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -131,19 +133,18 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.0 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/pgzip v1.2.6 // indirect - github.com/klauspost/reedsolomon v1.11.8 // indirect + github.com/klauspost/reedsolomon v1.12.1 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-ieproxy v0.0.1 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/minio-go/v7 v7.0.63 // indirect + github.com/minio/minio-go/v7 v7.0.69 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect @@ -152,36 +153,38 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/mxk/go-vss v1.2.0 // indirect github.com/natefinch/atomic v1.0.1 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/oklog/run v1.0.0 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect - github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.50.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rs/xid v1.5.0 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/vladimirvivien/gexe v0.1.1 // indirect github.com/zeebo/blake3 v0.2.3 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect go.starlark.net v0.0.0-20201006213952-227f4aabceb5 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.15.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/time v0.5.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect @@ -191,4 +194,4 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) -replace github.com/kopia/kopia => github.com/project-velero/kopia v0.0.0-20231023031817-cf7bbc7f8519 +replace github.com/kopia/kopia => github.com/project-velero/kopia v0.0.0-20240325091347-b901e3bfe3fd diff --git a/go.sum b/go.sum index 66f1d569b..59fb6b8d0 100644 --- a/go.sum +++ b/go.sum @@ -19,23 +19,23 @@ cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmW cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -45,27 +45,27 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.33.0 h1:PVrDOkIC8qQVa1P3SXGpQvfuJhN2LHOoyZvWs8D2X5M= -cloud.google.com/go/storage v1.33.0/go.mod h1:Hhh/dogNRGca7IWv1RC2YqEn0c0G77ctA/OxflYkiD8= +cloud.google.com/go/storage v1.39.1 h1:MvraqHKhogCOTXTlct/9C3K3+Uy2jBmFYb3/Sp6dVtY= +cloud.google.com/go/storage v1.39.1/go.mod h1:xK6xZmxZmo+fyP7+DEF6FhNc24/JAe95OLyOHCXFH1o= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= github.com/Azure/azure-sdk-for-go v67.2.0+incompatible h1:Uu/Ww6ernvPTrpq31kITVTIm/I5jlJ1wjtEH/bmSB2k= github.com/Azure/azure-sdk-for-go v67.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2/go.mod h1:FbdwsQ2EzwvXxOPcMFYO8ogEc9uMMIj3YkmCdXdAFmk= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.3.0 h1:LcJtQjCXJUm1s7JpUHZvu+bpgURhCatxVNbGADXniX0= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.3.0/go.mod h1:+OgGVo0Httq7N5oayfvaLQ/Jq+2gJdqfp++Hyyl7Tws= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 h1:nVocQV40OQne5613EeLayJiRAJuKlBGy+m22qWG+WRg= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0/go.mod h1:7QJP7dr2wznCMeqIrhMgWGf7XpAQnVrJqDm9nvV3Cu4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 h1:fXPMAmuh0gDuRDey0atC8cXBuKIlqCzCkL8sm1n9Ov0= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1/go.mod h1:SUZc9YRRHfx2+FAQKNDGrssXehqLpxmwRv2mC/5ntj4= github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7OgcSXPpwp3tx6qk= github.com/Azure/azure-storage-blob-go v0.15.0/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9BsJWPcne7GB7onqlPvz58= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= @@ -110,8 +110,8 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5 h1:IEjq88XO4PuBDcvmjQJcQGg+w+UaafSy8G5Kcb5tBhI= @@ -259,8 +259,10 @@ github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.13.1 h1:xVm/f9seEhZFL9+n5kv5XLrGwy6elc4V9v/XFY2vmd8= @@ -293,6 +295,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -332,8 +336,8 @@ github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -367,8 +371,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= @@ -421,20 +425,21 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= +github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -447,8 +452,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hanwen/go-fuse/v2 v2.4.0 h1:12OhD7CkXXQdvxG2osIdBQLdXh+nmLXY9unkUIe/xaU= -github.com/hanwen/go-fuse/v2 v2.4.0/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs= +github.com/hanwen/go-fuse/v2 v2.5.0 h1:JSJcwHQ1V9EGRy6QsosoLDMX6HaLdzyLOJpKdPqDt9k= +github.com/hanwen/go-fuse/v2 v2.5.0/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= @@ -511,16 +516,16 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= -github.com/klauspost/reedsolomon v1.11.8 h1:s8RpUW5TK4hjr+djiOpbZJB4ksx+TdYbRH7vHQpwPOY= -github.com/klauspost/reedsolomon v1.11.8/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A= +github.com/klauspost/reedsolomon v1.12.1 h1:NhWgum1efX1x58daOBGCFWcxtEhOhXKKl1HAPQUp03Q= +github.com/klauspost/reedsolomon v1.12.1/go.mod h1:nEi5Kjb6QqtbofI6s+cbG/j1da11c96IBYBSnVGtuBs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kopia/htmluibuild v0.0.1-0.20231019063300-75c2a788c7d0 h1:TvupyyfbUZzsO4DQJpQhKZnUa61xERcJ+ejCbHWG2NY= @@ -564,18 +569,16 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.63 h1:GbZ2oCvaUdgT5640WJOpyDhhDxvknAJU2/T3yurwcbQ= -github.com/minio/minio-go/v7 v7.0.63/go.mod h1:Q6X7Qjb7WMhvG65qKf4gUgA5XaiSox74kR1uAEjxRS4= +github.com/minio/minio-go/v7 v7.0.69 h1:l8AnsQFyY1xiwa/DaQskY4NXSLA2yrGsW5iD9nRPVS0= +github.com/minio/minio-go/v7 v7.0.69/go.mod h1:XAvOPJQ5Xlzk5o3o/ArO2NMbhSGkimC+bpW/ngRKDmQ= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -606,6 +609,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/mxk/go-vss v1.2.0 h1:JpdOPc/P6B3XyRoddn0iMiG/ADBi3AuEsv8RlTb+JeE= +github.com/mxk/go-vss v1.2.0/go.mod h1:ZQ4yFxCG54vqPnCd+p2IxAe5jwZdz56wSjbwzBXiFd8= github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -637,8 +642,8 @@ github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -648,26 +653,26 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/project-velero/kopia v0.0.0-20231023031817-cf7bbc7f8519 h1:DiikAMR1wBIY6oFoN76WEJz4f+6OM99ZiGzZ9m9v32I= -github.com/project-velero/kopia v0.0.0-20231023031817-cf7bbc7f8519/go.mod h1:V/zpEMjxzqEf3lF52m0b0nAIVQGolPYIOXRjVxeK1j0= +github.com/project-velero/kopia v0.0.0-20240325091347-b901e3bfe3fd h1:mjUqOG9msvzZwkoOVZxtSwFp2mISHA2g2u0T8KtzD6I= +github.com/project-velero/kopia v0.0.0-20240325091347-b901e3bfe3fd/go.mod h1:ME65fdntswtj0aI+EGq53/869f7tP5ptVTVoQRDcbO4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ= +github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -728,8 +733,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -739,11 +745,11 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tg123/go-htpasswd v1.2.1 h1:i4wfsX1KvvkyoMiHZzjS0VzbAPWfxzI8INcZAKtutoU= -github.com/tg123/go-htpasswd v1.2.1/go.mod h1:erHp1B86KXdwQf1X5ZrLb7erXZnWueEQezb2dql4q58= +github.com/tg123/go-htpasswd v1.2.2 h1:tmNccDsQ+wYsoRfiONzIhDm5OkVHQzN3w4FOBAlN6BY= +github.com/tg123/go-htpasswd v1.2.2/go.mod h1:FcIrK0J+6zptgVwK1JDlqyajW/1B4PtuJ/FLWl7nx8A= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -760,8 +766,9 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms= -github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zalando/go-keyring v0.2.4 h1:wi2xxTqdiwMKbM6TWwi+uJCG/Tum2UV0jqaQhCa9/68= +github.com/zalando/go-keyring v0.2.4/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= @@ -784,12 +791,18 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.starlark.net v0.0.0-20201006213952-227f4aabceb5 h1:ApvY/1gw+Yiqb/FKeks3KnVPWpkR3xzij82XPKLjJVw= go.starlark.net v0.0.0-20201006213952-227f4aabceb5/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU= @@ -804,8 +817,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -823,8 +836,8 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -862,8 +875,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -913,8 +927,9 @@ golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -929,8 +944,8 @@ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -942,8 +957,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1007,24 +1023,26 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1034,6 +1052,7 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1042,8 +1061,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1102,14 +1121,15 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -1134,16 +1154,17 @@ google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjR google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/api v0.146.0 h1:9aBYT4vQXt9dhCuLNfwfd3zpwu8atg0yPkjBymwSrOM= -google.golang.org/api v0.146.0/go.mod h1:OARJqIfoYjXJj4C1AiBSXYZt03qsoz8FQYU6fBEfrHM= +google.golang.org/api v0.170.0 h1:zMaruDePM88zxZBG+NG8+reALO2rfLhe/JShitLyT48= +google.golang.org/api v0.170.0/go.mod h1:/xql9M2btF85xac/VAm4PsLMTLVGUOpq4BE9R8jyNy8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1186,12 +1207,12 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA= -google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78 h1:SzXBGiWM1LNVYLCRP3e0/Gsze804l4jGoJ5lYysEO5I= +google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2 h1:9IZDv+/GcI6u+a4jRFRLxQs0RUCfavGfoOgEW6jpkI0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1213,8 +1234,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/golangci.yaml b/golangci.yaml index 88b3b7723..97ee4229d 100644 --- a/golangci.yaml +++ b/golangci.yaml @@ -255,6 +255,23 @@ linters-settings: rowserrcheck: packages: - github.com/jmoiron/sqlx + testifylint: + # TODO: enable them all + disable: + - bool-compare + - compares + - error-is-as + - error-nil + - expected-actual + - go-require + - float-compare + - require-error + - suite-dont-use-pkg + - suite-extra-assert-call + - suite-thelper + enable: + - empty + - len testpackage: # regexp pattern to skip files skip-regexp: (export|internal)_test\.go @@ -302,8 +319,10 @@ linters: - bodyclose - dogsled - durationcheck + - dupword - errcheck - exportloopref + - errchkjson - goconst - gofmt - goheader @@ -312,26 +331,25 @@ linters: - gosec - gosimple - govet + - ginkgolinter - importas - ineffassign - misspell - nakedret - nosprintfhostport + - nilerr + - noctx + - nolintlint + - revive - staticcheck - stylecheck - - revive + - testifylint - typecheck - unconvert - unparam - unused - usestdlibvars - whitespace - - dupword - - errchkjson - - ginkgolinter - - nilerr - - noctx - - nolintlint fast: false diff --git a/hack/build-image/Dockerfile b/hack/build-image/Dockerfile index 7165f9370..a60266fc7 100644 --- a/hack/build-image/Dockerfile +++ b/hack/build-image/Dockerfile @@ -93,7 +93,7 @@ RUN ARCH=$(go env GOARCH) && \ chmod +x /usr/bin/goreleaser # get golangci-lint -RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.54.2 +RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.55.0 # install kubectl RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/$(go env GOARCH)/kubectl diff --git a/internal/hook/item_hook_handler_test.go b/internal/hook/item_hook_handler_test.go index f8efb5f08..8b73572b6 100644 --- a/internal/hook/item_hook_handler_test.go +++ b/internal/hook/item_hook_handler_test.go @@ -2474,7 +2474,7 @@ func TestRestoreHookTrackerAdd(t *testing.T) { t.Run(tc.name, func(t *testing.T) { _, _ = GroupRestoreExecHooks(tc.resourceRestoreHooks, tc.pod, velerotest.NewLogger(), tc.hookTracker) tracker := tc.hookTracker.GetTracker() - assert.Equal(t, tc.expectedCnt, len(tracker)) + assert.Len(t, tracker, tc.expectedCnt) }) } } diff --git a/pkg/backup/backup_pv_action_test.go b/pkg/backup/backup_pv_action_test.go index d9e0a5b33..d9d2b52cf 100644 --- a/pkg/backup/backup_pv_action_test.go +++ b/pkg/backup/backup_pv_action_test.go @@ -50,14 +50,14 @@ func TestBackupPVAction(t *testing.T) { // and no additional items _, additional, err := a.Execute(pvc, backup) assert.NoError(t, err) - assert.Len(t, additional, 0) + assert.Empty(t, additional) // empty spec.volumeName should result in no error // and no additional items pvc.Object["spec"].(map[string]interface{})["volumeName"] = "" _, additional, err = a.Execute(pvc, backup) assert.NoError(t, err) - assert.Len(t, additional, 0) + assert.Empty(t, additional) // Action should clean the spec.Selector when the StorageClassName is not set. input := builder.ForPersistentVolumeClaim("abc", "abc").VolumeName("pv").Selector(&metav1.LabelSelector{MatchLabels: map[string]string{"abc": "abc"}}).Phase(corev1.ClaimBound).Result() @@ -119,21 +119,21 @@ func TestBackupPVAction(t *testing.T) { pvc.Object["spec"].(map[string]interface{})["volumeName"] = "myVolume" _, additional, err = a.Execute(pvc, backup) require.NoError(t, err) - require.Len(t, additional, 0) + require.Empty(t, additional) // non-empty spec.volumeName when status.phase is 'Pending' // should result in no error and no additional items pvc.Object["status"].(map[string]interface{})["phase"] = corev1api.ClaimPending _, additional, err = a.Execute(pvc, backup) require.NoError(t, err) - require.Len(t, additional, 0) + require.Empty(t, additional) // non-empty spec.volumeName when status.phase is 'Lost' // should result in no error and no additional items pvc.Object["status"].(map[string]interface{})["phase"] = corev1api.ClaimLost _, additional, err = a.Execute(pvc, backup) require.NoError(t, err) - require.Len(t, additional, 0) + require.Empty(t, additional) // non-empty spec.volumeName when status.phase is 'Bound' // should result in no error and one additional item for the PV @@ -148,5 +148,5 @@ func TestBackupPVAction(t *testing.T) { pvc.Object["spec"].(map[string]interface{})["volumeName"] = "" _, additional, err = a.Execute(pvc, backup) assert.NoError(t, err) - assert.Len(t, additional, 0) + assert.Empty(t, additional) } diff --git a/pkg/backup/pv_skip_tracker_test.go b/pkg/backup/pv_skip_tracker_test.go index 8e75a808c..bd258dd85 100644 --- a/pkg/backup/pv_skip_tracker_test.go +++ b/pkg/backup/pv_skip_tracker_test.go @@ -60,5 +60,5 @@ func TestTrackUntrack(t *testing.T) { tracker.Track("pv3", podVolumeApproach, "it's set to opt-out") tracker.Untrack("pv3") tracker.Track("pv3", csiSnapshotApproach, "not applicable for CSI ") - assert.Equal(t, 0, len(tracker.Summary())) + assert.Empty(t, tracker.Summary()) } diff --git a/pkg/client/config_test.go b/pkg/client/config_test.go index 938345b5a..56b198f79 100644 --- a/pkg/client/config_test.go +++ b/pkg/client/config_test.go @@ -91,7 +91,7 @@ func TestConfigOperations(t *testing.T) { // Test Features feature := savedConfig.Features() - assert.Equal(t, 1, len(feature)) + assert.Len(t, feature, 1) assert.Equal(t, expectedFeature, feature[0]) // Test Colorized diff --git a/pkg/cmd/cli/backuplocation/delete_test.go b/pkg/cmd/cli/backuplocation/delete_test.go index 9736c9883..0ed5d3130 100644 --- a/pkg/cmd/cli/backuplocation/delete_test.go +++ b/pkg/cmd/cli/backuplocation/delete_test.go @@ -89,13 +89,13 @@ func TestDeleteFunctions(t *testing.T) { bkrepoList := velerov1api.BackupRepositoryList{} t.Run("findAssociatedBackups", func(t *testing.T) { bkList, e := findAssociatedBackups(kbclient, "bk-loc-1", "ns1") - assert.Equal(t, 0, len(bkList.Items)) + assert.Empty(t, bkList.Items) assert.NoError(t, e) }) t.Run("findAssociatedBackupRepos", func(t *testing.T) { bkrepoList, e := findAssociatedBackupRepos(kbclient, "bk-loc-1", "ns1") - assert.Equal(t, 0, len(bkrepoList.Items)) + assert.Empty(t, bkrepoList.Items) assert.NoError(t, e) }) @@ -104,7 +104,7 @@ func TestDeleteFunctions(t *testing.T) { bk.Name = "bk-name-last" bkList.Items = append(bkList.Items, bk) errList := deleteBackups(kbclient, bkList) - assert.Equal(t, 1, len(errList)) + assert.Len(t, errList, 1) assert.Contains(t, errList[0].Error(), fmt.Sprintf("delete backup \"%s\" associated with deleted BSL: backups.velero.io \"%s\" not found", bk.Name, bk.Name)) }) t.Run("deleteBackupRepos", func(t *testing.T) { @@ -112,7 +112,7 @@ func TestDeleteFunctions(t *testing.T) { bkrepo.Name = "bk-repo-name-last" bkrepoList.Items = append(bkrepoList.Items, bkrepo) errList := deleteBackupRepos(kbclient, bkrepoList) - assert.Equal(t, 1, len(errList)) + assert.Len(t, errList, 1) assert.Contains(t, errList[0].Error(), fmt.Sprintf("delete backup repository \"%s\" associated with deleted BSL: backuprepositories.velero.io \"%s\" not found", bkrepo.Name, bkrepo.Name)) }) } diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index 6ca3d5949..20cefbfb0 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -799,6 +799,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string newPluginManager, backupStoreGetter, s.credentialFileStore, + s.repoEnsurer, ).SetupWithManager(s.mgr); err != nil { s.logger.Fatal(err, "unable to create controller", "controller", controller.BackupDeletion) } diff --git a/pkg/controller/backup_deletion_controller.go b/pkg/controller/backup_deletion_controller.go index 9ab7e318c..03a9e379a 100644 --- a/pkg/controller/backup_deletion_controller.go +++ b/pkg/controller/backup_deletion_controller.go @@ -68,6 +68,7 @@ type backupDeletionReconciler struct { newPluginManager func(logrus.FieldLogger) clientmgmt.Manager backupStoreGetter persistence.ObjectBackupStoreGetter credentialStore credentials.FileStore + repoEnsurer *repository.Ensurer } // NewBackupDeletionReconciler creates a new backup deletion reconciler. @@ -81,6 +82,7 @@ func NewBackupDeletionReconciler( newPluginManager func(logrus.FieldLogger) clientmgmt.Manager, backupStoreGetter persistence.ObjectBackupStoreGetter, credentialStore credentials.FileStore, + repoEnsurer *repository.Ensurer, ) *backupDeletionReconciler { return &backupDeletionReconciler{ Client: client, @@ -93,6 +95,7 @@ func NewBackupDeletionReconciler( newPluginManager: newPluginManager, backupStoreGetter: backupStoreGetter, credentialStore: credentialStore, + repoEnsurer: repoEnsurer, } } @@ -502,20 +505,16 @@ func (r *backupDeletionReconciler) deletePodVolumeSnapshots(ctx context.Context, return nil } - snapshots, err := getSnapshotsInBackup(ctx, backup, r.Client) + directSnapshots, err := getSnapshotsInBackup(ctx, backup, r.Client) if err != nil { return []error{err} } - var errs []error - for _, snapshot := range snapshots { - if err := r.repoMgr.Forget(ctx, snapshot); err != nil { - errs = append(errs, err) - } - } - return errs + return batchDeleteSnapshots(ctx, r.repoEnsurer, r.repoMgr, directSnapshots, backup, r.logger) } +var batchDeleteSnapshotFunc = batchDeleteSnapshots + func (r *backupDeletionReconciler) deleteMovedSnapshots(ctx context.Context, backup *velerov1api.Backup) []error { if r.repoMgr == nil { return nil @@ -532,26 +531,52 @@ func (r *backupDeletionReconciler) deleteMovedSnapshots(ctx context.Context, bac return []error{errors.Wrapf(err, "failed to retrieve config for snapshot info")} } var errs []error + directSnapshots := map[string][]repository.SnapshotIdentifier{} for i := range list.Items { cm := list.Items[i] - snapshot := repository.SnapshotIdentifier{} + if cm.Data == nil || len(cm.Data) == 0 { + errs = append(errs, errors.New("no snapshot info in config")) + continue + } + b, err := json.Marshal(cm.Data) if err != nil { errs = append(errs, errors.Wrapf(err, "fail to marshal the snapshot info into JSON")) continue } + + snapshot := repository.SnapshotIdentifier{} if err := json.Unmarshal(b, &snapshot); err != nil { errs = append(errs, errors.Wrapf(err, "failed to unmarshal snapshot info")) continue } - if err := r.repoMgr.Forget(ctx, snapshot); err != nil { - errs = append(errs, errors.Wrapf(err, "failed to delete snapshot %s, namespace: %s", snapshot.SnapshotID, snapshot.VolumeNamespace)) + + if snapshot.SnapshotID == "" || snapshot.VolumeNamespace == "" || snapshot.RepositoryType == "" { + errs = append(errs, errors.Errorf("invalid snapshot, ID %s, namespace %s, repository %s", snapshot.SnapshotID, snapshot.VolumeNamespace, snapshot.RepositoryType)) + continue } - r.logger.Infof("Deleted snapshot %s, namespace: %s, repo type: %s", snapshot.SnapshotID, snapshot.VolumeNamespace, snapshot.RepositoryType) + + if directSnapshots[snapshot.VolumeNamespace] == nil { + directSnapshots[snapshot.VolumeNamespace] = []repository.SnapshotIdentifier{} + } + + directSnapshots[snapshot.VolumeNamespace] = append(directSnapshots[snapshot.VolumeNamespace], snapshot) + + r.logger.Infof("Deleting snapshot %s, namespace: %s, repo type: %s", snapshot.SnapshotID, snapshot.VolumeNamespace, snapshot.RepositoryType) + } + + for i := range list.Items { + cm := list.Items[i] if err := r.Client.Delete(ctx, &cm); err != nil { r.logger.Warnf("Failed to delete snapshot info configmap %s/%s: %v", cm.Namespace, cm.Name, err) } } + + if len(directSnapshots) > 0 { + deleteErrs := batchDeleteSnapshotFunc(ctx, r.repoEnsurer, r.repoMgr, directSnapshots, backup, r.logger) + errs = append(errs, deleteErrs...) + } + return errs } @@ -592,7 +617,7 @@ func (r *backupDeletionReconciler) patchBackup(ctx context.Context, backup *vele // getSnapshotsInBackup returns a list of all pod volume snapshot ids associated with // a given Velero backup. -func getSnapshotsInBackup(ctx context.Context, backup *velerov1api.Backup, kbClient client.Client) ([]repository.SnapshotIdentifier, error) { +func getSnapshotsInBackup(ctx context.Context, backup *velerov1api.Backup, kbClient client.Client) (map[string][]repository.SnapshotIdentifier, error) { podVolumeBackups := &velerov1api.PodVolumeBackupList{} options := &client.ListOptions{ LabelSelector: labels.Set(map[string]string{ @@ -607,3 +632,31 @@ func getSnapshotsInBackup(ctx context.Context, backup *velerov1api.Backup, kbCli return podvolume.GetSnapshotIdentifier(podVolumeBackups), nil } + +func batchDeleteSnapshots(ctx context.Context, repoEnsurer *repository.Ensurer, repoMgr repository.Manager, + directSnapshots map[string][]repository.SnapshotIdentifier, backup *velerov1api.Backup, logger logrus.FieldLogger) []error { + var errs []error + for volumeNamespace, snapshots := range directSnapshots { + batchForget := []string{} + for _, snapshot := range snapshots { + batchForget = append(batchForget, snapshot.SnapshotID) + } + + // For volumes in one backup, the BSL and repositoryType should always be the same + repoType := snapshots[0].RepositoryType + repo, err := repoEnsurer.EnsureRepo(ctx, backup.Namespace, volumeNamespace, backup.Spec.StorageLocation, repoType) + if err != nil { + errs = append(errs, errors.Wrapf(err, "error to ensure repo %s-%s-%s, skip deleting PVB snapshots %v", backup.Spec.StorageLocation, volumeNamespace, repoType, batchForget)) + continue + } + + if forgetErrs := repoMgr.BatchForget(ctx, repo, batchForget); len(forgetErrs) > 0 { + errs = append(errs, forgetErrs...) + continue + } + + logger.Infof("Batch deleted snapshots %v", batchForget) + } + + return errs +} diff --git a/pkg/controller/backup_deletion_controller_test.go b/pkg/controller/backup_deletion_controller_test.go index 0dbb0a3e9..a524b1adf 100644 --- a/pkg/controller/backup_deletion_controller_test.go +++ b/pkg/controller/backup_deletion_controller_test.go @@ -18,9 +18,11 @@ package controller import ( "bytes" + "encoding/json" + "errors" "fmt" "io" - "sort" + "reflect" "time" "context" @@ -53,6 +55,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/plugin/velero" "github.com/vmware-tanzu/velero/pkg/plugin/velero/mocks" "github.com/vmware-tanzu/velero/pkg/repository" + repomocks "github.com/vmware-tanzu/velero/pkg/repository/mocks" velerotest "github.com/vmware-tanzu/velero/pkg/test" ) @@ -94,6 +97,7 @@ func setupBackupDeletionControllerTest(t *testing.T, req *velerov1api.DeleteBack func(logrus.FieldLogger) clientmgmt.Manager { return pluginManager }, NewFakeSingleObjectBackupStoreGetter(backupStore), velerotest.NewFakeCredentialsFileStore("", nil), + nil, ), req: ctrl.Request{NamespacedName: types.NamespacedName{Namespace: req.Namespace, Name: req.Name}}, } @@ -138,7 +142,7 @@ func TestBackupDeletionControllerReconcile(t *testing.T) { err = td.fakeClient.Get(ctx, td.req.NamespacedName, res) require.NoError(t, err) assert.Equal(t, "Processed", string(res.Status.Phase)) - assert.Equal(t, 1, len(res.Status.Errors)) + assert.Len(t, res.Status.Errors, 1) assert.Equal(t, "spec.backupName is required", res.Status.Errors[0]) }) @@ -206,7 +210,7 @@ func TestBackupDeletionControllerReconcile(t *testing.T) { err = td.fakeClient.Get(ctx, td.req.NamespacedName, res) require.NoError(t, err) assert.Equal(t, "Processed", string(res.Status.Phase)) - assert.Equal(t, 1, len(res.Status.Errors)) + assert.Len(t, res.Status.Errors, 1) assert.Equal(t, "backup is still in progress", res.Status.Errors[0]) }) @@ -221,7 +225,7 @@ func TestBackupDeletionControllerReconcile(t *testing.T) { err = td.fakeClient.Get(ctx, td.req.NamespacedName, res) require.NoError(t, err) assert.Equal(t, "Processed", string(res.Status.Phase)) - assert.Equal(t, 1, len(res.Status.Errors)) + assert.Len(t, res.Status.Errors, 1) assert.Equal(t, "backup not found", res.Status.Errors[0]) }) t.Run("unable to find backup storage location", func(t *testing.T) { @@ -236,7 +240,7 @@ func TestBackupDeletionControllerReconcile(t *testing.T) { err = td.fakeClient.Get(ctx, td.req.NamespacedName, res) require.NoError(t, err) assert.Equal(t, "Processed", string(res.Status.Phase)) - assert.Equal(t, 1, len(res.Status.Errors)) + assert.Len(t, res.Status.Errors, 1) assert.Equal(t, "backup storage location default not found", res.Status.Errors[0]) }) @@ -253,7 +257,7 @@ func TestBackupDeletionControllerReconcile(t *testing.T) { err = td.fakeClient.Get(ctx, td.req.NamespacedName, res) require.NoError(t, err) assert.Equal(t, "Processed", string(res.Status.Phase)) - assert.Equal(t, 1, len(res.Status.Errors)) + assert.Len(t, res.Status.Errors, 1) assert.Equal(t, "cannot delete backup because backup storage location default is currently in read-only mode", res.Status.Errors[0]) }) t.Run("full delete, no errors", func(t *testing.T) { @@ -684,7 +688,7 @@ func TestBackupDeletionControllerReconcile(t *testing.T) { err = td.fakeClient.Get(ctx, td.req.NamespacedName, res) require.NoError(t, err) assert.Equal(t, "Processed", string(res.Status.Phase)) - assert.Equal(t, 1, len(res.Status.Errors)) + assert.Len(t, res.Status.Errors, 1) assert.Equal(t, "backup not found", res.Status.Errors[0]) }) @@ -694,13 +698,13 @@ func TestGetSnapshotsInBackup(t *testing.T) { tests := []struct { name string podVolumeBackups []velerov1api.PodVolumeBackup - expected []repository.SnapshotIdentifier + expected map[string][]repository.SnapshotIdentifier longBackupNameEnabled bool }{ { name: "no pod volume backups", podVolumeBackups: nil, - expected: nil, + expected: map[string][]repository.SnapshotIdentifier{}, }, { name: "no pod volume backups with matching label", @@ -720,7 +724,7 @@ func TestGetSnapshotsInBackup(t *testing.T) { Status: velerov1api.PodVolumeBackupStatus{SnapshotID: "snap-2"}, }, }, - expected: nil, + expected: map[string][]repository.SnapshotIdentifier{}, }, { name: "some pod volume backups with matching label", @@ -761,16 +765,18 @@ func TestGetSnapshotsInBackup(t *testing.T) { Status: velerov1api.PodVolumeBackupStatus{SnapshotID: ""}, }, }, - expected: []repository.SnapshotIdentifier{ - { - VolumeNamespace: "ns-1", - SnapshotID: "snap-3", - RepositoryType: "restic", - }, - { - VolumeNamespace: "ns-1", - SnapshotID: "snap-4", - RepositoryType: "restic", + expected: map[string][]repository.SnapshotIdentifier{ + "ns-1": { + { + VolumeNamespace: "ns-1", + SnapshotID: "snap-3", + RepositoryType: "restic", + }, + { + VolumeNamespace: "ns-1", + SnapshotID: "snap-4", + RepositoryType: "restic", + }, }, }, }, @@ -814,11 +820,13 @@ func TestGetSnapshotsInBackup(t *testing.T) { Status: velerov1api.PodVolumeBackupStatus{SnapshotID: ""}, }, }, - expected: []repository.SnapshotIdentifier{ - { - VolumeNamespace: "ns-1", - SnapshotID: "snap-3", - RepositoryType: "restic", + expected: map[string][]repository.SnapshotIdentifier{ + "ns-1": { + { + VolumeNamespace: "ns-1", + SnapshotID: "snap-3", + RepositoryType: "restic", + }, }, }, }, @@ -843,21 +851,179 @@ func TestGetSnapshotsInBackup(t *testing.T) { res, err := getSnapshotsInBackup(context.TODO(), veleroBackup, clientBuilder.Build()) assert.NoError(t, err) - // sort to ensure good compare of slices - less := func(snapshots []repository.SnapshotIdentifier) func(i, j int) bool { - return func(i, j int) bool { - if snapshots[i].VolumeNamespace == snapshots[j].VolumeNamespace { - return snapshots[i].SnapshotID < snapshots[j].SnapshotID - } - return snapshots[i].VolumeNamespace < snapshots[j].VolumeNamespace + assert.True(t, reflect.DeepEqual(res, test.expected)) + }) + } +} + +func batchDeleteSucceed(ctx context.Context, repoEnsurer *repository.Ensurer, repoMgr repository.Manager, directSnapshots map[string][]repository.SnapshotIdentifier, backup *velerov1api.Backup, logger logrus.FieldLogger) []error { + return nil +} + +func batchDeleteFail(ctx context.Context, repoEnsurer *repository.Ensurer, repoMgr repository.Manager, directSnapshots map[string][]repository.SnapshotIdentifier, backup *velerov1api.Backup, logger logrus.FieldLogger) []error { + return []error{ + errors.New("fake-delete-1"), + errors.New("fake-delete-2"), + } +} + +func generateSnapshotData(snapshot *repository.SnapshotIdentifier) (map[string]string, error) { + if snapshot == nil { + return nil, nil + } + + b, err := json.Marshal(snapshot) + if err != nil { + return nil, err + } + + data := make(map[string]string) + if err := json.Unmarshal(b, &data); err != nil { + return nil, err + } + + return data, nil +} + +func TestDeleteMovedSnapshots(t *testing.T) { + tests := []struct { + name string + repoMgr repository.Manager + batchDeleteSucceed bool + backupName string + snapshots []*repository.SnapshotIdentifier + expected []string + }{ + { + name: "repoMgr is nil", + }, + { + name: "no cm", + repoMgr: repomocks.NewManager(t), + }, + { + name: "bad cm info", + repoMgr: repomocks.NewManager(t), + backupName: "backup-01", + snapshots: []*repository.SnapshotIdentifier{nil}, + expected: []string{"no snapshot info in config"}, + }, + { + name: "invalid snapshots", + repoMgr: repomocks.NewManager(t), + backupName: "backup-01", + snapshots: []*repository.SnapshotIdentifier{ + { + RepositoryType: "repo-1", + VolumeNamespace: "ns-1", + }, + { + SnapshotID: "snapshot-1", + VolumeNamespace: "ns-1", + }, + { + SnapshotID: "snapshot-1", + RepositoryType: "repo-1", + }, + }, + batchDeleteSucceed: true, + expected: []string{ + "invalid snapshot, ID , namespace ns-1, repository repo-1", + "invalid snapshot, ID snapshot-1, namespace ns-1, repository ", + "invalid snapshot, ID snapshot-1, namespace , repository repo-1", + }, + }, + { + name: "batch delete succeed", + repoMgr: repomocks.NewManager(t), + backupName: "backup-01", + snapshots: []*repository.SnapshotIdentifier{ + + { + SnapshotID: "snapshot-1", + RepositoryType: "repo-1", + VolumeNamespace: "ns-1", + }, + }, + batchDeleteSucceed: true, + expected: []string{}, + }, + { + name: "batch delete fail", + repoMgr: repomocks.NewManager(t), + backupName: "backup-01", + snapshots: []*repository.SnapshotIdentifier{ + { + RepositoryType: "repo-1", + VolumeNamespace: "ns-1", + }, + { + SnapshotID: "snapshot-1", + RepositoryType: "repo-1", + VolumeNamespace: "ns-1", + }, + }, + expected: []string{"invalid snapshot, ID , namespace ns-1, repository repo-1", "fake-delete-1", "fake-delete-2"}, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + objs := []runtime.Object{} + for i, snapshot := range test.snapshots { + snapshotData, err := generateSnapshotData(snapshot) + require.NoError(t, err) + + cm := corev1api.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1api.SchemeGroupVersion.String(), + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "velero", + Name: fmt.Sprintf("du-info-%d", i), + Labels: map[string]string{ + velerov1api.BackupNameLabel: test.backupName, + velerov1api.DataUploadSnapshotInfoLabel: "true", + }, + }, + Data: snapshotData, } + objs = append(objs, &cm) } - sort.Slice(test.expected, less(test.expected)) - sort.Slice(res, less(res)) + veleroBackup := &velerov1api.Backup{} + controller := NewBackupDeletionReconciler( + velerotest.NewLogger(), + velerotest.NewFakeControllerRuntimeClient(t, objs...), + NewBackupTracker(), + test.repoMgr, + metrics.NewServerMetrics(), + nil, // discovery helper + func(logrus.FieldLogger) clientmgmt.Manager { return pluginManager }, + NewFakeSingleObjectBackupStoreGetter(backupStore), + velerotest.NewFakeCredentialsFileStore("", nil), + nil, + ) - assert.Equal(t, test.expected, res) + veleroBackup.Name = test.backupName + + if test.batchDeleteSucceed { + batchDeleteSnapshotFunc = batchDeleteSucceed + } else { + batchDeleteSnapshotFunc = batchDeleteFail + } + + errs := controller.deleteMovedSnapshots(context.Background(), veleroBackup) + if test.expected == nil { + assert.Nil(t, errs) + } else { + assert.Equal(t, len(test.expected), len(errs)) + for i := range test.expected { + assert.EqualError(t, errs[i], test.expected[i]) + } + } }) } } diff --git a/pkg/controller/data_upload_controller.go b/pkg/controller/data_upload_controller.go index 4fe1fb5a7..de476e9af 100644 --- a/pkg/controller/data_upload_controller.go +++ b/pkg/controller/data_upload_controller.go @@ -343,7 +343,7 @@ func (r *DataUploadReconciler) runCancelableDataUpload(ctx context.Context, fsBa velerov1api.AsyncOperationIDLabel: du.Labels[velerov1api.AsyncOperationIDLabel], } - if err := fsBackup.StartBackup(path, fmt.Sprintf("%s/%s", du.Spec.SourceNamespace, du.Spec.SourcePVC), "", false, tags, du.Spec.DataMoverConfig); err != nil { + if err := fsBackup.StartBackup(path, datamover.GetRealSource(du.Spec.SourceNamespace, du.Spec.SourcePVC), "", false, tags, du.Spec.DataMoverConfig); err != nil { return r.errorOut(ctx, du, err, "error starting data path backup", log) } diff --git a/pkg/controller/pod_volume_restore_controller_test.go b/pkg/controller/pod_volume_restore_controller_test.go index 0ef0165f5..f24aed653 100644 --- a/pkg/controller/pod_volume_restore_controller_test.go +++ b/pkg/controller/pod_volume_restore_controller_test.go @@ -492,7 +492,7 @@ func TestFindVolumeRestoresForPod(t *testing.T) { logger: logrus.New(), } requests := reconciler.findVolumeRestoresForPod(context.Background(), pod) - assert.Len(t, requests, 0) + assert.Empty(t, requests) // contain one matching PVR reconciler.Client = clientBuilder.WithLists(&velerov1api.PodVolumeRestoreList{ diff --git a/pkg/controller/restore_controller_test.go b/pkg/controller/restore_controller_test.go index 65df4af57..7b67aa569 100644 --- a/pkg/controller/restore_controller_test.go +++ b/pkg/controller/restore_controller_test.go @@ -592,7 +592,7 @@ func TestRestoreReconcile(t *testing.T) { return } if !test.addValidFinalizer { - assert.Equal(t, 1, len(restorer.Calls)) + assert.Len(t, restorer.Calls, 1) } // validate Patch call 2 (setting phase) diff --git a/pkg/controller/restore_finalizer_controller_test.go b/pkg/controller/restore_finalizer_controller_test.go index 3a17bf637..5bc25fca3 100644 --- a/pkg/controller/restore_finalizer_controller_test.go +++ b/pkg/controller/restore_finalizer_controller_test.go @@ -442,7 +442,7 @@ func TestPatchDynamicPVWithVolumeInfo(t *testing.T) { errs := ctx.patchDynamicPVWithVolumeInfo() if tc.expectedErrNum > 0 { - assert.Equal(t, tc.expectedErrNum, len(errs.Namespaces)) + assert.Len(t, errs.Namespaces, tc.expectedErrNum) } for pvName, expectedPVInfo := range tc.expectedPatch { diff --git a/pkg/controller/schedule_controller_test.go b/pkg/controller/schedule_controller_test.go index b2150fc49..e7c0c25a5 100644 --- a/pkg/controller/schedule_controller_test.go +++ b/pkg/controller/schedule_controller_test.go @@ -219,16 +219,16 @@ func TestReconcileOfSchedule(t *testing.T) { // new backup shouldn't be submitted. if test.backup != nil && (test.backup.Status.Phase == velerov1.BackupPhaseNew || test.backup.Status.Phase == velerov1.BackupPhaseInProgress) { - assert.Equal(t, 1, len(backups.Items)) + assert.Len(t, backups.Items, 1) require.Nil(t, client.Delete(ctx, test.backup)) } require.Nil(t, client.List(ctx, backups)) if test.expectedBackupCreate == nil { - assert.Equal(t, 0, len(backups.Items)) + assert.Empty(t, backups.Items) } else { - assert.Equal(t, 1, len(backups.Items)) + assert.Len(t, backups.Items, 1) } }) } diff --git a/pkg/datamover/dataupload_delete_action.go b/pkg/datamover/dataupload_delete_action.go index f226c1967..18501719d 100644 --- a/pkg/datamover/dataupload_delete_action.go +++ b/pkg/datamover/dataupload_delete_action.go @@ -56,7 +56,9 @@ func genConfigmap(bak *velerov1.Backup, du velerov2alpha1.DataUpload) *corev1api VolumeNamespace: du.Spec.SourceNamespace, BackupStorageLocation: bak.Spec.StorageLocation, SnapshotID: du.Status.SnapshotID, - RepositoryType: GetUploaderType(du.Spec.DataMover), + RepositoryType: velerov1.BackupRepositoryTypeKopia, + UploaderType: GetUploaderType(du.Spec.DataMover), + Source: GetRealSource(du.Spec.SourceNamespace, du.Spec.SourcePVC), } b, err := json.Marshal(snapshot) if err != nil { diff --git a/pkg/datamover/util.go b/pkg/datamover/util.go index f39f49cfb..e4097f07e 100644 --- a/pkg/datamover/util.go +++ b/pkg/datamover/util.go @@ -16,6 +16,8 @@ limitations under the License. package datamover +import "fmt" + func GetUploaderType(dataMover string) string { if dataMover == "" || dataMover == "velero" { return "kopia" @@ -27,3 +29,7 @@ func GetUploaderType(dataMover string) string { func IsBuiltInUploader(dataMover string) bool { return dataMover == "" || dataMover == "velero" } + +func GetRealSource(sourceNamespace string, pvcName string) string { + return fmt.Sprintf("%s/%s", sourceNamespace, pvcName) +} diff --git a/pkg/datapath/manager_test.go b/pkg/datapath/manager_test.go index e4b4d40c6..ebe18d1a0 100644 --- a/pkg/datapath/manager_test.go +++ b/pkg/datapath/manager_test.go @@ -42,10 +42,10 @@ func TestManager(t *testing.T) { assert.Equal(t, async_job_1, ret) m.RemoveAsyncBR("job-0") - assert.Equal(t, 2, len(m.tracker)) + assert.Len(t, m.tracker, 2) m.RemoveAsyncBR("job-1") - assert.Equal(t, 1, len(m.tracker)) + assert.Len(t, m.tracker, 1) ret = m.GetAsyncBR("job-1") assert.Equal(t, nil, ret) diff --git a/pkg/install/daemonset_test.go b/pkg/install/daemonset_test.go index 017d5004d..a9cce29ea 100644 --- a/pkg/install/daemonset_test.go +++ b/pkg/install/daemonset_test.go @@ -34,8 +34,8 @@ func TestDaemonSet(t *testing.T) { assert.Equal(t, corev1.PullIfNotPresent, ds.Spec.Template.Spec.Containers[0].ImagePullPolicy) ds = DaemonSet("velero", WithSecret(true)) - assert.Equal(t, 7, len(ds.Spec.Template.Spec.Containers[0].Env)) - assert.Equal(t, 4, len(ds.Spec.Template.Spec.Volumes)) + assert.Len(t, ds.Spec.Template.Spec.Containers[0].Env, 7) + assert.Len(t, ds.Spec.Template.Spec.Volumes, 4) ds = DaemonSet("velero", WithFeatures([]string{"foo,bar,baz"})) assert.Len(t, ds.Spec.Template.Spec.Containers[0].Args, 3) diff --git a/pkg/install/deployment_test.go b/pkg/install/deployment_test.go index 8e9649737..faa78afec 100644 --- a/pkg/install/deployment_test.go +++ b/pkg/install/deployment_test.go @@ -43,8 +43,8 @@ func TestDeployment(t *testing.T) { assert.Equal(t, corev1.PullIfNotPresent, deploy.Spec.Template.Spec.Containers[0].ImagePullPolicy) deploy = Deployment("velero", WithSecret(true)) - assert.Equal(t, 7, len(deploy.Spec.Template.Spec.Containers[0].Env)) - assert.Equal(t, 3, len(deploy.Spec.Template.Spec.Volumes)) + assert.Len(t, deploy.Spec.Template.Spec.Containers[0].Env, 7) + assert.Len(t, deploy.Spec.Template.Spec.Volumes, 3) deploy = Deployment("velero", WithDefaultRepoMaintenanceFrequency(24*time.Hour)) assert.Len(t, deploy.Spec.Template.Spec.Containers[0].Args, 2) diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 61b91812d..3e273a9fd 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -69,7 +69,7 @@ const ( // data mover metrics DataUploadSuccessTotal = "data_upload_success_total" DataUploadFailureTotal = "data_upload_failure_total" - DataUploadCancelTotal = "data_upload_cancel_total" //nolint:gosec // Not a hard code secret. + DataUploadCancelTotal = "data_upload_cancel_total" DataDownloadSuccessTotal = "data_download_success_total" DataDownloadFailureTotal = "data_download_failure_total" DataDownloadCancelTotal = "data_download_cancel_total" diff --git a/pkg/podvolume/backupper_test.go b/pkg/podvolume/backupper_test.go index e08b772dd..618d380aa 100644 --- a/pkg/podvolume/backupper_test.go +++ b/pkg/podvolume/backupper_test.go @@ -642,22 +642,22 @@ func TestPVCBackupSummary(t *testing.T) { // it won't be added if the volme is not in the pvc map. pbs.addSkipped("vol-3", "whatever reason") - assert.Equal(t, 0, len(pbs.Skipped)) + assert.Empty(t, pbs.Skipped) pbs.addBackedup("vol-3") - assert.Equal(t, 0, len(pbs.Backedup)) + assert.Empty(t, pbs.Backedup) // only can be added as skipped when it's not in backedup set pbs.addBackedup("vol-1") - assert.Equal(t, 1, len(pbs.Backedup)) + assert.Len(t, pbs.Backedup, 1) assert.Equal(t, "pvc-1", pbs.Backedup["vol-1"].Name) pbs.addSkipped("vol-1", "whatever reason") - assert.Equal(t, 0, len(pbs.Skipped)) + assert.Empty(t, pbs.Skipped) pbs.addSkipped("vol-2", "vol-2 has to be skipped") - assert.Equal(t, 1, len(pbs.Skipped)) + assert.Len(t, pbs.Skipped, 1) assert.Equal(t, "pvc-2", pbs.Skipped["vol-2"].PVC.Name) // adding a vol as backedup removes it from skipped set pbs.addBackedup("vol-2") - assert.Equal(t, 0, len(pbs.Skipped)) - assert.Equal(t, 2, len(pbs.Backedup)) + assert.Empty(t, pbs.Skipped) + assert.Len(t, pbs.Backedup, 2) } diff --git a/pkg/podvolume/util.go b/pkg/podvolume/util.go index 6d09a5a4f..b1dfcbe65 100644 --- a/pkg/podvolume/util.go +++ b/pkg/podvolume/util.go @@ -122,19 +122,30 @@ func getVolumeBackupInfoForPod(podVolumeBackups []*velerov1api.PodVolumeBackup, } // GetSnapshotIdentifier returns the snapshots represented by SnapshotIdentifier for the given PVBs -func GetSnapshotIdentifier(podVolumeBackups *velerov1api.PodVolumeBackupList) []repository.SnapshotIdentifier { - var res []repository.SnapshotIdentifier +func GetSnapshotIdentifier(podVolumeBackups *velerov1api.PodVolumeBackupList) map[string][]repository.SnapshotIdentifier { + res := map[string][]repository.SnapshotIdentifier{} for _, item := range podVolumeBackups.Items { if item.Status.SnapshotID == "" { continue } - res = append(res, repository.SnapshotIdentifier{ + if res[item.Spec.Pod.Namespace] == nil { + res[item.Spec.Pod.Namespace] = []repository.SnapshotIdentifier{} + } + + snapshots := res[item.Spec.Pod.Namespace] + + snapshots = append(snapshots, repository.SnapshotIdentifier{ VolumeNamespace: item.Spec.Pod.Namespace, BackupStorageLocation: item.Spec.BackupStorageLocation, SnapshotID: item.Status.SnapshotID, RepositoryType: getRepositoryType(item.Spec.UploaderType), + UploaderType: item.Spec.UploaderType, + Source: item.Status.Path, + RepoIdentifier: item.Spec.RepoIdentifier, }) + + res[item.Spec.Pod.Namespace] = snapshots } return res diff --git a/pkg/repository/manager.go b/pkg/repository/manager.go index 3e412a73a..5b7c07cbc 100644 --- a/pkg/repository/manager.go +++ b/pkg/repository/manager.go @@ -48,6 +48,16 @@ type SnapshotIdentifier struct { // RepositoryType is the type of the repository where the // snapshot is stored RepositoryType string `json:"repositoryType"` + + // Source is the source of the data saved in the repo by the snapshot + Source string `json:"source"` + + // UploaderType is the type of uploader which saved the snapshot data + UploaderType string `json:"uploaderType"` + + // RepoIdentifier is the identifier of the repository where the + // snapshot is stored + RepoIdentifier string `json:"repoIdentifier"` } // Manager manages backup repositories. @@ -71,7 +81,12 @@ type Manager interface { // Forget removes a snapshot from the list of // available snapshots in a repo. - Forget(context.Context, SnapshotIdentifier) error + Forget(context.Context, *velerov1api.BackupRepository, string) error + + // BatchForget removes a list of snapshots from the list of + // available snapshots in a repo. + BatchForget(context.Context, *velerov1api.BackupRepository, []string) []error + // DefaultMaintenanceFrequency returns the default maintenance frequency from the specific repo DefaultMaintenanceFrequency(repo *velerov1api.BackupRepository) (time.Duration, error) } @@ -195,12 +210,7 @@ func (m *manager) UnlockRepo(repo *velerov1api.BackupRepository) error { return prd.EnsureUnlockRepo(context.Background(), param) } -func (m *manager) Forget(ctx context.Context, snapshot SnapshotIdentifier) error { - repo, err := m.repoEnsurer.EnsureRepo(ctx, m.namespace, snapshot.VolumeNamespace, snapshot.BackupStorageLocation, snapshot.RepositoryType) - if err != nil { - return err - } - +func (m *manager) Forget(ctx context.Context, repo *velerov1api.BackupRepository, snapshot string) error { m.repoLocker.LockExclusive(repo.Name) defer m.repoLocker.UnlockExclusive(repo.Name) @@ -217,7 +227,27 @@ func (m *manager) Forget(ctx context.Context, snapshot SnapshotIdentifier) error return errors.WithStack(err) } - return prd.Forget(context.Background(), snapshot.SnapshotID, param) + return prd.Forget(context.Background(), snapshot, param) +} + +func (m *manager) BatchForget(ctx context.Context, repo *velerov1api.BackupRepository, snapshots []string) []error { + m.repoLocker.LockExclusive(repo.Name) + defer m.repoLocker.UnlockExclusive(repo.Name) + + prd, err := m.getRepositoryProvider(repo) + if err != nil { + return []error{errors.WithStack(err)} + } + param, err := m.assembleRepoParam(repo) + if err != nil { + return []error{errors.WithStack(err)} + } + + if err := prd.BoostRepoConnect(context.Background(), param); err != nil { + return []error{errors.WithStack(err)} + } + + return prd.BatchForget(context.Background(), snapshots, param) } func (m *manager) DefaultMaintenanceFrequency(repo *velerov1api.BackupRepository) (time.Duration, error) { diff --git a/pkg/repository/mocks/Manager.go b/pkg/repository/mocks/Manager.go index 5508ce958..226411775 100644 --- a/pkg/repository/mocks/Manager.go +++ b/pkg/repository/mocks/Manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.14.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks @@ -6,7 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - repository "github.com/vmware-tanzu/velero/pkg/repository" time "time" @@ -18,10 +17,34 @@ type Manager struct { mock.Mock } +// BatchForget provides a mock function with given fields: _a0, _a1, _a2 +func (_m *Manager) BatchForget(_a0 context.Context, _a1 *v1.BackupRepository, _a2 []string) []error { + ret := _m.Called(_a0, _a1, _a2) + + if len(ret) == 0 { + panic("no return value specified for BatchForget") + } + + var r0 []error + if rf, ok := ret.Get(0).(func(context.Context, *v1.BackupRepository, []string) []error); ok { + r0 = rf(_a0, _a1, _a2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]error) + } + } + + return r0 +} + // ConnectToRepo provides a mock function with given fields: repo func (_m *Manager) ConnectToRepo(repo *v1.BackupRepository) error { ret := _m.Called(repo) + if len(ret) == 0 { + panic("no return value specified for ConnectToRepo") + } + var r0 error if rf, ok := ret.Get(0).(func(*v1.BackupRepository) error); ok { r0 = rf(repo) @@ -36,14 +59,21 @@ func (_m *Manager) ConnectToRepo(repo *v1.BackupRepository) error { func (_m *Manager) DefaultMaintenanceFrequency(repo *v1.BackupRepository) (time.Duration, error) { ret := _m.Called(repo) + if len(ret) == 0 { + panic("no return value specified for DefaultMaintenanceFrequency") + } + var r0 time.Duration + var r1 error + if rf, ok := ret.Get(0).(func(*v1.BackupRepository) (time.Duration, error)); ok { + return rf(repo) + } if rf, ok := ret.Get(0).(func(*v1.BackupRepository) time.Duration); ok { r0 = rf(repo) } else { r0 = ret.Get(0).(time.Duration) } - var r1 error if rf, ok := ret.Get(1).(func(*v1.BackupRepository) error); ok { r1 = rf(repo) } else { @@ -53,13 +83,17 @@ func (_m *Manager) DefaultMaintenanceFrequency(repo *v1.BackupRepository) (time. return r0, r1 } -// Forget provides a mock function with given fields: _a0, _a1 -func (_m *Manager) Forget(_a0 context.Context, _a1 repository.SnapshotIdentifier) error { - ret := _m.Called(_a0, _a1) +// Forget provides a mock function with given fields: _a0, _a1, _a2 +func (_m *Manager) Forget(_a0 context.Context, _a1 *v1.BackupRepository, _a2 string) error { + ret := _m.Called(_a0, _a1, _a2) + + if len(ret) == 0 { + panic("no return value specified for Forget") + } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, repository.SnapshotIdentifier) error); ok { - r0 = rf(_a0, _a1) + if rf, ok := ret.Get(0).(func(context.Context, *v1.BackupRepository, string) error); ok { + r0 = rf(_a0, _a1, _a2) } else { r0 = ret.Error(0) } @@ -71,6 +105,10 @@ func (_m *Manager) Forget(_a0 context.Context, _a1 repository.SnapshotIdentifier func (_m *Manager) InitRepo(repo *v1.BackupRepository) error { ret := _m.Called(repo) + if len(ret) == 0 { + panic("no return value specified for InitRepo") + } + var r0 error if rf, ok := ret.Get(0).(func(*v1.BackupRepository) error); ok { r0 = rf(repo) @@ -85,6 +123,10 @@ func (_m *Manager) InitRepo(repo *v1.BackupRepository) error { func (_m *Manager) PrepareRepo(repo *v1.BackupRepository) error { ret := _m.Called(repo) + if len(ret) == 0 { + panic("no return value specified for PrepareRepo") + } + var r0 error if rf, ok := ret.Get(0).(func(*v1.BackupRepository) error); ok { r0 = rf(repo) @@ -99,6 +141,10 @@ func (_m *Manager) PrepareRepo(repo *v1.BackupRepository) error { func (_m *Manager) PruneRepo(repo *v1.BackupRepository) error { ret := _m.Called(repo) + if len(ret) == 0 { + panic("no return value specified for PruneRepo") + } + var r0 error if rf, ok := ret.Get(0).(func(*v1.BackupRepository) error); ok { r0 = rf(repo) @@ -113,6 +159,10 @@ func (_m *Manager) PruneRepo(repo *v1.BackupRepository) error { func (_m *Manager) UnlockRepo(repo *v1.BackupRepository) error { ret := _m.Called(repo) + if len(ret) == 0 { + panic("no return value specified for UnlockRepo") + } + var r0 error if rf, ok := ret.Get(0).(func(*v1.BackupRepository) error); ok { r0 = rf(repo) @@ -123,13 +173,12 @@ func (_m *Manager) UnlockRepo(repo *v1.BackupRepository) error { return r0 } -type mockConstructorTestingTNewManager interface { +// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewManager(t interface { mock.TestingT Cleanup(func()) -} - -// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewManager(t mockConstructorTestingTNewManager) *Manager { +}) *Manager { mock := &Manager{} mock.Mock.Test(t) diff --git a/pkg/repository/provider/provider.go b/pkg/repository/provider/provider.go index 4b76830f5..d27d269da 100644 --- a/pkg/repository/provider/provider.go +++ b/pkg/repository/provider/provider.go @@ -57,6 +57,9 @@ type Provider interface { // Forget is to delete a snapshot from the repository Forget(ctx context.Context, snapshotID string, param RepoParam) error + // BatchForget is to delete a list of snapshots from the repository + BatchForget(ctx context.Context, snapshotIDs []string, param RepoParam) []error + // DefaultMaintenanceFrequency returns the default frequency to run maintenance DefaultMaintenanceFrequency(ctx context.Context, param RepoParam) time.Duration } diff --git a/pkg/repository/provider/restic.go b/pkg/repository/provider/restic.go index a77c950be..decc3af15 100644 --- a/pkg/repository/provider/restic.go +++ b/pkg/repository/provider/restic.go @@ -78,6 +78,16 @@ func (r *resticRepositoryProvider) Forget(ctx context.Context, snapshotID string return r.svc.Forget(param.BackupLocation, param.BackupRepo, snapshotID) } +func (r *resticRepositoryProvider) BatchForget(ctx context.Context, snapshotIDs []string, param RepoParam) []error { + errs := []error{} + for _, snapshot := range snapshotIDs { + err := r.Forget(ctx, snapshot, param) + errs = append(errs, err) + } + + return errs +} + func (r *resticRepositoryProvider) DefaultMaintenanceFrequency(ctx context.Context, param RepoParam) time.Duration { return r.svc.DefaultMaintenanceFrequency() } diff --git a/pkg/repository/provider/unified_repo.go b/pkg/repository/provider/unified_repo.go index 11c084549..a72ecdad4 100644 --- a/pkg/repository/provider/unified_repo.go +++ b/pkg/repository/provider/unified_repo.go @@ -314,6 +314,56 @@ func (urp *unifiedRepoProvider) Forget(ctx context.Context, snapshotID string, p return nil } +func (urp *unifiedRepoProvider) BatchForget(ctx context.Context, snapshotIDs []string, param RepoParam) []error { + log := urp.log.WithFields(logrus.Fields{ + "BSL name": param.BackupLocation.Name, + "repo name": param.BackupRepo.Name, + "repo UID": param.BackupRepo.UID, + "snapshotIDs": snapshotIDs, + }) + + log.Debug("Start to batch forget snapshot") + + repoOption, err := udmrepo.NewRepoOptions( + udmrepo.WithPassword(urp, param), + udmrepo.WithConfigFile(urp.workPath, string(param.BackupRepo.UID)), + udmrepo.WithDescription(repoOpDescForget), + ) + + if err != nil { + return []error{errors.Wrap(err, "error to get repo options")} + } + + bkRepo, err := urp.repoService.Open(ctx, *repoOption) + if err != nil { + return []error{errors.Wrap(err, "error to open backup repo")} + } + + defer func() { + c := bkRepo.Close(ctx) + if c != nil { + log.WithError(c).Error("Failed to close repo") + } + }() + + errs := []error{} + for _, snapshotID := range snapshotIDs { + err = bkRepo.DeleteManifest(ctx, udmrepo.ID(snapshotID)) + if err != nil { + errs = append(errs, errors.Wrapf(err, "error to delete manifest %s", snapshotID)) + } + } + + err = bkRepo.Flush(ctx) + if err != nil { + return []error{errors.Wrap(err, "error to flush repo")} + } + + log.Debug("Forget snapshot complete") + + return errs +} + func (urp *unifiedRepoProvider) DefaultMaintenanceFrequency(ctx context.Context, param RepoParam) time.Duration { return urp.repoService.DefaultMaintenanceFrequency() } diff --git a/pkg/repository/provider/unified_repo_test.go b/pkg/repository/provider/unified_repo_test.go index 9a7dd84da..44d7301c4 100644 --- a/pkg/repository/provider/unified_repo_test.go +++ b/pkg/repository/provider/unified_repo_test.go @@ -857,6 +857,161 @@ func TestForget(t *testing.T) { } } +func TestBatchForget(t *testing.T) { + var backupRepo *reposervicenmocks.BackupRepo + + testCases := []struct { + name string + funcTable localFuncTable + getter *credmock.SecretStore + repoService *reposervicenmocks.BackupRepoService + backupRepo *reposervicenmocks.BackupRepo + retFuncOpen []interface{} + retFuncDelete interface{} + retFuncFlush interface{} + credStoreReturn string + credStoreError error + snapshots []string + expectedErr []string + }{ + { + name: "get repo option fail", + expectedErr: []string{"error to get repo options: error to get repo password: invalid credentials interface"}, + }, + { + name: "repo open fail", + getter: new(credmock.SecretStore), + credStoreReturn: "fake-password", + funcTable: localFuncTable{ + getStorageVariables: func(*velerov1api.BackupStorageLocation, string, string) (map[string]string, error) { + return map[string]string{}, nil + }, + getStorageCredentials: func(*velerov1api.BackupStorageLocation, velerocredentials.FileStore) (map[string]string, error) { + return map[string]string{}, nil + }, + }, + repoService: new(reposervicenmocks.BackupRepoService), + retFuncOpen: []interface{}{ + func(context.Context, udmrepo.RepoOptions) udmrepo.BackupRepo { + return backupRepo + }, + + func(context.Context, udmrepo.RepoOptions) error { + return errors.New("fake-error-2") + }, + }, + expectedErr: []string{"error to open backup repo: fake-error-2"}, + }, + { + name: "delete fail", + getter: new(credmock.SecretStore), + credStoreReturn: "fake-password", + funcTable: localFuncTable{ + getStorageVariables: func(*velerov1api.BackupStorageLocation, string, string) (map[string]string, error) { + return map[string]string{}, nil + }, + getStorageCredentials: func(*velerov1api.BackupStorageLocation, velerocredentials.FileStore) (map[string]string, error) { + return map[string]string{}, nil + }, + }, + repoService: new(reposervicenmocks.BackupRepoService), + backupRepo: new(reposervicenmocks.BackupRepo), + retFuncOpen: []interface{}{ + func(context.Context, udmrepo.RepoOptions) udmrepo.BackupRepo { + return backupRepo + }, + + func(context.Context, udmrepo.RepoOptions) error { + return nil + }, + }, + retFuncDelete: func(context.Context, udmrepo.ID) error { + return errors.New("fake-error-3") + }, + snapshots: []string{"snapshot-1", "snapshot-2"}, + expectedErr: []string{"error to delete manifest snapshot-1: fake-error-3", "error to delete manifest snapshot-2: fake-error-3"}, + }, + { + name: "flush fail", + getter: new(credmock.SecretStore), + credStoreReturn: "fake-password", + funcTable: localFuncTable{ + getStorageVariables: func(*velerov1api.BackupStorageLocation, string, string) (map[string]string, error) { + return map[string]string{}, nil + }, + getStorageCredentials: func(*velerov1api.BackupStorageLocation, velerocredentials.FileStore) (map[string]string, error) { + return map[string]string{}, nil + }, + }, + repoService: new(reposervicenmocks.BackupRepoService), + backupRepo: new(reposervicenmocks.BackupRepo), + retFuncOpen: []interface{}{ + func(context.Context, udmrepo.RepoOptions) udmrepo.BackupRepo { + return backupRepo + }, + + func(context.Context, udmrepo.RepoOptions) error { + return nil + }, + }, + retFuncDelete: func(context.Context, udmrepo.ID) error { + return nil + }, + retFuncFlush: func(context.Context) error { + return errors.New("fake-error-4") + }, + expectedErr: []string{"error to flush repo: fake-error-4"}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + funcTable = tc.funcTable + + var secretStore velerocredentials.SecretStore + if tc.getter != nil { + tc.getter.On("Get", mock.Anything, mock.Anything).Return(tc.credStoreReturn, tc.credStoreError) + secretStore = tc.getter + } + + urp := unifiedRepoProvider{ + credentialGetter: velerocredentials.CredentialGetter{ + FromSecret: secretStore, + }, + repoService: tc.repoService, + log: velerotest.NewLogger(), + } + + backupRepo = tc.backupRepo + + if tc.repoService != nil { + tc.repoService.On("Open", mock.Anything, mock.Anything).Return(tc.retFuncOpen[0], tc.retFuncOpen[1]) + } + + if tc.backupRepo != nil { + backupRepo.On("DeleteManifest", mock.Anything, mock.Anything).Return(tc.retFuncDelete) + backupRepo.On("Flush", mock.Anything).Return(tc.retFuncFlush) + backupRepo.On("Close", mock.Anything).Return(nil) + } + + errs := urp.BatchForget(context.Background(), tc.snapshots, RepoParam{ + BackupLocation: &velerov1api.BackupStorageLocation{}, + BackupRepo: &velerov1api.BackupRepository{}, + }) + + if tc.expectedErr == nil { + assert.Equal(t, 0, len(errs)) + } else { + assert.Equal(t, len(tc.expectedErr), len(errs)) + + for i := range tc.expectedErr { + assert.EqualError(t, errs[i], tc.expectedErr[i]) + } + } + }) + } +} + func TestInitRepo(t *testing.T) { testCases := []struct { name string diff --git a/pkg/repository/udmrepo/kopialib/backend/utils.go b/pkg/repository/udmrepo/kopialib/backend/utils.go index 19fa7b278..a740a0b7b 100644 --- a/pkg/repository/udmrepo/kopialib/backend/utils.go +++ b/pkg/repository/udmrepo/kopialib/backend/utils.go @@ -30,7 +30,7 @@ func mustHaveString(key string, flags map[string]string) (string, error) { if value, exist := flags[key]; exist { return value, nil } - return "", errors.New("key " + key + " not found") + return "", errors.Errorf("key %s not found", key) } func optionalHaveString(key string, flags map[string]string) string { diff --git a/pkg/repository/udmrepo/kopialib/lib_repo.go b/pkg/repository/udmrepo/kopialib/lib_repo.go index 93d3c05b1..515c3d161 100644 --- a/pkg/repository/udmrepo/kopialib/lib_repo.go +++ b/pkg/repository/udmrepo/kopialib/lib_repo.go @@ -72,6 +72,10 @@ type kopiaObjectWriter struct { rawWriter object.Writer } +type openOptions struct { + allowIndexWriteOnLoad bool +} + const ( defaultLogInterval = time.Second * 10 defaultMaintainCheckPeriod = time.Hour @@ -115,7 +119,7 @@ func (ks *kopiaRepoService) Open(ctx context.Context, repoOption udmrepo.RepoOpt repoCtx := kopia.SetupKopiaLog(ctx, ks.logger) - r, err := openKopiaRepo(repoCtx, repoConfig, repoOption.RepoPassword) + r, err := openKopiaRepo(repoCtx, repoConfig, repoOption.RepoPassword, nil) if err != nil { return nil, err } @@ -158,11 +162,15 @@ func (ks *kopiaRepoService) Maintain(ctx context.Context, repoOption udmrepo.Rep repoCtx := kopia.SetupKopiaLog(ctx, ks.logger) - r, err := openKopiaRepo(repoCtx, repoConfig, repoOption.RepoPassword) + ks.logger.Info("Start to open repo for maintenance, allow index write on load") + + r, err := openKopiaRepo(repoCtx, repoConfig, repoOption.RepoPassword, &openOptions{allowIndexWriteOnLoad: true}) if err != nil { return err } + ks.logger.Info("Succeeded to open repo for maintenance") + defer func() { c := r.Close(repoCtx) if c != nil { @@ -546,8 +554,13 @@ func (lt *logThrottle) shouldLog() bool { return false } -func openKopiaRepo(ctx context.Context, configFile string, password string) (repo.Repository, error) { - r, err := kopiaRepoOpen(ctx, configFile, password, &repo.Options{}) +func openKopiaRepo(ctx context.Context, configFile string, password string, options *openOptions) (repo.Repository, error) { + allowIndexWriteOnLoad := false + if options != nil { + allowIndexWriteOnLoad = options.allowIndexWriteOnLoad + } + + r, err := kopiaRepoOpen(ctx, configFile, password, &repo.Options{AllowWriteOnIndexLoad: allowIndexWriteOnLoad}) if os.IsNotExist(err) { return nil, errors.Wrap(err, "error to open repo, repo doesn't exist") } @@ -560,7 +573,7 @@ func openKopiaRepo(ctx context.Context, configFile string, password string) (rep } func writeInitParameters(ctx context.Context, repoOption udmrepo.RepoOptions, logger logrus.FieldLogger) error { - r, err := openKopiaRepo(ctx, repoOption.ConfigFilePath, repoOption.RepoPassword) + r, err := openKopiaRepo(ctx, repoOption.ConfigFilePath, repoOption.RepoPassword, nil) if err != nil { return err } diff --git a/pkg/util/azure/credential.go b/pkg/util/azure/credential.go index 72da54b21..52df1798f 100644 --- a/pkg/util/azure/credential.go +++ b/pkg/util/azure/credential.go @@ -81,7 +81,7 @@ type configCredentialOptions struct { AdditionallyAllowedTenants []string } -// newConfigCredential works same as the azidentity.EnvironmentCredential but reads the credentials from a map +// newConfigCredential works similar as the azidentity.EnvironmentCredential but reads the credentials from a map // rather than environment variables. This is required for Velero to run B/R concurrently // https://github.com/Azure/azure-sdk-for-go/blob/sdk/azidentity/v1.3.0/sdk/azidentity/environment_credential.go#L80 func newConfigCredential(creds map[string]string, options configCredentialOptions) (azcore.TokenCredential, error) { @@ -102,19 +102,24 @@ func newConfigCredential(creds map[string]string, options configCredentialOption }) } - // certificate - if certPath := creds[CredentialKeyClientCertificatePath]; certPath != "" { - certData, err := os.ReadFile(certPath) - if err != nil { - return nil, errors.Wrapf(err, "failed to read certificate file %s", certPath) + // raw certificate or certificate file + if rawCerts, certsPath := []byte(creds[CredentialKeyClientCertificate]), creds[CredentialKeyClientCertificatePath]; len(rawCerts) > 0 || len(certsPath) > 0 { + var err error + // raw certificate isn't specified while certificate path is specified + if len(rawCerts) == 0 { + rawCerts, err = os.ReadFile(certsPath) + if err != nil { + return nil, errors.Wrapf(err, "failed to read certificate file %s", certsPath) + } } + var password []byte if v := creds[CredentialKeyClientCertificatePassword]; v != "" { password = []byte(v) } - certs, key, err := azidentity.ParseCertificates(certData, password) + certs, key, err := azidentity.ParseCertificates(rawCerts, password) if err != nil { - return nil, errors.Wrapf(err, "failed to load certificate from %s", certPath) + return nil, errors.Wrap(err, "failed to parse certificate") } o := &azidentity.ClientCertificateCredentialOptions{ AdditionallyAllowedTenants: options.AdditionallyAllowedTenants, diff --git a/pkg/util/azure/util.go b/pkg/util/azure/util.go index 41191d4b7..e708d6ce3 100644 --- a/pkg/util/azure/util.go +++ b/pkg/util/azure/util.go @@ -43,6 +43,7 @@ const ( CredentialKeyTenantID = "AZURE_TENANT_ID" // #nosec CredentialKeyClientID = "AZURE_CLIENT_ID" // #nosec CredentialKeyClientSecret = "AZURE_CLIENT_SECRET" // #nosec + CredentialKeyClientCertificate = "AZURE_CLIENT_CERTIFICATE" // #nosec CredentialKeyClientCertificatePath = "AZURE_CLIENT_CERTIFICATE_PATH" // #nosec CredentialKeyClientCertificatePassword = "AZURE_CLIENT_CERTIFICATE_PASSWORD" // #nosec CredentialKeySendCertChain = "AZURE_CLIENT_SEND_CERTIFICATE_CHAIN" // #nosec diff --git a/pkg/util/stringslice/stringslice_test.go b/pkg/util/stringslice/stringslice_test.go index b3fdeedf8..996261026 100644 --- a/pkg/util/stringslice/stringslice_test.go +++ b/pkg/util/stringslice/stringslice_test.go @@ -36,7 +36,7 @@ func TestHas(t *testing.T) { func TestExcept(t *testing.T) { items := []string{} except := Except(items, "asdf") - assert.Len(t, except, 0) + assert.Empty(t, except) items = []string{"a", "b", "c"} assert.Equal(t, []string{"b", "c"}, Except(items, "a")) diff --git a/site/content/docs/main/csi.md b/site/content/docs/main/csi.md index d1cc8e824..6fd1f9a72 100644 --- a/site/content/docs/main/csi.md +++ b/site/content/docs/main/csi.md @@ -24,7 +24,7 @@ Both of these can be added with the `velero install` command. ```bash velero install \ --features=EnableCSI \ ---plugins=,velero/velero-plugin-for-csi:v0.3.0 \ +--plugins=,velero/velero-plugin-for-csi:v0.7.0 \ ... ``` diff --git a/site/content/docs/main/file-system-backup.md b/site/content/docs/main/file-system-backup.md index 0580b55e9..11bf4a83e 100644 --- a/site/content/docs/main/file-system-backup.md +++ b/site/content/docs/main/file-system-backup.md @@ -586,6 +586,47 @@ Velero does not provide a mechanism to detect persistent volume claims that are To solve this, a controller was written by Thomann Bits&Beats: [velero-pvc-watcher][7] +## Support ReadOnlyRootFilesystem setting on Velero server pod +### Kopia +When the Velero server pod's SecurityContext sets the `ReadOnlyRootFileSystem` parameter to true, the Velero server pod's filesystem is running in read-only mode. +If the user creates a backup with Kopia as the uploader, or a backup enabling snapshot data mover function, the backup will fail, because the Kopia needs to write some cache and configuration data into the pod filesystem. + +``` +Errors: Velero: name: /mongodb-0 message: /Error backing up item error: /failed to wait BackupRepository: backup repository is not ready: error to connect to backup repo: error to connect repo with storage: error to connect to repository: unable to write config file: unable to create config directory: mkdir /home/cnb/udmrepo: read-only file system name: /mongodb-1 message: /Error backing up item error: /failed to wait BackupRepository: backup repository is not ready: error to connect to backup repo: error to connect repo with storage: error to connect to repository: unable to write config file: unable to create config directory: mkdir /home/cnb/udmrepo: read-only file system name: /mongodb-2 message: /Error backing up item error: /failed to wait BackupRepository: backup repository is not ready: error to connect to backup repo: error to connect repo with storage: error to connect to repository: unable to write config file: unable to create config directory: mkdir /home/cnb/udmrepo: read-only file system Cluster: +``` + +The workaround is making those directories as ephemeral k8s volumes, then those directories are not counted as pod's root filesystem. +The `user-name` is the Velero pod's running user name. The default value is `cnb`. + +``` yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: velero + namespace: velero +spec: + template: + spec: + containers: + - name: velero + ...... + volumeMounts: + ...... + - mountPath: /home//udmrepo + name: udmrepo + - mountPath: /home//.cache + name: cache + ...... + volumes: + ...... + - emptyDir: {} + name: udmrepo + - emptyDir: {} + name: cache + ...... +``` + + [1]: https://github.com/restic/restic [2]: https://github.com/kopia/kopia [3]: customize-installation.md#enable-restic-integration diff --git a/site/content/docs/v1.10/csi.md b/site/content/docs/v1.10/csi.md index c66077603..22bafca11 100644 --- a/site/content/docs/v1.10/csi.md +++ b/site/content/docs/v1.10/csi.md @@ -24,7 +24,7 @@ Both of these can be added with the `velero install` command. ```bash velero install \ --features=EnableCSI \ ---plugins=,velero/velero-plugin-for-csi:v0.3.0 \ +--plugins=,velero/velero-plugin-for-csi:v0.4.0 \ ... ``` diff --git a/site/content/docs/v1.11/csi.md b/site/content/docs/v1.11/csi.md index ea0ae78fe..09b9e555c 100644 --- a/site/content/docs/v1.11/csi.md +++ b/site/content/docs/v1.11/csi.md @@ -24,7 +24,7 @@ Both of these can be added with the `velero install` command. ```bash velero install \ --features=EnableCSI \ ---plugins=,velero/velero-plugin-for-csi:v0.3.0 \ +--plugins=,velero/velero-plugin-for-csi:v0.5.0 \ ... ``` diff --git a/site/content/docs/v1.12/csi.md b/site/content/docs/v1.12/csi.md index d1cc8e824..5a4e2d422 100644 --- a/site/content/docs/v1.12/csi.md +++ b/site/content/docs/v1.12/csi.md @@ -24,7 +24,7 @@ Both of these can be added with the `velero install` command. ```bash velero install \ --features=EnableCSI \ ---plugins=,velero/velero-plugin-for-csi:v0.3.0 \ +--plugins=,velero/velero-plugin-for-csi:v0.6.0 \ ... ``` diff --git a/site/content/docs/v1.13/csi.md b/site/content/docs/v1.13/csi.md index d1cc8e824..6fd1f9a72 100644 --- a/site/content/docs/v1.13/csi.md +++ b/site/content/docs/v1.13/csi.md @@ -24,7 +24,7 @@ Both of these can be added with the `velero install` command. ```bash velero install \ --features=EnableCSI \ ---plugins=,velero/velero-plugin-for-csi:v0.3.0 \ +--plugins=,velero/velero-plugin-for-csi:v0.7.0 \ ... ``` diff --git a/site/content/docs/v1.7/csi.md b/site/content/docs/v1.7/csi.md index 49f4f77e9..99365e719 100644 --- a/site/content/docs/v1.7/csi.md +++ b/site/content/docs/v1.7/csi.md @@ -27,7 +27,7 @@ Both of these can be added with the `velero install` command. ```bash velero install \ --features=EnableCSI \ ---plugins=,velero/velero-plugin-for-csi:v0.1.0 \ +--plugins=,velero/velero-plugin-for-csi:v0.2.0 \ ... ``` diff --git a/site/content/docs/v1.8/csi.md b/site/content/docs/v1.8/csi.md index 49f4f77e9..99365e719 100644 --- a/site/content/docs/v1.8/csi.md +++ b/site/content/docs/v1.8/csi.md @@ -27,7 +27,7 @@ Both of these can be added with the `velero install` command. ```bash velero install \ --features=EnableCSI \ ---plugins=,velero/velero-plugin-for-csi:v0.1.0 \ +--plugins=,velero/velero-plugin-for-csi:v0.2.0 \ ... ```