diff --git a/CLAUDE.md b/CLAUDE.md
index a4267581..9771c90e 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -2,9 +2,15 @@
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+## Architecture Overview
+### Core Components
+1. **Backend code** (`engine/`)
+ 1.1. **Entry Points** (`cmd/`)
+2. **Frontend code** (`ui/`)
+
## Build/Test/Lint Commands
- Build all components: `cd engine && make build`
-- Lint code: `cd engine && make lint`
+- Lint code: `cd engine && make run-lint`
- Run unit tests: `cd engine && make test`
- Run integration tests: `cd engine && make test-ci-integration`
- Run a specific test: `cd engine && GO111MODULE=on go test -v ./path/to/package -run TestName`
@@ -20,4 +26,123 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
- Follow standard Go import ordering
- Group similar functions together
- Error messages should be descriptive and actionable
-- UI uses pnpm for package management
\ No newline at end of file
+- UI uses pnpm for package management
+
+## Important Backend Workflow Notes
+
+- Always run tests, linter and normalize comments BEFORE committing anything
+- Run formatting, code generation, linting and testing on completion
+- Never commit without running completion sequence
+- Run tests and linter after making significant changes to verify functionality
+- IMPORTANT: Never put into commit message any mention of Claude or Claude Code
+- IMPORTANT: Never include "Test plan" sections in PR descriptions
+- Do not add comments that describe changes, progress, or historical modifications
+- Comments should only describe the current state and purpose of the code, not its history or evolution
+- After important functionality added, update README.md accordingly
+- When merging master changes to an active branch, make sure both branches are pulled and up to date first
+- Don't leave commented out code in place
+- Avoid multi-level nesting
+- Avoid multi-level ifs, never use else if
+- Never use goto
+- Avoid else branches if possible
+- Write tests in compact form by fitting struct fields to a single line (up to 130 characters)
+- Before any significant refactoring, ensure all tests pass and consider creating a new branch
+- When refactoring, editing, or fixing failed tests:
+ - Do not redesign fundamental parts of the code architecture
+ - If unable to fix an issue with the current approach, report the problem and ask for guidance
+ - Focus on minimal changes to address the specific issue at hand
+ - Preserve the existing patterns and conventions of the codebase
+
+## Backend Code Style Guidelines
+
+### Import Organization
+- Organize imports in the following order:
+ 1. Standard library packages first (e.g., "fmt", "context")
+ 2. A blank line separator
+ 3. Third-party packages
+ 4. A blank line separator
+ 5. Project imports (e.g., "gitlab.com/postgres-ai/database-lab/v3/pkg/*")
+- Example:
+ ```go
+ import (
+ "context"
+ "fmt"
+ "net/http"
+
+ "github.com/docker/docker/api/types"
+ "github.com/gorilla/mux"
+
+ "gitlab.com/postgres-ai/database-lab/v3/pkg/util/branching"
+ )
+ ```
+
+### Error Handling
+- Return errors to the caller rather than using panics
+- Use descriptive error messages that help with debugging
+- Use error wrapping: `fmt.Errorf("failed to process request: %w", err)`
+- Check errors immediately after function calls
+- Return early when possible to avoid deep nesting
+
+### Variable Naming
+- Use descriptive camelCase names for variables and functions
+- Good: `notFoundHandler`, `requestContext`, `userID`
+- Bad: `not_found_handler`, `x`, `temp1`
+- Be consistent with abbreviations (e.g., `httpClient` not `HTTPClient`)
+- Local scope variables can be short (e.g., "lmt" instead of "orderLimit")
+- Use constants for magic numbers and strings
+- Use meaningful names for constants and enums
+
+### Function Parameters
+- Group related parameters together logically
+- Use descriptive parameter names that indicate their purpose
+- Consider using parameter structs for functions with many (4+) parameters
+- If function returns 3 or more results, consider wrapping in Result/Response struct
+- If function accepts 3 or more input parameters, consider wrapping in Request/Input struct (but never add context to struct)
+
+### Documentation
+- All exported functions, types, and methods must have clear godoc comments
+- Begin comments with the name of the element being documented
+- Include usage examples for complex functions
+- Document any non-obvious behavior or edge cases
+- All comments should be lowercase, except for godoc public functions and methods
+- IMPORTANT: all comments except godoc comments must be lowercase, test messages must be lowercase, log messages must be lowercase
+
+### Code Structure
+- Keep code modular with focused responsibilities
+- Limit file sizes to 300-500 lines when possible
+- Group related functionality in the same package
+- Use interfaces to define behavior and enable mocking for tests
+- Keep code minimal and avoid unnecessary complexity
+- Don't keep old functions for imaginary compatibility
+- Interfaces should be defined on the consumer side (idiomatic Go)
+- Aim to pass interfaces but return concrete types when possible
+- Consider nested functions when they simplify complex functions
+
+### Code Layout
+- Keep cyclomatic complexity under 30
+- Function size preferences:
+ - Aim for functions around 50-60 lines when possible
+ - Don't break down functions too small as it can reduce readability
+ - Maintain focus on a single responsibility per function
+- Keep lines under 130 characters when possible
+- Avoid if-else chains and nested conditionals:
+ - Never use long if-else-if chains; use switch statements instead
+ - Prefer early returns to reduce nesting depth
+ - Extract complex conditions into separate boolean functions or variables
+ - Use context structs or functional options instead of multiple boolean flags
+
+### Testing
+- Write thorough tests with descriptive names (e.g., `TestRouter_HandlesMiddlewareCorrectly`)
+- Prefer subtests or table-based tests, using Testify
+- Use table-driven tests for testing multiple cases with the same logic
+- Test both success and error scenarios
+- Mock external dependencies to ensure unit tests are isolated and fast
+- Aim for at least 80% code coverage
+- Keep tests compact but readable
+- If test has too many subtests, consider splitting it to multiple tests
+- Never disable tests without a good reason and approval
+- Important: Never update code with special conditions to just pass tests
+- Don't create new test files if one already exists matching the source file name
+- Add new tests to existing test files following the same naming and structuring conventions
+- Don't add comments before subtests, t.Run("description") already communicates what test case is doing
+- Never use godoc-style comments for test functions
diff --git a/LICENSE b/LICENSE
index cb43d4eb..b0cc8d52 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright 2023 Postgres.ai https://postgres.ai/
+ Copyright 2023-2025 Postgres AI https://postgres.ai/
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index 9eada025..8ae9f89a 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@
-
+
@@ -92,7 +92,7 @@ Read more:
- Theoretical max of snapshots/clones: 264 ([ZFS](https://en.wikipedia.org/wiki/ZFS), default)
- Maximum size of PostgreSQL data directory: 256 quadrillion zebibytes, or 2128 bytes ([ZFS](https://en.wikipedia.org/wiki/ZFS), default)
- Support & technologies
- - Supported PostgreSQL versions: 9.6–17
+ - Supported PostgreSQL versions: 9.6–18
- Thin cloning ([CoW](https://en.wikipedia.org/wiki/Copy-on-write)) technologies: [ZFS](https://en.wikipedia.org/wiki/ZFS) and [LVM](https://en.wikipedia.org/wiki/Logical_Volume_Manager_(Linux))
- UI for manual tasks and API & CLI for automation
- Packaged in Docker containers for all components
diff --git a/engine/.gitlab-ci.yml b/engine/.gitlab-ci.yml
index a048e132..22c505d9 100644
--- a/engine/.gitlab-ci.yml
+++ b/engine/.gitlab-ci.yml
@@ -1,6 +1,6 @@
default:
image:
- name: golang:1.23
+ name: golang:1.24
pull_policy: if-not-present
stages:
@@ -8,7 +8,6 @@ stages:
- build-binary
- build
- integration-test
- - deploy
## Conditions.
.only_engine: &only_engine
@@ -59,7 +58,7 @@ lint:
build-binary-alpine:
<<: *only_engine
image:
- name: golang:1.23-alpine
+ name: golang:1.24-alpine
pull_policy: if-not-present
stage: build-binary
artifacts:
@@ -88,8 +87,8 @@ build-binary-client-master:
- make build-client
# Install google-cloud-sdk.
+ - curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
- echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
- - curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
- apt-get update && apt-get install -y google-cloud-sdk
# Authenticate.
@@ -108,8 +107,8 @@ build-binary-client:
- make build-client
# Install google-cloud-sdk.
+ - curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
- echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
- - curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
- apt-get update && apt-get install -y google-cloud-sdk
# Authenticate.
@@ -129,8 +128,8 @@ build-binary-client-rc:
- make build-client
# Install google-cloud-sdk.
+ - curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
- echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
- - curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
- apt-get update && apt-get install -y google-cloud-sdk
# Authenticate.
@@ -478,6 +477,11 @@ bash-test-17:
variables:
POSTGRES_VERSION: 17
+bash-test-18:
+ <<: *bash_test
+ variables:
+ POSTGRES_VERSION: 18
+
integration-test:
services:
- name: docker:24-dind
@@ -498,26 +502,3 @@ integration-test:
script:
- cd engine
- make test-ci-integration
-
-## Deploy
-.deploy-definition: &deploy_definition
- stage: deploy
- image:
- name: dtzar/helm-kubectl:2.14.1
- pull_policy: if-not-present
- script:
- - bash ./engine/scripts/do.sh subs_envs ./engine/deploy/swagger-ui.yaml /tmp/swagger-ui.yaml
- - kubectl apply --filename /tmp/swagger-ui.yaml -n $NAMESPACE
-
-deploy-swagger-ui-tag-release:
- <<: *only_tag_release
- <<: *deploy_definition
- environment:
- name: production
- variables:
- ENV: production
- NAMESPACE: production
- DOCKER_IMAGE_NAME: "registry.gitlab.com/postgres-ai/database-lab/dblab-swagger-ui"
- before_script:
- - export CLEAN_TAG=$(echo ${CI_COMMIT_TAG#"v"})
- - export TAG="${DOCKER_IMAGE_NAME}:${CLEAN_TAG}"
diff --git a/engine/.golangci.yml b/engine/.golangci.yml
index bad31644..18c7ec5c 100644
--- a/engine/.golangci.yml
+++ b/engine/.golangci.yml
@@ -63,6 +63,8 @@ linters-settings:
- performance
disabled-tags:
- experimental
+ staticcheck:
+ checks: [ "all" ]
linters:
enable:
diff --git a/engine/Dockerfile.ci-checker b/engine/Dockerfile.ci-checker
index b509bc51..d4ebcb20 100644
--- a/engine/Dockerfile.ci-checker
+++ b/engine/Dockerfile.ci-checker
@@ -1,4 +1,4 @@
-FROM docker:20.10.24
+FROM docker:27.1.1
# Install dependencies.
RUN apk update && apk add --no-cache bash
diff --git a/engine/Dockerfile.dblab-cli b/engine/Dockerfile.dblab-cli
index d14f8222..fb27b605 100644
--- a/engine/Dockerfile.dblab-cli
+++ b/engine/Dockerfile.dblab-cli
@@ -1,4 +1,4 @@
-FROM docker:20.10.24
+FROM docker:27.1.1
# Install dependencies.
RUN apk update && apk add --no-cache bash jq tzdata
diff --git a/engine/Dockerfile.dblab-server b/engine/Dockerfile.dblab-server
index c1d2644c..77e076ce 100644
--- a/engine/Dockerfile.dblab-server
+++ b/engine/Dockerfile.dblab-server
@@ -1,6 +1,6 @@
# See Guides to learn how to start a container: https://postgres.ai/docs/how-to-guides/administration/engine-manage
-FROM docker:20.10.24
+FROM docker:27.1.1
# Install dependencies
RUN apk update \
diff --git a/engine/Dockerfile.dblab-server-debug b/engine/Dockerfile.dblab-server-debug
index af6b1f17..f7e8c273 100644
--- a/engine/Dockerfile.dblab-server-debug
+++ b/engine/Dockerfile.dblab-server-debug
@@ -1,7 +1,7 @@
# How to start a container: https://postgres.ai/docs/how-to-guides/administration/engine-manage
# Compile stage
-FROM golang:1.23 AS build-env
+FROM golang:1.24 AS build-env
# Build Delve
RUN go install github.com/go-delve/delve/cmd/dlv@latest
@@ -12,7 +12,7 @@ RUN go install github.com/go-delve/delve/cmd/dlv@latest
# RUN GO111MODULE=on CGO_ENABLED=0 go build -gcflags="all=-N -l" -o /dblab-server-debug ./cmd/database-lab/main.go
# Final stage
-FROM docker:20.10.12
+FROM docker:27.1.1
# Install dependencies
RUN apk update \
diff --git a/engine/Dockerfile.dblab-server-zfs08 b/engine/Dockerfile.dblab-server-zfs08
index 5ed8938c..43ccc46a 100644
--- a/engine/Dockerfile.dblab-server-zfs08
+++ b/engine/Dockerfile.dblab-server-zfs08
@@ -1,6 +1,6 @@
# See Guides to learn how to start a container: https://postgres.ai/docs/how-to-guides/administration/engine-manage
-FROM docker:20.10.24
+FROM docker:27.1.1
# Install dependencies.
RUN apk update && apk add zfs=0.8.4-r0 --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/v3.12/main \
diff --git a/engine/Makefile b/engine/Makefile
index 84bf96de..ffb2edf0 100644
--- a/engine/Makefile
+++ b/engine/Makefile
@@ -34,7 +34,7 @@ help: ## Display the help message
all: clean build ## Build all binary components of the project
install-lint: ## Install the linter to $GOPATH/bin which is expected to be in $PATH
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.61.0
+ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.64.8
run-lint: ## Run linters
golangci-lint run
diff --git a/engine/cmd/cli/templates/help.go b/engine/cmd/cli/templates/help.go
index fe515397..be3b5993 100644
--- a/engine/cmd/cli/templates/help.go
+++ b/engine/cmd/cli/templates/help.go
@@ -5,7 +5,7 @@
// Package templates contains custom template output.
package templates
-//nolint
+// nolint
const CustomAppHelpTemplate = `NAME:
Database Lab CLI {{if .Version}}{{if not .HideVersion}}{{.Version}}{{end}}{{end}}
@@ -35,7 +35,7 @@ CONTACT US: https://postgres.ai, team@postgres.ai
`
-//nolint
+// nolint
const CustomCommandHelpTemplate = `USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}}
@@ -50,7 +50,7 @@ OPTIONS:
{{end}}{{end}}
`
-//nolint
+// nolint
const CustomSubcommandHelpTemplate = `USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
diff --git a/engine/cmd/database-lab/main.go b/engine/cmd/database-lab/main.go
index edce91b7..649c4825 100644
--- a/engine/cmd/database-lab/main.go
+++ b/engine/cmd/database-lab/main.go
@@ -18,7 +18,7 @@ import (
"syscall"
"time"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/pkg/errors"
@@ -62,7 +62,7 @@ func main() {
config.ApplyGlobals(cfg)
- docker, err := client.NewClientWithOpts(client.FromEnv)
+ docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
log.Fatal("Failed to create a Docker client:", err)
}
@@ -273,7 +273,7 @@ func main() {
func getNetworkGateway(docker *client.Client, internalNetworkID string) string {
gateway := ""
- networkResource, err := docker.NetworkInspect(context.Background(), internalNetworkID, types.NetworkInspectOptions{})
+ networkResource, err := docker.NetworkInspect(context.Background(), internalNetworkID, network.InspectOptions{})
if err != nil {
log.Err(err.Error())
return gateway
diff --git a/engine/cmd/runci/main.go b/engine/cmd/runci/main.go
index 47905644..b5e58fa6 100644
--- a/engine/cmd/runci/main.go
+++ b/engine/cmd/runci/main.go
@@ -7,7 +7,6 @@ import (
"os"
"strings"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
"github.com/pkg/errors"
@@ -22,7 +21,7 @@ import (
)
func main() {
- dockerCLI, err := client.NewClientWithOpts(client.FromEnv)
+ dockerCLI, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
log.Fatal("Failed to create a Docker client:", err)
}
@@ -129,7 +128,7 @@ func discoverNetwork(ctx context.Context, cfg *runci.Config, dockerCLI *client.C
for networkLabel, endpointSettings := range inspection.NetworkSettings.Networks {
if strings.HasPrefix(networkLabel, networks.NetworkPrefix) {
- networkResource, err := dockerCLI.NetworkInspect(ctx, endpointSettings.NetworkID, types.NetworkInspectOptions{})
+ networkResource, err := dockerCLI.NetworkInspect(ctx, endpointSettings.NetworkID, network.InspectOptions{})
if err != nil {
log.Err(err)
continue
diff --git a/engine/configs/config.example.logical_generic.yml b/engine/configs/config.example.logical_generic.yml
index 2ba2c6ac..a15d3cea 100644
--- a/engine/configs/config.example.logical_generic.yml
+++ b/engine/configs/config.example.logical_generic.yml
@@ -73,7 +73,7 @@ retrieval: # Data retrieval: initial sync and ongoing updates. Two methods:
type: remote # Source types: "local", "remote", "rdsIam"
connection: # Database connection parameters; use PGPASSWORD env var for password
dbname: postgres
- host: 34.56.78.90
+ host:
port: 5432
username: postgres
password: postgres # Use PGPASSWORD env var instead (higher priority)
diff --git a/engine/configs/standard/postgres/default/18/pg_hba.conf b/engine/configs/standard/postgres/default/18/pg_hba.conf
new file mode 100644
index 00000000..cccbfad1
--- /dev/null
+++ b/engine/configs/standard/postgres/default/18/pg_hba.conf
@@ -0,0 +1,128 @@
+# PostgreSQL Client Authentication Configuration File
+# ===================================================
+#
+# Refer to the "Client Authentication" section in the PostgreSQL
+# documentation for a complete description of this file. A short
+# synopsis follows.
+#
+# ----------------------
+# Authentication Records
+# ----------------------
+#
+# This file controls: which hosts are allowed to connect, how clients
+# are authenticated, which PostgreSQL user names they can use, which
+# databases they can access. Records take one of these forms:
+#
+# local DATABASE USER METHOD [OPTIONS]
+# host DATABASE USER ADDRESS METHOD [OPTIONS]
+# hostssl DATABASE USER ADDRESS METHOD [OPTIONS]
+# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS]
+# hostgssenc DATABASE USER ADDRESS METHOD [OPTIONS]
+# hostnogssenc DATABASE USER ADDRESS METHOD [OPTIONS]
+#
+# (The uppercase items must be replaced by actual values.)
+#
+# The first field is the connection type:
+# - "local" is a Unix-domain socket
+# - "host" is a TCP/IP socket (encrypted or not)
+# - "hostssl" is a TCP/IP socket that is SSL-encrypted
+# - "hostnossl" is a TCP/IP socket that is not SSL-encrypted
+# - "hostgssenc" is a TCP/IP socket that is GSSAPI-encrypted
+# - "hostnogssenc" is a TCP/IP socket that is not GSSAPI-encrypted
+#
+# DATABASE can be "all", "sameuser", "samerole", "replication", a
+# database name, a regular expression (if it starts with a slash (/))
+# or a comma-separated list thereof. The "all" keyword does not match
+# "replication". Access to replication must be enabled in a separate
+# record (see example below).
+#
+# USER can be "all", a user name, a group name prefixed with "+", a
+# regular expression (if it starts with a slash (/)) or a comma-separated
+# list thereof. In both the DATABASE and USER fields you can also write
+# a file name prefixed with "@" to include names from a separate file.
+#
+# ADDRESS specifies the set of hosts the record matches. It can be a
+# host name, or it is made up of an IP address and a CIDR mask that is
+# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that
+# specifies the number of significant bits in the mask. A host name
+# that starts with a dot (.) matches a suffix of the actual host name.
+# Alternatively, you can write an IP address and netmask in separate
+# columns to specify the set of hosts. Instead of a CIDR-address, you
+# can write "samehost" to match any of the server's own IP addresses,
+# or "samenet" to match any address in any subnet that the server is
+# directly connected to.
+#
+# METHOD can be "trust", "reject", "scram-sha-256", "password", "gss",
+# "sspi", "ident", "peer", "pam", "ldap", "radius", "cert" or "oauth".
+# Note that "password" sends passwords in clear text; "scram-sha-256" is
+# preferred since it sends encrypted passwords.
+#
+# OPTIONS are a set of options for the authentication in the format
+# NAME=VALUE. The available options depend on the different
+# authentication methods -- refer to the "Client Authentication"
+# section in the documentation for a list of which options are
+# available for which authentication methods.
+#
+# Database and user names containing spaces, commas, quotes and other
+# special characters must be quoted. Quoting one of the keywords
+# "all", "sameuser", "samerole" or "replication" makes the name lose
+# its special character, and just match a database or username with
+# that name.
+#
+# ---------------
+# Include Records
+# ---------------
+#
+# This file allows the inclusion of external files or directories holding
+# more records, using the following keywords:
+#
+# include FILE
+# include_if_exists FILE
+# include_dir DIRECTORY
+#
+# FILE is the file name to include, and DIR is the directory name containing
+# the file(s) to include. Any file in a directory will be loaded if suffixed
+# with ".conf". The files of a directory are ordered by name.
+# include_if_exists ignores missing files. FILE and DIRECTORY can be
+# specified as a relative or an absolute path, and can be double-quoted if
+# they contain spaces.
+#
+# -------------
+# Miscellaneous
+# -------------
+#
+# This file is read on server startup and when the server receives a
+# SIGHUP signal. If you edit the file on a running system, you have to
+# SIGHUP the server for the changes to take effect, run "pg_ctl reload",
+# or execute "SELECT pg_reload_conf()".
+#
+# ----------------------------------
+# Put your actual configuration here
+# ----------------------------------
+#
+# If you want to allow non-local connections, you need to add more
+# "host" records. In that case you will also need to make PostgreSQL
+# listen on a non-local interface via the listen_addresses
+# configuration parameter, or via the -i or -h command line switches.
+
+# CAUTION: Configuring the system for local "trust" authentication
+# allows any local user to connect as any PostgreSQL user, including
+# the database superuser. If you do not trust all your local users,
+# use another authentication method.
+
+
+# TYPE DATABASE USER ADDRESS METHOD
+
+# "local" is for Unix domain socket connections only
+local all all trust
+# IPv4 local connections:
+host all all 127.0.0.1/32 trust
+# IPv6 local connections:
+host all all ::1/128 trust
+# Allow replication connections from localhost, by a user with the
+# replication privilege.
+local replication all trust
+host replication all 127.0.0.1/32 trust
+host replication all ::1/128 trust
+
+host all all all scram-sha-256
diff --git a/engine/configs/standard/postgres/default/18/postgresql.dblab.postgresql.conf b/engine/configs/standard/postgres/default/18/postgresql.dblab.postgresql.conf
new file mode 100644
index 00000000..425de11c
--- /dev/null
+++ b/engine/configs/standard/postgres/default/18/postgresql.dblab.postgresql.conf
@@ -0,0 +1,884 @@
+# -----------------------------
+# PostgreSQL configuration file
+# -----------------------------
+#
+# This file consists of lines of the form:
+#
+# name = value
+#
+# (The "=" is optional.) Whitespace may be used. Comments are introduced with
+# "#" anywhere on a line. The complete list of parameter names and allowed
+# values can be found in the PostgreSQL documentation.
+#
+# The commented-out settings shown in this file represent the default values.
+# Re-commenting a setting is NOT sufficient to revert it to the default value;
+# you need to reload the server.
+#
+# This file is read on server startup and when the server receives a SIGHUP
+# signal. If you edit the file on a running system, you have to SIGHUP the
+# server for the changes to take effect, run "pg_ctl reload", or execute
+# "SELECT pg_reload_conf()". Some parameters, which are marked below,
+# require a server shutdown and restart to take effect.
+#
+# Any parameter can also be given as a command-line option to the server, e.g.,
+# "postgres -c log_connections=all". Some parameters can be changed at run time
+# with the "SET" SQL command.
+#
+# Memory units: B = bytes Time units: us = microseconds
+# kB = kilobytes ms = milliseconds
+# MB = megabytes s = seconds
+# GB = gigabytes min = minutes
+# TB = terabytes h = hours
+# d = days
+
+
+#------------------------------------------------------------------------------
+# FILE LOCATIONS
+#------------------------------------------------------------------------------
+
+# The default values of these variables are driven from the -D command-line
+# option or PGDATA environment variable, represented here as ConfigDir.
+
+#data_directory = 'ConfigDir' # use data in another directory
+ # (change requires restart)
+#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file
+ # (change requires restart)
+#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file
+ # (change requires restart)
+
+# If external_pid_file is not explicitly set, no extra PID file is written.
+#external_pid_file = '' # write an extra PID file
+ # (change requires restart)
+
+
+#------------------------------------------------------------------------------
+# CONNECTIONS AND AUTHENTICATION
+#------------------------------------------------------------------------------
+
+# - Connection Settings -
+
+listen_addresses = '*'
+ # comma-separated list of addresses;
+ # defaults to 'localhost'; use '*' for all
+ # (change requires restart)
+#port = 5432 # (change requires restart)
+max_connections = 100 # (change requires restart)
+#reserved_connections = 0 # (change requires restart)
+#superuser_reserved_connections = 3 # (change requires restart)
+#unix_socket_directories = '/var/run/postgresql' # comma-separated list of directories
+ # (change requires restart)
+#unix_socket_group = '' # (change requires restart)
+#unix_socket_permissions = 0777 # begin with 0 to use octal notation
+ # (change requires restart)
+#bonjour = off # advertise server via Bonjour
+ # (change requires restart)
+#bonjour_name = '' # defaults to the computer name
+ # (change requires restart)
+
+# - TCP settings -
+# see "man tcp" for details
+
+#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds;
+ # 0 selects the system default
+#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds;
+ # 0 selects the system default
+#tcp_keepalives_count = 0 # TCP_KEEPCNT;
+ # 0 selects the system default
+#tcp_user_timeout = 0 # TCP_USER_TIMEOUT, in milliseconds;
+ # 0 selects the system default
+
+#client_connection_check_interval = 0 # time between checks for client
+ # disconnection while running queries;
+ # 0 for never
+
+# - Authentication -
+
+#authentication_timeout = 1min # 1s-600s
+#password_encryption = scram-sha-256 # scram-sha-256 or md5
+#scram_iterations = 4096
+#md5_password_warnings = on
+#oauth_validator_libraries = '' # comma-separated list of trusted validator modules
+
+# GSSAPI using Kerberos
+#krb_server_keyfile = 'FILE:${sysconfdir}/krb5.keytab'
+#krb_caseins_users = off
+#gss_accept_delegation = off
+
+# - SSL -
+
+#ssl = off
+#ssl_ca_file = ''
+#ssl_cert_file = 'server.crt'
+#ssl_crl_file = ''
+#ssl_crl_dir = ''
+#ssl_key_file = 'server.key'
+#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed TLSv1.2 ciphers
+#ssl_tls13_ciphers = '' # allowed TLSv1.3 cipher suites, blank for default
+#ssl_prefer_server_ciphers = on
+#ssl_groups = 'X25519:prime256v1'
+#ssl_min_protocol_version = 'TLSv1.2'
+#ssl_max_protocol_version = ''
+#ssl_dh_params_file = ''
+#ssl_passphrase_command = ''
+#ssl_passphrase_command_supports_reload = off
+
+
+#------------------------------------------------------------------------------
+# RESOURCE USAGE (except WAL)
+#------------------------------------------------------------------------------
+
+# - Memory -
+
+shared_buffers = 128MB # min 128kB
+ # (change requires restart)
+#huge_pages = try # on, off, or try
+ # (change requires restart)
+#huge_page_size = 0 # zero for system default
+ # (change requires restart)
+#temp_buffers = 8MB # min 800kB
+#max_prepared_transactions = 0 # zero disables the feature
+ # (change requires restart)
+# Caution: it is not advisable to set max_prepared_transactions nonzero unless
+# you actively intend to use prepared transactions.
+#work_mem = 4MB # min 64kB
+#hash_mem_multiplier = 2.0 # 1-1000.0 multiplier on hash table work_mem
+#maintenance_work_mem = 64MB # min 64kB
+#autovacuum_work_mem = -1 # min 64kB, or -1 to use maintenance_work_mem
+#logical_decoding_work_mem = 64MB # min 64kB
+#max_stack_depth = 2MB # min 100kB
+#shared_memory_type = mmap # the default is the first option
+ # supported by the operating system:
+ # mmap
+ # sysv
+ # windows
+ # (change requires restart)
+dynamic_shared_memory_type = posix # the default is usually the first option
+ # supported by the operating system:
+ # posix
+ # sysv
+ # windows
+ # mmap
+ # (change requires restart)
+#min_dynamic_shared_memory = 0MB # (change requires restart)
+#vacuum_buffer_usage_limit = 2MB # size of vacuum and analyze buffer access strategy ring;
+ # 0 to disable vacuum buffer access strategy;
+ # range 128kB to 16GB
+
+# SLRU buffers (change requires restart)
+#commit_timestamp_buffers = 0 # memory for pg_commit_ts (0 = auto)
+#multixact_offset_buffers = 16 # memory for pg_multixact/offsets
+#multixact_member_buffers = 32 # memory for pg_multixact/members
+#notify_buffers = 16 # memory for pg_notify
+#serializable_buffers = 32 # memory for pg_serial
+#subtransaction_buffers = 0 # memory for pg_subtrans (0 = auto)
+#transaction_buffers = 0 # memory for pg_xact (0 = auto)
+
+# - Disk -
+
+#temp_file_limit = -1 # limits per-process temp file space
+ # in kilobytes, or -1 for no limit
+
+#file_copy_method = copy # copy, clone (if supported by OS)
+
+#max_notify_queue_pages = 1048576 # limits the number of SLRU pages allocated
+ # for NOTIFY / LISTEN queue
+
+# - Kernel Resources -
+
+#max_files_per_process = 1000 # min 64
+ # (change requires restart)
+
+# - Background Writer -
+
+#bgwriter_delay = 200ms # 10-10000ms between rounds
+#bgwriter_lru_maxpages = 100 # max buffers written/round, 0 disables
+#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round
+#bgwriter_flush_after = 512kB # measured in pages, 0 disables
+
+# - I/O -
+
+#backend_flush_after = 0 # measured in pages, 0 disables
+#effective_io_concurrency = 16 # 1-1000; 0 disables issuing multiple simultaneous IO requests
+#maintenance_io_concurrency = 16 # 1-1000; same as effective_io_concurrency
+#io_max_combine_limit = 128kB # usually 1-128 blocks (depends on OS)
+ # (change requires restart)
+#io_combine_limit = 128kB # usually 1-128 blocks (depends on OS)
+
+#io_method = worker # worker, io_uring, sync
+ # (change requires restart)
+#io_max_concurrency = -1 # Max number of IOs that one process
+ # can execute simultaneously
+ # -1 sets based on shared_buffers
+ # (change requires restart)
+#io_workers = 3 # 1-32;
+
+# - Worker Processes -
+
+#max_worker_processes = 8 # (change requires restart)
+#max_parallel_workers_per_gather = 2 # limited by max_parallel_workers
+#max_parallel_maintenance_workers = 2 # limited by max_parallel_workers
+#max_parallel_workers = 8 # number of max_worker_processes that
+ # can be used in parallel operations
+#parallel_leader_participation = on
+
+
+#------------------------------------------------------------------------------
+# WRITE-AHEAD LOG
+#------------------------------------------------------------------------------
+
+# - Settings -
+
+#wal_level = replica # minimal, replica, or logical
+ # (change requires restart)
+#fsync = on # flush data to disk for crash safety
+ # (turning this off can cause
+ # unrecoverable data corruption)
+#synchronous_commit = on # synchronization level;
+ # off, local, remote_write, remote_apply, or on
+#wal_sync_method = fsync # the default is the first option
+ # supported by the operating system:
+ # open_datasync
+ # fdatasync (default on Linux and FreeBSD)
+ # fsync
+ # fsync_writethrough
+ # open_sync
+#full_page_writes = on # recover from partial page writes
+#wal_log_hints = off # also do full page writes of non-critical updates
+ # (change requires restart)
+#wal_compression = off # enables compression of full-page writes;
+ # off, pglz, lz4, zstd, or on
+#wal_init_zero = on # zero-fill new WAL files
+#wal_recycle = on # recycle WAL files
+#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers
+ # (change requires restart)
+#wal_writer_delay = 200ms # 1-10000 milliseconds
+#wal_writer_flush_after = 1MB # measured in pages, 0 disables
+#wal_skip_threshold = 2MB
+
+#commit_delay = 0 # range 0-100000, in microseconds
+#commit_siblings = 5 # range 1-1000
+
+# - Checkpoints -
+
+#checkpoint_timeout = 5min # range 30s-1d
+#checkpoint_completion_target = 0.9 # checkpoint target duration, 0.0 - 1.0
+#checkpoint_flush_after = 256kB # measured in pages, 0 disables
+#checkpoint_warning = 30s # 0 disables
+max_wal_size = 1GB
+min_wal_size = 80MB
+
+# - Prefetching during recovery -
+
+#recovery_prefetch = try # prefetch pages referenced in the WAL?
+#wal_decode_buffer_size = 512kB # lookahead window used for prefetching
+ # (change requires restart)
+
+# - Archiving -
+
+#archive_mode = off # enables archiving; off, on, or always
+ # (change requires restart)
+#archive_library = '' # library to use to archive a WAL file
+ # (empty string indicates archive_command should
+ # be used)
+#archive_command = '' # command to use to archive a WAL file
+ # placeholders: %p = path of file to archive
+ # %f = file name only
+ # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
+#archive_timeout = 0 # force a WAL file switch after this
+ # number of seconds; 0 disables
+
+# - Archive Recovery -
+
+# These are only used in recovery mode.
+
+#restore_command = '' # command to use to restore an archived WAL file
+ # placeholders: %p = path of file to restore
+ # %f = file name only
+ # e.g. 'cp /mnt/server/archivedir/%f %p'
+#archive_cleanup_command = '' # command to execute at every restartpoint
+#recovery_end_command = '' # command to execute at completion of recovery
+
+# - Recovery Target -
+
+# Set these only when performing a targeted recovery.
+
+#recovery_target = '' # 'immediate' to end recovery as soon as a
+ # consistent state is reached
+ # (change requires restart)
+#recovery_target_name = '' # the named restore point to which recovery will proceed
+ # (change requires restart)
+#recovery_target_time = '' # the time stamp up to which recovery will proceed
+ # (change requires restart)
+#recovery_target_xid = '' # the transaction ID up to which recovery will proceed
+ # (change requires restart)
+#recovery_target_lsn = '' # the WAL LSN up to which recovery will proceed
+ # (change requires restart)
+#recovery_target_inclusive = on # Specifies whether to stop:
+ # just after the specified recovery target (on)
+ # just before the recovery target (off)
+ # (change requires restart)
+#recovery_target_timeline = 'latest' # 'current', 'latest', or timeline ID
+ # (change requires restart)
+#recovery_target_action = 'pause' # 'pause', 'promote', 'shutdown'
+ # (change requires restart)
+
+# - WAL Summarization -
+
+#summarize_wal = off # run WAL summarizer process?
+#wal_summary_keep_time = '10d' # when to remove old summary files, 0 = never
+
+
+#------------------------------------------------------------------------------
+# REPLICATION
+#------------------------------------------------------------------------------
+
+# - Sending Servers -
+
+# Set these on the primary and on any standby that will send replication data.
+
+#max_wal_senders = 10 # max number of walsender processes
+ # (change requires restart)
+#max_replication_slots = 10 # max number of replication slots
+ # (change requires restart)
+#wal_keep_size = 0 # in megabytes; 0 disables
+#max_slot_wal_keep_size = -1 # in megabytes; -1 disables
+#idle_replication_slot_timeout = 0 # in seconds; 0 disables
+#wal_sender_timeout = 60s # in milliseconds; 0 disables
+#track_commit_timestamp = off # collect timestamp of transaction commit
+ # (change requires restart)
+
+# - Primary Server -
+
+# These settings are ignored on a standby server.
+
+#synchronous_standby_names = '' # standby servers that provide sync rep
+ # method to choose sync standbys, number of sync standbys,
+ # and comma-separated list of application_name
+ # from standby(s); '*' = all
+#synchronized_standby_slots = '' # streaming replication standby server slot
+ # names that logical walsender processes will wait for
+
+# - Standby Servers -
+
+# These settings are ignored on a primary server.
+
+#primary_conninfo = '' # connection string to sending server
+#primary_slot_name = '' # replication slot on sending server
+#hot_standby = on # "off" disallows queries during recovery
+ # (change requires restart)
+#max_standby_archive_delay = 30s # max delay before canceling queries
+ # when reading WAL from archive;
+ # -1 allows indefinite delay
+#max_standby_streaming_delay = 30s # max delay before canceling queries
+ # when reading streaming WAL;
+ # -1 allows indefinite delay
+#wal_receiver_create_temp_slot = off # create temp slot if primary_slot_name
+ # is not set
+#wal_receiver_status_interval = 10s # send replies at least this often
+ # 0 disables
+#hot_standby_feedback = off # send info from standby to prevent
+ # query conflicts
+#wal_receiver_timeout = 60s # time that receiver waits for
+ # communication from primary
+ # in milliseconds; 0 disables
+#wal_retrieve_retry_interval = 5s # time to wait before retrying to
+ # retrieve WAL after a failed attempt
+#recovery_min_apply_delay = 0 # minimum delay for applying changes during recovery
+#sync_replication_slots = off # enables slot synchronization on the physical standby from the primary
+
+# - Subscribers -
+
+# These settings are ignored on a publisher.
+
+#max_active_replication_origins = 10 # max number of active replication origins
+ # (change requires restart)
+#max_logical_replication_workers = 4 # taken from max_worker_processes
+ # (change requires restart)
+#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers
+#max_parallel_apply_workers_per_subscription = 2 # taken from max_logical_replication_workers
+
+
+#------------------------------------------------------------------------------
+# QUERY TUNING
+#------------------------------------------------------------------------------
+
+# - Planner Method Configuration -
+
+#enable_async_append = on
+#enable_bitmapscan = on
+#enable_gathermerge = on
+#enable_hashagg = on
+#enable_hashjoin = on
+#enable_incremental_sort = on
+#enable_indexscan = on
+#enable_indexonlyscan = on
+#enable_material = on
+#enable_memoize = on
+#enable_mergejoin = on
+#enable_nestloop = on
+#enable_parallel_append = on
+#enable_parallel_hash = on
+#enable_partition_pruning = on
+#enable_partitionwise_join = off
+#enable_partitionwise_aggregate = off
+#enable_presorted_aggregate = on
+#enable_seqscan = on
+#enable_sort = on
+#enable_tidscan = on
+#enable_group_by_reordering = on
+#enable_distinct_reordering = on
+#enable_self_join_elimination = on
+
+# - Planner Cost Constants -
+
+#seq_page_cost = 1.0 # measured on an arbitrary scale
+#random_page_cost = 4.0 # same scale as above
+#cpu_tuple_cost = 0.01 # same scale as above
+#cpu_index_tuple_cost = 0.005 # same scale as above
+#cpu_operator_cost = 0.0025 # same scale as above
+#parallel_setup_cost = 1000.0 # same scale as above
+#parallel_tuple_cost = 0.1 # same scale as above
+#min_parallel_table_scan_size = 8MB
+#min_parallel_index_scan_size = 512kB
+#effective_cache_size = 4GB
+
+#jit_above_cost = 100000 # perform JIT compilation if available
+ # and query more expensive than this;
+ # -1 disables
+#jit_inline_above_cost = 500000 # inline small functions if query is
+ # more expensive than this; -1 disables
+#jit_optimize_above_cost = 500000 # use expensive JIT optimizations if
+ # query is more expensive than this;
+ # -1 disables
+
+# - Genetic Query Optimizer -
+
+#geqo = on
+#geqo_threshold = 12
+#geqo_effort = 5 # range 1-10
+#geqo_pool_size = 0 # selects default based on effort
+#geqo_generations = 0 # selects default based on effort
+#geqo_selection_bias = 2.0 # range 1.5-2.0
+#geqo_seed = 0.0 # range 0.0-1.0
+
+# - Other Planner Options -
+
+#default_statistics_target = 100 # range 1-10000
+#constraint_exclusion = partition # on, off, or partition
+#cursor_tuple_fraction = 0.1 # range 0.0-1.0
+#from_collapse_limit = 8
+#jit = on # allow JIT compilation
+#join_collapse_limit = 8 # 1 disables collapsing of explicit
+ # JOIN clauses
+#plan_cache_mode = auto # auto, force_generic_plan or
+ # force_custom_plan
+#recursive_worktable_factor = 10.0 # range 0.001-1000000
+
+
+#------------------------------------------------------------------------------
+# REPORTING AND LOGGING
+#------------------------------------------------------------------------------
+
+# - Where to Log -
+
+#log_destination = 'stderr' # Valid values are combinations of
+ # stderr, csvlog, jsonlog, syslog, and
+ # eventlog, depending on platform.
+ # csvlog and jsonlog require
+ # logging_collector to be on.
+
+# This is used when logging to stderr:
+#logging_collector = off # Enable capturing of stderr, jsonlog,
+ # and csvlog into log files. Required
+ # to be on for csvlogs and jsonlogs.
+ # (change requires restart)
+
+# These are only used if logging_collector is on:
+#log_directory = 'log' # directory where log files are written,
+ # can be absolute or relative to PGDATA
+#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,
+ # can include strftime() escapes
+#log_file_mode = 0600 # creation mode for log files,
+ # begin with 0 to use octal notation
+#log_rotation_age = 1d # Automatic rotation of logfiles will
+ # happen after that time. 0 disables.
+#log_rotation_size = 10MB # Automatic rotation of logfiles will
+ # happen after that much log output.
+ # 0 disables.
+#log_truncate_on_rotation = off # If on, an existing log file with the
+ # same name as the new log file will be
+ # truncated rather than appended to.
+ # But such truncation only occurs on
+ # time-driven rotation, not on restarts
+ # or size-driven rotation. Default is
+ # off, meaning append to existing files
+ # in all cases.
+
+# These are relevant when logging to syslog:
+#syslog_facility = 'LOCAL0'
+#syslog_ident = 'postgres'
+#syslog_sequence_numbers = on
+#syslog_split_messages = on
+
+# This is only relevant when logging to eventlog (Windows):
+# (change requires restart)
+#event_source = 'PostgreSQL'
+
+# - When to Log -
+
+#log_min_messages = warning # values in order of decreasing detail:
+ # debug5
+ # debug4
+ # debug3
+ # debug2
+ # debug1
+ # info
+ # notice
+ # warning
+ # error
+ # log
+ # fatal
+ # panic
+
+#log_min_error_statement = error # values in order of decreasing detail:
+ # debug5
+ # debug4
+ # debug3
+ # debug2
+ # debug1
+ # info
+ # notice
+ # warning
+ # error
+ # log
+ # fatal
+ # panic (effectively off)
+
+#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements
+ # and their durations, > 0 logs only
+ # statements running at least this number
+ # of milliseconds
+
+#log_min_duration_sample = -1 # -1 is disabled, 0 logs a sample of statements
+ # and their durations, > 0 logs only a sample of
+ # statements running at least this number
+ # of milliseconds;
+ # sample fraction is determined by log_statement_sample_rate
+
+#log_statement_sample_rate = 1.0 # fraction of logged statements exceeding
+ # log_min_duration_sample to be logged;
+ # 1.0 logs all such statements, 0.0 never logs
+
+
+#log_transaction_sample_rate = 0.0 # fraction of transactions whose statements
+ # are logged regardless of their duration; 1.0 logs all
+ # statements from all transactions, 0.0 never logs
+
+#log_startup_progress_interval = 10s # Time between progress updates for
+ # long-running startup operations.
+ # 0 disables the feature, > 0 indicates
+ # the interval in milliseconds.
+
+# - What to Log -
+
+#debug_print_parse = off
+#debug_print_rewritten = off
+#debug_print_plan = off
+#debug_pretty_print = on
+#log_autovacuum_min_duration = 10min # log autovacuum activity;
+ # -1 disables, 0 logs all actions and
+ # their durations, > 0 logs only
+ # actions running at least this number
+ # of milliseconds.
+#log_checkpoints = on
+#log_connections = '' # log aspects of connection setup
+ # options include receipt, authentication, authorization,
+ # setup_durations, and all to log all of these aspects
+#log_disconnections = off
+#log_duration = off # log statement duration
+#log_error_verbosity = default # terse, default, or verbose messages
+#log_hostname = off
+#log_line_prefix = '%m [%p] ' # special values:
+ # %a = application name
+ # %u = user name
+ # %d = database name
+ # %r = remote host and port
+ # %h = remote host
+ # %L = local address
+ # %b = backend type
+ # %p = process ID
+ # %P = process ID of parallel group leader
+ # %t = timestamp without milliseconds
+ # %m = timestamp with milliseconds
+ # %n = timestamp with milliseconds (as a Unix epoch)
+ # %Q = query ID (0 if none or not computed)
+ # %i = command tag
+ # %e = SQL state
+ # %c = session ID
+ # %l = session line number
+ # %s = session start timestamp
+ # %v = virtual transaction ID
+ # %x = transaction ID (0 if none)
+ # %q = stop here in non-session
+ # processes
+ # %% = '%'
+ # e.g. '<%u%%%d> '
+#log_lock_waits = off # log lock waits >= deadlock_timeout
+#log_lock_failures = off # log lock failures
+#log_recovery_conflict_waits = off # log standby recovery conflict waits
+ # >= deadlock_timeout
+#log_parameter_max_length = -1 # when logging statements, limit logged
+ # bind-parameter values to N bytes;
+ # -1 means print in full, 0 disables
+#log_parameter_max_length_on_error = 0 # when logging an error, limit logged
+ # bind-parameter values to N bytes;
+ # -1 means print in full, 0 disables
+#log_statement = 'none' # none, ddl, mod, all
+#log_replication_commands = off
+#log_temp_files = -1 # log temporary files equal or larger
+ # than the specified size in kilobytes;
+ # -1 disables, 0 logs all temp files
+log_timezone = 'Etc/UTC'
+
+# - Process Title -
+
+#cluster_name = '' # added to process titles if nonempty
+ # (change requires restart)
+#update_process_title = on
+
+
+#------------------------------------------------------------------------------
+# STATISTICS
+#------------------------------------------------------------------------------
+
+# - Cumulative Query and Index Statistics -
+
+#track_activities = on
+#track_activity_query_size = 1024 # (change requires restart)
+#track_counts = on
+#track_cost_delay_timing = off
+#track_io_timing = off
+#track_wal_io_timing = off
+#track_functions = none # none, pl, all
+#stats_fetch_consistency = cache # cache, none, snapshot
+
+
+# - Monitoring -
+
+#compute_query_id = auto
+#log_statement_stats = off
+#log_parser_stats = off
+#log_planner_stats = off
+#log_executor_stats = off
+
+
+#------------------------------------------------------------------------------
+# VACUUMING
+#------------------------------------------------------------------------------
+
+# - Automatic Vacuuming -
+
+#autovacuum = on # Enable autovacuum subprocess? 'on'
+ # requires track_counts to also be on.
+autovacuum_worker_slots = 16 # autovacuum worker slots to allocate
+ # (change requires restart)
+#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
+#autovacuum_naptime = 1min # time between autovacuum runs
+#autovacuum_vacuum_threshold = 50 # min number of row updates before
+ # vacuum
+#autovacuum_vacuum_insert_threshold = 1000 # min number of row inserts
+ # before vacuum; -1 disables insert
+ # vacuums
+#autovacuum_analyze_threshold = 50 # min number of row updates before
+ # analyze
+#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum
+#autovacuum_vacuum_insert_scale_factor = 0.2 # fraction of unfrozen pages
+ # before insert vacuum
+#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze
+#autovacuum_vacuum_max_threshold = 100000000 # max number of row updates
+ # before vacuum; -1 disables max
+ # threshold
+#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum
+ # (change requires restart)
+#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age
+ # before forced vacuum
+ # (change requires restart)
+#autovacuum_vacuum_cost_delay = 2ms # default vacuum cost delay for
+ # autovacuum, in milliseconds;
+ # -1 means use vacuum_cost_delay
+#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for
+ # autovacuum, -1 means use
+ # vacuum_cost_limit
+
+# - Cost-Based Vacuum Delay -
+
+#vacuum_cost_delay = 0 # 0-100 milliseconds (0 disables)
+#vacuum_cost_page_hit = 1 # 0-10000 credits
+#vacuum_cost_page_miss = 2 # 0-10000 credits
+#vacuum_cost_page_dirty = 20 # 0-10000 credits
+#vacuum_cost_limit = 200 # 1-10000 credits
+
+# - Default Behavior -
+
+#vacuum_truncate = on # enable truncation after vacuum
+
+# - Freezing -
+
+#vacuum_freeze_table_age = 150000000
+#vacuum_freeze_min_age = 50000000
+#vacuum_failsafe_age = 1600000000
+#vacuum_multixact_freeze_table_age = 150000000
+#vacuum_multixact_freeze_min_age = 5000000
+#vacuum_multixact_failsafe_age = 1600000000
+#vacuum_max_eager_freeze_failure_rate = 0.03 # 0 disables eager scanning
+
+#------------------------------------------------------------------------------
+# CLIENT CONNECTION DEFAULTS
+#------------------------------------------------------------------------------
+
+# - Statement Behavior -
+
+#client_min_messages = notice # values in order of decreasing detail:
+ # debug5
+ # debug4
+ # debug3
+ # debug2
+ # debug1
+ # log
+ # notice
+ # warning
+ # error
+#search_path = '"$user", public' # schema names
+#row_security = on
+#default_table_access_method = 'heap'
+#default_tablespace = '' # a tablespace name, '' uses the default
+#default_toast_compression = 'pglz' # 'pglz' or 'lz4'
+#temp_tablespaces = '' # a list of tablespace names, '' uses
+ # only default tablespace
+#check_function_bodies = on
+#default_transaction_isolation = 'read committed'
+#default_transaction_read_only = off
+#default_transaction_deferrable = off
+#session_replication_role = 'origin'
+#statement_timeout = 0 # in milliseconds, 0 is disabled
+#transaction_timeout = 0 # in milliseconds, 0 is disabled
+#lock_timeout = 0 # in milliseconds, 0 is disabled
+#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled
+#idle_session_timeout = 0 # in milliseconds, 0 is disabled
+#bytea_output = 'hex' # hex, escape
+#xmlbinary = 'base64'
+#xmloption = 'content'
+#gin_pending_list_limit = 4MB
+#createrole_self_grant = '' # set and/or inherit
+#event_triggers = on
+
+# - Locale and Formatting -
+
+datestyle = 'iso, mdy'
+#intervalstyle = 'postgres'
+timezone = 'Etc/UTC'
+#timezone_abbreviations = 'Default' # Select the set of available time zone
+ # abbreviations. Currently, there are
+ # Default
+ # Australia (historical usage)
+ # India
+ # You can create your own file in
+ # share/timezonesets/.
+#extra_float_digits = 1 # min -15, max 3; any value >0 actually
+ # selects precise output mode
+#client_encoding = sql_ascii # actually, defaults to database
+ # encoding
+
+# These settings are initialized by initdb, but they can be changed.
+lc_messages = 'en_US.utf8' # locale for system error message
+ # strings
+lc_monetary = 'en_US.utf8' # locale for monetary formatting
+lc_numeric = 'en_US.utf8' # locale for number formatting
+lc_time = 'en_US.utf8' # locale for time formatting
+
+#icu_validation_level = warning # report ICU locale validation
+ # errors at the given level
+
+# default configuration for text search
+default_text_search_config = 'pg_catalog.english'
+
+# - Shared Library Preloading -
+
+#local_preload_libraries = ''
+#session_preload_libraries = ''
+#shared_preload_libraries = '' # (change requires restart)
+#jit_provider = 'llvmjit' # JIT library to use
+
+# - Other Defaults -
+
+#dynamic_library_path = '$libdir'
+#extension_control_path = '$system'
+#gin_fuzzy_search_limit = 0
+
+
+#------------------------------------------------------------------------------
+# LOCK MANAGEMENT
+#------------------------------------------------------------------------------
+
+#deadlock_timeout = 1s
+#max_locks_per_transaction = 64 # min 10
+ # (change requires restart)
+#max_pred_locks_per_transaction = 64 # min 10
+ # (change requires restart)
+#max_pred_locks_per_relation = -2 # negative values mean
+ # (max_pred_locks_per_transaction
+ # / -max_pred_locks_per_relation) - 1
+#max_pred_locks_per_page = 2 # min 0
+
+
+#------------------------------------------------------------------------------
+# VERSION AND PLATFORM COMPATIBILITY
+#------------------------------------------------------------------------------
+
+# - Previous PostgreSQL Versions -
+
+#array_nulls = on
+#backslash_quote = safe_encoding # on, off, or safe_encoding
+#escape_string_warning = on
+#lo_compat_privileges = off
+#quote_all_identifiers = off
+#standard_conforming_strings = on
+#synchronize_seqscans = on
+
+# - Other Platforms and Clients -
+
+#transform_null_equals = off
+#allow_alter_system = on
+
+
+#------------------------------------------------------------------------------
+# ERROR HANDLING
+#------------------------------------------------------------------------------
+
+#exit_on_error = off # terminate session on any error?
+#restart_after_crash = on # reinitialize after backend crash?
+#data_sync_retry = off # retry or panic on failure to fsync
+ # data?
+ # (change requires restart)
+#recovery_init_sync_method = fsync # fsync, syncfs (Linux 5.8+)
+
+
+#------------------------------------------------------------------------------
+# CONFIG FILE INCLUDES
+#------------------------------------------------------------------------------
+
+# These options allow settings to be loaded from files other than the
+# default postgresql.conf. Note that these are directives, not variable
+# assignments, so they can usefully be given more than once.
+
+#include_dir = '...' # include files ending in '.conf' from
+ # a directory, e.g., 'conf.d'
+#include_if_exists = '...' # include file only if it exists
+#include = '...' # include file
+
+
+#------------------------------------------------------------------------------
+# CUSTOMIZED OPTIONS
+#------------------------------------------------------------------------------
+
+# Add settings for extensions here
diff --git a/engine/deploy/swagger-ui.yaml b/engine/deploy/swagger-ui.yaml
deleted file mode 100644
index 9bed354d..00000000
--- a/engine/deploy/swagger-ui.yaml
+++ /dev/null
@@ -1,34 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
- name: dblab-swagger-ui
- labels:
- app: dblab-swagger-ui
-spec:
- type: ClusterIP
- ports:
- - port: 80
- targetPort: 80
- selector:
- app: dblab-swagger-ui
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: dblab-swagger-ui
- labels:
- app: dblab-swagger-ui
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: dblab-swagger-ui
- template:
- metadata:
- labels:
- app: dblab-swagger-ui
- spec:
- containers:
- - name: dblab-swagger-ui
- image: $TAG
- imagePullPolicy: Always
diff --git a/engine/go.mod b/engine/go.mod
index ec0ddf86..81d0e24c 100644
--- a/engine/go.mod
+++ b/engine/go.mod
@@ -1,24 +1,24 @@
module gitlab.com/postgres-ai/database-lab/v3
-go 1.23
+go 1.24.7
require (
github.com/AlekSi/pointer v1.2.0
github.com/ahmetalpbalkan/dlog v0.0.0-20170105205344-4fb5f8204f26
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
github.com/aws/aws-sdk-go v1.44.309
- github.com/docker/cli v25.0.6+incompatible
- github.com/docker/docker v25.0.6+incompatible
- github.com/docker/go-connections v0.4.0
+ github.com/docker/cli v27.1.1+incompatible
+ github.com/docker/docker v28.5.1+incompatible
+ github.com/docker/go-connections v0.6.0
github.com/docker/go-units v0.5.0
github.com/dustin/go-humanize v1.0.1
- github.com/golang-jwt/jwt/v4 v4.5.0
+ github.com/golang-jwt/jwt/v4 v4.5.2
github.com/google/go-github/v34 v34.0.0
- github.com/google/uuid v1.3.0
+ github.com/google/uuid v1.6.0
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.5.0
github.com/jackc/pgtype v1.14.0
- github.com/jackc/pgx/v4 v4.18.1
+ github.com/jackc/pgx/v4 v4.18.3
github.com/lib/pq v1.10.9
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
github.com/pkg/errors v0.9.1
@@ -27,73 +27,76 @@ require (
github.com/sergi/go-diff v1.3.1
github.com/sethvargo/go-password v0.2.0
github.com/shirou/gopsutil v3.21.11+incompatible
- github.com/stretchr/testify v1.9.0
- github.com/testcontainers/testcontainers-go v0.12.0
+ github.com/stretchr/testify v1.11.0
+ github.com/testcontainers/testcontainers-go v0.40.0
github.com/urfave/cli/v2 v2.25.7
github.com/wagslane/go-password-validator v0.3.0
- golang.org/x/crypto v0.14.0
- golang.org/x/mod v0.12.0
- golang.org/x/oauth2 v0.10.0
+ golang.org/x/crypto v0.45.0
+ golang.org/x/mod v0.29.0
+ golang.org/x/oauth2 v0.30.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
)
require (
+ dario.cat/mergo v1.0.2 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
- github.com/Microsoft/go-winio v0.6.1 // indirect
- github.com/cenkalti/backoff v2.2.1+incompatible // indirect
- github.com/containerd/containerd v1.7.2 // indirect
+ github.com/Microsoft/go-winio v0.6.2 // indirect
+ github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+ github.com/containerd/errdefs v1.0.0 // indirect
+ github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
+ github.com/containerd/platforms v0.2.1 // indirect
+ github.com/cpuguy83/dockercfg v0.3.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
- github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.6.0 // indirect
+ github.com/ebitengine/purego v0.8.4 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
- github.com/gogo/protobuf v1.3.2 // indirect
- github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
- github.com/jackc/pgconn v1.14.1 // indirect
+ github.com/jackc/pgconn v1.14.3 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
- github.com/jackc/pgproto3/v2 v2.3.2 // indirect
+ github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
- github.com/klauspost/compress v1.16.7 // indirect
- github.com/kr/pretty v0.3.1 // indirect
- github.com/magiconair/properties v1.8.5 // indirect
- github.com/moby/patternmatcher v0.5.0 // indirect
- github.com/moby/sys/sequential v0.5.0 // indirect
- github.com/moby/sys/user v0.3.0 // indirect
+ github.com/klauspost/compress v1.18.0 // indirect
+ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
+ github.com/magiconair/properties v1.8.10 // indirect
+ github.com/moby/docker-image-spec v1.3.1 // indirect
+ github.com/moby/go-archive v0.1.0 // indirect
+ github.com/moby/patternmatcher v0.6.0 // indirect
+ github.com/moby/sys/sequential v0.6.0 // indirect
+ github.com/moby/sys/user v0.4.0 // indirect
+ github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
- github.com/opencontainers/image-spec v1.1.0-rc4 // indirect
+ github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/rogpeppe/go-internal v1.10.0 // indirect
+ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/shirou/gopsutil/v4 v4.25.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/objx v0.5.2 // indirect
- github.com/tklauser/go-sysconf v0.3.11 // indirect
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
- github.com/yusufpapurcu/wmi v1.2.3 // indirect
+ github.com/yusufpapurcu/wmi v1.2.4 // indirect
+ go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect
- go.opentelemetry.io/otel v1.30.0 // indirect
- go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0 // indirect
- go.opentelemetry.io/otel/metric v1.30.0 // indirect
- go.opentelemetry.io/otel/sdk v1.18.0 // indirect
- go.opentelemetry.io/otel/trace v1.30.0 // indirect
- golang.org/x/net v0.17.0 // indirect
- golang.org/x/sys v0.13.0 // indirect
- golang.org/x/text v0.13.0 // indirect
- golang.org/x/tools v0.11.0 // indirect
- google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
- google.golang.org/protobuf v1.31.0 // indirect
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+ go.opentelemetry.io/otel v1.35.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
+ go.opentelemetry.io/otel/metric v1.35.0 // indirect
+ go.opentelemetry.io/otel/sdk v1.21.0 // indirect
+ go.opentelemetry.io/otel/trace v1.35.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.0.0 // indirect
+ golang.org/x/sys v0.38.0 // indirect
+ golang.org/x/text v0.31.0 // indirect
+ golang.org/x/time v0.12.0 // indirect
+ google.golang.org/protobuf v1.35.2 // indirect
)
diff --git a/engine/go.sum b/engine/go.sum
index 9be68150..16595c52 100644
--- a/engine/go.sum
+++ b/engine/go.sum
@@ -1,282 +1,63 @@
-bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
-cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
-cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
-cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
-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/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/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=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
-cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
-cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
-dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0=
+dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
+dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
-github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
-github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
-github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
-github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
-github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
-github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
-github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
-github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
-github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
-github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
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/Flaque/filet v0.0.0-20201012163910-45f684403088 h1:PnnQln5IGbhLeJOi6hVs+lCeF+B1dRfFKPGXUAez0Ww=
-github.com/Flaque/filet v0.0.0-20201012163910-45f684403088/go.mod h1:TK+jB3mBs+8ZMWhU5BqZKnZWJ1MrLo8etNVg51ueTBo=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
-github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
-github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
-github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
-github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
-github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
-github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
-github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
-github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
-github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
-github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
-github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
-github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
-github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
-github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
-github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
-github.com/Microsoft/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek=
-github.com/Microsoft/hcsshim v0.10.0-rc.8/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM=
-github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
-github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
-github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
-github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/ahmetalpbalkan/dlog v0.0.0-20170105205344-4fb5f8204f26 h1:pzStYMLAXM7CNQjS/Wn+zK9MUxDhSUNfVvnHsyQyjs0=
github.com/ahmetalpbalkan/dlog v0.0.0-20170105205344-4fb5f8204f26/go.mod h1:ilK+u7u1HoqaDk0mjhh27QJB7PyWMreGffEvOCoEKiY=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
-github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.44.309 h1:IPJOFBzXekakxmEpDwd4RTKmmBR6LIAiXgNsM51bWbU=
github.com/aws/aws-sdk-go v1.44.309/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
-github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
-github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
-github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
-github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
-github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
-github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
-github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
-github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
-github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
-github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
-github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
-github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
-github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
-github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
-github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
-github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E=
-github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
-github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI=
-github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
-github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
-github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
-github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
-github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
-github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
-github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
-github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
-github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
-github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
-github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
-github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
-github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
-github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
-github.com/containerd/containerd v1.7.2 h1:UF2gdONnxO8I6byZXDi5sXWiWvlW3D/sci7dTQimEJo=
-github.com/containerd/containerd v1.7.2/go.mod h1:afcz74+K10M/+cjGHIVQrCt3RAQhUSCAjJ9iMYhhkuI=
-github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo=
-github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
-github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
-github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
-github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
-github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
-github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
-github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
-github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU=
-github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
-github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
-github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g=
-github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
-github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0=
-github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA=
-github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow=
+github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
+github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
+github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
+github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
-github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
-github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
-github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
-github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
-github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
-github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
-github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
-github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
-github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
-github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
-github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
-github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
-github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
-github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
-github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
-github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
-github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
-github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4=
-github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
-github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
+github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
-github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
-github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
+github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
-github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
-github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
-github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
-github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
-github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
-github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
-github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
-github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
-github.com/docker/cli v25.0.6+incompatible h1:F1mCw1kUGixOkM8WQbcG5kniPvP8XCFxreFxl4b/UnY=
-github.com/docker/cli v25.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
-github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg=
-github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
-github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
-github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
-github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
-github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
-github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE=
+github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM=
+github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
+github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
-github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
-github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
-github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
+github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
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/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
-github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
-github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
-github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
-github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
-github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -284,129 +65,30 @@ 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-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-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=
-github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
-github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
-github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
-github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
-github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
-github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
-github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
-github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
-github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
-github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
-github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
-github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
-github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-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/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-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
+github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-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/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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
-github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v34 v34.0.0 h1:/siYFImY8KwGc5QD1gaPf+f8QX6tLwxNIco2RkYxoFA=
github.com/google/go-github/v34 v34.0.0/go.mod h1:w/2qlrXUfty+lbyO6tatnzIw97v1CM+/jZcwXMDiPQQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-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/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
-github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+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/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
-github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
-github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
-github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@@ -417,9 +99,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
-github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
-github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4=
-github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E=
+github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
+github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
@@ -435,8 +116,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
-github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0=
-github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
+github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
@@ -450,44 +131,24 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
-github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0=
-github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE=
+github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA=
+github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
-github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
-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.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
-github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
+github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
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.2/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/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -498,266 +159,121 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
-github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
-github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
-github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
+github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
+github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
-github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
-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/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
-github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
-github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
-github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
-github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM=
-github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
-github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
-github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
-github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
-github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
-github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
-github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
-github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
-github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
-github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
+github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
+github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
+github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
+github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
+github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
+github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
+github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
+github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
+github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
+github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
+github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
-github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-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/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
-github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
-github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
-github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
-github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
-github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
-github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
-github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
-github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
-github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
-github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
-github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
-github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
+github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
+github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
-github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/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=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
-github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
-github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
-github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-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/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
-github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
-github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
-github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
-github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
-github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI=
github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
+github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
-github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
-github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
-github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
-github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
-github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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/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 v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
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=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
-github.com/testcontainers/testcontainers-go v0.12.0 h1:SK0NryGHIx7aifF6YqReORL18aGAA4bsDPtikDVCEyg=
-github.com/testcontainers/testcontainers-go v0.12.0/go.mod h1:SIndOQXZng0IW8iWU1Js0ynrfZ8xcxrTtDfF6rD2pxs=
-github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
-github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
-github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
+github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
+github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
+github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
+github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
-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/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
-github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
-github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
-github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
-github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/wagslane/go-password-validator v0.3.0 h1:vfxOPzGHkz5S146HDpavl0cw1DSVP061Ry2PX0/ON6I=
github.com/wagslane/go-password-validator v0.3.0/go.mod h1:TI1XJ6T5fRdRnHqHt14pvy1tNVnrwe7m3/f1f2fDphQ=
-github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
-github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
-github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
-github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
-github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
-github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
+github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
+github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
-go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
-go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
+go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI=
-go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
-go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0 h1:IAtl+7gua134xcV3NieDhJHjjOVeJhXAnYf/0hswjUY=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.18.0/go.mod h1:w+pXobnBzh95MNIkeIuAKcHe/Uu/CX2PKIvBP6ipKRA=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0 h1:6pu8ttx76BxHf+xz/H77AUZkPF3cwWzXqAUsXhVKI18=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.18.0/go.mod h1:IOmXxPrxoxFMXdNy7lfDmE8MzE61YPcurbUm0SMjerI=
-go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
-go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
-go.opentelemetry.io/otel/sdk v1.18.0 h1:e3bAB0wB3MljH38sHzpV/qWrOTCFrdZF2ct9F8rBkcY=
-go.opentelemetry.io/otel/sdk v1.18.0/go.mod h1:1RCygWV7plY2KmdskZEDDBs4tJeHG92MdHZIluiYs/M=
-go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
-go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
+go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
+go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
+go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
+go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
+go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
+go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
+go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
+go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -771,407 +287,117 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
-golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
-golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
-golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
-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=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
-golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
-golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
-golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
-golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
-golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
+golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
-golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
-golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
-golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
-golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-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=
-golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
+golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20211108170745-6635138e15ea/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
-golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
-golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
+golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
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=
-golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
-golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
-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=
-golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
+golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
-golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
-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=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211109184856-51b60fd695b3/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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
-golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
+golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
-golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
+golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
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=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
-golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
+golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
+golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
+golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
-golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8=
-golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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=
-google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
-google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
-google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
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.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
-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=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
-google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw=
-google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
-google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-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=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o=
-google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
-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=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
+google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
+google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
+google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
+google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
-gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
-gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
-gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
-gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
+gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
-k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
-k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
-k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
-k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
-k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
-k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
-k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
-k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
-k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
-k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
-k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
-sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
-sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
-sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/engine/internal/cloning/base.go b/engine/internal/cloning/base.go
index e5edb759..952a9436 100644
--- a/engine/internal/cloning/base.go
+++ b/engine/internal/cloning/base.go
@@ -387,8 +387,13 @@ func (c *Base) destroyClone(cloneID string, w *CloneWrapper) {
if w.Clone.Snapshot != nil {
c.decrementCloneNumber(w.Clone.Snapshot.ID)
}
+
c.observingCh <- cloneID
+ if err := c.provision.CleanupCloneDataset(w.Clone, w.Clone.Snapshot.Pool); err != nil {
+ log.Errf("failed to cleanup clone dataset: %v", err)
+ }
+
c.SaveClonesState()
c.webhookCh <- webhooks.CloneEvent{
@@ -430,8 +435,10 @@ func (c *Base) refreshCloneMetadata(w *CloneWrapper) {
return
}
+ c.cloneMutex.Lock()
w.Clone.Metadata.CloneDiffSize = sessionState.CloneDiffSize
w.Clone.Metadata.LogicalSize = sessionState.LogicalReferenced
+ c.cloneMutex.Unlock()
}
// UpdateClone updates clone.
@@ -522,11 +529,6 @@ func (c *Base) ResetClone(cloneID string, resetOptions types.ResetCloneRequest)
log.Warn("clone has dependent snapshots", cloneID)
c.cloneMutex.Lock()
w.Clone.Revision++
- w.Clone.HasDependent = true
- c.cloneMutex.Unlock()
- } else {
- c.cloneMutex.Lock()
- w.Clone.HasDependent = false
c.cloneMutex.Unlock()
}
@@ -625,6 +627,8 @@ func (c *Base) GetClones() []*models.Clone {
clones := make([]*models.Clone, 0, c.lenClones())
c.cloneMutex.RLock()
+ requestsByPool := make(map[string][]resources.SessionStateRequest)
+
for _, cloneWrapper := range c.clones {
if cloneWrapper.Clone.Snapshot != nil {
snapshot, err := c.getSnapshotByID(cloneWrapper.Clone.Snapshot.ID)
@@ -637,12 +641,30 @@ func (c *Base) GetClones() []*models.Clone {
}
}
- c.refreshCloneMetadata(cloneWrapper)
+ if cloneWrapper.Session != nil && cloneWrapper.Clone != nil {
+ pool := cloneWrapper.Session.Pool
+ requestsByPool[pool] = append(requestsByPool[pool], resources.SessionStateRequest{
+ CloneID: cloneWrapper.Clone.ID,
+ Branch: cloneWrapper.Clone.Branch,
+ })
+ }
clones = append(clones, cloneWrapper.Clone)
}
c.cloneMutex.RUnlock()
+ sessionStates, err := c.provision.GetBatchSessionState(requestsByPool)
+ if err != nil {
+ log.Err("failed to get batch session states: ", err)
+ }
+
+ for _, clone := range clones {
+ if state, ok := sessionStates[clone.ID]; ok {
+ clone.Metadata.CloneDiffSize = state.CloneDiffSize
+ clone.Metadata.LogicalSize = state.LogicalReferenced
+ }
+ }
+
sort.Slice(clones, func(i, j int) bool {
return clones[i].CreatedAt.After(clones[j].CreatedAt.Time)
})
diff --git a/engine/internal/diagnostic/logs_integration_test.go b/engine/internal/diagnostic/logs_integration_test.go
index 3766a07d..d4e783e5 100644
--- a/engine/internal/diagnostic/logs_integration_test.go
+++ b/engine/internal/diagnostic/logs_integration_test.go
@@ -36,7 +36,7 @@ func TestContainerOutputCollection(t *testing.T) {
dir := t.TempDir()
- docker, err := client.NewClientWithOpts(client.FromEnv)
+ docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
require.NoError(t, err)
engProps := global.EngineProps{
diff --git a/engine/internal/embeddedui/embedded_ui_integration_test.go b/engine/internal/embeddedui/embedded_ui_integration_test.go
index f11a24d1..c9ab8d95 100644
--- a/engine/internal/embeddedui/embedded_ui_integration_test.go
+++ b/engine/internal/embeddedui/embedded_ui_integration_test.go
@@ -11,7 +11,7 @@ import (
"context"
"testing"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/stretchr/testify/assert"
@@ -25,7 +25,7 @@ import (
func TestStartExistingContainer(t *testing.T) {
t.Parallel()
- docker, err := client.NewClientWithOpts(client.FromEnv)
+ docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
require.NoError(t, err)
engProps := global.EngineProps{
@@ -66,7 +66,7 @@ func TestStartExistingContainer(t *testing.T) {
list, err := docker.ContainerList(
ctx,
- types.ContainerListOptions{
+ container.ListOptions{
All: true,
Filters: filterArgs,
},
diff --git a/engine/internal/provision/databases/postgres/postgres.go b/engine/internal/provision/databases/postgres/postgres.go
index 5ca5bb94..41601620 100644
--- a/engine/internal/provision/databases/postgres/postgres.go
+++ b/engine/internal/provision/databases/postgres/postgres.go
@@ -129,7 +129,7 @@ func Start(r runners.Runner, c *resources.AppConfig) error {
}
func collectDiagnostics(c *resources.AppConfig) {
- dockerClient, err := client.NewClientWithOpts(client.FromEnv)
+ dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
log.Fatal("Failed to create a Docker client:", err)
}
diff --git a/engine/internal/provision/docker/docker.go b/engine/internal/provision/docker/docker.go
index e537e8b7..108b5cea 100644
--- a/engine/internal/provision/docker/docker.go
+++ b/engine/internal/provision/docker/docker.go
@@ -15,8 +15,9 @@ import (
"strconv"
"strings"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
+ imagetypes "github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"github.com/shirou/gopsutil/host"
@@ -130,7 +131,7 @@ func createDefaultVolumes(c *resources.AppConfig) (string, []string) {
func getMountVolumes(r runners.Runner, c *resources.AppConfig, containerID string) ([]string, error) {
inspectCmd := "docker inspect -f '{{ json .Mounts }}' " + containerID
- var mountPoints []types.MountPoint
+ var mountPoints []container.MountPoint
out, err := r.Run(inspectCmd, true)
if err != nil {
@@ -144,7 +145,7 @@ func getMountVolumes(r runners.Runner, c *resources.AppConfig, containerID strin
return buildVolumesFromMountPoints(c, mountPoints), nil
}
-func buildVolumesFromMountPoints(c *resources.AppConfig, mountPoints []types.MountPoint) []string {
+func buildVolumesFromMountPoints(c *resources.AppConfig, mountPoints []container.MountPoint) []string {
unixSocketCloneDir := c.Pool.SocketCloneDir(c.CloneName)
mounts := tools.GetMountsFromMountPoints(c.CloneDir(), mountPoints)
volumes := make([]string, 0, len(mounts))
@@ -276,7 +277,7 @@ func ImageExists(ctx context.Context, docker *client.Client, dockerImage string)
filterArgs := filters.NewArgs()
filterArgs.Add(referenceKey, dockerImage)
- list, err := docker.ImageList(ctx, types.ImageListOptions{
+ list, err := docker.ImageList(ctx, imagetypes.ListOptions{
All: false,
Filters: filterArgs,
})
@@ -290,7 +291,7 @@ func ImageExists(ctx context.Context, docker *client.Client, dockerImage string)
// PullImage pulls Docker image from DockerHub registry.
func PullImage(ctx context.Context, docker *client.Client, dockerImage string) error {
- pullResponse, err := docker.ImagePull(ctx, dockerImage, types.ImagePullOptions{})
+ pullResponse, err := docker.ImagePull(ctx, dockerImage, imagetypes.PullOptions{})
if err != nil {
return fmt.Errorf("failed to pull image: %w", err)
diff --git a/engine/internal/provision/docker/docker_test.go b/engine/internal/provision/docker/docker_test.go
index edf43e39..10a0343d 100644
--- a/engine/internal/provision/docker/docker_test.go
+++ b/engine/internal/provision/docker/docker_test.go
@@ -7,7 +7,7 @@ package docker
import (
"testing"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/stretchr/testify/assert"
"gitlab.com/postgres-ai/database-lab/v3/internal/provision/resources"
@@ -34,7 +34,7 @@ func TestSystemVolumes(t *testing.T) {
func TestVolumesBuilding(t *testing.T) {
testCases := []struct {
appConfig *resources.AppConfig
- mountPoints []types.MountPoint
+ mountPoints []container.MountPoint
expectedVolumes []string
}{
{
@@ -50,15 +50,15 @@ func TestVolumesBuilding(t *testing.T) {
SocketSubDir: "sockets",
},
},
- mountPoints: []types.MountPoint{
- {Source: "/lib/modules", Destination: "/lib/modules"},
- {Source: "/proc", Destination: "/host_proc"},
- {Source: "/tmp", Destination: "/tmp"},
- {Source: "/var/run/docker.sock", Destination: "/var/run/docker.sock"},
- {Source: "/sys/kernel/debug", Destination: "/sys/kernel/debug"},
- {Source: "/var/lib/dblab", Destination: "/var/lib/dblab", Propagation: "rshared"},
- {Source: "/home/user/.dblab/server.yml", Destination: "/home/dblab/configs/config.yml"},
- {Source: "/home/user/.dblab/configs", Destination: "/home/dblab/configs"},
+ mountPoints: []container.MountPoint{
+ {Type: "bind", Source: "/lib/modules", Destination: "/lib/modules"},
+ {Type: "bind", Source: "/proc", Destination: "/host_proc"},
+ {Type: "bind", Source: "/tmp", Destination: "/tmp"},
+ {Type: "bind", Source: "/var/run/docker.sock", Destination: "/var/run/docker.sock"},
+ {Type: "bind", Source: "/sys/kernel/debug", Destination: "/sys/kernel/debug"},
+ {Type: "bind", Source: "/var/lib/dblab", Destination: "/var/lib/dblab", Propagation: "rshared"},
+ {Type: "bind", Source: "/home/user/.dblab/server.yml", Destination: "/home/dblab/configs/config.yml"},
+ {Type: "bind", Source: "/home/user/.dblab/configs", Destination: "/home/dblab/configs"},
},
expectedVolumes: []string{
"--volume /var/lib/dblab/dblab_pool/sockets/dblab_clone_6000:/var/lib/dblab/dblab_pool/sockets/dblab_clone_6000:rshared",
diff --git a/engine/internal/provision/mode_local.go b/engine/internal/provision/mode_local.go
index 7bc89cab..e457e859 100644
--- a/engine/internal/provision/mode_local.go
+++ b/engine/internal/provision/mode_local.go
@@ -274,10 +274,8 @@ func (p *Provisioner) ResetSession(session *resources.Session, clone *models.Clo
return nil, errors.Wrap(err, "failed to stop container")
}
- if clone.Revision == branching.DefaultRevision || !clone.HasDependent {
- if err = fsm.DestroyClone(clone.Branch, name, clone.Revision); err != nil {
- return nil, errors.Wrap(err, "failed to destroy clone")
- }
+ if err = fsm.DestroyClone(clone.Branch, name, clone.Revision); err != nil {
+ return nil, errors.Wrap(err, "failed to destroy clone")
}
if err = newFSManager.CreateClone(clone.Branch, name, snapshot.ID, clone.Revision); err != nil {
@@ -300,9 +298,14 @@ func (p *Provisioner) ResetSession(session *resources.Session, clone *models.Clo
}
snapshotModel := &models.Snapshot{
- ID: snapshot.ID,
- CreatedAt: models.NewLocalTime(snapshot.CreatedAt),
- DataStateAt: models.NewLocalTime(snapshot.DataStateAt),
+ ID: snapshot.ID,
+ CreatedAt: models.NewLocalTime(snapshot.CreatedAt),
+ DataStateAt: models.NewLocalTime(snapshot.DataStateAt),
+ PhysicalSize: snapshot.Used,
+ LogicalSize: snapshot.LogicalReferenced,
+ Pool: snapshot.Pool,
+ Branch: snapshot.Branch,
+ Message: snapshot.Message,
}
return snapshotModel, nil
@@ -335,6 +338,31 @@ func (p *Provisioner) GetSessionState(s *resources.Session, branch, cloneID stri
return fsm.GetSessionState(branch, cloneID)
}
+// GetBatchSessionState retrieves session states for multiple clones efficiently.
+func (p *Provisioner) GetBatchSessionState(batch map[string][]resources.SessionStateRequest) (map[string]resources.SessionState, error) {
+ batchResults := make(map[string]resources.SessionState)
+
+ for poolName, reqs := range batch {
+ fsm, err := p.pm.GetFSManager(poolName)
+ if err != nil {
+ log.Err(fmt.Sprintf("failed to find filesystem manager for pool %s: %v", poolName, err))
+ continue
+ }
+
+ results, err := fsm.GetBatchSessionState(reqs)
+ if err != nil {
+ log.Err(fmt.Sprintf("failed to get batch session state for pool %s: %v", poolName, err))
+ continue
+ }
+
+ for cloneID, state := range results {
+ batchResults[cloneID] = state
+ }
+ }
+
+ return batchResults, nil
+}
+
// GetPoolEntryList provides an ordered list of available pools.
func (p *Provisioner) GetPoolEntryList() []models.PoolEntry {
fsmList := p.pm.GetFSManagerOrderedList()
@@ -571,6 +599,46 @@ func (p *Provisioner) StopAllSessions(exceptClones map[string]struct{}) error {
return nil
}
+func reviewDown(repo *models.Repo, cloneDataset string) string {
+ for snapshotID := range repo.Snapshots {
+ if strings.HasPrefix(snapshotID, cloneDataset) {
+ return snapshotID
+ }
+ }
+
+ return ""
+}
+
+// CleanupCloneDataset removes a clone dataset.
+func (p *Provisioner) CleanupCloneDataset(clone *models.Clone, pool string) error {
+ if clone.Snapshot == nil {
+ return fmt.Errorf("clone has no snapshot, so the pool cannot be determined. Skip cleanup")
+ }
+
+ fsm, err := p.pm.GetFSManager(clone.Snapshot.Pool)
+ if err != nil {
+ return fmt.Errorf("cannot work with pool %s: %w", pool, err)
+ }
+
+ repo, err := fsm.GetRepo()
+ if err != nil {
+ return fmt.Errorf("failed to get snapshots: %w", err)
+ }
+
+ snapshotDep := reviewDown(repo, branching.CloneName(pool, clone.Branch, clone.ID, clone.Revision))
+ if snapshotDep != "" {
+ log.Dbg(fmt.Sprintf("Dataset has commit: %s. Skip destroying", snapshotDep))
+
+ return nil
+ }
+
+ if err = fsm.DestroyClone(clone.Branch, clone.ID, clone.Revision); err != nil {
+ return fmt.Errorf("failed to destroy clone: %w", err)
+ }
+
+ return nil
+}
+
func (p *Provisioner) stopPoolSessions(fsm pool.FSManager, exceptClones map[string]struct{}) error {
fsPool := fsm.Pool()
diff --git a/engine/internal/provision/mode_local_test.go b/engine/internal/provision/mode_local_test.go
index 72c70e13..c610d18e 100644
--- a/engine/internal/provision/mode_local_test.go
+++ b/engine/internal/provision/mode_local_test.go
@@ -87,7 +87,7 @@ func (m mockFSManager) DestroySnapshot(_ string, _ thinclones.DestroyOptions) (e
return nil
}
-func (m mockFSManager) CleanupSnapshots(_ int) ([]string, error) {
+func (m mockFSManager) CleanupSnapshots(_ int, _ models.RetrievalMode) ([]string, error) {
return nil, nil
}
@@ -102,6 +102,10 @@ func (m mockFSManager) GetSessionState(_, _ string) (*resources.SessionState, er
return nil, nil
}
+func (m mockFSManager) GetBatchSessionState(_ []resources.SessionStateRequest) (map[string]resources.SessionState, error) {
+ return make(map[string]resources.SessionState), nil
+}
+
func (m mockFSManager) GetFilesystemState() (models.FileSystem, error) {
return models.FileSystem{Mode: "zfs"}, nil
}
@@ -214,6 +218,14 @@ func (m mockFSManager) KeepRelation(_ string) error {
return nil
}
+func (m mockFSManager) GetDatasetOrigins(_ string) []string {
+ return nil
+}
+
+func (m mockFSManager) GetActiveDatasets(_ string) ([]string, error) {
+ return nil, nil
+}
+
func TestBuildPoolEntry(t *testing.T) {
testCases := []struct {
pool *resources.Pool
diff --git a/engine/internal/provision/pool/manager.go b/engine/internal/provision/pool/manager.go
index 1c63a6a2..d7e018f3 100644
--- a/engine/internal/provision/pool/manager.go
+++ b/engine/internal/provision/pool/manager.go
@@ -39,6 +39,7 @@ type Cloner interface {
// StateReporter describes methods of state reporting.
type StateReporter interface {
GetSessionState(branch, name string) (*resources.SessionState, error)
+ GetBatchSessionState(requests []resources.SessionStateRequest) (map[string]resources.SessionState, error)
GetFilesystemState() (models.FileSystem, error)
}
@@ -46,7 +47,7 @@ type StateReporter interface {
type Snapshotter interface {
CreateSnapshot(poolSuffix, dataStateAt string) (snapshotName string, err error)
DestroySnapshot(snapshotName string, options thinclones.DestroyOptions) (err error)
- CleanupSnapshots(retentionLimit int) ([]string, error)
+ CleanupSnapshots(retentionLimit int, mode models.RetrievalMode) ([]string, error)
SnapshotList() []resources.Snapshot
RefreshSnapshotList()
}
@@ -57,7 +58,7 @@ type Branching interface {
VerifyBranchMetadata() error
CreateDataset(datasetName string) error
CreateBranch(branchName, snapshotID string) error
- DestroyDataset(branchName string) (err error)
+ DestroyDataset(dataset string) (err error)
ListBranches() (map[string]string, error)
ListAllBranches(filterPools []string) ([]models.BranchEntity, error)
GetRepo() (*models.Repo, error)
@@ -78,6 +79,8 @@ type Branching interface {
Reset(snapshotID string, options thinclones.ResetOptions) error
HasDependentEntity(snapshotName string) ([]string, error)
KeepRelation(snapshotName string) error
+ GetDatasetOrigins(snapshotName string) []string
+ GetActiveDatasets(dataset string) ([]string, error)
}
// Pooler describes methods for Pool providing.
diff --git a/engine/internal/provision/resources/resources.go b/engine/internal/provision/resources/resources.go
index 1a5538ee..5892bb76 100644
--- a/engine/internal/provision/resources/resources.go
+++ b/engine/internal/provision/resources/resources.go
@@ -48,3 +48,9 @@ type SessionState struct {
CloneDiffSize uint64
LogicalReferenced uint64
}
+
+// SessionStateRequest defines a request for batch session state retrieval.
+type SessionStateRequest struct {
+ CloneID string
+ Branch string
+}
diff --git a/engine/internal/provision/thinclones/lvm/lvmanager.go b/engine/internal/provision/thinclones/lvm/lvmanager.go
index 8afc4c74..911cb61e 100644
--- a/engine/internal/provision/thinclones/lvm/lvmanager.go
+++ b/engine/internal/provision/thinclones/lvm/lvmanager.go
@@ -106,7 +106,7 @@ func (m *LVManager) DestroySnapshot(_ string, _ thinclones.DestroyOptions) error
}
// CleanupSnapshots is not supported in LVM mode.
-func (m *LVManager) CleanupSnapshots(_ int) ([]string, error) {
+func (m *LVManager) CleanupSnapshots(_ int, _ models.RetrievalMode) ([]string, error) {
log.Msg("Cleanup snapshots is not supported in LVM mode. Skip the operation.")
return nil, nil
@@ -136,6 +136,11 @@ func (m *LVManager) GetSessionState(_, _ string) (*resources.SessionState, error
return &resources.SessionState{}, nil
}
+// GetBatchSessionState is not implemented.
+func (m *LVManager) GetBatchSessionState(_ []resources.SessionStateRequest) (map[string]resources.SessionState, error) {
+ return make(map[string]resources.SessionState), nil
+}
+
// GetFilesystemState is not implemented.
func (m *LVManager) GetFilesystemState() (models.FileSystem, error) {
// TODO(anatoly): Implement.
@@ -316,3 +321,17 @@ func (m *LVManager) KeepRelation(_ string) error {
return nil
}
+
+// GetDatasetOrigins provides a list of dataset origins.
+func (m *LVManager) GetDatasetOrigins(_ string) []string {
+ log.Msg("GetDatasetOrigins is not supported for LVM. Skip the operation")
+
+ return nil
+}
+
+// GetActiveDatasets provides a list of active datasets.
+func (m *LVManager) GetActiveDatasets(_ string) ([]string, error) {
+ log.Msg("GetDatasetOrigins is not supported for LVM. Skip the operation")
+
+ return nil, nil
+}
diff --git a/engine/internal/provision/thinclones/zfs/branching.go b/engine/internal/provision/thinclones/zfs/branching.go
index f446edc9..a452897f 100644
--- a/engine/internal/provision/thinclones/zfs/branching.go
+++ b/engine/internal/provision/thinclones/zfs/branching.go
@@ -77,7 +77,7 @@ func (m *Manager) InitBranching() error {
continue
}
- if err := m.SetRelation(leader.ID, follower.ID); err != nil {
+ if err := m.SetRelation(follower.ID, leader.ID); err != nil {
return fmt.Errorf("failed to set snapshot relations: %w", err)
}
@@ -126,32 +126,33 @@ func (m *Manager) VerifyBranchMetadata() error {
return nil
}
- latest := snapshots[0]
+ branchHeads := make(map[string]string)
- brName, err := m.getProperty(branchProp, latest.ID)
- if err != nil {
- log.Dbg("cannot find branch for snapshot", latest.ID, err.Error())
- }
+ for i := numberSnapshots; i > 0; i-- {
+ sn := snapshots[i-1]
+ log.Dbg(sn)
- for i := numberSnapshots; i > 1; i-- {
- if err := m.SetRelation(snapshots[i-1].ID, snapshots[i-2].ID); err != nil {
- return fmt.Errorf("failed to set snapshot relations: %w", err)
+ if err := m.DeleteBranchProp(sn.Branch, sn.ID); err != nil {
+ return fmt.Errorf("failed to clean branch property: %w", err)
}
- if brName == "" {
- brName, err = m.getProperty(branchProp, snapshots[i-1].ID)
- if err != nil {
- log.Dbg("cannot find branch for snapshot", snapshots[i-1].ID, err.Error())
- }
+ head, ok := branchHeads[sn.Branch]
+ if !ok {
+ branchHeads[sn.Branch] = sn.ID
+ continue
+ }
+
+ if err := m.SetRelation(head, sn.ID); err != nil {
+ return fmt.Errorf("failed to set snapshot relations: %w", err)
}
- }
- if brName == "" {
- brName = branching.DefaultBranch
+ branchHeads[sn.Branch] = sn.ID
}
- if err := m.AddBranchProp(brName, latest.ID); err != nil {
- return fmt.Errorf("failed to add branch property: %w", err)
+ for brName, latestID := range branchHeads {
+ if err := m.AddBranchProp(brName, latestID); err != nil {
+ return fmt.Errorf("failed to add branch property: %w", err)
+ }
}
log.Msg("data branching has been verified")
@@ -246,7 +247,7 @@ func (m *Manager) ListAllBranches(poolList []string) ([]models.BranchEntity, err
cmd := fmt.Sprintf(
// Get all ZFS snapshots (-t) with options (-o) without output headers (-H).
// Excluding snapshots without "dle:branch" property ("grep -v").
- `zfs list -H -t snapshot -o %s,name %s | grep -v "^-" | cat`, branchProp, poolFilter,
+ `zfs list -H -t snapshot -S %s -o %s,name %s | grep -v "^-" | cat`, dataStateAtLabel, branchProp, poolFilter,
)
out, err := m.runner.Run(cmd)
@@ -266,13 +267,15 @@ func (m *Manager) ListAllBranches(poolList []string) ([]models.BranchEntity, err
continue
}
+ dataset := branching.ParseBaseDatasetFromSnapshot(fields[1])
+
if !strings.Contains(fields[0], branchSep) {
- branches = append(branches, models.BranchEntity{Name: fields[0], SnapshotID: fields[1]})
+ branches = append(branches, models.BranchEntity{Name: fields[0], Dataset: dataset, SnapshotID: fields[1]})
continue
}
for _, branchName := range strings.Split(fields[0], branchSep) {
- branches = append(branches, models.BranchEntity{Name: branchName, SnapshotID: fields[1]})
+ branches = append(branches, models.BranchEntity{Name: branchName, Dataset: dataset, SnapshotID: fields[1]})
}
}
@@ -538,22 +541,6 @@ func (m *Manager) HasDependentEntity(snapshotName string) ([]string, error) {
dependentClones := strings.Split(clones, ",")
- // Check clones of dependent snapshots.
- if child != "" {
- // check all child snapshots
- childList := strings.Split(child, ",")
-
- for _, childSnapshot := range childList {
- // TODO: limit the max level of recursion.
- childClones, err := m.HasDependentEntity(childSnapshot)
- if err != nil {
- return nil, fmt.Errorf("failed to check dependent clones of dependent snapshots: %w", err)
- }
-
- dependentClones = append(dependentClones, childClones...)
- }
- }
-
return dependentClones, nil
}
diff --git a/engine/internal/provision/thinclones/zfs/zfs.go b/engine/internal/provision/thinclones/zfs/zfs.go
index c753b1cf..4358d0a7 100644
--- a/engine/internal/provision/thinclones/zfs/zfs.go
+++ b/engine/internal/provision/thinclones/zfs/zfs.go
@@ -9,6 +9,7 @@ import (
"encoding/base64"
"fmt"
"path"
+ "sort"
"strconv"
"strings"
"sync"
@@ -235,13 +236,27 @@ func (m *Manager) DestroyClone(branchName, cloneName string, revision int) error
return nil
}
+ cloneDataset := m.config.Pool.CloneDataset(branchName, cloneName)
+ cloneOrigins := m.GetDatasetOrigins(cloneDataset)
+
+ if m.hasDependentSnapshots(cloneOrigins, cloneMountName) {
+ log.Msg(fmt.Sprintf("clone %q has dependent snapshot; skipping", cloneMountName))
+ return nil
+ }
+
+ // TODO: check pre-clone for physical mode.
+ if len(cloneOrigins) <= branching.MinDatasetNumber {
+ // There are no other revisions, so we can destroy the entire clone dataset.
+ cloneMountName = cloneDataset
+ }
+
// Delete the clone and all snapshots and clones depending on it.
// TODO(anatoly): right now, we are using this function only for
// deleting thin clones created by users. If we are going to use
// this function to delete clones used during the preparation
// of baseline snapshots, we need to omit `-R`, to avoid
// unexpected deletion of users' clones.
- cmd := fmt.Sprintf("zfs destroy %s", cloneMountName)
+ cmd := fmt.Sprintf("zfs destroy -r %s", cloneMountName)
if _, err = m.runner.Run(cmd); err != nil {
if strings.Contains(cloneName, "clone_pre") {
@@ -254,6 +269,59 @@ func (m *Manager) DestroyClone(branchName, cloneName string, revision int) error
return nil
}
+func (m *Manager) GetDatasetOrigins(cloneDataset string) []string {
+ listZfsClonesCmd := "zfs list -H -o origin -r " + cloneDataset
+
+ out, err := m.runner.Run(listZfsClonesCmd, false)
+ if err != nil {
+ log.Warn(fmt.Sprintf("failed to check clone dataset %s: %v", cloneDataset, err))
+ return nil
+ }
+
+ lines := strings.Split(strings.TrimSpace(out), "\n")
+
+ return lines
+}
+
+func (m *Manager) GetActiveDatasets(cloneDataset string) ([]string, error) {
+ listZfsClonesCmd := fmt.Sprintf("zfs list -t snapshot -H -o name -r %s | grep %s", m.config.Pool.Name, cloneDataset)
+
+ out, err := m.runner.Run(listZfsClonesCmd, false)
+ if err != nil {
+ log.Dbg(fmt.Sprintf("no active datasets %s: %v", cloneDataset, err))
+ }
+
+ lines := strings.Split(strings.TrimSpace(out), "\n")
+
+ datasetRegistry := make([]string, 0, len(lines))
+
+ for _, line := range lines {
+ name := strings.TrimSpace(line)
+ if name == "" || name == empty {
+ continue
+ }
+
+ datasetRegistry = append(datasetRegistry, name)
+ }
+
+ return datasetRegistry, nil
+}
+
+func (m *Manager) hasDependentSnapshots(origins []string, cloneMountName string) bool {
+ for _, name := range origins {
+ if name == empty {
+ continue
+ }
+
+ if strings.HasPrefix(name, cloneMountName) {
+ log.Dbg(fmt.Sprintf("%s has dependent snapshot %s", cloneMountName, name))
+ return true
+ }
+ }
+
+ return false
+}
+
// cloneExists checks whether a ZFS clone exists.
func (m *Manager) cloneExists(name string) (bool, error) {
listZfsClonesCmd := "zfs list -r " + m.config.Pool.Name
@@ -373,11 +441,17 @@ func (m *Manager) CreateSnapshot(poolSuffix, dataStateAt string) (string, error)
return "", fmt.Errorf("failed to parse dataStateAt: %w", err)
}
+ branch := branching.ParseBranchNameFromSnapshot(snapshotName, poolName)
+ if branch == "" {
+ branch = branching.DefaultBranch
+ }
+
newSnapshot := resources.Snapshot{
ID: snapshotName,
CreatedAt: time.Now(),
DataStateAt: dataStateTime,
Pool: m.config.Pool.Name,
+ Branch: branch,
}
if !strings.HasSuffix(snapshotName, m.config.PreSnapshotSuffix) {
@@ -504,7 +578,7 @@ func (m *Manager) checkDependentClones(snapshotName string) (string, error) {
}
// CleanupSnapshots destroys old snapshots considering retention limit and related clones.
-func (m *Manager) CleanupSnapshots(retentionLimit int) ([]string, error) {
+func (m *Manager) CleanupSnapshots(retentionLimit int, mode models.RetrievalMode) ([]string, error) {
clonesCmd := fmt.Sprintf("zfs list -S clones -o name,origin -H -r %s", m.config.Pool.Name)
clonesOutput, err := m.runner.Run(clonesCmd)
@@ -514,10 +588,16 @@ func (m *Manager) CleanupSnapshots(retentionLimit int) ([]string, error) {
busySnapshots := m.getBusySnapshotList(clonesOutput)
+ modeFilter := ""
+
+ if mode == models.Physical {
+ modeFilter = "| grep _pre$"
+ }
+
cleanupCmd := fmt.Sprintf(
- "zfs list -t snapshot -H -o name -s %s -s creation -r %s | grep -v clone | grep _pre$ | head -n -%d %s"+
+ "zfs list -t snapshot -H -o name -s %s -s creation -r %s | grep -v clone %s | head -n -%d %s"+
"| xargs -n1 --no-run-if-empty zfs destroy -R ",
- dataStateAtLabel, m.config.Pool.Name, retentionLimit, excludeBusySnapshots(busySnapshots))
+ dataStateAtLabel, m.config.Pool.Name, modeFilter, retentionLimit, excludeBusySnapshots(busySnapshots))
out, err := m.runner.Run(cleanupCmd)
if err != nil {
@@ -526,13 +606,128 @@ func (m *Manager) CleanupSnapshots(retentionLimit int) ([]string, error) {
return nil, errors.Wrap(err, "failed to clean up snapshots")
}
+ if err := m.cleanupEmptyDatasets(clonesOutput); err != nil {
+ return nil, fmt.Errorf("failed to clean up empty datasets: %w", err)
+ }
+
lines := strings.Split(out, "\n")
m.RefreshSnapshotList()
+ firstSnapshotID := ""
+
+ m.mu.Lock()
+ if l := len(m.snapshots); l > 0 {
+ firstSnapshotID = m.snapshots[l-1].ID
+ }
+ m.mu.Unlock()
+
+ m.reviewParentProperty(firstSnapshotID)
+
return lines, nil
}
+func (m *Manager) reviewParentProperty(snapshotID string) {
+ if snapshotID == "" {
+ return
+ }
+
+ parent, err := m.getProperty(parentProp, snapshotID)
+ if err != nil {
+ log.Err("failed to review parent property:", err)
+
+ return
+ }
+
+ if parent == "" {
+ return
+ }
+
+ _, err = m.GetSnapshotProperties(parent)
+ if err != nil {
+ // Parent snapshot not found, clean up the property.
+ if err = m.setParent("", snapshotID); err != nil {
+ log.Err(err)
+ }
+ }
+}
+
+func (m *Manager) cleanupEmptyDatasets(clonesOutput string) error {
+ datasetsToRemove := m.getEmptyDatasets(clonesOutput)
+
+ for _, dataset := range datasetsToRemove {
+ log.Dbg("Remove empty dataset: ", dataset)
+
+ if err := m.DestroyDataset(dataset); err != nil {
+ return fmt.Errorf("failed to destroy dataset %s: %w", dataset, err)
+ }
+ }
+
+ return nil
+}
+
+func (m *Manager) getEmptyDatasets(clonesOutput string) []string {
+ const outputParts = 2
+
+ lines := strings.Split(strings.TrimSpace(clonesOutput), "\n")
+
+ allDatasets := make(map[string]struct{})
+ emptyDatasets := []string{}
+
+ for _, line := range lines {
+ if line == "" {
+ continue
+ }
+
+ parts := strings.Fields(line)
+ if len(parts) != outputParts {
+ continue
+ }
+
+ dataset := parts[0]
+ origin := parts[1]
+
+ // Skip branch datasets (only process clones)
+ // /branch///r
+ pathParts := strings.Split(dataset, "/")
+ if len(pathParts) <= 3 || pathParts[1] != branching.BranchDir {
+ continue
+ }
+
+ allDatasets[dataset] = struct{}{}
+
+ if origin == empty {
+ emptyDatasets = append(emptyDatasets, dataset)
+ }
+ }
+
+ // Find empty datasets without children
+ datasetsToRemove := []string{}
+
+ for _, dataset := range emptyDatasets {
+ hasChild := false
+ prefix := dataset + "/"
+
+ for other := range allDatasets {
+ if strings.HasPrefix(other, prefix) {
+ hasChild = true
+ break
+ }
+ }
+
+ if !hasChild {
+ datasetsToRemove = append(datasetsToRemove, dataset)
+ }
+ }
+
+ // Sort by depth (the deepest first) to avoid conflicts
+ sort.Slice(datasetsToRemove, func(i, j int) bool {
+ return strings.Count(datasetsToRemove[i], "/") > strings.Count(datasetsToRemove[j], "/")
+ })
+
+ return datasetsToRemove
+}
+
func (m *Manager) getBusySnapshotList(clonesOutput string) []string {
systemClones := make(map[string]string)
branchingSnapshotDatasets := []string{}
@@ -594,7 +789,7 @@ func (m *Manager) GetSessionState(branch, name string) (*resources.SessionState,
var sEntry *ListEntry
- entryName := path.Join(m.config.Pool.Name, "branch", branch, name)
+ entryName := branching.CloneDataset(m.config.Pool.Name, branch, name)
for _, entry := range entries {
if entry.Name == entryName {
@@ -615,6 +810,34 @@ func (m *Manager) GetSessionState(branch, name string) (*resources.SessionState,
return state, nil
}
+// GetBatchSessionState returns session states for multiple clones in a single ZFS query.
+func (m *Manager) GetBatchSessionState(requests []resources.SessionStateRequest) (map[string]resources.SessionState, error) {
+ entries, err := m.listFilesystems(m.config.Pool.Name)
+ if err != nil {
+ return nil, fmt.Errorf("failed to list filesystems: %w", err)
+ }
+
+ entryMap := make(map[string]*ListEntry, len(entries))
+ for _, entry := range entries {
+ entryMap[entry.Name] = entry
+ }
+
+ sessionStates := make(map[string]resources.SessionState, len(requests))
+
+ for _, req := range requests {
+ entryName := branching.CloneDataset(m.config.Pool.Name, req.Branch, req.CloneID)
+
+ if entry, ok := entryMap[entryName]; ok {
+ sessionStates[req.CloneID] = resources.SessionState{
+ CloneDiffSize: entry.Used,
+ LogicalReferenced: entry.LogicalReferenced,
+ }
+ }
+ }
+
+ return sessionStates, nil
+}
+
// GetFilesystemState returns a disk state.
func (m *Manager) GetFilesystemState() (models.FileSystem, error) {
parts := strings.SplitN(m.config.Pool.Name, "/", 2)
@@ -675,7 +898,9 @@ func (m *Manager) SnapshotList() []resources.Snapshot {
// RefreshSnapshotList updates the list of snapshots.
func (m *Manager) RefreshSnapshotList() {
snapshots, err := m.getSnapshots()
- if err != nil {
+
+ var emptyPoolError *EmptyPoolError
+ if err != nil && !errors.As(err, &emptyPoolError) {
log.Err("failed to refresh snapshot list: ", err)
return
}
diff --git a/engine/internal/provision/thinclones/zfs/zfs_test.go b/engine/internal/provision/thinclones/zfs/zfs_test.go
index 0001c8a6..040eb73a 100644
--- a/engine/internal/provision/thinclones/zfs/zfs_test.go
+++ b/engine/internal/provision/thinclones/zfs/zfs_test.go
@@ -2,6 +2,7 @@ package zfs
import (
"errors"
+ "sort"
"testing"
"github.com/stretchr/testify/assert"
@@ -234,3 +235,120 @@ func TestSnapshotList(t *testing.T) {
require.Equal(t, []resources.Snapshot{{ID: "test3"}, {ID: "test1"}}, fsManager.SnapshotList())
})
}
+
+func TestCleanupEmptyDatasets(t *testing.T) {
+ tests := []struct {
+ name string
+ input string
+ expectedDestroyed []string
+ }{
+ {
+ name: "datasets with children should not be removed",
+ input: `test_pool -
+test_pool/branch -
+test_pool/branch/main -
+test_pool/branch/main/clone001 -
+test_pool/branch/main/clone001/r0 test_pool@snapshot001`,
+ expectedDestroyed: []string{},
+ },
+ {
+ name: "empty branch datasets without children should not be removed",
+ input: `test_pool -
+test_pool/branch -
+test_pool/branch/main -
+test_pool/branch/branch1 -
+test_pool/branch/branch2 -`,
+ expectedDestroyed: []string{},
+ },
+ {
+ name: "mixed case - some with children, some without",
+ input: `test_pool -
+test_pool/branch -
+test_pool/branch/main -
+test_pool/branch/main/clone001 -
+test_pool/branch/main/clone001/r0 test_pool@snapshot001
+test_pool/branch/main/clone002 -
+test_pool/branch/main/clone002/r0 test_pool@snapshot002
+test_pool/branch/branch -
+test_pool/temporary -`,
+ expectedDestroyed: []string{},
+ },
+
+ {
+ name: "empty input",
+ input: ``,
+ expectedDestroyed: []string{},
+ },
+ {
+ name: "only whitespace",
+ input: ` `,
+ expectedDestroyed: []string{},
+ },
+ {
+ name: "malformed lines should be skipped",
+ input: `test_pool -
+test_pool/branch
+invalid line without tabs
+test_pool/orphaned -
+ -
+test_pool/valid test_pool@snap1`,
+ expectedDestroyed: []string{},
+ },
+ {
+ name: "original example",
+ input: `test_dblab_pool -
+test_dblab_pool/branch -
+test_dblab_pool/branch/main -
+test_dblab_pool/branch/main/clone_pre_20250923095219 -
+test_dblab_pool/branch/main/clone_pre_20250923095219/r0 test_dblab_pool@snapshot_20250923095219_pre
+test_dblab_pool/branch/main/clone_pre_20250923095500 -
+test_dblab_pool/branch/main/clone_pre_20250923095500/r0 test_dblab_pool@snapshot_20250923095500_pre
+test_dblab_pool/branch/main/clone_pre_20250923100000 -
+test_dblab_pool/branch/main/clone_pre_20250923100000/r0 test_dblab_pool@snapshot_20250923100000_pre`,
+ expectedDestroyed: []string{},
+ },
+ {
+ name: "should skip branch datasets and only process clones",
+ input: `test_pool -
+test_pool/branch -
+test_pool/branch/main -
+test_pool/branch/main/clone001 -
+test_pool/branch/main/clone002 -
+test_pool/branch/feature -
+test_pool/branch/feature/orphaned_clone -
+test_pool/other -
+test_pool/other/dataset -`,
+ expectedDestroyed: []string{
+ "test_pool/branch/main/clone001",
+ "test_pool/branch/main/clone002",
+ "test_pool/branch/feature/orphaned_clone",
+ // Note: test_pool/other/dataset is NOT removed (not under /branch/)
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ fsManager := NewFSManager(runnerMock{}, Config{Pool: &resources.Pool{Name: "testPool"}})
+
+ destroyedDatasets := fsManager.getEmptyDatasets(tt.input)
+
+ sort.Strings(destroyedDatasets)
+ sort.Strings(tt.expectedDestroyed)
+
+ if len(destroyedDatasets) != len(tt.expectedDestroyed) {
+ t.Errorf("destroyed count mismatch: got %d, want %d\nDestroyed: %v\nExpected: %v",
+ len(destroyedDatasets), len(tt.expectedDestroyed),
+ destroyedDatasets, tt.expectedDestroyed)
+ return
+ }
+
+ for i := range destroyedDatasets {
+ if destroyedDatasets[i] != tt.expectedDestroyed[i] {
+ t.Errorf("destroyed dataset mismatch at index %d: got %s, want %s",
+ i, destroyedDatasets[i], tt.expectedDestroyed[i])
+ }
+ }
+ })
+ }
+}
diff --git a/engine/internal/retrieval/engine/postgres/logical/activity.go b/engine/internal/retrieval/engine/postgres/logical/activity.go
index 7649981b..3de34c71 100644
--- a/engine/internal/retrieval/engine/postgres/logical/activity.go
+++ b/engine/internal/retrieval/engine/postgres/logical/activity.go
@@ -7,6 +7,7 @@ import (
"strconv"
"github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/jackc/pgx/v4"
@@ -43,6 +44,8 @@ func dbSourceActivity(ctx context.Context, dbCfg Connection) ([]activity.PGEvent
return nil, fmt.Errorf("failed to connect to DB: %w", err)
}
+ defer func() { _ = querier.Close(context.Background()) }()
+
rows, err := querier.Query(ctx, statQuery)
if err != nil {
return nil, fmt.Errorf("failed to perform query to get DB activity: %w", err)
@@ -77,11 +80,14 @@ func pgContainerActivity(ctx context.Context, docker *client.Client, containerID
return []activity.PGEvent{}, nil
}
- activityCmd := []string{"psql", "-U", db.User(), "-d", db.Name(), "--record-separator='" + customRecordSeparator + "'", "-XAtc", statQuery}
+ activityCmd := []string{"psql", "-U", db.User(), "-d", db.Name(),
+ "--set=connect_timeout=5",
+ "-c", "SET statement_timeout = '10s';",
+ "--record-separator='" + customRecordSeparator + "'", "-XAtc", statQuery}
log.Msg("Running activity command: ", activityCmd)
- execCfg := types.ExecConfig{
+ execCfg := container.ExecOptions{
Tty: true,
Cmd: activityCmd,
}
diff --git a/engine/internal/retrieval/engine/postgres/logical/dump.go b/engine/internal/retrieval/engine/postgres/logical/dump.go
index d2a8ba57..b4d808a7 100644
--- a/engine/internal/retrieval/engine/postgres/logical/dump.go
+++ b/engine/internal/retrieval/engine/postgres/logical/dump.go
@@ -13,7 +13,6 @@ import (
"strings"
"time"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/mount"
@@ -390,7 +389,7 @@ func (d *DumpJob) Run(ctx context.Context) (err error) {
log.Msg("Running analyze command: ", analyzeCmd)
- if err := tools.ExecCommand(ctx, d.dockerClient, containerID, types.ExecConfig{
+ if err := tools.ExecCommand(ctx, d.dockerClient, containerID, container.ExecOptions{
Cmd: analyzeCmd,
Env: []string{"PGAPPNAME=" + dleRetrieval},
}); err != nil {
@@ -473,7 +472,7 @@ func (d *DumpJob) cleanupDumpLocation(ctx context.Context, dumpContID string, db
log.Msg("Running cleanup command: ", cleanupCmd)
- if out, err := tools.ExecCommandWithOutput(ctx, d.dockerClient, dumpContID, types.ExecConfig{
+ if out, err := tools.ExecCommandWithOutput(ctx, d.dockerClient, dumpContID, container.ExecOptions{
Tty: true,
Cmd: cleanupCmd,
}); err != nil {
@@ -502,7 +501,7 @@ func (d *DumpJob) dumpDatabase(ctx context.Context, dumpContID, dbName string, d
log.Msg("Running dump command: ", dumpCommand)
- if output, err := d.performDumpCommand(ctx, dumpContID, types.ExecConfig{
+ if output, err := d.performDumpCommand(ctx, dumpContID, container.ExecOptions{
Tty: true,
Cmd: dumpCommand,
Env: d.getExecEnvironmentVariables(),
@@ -528,7 +527,7 @@ func setupPGData(ctx context.Context, dockerClient *client.Client, dataDir, dump
return nil
}
- if err := tools.ExecCommand(ctx, dockerClient, dumpContID, types.ExecConfig{
+ if err := tools.ExecCommand(ctx, dockerClient, dumpContID, container.ExecOptions{
Cmd: []string{"chown", "-R", "postgres", dataDir},
}); err != nil {
return errors.Wrap(err, "failed to set permissions")
@@ -581,7 +580,7 @@ func (d *DumpJob) setupConnectionOptions(ctx context.Context) error {
return nil
}
-func (d *DumpJob) performDumpCommand(ctx context.Context, contID string, commandCfg types.ExecConfig) (string, error) {
+func (d *DumpJob) performDumpCommand(ctx context.Context, contID string, commandCfg container.ExecOptions) (string, error) {
if d.DumpOptions.Restore.Enabled {
d.dbMark.DataStateAt = time.Now().Format(tools.DataStateAtFormat)
}
diff --git a/engine/internal/retrieval/engine/postgres/logical/dump_integration_test.go b/engine/internal/retrieval/engine/postgres/logical/dump_integration_test.go
index 129da6a6..c368907f 100644
--- a/engine/internal/retrieval/engine/postgres/logical/dump_integration_test.go
+++ b/engine/internal/retrieval/engine/postgres/logical/dump_integration_test.go
@@ -14,7 +14,7 @@ import (
"testing"
"time"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
@@ -32,7 +32,7 @@ func TestStartExisingDumpContainer(t *testing.T) {
t.Parallel()
ctx := context.Background()
- docker, err := client.NewClientWithOpts(client.FromEnv)
+ docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
require.NoError(t, err)
// create dump job
@@ -63,13 +63,13 @@ func TestStartExisingDumpContainer(t *testing.T) {
assert.NoError(t, err)
// create dump container and stop it
- container, err := docker.ContainerCreate(ctx, job.buildContainerConfig(""), nil, &network.NetworkingConfig{},
+ containerResp, err := docker.ContainerCreate(ctx, job.buildContainerConfig(""), nil, &network.NetworkingConfig{},
nil, job.dumpContainerName(),
)
assert.NoError(t, err)
// clean container in case of any error
- defer tools.RemoveContainer(ctx, docker, container.ID, 10)
+ defer tools.RemoveContainer(ctx, docker, containerResp.ID, 10)
job.Run(ctx)
@@ -79,7 +79,7 @@ func TestStartExisingDumpContainer(t *testing.T) {
list, err := docker.ContainerList(
ctx,
- types.ContainerListOptions{
+ container.ListOptions{
All: false,
Filters: filterArgs,
},
diff --git a/engine/internal/retrieval/engine/postgres/logical/logical.go b/engine/internal/retrieval/engine/postgres/logical/logical.go
index bd985a87..0d3ea39b 100644
--- a/engine/internal/retrieval/engine/postgres/logical/logical.go
+++ b/engine/internal/retrieval/engine/postgres/logical/logical.go
@@ -28,7 +28,7 @@ func isAlreadyMounted(mounts []mount.Mount, dir string) bool {
dir = strings.Trim(dir, "/")
for _, mountPoint := range mounts {
- if strings.Trim(mountPoint.Source, "/") == dir {
+ if strings.Trim(mountPoint.Source, "/") == dir || strings.Trim(mountPoint.Target, "/") == dir {
return true
}
}
diff --git a/engine/internal/retrieval/engine/postgres/logical/logical_test.go b/engine/internal/retrieval/engine/postgres/logical/logical_test.go
index 0c61cd52..ead6521d 100644
--- a/engine/internal/retrieval/engine/postgres/logical/logical_test.go
+++ b/engine/internal/retrieval/engine/postgres/logical/logical_test.go
@@ -38,6 +38,16 @@ func TestIsAlreadyMounted(t *testing.T) {
dumpLocation: "/var/lib/dblab/new_pool/dump",
expectedResult: false,
},
+ {
+ source: []mount.Mount{{Source: "/host/path/dump", Target: "/var/lib/dblab/pool/dump"}},
+ dumpLocation: "/var/lib/dblab/pool/dump",
+ expectedResult: true,
+ },
+ {
+ source: []mount.Mount{{Source: "/host/path/dump", Target: "/var/lib/dblab/pool/dump/"}},
+ dumpLocation: "/var/lib/dblab/pool/dump",
+ expectedResult: true,
+ },
}
for _, tc := range testCases {
diff --git a/engine/internal/retrieval/engine/postgres/logical/restore.go b/engine/internal/retrieval/engine/postgres/logical/restore.go
index 9e4aa52c..8506a6c3 100644
--- a/engine/internal/retrieval/engine/postgres/logical/restore.go
+++ b/engine/internal/retrieval/engine/postgres/logical/restore.go
@@ -6,10 +6,12 @@
package logical
import (
+ "archive/tar"
"bufio"
"bytes"
"context"
"fmt"
+ "io"
"io/fs"
"os"
"path"
@@ -19,11 +21,9 @@ import (
"strings"
"time"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/client"
- "github.com/docker/docker/pkg/archive"
"github.com/pkg/errors"
"gitlab.com/postgres-ai/database-lab/v3/internal/provision/resources"
@@ -292,7 +292,7 @@ func (r *RestoreJob) Run(ctx context.Context) (err error) {
log.Msg("Running analyze command: ", analyzeCmd)
- if err := tools.ExecCommand(ctx, r.dockerClient, containerID, types.ExecConfig{
+ if err := tools.ExecCommand(ctx, r.dockerClient, containerID, container.ExecOptions{
Cmd: analyzeCmd,
Env: []string{"PGAPPNAME=" + dleRetrieval},
}); err != nil {
@@ -408,7 +408,7 @@ func (r *RestoreJob) extractDBNameFromDump(ctx context.Context, contID, dumpPath
extractDBNameCmd := fmt.Sprintf("pg_restore --list %s | grep %s | tr -d '[;]'", dumpPath, prefixDBName)
log.Msg("Extract database name: ", extractDBNameCmd)
- outputLine, err := tools.ExecCommandWithOutput(ctx, r.dockerClient, contID, types.ExecConfig{
+ outputLine, err := tools.ExecCommandWithOutput(ctx, r.dockerClient, contID, container.ExecOptions{
Cmd: []string{"bash", "-c", extractDBNameCmd},
})
if err != nil {
@@ -573,7 +573,7 @@ func (r *RestoreJob) restoreDB(ctx context.Context, contID, dbName string, dbDef
log.Msg("Running preparatory command to create list file for "+dbName, preCmd)
- output, err := tools.ExecCommandWithOutput(ctx, r.dockerClient, contID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, r.dockerClient, contID, container.ExecOptions{
Tty: true,
Cmd: preCmd,
Env: []string{"PGAPPNAME=" + dleRetrieval},
@@ -589,7 +589,7 @@ func (r *RestoreJob) restoreDB(ctx context.Context, contID, dbName string, dbDef
restoreCommand := r.buildLogicalRestoreCommand(dbName, dbDefinition, tmpListFile)
log.Msg("Running restore command for "+dbName, restoreCommand)
- output, err := tools.ExecCommandWithOutput(ctx, r.dockerClient, contID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, r.dockerClient, contID, container.ExecOptions{
Tty: true,
Cmd: restoreCommand,
Env: []string{"PGAPPNAME=" + dleRetrieval},
@@ -647,7 +647,7 @@ func (r *RestoreJob) prepareDB(ctx context.Context, contID, dbName string) error
cmd := []string{"psql", "--username", r.globalCfg.Database.User(), "--dbname", defaults.DBName, "--file", dstPath}
log.Msg("Run command", cmd)
- if out, err := tools.ExecCommandWithOutput(ctx, r.dockerClient, contID, types.ExecConfig{Tty: true, Cmd: cmd}); err != nil {
+ if out, err := tools.ExecCommandWithOutput(ctx, r.dockerClient, contID, container.ExecOptions{Tty: true, Cmd: cmd}); err != nil {
log.Dbg("Command output: ", out)
return errors.Wrap(err, "failed to exec restore command")
}
@@ -656,35 +656,58 @@ func (r *RestoreJob) prepareDB(ctx context.Context, contID, dbName string) error
}
func (r *RestoreJob) prepareArchive(ctx context.Context, contID string, tempFile *os.File, dstPath string) error {
- srcInfo, err := archive.CopyInfoSourcePath(tempFile.Name(), false)
+ archiveReader, err := createTarArchive(tempFile, dstPath)
if err != nil {
return err
}
- srcArchive, err := archive.TarResource(srcInfo)
- if err != nil {
- return err
+ dstDir := filepath.Dir(dstPath)
+ if err := r.dockerClient.CopyToContainer(ctx, contID, dstDir, archiveReader, container.CopyToContainerOptions{
+ AllowOverwriteDirWithFile: true,
+ CopyUIDGID: true,
+ }); err != nil {
+ log.Err(err)
+
+ return errors.Wrap(err, "failed to copy auxiliary file")
}
- defer func() { _ = srcArchive.Close() }()
+ return nil
+}
+
+// createTarArchive creates a tar archive from a file for the given destination path.
+func createTarArchive(tempFile *os.File, dstPath string) (io.Reader, error) {
+ var buf bytes.Buffer
+ tarWriter := tar.NewWriter(&buf)
- dstDir, preparedArchive, err := archive.PrepareArchiveCopy(srcArchive, srcInfo, archive.CopyInfo{Path: dstPath})
+ fileInfo, err := tempFile.Stat()
if err != nil {
- return err
+ return nil, errors.Wrap(err, "failed to stat file")
}
- defer func() { _ = preparedArchive.Close() }()
+ header := &tar.Header{
+ Name: filepath.Base(dstPath),
+ Mode: int64(fileInfo.Mode()),
+ Size: fileInfo.Size(),
+ ModTime: fileInfo.ModTime(),
+ }
- if err := r.dockerClient.CopyToContainer(ctx, contID, dstDir, preparedArchive, types.CopyToContainerOptions{
- AllowOverwriteDirWithFile: true,
- CopyUIDGID: true,
- }); err != nil {
- log.Err(err)
+ if err := tarWriter.WriteHeader(header); err != nil {
+ return nil, errors.Wrap(err, "failed to write tar header")
+ }
- return errors.Wrap(err, "failed to copy auxiliary file")
+ if _, err := tempFile.Seek(0, 0); err != nil {
+ return nil, errors.Wrap(err, "failed to seek file")
}
- return nil
+ if _, err := io.Copy(tarWriter, tempFile); err != nil {
+ return nil, errors.Wrap(err, "failed to copy file to tar")
+ }
+
+ if err := tarWriter.Close(); err != nil {
+ return nil, errors.Wrap(err, "failed to close tar writer")
+ }
+
+ return &buf, nil
}
// formatDBName extracts a database name from a file name and adjusts it.
@@ -735,7 +758,7 @@ func (r *RestoreJob) retrieveDataStateAt(ctx context.Context, contID, dumpLocati
log.Dbg("Running a restore metadata command: ", restoreMetaCmd)
- execCommand, err := r.dockerClient.ContainerExecCreate(ctx, contID, types.ExecConfig{
+ execCommand, err := r.dockerClient.ContainerExecCreate(ctx, contID, container.ExecOptions{
AttachStdout: true,
AttachStderr: true,
Cmd: restoreMetaCmd,
@@ -744,7 +767,7 @@ func (r *RestoreJob) retrieveDataStateAt(ctx context.Context, contID, dumpLocati
return "", errors.Wrap(err, "failed to create a restore metadata command")
}
- execAttach, err := r.dockerClient.ContainerExecAttach(ctx, execCommand.ID, types.ExecStartCheck{})
+ execAttach, err := r.dockerClient.ContainerExecAttach(ctx, execCommand.ID, container.ExecStartOptions{})
if err != nil {
return "", errors.Wrap(err, "failed to exec a restore metadata command")
}
diff --git a/engine/internal/retrieval/engine/postgres/logical/restore_test.go b/engine/internal/retrieval/engine/postgres/logical/restore_test.go
index 94bba845..e76a26e1 100644
--- a/engine/internal/retrieval/engine/postgres/logical/restore_test.go
+++ b/engine/internal/retrieval/engine/postgres/logical/restore_test.go
@@ -5,7 +5,9 @@
package logical
import (
+ "archive/tar"
"context"
+ "io"
"os"
"path"
"testing"
@@ -446,5 +448,38 @@ func TestDBNameFormatter(t *testing.T) {
formattedDB := formatDBName(tc.filename)
assert.Equal(t, tc.dbname, formattedDB)
}
+}
+func TestCreateTarArchive(t *testing.T) {
+ // create a temporary file with test content
+ tempFile, err := os.CreateTemp("", "test-archive-*.sql")
+ require.NoError(t, err)
+ defer os.Remove(tempFile.Name())
+
+ testContent := []byte("SELECT 1; -- test database dump content\n")
+ _, err = tempFile.Write(testContent)
+ require.NoError(t, err)
+
+ // call the actual function being tested
+ dstPath := "/tmp/testdb.sql"
+ archiveReader, err := createTarArchive(tempFile, dstPath)
+ require.NoError(t, err)
+ require.NotNil(t, archiveReader)
+
+ // verify the tar archive is valid and contains expected file
+ tarReader := tar.NewReader(archiveReader)
+ tarHeader, err := tarReader.Next()
+ require.NoError(t, err)
+
+ assert.Equal(t, "testdb.sql", tarHeader.Name)
+ assert.Equal(t, int64(len(testContent)), tarHeader.Size)
+
+ // read and verify content
+ content, err := io.ReadAll(tarReader)
+ require.NoError(t, err)
+ assert.Equal(t, testContent, content)
+
+ // verify no more files in the tar
+ _, err = tarReader.Next()
+ assert.Equal(t, io.EOF, err)
}
diff --git a/engine/internal/retrieval/engine/postgres/physical/physical.go b/engine/internal/retrieval/engine/postgres/physical/physical.go
index 62f719e3..165f7e9b 100644
--- a/engine/internal/retrieval/engine/postgres/physical/physical.go
+++ b/engine/internal/retrieval/engine/postgres/physical/physical.go
@@ -15,12 +15,11 @@ import (
"strings"
"time"
- "github.com/docker/docker/api/types"
+ "github.com/containerd/errdefs"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/client"
-
"github.com/pkg/errors"
"gitlab.com/postgres-ai/database-lab/v3/internal/diagnostic"
@@ -240,7 +239,7 @@ func (r *RestoreJob) Run(ctx context.Context) (err error) {
log.Msg("Running restore command: ", r.restorer.GetRestoreCommand())
log.Msg(fmt.Sprintf("View logs using the command: %s %s", tools.ViewLogsCmd, r.restoreContainerName()))
- if err := tools.ExecCommand(ctx, r.dockerClient, contID, types.ExecConfig{
+ if err := tools.ExecCommand(ctx, r.dockerClient, contID, container.ExecOptions{
Cmd: []string{"bash", "-c", r.restorer.GetRestoreCommand() + " >& /proc/1/fd/1"},
}); err != nil {
return errors.Wrap(err, "failed to restore data")
@@ -284,7 +283,7 @@ func (r *RestoreJob) Run(ctx context.Context) (err error) {
}
// Set permissions.
- if err := tools.ExecCommand(ctx, r.dockerClient, contID, types.ExecConfig{
+ if err := tools.ExecCommand(ctx, r.dockerClient, contID, container.ExecOptions{
Cmd: []string{"chown", "-R", "postgres", dataDir},
}); err != nil {
return errors.Wrap(err, "failed to set permissions")
@@ -320,7 +319,7 @@ func (r *RestoreJob) syncInstanceName() string {
func (r *RestoreJob) runSyncInstance(ctx context.Context) (err error) {
syncContainer, err := r.dockerClient.ContainerInspect(ctx, r.syncInstanceName())
- if err != nil && !client.IsErrNotFound(err) {
+ if err != nil && !errdefs.IsNotFound(err) {
return errors.Wrap(err, "failed to inspect sync container")
}
diff --git a/engine/internal/retrieval/engine/postgres/physical/wal_g.go b/engine/internal/retrieval/engine/postgres/physical/wal_g.go
index 0abb2b36..7f015784 100644
--- a/engine/internal/retrieval/engine/postgres/physical/wal_g.go
+++ b/engine/internal/retrieval/engine/postgres/physical/wal_g.go
@@ -9,7 +9,7 @@ import (
"fmt"
"strings"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"golang.org/x/mod/semver"
@@ -114,7 +114,7 @@ func getLastBackupName(ctx context.Context, dockerClient *client.Client, contain
// parseLastBackupFromList parses the name of the latest backup from "wal-g backup-list" output.
func parseLastBackupFromList(ctx context.Context, dockerClient *client.Client, containerID string) (string, error) {
- output, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
Cmd: []string{"bash", "-c", "wal-g backup-list | grep base | sort -nk1 | tail -1 | awk '{print $1}'"},
})
if err != nil {
@@ -128,7 +128,7 @@ func parseLastBackupFromList(ctx context.Context, dockerClient *client.Client, c
// parseLastBackupFromDetails parses the name of the latest backup from "wal-g backup-list --detail" output.
func parseLastBackupFromDetails(ctx context.Context, dockerClient *client.Client, containerID string) (string, error) {
- output, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
Cmd: []string{"bash", "-c", "wal-g backup-list --detail | tail -1 | awk '{print $1}'"},
})
if err != nil {
@@ -142,7 +142,7 @@ func parseLastBackupFromDetails(ctx context.Context, dockerClient *client.Client
// getWalgVersion fetches the WAL-G version installed in the provided container.
func getWalgVersion(ctx context.Context, dockerClient *client.Client, containerID string) (string, error) {
- output, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
Cmd: []string{"bash", "-c", "wal-g --version"},
})
if err != nil {
diff --git a/engine/internal/retrieval/engine/postgres/snapshot/logical.go b/engine/internal/retrieval/engine/postgres/snapshot/logical.go
index 744be021..042d28f9 100644
--- a/engine/internal/retrieval/engine/postgres/snapshot/logical.go
+++ b/engine/internal/retrieval/engine/postgres/snapshot/logical.go
@@ -34,6 +34,7 @@ import (
"gitlab.com/postgres-ai/database-lab/v3/internal/telemetry"
"gitlab.com/postgres-ai/database-lab/v3/pkg/config/global"
"gitlab.com/postgres-ai/database-lab/v3/pkg/log"
+ "gitlab.com/postgres-ai/database-lab/v3/pkg/models"
"gitlab.com/postgres-ai/database-lab/v3/pkg/util"
)
@@ -151,7 +152,7 @@ func (s *LogicalInitial) Run(ctx context.Context) error {
log.Dbg("Cleaning up old snapshots from a dataset")
- if _, err := s.cloneManager.CleanupSnapshots(0); err != nil {
+ if _, err := s.cloneManager.CleanupSnapshots(0, models.Logical); err != nil {
return errors.Wrap(err, "failed to destroy old snapshots")
}
diff --git a/engine/internal/retrieval/engine/postgres/snapshot/physical.go b/engine/internal/retrieval/engine/postgres/snapshot/physical.go
index f49b9d8d..2d95e699 100644
--- a/engine/internal/retrieval/engine/postgres/snapshot/physical.go
+++ b/engine/internal/retrieval/engine/postgres/snapshot/physical.go
@@ -19,7 +19,6 @@ import (
"github.com/araddon/dateparse"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
@@ -47,6 +46,7 @@ import (
"gitlab.com/postgres-ai/database-lab/v3/internal/telemetry"
"gitlab.com/postgres-ai/database-lab/v3/pkg/config/global"
"gitlab.com/postgres-ai/database-lab/v3/pkg/log"
+ "gitlab.com/postgres-ai/database-lab/v3/pkg/models"
"gitlab.com/postgres-ai/database-lab/v3/pkg/util"
"gitlab.com/postgres-ai/database-lab/v3/pkg/util/branching"
)
@@ -367,7 +367,8 @@ func (p *PhysicalInitial) run(ctx context.Context) (err error) {
defer func() {
if err != nil {
- if errDestroy := p.cloneManager.DestroyClone(branching.DefaultBranch, cloneName, branching.DefaultRevision); errDestroy != nil {
+ cloneDataset := branching.CloneDataset(p.fsPool.Name, branching.DefaultBranch, cloneName)
+ if errDestroy := p.cloneManager.DestroyDataset(cloneDataset); errDestroy != nil {
log.Err(fmt.Sprintf("failed to destroy clone %q: %v", cloneName, errDestroy))
}
}
@@ -402,6 +403,10 @@ func (p *PhysicalInitial) run(ctx context.Context) (err error) {
p.tm.SendEvent(ctx, telemetry.SnapshotCreatedEvent, telemetry.SnapshotCreated{})
+ if err := p.cloneManager.VerifyBranchMetadata(); err != nil {
+ log.Warn("cannot verify branch metadata", err.Error())
+ }
+
if err := p.cleanupOldLogs(); err != nil {
log.Warn("cannot clean up old logs", err.Error())
}
@@ -728,7 +733,7 @@ func (p *PhysicalInitial) getDSAFromWAL(ctx context.Context, pgVersion float64,
walDirectory := walDir(cloneDir, pgVersion)
- output, err := tools.ExecCommandWithOutput(ctx, p.dockerClient, containerID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, p.dockerClient, containerID, container.ExecOptions{
Cmd: []string{"ls", "-t", walDirectory},
})
if err != nil {
@@ -777,7 +782,7 @@ func (p *PhysicalInitial) parseWAL(
) string {
cmd := walCommand(pgVersion, walFilePath)
- output, err := tools.ExecCommandWithOutput(ctx, p.dockerClient, containerID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, p.dockerClient, containerID, container.ExecOptions{
Cmd: []string{"sh", "-c", cmd},
})
if err != nil {
@@ -956,7 +961,7 @@ func (p *PhysicalInitial) checkRecovery(ctx context.Context, containerID string)
log.Msg("Check recovery command", checkRecoveryCmd)
- output, err := tools.ExecCommandWithResponse(ctx, p.dockerClient, containerID, types.ExecConfig{
+ output, err := tools.ExecCommandWithResponse(ctx, p.dockerClient, containerID, container.ExecOptions{
Cmd: checkRecoveryCmd,
AttachStderr: false,
AttachStdout: true,
@@ -1040,7 +1045,7 @@ func (p *PhysicalInitial) getLastXActReplayTimestamp(ctx context.Context, contai
log.Msg("Running dataStateAt command", extractionCommand)
- output, err := tools.ExecCommandWithOutput(ctx, p.dockerClient, containerID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, p.dockerClient, containerID, container.ExecOptions{
Cmd: extractionCommand,
User: defaults.Username,
})
@@ -1079,7 +1084,7 @@ func (p *PhysicalInitial) runPromoteCommand(ctx context.Context, containerID, cl
log.Msg("Running promote command", promoteCommand)
- output, err := tools.ExecCommandWithOutput(ctx, p.dockerClient, containerID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, p.dockerClient, containerID, container.ExecOptions{
User: defaults.Username,
Cmd: promoteCommand,
Env: []string{
@@ -1122,7 +1127,7 @@ func (p *PhysicalInitial) cleanupSnapshots(retentionLimit int) error {
default:
}
- _, err := p.cloneManager.CleanupSnapshots(retentionLimit)
+ _, err := p.cloneManager.CleanupSnapshots(retentionLimit, models.Physical)
if err != nil {
return errors.Wrap(err, "failed to clean up snapshots")
}
diff --git a/engine/internal/retrieval/engine/postgres/snapshot/physical_integration_test.go b/engine/internal/retrieval/engine/postgres/snapshot/physical_integration_test.go
index a8342004..687394ab 100644
--- a/engine/internal/retrieval/engine/postgres/snapshot/physical_integration_test.go
+++ b/engine/internal/retrieval/engine/postgres/snapshot/physical_integration_test.go
@@ -86,7 +86,7 @@ const (
)
func TestParsingWAL96(t *testing.T) {
- dockerCLI, err := client.NewClientWithOpts(client.FromEnv)
+ dockerCLI, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
t.Fatal("Failed to create a Docker client:", err)
}
@@ -95,7 +95,7 @@ func TestParsingWAL96(t *testing.T) {
}
func TestParsingWAL(t *testing.T) {
- dockerCLI, err := client.NewClientWithOpts(client.FromEnv)
+ dockerCLI, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
t.Fatal("Failed to create a Docker client:", err)
}
@@ -145,7 +145,7 @@ func testWALParsing(t *testing.T, dockerCLI *client.Client, pgVersion float64, i
defer func() { _ = postgresContainer.Terminate(ctx) }()
// Prepare test data.
- code, err := postgresContainer.Exec(ctx, []string{"psql", "-U", user, "-d", dbname, "-XAtc", initialSQL})
+ code, _, err := postgresContainer.Exec(ctx, []string{"psql", "-U", user, "-d", dbname, "-XAtc", initialSQL})
require.Nil(t, err)
assert.Equal(t, 0, code)
diff --git a/engine/internal/retrieval/engine/postgres/tools/cont/container.go b/engine/internal/retrieval/engine/postgres/tools/cont/container.go
index a5d59a0c..0c39db56 100644
--- a/engine/internal/retrieval/engine/postgres/tools/cont/container.go
+++ b/engine/internal/retrieval/engine/postgres/tools/cont/container.go
@@ -10,7 +10,6 @@ import (
"strings"
"time"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
@@ -152,7 +151,7 @@ func cleanUpContainers(ctx context.Context, dockerCli *client.Client, instanceID
return nil
}
-func getContainerList(ctx context.Context, d *client.Client, instanceID string, pairs []filters.KeyValuePair) ([]types.Container, error) {
+func getContainerList(ctx context.Context, d *client.Client, instanceID string, pairs []filters.KeyValuePair) ([]container.Summary, error) {
filterPairs := append([]filters.KeyValuePair{
{
Key: labelFilter,
@@ -183,7 +182,7 @@ func shouldStopInternalProcess(controlLabel string) bool {
return controlLabel == DBLabSyncLabel
}
-func getContainerName(controlCont types.Container) string {
+func getContainerName(controlCont container.Summary) string {
return strings.Join(controlCont.Names, ", ")
}
diff --git a/engine/internal/retrieval/engine/postgres/tools/db/image_content.go b/engine/internal/retrieval/engine/postgres/tools/db/image_content.go
index a66762c6..718b5c46 100644
--- a/engine/internal/retrieval/engine/postgres/tools/db/image_content.go
+++ b/engine/internal/retrieval/engine/postgres/tools/db/image_content.go
@@ -12,7 +12,6 @@ import (
"os/signal"
"strings"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/jackc/pgx/v4"
@@ -94,7 +93,7 @@ func (i *ImageContent) Databases() map[string]struct{} {
// Collect collects extension and locale lists from the provided Docker image.
func (i *ImageContent) Collect(dockerImage string) error {
- docker, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.39"))
+ docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
log.Fatal("Failed to create a Docker client:", err)
}
@@ -245,7 +244,7 @@ func resetHBA(ctx context.Context, dockerClient *client.Client, containerID stri
log.Dbg("Reset pg_hba", command)
- out, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ out, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
Tty: true,
Cmd: command,
})
@@ -263,7 +262,7 @@ func setListenAddresses(ctx context.Context, dockerClient *client.Client, contai
log.Dbg("Set listen addresses", command)
- out, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ out, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
Tty: true,
Cmd: command,
})
@@ -281,7 +280,7 @@ func getLocales(ctx context.Context, dockerClient *client.Client, containerID st
log.Dbg("Get locale list", command)
- out, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ out, err := tools.ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
Tty: true,
Cmd: command,
})
diff --git a/engine/internal/retrieval/engine/postgres/tools/pgtool/pgtool.go b/engine/internal/retrieval/engine/postgres/tools/pgtool/pgtool.go
index 06e07fd1..176b6a8d 100644
--- a/engine/internal/retrieval/engine/postgres/tools/pgtool/pgtool.go
+++ b/engine/internal/retrieval/engine/postgres/tools/pgtool/pgtool.go
@@ -11,6 +11,7 @@ import (
"os"
"github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/pkg/errors"
)
@@ -23,7 +24,7 @@ func ReadControlData(ctx context.Context, d *client.Client, contID, dataDir stri
return types.HijackedResponse{}, errors.Wrap(err, "failed to create an exec command")
}
- attachResponse, err := d.ContainerExecAttach(ctx, controlDataCmd.ID, types.ExecStartCheck{})
+ attachResponse, err := d.ContainerExecAttach(ctx, controlDataCmd.ID, container.ExecStartOptions{})
if err != nil {
return types.HijackedResponse{}, errors.Wrap(err, "failed to attach to the exec command")
}
@@ -31,10 +32,10 @@ func ReadControlData(ctx context.Context, d *client.Client, contID, dataDir stri
return attachResponse, nil
}
-func pgControlDataConfig(pgDataDir string, pgVersion float64) types.ExecConfig {
+func pgControlDataConfig(pgDataDir string, pgVersion float64) container.ExecOptions {
command := fmt.Sprintf("/usr/lib/postgresql/%g/bin/pg_controldata", pgVersion)
- return types.ExecConfig{
+ return container.ExecOptions{
AttachStdout: true,
AttachStderr: true,
Cmd: []string{command, "-D", pgDataDir},
diff --git a/engine/internal/retrieval/engine/postgres/tools/query/preprocessor.go b/engine/internal/retrieval/engine/postgres/tools/query/preprocessor.go
index 00d48552..2f55d003 100644
--- a/engine/internal/retrieval/engine/postgres/tools/query/preprocessor.go
+++ b/engine/internal/retrieval/engine/postgres/tools/query/preprocessor.go
@@ -12,7 +12,7 @@ import (
"path"
"sync"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"gitlab.com/postgres-ai/database-lab/v3/internal/retrieval/engine/postgres/tools"
@@ -167,7 +167,7 @@ func (q *Processor) runSQLFile(ctx context.Context, containerID, filename string
log.Msg("Run psql command", psqlCommand)
- output, err := tools.ExecCommandWithOutput(ctx, q.docker, containerID, types.ExecConfig{Cmd: psqlCommand})
+ output, err := tools.ExecCommandWithOutput(ctx, q.docker, containerID, container.ExecOptions{Cmd: psqlCommand})
return output, err
}
@@ -198,7 +198,7 @@ func (q *Processor) runInlineSQL(ctx context.Context, containerID, inlineSQL str
log.Msg("Run psql command", psqlCommand)
- output, err := tools.ExecCommandWithOutput(ctx, q.docker, containerID, types.ExecConfig{Cmd: psqlCommand})
+ output, err := tools.ExecCommandWithOutput(ctx, q.docker, containerID, container.ExecOptions{Cmd: psqlCommand})
return output, err
}
diff --git a/engine/internal/retrieval/engine/postgres/tools/tools.go b/engine/internal/retrieval/engine/postgres/tools/tools.go
index 1fe2cefe..e24970ae 100644
--- a/engine/internal/retrieval/engine/postgres/tools/tools.go
+++ b/engine/internal/retrieval/engine/postgres/tools/tools.go
@@ -26,6 +26,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
+ imagetypes "github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
@@ -181,8 +182,9 @@ func AddVolumesToHostConfig(ctx context.Context, docker *client.Client, hostConf
}
// GetMountsFromMountPoints creates a list of mounts.
-func GetMountsFromMountPoints(dataDir string, mountPoints []types.MountPoint) []mount.Mount {
+func GetMountsFromMountPoints(dataDir string, mountPoints []container.MountPoint) []mount.Mount {
mounts := make([]mount.Mount, 0, len(mountPoints))
+ seen := make(map[string]struct{})
for _, mountPoint := range mountPoints {
// Rewrite mounting to data directory.
@@ -192,15 +194,39 @@ func GetMountsFromMountPoints(dataDir string, mountPoints []types.MountPoint) []
mountPoint.Destination = dataDir
}
- mounts = append(mounts, mount.Mount{
+ // Deduplicate mounts by normalizing paths and checking both source and target.
+ normalizedSource := strings.Trim(mountPoint.Source, "/")
+ normalizedTarget := strings.Trim(mountPoint.Destination, "/")
+ mountKey := normalizedSource + "|" + normalizedTarget
+
+ if _, ok := seen[mountKey]; ok {
+ log.Dbg("skipping duplicate mount", mountPoint.Source, "to", mountPoint.Destination)
+ continue
+ }
+
+ seen[mountKey] = struct{}{}
+
+ // for volume mounts, use the volume name instead of the full path
+ source := mountPoint.Source
+ if mountPoint.Type == mount.TypeVolume {
+ source = mountPoint.Name
+ }
+
+ m := mount.Mount{
Type: mountPoint.Type,
- Source: mountPoint.Source,
+ Source: source,
Target: mountPoint.Destination,
ReadOnly: !mountPoint.RW,
- BindOptions: &mount.BindOptions{
+ }
+
+ // bindobtions should only be set for bind mounts, not volume mounts
+ if mountPoint.Type == mount.TypeBind {
+ m.BindOptions = &mount.BindOptions{
Propagation: mountPoint.Propagation,
- },
- })
+ }
+ }
+
+ mounts = append(mounts, m)
}
return mounts
@@ -212,7 +238,7 @@ func InitDB(ctx context.Context, dockerClient *client.Client, containerID string
log.Dbg("Init db", initCommand)
- out, err := ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ out, err := ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
Tty: true,
Cmd: initCommand,
})
@@ -232,7 +258,7 @@ func MakeDir(ctx context.Context, dockerClient *client.Client, dumpContID, dataD
log.Msg("Running mkdir command: ", mkdirCmd)
- if out, err := ExecCommandWithOutput(ctx, dockerClient, dumpContID, types.ExecConfig{
+ if out, err := ExecCommandWithOutput(ctx, dockerClient, dumpContID, container.ExecOptions{
Cmd: mkdirCmd,
User: defaults.Username,
}); err != nil {
@@ -249,7 +275,7 @@ func LsContainerDirectory(ctx context.Context, dockerClient *client.Client, cont
log.Dbg("Check directory: ", lsCommand)
- out, err := ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ out, err := ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
Tty: true,
Cmd: lsCommand,
})
@@ -271,7 +297,7 @@ func StartPostgres(ctx context.Context, dockerClient *client.Client, containerID
log.Msg("Starting PostgreSQL instance", startCommand)
- out, err := ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ out, err := ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
Tty: true,
Cmd: startCommand,
})
@@ -308,7 +334,7 @@ func RunCheckpoint(
ctx,
dockerClient,
containerID,
- types.ExecConfig{Cmd: commandCheckpoint},
+ container.ExecOptions{Cmd: commandCheckpoint},
)
if err != nil {
return errors.Wrap(err, "failed to make checkpoint")
@@ -331,7 +357,7 @@ func StopPostgres(ctx context.Context, dockerClient *client.Client, containerID,
log.Msg("Stopping PostgreSQL instance", stopCommand)
- if output, err := ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{
+ if output, err := ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{
User: defaults.Username,
Cmd: stopCommand,
}); err != nil {
@@ -451,7 +477,7 @@ func printPostgresLogsHint(ctx context.Context, dockerClient *client.Client, con
func PrintLastPostgresLogs(ctx context.Context, dockerClient *client.Client, containerID, clonePath string) {
command := []string{"bash", "-c", "tail -n 20 $(ls -t " + clonePath + "/log/*.csv | tail -n 1)"}
- output, err := ExecCommandWithOutput(ctx, dockerClient, containerID, types.ExecConfig{Cmd: command})
+ output, err := ExecCommandWithOutput(ctx, dockerClient, containerID, container.ExecOptions{Cmd: command})
if err != nil {
log.Err(errors.Wrap(err, "failed to read Postgres logs"))
}
@@ -494,7 +520,7 @@ func RemoveContainer(ctx context.Context, dockerClient *client.Client, container
// PullImage pulls a Docker image.
func PullImage(ctx context.Context, dockerClient *client.Client, image string) error {
- inspectionResult, _, err := dockerClient.ImageInspectWithRaw(ctx, image)
+ inspectionResult, err := dockerClient.ImageInspect(ctx, image)
if err != nil {
if _, ok := err.(errdefs.ErrNotFound); !ok {
return errors.Wrapf(err, "failed to inspect image %q", image)
@@ -506,7 +532,7 @@ func PullImage(ctx context.Context, dockerClient *client.Client, image string) e
return nil
}
- pullOutput, err := dockerClient.ImagePull(ctx, image, types.ImagePullOptions{})
+ pullOutput, err := dockerClient.ImagePull(ctx, image, imagetypes.PullOptions{})
if err != nil {
return errors.Wrapf(err, "failed to pull image %q", image)
}
@@ -521,7 +547,7 @@ func PullImage(ctx context.Context, dockerClient *client.Client, image string) e
}
// ExecCommand runs command in Docker container.
-func ExecCommand(ctx context.Context, dockerClient *client.Client, containerID string, execCfg types.ExecConfig) error {
+func ExecCommand(ctx context.Context, dockerClient *client.Client, containerID string, execCfg container.ExecOptions) error {
execCfg.AttachStdout = true
execCfg.AttachStderr = true
@@ -530,7 +556,7 @@ func ExecCommand(ctx context.Context, dockerClient *client.Client, containerID s
return errors.Wrap(err, "failed to create command")
}
- if err := dockerClient.ContainerExecStart(ctx, execCommand.ID, types.ExecStartCheck{}); err != nil {
+ if err := dockerClient.ContainerExecStart(ctx, execCommand.ID, container.ExecStartOptions{}); err != nil {
return errors.Wrap(err, "failed to start a command")
}
@@ -560,7 +586,9 @@ func inspectCommandExitCode(ctx context.Context, dockerClient *client.Client, co
}
// ExecCommandWithOutput runs command in Docker container, enables all stdout and stderr and returns the command output.
-func ExecCommandWithOutput(ctx context.Context, dockerClient *client.Client, containerID string, execCfg types.ExecConfig) (string, error) {
+func ExecCommandWithOutput(
+ ctx context.Context, dockerClient *client.Client, containerID string, execCfg container.ExecOptions,
+) (string, error) {
execCfg.AttachStdout = true
execCfg.AttachStderr = true
@@ -568,18 +596,22 @@ func ExecCommandWithOutput(ctx context.Context, dockerClient *client.Client, con
}
// ExecCommandWithResponse runs command in Docker container and returns the command output.
-func ExecCommandWithResponse(ctx context.Context, docker *client.Client, containerID string, execCfg types.ExecConfig) (string, error) {
+func ExecCommandWithResponse(
+ ctx context.Context, docker *client.Client, containerID string, execCfg container.ExecOptions,
+) (string, error) {
return execCommandWithResponse(ctx, docker, containerID, execCfg)
}
-func execCommandWithResponse(ctx context.Context, docker *client.Client, containerID string, execCfg types.ExecConfig) (string, error) {
+func execCommandWithResponse(
+ ctx context.Context, docker *client.Client, containerID string, execCfg container.ExecOptions,
+) (string, error) {
execCommand, err := docker.ContainerExecCreate(ctx, containerID, execCfg)
if err != nil {
return "", errors.Wrap(err, "failed to create an exec command")
}
- attachResponse, err := docker.ContainerExecAttach(ctx, execCommand.ID, types.ExecStartCheck{})
+ attachResponse, err := docker.ContainerExecAttach(ctx, execCommand.ID, container.ExecStartOptions{})
if err != nil {
return "", errors.Wrap(err, "failed to attach to exec command")
}
@@ -624,6 +656,10 @@ func processAttachResponse(ctx context.Context, reader io.Reader) ([]byte, error
break
case <-ctx.Done():
+ if closer, ok := reader.(io.Closer); ok {
+ _ = closer.Close()
+ }
+
return nil, ctx.Err()
}
diff --git a/engine/internal/retrieval/engine/postgres/tools/tools_test.go b/engine/internal/retrieval/engine/postgres/tools/tools_test.go
index 9398470e..8e04b2dd 100644
--- a/engine/internal/retrieval/engine/postgres/tools/tools_test.go
+++ b/engine/internal/retrieval/engine/postgres/tools/tools_test.go
@@ -8,7 +8,7 @@ import (
"os"
"testing"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -37,17 +37,21 @@ func TestIfDirectoryEmpty(t *testing.T) {
func TestGetMountsFromMountPoints(t *testing.T) {
testCases := []struct {
+ name string
dataDir string
- mountPoints []types.MountPoint
+ mountPoints []container.MountPoint
expectedPoints []mount.Mount
}{
{
+ name: "simple mount without transformation",
dataDir: "/var/lib/dblab/clones/dblab_clone_6000/data",
- mountPoints: []types.MountPoint{{
+ mountPoints: []container.MountPoint{{
+ Type: mount.TypeBind,
Source: "/var/lib/pgsql/data",
Destination: "/var/lib/postgresql/data",
}},
expectedPoints: []mount.Mount{{
+ Type: mount.TypeBind,
Source: "/var/lib/pgsql/data",
Target: "/var/lib/postgresql/data",
ReadOnly: true,
@@ -56,14 +60,16 @@ func TestGetMountsFromMountPoints(t *testing.T) {
},
}},
},
-
{
+ name: "mount with path transformation",
dataDir: "/var/lib/dblab/clones/dblab_clone_6000/data",
- mountPoints: []types.MountPoint{{
+ mountPoints: []container.MountPoint{{
+ Type: mount.TypeBind,
Source: "/var/lib/postgresql",
Destination: "/var/lib/dblab",
}},
expectedPoints: []mount.Mount{{
+ Type: mount.TypeBind,
Source: "/var/lib/postgresql/clones/dblab_clone_6000/data",
Target: "/var/lib/dblab/clones/dblab_clone_6000/data",
ReadOnly: true,
@@ -72,10 +78,63 @@ func TestGetMountsFromMountPoints(t *testing.T) {
},
}},
},
+ {
+ name: "deduplicate identical mounts",
+ dataDir: "/var/lib/dblab/data",
+ mountPoints: []container.MountPoint{
+ {Type: mount.TypeBind, Source: "/host/dump", Destination: "/var/lib/dblab/dump"},
+ {Type: mount.TypeBind, Source: "/host/dump", Destination: "/var/lib/dblab/dump"},
+ },
+ expectedPoints: []mount.Mount{{
+ Type: mount.TypeBind,
+ Source: "/host/dump",
+ Target: "/var/lib/dblab/dump",
+ ReadOnly: true,
+ BindOptions: &mount.BindOptions{
+ Propagation: "",
+ },
+ }},
+ },
+ {
+ name: "deduplicate mounts with trailing slashes",
+ dataDir: "/var/lib/dblab/data",
+ mountPoints: []container.MountPoint{
+ {Type: mount.TypeBind, Source: "/host/dump/", Destination: "/var/lib/dblab/dump"},
+ {Type: mount.TypeBind, Source: "/host/dump", Destination: "/var/lib/dblab/dump/"},
+ },
+ expectedPoints: []mount.Mount{{
+ Type: mount.TypeBind,
+ Source: "/host/dump/",
+ Target: "/var/lib/dblab/dump",
+ ReadOnly: true,
+ BindOptions: &mount.BindOptions{
+ Propagation: "",
+ },
+ }},
+ },
+ {
+ name: "volume mount uses name instead of path",
+ dataDir: "/var/lib/dblab/data",
+ mountPoints: []container.MountPoint{{
+ Type: mount.TypeVolume,
+ Name: "3749a7e336f27d8c1ce2a81c7b945954f7522ecc3a4be4a3855bf64473f63a89",
+ Source: "/var/lib/docker/volumes/3749a7e336f27d8c1ce2a81c7b945954f7522ecc3a4be4a3855bf64473f63a89/_data",
+ Destination: "/var/lib/docker",
+ RW: false,
+ }},
+ expectedPoints: []mount.Mount{{
+ Type: mount.TypeVolume,
+ Source: "3749a7e336f27d8c1ce2a81c7b945954f7522ecc3a4be4a3855bf64473f63a89",
+ Target: "/var/lib/docker",
+ ReadOnly: true,
+ }},
+ },
}
for _, tc := range testCases {
- mounts := GetMountsFromMountPoints(tc.dataDir, tc.mountPoints)
- assert.Equal(t, tc.expectedPoints, mounts)
+ t.Run(tc.name, func(t *testing.T) {
+ mounts := GetMountsFromMountPoints(tc.dataDir, tc.mountPoints)
+ assert.Equal(t, tc.expectedPoints, mounts)
+ })
}
}
diff --git a/engine/internal/runci/handlers.go b/engine/internal/runci/handlers.go
index 35236a49..767185e1 100644
--- a/engine/internal/runci/handlers.go
+++ b/engine/internal/runci/handlers.go
@@ -13,7 +13,6 @@ import (
"os"
"path"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/network"
@@ -233,7 +232,7 @@ func (s *Server) runCommands(ctx context.Context, clone *models.Clone, runID str
log.Msg("Running command: ", cmd)
- output, err := tools.ExecCommandWithOutput(ctx, s.docker, contRunner.ID, types.ExecConfig{
+ output, err := tools.ExecCommandWithOutput(ctx, s.docker, contRunner.ID, container.ExecOptions{
Cmd: cmd,
})
if err != nil {
diff --git a/engine/internal/srv/branch.go b/engine/internal/srv/branch.go
index 389b931c..1941591b 100644
--- a/engine/internal/srv/branch.go
+++ b/engine/internal/srv/branch.go
@@ -47,9 +47,6 @@ func (s *Server) listBranches(w http.ResponseWriter, r *http.Request) {
branchDetails := make([]models.BranchView, 0, len(branches))
- // branchRegistry is used to display the "main" branch with only the most recent snapshot.
- branchRegistry := make(map[string]int, 0)
-
for _, branchEntity := range branches {
snapshotDetails, ok := repo.Snapshots[branchEntity.SnapshotID]
if !ok {
@@ -60,6 +57,7 @@ func (s *Server) listBranches(w http.ResponseWriter, r *http.Request) {
branchView := models.BranchView{
Name: branchEntity.Name,
+ BaseDataset: branchEntity.Dataset,
Parent: parentSnapshot,
DataStateAt: snapshotDetails.DataStateAt,
SnapshotID: snapshotDetails.ID,
@@ -67,15 +65,6 @@ func (s *Server) listBranches(w http.ResponseWriter, r *http.Request) {
NumSnapshots: numSnapshots,
}
- if position, ok := branchRegistry[branchEntity.Name]; ok {
- if branchView.DataStateAt > branchDetails[position].DataStateAt {
- branchDetails[position] = branchView
- }
-
- continue
- }
-
- branchRegistry[branchView.Name] = len(branchDetails)
branchDetails = append(branchDetails, branchView)
}
@@ -136,15 +125,36 @@ func containsString(slice []string, s string) bool {
}
func (s *Server) getFSManagerForBranch(branchName string) (pool.FSManager, error) {
+ return s.getFSManagerForBranchAndDataset(branchName, "")
+}
+
+func (s *Server) getFSManagerForBranchAndDataset(branchName, dataset string) (pool.FSManager, error) {
allBranches, err := s.getAllAvailableBranches(s.pm.First())
if err != nil {
return nil, fmt.Errorf("failed to get branch list: %w", err)
}
for _, branchEntity := range allBranches {
- if branchEntity.Name == branchName { // TODO: filter by pool name as well because branch name is ambiguous.
+ if branchEntity.Name != branchName {
+ continue
+ }
+
+ if dataset == "" {
return s.getFSManagerForSnapshot(branchEntity.SnapshotID)
}
+
+ fsm, err := s.getFSManagerForSnapshot(branchEntity.SnapshotID)
+ if err != nil {
+ continue
+ }
+
+ if fsm.Pool().Name == dataset {
+ return fsm, nil
+ }
+ }
+
+ if dataset != "" {
+ return nil, fmt.Errorf("failed to find dataset %s of the branch: %s", dataset, branchName)
}
return nil, fmt.Errorf("failed to found dataset of the branch: %s", branchName)
@@ -185,6 +195,16 @@ func (s *Server) createBranch(w http.ResponseWriter, r *http.Request) {
}
}
+ snapshotID := createRequest.SnapshotID
+
+ if snapshotID != "" {
+ fsm, err = s.getFSManagerForSnapshot(snapshotID)
+ if err != nil {
+ api.SendBadRequestError(w, r, err.Error())
+ return
+ }
+ }
+
if fsm == nil {
api.SendBadRequestError(w, r, "no pool manager found")
return
@@ -201,8 +221,6 @@ func (s *Server) createBranch(w http.ResponseWriter, r *http.Request) {
return
}
- snapshotID := createRequest.SnapshotID
-
if snapshotID == "" {
if createRequest.BaseBranch == "" {
api.SendBadRequestError(w, r, "either base branch name or base snapshot ID must be specified")
@@ -434,17 +452,6 @@ func (s *Server) snapshot(w http.ResponseWriter, r *http.Request) {
return
}
- snapshot, err := s.Cloning.GetSnapshotByID(snapshotName)
- if err != nil {
- api.SendBadRequestError(w, r, err.Error())
- return
- }
-
- if err := s.Cloning.UpdateCloneSnapshot(clone.ID, snapshot); err != nil {
- api.SendBadRequestError(w, r, err.Error())
- return
- }
-
s.tm.SendEvent(context.Background(), telemetry.SnapshotCreatedEvent, telemetry.SnapshotCreated{})
if err := api.WriteJSON(w, http.StatusOK, types.SnapshotResponse{SnapshotID: snapshotName}); err != nil {
@@ -472,6 +479,18 @@ func filterSnapshotsByBranch(pool *resources.Pool, branch string, snapshots []mo
return filtered
}
+func filterSnapshotsByDataset(dataset string, snapshots []models.Snapshot) []models.Snapshot {
+ filtered := make([]models.Snapshot, 0)
+
+ for _, sn := range snapshots {
+ if sn.Pool == dataset {
+ filtered = append(filtered, sn)
+ }
+ }
+
+ return filtered
+}
+
func (s *Server) log(w http.ResponseWriter, r *http.Request) {
branchName := mux.Vars(r)["branchName"]
@@ -632,11 +651,17 @@ func snapshotsToRemove(repo *models.Repo, snapshotID, branchName string) []strin
}
func traverseUp(repo *models.Repo, snapshotID, branchName string) []string {
+ removingList := []string{}
+ visited := make(map[string]struct{})
snapshotPointer := repo.Snapshots[snapshotID]
- removingList := []string{}
+ for snapshotPointer.Parent != "-" && snapshotPointer.Parent != "" {
+ if _, found := visited[snapshotPointer.ID]; found {
+ break
+ }
+
+ visited[snapshotPointer.ID] = struct{}{}
- for snapshotPointer.Parent != "-" {
for _, snapshotRoot := range snapshotPointer.Root {
if snapshotRoot == branchName {
return removingList
@@ -644,7 +669,13 @@ func traverseUp(repo *models.Repo, snapshotID, branchName string) []string {
}
removingList = append(removingList, snapshotPointer.ID)
- snapshotPointer = repo.Snapshots[snapshotPointer.Parent]
+
+ nextSnapshot, exists := repo.Snapshots[snapshotPointer.Parent]
+ if !exists {
+ break
+ }
+
+ snapshotPointer = nextSnapshot
}
return removingList
diff --git a/engine/internal/srv/config.go b/engine/internal/srv/config.go
index e10bcbf8..fc4cf9f2 100644
--- a/engine/internal/srv/config.go
+++ b/engine/internal/srv/config.go
@@ -8,7 +8,7 @@ import (
"regexp"
"time"
- "github.com/docker/docker/api/types"
+ imagetypes "github.com/docker/docker/api/types/image"
yamlv2 "gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
@@ -350,7 +350,7 @@ func (s *Server) validateConfig(
}
if proj.DockerImage != nil {
- stream, err := s.docker.ImagePull(ctx, *proj.DockerImage, types.ImagePullOptions{})
+ stream, err := s.docker.ImagePull(ctx, *proj.DockerImage, imagetypes.PullOptions{})
if err != nil {
return err
}
diff --git a/engine/internal/srv/routes.go b/engine/internal/srv/routes.go
index 15f2ab56..82458171 100644
--- a/engine/internal/srv/routes.go
+++ b/engine/internal/srv/routes.go
@@ -6,6 +6,7 @@ import (
"fmt"
"net/http"
"os"
+ "path"
"sort"
"strconv"
"strings"
@@ -55,7 +56,7 @@ func (s *Server) retrievalState(w http.ResponseWriter, r *http.Request) {
retrieving.NextRefresh = models.NewLocalTime(spec.Next(time.Now()))
}
- retrieving.Activity = s.jobActivity(r.Context())
+ retrieving.Activity = s.jobActivity(context.Background())
if err := api.WriteJSON(w, http.StatusOK, retrieving); err != nil {
api.SendError(w, r, err)
@@ -108,8 +109,11 @@ func (s *Server) getSnapshots(w http.ResponseWriter, r *http.Request) {
return
}
- if branchRequest := r.URL.Query().Get("branch"); branchRequest != "" {
- fsm, err := s.getFSManagerForBranch(branchRequest)
+ branchRequest := r.URL.Query().Get("branch")
+ datasetRequest := r.URL.Query().Get("dataset")
+
+ if branchRequest != "" {
+ fsm, err := s.getFSManagerForBranchAndDataset(branchRequest, datasetRequest)
if err != nil {
api.SendBadRequestError(w, r, err.Error())
return
@@ -123,6 +127,10 @@ func (s *Server) getSnapshots(w http.ResponseWriter, r *http.Request) {
snapshots = filterSnapshotsByBranch(fsm.Pool(), branchRequest, snapshots)
}
+ if branchRequest == "" && datasetRequest != "" {
+ snapshots = filterSnapshotsByDataset(datasetRequest, snapshots)
+ }
+
if err = api.WriteJSON(w, http.StatusOK, snapshots); err != nil {
api.SendError(w, r, err)
return
@@ -182,7 +190,9 @@ func (s *Server) createSnapshot(w http.ResponseWriter, r *http.Request) {
return
}
- // TODO: set branching metadata.
+ if err := fsManager.VerifyBranchMetadata(); err != nil {
+ log.Warn("cannot verify branch metadata", err.Error())
+ }
latestSnapshot := snapshotList[0]
@@ -320,6 +330,28 @@ func (s *Server) deleteSnapshot(w http.ResponseWriter, r *http.Request) {
}
}
+ // When recursively deleting, set the branch label to the parent
+ if force && snapshotProperties.Parent != "" {
+ parentProps, err := fsm.GetSnapshotProperties(snapshotProperties.Parent)
+ if err != nil {
+ log.Err(err.Error())
+ }
+
+ branchName := snapshotProperties.Branch
+ fullDataset, _, found := strings.Cut(snapshotID, "@")
+
+ if branchName == "" && found {
+ branchName, _ = branching.ParseBranchName(fullDataset, poolName)
+ }
+
+ if branchName != "" && !isRoot(parentProps.Root, branchName) {
+ err := fsm.AddBranchProp(branchName, snapshotProperties.Parent)
+ if err != nil {
+ log.Err(err.Error())
+ }
+ }
+ }
+
if err = fsm.DestroySnapshot(snapshotID, thinclones.DestroyOptions{Force: force}); err != nil {
api.SendBadRequestError(w, r, err.Error())
return
@@ -331,22 +363,37 @@ func (s *Server) deleteSnapshot(w http.ResponseWriter, r *http.Request) {
return
}
- if snapshotProperties.Clones == "" && snapshot.NumClones == 0 {
+ if snapshotProperties.Clones == "" && snapshot.NumClones == 0 && snapshotProperties.Child == "" {
// Destroy dataset if there are no related objects
if fullDataset, _, found := strings.Cut(snapshotID, "@"); found && fullDataset != poolName {
- if err = fsm.DestroyDataset(fullDataset); err != nil {
+ activeDatasets, err := fsm.GetActiveDatasets(fullDataset)
+ if err != nil {
api.SendBadRequestError(w, r, err.Error())
return
}
+ // No active datasets or clones
+ if len(activeDatasets) == 0 && !s.hasActiveClone(fullDataset, poolName) {
+ if err = fsm.DestroyDataset(fullDataset); err != nil {
+ api.SendBadRequestError(w, r, err.Error())
+ return
+ }
+ }
+
// Remove dle:branch and dle:root from parent snapshot
if snapshotProperties.Parent != "" {
+ parentProps, err := fsm.GetSnapshotProperties(snapshotProperties.Parent)
+ if err != nil {
+ log.Err(err.Error())
+ }
+
branchName := snapshotProperties.Branch
if branchName == "" {
branchName, _ = branching.ParseBranchName(fullDataset, poolName)
}
- if branchName != "" {
+ // Clean up user branch labels and prevent main branch deletion
+ if branchName != "" && branchName != branching.DefaultBranch && isRoot(parentProps.Root, branchName) {
if err := fsm.DeleteBranchProp(branchName, snapshotProperties.Parent); err != nil {
log.Err(err.Error())
}
@@ -357,11 +404,18 @@ func (s *Server) deleteSnapshot(w http.ResponseWriter, r *http.Request) {
}
}
- // TODO: review all available revisions. Destroy base dataset only if there no any revision.
- if baseDataset, found := strings.CutSuffix(fullDataset, "/r0"); found {
- if err = fsm.DestroyDataset(baseDataset); err != nil {
- api.SendBadRequestError(w, r, err.Error())
- return
+ // Check if the dataset ends with revision (for example, /r0)
+ if branching.RevisionPattern.MatchString(fullDataset) {
+ // Remove the revision suffix
+ baseDataset := branching.RevisionPattern.ReplaceAllString(fullDataset, "")
+ origins := fsm.GetDatasetOrigins(baseDataset)
+
+ // If this is the last revision, remove the base dataset
+ if len(origins) < branching.MinDatasetNumber {
+ if err = fsm.DestroyDataset(baseDataset); err != nil {
+ api.SendBadRequestError(w, r, err.Error())
+ return
+ }
}
}
}
@@ -389,6 +443,30 @@ func (s *Server) deleteSnapshot(w http.ResponseWriter, r *http.Request) {
}
}
+func (s *Server) hasActiveClone(fullDataset, poolName string) bool {
+ cloneID, ok := branching.ParseCloneName(fullDataset, poolName)
+ if !ok {
+ return false
+ }
+
+ _, errClone := s.Cloning.GetClone(cloneID)
+ if errClone != nil && errClone.Error() == "clone not found" {
+ return false
+ }
+
+ return true
+}
+
+func isRoot(root, branch string) bool {
+ if root == "" || branch == "" {
+ return false
+ }
+
+ rootBranches := strings.Split(root, ",")
+
+ return containsString(rootBranches, branch)
+}
+
func (s *Server) detectPoolName(snapshotID string) (string, error) {
const snapshotParts = 2
@@ -438,9 +516,9 @@ func (s *Server) createSnapshotClone(w http.ResponseWriter, r *http.Request) {
return
}
- cloneName := clone.ID
+ fullClonePath := path.Join(branching.BranchDir, clone.Branch, clone.ID, branching.RevisionSegment(branching.DefaultRevision))
- snapshotID, err := fsm.CreateSnapshot(cloneName, time.Now().Format(util.DataStateAtFormat))
+ snapshotID, err := fsm.CreateSnapshot(fullClonePath, time.Now().Format(util.DataStateAtFormat))
if err != nil {
api.SendBadRequestError(w, r, fmt.Sprintf("failed to create a snapshot: %s", err.Error()))
return
diff --git a/engine/pkg/client/dblabapi/branch.go b/engine/pkg/client/dblabapi/branch.go
index b0505b6d..259e7278 100644
--- a/engine/pkg/client/dblabapi/branch.go
+++ b/engine/pkg/client/dblabapi/branch.go
@@ -10,6 +10,7 @@ import (
"encoding/json"
"fmt"
"net/http"
+ "slices"
"sort"
"gitlab.com/postgres-ai/database-lab/v3/pkg/client/dblabapi/types"
@@ -44,6 +45,7 @@ func (c *Client) ListBranches(ctx context.Context) ([]string, error) {
listBranches = append(listBranches, branchView.Name)
}
+ listBranches = slices.Compact(listBranches)
sort.Strings(listBranches)
return listBranches, nil
diff --git a/engine/pkg/models/branch.go b/engine/pkg/models/branch.go
index e29f3cc7..dcdf4203 100644
--- a/engine/pkg/models/branch.go
+++ b/engine/pkg/models/branch.go
@@ -35,6 +35,7 @@ type SnapshotDetails struct {
// BranchView describes branch view.
type BranchView struct {
Name string `json:"name"`
+ BaseDataset string `json:"baseDataset"`
Parent string `json:"parent"`
DataStateAt string `json:"dataStateAt"`
SnapshotID string `json:"snapshotID"`
@@ -45,5 +46,6 @@ type BranchView struct {
// BranchEntity defines a branch-snapshot pair.
type BranchEntity struct {
Name string
+ Dataset string
SnapshotID string
}
diff --git a/engine/pkg/models/clone.go b/engine/pkg/models/clone.go
index b7300175..da6e4d1c 100644
--- a/engine/pkg/models/clone.go
+++ b/engine/pkg/models/clone.go
@@ -6,17 +6,16 @@ package models
// Clone defines a clone model.
type Clone struct {
- ID string `json:"id"`
- Snapshot *Snapshot `json:"snapshot"`
- Branch string `json:"branch"`
- Revision int `json:"revision"`
- HasDependent bool `json:"hasDependent"`
- Protected bool `json:"protected"`
- DeleteAt *LocalTime `json:"deleteAt"`
- CreatedAt *LocalTime `json:"createdAt"`
- Status Status `json:"status"`
- DB Database `json:"db"`
- Metadata CloneMetadata `json:"metadata"`
+ ID string `json:"id"`
+ Snapshot *Snapshot `json:"snapshot"`
+ Branch string `json:"branch"`
+ Revision int `json:"revision"`
+ Protected bool `json:"protected"`
+ DeleteAt *LocalTime `json:"deleteAt"`
+ CreatedAt *LocalTime `json:"createdAt"`
+ Status Status `json:"status"`
+ DB Database `json:"db"`
+ Metadata CloneMetadata `json:"metadata"`
}
// CloneMetadata contains fields describing a clone model.
diff --git a/engine/pkg/util/branching/branching.go b/engine/pkg/util/branching/branching.go
index 75053856..3439dbdb 100644
--- a/engine/pkg/util/branching/branching.go
+++ b/engine/pkg/util/branching/branching.go
@@ -8,6 +8,7 @@ package branching
import (
"fmt"
"path"
+ "regexp"
"strings"
)
@@ -20,8 +21,16 @@ const (
// BranchDir defines branch directory in the pool.
BranchDir = "branch"
+
+ // MinDatasetNumber is 2 because:
+ // - test_dblab_pool/branch/001-branch/clone001 - root
+ // - test_dblab_pool/branch/001-branch/clone001/r0 - revision
+ MinDatasetNumber = 2
)
+// RevisionPattern creates a regex pattern to match dataset revision.
+var RevisionPattern = regexp.MustCompile(`/r\d+$`)
+
// BranchName returns a full branch name in the data pool.
func BranchName(poolName, branchName string) string {
return path.Join(poolName, BranchDir, branchName)
@@ -108,3 +117,15 @@ func ParseBranchNameFromSnapshot(snapshot, poolName string) string {
return branch
}
+
+// ParseBaseDatasetFromSnapshot parses base dataset from the snapshot ID.
+func ParseBaseDatasetFromSnapshot(snapshot string) string {
+ fullDataset, _, found := strings.Cut(snapshot, "@")
+ if !found {
+ return ""
+ }
+
+ dataset, _, _ := strings.Cut(fullDataset, "/"+BranchDir+"/")
+
+ return dataset
+}
diff --git a/engine/pkg/util/networks/networks.go b/engine/pkg/util/networks/networks.go
index 311db071..400052ab 100644
--- a/engine/pkg/util/networks/networks.go
+++ b/engine/pkg/util/networks/networks.go
@@ -9,7 +9,6 @@ import (
"context"
"fmt"
- "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/client"
@@ -33,7 +32,7 @@ func Setup(ctx context.Context, dockerCLI *client.Client, instanceID, containerN
log.Dbg("Discovering internal network:", networkName)
- networkResource, err := dockerCLI.NetworkInspect(ctx, networkName, types.NetworkInspectOptions{})
+ networkResource, err := dockerCLI.NetworkInspect(ctx, networkName, network.InspectOptions{})
if err == nil {
if !hasContainerConnected(networkResource, containerName) {
if err := dockerCLI.NetworkConnect(ctx, networkResource.ID, containerName, &network.EndpointSettings{}); err != nil {
@@ -49,15 +48,14 @@ func Setup(ctx context.Context, dockerCLI *client.Client, instanceID, containerN
log.Dbg("Internal network not found:", err.Error())
log.Dbg("Creating a new internal network:", networkName)
- internalNetwork, err := dockerCLI.NetworkCreate(ctx, networkName, types.NetworkCreate{
+ internalNetwork, err := dockerCLI.NetworkCreate(ctx, networkName, network.CreateOptions{
Labels: map[string]string{
"instance": instanceID,
"app": DLEApp,
"type": InternalType,
},
- Attachable: true,
- Internal: true,
- CheckDuplicate: true,
+ Attachable: true,
+ Internal: true,
})
if err != nil {
return "", err
@@ -83,7 +81,7 @@ func Stop(dockerCLI *client.Client, internalNetworkID, containerName string) {
log.Dbg("DLE container has been disconnected from the internal network:", containerName)
- networkInspect, err := dockerCLI.NetworkInspect(context.Background(), internalNetworkID, types.NetworkInspectOptions{})
+ networkInspect, err := dockerCLI.NetworkInspect(context.Background(), internalNetworkID, network.InspectOptions{})
if err != nil {
log.Errf(err.Error())
return
@@ -107,7 +105,7 @@ func Connect(ctx context.Context, dockerCLI *client.Client, instanceID, containe
log.Dbg("Discovering internal network:", networkName)
- networkResource, err := dockerCLI.NetworkInspect(ctx, networkName, types.NetworkInspectOptions{})
+ networkResource, err := dockerCLI.NetworkInspect(ctx, networkName, network.InspectOptions{})
if err != nil {
return fmt.Errorf("internal network not found: %w", err)
}
@@ -131,7 +129,7 @@ func Reconnect(ctx context.Context, dockerCLI *client.Client, instanceID, contai
log.Dbg("Discovering internal network:", networkName)
- networkResource, err := dockerCLI.NetworkInspect(ctx, networkName, types.NetworkInspectOptions{})
+ networkResource, err := dockerCLI.NetworkInspect(ctx, networkName, network.InspectOptions{})
if err != nil {
return fmt.Errorf("internal network not found: %w", err)
}
@@ -153,7 +151,7 @@ func Reconnect(ctx context.Context, dockerCLI *client.Client, instanceID, contai
return nil
}
-func hasContainerConnected(networkResource types.NetworkResource, containerID string) bool {
+func hasContainerConnected(networkResource network.Inspect, containerID string) bool {
for _, container := range networkResource.Containers {
if container.Name == containerID {
return true
diff --git a/engine/pkg/util/networks/networks_test.go b/engine/pkg/util/networks/networks_test.go
index 8b8393fb..5281845b 100644
--- a/engine/pkg/util/networks/networks_test.go
+++ b/engine/pkg/util/networks/networks_test.go
@@ -7,7 +7,7 @@ package networks
import (
"testing"
- "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/network"
"github.com/stretchr/testify/assert"
)
@@ -21,8 +21,8 @@ func TestInternalNetworks(t *testing.T) {
func TestIfContainerConnected(t *testing.T) {
t.Run("test if container connected", func(t *testing.T) {
- resource := types.NetworkResource{
- Containers: map[string]types.EndpointResource{
+ resource := network.Inspect{
+ Containers: map[string]network.EndpointResource{
"testID": {Name: "test_server"},
},
}
diff --git a/engine/scripts/cli_install.sh b/engine/scripts/cli_install.sh
index ee46abfb..8dbda161 100644
--- a/engine/scripts/cli_install.sh
+++ b/engine/scripts/cli_install.sh
@@ -31,7 +31,7 @@ esac
arch=$(uname -m)
case "$arch" in
x86_64*) arch="amd64" ;;
- arm64*) arch="arm64" ;;
+ arm64*|aarch64*) arch="arm64" ;;
*) echo "Unsupported architecture: $arch"; exit 1 ;;
esac
diff --git a/engine/test/1.synthetic.sh b/engine/test/1.synthetic.sh
index 7e49636a..2d7ccc4f 100644
--- a/engine/test/1.synthetic.sh
+++ b/engine/test/1.synthetic.sh
@@ -263,7 +263,7 @@ dblab clone create \
--branch 001-branch \
--id branchclone002 || (echo "Failed to create a clone on branch" && exit 1)
-dblab commit --clone-id branchclone002 -m branchclone002 || (echo "Failed to create a snapshot" && exit 1)
+dblab snapshot create --clone-id branchclone002 --message branchclone002 || (echo "Failed to create a snapshot" && exit 1)
dblab log 001-branch || (echo "Failed to show branch history" && exit 1)
diff --git a/engine/test/2.logical_generic.sh b/engine/test/2.logical_generic.sh
index 93fdb268..fb21a94b 100644
--- a/engine/test/2.logical_generic.sh
+++ b/engine/test/2.logical_generic.sh
@@ -19,6 +19,10 @@ export DLE_SERVER_PORT=${DLE_SERVER_PORT:-12345}
export DLE_PORT_POOL_FROM=${DLE_PORT_POOL_FROM:-9000}
export DLE_PORT_POOL_TO=${DLE_PORT_POOL_TO:-9099}
+if [ "${POSTGRES_VERSION}" = "18" ]; then
+ EXTENDED_IMAGE_TAG=""
+fi
+
DIR=${0%/*}
if [[ "${SOURCE_HOST}" = "172.17.0.1" ]]; then
@@ -103,7 +107,7 @@ yq eval -i '
.provision.portPool.to = env(DLE_PORT_POOL_TO) |
.retrieval.spec.logicalDump.options.dumpLocation = env(DLE_TEST_MOUNT_DIR) + "/" + env(DLE_TEST_POOL_NAME) + "/dump" |
.retrieval.spec.logicalRestore.options.dumpLocation = env(DLE_TEST_MOUNT_DIR) + "/" + env(DLE_TEST_POOL_NAME) + "/dump" |
- .databaseContainer.dockerImage = "registry.gitlab.com/postgres-ai/custom-images/extended-postgres:" + strenv(POSTGRES_VERSION) + env(EXTENDED_IMAGE_TAG)
+ .databaseContainer.dockerImage = "registry.gitlab.com/postgres-ai/custom-images/extended-postgres:" + strenv(POSTGRES_VERSION) + strenv(EXTENDED_IMAGE_TAG)
' "${configDir}/server.yml"
SHARED_PRELOAD_LIBRARIES="pg_stat_statements, auto_explain, pgaudit, logerrors, pg_stat_kcache"
diff --git a/engine/test/4.physical_basebackup.sh b/engine/test/4.physical_basebackup.sh
index eb562197..d7d1e001 100644
--- a/engine/test/4.physical_basebackup.sh
+++ b/engine/test/4.physical_basebackup.sh
@@ -18,6 +18,10 @@ export DLE_SERVER_PORT=${DLE_SERVER_PORT:-12345}
export DLE_PORT_POOL_FROM=${DLE_PORT_POOL_FROM:-9000}
export DLE_PORT_POOL_TO=${DLE_PORT_POOL_TO:-9099}
+if [ "${POSTGRES_VERSION}" = "18" ]; then
+ EXTENDED_IMAGE_TAG=""
+fi
+
DIR=${0%/*}
if [[ "${SOURCE_HOST}" = "172.17.0.1" ]]; then
@@ -115,7 +119,7 @@ yq eval -i '
.poolManager.mountDir = env(DLE_TEST_MOUNT_DIR) |
.provision.portPool.from = env(DLE_PORT_POOL_FROM) |
.provision.portPool.to = env(DLE_PORT_POOL_TO) |
- .databaseContainer.dockerImage = "registry.gitlab.com/postgres-ai/custom-images/extended-postgres:" + strenv(POSTGRES_VERSION) + env(EXTENDED_IMAGE_TAG) |
+ .databaseContainer.dockerImage = "registry.gitlab.com/postgres-ai/custom-images/extended-postgres:" + strenv(POSTGRES_VERSION) + strenv(EXTENDED_IMAGE_TAG) |
.retrieval.spec.physicalRestore.options.envs.PGUSER = strenv(SOURCE_USERNAME) |
.retrieval.spec.physicalRestore.options.envs.PGPASSWORD = strenv(SOURCE_PASSWORD) |
.retrieval.spec.physicalRestore.options.envs.PGHOST = strenv(SOURCE_HOST) |
diff --git a/engine/test/_cleanup.sh b/engine/test/_cleanup.sh
index 6e9ccca6..de5755a0 100644
--- a/engine/test/_cleanup.sh
+++ b/engine/test/_cleanup.sh
@@ -3,7 +3,7 @@ set -euxo pipefail
DLE_TEST_MOUNT_DIR="/var/lib/test/dblab_mount"
DLE_TEST_POOL_NAME="test_dblab_pool"
-TMP_DATA_DIR="/tmp/dle_test/logical_generic"
+TMP_DATA_DIR="/tmp/dle_test"
ZFS_FILE="$(pwd)/zfs_file"
# Stop and remove test Docker containers
diff --git a/ui/package.json b/ui/package.json
index 63a3af14..29908896 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -48,7 +48,29 @@
"elliptic@>=4.0.0 <=6.5.6": ">=6.5.7",
"elliptic@>=2.0.0 <=6.5.6": ">=6.5.7",
"elliptic@>=5.2.1 <=6.5.6": ">=6.5.7",
- "dompurify@<2.5.4": ">=2.5.4"
+ "dompurify@<2.5.4": ">=2.5.4",
+ "http-proxy-middleware@<2.0.7": ">=2.0.7",
+ "nanoid@<3.3.8": "3.3.8",
+ "elliptic@<=6.6.0": ">=6.6.1",
+ "cookie@<0.7.0": ">=0.7.0",
+ "@babel/runtime-corejs3@<7.26.10": ">=7.26.10",
+ "@babel/runtime@<7.26.10": ">=7.26.10",
+ "@babel/helpers@<7.26.10": ">=7.26.10",
+ "http-proxy-middleware@>=1.3.0 <2.0.9": ">=2.0.9",
+ "http-proxy-middleware@>=1.3.0 <2.0.8": ">=2.0.8",
+ "cross-spawn@>=7.0.0 <7.0.5": ">=7.0.5",
+ "path-to-regexp@<0.1.12": ">=0.1.12",
+ "brace-expansion@>=1.0.0 <=1.1.11": "1.1.12",
+ "brace-expansion@>=2.0.0 <=2.0.1": "2.0.2",
+ "brace-expansion@>2.0.2": "2.0.2",
+ "pbkdf2@<=3.1.2": ">=3.1.3",
+ "pbkdf2@>=3.0.10 <=3.1.2": ">=3.1.3",
+ "elliptic@<6.6.0": ">=6.6.0",
+ "prismjs@<1.30.0": ">=1.30.0",
+ "form-data@>=3.0.0 <3.0.4": ">=3.0.4",
+ "form-data@<2.5.4": ">=2.5.4",
+ "on-headers@<1.1.0": ">=1.1.0",
+ "tmp@<=0.2.3": ">=0.2.4"
}
}
}
diff --git a/ui/packages/ce/package.json b/ui/packages/ce/package.json
index 55e54843..00d73fec 100644
--- a/ui/packages/ce/package.json
+++ b/ui/packages/ce/package.json
@@ -1,6 +1,6 @@
{
"name": "@postgres.ai/ce",
- "version": "4.0.0",
+ "version": "4.0.2",
"private": true,
"dependencies": {
"@craco/craco": "^6.4.3",
@@ -26,7 +26,7 @@
"copy-to-clipboard": "^3.3.1",
"create-file-webpack": "^1.0.2",
"crypto-browserify": "^3.12.0",
- "cypress": "^12.15.0",
+ "cypress": "^14.5.4",
"date-fns": "^2.22.1",
"eslint-plugin-cypress": "^2.13.3",
"formik": "^2.2.9",
diff --git a/ui/packages/ce/src/api/snapshots/getSnapshots.ts b/ui/packages/ce/src/api/snapshots/getSnapshots.ts
index b26788eb..16af68a8 100644
--- a/ui/packages/ce/src/api/snapshots/getSnapshots.ts
+++ b/ui/packages/ce/src/api/snapshots/getSnapshots.ts
@@ -13,7 +13,14 @@ import {
import { request } from 'helpers/request'
export const getSnapshots: GetSnapshots = async (req) => {
- const url = `/snapshots${req.branchName ? `?branch=${req.branchName}` : ''}`;
+ const params = new URLSearchParams()
+ if (req.branchName) {
+ params.append('branch', req.branchName)
+ }
+ if (req.dataset) {
+ params.append('dataset', req.dataset)
+ }
+ const url = `/snapshots${params.toString() ? `?${params.toString()}` : ''}`;
const response = await request(url);
return {
diff --git a/ui/packages/shared/.gitlab-ci.yml b/ui/packages/shared/.gitlab-ci.yml
index 15baf4c9..440fa3a5 100644
--- a/ui/packages/shared/.gitlab-ci.yml
+++ b/ui/packages/shared/.gitlab-ci.yml
@@ -69,7 +69,7 @@ publish-shared-release:
- export VERSION=${CI_COMMIT_TAG#"v"}
# Build and pack
- - npm version "$VERSION" --no-git-tag-version
+ - npm version "$VERSION" --no-git-tag-version --allow-same-version
- pnpm run pack
# Publish
diff --git a/ui/packages/shared/components/ResetCloneModal/index.tsx b/ui/packages/shared/components/ResetCloneModal/index.tsx
index 4b278137..744f5ace 100644
--- a/ui/packages/shared/components/ResetCloneModal/index.tsx
+++ b/ui/packages/shared/components/ResetCloneModal/index.tsx
@@ -7,8 +7,6 @@
import { useEffect, useState } from 'react'
import { makeStyles } from '@material-ui/core'
-import { formatDistanceToNowStrict } from 'date-fns'
-
import { Clone } from '@postgres.ai/shared/types/api/entities/clone'
import { Snapshot } from '@postgres.ai/shared/types/api/entities/snapshot'
import { Text } from '@postgres.ai/shared/components/Text'
@@ -18,7 +16,7 @@ import { ImportantText } from '@postgres.ai/shared/components/ImportantText'
import { Spinner } from '@postgres.ai/shared/components/Spinner'
import { SimpleModalControls } from '@postgres.ai/shared/components/SimpleModalControls'
import { compareSnapshotsDesc } from '@postgres.ai/shared/utils/snapshot'
-import { isValidDate } from '@postgres.ai/shared/utils/date'
+import { formatDateWithDistance } from '@postgres.ai/shared/utils/date'
type Props = {
isOpen: boolean
@@ -111,12 +109,7 @@ export const ResetCloneModal = (props: Props) => {
value: snapshot.id,
children: (
<>
- {snapshot.dataStateAt} (
- {isValidDate(snapshot.dataStateAtDate) &&
- formatDistanceToNowStrict(snapshot.dataStateAtDate, {
- addSuffix: true,
- })}
- )
+ {formatDateWithDistance(snapshot.dataStateAt, snapshot.dataStateAtDate)}
{isLatest && (
Latest
)}
diff --git a/ui/packages/shared/package.json b/ui/packages/shared/package.json
index a5fd0980..04628f42 100644
--- a/ui/packages/shared/package.json
+++ b/ui/packages/shared/package.json
@@ -1,6 +1,6 @@
{
"name": "@postgres.ai/shared",
- "version": "4.0.0",
+ "version": "4.0.2",
"scripts": {
"build": "tsc -p tsconfig.build.json && node scripts/copy-assets.js",
"pack": "node scripts/pack.js"
@@ -50,6 +50,6 @@
"react": "^17.0.0 || ^18.0.0"
},
"devDependencies": {
- "glob": "^11.0.2"
+ "glob": "^11.1.0"
}
}
diff --git a/ui/packages/shared/pages/Branches/components/BranchesTable/index.tsx b/ui/packages/shared/pages/Branches/components/BranchesTable/index.tsx
index a8406df2..c67c88db 100644
--- a/ui/packages/shared/pages/Branches/components/BranchesTable/index.tsx
+++ b/ui/packages/shared/pages/Branches/components/BranchesTable/index.tsx
@@ -10,9 +10,7 @@ import { useEffect, useState } from 'react'
import copy from 'copy-to-clipboard'
import { makeStyles } from '@material-ui/core'
import { useHistory } from 'react-router-dom'
-import { formatDistanceToNowStrict } from 'date-fns'
-
-import { isValidDate } from '@postgres.ai/shared/utils/date'
+import { formatDateWithDistance } from '@postgres.ai/shared/utils/date'
import { ArrowDropDownIcon } from '@postgres.ai/shared/icons/ArrowDropDown'
import { Branch } from '@postgres.ai/shared/types/api/endpoints/getBranches'
import { HorizontalScrollContainer } from '@postgres.ai/shared/components/HorizontalScrollContainer'
@@ -168,13 +166,7 @@ export const BranchesTable = ({
{branch.name}{branch.parent}
- {branch.dataStateAt} (
- {isValidDate(new Date(branch.dataStateAt))
- ? formatDistanceToNowStrict(new Date(branch.dataStateAt), {
- addSuffix: true,
- })
- : '-'}
- )
+ {formatDateWithDistance(branch.dataStateAt, new Date(branch.dataStateAt))}
{branch.snapshotID}{branch.numSnapshots}
diff --git a/ui/packages/shared/pages/CreateBranch/index.tsx b/ui/packages/shared/pages/CreateBranch/index.tsx
index 0ae11354..d828d1d9 100644
--- a/ui/packages/shared/pages/CreateBranch/index.tsx
+++ b/ui/packages/shared/pages/CreateBranch/index.tsx
@@ -107,6 +107,7 @@ export const CreateBranchPage = observer(
const classes = useStyles()
const history = useHistory()
const [branchSnapshots, setBranchSnapshots] = useState([])
+ const [selectedBranchKey, setSelectedBranchKey] = useState('main|')
const {
load,
@@ -131,8 +132,8 @@ export const CreateBranchPage = observer(
})
}
- const fetchSnapshots = async (branchName: string) => {
- await getSnapshots(instanceId, branchName).then((response) => {
+ const fetchSnapshots = async (branchName: string, dataset?: string) => {
+ await getSnapshots(instanceId, branchName, dataset).then((response) => {
if (response) {
setBranchSnapshots(response)
formik.setFieldValue('snapshotID', response[0]?.id)
@@ -143,17 +144,28 @@ export const CreateBranchPage = observer(
const handleParentBranchChange = async (
e: React.ChangeEvent,
) => {
- const branchName = e.target.value
+ const compositeKey = e.target.value
+ const [branchName, dataset] = compositeKey.split('|')
+
+ setSelectedBranchKey(compositeKey)
formik.setFieldValue('baseBranch', branchName)
- await fetchSnapshots(branchName)
+ await fetchSnapshots(branchName, dataset)
}
const [{ formik }] = useForm(handleSubmit)
- useEffect(() => {
- load(instanceId)
- fetchSnapshots(formik.values.baseBranch)
- }, [formik.values.baseBranch])
+ useEffect(() => {
+ load(instanceId);
+ }, [instanceId]);
+
+ useEffect(() => {
+ if (!branchesList?.length) return;
+ const selected = branchesList.find(b => b.name === formik.values.baseBranch);
+ if (!selected) return;
+ const compositeKey = `${selected.name}|${selected.baseDataset || ''}`;
+ setSelectedBranchKey(compositeKey);
+ fetchSnapshots(selected.name, selected.baseDataset);
+ }, [branchesList]);
if (isBranchesLoading) {
return
@@ -207,16 +219,20 @@ export const CreateBranchPage = observer(