From ac6e6b8cb8463de8fee7535d0d9cd5280ee9edd8 Mon Sep 17 00:00:00 2001 From: Lokesh Mandvekar Date: Wed, 4 Mar 2026 15:57:11 +0530 Subject: [PATCH 1/6] vendor update without CNI Update download.FromURL call for new signature The download.FromURL function in container-libs/common now requires a context.Context and download.Options parameter. rootlessport: clarify RootlessCNI comment Update the comment for the RootlessCNI conditional to clarify that the flag is for rootless bridge networking, not CNI specifically. The bool is set when netStatus != nil in slirp4netns and will be removed when slirp4netns and rootlessport are fully dropped. Signed-off-by: Lokesh Mandvekar --- cmd/rootlessport/main.go | 3 +- go.mod | 34 +- go.sum | 58 +- test/buildah-bud/apply-podman-deltas | 4 +- test/buildah-bud/buildah-tests.diff | 41 +- vendor/cyphar.com/go-pathrs/.golangci.yml | 2 +- vendor/cyphar.com/go-pathrs/doc.go | 2 +- vendor/cyphar.com/go-pathrs/handle_linux.go | 10 +- .../go-pathrs/internal/fdutils/fd_linux.go | 2 +- .../internal/libpathrs/error_unix.go | 2 +- .../internal/libpathrs/libpathrs_linux.go | 6 +- .../go-pathrs/procfs/procfs_linux.go | 15 +- vendor/cyphar.com/go-pathrs/root_linux.go | 30 +- vendor/cyphar.com/go-pathrs/utils_linux.go | 2 +- .../containernetworking/cni/LICENSE | 202 ---- .../containernetworking/cni/libcni/api.go | 900 ------------------ .../containernetworking/cni/libcni/conf.go | 445 --------- .../cni/pkg/invoke/args.go | 128 --- .../cni/pkg/invoke/delegate.go | 89 -- .../cni/pkg/invoke/exec.go | 187 ---- .../cni/pkg/invoke/find.go | 48 - .../cni/pkg/invoke/os_unix.go | 21 - .../cni/pkg/invoke/os_windows.go | 18 - .../cni/pkg/invoke/raw_exec.go | 88 -- .../cni/pkg/types/020/types.go | 189 ---- .../cni/pkg/types/040/types.go | 306 ------ .../cni/pkg/types/100/types.go | 352 ------- .../containernetworking/cni/pkg/types/args.go | 122 --- .../cni/pkg/types/create/create.go | 59 -- .../cni/pkg/types/internal/convert.go | 92 -- .../cni/pkg/types/internal/create.go | 66 -- .../cni/pkg/types/types.go | 325 ------- .../cni/pkg/utils/utils.go | 82 -- .../cni/pkg/version/conf.go | 26 - .../cni/pkg/version/plugin.go | 168 ---- .../cni/pkg/version/reconcile.go | 49 - .../cni/pkg/version/version.go | 90 -- .../github.com/containers/buildah/.cirrus.yml | 26 +- vendor/github.com/containers/buildah/Makefile | 13 +- .../github.com/containers/buildah/buildah.go | 42 +- .../containers/buildah/chroot/run_common.go | 8 - .../github.com/containers/buildah/config.go | 5 +- .../containers/buildah/define/build.go | 11 +- .../containers/buildah/define/namespace.go | 4 +- .../containers/buildah/define/types.go | 15 + vendor/github.com/containers/buildah/image.go | 140 ++- .../buildah/imagebuildah/executor.go | 57 +- .../buildah/imagebuildah/stage_executor.go | 12 +- .../github.com/containers/buildah/import.go | 2 +- .../github.com/containers/buildah/install.md | 32 - .../internal/mkcw/embed/entrypoint_amd64.gz | Bin 362 -> 378756 bytes vendor/github.com/containers/buildah/new.go | 7 +- .../containers/buildah/pkg/cli/build.go | 4 +- .../containers/buildah/pkg/cli/common.go | 14 +- .../containers/buildah/pkg/overlay/overlay.go | 12 +- vendor/github.com/containers/buildah/pull.go | 8 - vendor/github.com/containers/buildah/run.go | 12 +- .../containers/buildah/run_common.go | 178 ++-- .../containers/buildah/run_freebsd.go | 4 - .../containers/buildah/run_linux.go | 4 - .../github.com/containers/buildah/run_unix.go | 2 +- .../containers/buildah/run_unsupported.go | 2 +- vendor/github.com/containers/buildah/util.go | 8 +- .../github.com/coreos/go-oidc/v3/oidc/oidc.go | 4 +- .../docker/docker/api/types/blkiodev/blkio.go | 23 - .../docker/api/types/common/id_response.go | 13 - .../docker/api/types/container/change_type.go | 15 - .../api/types/container/change_types.go | 23 - .../docker/api/types/container/commit.go | 7 - .../docker/api/types/container/config.go | 73 -- .../docker/api/types/container/container.go | 188 ---- .../api/types/container/create_request.go | 13 - .../api/types/container/create_response.go | 19 - .../docker/api/types/container/disk_usage.go | 10 - .../docker/api/types/container/errors.go | 9 - .../docker/docker/api/types/container/exec.go | 53 -- .../api/types/container/filesystem_change.go | 19 - .../docker/api/types/container/health.go | 50 - .../docker/api/types/container/hostconfig.go | 506 ---------- .../api/types/container/hostconfig_unix.go | 45 - .../api/types/container/hostconfig_windows.go | 47 - .../api/types/container/network_settings.go | 85 -- .../docker/api/types/container/options.go | 67 -- .../docker/docker/api/types/container/port.go | 23 - .../docker/api/types/container/state.go | 64 -- .../docker/api/types/container/stats.go | 177 ---- .../api/types/container/top_response.go | 18 - .../api/types/container/update_response.go | 14 - .../api/types/container/wait_exit_error.go | 12 - .../api/types/container/wait_response.go | 18 - .../api/types/container/waitcondition.go | 22 - .../docker/docker/api/types/filters/errors.go | 24 - .../api/types/filters/filters_deprecated.go | 61 -- .../docker/docker/api/types/filters/parse.go | 302 ------ .../docker/docker/api/types/mount/mount.go | 157 --- .../api/types/network/create_response.go | 19 - .../docker/api/types/network/endpoint.go | 151 --- .../docker/docker/api/types/network/ipam.go | 173 ---- .../docker/api/types/network/network.go | 168 ---- .../docker/api/types/registry/authconfig.go | 112 --- .../docker/api/types/registry/authenticate.go | 21 - .../docker/api/types/registry/registry.go | 122 --- .../docker/api/types/registry/search.go | 48 - .../docker/api/types/storage/driver_data.go | 23 - .../docker/api/types/strslice/strslice.go | 30 - .../docker/docker/api/types/swarm/common.go | 48 - .../docker/docker/api/types/swarm/config.go | 62 -- .../docker/api/types/swarm/container.go | 119 --- .../docker/docker/api/types/swarm/network.go | 121 --- .../docker/docker/api/types/swarm/node.go | 151 --- .../docker/docker/api/types/swarm/runtime.go | 37 - .../docker/api/types/swarm/runtime/runtime.go | 27 - .../docker/docker/api/types/swarm/secret.go | 66 -- .../docker/docker/api/types/swarm/service.go | 272 ------ .../types/swarm/service_create_response.go | 20 - .../types/swarm/service_update_response.go | 12 - .../docker/docker/api/types/swarm/swarm.go | 244 ----- .../docker/docker/api/types/swarm/task.go | 230 ----- .../docker/api/types/versions/compare.go | 65 -- .../docker/pkg/homedir/homedir_linux.go | 105 -- .../docker/pkg/jsonmessage/jsonmessage.go | 314 ------ .../fsouza/go-dockerclient/client.go | 8 +- .../fsouza/go-dockerclient/container.go | 148 +-- .../go-dockerclient/container_update.go | 29 +- .../fsouza/go-dockerclient/distribution.go | 2 +- .../fsouza/go-dockerclient/image.go | 18 +- .../github.com/fsouza/go-dockerclient/misc.go | 45 +- .../fsouza/go-dockerclient/network.go | 2 + .../fsouza/go-dockerclient/swarm.go | 161 ---- .../fsouza/go-dockerclient/swarm_configs.go | 175 ---- .../fsouza/go-dockerclient/swarm_node.go | 134 --- .../fsouza/go-dockerclient/swarm_secrets.go | 175 ---- .../fsouza/go-dockerclient/swarm_service.go | 218 ----- .../fsouza/go-dockerclient/swarm_task.go | 72 -- .../github.com/fsouza/go-dockerclient/tar.go | 3 +- .../go-containerregistry/pkg/v1/config.go | 9 +- .../frontend/dockerfile/parser/directives.go | 34 +- .../frontend/dockerfile/parser/parser.go | 21 +- .../moby/buildkit/util/stack/stack.pb.go | 2 +- vendor/github.com/moby/go-archive/archive.go | 40 - .../moby/go-archive/xattr_supported_unix.go | 2 +- .../moby/api}/pkg/stdcopy/stdcopy.go | 106 +-- .../client/pkg/jsonmessage/jsonmessage.go | 245 +++++ .../{docker/docker => moby/moby/v2}/AUTHORS | 20 + .../{docker/docker => moby/moby/v2}/LICENSE | 0 .../{docker/docker => moby/moby/v2}/NOTICE | 0 .../moby/v2}/pkg/homedir/homedir.go | 0 .../moby/moby/v2/pkg/homedir/homedir_linux.go | 125 +++ .../moby/v2}/pkg/homedir/homedir_others.go | 5 + vendor/github.com/morikuni/aec/LICENSE | 21 - vendor/github.com/morikuni/aec/README.md | 178 ---- vendor/github.com/morikuni/aec/aec.go | 137 --- vendor/github.com/morikuni/aec/ansi.go | 59 -- vendor/github.com/morikuni/aec/builder.go | 388 -------- vendor/github.com/morikuni/aec/sample.gif | Bin 12548 -> 0 bytes vendor/github.com/morikuni/aec/sgr.go | 202 ---- .../runc/internal/linux/linux.go | 26 +- .../runc/libcontainer/devices/device_unix.go | 2 +- .../sigstore/pkg/cryptoutils/publickey.go | 26 + .../sigstore/sigstore/pkg/signature/signer.go | 3 - .../common/libnetwork/cni/README.md | 10 - .../common/libnetwork/cni/cni_conversion.go | 461 --------- .../common/libnetwork/cni/cni_exec.go | 122 --- .../common/libnetwork/cni/cni_types.go | 286 ------ .../common/libnetwork/cni/config.go | 246 ----- .../common/libnetwork/cni/config_freebsd.go | 16 - .../common/libnetwork/cni/config_linux.go | 19 - .../common/libnetwork/cni/network.go | 359 ------- .../go.podman.io/common/libnetwork/cni/run.go | 302 ------ .../common/libnetwork/cni/run_freebsd.go | 19 - .../common/libnetwork/cni/run_linux.go | 17 - .../internal/rootlessnetns/netns.go | 8 - .../internal/rootlessnetns/netns_freebsd.go | 2 +- .../internal/rootlessnetns/netns_linux.go | 69 +- .../common/libnetwork/netavark/config.go | 2 +- .../common/libnetwork/netavark/network.go | 4 +- .../common/libnetwork/network/interface.go | 84 +- .../libnetwork/network/interface_cni.go | 119 --- .../network/interface_cni_unsupported.go | 30 - .../libnetwork/network/interface_freebsd.go | 2 - .../libnetwork/network/interface_linux.go | 2 - .../common/libnetwork/pasta/pasta_linux.go | 4 +- .../libnetwork/slirp4netns/slirp4netns.go | 4 +- .../common/libnetwork/types/const.go | 5 +- .../go.podman.io/common/pkg/config/config.go | 5 +- .../common/pkg/config/containers.conf | 23 +- .../common/pkg/config/containers.conf-freebsd | 23 +- .../go.podman.io/common/pkg/config/default.go | 9 - .../common/pkg/netns/netns_linux.go | 217 ++++- vendor/golang.org/x/crypto/sha3/hashes.go | 95 -- .../golang.org/x/crypto/sha3/legacy_hash.go | 263 ----- .../x/crypto/sha3/legacy_keccakf.go | 416 -------- vendor/golang.org/x/crypto/sha3/shake.go | 119 --- vendor/modules.txt | 78 +- 194 files changed, 1377 insertions(+), 14710 deletions(-) delete mode 100644 vendor/github.com/containernetworking/cni/LICENSE delete mode 100644 vendor/github.com/containernetworking/cni/libcni/api.go delete mode 100644 vendor/github.com/containernetworking/cni/libcni/conf.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/invoke/args.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/invoke/exec.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/invoke/find.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/invoke/os_windows.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/types/020/types.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/types/040/types.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/types/100/types.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/types/args.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/types/create/create.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/types/internal/convert.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/types/internal/create.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/types/types.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/utils/utils.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/version/conf.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/version/plugin.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/version/reconcile.go delete mode 100644 vendor/github.com/containernetworking/cni/pkg/version/version.go delete mode 100644 vendor/github.com/docker/docker/api/types/blkiodev/blkio.go delete mode 100644 vendor/github.com/docker/docker/api/types/common/id_response.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/change_type.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/change_types.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/commit.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/config.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/container.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/create_request.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/create_response.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/disk_usage.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/errors.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/exec.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/filesystem_change.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/health.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/network_settings.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/options.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/port.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/state.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/stats.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/top_response.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/update_response.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/wait_exit_error.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/wait_response.go delete mode 100644 vendor/github.com/docker/docker/api/types/container/waitcondition.go delete mode 100644 vendor/github.com/docker/docker/api/types/filters/errors.go delete mode 100644 vendor/github.com/docker/docker/api/types/filters/filters_deprecated.go delete mode 100644 vendor/github.com/docker/docker/api/types/filters/parse.go delete mode 100644 vendor/github.com/docker/docker/api/types/mount/mount.go delete mode 100644 vendor/github.com/docker/docker/api/types/network/create_response.go delete mode 100644 vendor/github.com/docker/docker/api/types/network/endpoint.go delete mode 100644 vendor/github.com/docker/docker/api/types/network/ipam.go delete mode 100644 vendor/github.com/docker/docker/api/types/network/network.go delete mode 100644 vendor/github.com/docker/docker/api/types/registry/authconfig.go delete mode 100644 vendor/github.com/docker/docker/api/types/registry/authenticate.go delete mode 100644 vendor/github.com/docker/docker/api/types/registry/registry.go delete mode 100644 vendor/github.com/docker/docker/api/types/registry/search.go delete mode 100644 vendor/github.com/docker/docker/api/types/storage/driver_data.go delete mode 100644 vendor/github.com/docker/docker/api/types/strslice/strslice.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/common.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/config.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/container.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/network.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/node.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/runtime/runtime.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/secret.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/service.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/service_create_response.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/service_update_response.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/swarm.go delete mode 100644 vendor/github.com/docker/docker/api/types/swarm/task.go delete mode 100644 vendor/github.com/docker/docker/api/types/versions/compare.go delete mode 100644 vendor/github.com/docker/docker/pkg/homedir/homedir_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go delete mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm.go delete mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_configs.go delete mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_node.go delete mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go delete mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_service.go delete mode 100644 vendor/github.com/fsouza/go-dockerclient/swarm_task.go rename vendor/github.com/{docker/docker => moby/moby/api}/pkg/stdcopy/stdcopy.go (50%) create mode 100644 vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go rename vendor/github.com/{docker/docker => moby/moby/v2}/AUTHORS (99%) rename vendor/github.com/{docker/docker => moby/moby/v2}/LICENSE (100%) rename vendor/github.com/{docker/docker => moby/moby/v2}/NOTICE (100%) rename vendor/github.com/{docker/docker => moby/moby/v2}/pkg/homedir/homedir.go (100%) create mode 100644 vendor/github.com/moby/moby/v2/pkg/homedir/homedir_linux.go rename vendor/github.com/{docker/docker => moby/moby/v2}/pkg/homedir/homedir_others.go (84%) delete mode 100644 vendor/github.com/morikuni/aec/LICENSE delete mode 100644 vendor/github.com/morikuni/aec/README.md delete mode 100644 vendor/github.com/morikuni/aec/aec.go delete mode 100644 vendor/github.com/morikuni/aec/ansi.go delete mode 100644 vendor/github.com/morikuni/aec/builder.go delete mode 100644 vendor/github.com/morikuni/aec/sample.gif delete mode 100644 vendor/github.com/morikuni/aec/sgr.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/README.md delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/cni_conversion.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/cni_exec.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/cni_types.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/config.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/config_freebsd.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/config_linux.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/network.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/run.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/run_freebsd.go delete mode 100644 vendor/go.podman.io/common/libnetwork/cni/run_linux.go delete mode 100644 vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns.go delete mode 100644 vendor/go.podman.io/common/libnetwork/network/interface_cni.go delete mode 100644 vendor/go.podman.io/common/libnetwork/network/interface_cni_unsupported.go delete mode 100644 vendor/golang.org/x/crypto/sha3/hashes.go delete mode 100644 vendor/golang.org/x/crypto/sha3/legacy_hash.go delete mode 100644 vendor/golang.org/x/crypto/sha3/legacy_keccakf.go delete mode 100644 vendor/golang.org/x/crypto/sha3/shake.go diff --git a/cmd/rootlessport/main.go b/cmd/rootlessport/main.go index 107f5403e74..c1486d8402d 100644 --- a/cmd/rootlessport/main.go +++ b/cmd/rootlessport/main.go @@ -194,7 +194,8 @@ outer: return err } - // we only need to have a socket to reload ports when we run under rootless cni + // we only need to have a socket to reload ports when we are using + // rootless bridge networking (RootlessCNI is set when netStatus != nil) if cfg.RootlessCNI { socketfile := filepath.Join(socketDir, cfg.ContainerID) // make sure to remove the file if it exists to prevent EADDRINUSE diff --git a/go.mod b/go.mod index cffc27fd75e..08f2408fa16 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,13 @@ module github.com/containers/podman/v6 // Warning: if there is a "toolchain" directive anywhere in this file (and most of the // time there shouldn't be), its version must be an exact match to the "go" directive. -go 1.25.0 +go 1.25.5 require ( github.com/Microsoft/go-winio v0.6.2 github.com/blang/semver/v4 v4.0.0 github.com/checkpoint-restore/checkpointctl v1.5.0 github.com/checkpoint-restore/go-criu/v7 v7.2.0 - github.com/containernetworking/plugins v1.9.0 github.com/containers/buildah v1.42.1-0.20260216192603-e473f9d26ec6 github.com/containers/gvisor-tap-vsock v0.8.8 github.com/containers/libhvee v0.10.1-0.20250829163521-178d10e67860 @@ -65,9 +64,9 @@ require ( github.com/stretchr/testify v1.11.1 github.com/vbauerster/mpb/v8 v8.12.0 github.com/vishvananda/netlink v1.3.1 - go.podman.io/common v0.67.1-0.20260313003550-7415b6a27ee6 - go.podman.io/image/v5 v5.39.2-0.20260313003550-7415b6a27ee6 - go.podman.io/storage v1.62.1-0.20260313003550-7415b6a27ee6 + go.podman.io/common v0.67.1-0.20260316162257-e70c309aabae + go.podman.io/image/v5 v5.39.2-0.20260316162257-e70c309aabae + go.podman.io/storage v1.62.1-0.20260316162257-e70c309aabae golang.org/x/crypto v0.49.0 golang.org/x/net v0.51.0 golang.org/x/sync v0.20.0 @@ -82,7 +81,7 @@ require ( ) require ( - cyphar.com/go-pathrs v0.2.1 // indirect + cyphar.com/go-pathrs v0.2.4 // indirect dario.cat/mergo v1.0.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/BurntSushi/toml v1.6.0 // indirect @@ -99,23 +98,22 @@ require ( github.com/containerd/platforms v1.0.0-rc.2 // indirect github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect github.com/containerd/typeurl/v2 v2.2.3 // indirect - github.com/containernetworking/cni v1.3.0 // indirect + github.com/containernetworking/plugins v1.9.0 // indirect github.com/containers/common v0.64.2 // indirect github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect github.com/containers/luksy v0.0.0-20251208191447-ca096313c38f // indirect - github.com/coreos/go-oidc/v3 v3.16.0 // indirect + github.com/coreos/go-oidc/v3 v3.17.0 // indirect github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e // indirect github.com/disiqueira/gotree/v3 v3.0.2 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker v28.5.2+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.5 // indirect github.com/ebitengine/purego v0.10.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/fsouza/go-dockerclient v1.12.3 // indirect + github.com/fsouza/go-dockerclient v1.13.0 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -124,7 +122,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/go-containerregistry v0.20.6 // indirect + github.com/google/go-containerregistry v0.20.7 // indirect github.com/google/go-intervals v0.0.2 // indirect github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -139,16 +137,16 @@ require ( github.com/mdlayher/socket v0.5.1 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mistifyio/go-zfs/v4 v4.0.0 // indirect - github.com/moby/buildkit v0.26.3 // indirect - github.com/moby/go-archive v0.1.0 // indirect + github.com/moby/buildkit v0.28.0 // indirect + github.com/moby/go-archive v0.2.0 // indirect + github.com/moby/moby/v2 v2.0.0-beta.6 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/sequential v0.6.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect - github.com/morikuni/aec v1.0.0 // indirect - github.com/opencontainers/runc v1.4.0 // indirect + github.com/opencontainers/runc v1.4.1 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pkg/sftp v1.13.10 // indirect @@ -158,9 +156,9 @@ require ( github.com/proglottis/gpgme v0.1.6 // indirect github.com/seccomp/libseccomp-golang v0.11.1 // indirect github.com/secure-systems-lab/go-securesystemslib v0.10.0 // indirect - github.com/sigstore/fulcio v1.8.1 // indirect + github.com/sigstore/fulcio v1.8.5 // indirect github.com/sigstore/protobuf-specs v0.5.0 // indirect - github.com/sigstore/sigstore v1.9.6-0.20251111174640-d8ab8afb1326 // indirect + github.com/sigstore/sigstore v1.10.4 // indirect github.com/skeema/knownhosts v1.3.2 // indirect github.com/smallstep/pkcs7 v0.1.1 // indirect github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 // indirect @@ -190,3 +188,5 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect tags.cncf.io/container-device-interface/specs-go v1.1.0 // indirect ) + +replace github.com/containers/buildah => github.com/lsm5/buildah v0.0.0-20260317084505-caaea7f2d096 diff --git a/go.sum b/go.sum index 1a7a2915919..e143a8daf4e 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8= -cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= +cyphar.com/go-pathrs v0.2.4 h1:iD/mge36swa1UFKdINkr1Frkpp6wZsy3YYEildj9cLY= +cyphar.com/go-pathrs v0.2.4/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= 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= @@ -55,8 +55,6 @@ github.com/containernetworking/cni v1.3.0 h1:v6EpN8RznAZj9765HhXQrtXgX+ECGebEYEm github.com/containernetworking/cni v1.3.0/go.mod h1:Bs8glZjjFfGPHMw6hQu82RUgEPNGEaBb9KS5KtNMnJ4= github.com/containernetworking/plugins v1.9.0 h1:Mg3SXBdRGkdXyFC4lcwr6u2ZB2SDeL6LC3U+QrEANuQ= github.com/containernetworking/plugins v1.9.0/go.mod h1:JG3BxoJifxxHBhG3hFyxyhid7JgRVBu/wtooGEvWf1c= -github.com/containers/buildah v1.42.1-0.20260216192603-e473f9d26ec6 h1:j8qnAjmrLf6x47qChpQZla1JzdMZ2BEmhTFlE0e9EUU= -github.com/containers/buildah v1.42.1-0.20260216192603-e473f9d26ec6/go.mod h1:rnvz1cLM9/wTR4BYODd62GHIwTrWzQsn5J1+qEbjgJ8= github.com/containers/common v0.64.2 h1:1xepE7QwQggUXxmyQ1Dbh6Cn0yd7ktk14sN3McSWf5I= github.com/containers/common v0.64.2/go.mod h1:o29GfYy4tefUuShm8mOn2AiL5Mpzdio+viHI7n24KJ4= github.com/containers/gvisor-tap-vsock v0.8.8 h1:5FznbOYMIuaCv8B6zQ7M6wjqP63Lasy0A6GpViEnjTg= @@ -73,8 +71,8 @@ github.com/containers/psgo v1.10.0 h1:r9cEzAMVRtC0sw4ayIPjbd9EgF9pPaTCqKgDHhS0D/ github.com/containers/psgo v1.10.0/go.mod h1:e44fw+1A7eJH1y0eWAo3P7sjfftXDlfF4AY498h+svQ= github.com/containers/winquit v1.1.0 h1:jArun04BNDQvt2W0Y78kh9TazN2EIEMG5Im6/JY7+pE= github.com/containers/winquit v1.1.0/go.mod h1:PsPeZlnbkmGGIToMPHF1zhWjBUkd8aHjMOr/vFcPxw8= -github.com/coreos/go-oidc/v3 v3.16.0 h1:qRQUCFstKpXwmEjDQTIbyY/5jF00+asXzSkmkoa/mow= -github.com/coreos/go-oidc/v3 v3.16.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= +github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= +github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= @@ -104,8 +102,6 @@ github.com/docker/cli v29.3.0+incompatible h1:z3iWveU7h19Pqx7alZES8j+IeFQZ1lhTwb github.com/docker/cli v29.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= -github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY= github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= @@ -125,8 +121,8 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fsouza/go-dockerclient v1.12.3 h1:CEsX4/msyMEekHAR9Pf8XniZBtwGo0Kl+mLPQ/AnSys= -github.com/fsouza/go-dockerclient v1.12.3/go.mod h1:gl0t2KUfrsLbm4tw5/ySsJkkFpi7Fz9gXzY2BKLEvZA= +github.com/fsouza/go-dockerclient v1.13.0 h1:i6VWBKrFprrqDDK6rEYw0Zp5KsN+cVlqZ/ODaIX2erM= +github.com/fsouza/go-dockerclient v1.13.0/go.mod h1:slZeNd4OpH+YfOrTc4+fkjtq8fwKymehRReLvUVFfpI= github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= @@ -158,8 +154,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU= -github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y= +github.com/google/go-containerregistry v0.20.7 h1:24VGNpS0IwrOZ2ms2P1QE3Xa5X9p4phx0aUgzYzHW6I= +github.com/google/go-containerregistry v0.20.7/go.mod h1:Lx5LCZQjLH1QBaMPeGwsME9biPeo1lPx6lbGj/UmzgM= github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM= github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -223,6 +219,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/linuxkit/virtsock v0.0.0-20241009230534-cb6a20cc0422 h1:XvRuyDDRvi+UDxHN/M4MW4HxjmNVMmUKQj/+AbgsYgk= github.com/linuxkit/virtsock v0.0.0-20241009230534-cb6a20cc0422/go.mod h1:JLgfq4XMVbvfNlAXla/41lZnp21O72a/wWHGJefAvgQ= +github.com/lsm5/buildah v0.0.0-20260317084505-caaea7f2d096 h1:hYBxMWR8SeYIVIUm9zAfOQV2t7hWDKMO/ju0PP70YwY= +github.com/lsm5/buildah v0.0.0-20260317084505-caaea7f2d096/go.mod h1:kFd6qpK0J6WQXwEGR/NMNwnyHg0GtDJCtPny8rG4Ako= github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0= github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= @@ -251,16 +249,18 @@ github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mistifyio/go-zfs/v4 v4.0.0 h1:sU0+5dX45tdDK5xNZ3HBi95nxUc48FS92qbIZEvpAg4= github.com/mistifyio/go-zfs/v4 v4.0.0/go.mod h1:weotFtXTHvBwhr9Mv96KYnDkTPBOHFUbm9cBmQpesL0= -github.com/moby/buildkit v0.26.3 h1:D+ruZVAk/3ipRq5XRxBH9/DIFpRjSlTtMbghT5gQP9g= -github.com/moby/buildkit v0.26.3/go.mod h1:4T4wJzQS4kYWIfFRjsbJry4QoxDBjK+UGOEOs1izL7w= +github.com/moby/buildkit v0.28.0 h1:rKulfRRSduHJPNpLTk481fHElqN9tps0VUx8YV/5zsA= +github.com/moby/buildkit v0.28.0/go.mod h1:RCuOcj/bVsCriBG8NeFzRxjiCFQKnKP7KOVlNTS18t4= 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/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8= +github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU= github.com/moby/moby/api v1.54.0 h1:7kbUgyiKcoBhm0UrWbdrMs7RX8dnwzURKVbZGy2GnL0= github.com/moby/moby/api v1.54.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc= github.com/moby/moby/client v0.3.0 h1:UUGL5okry+Aomj3WhGt9Aigl3ZOxZGqR7XPo+RLPlKs= github.com/moby/moby/client v0.3.0/go.mod h1:HJgFbJRvogDQjbM8fqc1MCEm4mIAGMLjXbgwoZp6jCQ= +github.com/moby/moby/v2 v2.0.0-beta.6 h1:esIpPmQk4oZyPkbu+5hDAE+as2LEKaYxQcWSC5zUGiM= +github.com/moby/moby/v2 v2.0.0-beta.6/go.mod h1:nrC3bakOe44FcxsHAuvxsIHWtS4Vcf8Kn1j44kcZRLs= 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/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk= @@ -281,8 +281,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI= @@ -295,8 +293,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 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/opencontainers/runc v1.4.0 h1:FG1Hw0GBYPsNki+mBz1QOrSzbwbAcerhrAD2r097QCc= -github.com/opencontainers/runc v1.4.0/go.mod h1:sch3Bh3c1NlyAkALoAUz5Br9ubMLZzFcxuovZbnkErk= +github.com/opencontainers/runc v1.4.1 h1:eg1A930KKiZ3IShaYHPRiDi6uMrHMnd7OiElHBLgqfY= +github.com/opencontainers/runc v1.4.1/go.mod h1:ufk5PTTsy5pnGBAvTh50e+eqGk01pYH2YcVxh557Qlk= github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg= github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.9.1-0.20251205004911-5e639034dcdc h1:82NlZLiQEB6Wp+nmASMlkHsEXz3Q0pXJbK7QO6ck5lo= @@ -339,12 +337,12 @@ github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI= github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= -github.com/sigstore/fulcio v1.8.1 h1:PmoQv3XmhjR2BWFWw5LcMUXJPmhyizOIL7HeYnpio58= -github.com/sigstore/fulcio v1.8.1/go.mod h1:7tP3KW9eCGlPYRj5N4MSuUOat7CkeIHuXZ2jAUQ+Rwc= +github.com/sigstore/fulcio v1.8.5 h1:HYTD1/L5wlBp8JxsWxUf8hmfaNBBF/x3r3p5l6tZwbA= +github.com/sigstore/fulcio v1.8.5/go.mod h1:tSLYK3JsKvJpDW1BsIsVHZgHj+f8TjXARzqIUWSsSPQ= github.com/sigstore/protobuf-specs v0.5.0 h1:F8YTI65xOHw70NrvPwJ5PhAzsvTnuJMGLkA4FIkofAY= github.com/sigstore/protobuf-specs v0.5.0/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc= -github.com/sigstore/sigstore v1.9.6-0.20251111174640-d8ab8afb1326 h1:s39MsSDVn8LhePV5adidcOjjKHaplLxpHM1mvbC24l4= -github.com/sigstore/sigstore v1.9.6-0.20251111174640-d8ab8afb1326/go.mod h1:xSCb7eki7lCdi+mNh4I4MVpKPP2cWGtDYmSPPmX/K70= +github.com/sigstore/sigstore v1.10.4 h1:ytOmxMgLdcUed3w1SbbZOgcxqwMG61lh1TmZLN+WeZE= +github.com/sigstore/sigstore v1.10.4/go.mod h1:tDiyrdOref3q6qJxm2G+JHghqfmvifB7hw+EReAfnbI= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg= @@ -433,12 +431,12 @@ go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4A go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= -go.podman.io/common v0.67.1-0.20260313003550-7415b6a27ee6 h1:2W+x/bT6mWCYUhYnZqLjpaVwQ13qP2/ruXgGJwbP56k= -go.podman.io/common v0.67.1-0.20260313003550-7415b6a27ee6/go.mod h1:0SZygTu/+zU+jD4oLtamBoZXiGrD3uJdDhlgYWl9x3U= -go.podman.io/image/v5 v5.39.2-0.20260313003550-7415b6a27ee6 h1:GR9v4x4Er9blWVddAi8yETG6MA81leh/z/HP+HmVdfo= -go.podman.io/image/v5 v5.39.2-0.20260313003550-7415b6a27ee6/go.mod h1:P9wOtKQ6IMXhcrIp7LXGnluaHRgRZEK8Dyh1biyFpkg= -go.podman.io/storage v1.62.1-0.20260313003550-7415b6a27ee6 h1:jhj6/WSU9omBCMY3woPF8HL6c+LT8CXS3RV/TotHXIk= -go.podman.io/storage v1.62.1-0.20260313003550-7415b6a27ee6/go.mod h1:zkm6ScbnKEMuDwswj+IFjtjXbI8g/MFDdljd6R5mf6U= +go.podman.io/common v0.67.1-0.20260316162257-e70c309aabae h1:VoUmnazJGnPqWoGYF3YzRU0ZgA9DQ3qg1bYCqhkYUyg= +go.podman.io/common v0.67.1-0.20260316162257-e70c309aabae/go.mod h1:sugHfpSU9btZ6KRTruHrfbzTO8HbOCX9s++p7kmdbOQ= +go.podman.io/image/v5 v5.39.2-0.20260316162257-e70c309aabae h1:jBTnK7tFX0O7b5wuo2b+JunSLxJE0rSsTvhiTGtfNf8= +go.podman.io/image/v5 v5.39.2-0.20260316162257-e70c309aabae/go.mod h1:eSTQb66cEeMtWaj3y4mfDsMB7t068tG+UjbPLWj60ho= +go.podman.io/storage v1.62.1-0.20260316162257-e70c309aabae h1:2cNSnB3KSKTtmd+PBqAHsQmNjhOkmh2Ne0mhhMRrMRo= +go.podman.io/storage v1.62.1-0.20260316162257-e70c309aabae/go.mod h1:k8lWBDknm4IJEfY9Gy3P/wRFT8aWvtk+rPtD8FKxIBE= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas index dc80701bf9b..3595352987b 100755 --- a/test/buildah-bud/apply-podman-deltas +++ b/test/buildah-bud/apply-podman-deltas @@ -338,7 +338,9 @@ skip_if_remote "FIXME: 2025-04-01 git related errors returning wrong exit code" skip "process substitution with overlay context not supported" \ "build-with-timestamp-applies-to-oci-archive" \ "build-with-timestamp-applies-to-oci-archive-with-base" \ - "build-with-run-mount" + "build-with-run-mount" \ + "use-secret-to-env-variable" \ + "use-secret-to-env-variable-and-file-path" # END temporary workarounds that must be reevaluated periodically ############################################################################### diff --git a/test/buildah-bud/buildah-tests.diff b/test/buildah-bud/buildah-tests.diff index e746000b481..5db2ca4cf7f 100644 --- a/test/buildah-bud/buildah-tests.diff +++ b/test/buildah-bud/buildah-tests.diff @@ -1,4 +1,4 @@ -From 1ca19690f26005148482b1fbeff0aa52a67ee898 Mon Sep 17 00:00:00 2001 +From 53c97f858285ff043b4121988433f2312482eba9 Mon Sep 17 00:00:00 2001 From: Ed Santiago Date: Thu, 6 Oct 2022 17:32:59 -0600 Subject: [PATCH] tweaks for running buildah tests under podman @@ -6,15 +6,16 @@ Subject: [PATCH] tweaks for running buildah tests under podman Signed-off-by: Ed Santiago Signed-off-by: Paul Holzinger Signed-off-by: Danish Prakash +Signed-off-by: Lokesh Mandvekar --- tests/helpers.bash | 166 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 162 insertions(+), 4 deletions(-) diff --git a/tests/helpers.bash b/tests/helpers.bash -index d08221a52759..5e9c818092cb 100644 +index 5ba4f5a..6a41f10 100644 --- a/tests/helpers.bash +++ b/tests/helpers.bash -@@ -85,6 +85,42 @@ EOF +@@ -86,6 +86,42 @@ EOF BUILDAH_REGISTRY_OPTS="${regconfopt} ${regconfdir} --short-name-alias-conf ${TEST_SCRATCH_DIR}/cache/shortnames.conf" COPY_REGISTRY_OPTS="${BUILDAH_REGISTRY_OPTS}" PODMAN_REGISTRY_OPTS="${regconfopt}" @@ -55,12 +56,12 @@ index d08221a52759..5e9c818092cb 100644 + die "podman server never came up: $PODMAN_SOCK_FILE" + fi } - + function starthttpd() { # directoryspecs [working-directory-or-"" [certfile, keyfile]] -@@ -154,6 +190,22 @@ function teardown_tests() { +@@ -155,6 +191,22 @@ function teardown_tests() { stop_git_daemon stop_registry - + + if [[ -n "$PODMAN_SERVER_PID" ]]; then + echo "teardown: stopping podman server $PODMAN_SERVER_PID" + kill $PODMAN_SERVER_PID @@ -80,9 +81,9 @@ index d08221a52759..5e9c818092cb 100644 # Workaround for #1991 - buildah + overlayfs leaks mount points. # Many tests leave behind /var/tmp/.../root/overlay and sub-mounts; # let's find those and clean them up, otherwise 'rm -rf' fails. -@@ -275,7 +327,12 @@ function copy() { +@@ -276,7 +328,12 @@ function copy() { } - + function podman() { - command ${PODMAN_BINARY:-podman} ${PODMAN_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@" + local cmd=${PODMAN_BINARY:-podman} @@ -92,12 +93,12 @@ index d08221a52759..5e9c818092cb 100644 + fi + command $cmd $opts "$@" } - + # There are various scenarios where we would like to execute `tests` as rootless user, however certain commands like `buildah mount` -@@ -382,8 +439,86 @@ function run_buildah() { +@@ -383,8 +440,86 @@ function run_buildah() { --retry) retry=3; shift;; # retry network flakes esac - + + local podman_or_buildah=${BUILDAH_BINARY} + local _opts="${ROOTDIR_OPTS} ${BUILDAH_REGISTRY_OPTS}" + local copydown=: @@ -179,12 +180,12 @@ index d08221a52759..5e9c818092cb 100644 # Remember command args, for possible use in later diagnostic messages - MOST_RECENT_BUILDAH_COMMAND="buildah $*" + MOST_RECENT_BUILDAH_COMMAND="$cmd_basename $*" - + # If session is rootless and `buildah mount` is invoked, perform unshare, # since normal user cannot mount a filesystem unless they're in a user namespace along with its own mount namespace. -@@ -397,8 +532,8 @@ function run_buildah() { +@@ -398,8 +533,8 @@ function run_buildah() { retry=$(( retry - 1 )) - + # stdout is only emitted upon error; this echo is to help a debugger - echo "${_LOG_PROMPT} ${BUILDAH_BINARY} $*" - run env CONTAINERS_CONF=${CONTAINERS_CONF:-$(dirname ${BASH_SOURCE})/containers.conf} timeout --foreground --kill=10 $BUILDAH_TIMEOUT ${BUILDAH_BINARY} ${BUILDAH_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@" @@ -193,20 +194,20 @@ index d08221a52759..5e9c818092cb 100644 # without "quotes", multiple lines are glommed together into one if [ -n "$output" ]; then echo "$output" -@@ -425,6 +560,9 @@ function run_buildah() { +@@ -426,6 +561,9 @@ function run_buildah() { false fi - + + if [[ "$status" -eq 0 ]] ; then + eval ${copydown} + fi if [ -n "$expected_rc" ]; then if [ "$status" -eq "$expected_rc" ]; then return -@@ -753,6 +891,26 @@ function skip_if_no_unshare() { - fi +@@ -772,6 +910,26 @@ function skip_unless_arch() { + skip "test requires one of these architectures: $* (current: $goarch)" } - + +#################### +# skip_if_remote # (only applicable for podman) +#################### @@ -231,5 +232,5 @@ index d08221a52759..5e9c818092cb 100644 # start_git_daemon # ###################### -- -2.51.1 +2.53.0 diff --git a/vendor/cyphar.com/go-pathrs/.golangci.yml b/vendor/cyphar.com/go-pathrs/.golangci.yml index 2778a3268ef..a28cbd2a4fd 100644 --- a/vendor/cyphar.com/go-pathrs/.golangci.yml +++ b/vendor/cyphar.com/go-pathrs/.golangci.yml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: MPL-2.0 # # libpathrs: safe path resolution on Linux -# Copyright (C) 2019-2025 Aleksa Sarai # Copyright (C) 2019-2025 SUSE LLC +# Copyright (C) 2026 Aleksa Sarai # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/cyphar.com/go-pathrs/doc.go b/vendor/cyphar.com/go-pathrs/doc.go index a7ee4bc487f..c3b4eedd0f8 100644 --- a/vendor/cyphar.com/go-pathrs/doc.go +++ b/vendor/cyphar.com/go-pathrs/doc.go @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/cyphar.com/go-pathrs/handle_linux.go b/vendor/cyphar.com/go-pathrs/handle_linux.go index 3221ef67389..6ed0b7af7ad 100644 --- a/vendor/cyphar.com/go-pathrs/handle_linux.go +++ b/vendor/cyphar.com/go-pathrs/handle_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -30,11 +30,9 @@ import ( // you can try to use [Root.Open] or [Root.OpenFile]. // // It is critical that perform all relevant operations through this [Handle] -// (rather than fetching the file descriptor yourself with [Handle.IntoRaw]), +// (rather than fetching the underlying [os.File] yourself with [Handle.IntoFile]), // because the security properties of libpathrs depend on users doing all // relevant filesystem operations through libpathrs. -// -// [os.File]: https://pkg.go.dev/os#File type Handle struct { inner *os.File } @@ -43,7 +41,7 @@ type Handle struct { // handle will be copied by this method, so the original handle should still be // freed by the caller. // -// This is effectively the inverse operation of [Handle.IntoRaw], and is used +// This is effectively the inverse operation of [Handle.IntoFile], and is used // for "deserialising" pathrs root handles. func HandleFromFile(file *os.File) (*Handle, error) { newFile, err := fdutils.DupFile(file) @@ -92,8 +90,6 @@ func (h *Handle) OpenFile(flags int) (*os.File, error) { // calling [Handle.Close] will also close any copies of the returned [os.File]. // If you want to get an independent copy, use [Handle.Clone] followed by // [Handle.IntoFile] on the cloned [Handle]. -// -// [os.File]: https://pkg.go.dev/os#File func (h *Handle) IntoFile() *os.File { // TODO: Figure out if we really don't want to make a copy. // TODO: We almost certainly want to clear r.inner here, but we can't do diff --git a/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go b/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go index 41aea3e4b3d..418b298149e 100644 --- a/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go +++ b/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go b/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go index c9f416de01f..8f610ca564e 100644 --- a/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go +++ b/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go @@ -5,8 +5,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go b/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go index c07b80e3071..d54497a5b70 100644 --- a/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go +++ b/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -100,7 +100,7 @@ func InRootReadlink(rootFd uintptr, path string) (string, error) { size := 128 for { linkBuf := make([]byte, size) - n := C.pathrs_inroot_readlink(C.int(rootFd), cPath, C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.ulong(len(linkBuf))) + n := C.pathrs_inroot_readlink(C.int(rootFd), cPath, C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.size_t(len(linkBuf))) switch { case int(n) < C.__PATHRS_MAX_ERR_VALUE: return "", fetchError(n) @@ -301,7 +301,7 @@ func ProcReadlinkat(procRootFd int, base ProcBase, path string) (string, error) linkBuf := make([]byte, size) n := C.pathrs_proc_readlinkat( C.int(procRootFd), cBase, cPath, - C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.ulong(len(linkBuf))) + C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.size_t(len(linkBuf))) switch { case int(n) < C.__PATHRS_MAX_ERR_VALUE: return "", fetchError(n) diff --git a/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go b/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go index 5533c427cb7..915e9ccdb58 100644 --- a/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go +++ b/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -56,16 +56,15 @@ var ( // *before* you call wait(2)or any equivalent method that could reap // zombies). func ProcPid(pid int) ProcBase { - if pid < 0 || pid >= 1<<31 { + if pid < 0 || uint64(pid) >= 1<<31 { panic("invalid ProcBasePid value") // TODO: should this be an error? } - return ProcBase{inner: libpathrs.ProcPid(uint32(pid))} + pid32 := uint32(pid) //nolint:gosec // G115 false positive + return ProcBase{inner: libpathrs.ProcPid(pid32)} } // ThreadCloser is a callback that needs to be called when you are done // operating on an [os.File] fetched using [Handle.OpenThreadSelf]. -// -// [os.File]: https://pkg.go.dev/os#File type ThreadCloser func() // Handle is a wrapper around an *os.File handle to "/proc", which can be @@ -181,8 +180,6 @@ func (proc *Handle) OpenRoot(path string, flags int) (*os.File, error) { // Unlike [Handle.OpenThreadSelf], this method does not involve locking // the goroutine to the current OS thread and so is simpler to use and // theoretically has slightly less overhead. -// -// [runtime.LockOSThread]: https://pkg.go.dev/runtime#LockOSThread func (proc *Handle) OpenSelf(path string, flags int) (*os.File, error) { file, closer, err := proc.open(ProcSelf, path, flags) if closer != nil { @@ -228,10 +225,6 @@ func (proc *Handle) OpenPid(pid int, path string, flags int) (*os.File, error) { // callback MUST be called AFTER you have finished using the returned // [os.File]. This callback is completely separate to [os.File.Close], so it // must be called regardless of how you close the handle. -// -// [runtime.LockOSThread]: https://pkg.go.dev/runtime#LockOSThread -// [os.File]: https://pkg.go.dev/os#File -// [os.File.Close]: https://pkg.go.dev/os#File.Close func (proc *Handle) OpenThreadSelf(path string, flags int) (*os.File, ThreadCloser, error) { return proc.open(ProcThreadSelf, path, flags) } diff --git a/vendor/cyphar.com/go-pathrs/root_linux.go b/vendor/cyphar.com/go-pathrs/root_linux.go index edc9e4c87f9..5bc2e907170 100644 --- a/vendor/cyphar.com/go-pathrs/root_linux.go +++ b/vendor/cyphar.com/go-pathrs/root_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -54,8 +54,6 @@ func OpenRoot(path string) (*Root, error) { // still be closed by the caller. // // This is effectively the inverse operation of [Root.IntoFile]. -// -// [os.File]: https://pkg.go.dev/os#File func RootFromFile(file *os.File) (*Root, error) { newFile, err := fdutils.DupFile(file) if err != nil { @@ -109,8 +107,6 @@ func (r *Root) ResolveNoFollow(path string) (*Handle, error) { // ergonomic to use. // // This is effectively equivalent to [os.Open]. -// -// [os.Open]: https://pkg.go.dev/os#Open func (r *Root) Open(path string) (*os.File, error) { return r.OpenFile(path, os.O_RDONLY) } @@ -127,8 +123,6 @@ func (r *Root) Open(path string) (*os.File, error) { // // This is effectively equivalent to [os.OpenFile], except that os.O_CREAT is // not supported. -// -// [os.OpenFile]: https://pkg.go.dev/os#OpenFile func (r *Root) OpenFile(path string, flags int) (*os.File, error) { return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*os.File, error) { fd, err := libpathrs.InRootOpen(rootFd, path, flags) @@ -145,8 +139,6 @@ func (r *Root) OpenFile(path string, flags int) (*os.File, error) { // // Unlike [os.Create], if the file already exists an error is created rather // than the file being opened and truncated. -// -// [os.Create]: https://pkg.go.dev/os#Create func (r *Root) Create(path string, flags int, mode os.FileMode) (*os.File, error) { unixMode, err := toUnixMode(mode, false) if err != nil { @@ -194,8 +186,6 @@ func (r *Root) RemoveFile(path string) error { // directory tree. // // This is effectively equivalent to [os.Remove]. -// -// [os.Remove]: https://pkg.go.dev/os#Remove func (r *Root) Remove(path string) error { // In order to match os.Remove's implementation we need to also do both // syscalls unconditionally and adjust the error based on whether @@ -219,8 +209,6 @@ func (r *Root) Remove(path string) error { // RemoveAll recursively deletes a path and all of its children. // // This is effectively equivalent to [os.RemoveAll]. -// -// [os.RemoveAll]: https://pkg.go.dev/os#RemoveAll func (r *Root) RemoveAll(path string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { err := libpathrs.InRootRemoveAll(rootFd, path) @@ -233,8 +221,6 @@ func (r *Root) RemoveAll(path string) error { // mode is used for the new directory (the process's umask applies). // // This is effectively equivalent to [os.Mkdir]. -// -// [os.Mkdir]: https://pkg.go.dev/os#Mkdir func (r *Root) Mkdir(path string, mode os.FileMode) error { unixMode, err := toUnixMode(mode, false) if err != nil { @@ -253,8 +239,6 @@ func (r *Root) Mkdir(path string, mode os.FileMode) error { // directories created by this function (the process's umask applies). // // This is effectively equivalent to [os.MkdirAll]. -// -// [os.MkdirAll]: https://pkg.go.dev/os#MkdirAll func (r *Root) MkdirAll(path string, mode os.FileMode) (*Handle, error) { unixMode, err := toUnixMode(mode, false) if err != nil { @@ -278,9 +262,7 @@ func (r *Root) MkdirAll(path string, mode os.FileMode) (*Handle, error) { // directory tree. The provided mode is used for the new directory (the // process's umask applies). // -// This is effectively equivalent to [unix.Mknod]. -// -// [unix.Mknod]: https://pkg.go.dev/golang.org/x/sys/unix#Mknod +// This is effectively equivalent to [golang.org/x/sys/unix.Mknod]. func (r *Root) Mknod(path string, mode os.FileMode, dev uint64) error { unixMode, err := toUnixMode(mode, true) if err != nil { @@ -298,8 +280,6 @@ func (r *Root) Mknod(path string, mode os.FileMode, dev uint64) error { // created at path and is a link to target. // // This is effectively equivalent to [os.Symlink]. -// -// [os.Symlink]: https://pkg.go.dev/os#Symlink func (r *Root) Symlink(path, target string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { err := libpathrs.InRootSymlink(rootFd, path, target) @@ -314,8 +294,6 @@ func (r *Root) Symlink(path, target string) error { // host). // // This is effectively equivalent to [os.Link]. -// -// [os.Link]: https://pkg.go.dev/os#Link func (r *Root) Hardlink(path, target string) error { _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { err := libpathrs.InRootHardlink(rootFd, path, target) @@ -327,8 +305,6 @@ func (r *Root) Hardlink(path, target string) error { // Readlink returns the target of a symlink with a [Root]'s directory tree. // // This is effectively equivalent to [os.Readlink]. -// -// [os.Readlink]: https://pkg.go.dev/os#Readlink func (r *Root) Readlink(path string) (string, error) { return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (string, error) { return libpathrs.InRootReadlink(rootFd, path) @@ -345,8 +321,6 @@ func (r *Root) Readlink(path string) (string, error) { // calling [Root.Close] will also close any copies of the returned [os.File]. // If you want to get an independent copy, use [Root.Clone] followed by // [Root.IntoFile] on the cloned [Root]. -// -// [os.File]: https://pkg.go.dev/os#File func (r *Root) IntoFile() *os.File { // TODO: Figure out if we really don't want to make a copy. // TODO: We almost certainly want to clear r.inner here, but we can't do diff --git a/vendor/cyphar.com/go-pathrs/utils_linux.go b/vendor/cyphar.com/go-pathrs/utils_linux.go index 2208d608f8d..b4e7e08e7df 100644 --- a/vendor/cyphar.com/go-pathrs/utils_linux.go +++ b/vendor/cyphar.com/go-pathrs/utils_linux.go @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 /* * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai * Copyright (C) 2019-2025 SUSE LLC + * Copyright (C) 2026 Aleksa Sarai * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/vendor/github.com/containernetworking/cni/LICENSE b/vendor/github.com/containernetworking/cni/LICENSE deleted file mode 100644 index 8f71f43fee3..00000000000 --- a/vendor/github.com/containernetworking/cni/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/vendor/github.com/containernetworking/cni/libcni/api.go b/vendor/github.com/containernetworking/cni/libcni/api.go deleted file mode 100644 index 6ac26949e6f..00000000000 --- a/vendor/github.com/containernetworking/cni/libcni/api.go +++ /dev/null @@ -1,900 +0,0 @@ -// Copyright 2015 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package libcni - -// Note this is the actual implementation of the CNI specification, which -// is reflected in the SPEC.md file. -// it is typically bundled into runtime providers (i.e. containerd or cri-o would use this -// before calling runc or hcsshim). It is also bundled into CNI providers as well, for example, -// to add an IP to a container, to parse the configuration of the CNI and so on. - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "os" - "path/filepath" - "sort" - "strings" - - "github.com/containernetworking/cni/pkg/invoke" - "github.com/containernetworking/cni/pkg/types" - "github.com/containernetworking/cni/pkg/types/create" - "github.com/containernetworking/cni/pkg/utils" - "github.com/containernetworking/cni/pkg/version" -) - -var ( - CacheDir = "/var/lib/cni" - // slightly awkward wording to preserve anyone matching on error strings - ErrorCheckNotSupp = fmt.Errorf("does not support the CHECK command") -) - -const ( - CNICacheV1 = "cniCacheV1" -) - -// A RuntimeConf holds the arguments to one invocation of a CNI plugin -// excepting the network configuration, with the nested exception that -// the `runtimeConfig` from the network configuration is included -// here. -type RuntimeConf struct { - ContainerID string - NetNS string - IfName string - Args [][2]string - // A dictionary of capability-specific data passed by the runtime - // to plugins as top-level keys in the 'runtimeConfig' dictionary - // of the plugin's stdin data. libcni will ensure that only keys - // in this map which match the capabilities of the plugin are passed - // to the plugin - CapabilityArgs map[string]interface{} - - // DEPRECATED. Will be removed in a future release. - CacheDir string -} - -// Use PluginConfig instead of NetworkConfig, the NetworkConfig -// backwards-compat alias will be removed in a future release. -type NetworkConfig = PluginConfig - -type PluginConfig struct { - Network *types.PluginConf - Bytes []byte -} - -type NetworkConfigList struct { - Name string - CNIVersion string - DisableCheck bool - DisableGC bool - LoadOnlyInlinedPlugins bool - Plugins []*PluginConfig - Bytes []byte -} - -type NetworkAttachment struct { - ContainerID string - Network string - IfName string - Config []byte - NetNS string - CniArgs [][2]string - CapabilityArgs map[string]interface{} -} - -type GCArgs struct { - ValidAttachments []types.GCAttachment -} - -type CNI interface { - AddNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) (types.Result, error) - CheckNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error - DelNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error - GetNetworkListCachedResult(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error) - GetNetworkListCachedConfig(net *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error) - - AddNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) (types.Result, error) - CheckNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error - DelNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error - GetNetworkCachedResult(net *PluginConfig, rt *RuntimeConf) (types.Result, error) - GetNetworkCachedConfig(net *PluginConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) - - ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error) - ValidateNetwork(ctx context.Context, net *PluginConfig) ([]string, error) - - GCNetworkList(ctx context.Context, net *NetworkConfigList, args *GCArgs) error - GetStatusNetworkList(ctx context.Context, net *NetworkConfigList) error - - GetCachedAttachments(containerID string) ([]*NetworkAttachment, error) - - GetVersionInfo(ctx context.Context, pluginType string) (version.PluginInfo, error) -} - -type CNIConfig struct { - Path []string - exec invoke.Exec - cacheDir string -} - -// CNIConfig implements the CNI interface -var _ CNI = &CNIConfig{} - -// NewCNIConfig returns a new CNIConfig object that will search for plugins -// in the given paths and use the given exec interface to run those plugins, -// or if the exec interface is not given, will use a default exec handler. -func NewCNIConfig(path []string, exec invoke.Exec) *CNIConfig { - return NewCNIConfigWithCacheDir(path, "", exec) -} - -// NewCNIConfigWithCacheDir returns a new CNIConfig object that will search for plugins -// in the given paths use the given exec interface to run those plugins, -// or if the exec interface is not given, will use a default exec handler. -// The given cache directory will be used for temporary data storage when needed. -func NewCNIConfigWithCacheDir(path []string, cacheDir string, exec invoke.Exec) *CNIConfig { - return &CNIConfig{ - Path: path, - cacheDir: cacheDir, - exec: exec, - } -} - -func buildOneConfig(name, cniVersion string, orig *PluginConfig, prevResult types.Result, rt *RuntimeConf) (*PluginConfig, error) { - var err error - - inject := map[string]interface{}{ - "name": name, - "cniVersion": cniVersion, - } - // Add previous plugin result - if prevResult != nil { - inject["prevResult"] = prevResult - } - - // Ensure every config uses the same name and version - orig, err = InjectConf(orig, inject) - if err != nil { - return nil, err - } - if rt != nil { - return injectRuntimeConfig(orig, rt) - } - - return orig, nil -} - -// This function takes a libcni RuntimeConf structure and injects values into -// a "runtimeConfig" dictionary in the CNI network configuration JSON that -// will be passed to the plugin on stdin. -// -// Only "capabilities arguments" passed by the runtime are currently injected. -// These capabilities arguments are filtered through the plugin's advertised -// capabilities from its config JSON, and any keys in the CapabilityArgs -// matching plugin capabilities are added to the "runtimeConfig" dictionary -// sent to the plugin via JSON on stdin. For example, if the plugin's -// capabilities include "portMappings", and the CapabilityArgs map includes a -// "portMappings" key, that key and its value are added to the "runtimeConfig" -// dictionary to be passed to the plugin's stdin. -func injectRuntimeConfig(orig *PluginConfig, rt *RuntimeConf) (*PluginConfig, error) { - var err error - - rc := make(map[string]interface{}) - for capability, supported := range orig.Network.Capabilities { - if !supported { - continue - } - if data, ok := rt.CapabilityArgs[capability]; ok { - rc[capability] = data - } - } - - if len(rc) > 0 { - orig, err = InjectConf(orig, map[string]interface{}{"runtimeConfig": rc}) - if err != nil { - return nil, err - } - } - - return orig, nil -} - -// ensure we have a usable exec if the CNIConfig was not given one -func (c *CNIConfig) ensureExec() invoke.Exec { - if c.exec == nil { - c.exec = &invoke.DefaultExec{ - RawExec: &invoke.RawExec{Stderr: os.Stderr}, - PluginDecoder: version.PluginDecoder{}, - } - } - return c.exec -} - -type cachedInfo struct { - Kind string `json:"kind"` - ContainerID string `json:"containerId"` - Config []byte `json:"config"` - IfName string `json:"ifName"` - NetworkName string `json:"networkName"` - NetNS string `json:"netns,omitempty"` - CniArgs [][2]string `json:"cniArgs,omitempty"` - CapabilityArgs map[string]interface{} `json:"capabilityArgs,omitempty"` - RawResult map[string]interface{} `json:"result,omitempty"` - Result types.Result `json:"-"` -} - -// getCacheDir returns the cache directory in this order: -// 1) global cacheDir from CNIConfig object -// 2) deprecated cacheDir from RuntimeConf object -// 3) fall back to default cache directory -func (c *CNIConfig) getCacheDir(rt *RuntimeConf) string { - if c.cacheDir != "" { - return c.cacheDir - } - if rt.CacheDir != "" { - return rt.CacheDir - } - return CacheDir -} - -func (c *CNIConfig) getCacheFilePath(netName string, rt *RuntimeConf) (string, error) { - if netName == "" || rt.ContainerID == "" || rt.IfName == "" { - return "", fmt.Errorf("cache file path requires network name (%q), container ID (%q), and interface name (%q)", netName, rt.ContainerID, rt.IfName) - } - return filepath.Join(c.getCacheDir(rt), "results", fmt.Sprintf("%s-%s-%s", netName, rt.ContainerID, rt.IfName)), nil -} - -func (c *CNIConfig) cacheAdd(result types.Result, config []byte, netName string, rt *RuntimeConf) error { - cached := cachedInfo{ - Kind: CNICacheV1, - ContainerID: rt.ContainerID, - Config: config, - IfName: rt.IfName, - NetworkName: netName, - NetNS: rt.NetNS, - CniArgs: rt.Args, - CapabilityArgs: rt.CapabilityArgs, - } - - // We need to get type.Result into cachedInfo as JSON map - // Marshal to []byte, then Unmarshal into cached.RawResult - data, err := json.Marshal(result) - if err != nil { - return err - } - - err = json.Unmarshal(data, &cached.RawResult) - if err != nil { - return err - } - - newBytes, err := json.Marshal(&cached) - if err != nil { - return err - } - - fname, err := c.getCacheFilePath(netName, rt) - if err != nil { - return err - } - if err := os.MkdirAll(filepath.Dir(fname), 0o700); err != nil { - return err - } - - return os.WriteFile(fname, newBytes, 0o600) -} - -func (c *CNIConfig) cacheDel(netName string, rt *RuntimeConf) error { - fname, err := c.getCacheFilePath(netName, rt) - if err != nil { - // Ignore error - return nil - } - return os.Remove(fname) -} - -func (c *CNIConfig) getCachedConfig(netName string, rt *RuntimeConf) ([]byte, *RuntimeConf, error) { - var bytes []byte - - fname, err := c.getCacheFilePath(netName, rt) - if err != nil { - return nil, nil, err - } - bytes, err = os.ReadFile(fname) - if err != nil { - // Ignore read errors; the cached result may not exist on-disk - return nil, nil, nil - } - - unmarshaled := cachedInfo{} - if err := json.Unmarshal(bytes, &unmarshaled); err != nil { - return nil, nil, fmt.Errorf("failed to unmarshal cached network %q config: %w", netName, err) - } - if unmarshaled.Kind != CNICacheV1 { - return nil, nil, fmt.Errorf("read cached network %q config has wrong kind: %v", netName, unmarshaled.Kind) - } - - newRt := *rt - if unmarshaled.CniArgs != nil { - newRt.Args = unmarshaled.CniArgs - } - newRt.CapabilityArgs = unmarshaled.CapabilityArgs - - return unmarshaled.Config, &newRt, nil -} - -func (c *CNIConfig) getLegacyCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) { - fname, err := c.getCacheFilePath(netName, rt) - if err != nil { - return nil, err - } - data, err := os.ReadFile(fname) - if err != nil { - // Ignore read errors; the cached result may not exist on-disk - return nil, nil - } - - // Load the cached result - result, err := create.CreateFromBytes(data) - if err != nil { - return nil, err - } - - // Convert to the config version to ensure plugins get prevResult - // in the same version as the config. The cached result version - // should match the config version unless the config was changed - // while the container was running. - result, err = result.GetAsVersion(cniVersion) - if err != nil { - return nil, fmt.Errorf("failed to convert cached result to config version %q: %w", cniVersion, err) - } - return result, nil -} - -func (c *CNIConfig) getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) { - fname, err := c.getCacheFilePath(netName, rt) - if err != nil { - return nil, err - } - fdata, err := os.ReadFile(fname) - if err != nil { - // Ignore read errors; the cached result may not exist on-disk - return nil, nil - } - - cachedInfo := cachedInfo{} - if err := json.Unmarshal(fdata, &cachedInfo); err != nil || cachedInfo.Kind != CNICacheV1 { - return c.getLegacyCachedResult(netName, cniVersion, rt) - } - - newBytes, err := json.Marshal(&cachedInfo.RawResult) - if err != nil { - return nil, fmt.Errorf("failed to marshal cached network %q config: %w", netName, err) - } - - // Load the cached result - result, err := create.CreateFromBytes(newBytes) - if err != nil { - return nil, err - } - - // Convert to the config version to ensure plugins get prevResult - // in the same version as the config. The cached result version - // should match the config version unless the config was changed - // while the container was running. - result, err = result.GetAsVersion(cniVersion) - if err != nil { - return nil, fmt.Errorf("failed to convert cached result to config version %q: %w", cniVersion, err) - } - return result, nil -} - -// GetNetworkListCachedResult returns the cached Result of the previous -// AddNetworkList() operation for a network list, or an error. -func (c *CNIConfig) GetNetworkListCachedResult(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) { - return c.getCachedResult(list.Name, list.CNIVersion, rt) -} - -// GetNetworkCachedResult returns the cached Result of the previous -// AddNetwork() operation for a network, or an error. -func (c *CNIConfig) GetNetworkCachedResult(net *PluginConfig, rt *RuntimeConf) (types.Result, error) { - return c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt) -} - -// GetNetworkListCachedConfig copies the input RuntimeConf to output -// RuntimeConf with fields updated with info from the cached Config. -func (c *CNIConfig) GetNetworkListCachedConfig(list *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error) { - return c.getCachedConfig(list.Name, rt) -} - -// GetNetworkCachedConfig copies the input RuntimeConf to output -// RuntimeConf with fields updated with info from the cached Config. -func (c *CNIConfig) GetNetworkCachedConfig(net *PluginConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) { - return c.getCachedConfig(net.Network.Name, rt) -} - -// GetCachedAttachments returns a list of network attachments from the cache. -// The returned list will be filtered by the containerID if the value is not empty. -func (c *CNIConfig) GetCachedAttachments(containerID string) ([]*NetworkAttachment, error) { - dirPath := filepath.Join(c.getCacheDir(&RuntimeConf{}), "results") - entries, err := os.ReadDir(dirPath) - if err != nil { - if os.IsNotExist(err) { - return nil, nil - } - return nil, err - } - - fileNames := make([]string, 0, len(entries)) - for _, e := range entries { - fileNames = append(fileNames, e.Name()) - } - sort.Strings(fileNames) - - attachments := []*NetworkAttachment{} - for _, fname := range fileNames { - if len(containerID) > 0 { - part := fmt.Sprintf("-%s-", containerID) - pos := strings.Index(fname, part) - if pos <= 0 || pos+len(part) >= len(fname) { - continue - } - } - - cacheFile := filepath.Join(dirPath, fname) - bytes, err := os.ReadFile(cacheFile) - if err != nil { - continue - } - - cachedInfo := cachedInfo{} - - if err := json.Unmarshal(bytes, &cachedInfo); err != nil { - continue - } - if cachedInfo.Kind != CNICacheV1 { - continue - } - if len(containerID) > 0 && cachedInfo.ContainerID != containerID { - continue - } - if cachedInfo.IfName == "" || cachedInfo.NetworkName == "" { - continue - } - - attachments = append(attachments, &NetworkAttachment{ - ContainerID: cachedInfo.ContainerID, - Network: cachedInfo.NetworkName, - IfName: cachedInfo.IfName, - Config: cachedInfo.Config, - NetNS: cachedInfo.NetNS, - CniArgs: cachedInfo.CniArgs, - CapabilityArgs: cachedInfo.CapabilityArgs, - }) - } - return attachments, nil -} - -func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *PluginConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) { - c.ensureExec() - pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path) - if err != nil { - return nil, err - } - if err := utils.ValidateContainerID(rt.ContainerID); err != nil { - return nil, err - } - if err := utils.ValidateNetworkName(name); err != nil { - return nil, err - } - if err := utils.ValidateInterfaceName(rt.IfName); err != nil { - return nil, err - } - - newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt) - if err != nil { - return nil, err - } - - return invoke.ExecPluginWithResult(ctx, pluginPath, newConf.Bytes, c.args("ADD", rt), c.exec) -} - -// AddNetworkList executes a sequence of plugins with the ADD command -func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) { - var err error - var result types.Result - for _, net := range list.Plugins { - result, err = c.addNetwork(ctx, list.Name, list.CNIVersion, net, result, rt) - if err != nil { - return nil, fmt.Errorf("plugin %s failed (add): %w", pluginDescription(net.Network), err) - } - } - - if err = c.cacheAdd(result, list.Bytes, list.Name, rt); err != nil { - return nil, fmt.Errorf("failed to set network %q cached result: %w", list.Name, err) - } - - return result, nil -} - -func (c *CNIConfig) checkNetwork(ctx context.Context, name, cniVersion string, net *PluginConfig, prevResult types.Result, rt *RuntimeConf) error { - c.ensureExec() - pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path) - if err != nil { - return err - } - - newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt) - if err != nil { - return err - } - - return invoke.ExecPluginWithoutResult(ctx, pluginPath, newConf.Bytes, c.args("CHECK", rt), c.exec) -} - -// CheckNetworkList executes a sequence of plugins with the CHECK command -func (c *CNIConfig) CheckNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) error { - // CHECK was added in CNI spec version 0.4.0 and higher - if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil { - return err - } else if !gtet { - return fmt.Errorf("configuration version %q %w", list.CNIVersion, ErrorCheckNotSupp) - } - - if list.DisableCheck { - return nil - } - - cachedResult, err := c.getCachedResult(list.Name, list.CNIVersion, rt) - if err != nil { - return fmt.Errorf("failed to get network %q cached result: %w", list.Name, err) - } - - for _, net := range list.Plugins { - if err := c.checkNetwork(ctx, list.Name, list.CNIVersion, net, cachedResult, rt); err != nil { - return err - } - } - - return nil -} - -func (c *CNIConfig) delNetwork(ctx context.Context, name, cniVersion string, net *PluginConfig, prevResult types.Result, rt *RuntimeConf) error { - c.ensureExec() - pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path) - if err != nil { - return err - } - - newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt) - if err != nil { - return err - } - - return invoke.ExecPluginWithoutResult(ctx, pluginPath, newConf.Bytes, c.args("DEL", rt), c.exec) -} - -// DelNetworkList executes a sequence of plugins with the DEL command -func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) error { - var cachedResult types.Result - - // Cached result on DEL was added in CNI spec version 0.4.0 and higher - if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil { - return err - } else if gtet { - if cachedResult, err = c.getCachedResult(list.Name, list.CNIVersion, rt); err != nil { - _ = c.cacheDel(list.Name, rt) - cachedResult = nil - } - } - - for i := len(list.Plugins) - 1; i >= 0; i-- { - net := list.Plugins[i] - if err := c.delNetwork(ctx, list.Name, list.CNIVersion, net, cachedResult, rt); err != nil { - return fmt.Errorf("plugin %s failed (delete): %w", pluginDescription(net.Network), err) - } - } - - _ = c.cacheDel(list.Name, rt) - - return nil -} - -func pluginDescription(net *types.PluginConf) string { - if net == nil { - return "" - } - pluginType := net.Type - out := fmt.Sprintf("type=%q", pluginType) - name := net.Name - if name != "" { - out += fmt.Sprintf(" name=%q", name) - } - return out -} - -// AddNetwork executes the plugin with the ADD command -func (c *CNIConfig) AddNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) (types.Result, error) { - result, err := c.addNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, nil, rt) - if err != nil { - return nil, err - } - - if err = c.cacheAdd(result, net.Bytes, net.Network.Name, rt); err != nil { - return nil, fmt.Errorf("failed to set network %q cached result: %w", net.Network.Name, err) - } - - return result, nil -} - -// CheckNetwork executes the plugin with the CHECK command -func (c *CNIConfig) CheckNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error { - // CHECK was added in CNI spec version 0.4.0 and higher - if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil { - return err - } else if !gtet { - return fmt.Errorf("configuration version %q %w", net.Network.CNIVersion, ErrorCheckNotSupp) - } - - cachedResult, err := c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt) - if err != nil { - return fmt.Errorf("failed to get network %q cached result: %w", net.Network.Name, err) - } - return c.checkNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt) -} - -// DelNetwork executes the plugin with the DEL command -func (c *CNIConfig) DelNetwork(ctx context.Context, net *PluginConfig, rt *RuntimeConf) error { - var cachedResult types.Result - - // Cached result on DEL was added in CNI spec version 0.4.0 and higher - if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil { - return err - } else if gtet { - cachedResult, err = c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt) - if err != nil { - return fmt.Errorf("failed to get network %q cached result: %w", net.Network.Name, err) - } - } - - if err := c.delNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt); err != nil { - return err - } - _ = c.cacheDel(net.Network.Name, rt) - return nil -} - -// ValidateNetworkList checks that a configuration is reasonably valid. -// - all the specified plugins exist on disk -// - every plugin supports the desired version. -// -// Returns a list of all capabilities supported by the configuration, or error -func (c *CNIConfig) ValidateNetworkList(ctx context.Context, list *NetworkConfigList) ([]string, error) { - version := list.CNIVersion - - // holding map for seen caps (in case of duplicates) - caps := map[string]interface{}{} - - errs := []error{} - for _, net := range list.Plugins { - if err := c.validatePlugin(ctx, net.Network.Type, version); err != nil { - errs = append(errs, err) - } - for c, enabled := range net.Network.Capabilities { - if !enabled { - continue - } - caps[c] = struct{}{} - } - } - - if len(errs) > 0 { - return nil, fmt.Errorf("%v", errs) - } - - // make caps list - cc := make([]string, 0, len(caps)) - for c := range caps { - cc = append(cc, c) - } - - return cc, nil -} - -// ValidateNetwork checks that a configuration is reasonably valid. -// It uses the same logic as ValidateNetworkList) -// Returns a list of capabilities -func (c *CNIConfig) ValidateNetwork(ctx context.Context, net *PluginConfig) ([]string, error) { - caps := []string{} - for c, ok := range net.Network.Capabilities { - if ok { - caps = append(caps, c) - } - } - if err := c.validatePlugin(ctx, net.Network.Type, net.Network.CNIVersion); err != nil { - return nil, err - } - return caps, nil -} - -// validatePlugin checks that an individual plugin's configuration is sane -func (c *CNIConfig) validatePlugin(ctx context.Context, pluginName, expectedVersion string) error { - c.ensureExec() - pluginPath, err := c.exec.FindInPath(pluginName, c.Path) - if err != nil { - return err - } - if expectedVersion == "" { - expectedVersion = "0.1.0" - } - - vi, err := invoke.GetVersionInfo(ctx, pluginPath, c.exec) - if err != nil { - return err - } - for _, vers := range vi.SupportedVersions() { - if vers == expectedVersion { - return nil - } - } - return fmt.Errorf("plugin %s does not support config version %q", pluginName, expectedVersion) -} - -// GetVersionInfo reports which versions of the CNI spec are supported by -// the given plugin. -func (c *CNIConfig) GetVersionInfo(ctx context.Context, pluginType string) (version.PluginInfo, error) { - c.ensureExec() - pluginPath, err := c.exec.FindInPath(pluginType, c.Path) - if err != nil { - return nil, err - } - - return invoke.GetVersionInfo(ctx, pluginPath, c.exec) -} - -// GCNetworkList will do two things -// - dump the list of cached attachments, and issue deletes as necessary -// - issue a GC to the underlying plugins (if the version is high enough) -func (c *CNIConfig) GCNetworkList(ctx context.Context, list *NetworkConfigList, args *GCArgs) error { - // If DisableGC is set, then don't bother GCing at all. - if list.DisableGC { - return nil - } - - // First, get the list of cached attachments - cachedAttachments, err := c.GetCachedAttachments("") - if err != nil { - return nil - } - - var validAttachments map[types.GCAttachment]interface{} - if args != nil { - validAttachments = make(map[types.GCAttachment]interface{}, len(args.ValidAttachments)) - for _, a := range args.ValidAttachments { - validAttachments[a] = nil - } - } - - var errs []error - - for _, cachedAttachment := range cachedAttachments { - if cachedAttachment.Network != list.Name { - continue - } - // we found this attachment - gca := types.GCAttachment{ - ContainerID: cachedAttachment.ContainerID, - IfName: cachedAttachment.IfName, - } - if _, ok := validAttachments[gca]; ok { - continue - } - // otherwise, this attachment wasn't valid and we should issue a CNI DEL - rt := RuntimeConf{ - ContainerID: cachedAttachment.ContainerID, - NetNS: cachedAttachment.NetNS, - IfName: cachedAttachment.IfName, - Args: cachedAttachment.CniArgs, - CapabilityArgs: cachedAttachment.CapabilityArgs, - } - if err := c.DelNetworkList(ctx, list, &rt); err != nil { - errs = append(errs, fmt.Errorf("failed to delete stale attachment %s %s: %w", rt.ContainerID, rt.IfName, err)) - } - } - - // now, if the version supports it, issue a GC - if gt, _ := version.GreaterThanOrEqualTo(list.CNIVersion, "1.1.0"); gt { - inject := map[string]interface{}{ - "name": list.Name, - "cniVersion": list.CNIVersion, - } - if args != nil { - inject["cni.dev/valid-attachments"] = args.ValidAttachments - // #1101: spec used incorrect variable name - inject["cni.dev/attachments"] = args.ValidAttachments - } - - for _, plugin := range list.Plugins { - // build config here - pluginConfig, err := InjectConf(plugin, inject) - if err != nil { - errs = append(errs, fmt.Errorf("failed to generate configuration to GC plugin %s: %w", plugin.Network.Type, err)) - } - if err := c.gcNetwork(ctx, pluginConfig); err != nil { - errs = append(errs, fmt.Errorf("failed to GC plugin %s: %w", plugin.Network.Type, err)) - } - } - } - - return errors.Join(errs...) -} - -func (c *CNIConfig) gcNetwork(ctx context.Context, net *PluginConfig) error { - c.ensureExec() - pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path) - if err != nil { - return err - } - args := c.args("GC", &RuntimeConf{}) - - return invoke.ExecPluginWithoutResult(ctx, pluginPath, net.Bytes, args, c.exec) -} - -func (c *CNIConfig) GetStatusNetworkList(ctx context.Context, list *NetworkConfigList) error { - // If the version doesn't support status, abort. - if gt, _ := version.GreaterThanOrEqualTo(list.CNIVersion, "1.1.0"); !gt { - return nil - } - - inject := map[string]interface{}{ - "name": list.Name, - "cniVersion": list.CNIVersion, - } - - for _, plugin := range list.Plugins { - // build config here - pluginConfig, err := InjectConf(plugin, inject) - if err != nil { - return fmt.Errorf("failed to generate configuration to get plugin STATUS %s: %w", plugin.Network.Type, err) - } - if err := c.getStatusNetwork(ctx, pluginConfig); err != nil { - return err // Don't collect errors here, so we return a clean error code. - } - } - return nil -} - -func (c *CNIConfig) getStatusNetwork(ctx context.Context, net *PluginConfig) error { - c.ensureExec() - pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path) - if err != nil { - return err - } - args := c.args("STATUS", &RuntimeConf{}) - - return invoke.ExecPluginWithoutResult(ctx, pluginPath, net.Bytes, args, c.exec) -} - -// ===== -func (c *CNIConfig) args(action string, rt *RuntimeConf) *invoke.Args { - return &invoke.Args{ - Command: action, - ContainerID: rt.ContainerID, - NetNS: rt.NetNS, - PluginArgs: rt.Args, - IfName: rt.IfName, - Path: strings.Join(c.Path, string(os.PathListSeparator)), - } -} diff --git a/vendor/github.com/containernetworking/cni/libcni/conf.go b/vendor/github.com/containernetworking/cni/libcni/conf.go deleted file mode 100644 index 7f8482e75e1..00000000000 --- a/vendor/github.com/containernetworking/cni/libcni/conf.go +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright 2015 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package libcni - -import ( - "encoding/json" - "errors" - "fmt" - "os" - "path/filepath" - "slices" - "sort" - "strings" - - "github.com/containernetworking/cni/pkg/types" - "github.com/containernetworking/cni/pkg/version" -) - -type NotFoundError struct { - Dir string - Name string -} - -func (e NotFoundError) Error() string { - return fmt.Sprintf(`no net configuration with name "%s" in %s`, e.Name, e.Dir) -} - -type NoConfigsFoundError struct { - Dir string -} - -func (e NoConfigsFoundError) Error() string { - return fmt.Sprintf(`no net configurations found in %s`, e.Dir) -} - -// This will not validate that the plugins actually belong to the netconfig by ensuring -// that they are loaded from a directory named after the networkName, relative to the network config. -// -// Since here we are just accepting raw bytes, the caller is responsible for ensuring that the plugin -// config provided here actually "belongs" to the networkconfig in question. -func NetworkPluginConfFromBytes(pluginConfBytes []byte) (*PluginConfig, error) { - // TODO why are we creating a struct that holds both the byte representation and the deserialized - // representation, and returning that, instead of just returning the deserialized representation? - conf := &PluginConfig{Bytes: pluginConfBytes, Network: &types.PluginConf{}} - if err := json.Unmarshal(pluginConfBytes, conf.Network); err != nil { - return nil, fmt.Errorf("error parsing configuration: %w", err) - } - if conf.Network.Type == "" { - return nil, fmt.Errorf("error parsing configuration: missing 'type'") - } - return conf, nil -} - -// Given a path to a directory containing a network configuration, and the name of a network, -// loads all plugin definitions found at path `networkConfPath/networkName/*.conf` -func NetworkPluginConfsFromFiles(networkConfPath, networkName string) ([]*PluginConfig, error) { - var pConfs []*PluginConfig - - pluginConfPath := filepath.Join(networkConfPath, networkName) - - pluginConfFiles, err := ConfFiles(pluginConfPath, []string{".conf"}) - if err != nil { - return nil, fmt.Errorf("failed to read plugin config files in %s: %w", pluginConfPath, err) - } - - for _, pluginConfFile := range pluginConfFiles { - pluginConfBytes, err := os.ReadFile(pluginConfFile) - if err != nil { - return nil, fmt.Errorf("error reading %s: %w", pluginConfFile, err) - } - pluginConf, err := NetworkPluginConfFromBytes(pluginConfBytes) - if err != nil { - return nil, err - } - pConfs = append(pConfs, pluginConf) - } - return pConfs, nil -} - -func NetworkConfFromBytes(confBytes []byte) (*NetworkConfigList, error) { - rawList := make(map[string]interface{}) - if err := json.Unmarshal(confBytes, &rawList); err != nil { - return nil, fmt.Errorf("error parsing configuration list: %w", err) - } - - rawName, ok := rawList["name"] - if !ok { - return nil, fmt.Errorf("error parsing configuration list: no name") - } - name, ok := rawName.(string) - if !ok { - return nil, fmt.Errorf("error parsing configuration list: invalid name type %T", rawName) - } - - var cniVersion string - rawVersion, ok := rawList["cniVersion"] - if ok { - cniVersion, ok = rawVersion.(string) - if !ok { - return nil, fmt.Errorf("error parsing configuration list: invalid cniVersion type %T", rawVersion) - } - } - - rawVersions, ok := rawList["cniVersions"] - if ok { - // Parse the current package CNI version - rvs, ok := rawVersions.([]interface{}) - if !ok { - return nil, fmt.Errorf("error parsing configuration list: invalid type for cniVersions: %T", rvs) - } - vs := make([]string, 0, len(rvs)) - for i, rv := range rvs { - v, ok := rv.(string) - if !ok { - return nil, fmt.Errorf("error parsing configuration list: invalid type for cniVersions index %d: %T", i, rv) - } - gt, err := version.GreaterThan(v, version.Current()) - if err != nil { - return nil, fmt.Errorf("error parsing configuration list: invalid cniVersions entry %s at index %d: %w", v, i, err) - } else if !gt { - // Skip versions "greater" than this implementation of the spec - vs = append(vs, v) - } - } - - // if cniVersion was already set, append it to the list for sorting. - if cniVersion != "" { - gt, err := version.GreaterThan(cniVersion, version.Current()) - if err != nil { - return nil, fmt.Errorf("error parsing configuration list: invalid cniVersion %s: %w", cniVersion, err) - } else if !gt { - // ignore any versions higher than the current implemented spec version - vs = append(vs, cniVersion) - } - } - slices.SortFunc[[]string](vs, func(v1, v2 string) int { - if v1 == v2 { - return 0 - } - if gt, _ := version.GreaterThan(v1, v2); gt { - return 1 - } - return -1 - }) - if len(vs) > 0 { - cniVersion = vs[len(vs)-1] - } - } - - readBool := func(key string) (bool, error) { - rawVal, ok := rawList[key] - if !ok { - return false, nil - } - if b, ok := rawVal.(bool); ok { - return b, nil - } - - s, ok := rawVal.(string) - if !ok { - return false, fmt.Errorf("error parsing configuration list: invalid type %T for %s", rawVal, key) - } - s = strings.ToLower(s) - switch s { - case "false": - return false, nil - case "true": - return true, nil - } - return false, fmt.Errorf("error parsing configuration list: invalid value %q for %s", s, key) - } - - disableCheck, err := readBool("disableCheck") - if err != nil { - return nil, err - } - - disableGC, err := readBool("disableGC") - if err != nil { - return nil, err - } - - loadOnlyInlinedPlugins, err := readBool("loadOnlyInlinedPlugins") - if err != nil { - return nil, err - } - - list := &NetworkConfigList{ - Name: name, - DisableCheck: disableCheck, - DisableGC: disableGC, - LoadOnlyInlinedPlugins: loadOnlyInlinedPlugins, - CNIVersion: cniVersion, - Bytes: confBytes, - } - - var plugins []interface{} - plug, ok := rawList["plugins"] - // We can have a `plugins` list key in the main conf, - // We can also have `loadOnlyInlinedPlugins == true` - // - // If `plugins` is there, then `loadOnlyInlinedPlugins` can be true - // - // If plugins is NOT there, then `loadOnlyInlinedPlugins` cannot be true - // - // We have to have at least some plugins. - if !ok && loadOnlyInlinedPlugins { - return nil, fmt.Errorf("error parsing configuration list: `loadOnlyInlinedPlugins` is true, and no 'plugins' key") - } else if !ok && !loadOnlyInlinedPlugins { - return list, nil - } - - plugins, ok = plug.([]interface{}) - if !ok { - return nil, fmt.Errorf("error parsing configuration list: invalid 'plugins' type %T", plug) - } - if len(plugins) == 0 { - return nil, fmt.Errorf("error parsing configuration list: no plugins in list") - } - - for i, conf := range plugins { - newBytes, err := json.Marshal(conf) - if err != nil { - return nil, fmt.Errorf("failed to marshal plugin config %d: %w", i, err) - } - netConf, err := ConfFromBytes(newBytes) - if err != nil { - return nil, fmt.Errorf("failed to parse plugin config %d: %w", i, err) - } - list.Plugins = append(list.Plugins, netConf) - } - return list, nil -} - -func NetworkConfFromFile(filename string) (*NetworkConfigList, error) { - bytes, err := os.ReadFile(filename) - if err != nil { - return nil, fmt.Errorf("error reading %s: %w", filename, err) - } - - conf, err := NetworkConfFromBytes(bytes) - if err != nil { - return nil, err - } - - if !conf.LoadOnlyInlinedPlugins { - plugins, err := NetworkPluginConfsFromFiles(filepath.Dir(filename), conf.Name) - if err != nil { - return nil, err - } - conf.Plugins = append(conf.Plugins, plugins...) - } - - if len(conf.Plugins) == 0 { - // Having 0 plugins for a given network is not necessarily a problem, - // but return as error for caller to decide, since they tried to load - return nil, fmt.Errorf("no plugin configs found") - } - return conf, nil -} - -// Deprecated: This file format is no longer supported, use NetworkConfXXX and NetworkPluginXXX functions -func ConfFromBytes(bytes []byte) (*NetworkConfig, error) { - return NetworkPluginConfFromBytes(bytes) -} - -// Deprecated: This file format is no longer supported, use NetworkConfXXX and NetworkPluginXXX functions -func ConfFromFile(filename string) (*NetworkConfig, error) { - bytes, err := os.ReadFile(filename) - if err != nil { - return nil, fmt.Errorf("error reading %s: %w", filename, err) - } - return ConfFromBytes(bytes) -} - -func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) { - return NetworkConfFromBytes(bytes) -} - -func ConfListFromFile(filename string) (*NetworkConfigList, error) { - return NetworkConfFromFile(filename) -} - -// ConfFiles simply returns a slice of all files in the provided directory -// with extensions matching the provided set. -func ConfFiles(dir string, extensions []string) ([]string, error) { - // In part, adapted from rkt/networking/podenv.go#listFiles - files, err := os.ReadDir(dir) - switch { - case err == nil: // break - case os.IsNotExist(err): - // If folder not there, return no error - only return an - // error if we cannot read contents or there are no contents. - return nil, nil - default: - return nil, err - } - - confFiles := []string{} - for _, f := range files { - if f.IsDir() { - continue - } - fileExt := filepath.Ext(f.Name()) - for _, ext := range extensions { - if fileExt == ext { - confFiles = append(confFiles, filepath.Join(dir, f.Name())) - } - } - } - return confFiles, nil -} - -// Deprecated: This file format is no longer supported, use NetworkConfXXX and NetworkPluginXXX functions -func LoadConf(dir, name string) (*NetworkConfig, error) { - files, err := ConfFiles(dir, []string{".conf", ".json"}) - switch { - case err != nil: - return nil, err - case len(files) == 0: - return nil, NoConfigsFoundError{Dir: dir} - } - sort.Strings(files) - - for _, confFile := range files { - conf, err := ConfFromFile(confFile) - if err != nil { - return nil, err - } - if conf.Network.Name == name { - return conf, nil - } - } - return nil, NotFoundError{dir, name} -} - -func LoadConfList(dir, name string) (*NetworkConfigList, error) { - return LoadNetworkConf(dir, name) -} - -// LoadNetworkConf looks at all the network configs in a given dir, -// loads and parses them all, and returns the first one with an extension of `.conf` -// that matches the provided network name predicate. -func LoadNetworkConf(dir, name string) (*NetworkConfigList, error) { - // TODO this .conflist/.conf extension thing is confusing and inexact - // for implementors. We should pick one extension for everything and stick with it. - files, err := ConfFiles(dir, []string{".conflist"}) - if err != nil { - return nil, err - } - sort.Strings(files) - - for _, confFile := range files { - conf, err := NetworkConfFromFile(confFile) - if err != nil { - return nil, err - } - if conf.Name == name { - return conf, nil - } - } - - // Deprecated: Try and load a network configuration file (instead of list) - // from the same name, then upconvert. - singleConf, err := LoadConf(dir, name) - if err != nil { - // A little extra logic so the error makes sense - var ncfErr NoConfigsFoundError - if len(files) != 0 && errors.As(err, &ncfErr) { - // Config lists found but no config files found - return nil, NotFoundError{dir, name} - } - - return nil, err - } - return ConfListFromConf(singleConf) -} - -// InjectConf takes a PluginConfig and inserts additional values into it, ensuring the result is serializable. -func InjectConf(original *PluginConfig, newValues map[string]interface{}) (*PluginConfig, error) { - config := make(map[string]interface{}) - err := json.Unmarshal(original.Bytes, &config) - if err != nil { - return nil, fmt.Errorf("unmarshal existing network bytes: %w", err) - } - - for key, value := range newValues { - if key == "" { - return nil, fmt.Errorf("keys cannot be empty") - } - - if value == nil { - return nil, fmt.Errorf("key '%s' value must not be nil", key) - } - - config[key] = value - } - - newBytes, err := json.Marshal(config) - if err != nil { - return nil, err - } - - return NetworkPluginConfFromBytes(newBytes) -} - -// ConfListFromConf "upconverts" a network config in to a NetworkConfigList, -// with the single network as the only entry in the list. -// -// Deprecated: Non-conflist file formats are unsupported, use NetworkConfXXX and NetworkPluginXXX functions -func ConfListFromConf(original *PluginConfig) (*NetworkConfigList, error) { - // Re-deserialize the config's json, then make a raw map configlist. - // This may seem a bit strange, but it's to make the Bytes fields - // actually make sense. Otherwise, the generated json is littered with - // golang default values. - - rawConfig := make(map[string]interface{}) - if err := json.Unmarshal(original.Bytes, &rawConfig); err != nil { - return nil, err - } - - rawConfigList := map[string]interface{}{ - "name": original.Network.Name, - "cniVersion": original.Network.CNIVersion, - "plugins": []interface{}{rawConfig}, - } - - b, err := json.Marshal(rawConfigList) - if err != nil { - return nil, err - } - return ConfListFromBytes(b) -} diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/args.go b/vendor/github.com/containernetworking/cni/pkg/invoke/args.go deleted file mode 100644 index 3cdb4bc8dad..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/args.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2015 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package invoke - -import ( - "fmt" - "os" - "strings" -) - -type CNIArgs interface { - // For use with os/exec; i.e., return nil to inherit the - // environment from this process - // For use in delegation; inherit the environment from this - // process and allow overrides - AsEnv() []string -} - -type inherited struct{} - -var inheritArgsFromEnv inherited - -func (*inherited) AsEnv() []string { - return nil -} - -func ArgsFromEnv() CNIArgs { - return &inheritArgsFromEnv -} - -type Args struct { - Command string - ContainerID string - NetNS string - PluginArgs [][2]string - PluginArgsStr string - IfName string - Path string -} - -// Args implements the CNIArgs interface -var _ CNIArgs = &Args{} - -func (args *Args) AsEnv() []string { - env := os.Environ() - pluginArgsStr := args.PluginArgsStr - if pluginArgsStr == "" { - pluginArgsStr = stringify(args.PluginArgs) - } - - // Duplicated values which come first will be overridden, so we must put the - // custom values in the end to avoid being overridden by the process environments. - env = append(env, - "CNI_COMMAND="+args.Command, - "CNI_CONTAINERID="+args.ContainerID, - "CNI_NETNS="+args.NetNS, - "CNI_ARGS="+pluginArgsStr, - "CNI_IFNAME="+args.IfName, - "CNI_PATH="+args.Path, - ) - return dedupEnv(env) -} - -// taken from rkt/networking/net_plugin.go -func stringify(pluginArgs [][2]string) string { - entries := make([]string, len(pluginArgs)) - - for i, kv := range pluginArgs { - entries[i] = strings.Join(kv[:], "=") - } - - return strings.Join(entries, ";") -} - -// DelegateArgs implements the CNIArgs interface -// used for delegation to inherit from environments -// and allow some overrides like CNI_COMMAND -var _ CNIArgs = &DelegateArgs{} - -type DelegateArgs struct { - Command string -} - -func (d *DelegateArgs) AsEnv() []string { - env := os.Environ() - - // The custom values should come in the end to override the existing - // process environment of the same key. - env = append(env, - "CNI_COMMAND="+d.Command, - ) - return dedupEnv(env) -} - -// dedupEnv returns a copy of env with any duplicates removed, in favor of later values. -// Items not of the normal environment "key=value" form are preserved unchanged. -func dedupEnv(env []string) []string { - out := make([]string, 0, len(env)) - envMap := map[string]string{} - - for _, kv := range env { - // find the first "=" in environment, if not, just keep it - eq := strings.Index(kv, "=") - if eq < 0 { - out = append(out, kv) - continue - } - envMap[kv[:eq]] = kv[eq+1:] - } - - for k, v := range envMap { - out = append(out, fmt.Sprintf("%s=%s", k, v)) - } - - return out -} diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go b/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go deleted file mode 100644 index c8b548e7c61..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/delegate.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package invoke - -import ( - "context" - "os" - "path/filepath" - - "github.com/containernetworking/cni/pkg/types" -) - -func delegateCommon(delegatePlugin string, exec Exec) (string, Exec, error) { - if exec == nil { - exec = defaultExec - } - - paths := filepath.SplitList(os.Getenv("CNI_PATH")) - pluginPath, err := exec.FindInPath(delegatePlugin, paths) - if err != nil { - return "", nil, err - } - - return pluginPath, exec, nil -} - -// DelegateAdd calls the given delegate plugin with the CNI ADD action and -// JSON configuration -func DelegateAdd(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) (types.Result, error) { - pluginPath, realExec, err := delegateCommon(delegatePlugin, exec) - if err != nil { - return nil, err - } - - // DelegateAdd will override the original "CNI_COMMAND" env from process with ADD - return ExecPluginWithResult(ctx, pluginPath, netconf, delegateArgs("ADD"), realExec) -} - -// DelegateCheck calls the given delegate plugin with the CNI CHECK action and -// JSON configuration -func DelegateCheck(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { - return delegateNoResult(ctx, delegatePlugin, netconf, exec, "CHECK") -} - -func delegateNoResult(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec, verb string) error { - pluginPath, realExec, err := delegateCommon(delegatePlugin, exec) - if err != nil { - return err - } - - return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs(verb), realExec) -} - -// DelegateDel calls the given delegate plugin with the CNI DEL action and -// JSON configuration -func DelegateDel(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { - return delegateNoResult(ctx, delegatePlugin, netconf, exec, "DEL") -} - -// DelegateStatus calls the given delegate plugin with the CNI STATUS action and -// JSON configuration -func DelegateStatus(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { - return delegateNoResult(ctx, delegatePlugin, netconf, exec, "STATUS") -} - -// DelegateGC calls the given delegate plugin with the CNI GC action and -// JSON configuration -func DelegateGC(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { - return delegateNoResult(ctx, delegatePlugin, netconf, exec, "GC") -} - -// return CNIArgs used by delegation -func delegateArgs(action string) *DelegateArgs { - return &DelegateArgs{ - Command: action, - } -} diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go b/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go deleted file mode 100644 index a5e015fc925..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/exec.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2015 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package invoke - -import ( - "context" - "encoding/json" - "fmt" - "os" - - "github.com/containernetworking/cni/pkg/types" - "github.com/containernetworking/cni/pkg/types/create" - "github.com/containernetworking/cni/pkg/version" -) - -// Exec is an interface encapsulates all operations that deal with finding -// and executing a CNI plugin. Tests may provide a fake implementation -// to avoid writing fake plugins to temporary directories during the test. -type Exec interface { - ExecPlugin(ctx context.Context, pluginPath string, stdinData []byte, environ []string) ([]byte, error) - FindInPath(plugin string, paths []string) (string, error) - Decode(jsonBytes []byte) (version.PluginInfo, error) -} - -// Plugin must return result in same version as specified in netconf; but -// for backwards compatibility reasons if the result version is empty use -// config version (rather than technically correct 0.1.0). -// https://github.com/containernetworking/cni/issues/895 -func fixupResultVersion(netconf, result []byte) (string, []byte, error) { - versionDecoder := &version.ConfigDecoder{} - confVersion, err := versionDecoder.Decode(netconf) - if err != nil { - return "", nil, err - } - - var rawResult map[string]interface{} - if err := json.Unmarshal(result, &rawResult); err != nil { - return "", nil, fmt.Errorf("failed to unmarshal raw result: %w", err) - } - - // plugin output of "null" is successfully unmarshalled, but results in a nil - // map which causes a panic when the confVersion is assigned below. - if rawResult == nil { - rawResult = make(map[string]interface{}) - } - - // Manually decode Result version; we need to know whether its cniVersion - // is empty, while built-in decoders (correctly) substitute 0.1.0 for an - // empty version per the CNI spec. - if resultVerRaw, ok := rawResult["cniVersion"]; ok { - resultVer, ok := resultVerRaw.(string) - if ok && resultVer != "" { - return resultVer, result, nil - } - } - - // If the cniVersion is not present or empty, assume the result is - // the same CNI spec version as the config - rawResult["cniVersion"] = confVersion - newBytes, err := json.Marshal(rawResult) - if err != nil { - return "", nil, fmt.Errorf("failed to remarshal fixed result: %w", err) - } - - return confVersion, newBytes, nil -} - -// For example, a testcase could pass an instance of the following fakeExec -// object to ExecPluginWithResult() to verify the incoming stdin and environment -// and provide a tailored response: -// -// import ( -// "encoding/json" -// "path" -// "strings" -// ) -// -// type fakeExec struct { -// version.PluginDecoder -// } -// -// func (f *fakeExec) ExecPlugin(pluginPath string, stdinData []byte, environ []string) ([]byte, error) { -// net := &types.NetConf{} -// err := json.Unmarshal(stdinData, net) -// if err != nil { -// return nil, fmt.Errorf("failed to unmarshal configuration: %v", err) -// } -// pluginName := path.Base(pluginPath) -// if pluginName != net.Type { -// return nil, fmt.Errorf("plugin name %q did not match config type %q", pluginName, net.Type) -// } -// for _, e := range environ { -// // Check environment for forced failure request -// parts := strings.Split(e, "=") -// if len(parts) > 0 && parts[0] == "FAIL" { -// return nil, fmt.Errorf("failed to execute plugin %s", pluginName) -// } -// } -// return []byte("{\"CNIVersion\":\"0.4.0\"}"), nil -// } -// -// func (f *fakeExec) FindInPath(plugin string, paths []string) (string, error) { -// if len(paths) > 0 { -// return path.Join(paths[0], plugin), nil -// } -// return "", fmt.Errorf("failed to find plugin %s in paths %v", plugin, paths) -// } - -func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) (types.Result, error) { - if exec == nil { - exec = defaultExec - } - - stdoutBytes, err := exec.ExecPlugin(ctx, pluginPath, netconf, args.AsEnv()) - if err != nil { - return nil, err - } - - resultVersion, fixedBytes, err := fixupResultVersion(netconf, stdoutBytes) - if err != nil { - return nil, err - } - - return create.Create(resultVersion, fixedBytes) -} - -func ExecPluginWithoutResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) error { - if exec == nil { - exec = defaultExec - } - _, err := exec.ExecPlugin(ctx, pluginPath, netconf, args.AsEnv()) - return err -} - -// GetVersionInfo returns the version information available about the plugin. -// For recent-enough plugins, it uses the information returned by the VERSION -// command. For older plugins which do not recognize that command, it reports -// version 0.1.0 -func GetVersionInfo(ctx context.Context, pluginPath string, exec Exec) (version.PluginInfo, error) { - if exec == nil { - exec = defaultExec - } - args := &Args{ - Command: "VERSION", - - // set fake values required by plugins built against an older version of skel - NetNS: "dummy", - IfName: "dummy", - Path: "dummy", - } - stdin := []byte(fmt.Sprintf(`{"cniVersion":%q}`, version.Current())) - stdoutBytes, err := exec.ExecPlugin(ctx, pluginPath, stdin, args.AsEnv()) - if err != nil { - if err.Error() == "unknown CNI_COMMAND: VERSION" { - return version.PluginSupports("0.1.0"), nil - } - return nil, err - } - - return exec.Decode(stdoutBytes) -} - -// DefaultExec is an object that implements the Exec interface which looks -// for and executes plugins from disk. -type DefaultExec struct { - *RawExec - version.PluginDecoder -} - -// DefaultExec implements the Exec interface -var _ Exec = &DefaultExec{} - -var defaultExec = &DefaultExec{ - RawExec: &RawExec{Stderr: os.Stderr}, -} diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/find.go b/vendor/github.com/containernetworking/cni/pkg/invoke/find.go deleted file mode 100644 index e62029eb788..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/find.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2015 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package invoke - -import ( - "fmt" - "os" - "path/filepath" - "strings" -) - -// FindInPath returns the full path of the plugin by searching in the provided path -func FindInPath(plugin string, paths []string) (string, error) { - if plugin == "" { - return "", fmt.Errorf("no plugin name provided") - } - - if strings.ContainsRune(plugin, os.PathSeparator) { - return "", fmt.Errorf("invalid plugin name: %s", plugin) - } - - if len(paths) == 0 { - return "", fmt.Errorf("no paths provided") - } - - for _, path := range paths { - for _, fe := range ExecutableFileExtensions { - fullpath := filepath.Join(path, plugin) + fe - if fi, err := os.Stat(fullpath); err == nil && fi.Mode().IsRegular() { - return fullpath, nil - } - } - } - - return "", fmt.Errorf("failed to find plugin %q in path %s", plugin, paths) -} diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go b/vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go deleted file mode 100644 index ed0999bd0e1..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/os_unix.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris -// +build darwin dragonfly freebsd linux netbsd openbsd solaris - -package invoke - -// Valid file extensions for plugin executables. -var ExecutableFileExtensions = []string{""} diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/os_windows.go b/vendor/github.com/containernetworking/cni/pkg/invoke/os_windows.go deleted file mode 100644 index 7665125b133..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/os_windows.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package invoke - -// Valid file extensions for plugin executables. -var ExecutableFileExtensions = []string{".exe", ""} diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go b/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go deleted file mode 100644 index 5ab5cc88576..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/invoke/raw_exec.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package invoke - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "os/exec" - "strings" - "time" - - "github.com/containernetworking/cni/pkg/types" -) - -type RawExec struct { - Stderr io.Writer -} - -func (e *RawExec) ExecPlugin(ctx context.Context, pluginPath string, stdinData []byte, environ []string) ([]byte, error) { - stdout := &bytes.Buffer{} - stderr := &bytes.Buffer{} - c := exec.CommandContext(ctx, pluginPath) - c.Env = environ - c.Stdin = bytes.NewBuffer(stdinData) - c.Stdout = stdout - c.Stderr = stderr - - // Retry the command on "text file busy" errors - for i := 0; i <= 5; i++ { - err := c.Run() - - // Command succeeded - if err == nil { - break - } - - // If the plugin is currently about to be written, then we wait a - // second and try it again - if strings.Contains(err.Error(), "text file busy") { - time.Sleep(time.Second) - continue - } - - // All other errors except than the busy text file - return nil, e.pluginErr(err, stdout.Bytes(), stderr.Bytes()) - } - - // Copy stderr to caller's buffer in case plugin printed to both - // stdout and stderr for some reason. Ignore failures as stderr is - // only informational. - if e.Stderr != nil && stderr.Len() > 0 { - _, _ = stderr.WriteTo(e.Stderr) - } - return stdout.Bytes(), nil -} - -func (e *RawExec) pluginErr(err error, stdout, stderr []byte) error { - emsg := types.Error{} - if len(stdout) == 0 { - if len(stderr) == 0 { - emsg.Msg = fmt.Sprintf("netplugin failed with no error message: %v", err) - } else { - emsg.Msg = fmt.Sprintf("netplugin failed: %q", string(stderr)) - } - } else if perr := json.Unmarshal(stdout, &emsg); perr != nil { - emsg.Msg = fmt.Sprintf("netplugin failed but error parsing its diagnostic message %q: %v", string(stdout), perr) - } - return &emsg -} - -func (e *RawExec) FindInPath(plugin string, paths []string) (string, error) { - return FindInPath(plugin, paths) -} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/020/types.go b/vendor/github.com/containernetworking/cni/pkg/types/020/types.go deleted file mode 100644 index 99b151ff240..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/types/020/types.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types020 - -import ( - "encoding/json" - "fmt" - "io" - "net" - "os" - - "github.com/containernetworking/cni/pkg/types" - convert "github.com/containernetworking/cni/pkg/types/internal" -) - -const ImplementedSpecVersion string = "0.2.0" - -var supportedVersions = []string{"", "0.1.0", ImplementedSpecVersion} - -// Register converters for all versions less than the implemented spec version -func init() { - convert.RegisterConverter("0.1.0", []string{ImplementedSpecVersion}, convertFrom010) - convert.RegisterConverter(ImplementedSpecVersion, []string{"0.1.0"}, convertTo010) - - // Creator - convert.RegisterCreator(supportedVersions, NewResult) -} - -// Compatibility types for CNI version 0.1.0 and 0.2.0 - -// NewResult creates a new Result object from JSON data. The JSON data -// must be compatible with the CNI versions implemented by this type. -func NewResult(data []byte) (types.Result, error) { - result := &Result{} - if err := json.Unmarshal(data, result); err != nil { - return nil, err - } - for _, v := range supportedVersions { - if result.CNIVersion == v { - if result.CNIVersion == "" { - result.CNIVersion = "0.1.0" - } - return result, nil - } - } - return nil, fmt.Errorf("result type supports %v but unmarshalled CNIVersion is %q", - supportedVersions, result.CNIVersion) -} - -// GetResult converts the given Result object to the ImplementedSpecVersion -// and returns the concrete type or an error -func GetResult(r types.Result) (*Result, error) { - result020, err := convert.Convert(r, ImplementedSpecVersion) - if err != nil { - return nil, err - } - result, ok := result020.(*Result) - if !ok { - return nil, fmt.Errorf("failed to convert result") - } - return result, nil -} - -func convertFrom010(from types.Result, toVersion string) (types.Result, error) { - if toVersion != "0.2.0" { - panic("only converts to version 0.2.0") - } - fromResult := from.(*Result) - return &Result{ - CNIVersion: ImplementedSpecVersion, - IP4: fromResult.IP4.Copy(), - IP6: fromResult.IP6.Copy(), - DNS: *fromResult.DNS.Copy(), - }, nil -} - -func convertTo010(from types.Result, toVersion string) (types.Result, error) { - if toVersion != "0.1.0" { - panic("only converts to version 0.1.0") - } - fromResult := from.(*Result) - return &Result{ - CNIVersion: "0.1.0", - IP4: fromResult.IP4.Copy(), - IP6: fromResult.IP6.Copy(), - DNS: *fromResult.DNS.Copy(), - }, nil -} - -// Result is what gets returned from the plugin (via stdout) to the caller -type Result struct { - CNIVersion string `json:"cniVersion,omitempty"` - IP4 *IPConfig `json:"ip4,omitempty"` - IP6 *IPConfig `json:"ip6,omitempty"` - DNS types.DNS `json:"dns,omitempty"` -} - -func (r *Result) Version() string { - return r.CNIVersion -} - -func (r *Result) GetAsVersion(version string) (types.Result, error) { - // If the creator of the result did not set the CNIVersion, assume it - // should be the highest spec version implemented by this Result - if r.CNIVersion == "" { - r.CNIVersion = ImplementedSpecVersion - } - return convert.Convert(r, version) -} - -func (r *Result) Print() error { - return r.PrintTo(os.Stdout) -} - -func (r *Result) PrintTo(writer io.Writer) error { - data, err := json.MarshalIndent(r, "", " ") - if err != nil { - return err - } - _, err = writer.Write(data) - return err -} - -// IPConfig contains values necessary to configure an interface -type IPConfig struct { - IP net.IPNet - Gateway net.IP - Routes []types.Route -} - -func (i *IPConfig) Copy() *IPConfig { - if i == nil { - return nil - } - - var routes []types.Route - for _, fromRoute := range i.Routes { - routes = append(routes, *fromRoute.Copy()) - } - return &IPConfig{ - IP: i.IP, - Gateway: i.Gateway, - Routes: routes, - } -} - -// net.IPNet is not JSON (un)marshallable so this duality is needed -// for our custom IPNet type - -// JSON (un)marshallable types -type ipConfig struct { - IP types.IPNet `json:"ip"` - Gateway net.IP `json:"gateway,omitempty"` - Routes []types.Route `json:"routes,omitempty"` -} - -func (c *IPConfig) MarshalJSON() ([]byte, error) { - ipc := ipConfig{ - IP: types.IPNet(c.IP), - Gateway: c.Gateway, - Routes: c.Routes, - } - - return json.Marshal(ipc) -} - -func (c *IPConfig) UnmarshalJSON(data []byte) error { - ipc := ipConfig{} - if err := json.Unmarshal(data, &ipc); err != nil { - return err - } - - c.IP = net.IPNet(ipc.IP) - c.Gateway = ipc.Gateway - c.Routes = ipc.Routes - return nil -} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/040/types.go b/vendor/github.com/containernetworking/cni/pkg/types/040/types.go deleted file mode 100644 index 3633b0eaa3a..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/types/040/types.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types040 - -import ( - "encoding/json" - "fmt" - "io" - "net" - "os" - - "github.com/containernetworking/cni/pkg/types" - types020 "github.com/containernetworking/cni/pkg/types/020" - convert "github.com/containernetworking/cni/pkg/types/internal" -) - -const ImplementedSpecVersion string = "0.4.0" - -var supportedVersions = []string{"0.3.0", "0.3.1", ImplementedSpecVersion} - -// Register converters for all versions less than the implemented spec version -func init() { - // Up-converters - convert.RegisterConverter("0.1.0", supportedVersions, convertFrom02x) - convert.RegisterConverter("0.2.0", supportedVersions, convertFrom02x) - convert.RegisterConverter("0.3.0", supportedVersions, convertInternal) - convert.RegisterConverter("0.3.1", supportedVersions, convertInternal) - - // Down-converters - convert.RegisterConverter("0.4.0", []string{"0.3.0", "0.3.1"}, convertInternal) - convert.RegisterConverter("0.4.0", []string{"0.1.0", "0.2.0"}, convertTo02x) - convert.RegisterConverter("0.3.1", []string{"0.1.0", "0.2.0"}, convertTo02x) - convert.RegisterConverter("0.3.0", []string{"0.1.0", "0.2.0"}, convertTo02x) - - // Creator - convert.RegisterCreator(supportedVersions, NewResult) -} - -func NewResult(data []byte) (types.Result, error) { - result := &Result{} - if err := json.Unmarshal(data, result); err != nil { - return nil, err - } - for _, v := range supportedVersions { - if result.CNIVersion == v { - return result, nil - } - } - return nil, fmt.Errorf("result type supports %v but unmarshalled CNIVersion is %q", - supportedVersions, result.CNIVersion) -} - -func GetResult(r types.Result) (*Result, error) { - resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion) - if err != nil { - return nil, err - } - result, ok := resultCurrent.(*Result) - if !ok { - return nil, fmt.Errorf("failed to convert result") - } - return result, nil -} - -func NewResultFromResult(result types.Result) (*Result, error) { - newResult, err := convert.Convert(result, ImplementedSpecVersion) - if err != nil { - return nil, err - } - return newResult.(*Result), nil -} - -// Result is what gets returned from the plugin (via stdout) to the caller -type Result struct { - CNIVersion string `json:"cniVersion,omitempty"` - Interfaces []*Interface `json:"interfaces,omitempty"` - IPs []*IPConfig `json:"ips,omitempty"` - Routes []*types.Route `json:"routes,omitempty"` - DNS types.DNS `json:"dns,omitempty"` -} - -func convert020IPConfig(from *types020.IPConfig, ipVersion string) *IPConfig { - return &IPConfig{ - Version: ipVersion, - Address: from.IP, - Gateway: from.Gateway, - } -} - -func convertFrom02x(from types.Result, toVersion string) (types.Result, error) { - fromResult := from.(*types020.Result) - toResult := &Result{ - CNIVersion: toVersion, - DNS: *fromResult.DNS.Copy(), - Routes: []*types.Route{}, - } - if fromResult.IP4 != nil { - toResult.IPs = append(toResult.IPs, convert020IPConfig(fromResult.IP4, "4")) - for _, fromRoute := range fromResult.IP4.Routes { - toResult.Routes = append(toResult.Routes, fromRoute.Copy()) - } - } - - if fromResult.IP6 != nil { - toResult.IPs = append(toResult.IPs, convert020IPConfig(fromResult.IP6, "6")) - for _, fromRoute := range fromResult.IP6.Routes { - toResult.Routes = append(toResult.Routes, fromRoute.Copy()) - } - } - - return toResult, nil -} - -func convertInternal(from types.Result, toVersion string) (types.Result, error) { - fromResult := from.(*Result) - toResult := &Result{ - CNIVersion: toVersion, - DNS: *fromResult.DNS.Copy(), - Routes: []*types.Route{}, - } - for _, fromIntf := range fromResult.Interfaces { - toResult.Interfaces = append(toResult.Interfaces, fromIntf.Copy()) - } - for _, fromIPC := range fromResult.IPs { - toResult.IPs = append(toResult.IPs, fromIPC.Copy()) - } - for _, fromRoute := range fromResult.Routes { - toResult.Routes = append(toResult.Routes, fromRoute.Copy()) - } - return toResult, nil -} - -func convertTo02x(from types.Result, toVersion string) (types.Result, error) { - fromResult := from.(*Result) - toResult := &types020.Result{ - CNIVersion: toVersion, - DNS: *fromResult.DNS.Copy(), - } - - for _, fromIP := range fromResult.IPs { - // Only convert the first IP address of each version as 0.2.0 - // and earlier cannot handle multiple IP addresses - if fromIP.Version == "4" && toResult.IP4 == nil { - toResult.IP4 = &types020.IPConfig{ - IP: fromIP.Address, - Gateway: fromIP.Gateway, - } - } else if fromIP.Version == "6" && toResult.IP6 == nil { - toResult.IP6 = &types020.IPConfig{ - IP: fromIP.Address, - Gateway: fromIP.Gateway, - } - } - if toResult.IP4 != nil && toResult.IP6 != nil { - break - } - } - - for _, fromRoute := range fromResult.Routes { - is4 := fromRoute.Dst.IP.To4() != nil - if is4 && toResult.IP4 != nil { - toResult.IP4.Routes = append(toResult.IP4.Routes, types.Route{ - Dst: fromRoute.Dst, - GW: fromRoute.GW, - }) - } else if !is4 && toResult.IP6 != nil { - toResult.IP6.Routes = append(toResult.IP6.Routes, types.Route{ - Dst: fromRoute.Dst, - GW: fromRoute.GW, - }) - } - } - - // 0.2.0 and earlier require at least one IP address in the Result - if toResult.IP4 == nil && toResult.IP6 == nil { - return nil, fmt.Errorf("cannot convert: no valid IP addresses") - } - - return toResult, nil -} - -func (r *Result) Version() string { - return r.CNIVersion -} - -func (r *Result) GetAsVersion(version string) (types.Result, error) { - // If the creator of the result did not set the CNIVersion, assume it - // should be the highest spec version implemented by this Result - if r.CNIVersion == "" { - r.CNIVersion = ImplementedSpecVersion - } - return convert.Convert(r, version) -} - -func (r *Result) Print() error { - return r.PrintTo(os.Stdout) -} - -func (r *Result) PrintTo(writer io.Writer) error { - data, err := json.MarshalIndent(r, "", " ") - if err != nil { - return err - } - _, err = writer.Write(data) - return err -} - -// Interface contains values about the created interfaces -type Interface struct { - Name string `json:"name"` - Mac string `json:"mac,omitempty"` - Sandbox string `json:"sandbox,omitempty"` -} - -func (i *Interface) String() string { - return fmt.Sprintf("%+v", *i) -} - -func (i *Interface) Copy() *Interface { - if i == nil { - return nil - } - newIntf := *i - return &newIntf -} - -// Int returns a pointer to the int value passed in. Used to -// set the IPConfig.Interface field. -func Int(v int) *int { - return &v -} - -// IPConfig contains values necessary to configure an IP address on an interface -type IPConfig struct { - // IP version, either "4" or "6" - Version string - // Index into Result structs Interfaces list - Interface *int - Address net.IPNet - Gateway net.IP -} - -func (i *IPConfig) String() string { - return fmt.Sprintf("%+v", *i) -} - -func (i *IPConfig) Copy() *IPConfig { - if i == nil { - return nil - } - - ipc := &IPConfig{ - Version: i.Version, - Address: i.Address, - Gateway: i.Gateway, - } - if i.Interface != nil { - intf := *i.Interface - ipc.Interface = &intf - } - return ipc -} - -// JSON (un)marshallable types -type ipConfig struct { - Version string `json:"version"` - Interface *int `json:"interface,omitempty"` - Address types.IPNet `json:"address"` - Gateway net.IP `json:"gateway,omitempty"` -} - -func (c *IPConfig) MarshalJSON() ([]byte, error) { - ipc := ipConfig{ - Version: c.Version, - Interface: c.Interface, - Address: types.IPNet(c.Address), - Gateway: c.Gateway, - } - - return json.Marshal(ipc) -} - -func (c *IPConfig) UnmarshalJSON(data []byte) error { - ipc := ipConfig{} - if err := json.Unmarshal(data, &ipc); err != nil { - return err - } - - c.Version = ipc.Version - c.Interface = ipc.Interface - c.Address = net.IPNet(ipc.Address) - c.Gateway = ipc.Gateway - return nil -} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/100/types.go b/vendor/github.com/containernetworking/cni/pkg/types/100/types.go deleted file mode 100644 index f58b91206dc..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/types/100/types.go +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types100 - -import ( - "encoding/json" - "fmt" - "io" - "net" - "os" - - "github.com/containernetworking/cni/pkg/types" - types040 "github.com/containernetworking/cni/pkg/types/040" - convert "github.com/containernetworking/cni/pkg/types/internal" -) - -// The types did not change between v1.0 and v1.1 -const ImplementedSpecVersion string = "1.1.0" - -var supportedVersions = []string{"1.0.0", "1.1.0"} - -// Register converters for all versions less than the implemented spec version -func init() { - // Up-converters - convert.RegisterConverter("0.1.0", supportedVersions, convertFrom02x) - convert.RegisterConverter("0.2.0", supportedVersions, convertFrom02x) - convert.RegisterConverter("0.3.0", supportedVersions, convertFrom04x) - convert.RegisterConverter("0.3.1", supportedVersions, convertFrom04x) - convert.RegisterConverter("0.4.0", supportedVersions, convertFrom04x) - convert.RegisterConverter("1.0.0", []string{"1.1.0"}, convertFrom100) - - // Down-converters - convert.RegisterConverter("1.0.0", []string{"0.3.0", "0.3.1", "0.4.0"}, convertTo04x) - convert.RegisterConverter("1.0.0", []string{"0.1.0", "0.2.0"}, convertTo02x) - convert.RegisterConverter("1.1.0", []string{"0.3.0", "0.3.1", "0.4.0"}, convertTo04x) - convert.RegisterConverter("1.1.0", []string{"0.1.0", "0.2.0"}, convertTo02x) - convert.RegisterConverter("1.1.0", []string{"1.0.0"}, convertFrom100) - - // Creator - convert.RegisterCreator(supportedVersions, NewResult) -} - -func NewResult(data []byte) (types.Result, error) { - result := &Result{} - if err := json.Unmarshal(data, result); err != nil { - return nil, err - } - for _, v := range supportedVersions { - if result.CNIVersion == v { - return result, nil - } - } - return nil, fmt.Errorf("result type supports %v but unmarshalled CNIVersion is %q", - supportedVersions, result.CNIVersion) -} - -func GetResult(r types.Result) (*Result, error) { - resultCurrent, err := r.GetAsVersion(ImplementedSpecVersion) - if err != nil { - return nil, err - } - result, ok := resultCurrent.(*Result) - if !ok { - return nil, fmt.Errorf("failed to convert result") - } - return result, nil -} - -func NewResultFromResult(result types.Result) (*Result, error) { - newResult, err := convert.Convert(result, ImplementedSpecVersion) - if err != nil { - return nil, err - } - return newResult.(*Result), nil -} - -// Result is what gets returned from the plugin (via stdout) to the caller -type Result struct { - CNIVersion string `json:"cniVersion,omitempty"` - Interfaces []*Interface `json:"interfaces,omitempty"` - IPs []*IPConfig `json:"ips,omitempty"` - Routes []*types.Route `json:"routes,omitempty"` - DNS types.DNS `json:"dns,omitempty"` -} - -// Note: DNS should be omit if DNS is empty but default Marshal function -// will output empty structure hence need to write a Marshal function -func (r *Result) MarshalJSON() ([]byte, error) { - // use type alias to escape recursion for json.Marshal() to MarshalJSON() - type fixObjType = Result - - bytes, err := json.Marshal(fixObjType(*r)) //nolint:all - if err != nil { - return nil, err - } - - fixupObj := make(map[string]interface{}) - if err := json.Unmarshal(bytes, &fixupObj); err != nil { - return nil, err - } - - if r.DNS.IsEmpty() { - delete(fixupObj, "dns") - } - - return json.Marshal(fixupObj) -} - -// convertFrom100 does nothing except set the version; the types are the same -func convertFrom100(from types.Result, toVersion string) (types.Result, error) { - fromResult := from.(*Result) - - result := &Result{ - CNIVersion: toVersion, - Interfaces: fromResult.Interfaces, - IPs: fromResult.IPs, - Routes: fromResult.Routes, - DNS: fromResult.DNS, - } - return result, nil -} - -func convertFrom02x(from types.Result, toVersion string) (types.Result, error) { - result040, err := convert.Convert(from, "0.4.0") - if err != nil { - return nil, err - } - result100, err := convertFrom04x(result040, toVersion) - if err != nil { - return nil, err - } - return result100, nil -} - -func convertIPConfigFrom040(from *types040.IPConfig) *IPConfig { - to := &IPConfig{ - Address: from.Address, - Gateway: from.Gateway, - } - if from.Interface != nil { - intf := *from.Interface - to.Interface = &intf - } - return to -} - -func convertInterfaceFrom040(from *types040.Interface) *Interface { - return &Interface{ - Name: from.Name, - Mac: from.Mac, - Sandbox: from.Sandbox, - } -} - -func convertFrom04x(from types.Result, toVersion string) (types.Result, error) { - fromResult := from.(*types040.Result) - toResult := &Result{ - CNIVersion: toVersion, - DNS: *fromResult.DNS.Copy(), - Routes: []*types.Route{}, - } - for _, fromIntf := range fromResult.Interfaces { - toResult.Interfaces = append(toResult.Interfaces, convertInterfaceFrom040(fromIntf)) - } - for _, fromIPC := range fromResult.IPs { - toResult.IPs = append(toResult.IPs, convertIPConfigFrom040(fromIPC)) - } - for _, fromRoute := range fromResult.Routes { - toResult.Routes = append(toResult.Routes, fromRoute.Copy()) - } - return toResult, nil -} - -func convertIPConfigTo040(from *IPConfig) *types040.IPConfig { - version := "6" - if from.Address.IP.To4() != nil { - version = "4" - } - to := &types040.IPConfig{ - Version: version, - Address: from.Address, - Gateway: from.Gateway, - } - if from.Interface != nil { - intf := *from.Interface - to.Interface = &intf - } - return to -} - -func convertInterfaceTo040(from *Interface) *types040.Interface { - return &types040.Interface{ - Name: from.Name, - Mac: from.Mac, - Sandbox: from.Sandbox, - } -} - -func convertTo04x(from types.Result, toVersion string) (types.Result, error) { - fromResult := from.(*Result) - toResult := &types040.Result{ - CNIVersion: toVersion, - DNS: *fromResult.DNS.Copy(), - Routes: []*types.Route{}, - } - for _, fromIntf := range fromResult.Interfaces { - toResult.Interfaces = append(toResult.Interfaces, convertInterfaceTo040(fromIntf)) - } - for _, fromIPC := range fromResult.IPs { - toResult.IPs = append(toResult.IPs, convertIPConfigTo040(fromIPC)) - } - for _, fromRoute := range fromResult.Routes { - toResult.Routes = append(toResult.Routes, fromRoute.Copy()) - } - return toResult, nil -} - -func convertTo02x(from types.Result, toVersion string) (types.Result, error) { - // First convert to 0.4.0 - result040, err := convertTo04x(from, "0.4.0") - if err != nil { - return nil, err - } - result02x, err := convert.Convert(result040, toVersion) - if err != nil { - return nil, err - } - return result02x, nil -} - -func (r *Result) Version() string { - return r.CNIVersion -} - -func (r *Result) GetAsVersion(version string) (types.Result, error) { - // If the creator of the result did not set the CNIVersion, assume it - // should be the highest spec version implemented by this Result - if r.CNIVersion == "" { - r.CNIVersion = ImplementedSpecVersion - } - return convert.Convert(r, version) -} - -func (r *Result) Print() error { - return r.PrintTo(os.Stdout) -} - -func (r *Result) PrintTo(writer io.Writer) error { - data, err := json.MarshalIndent(r, "", " ") - if err != nil { - return err - } - _, err = writer.Write(data) - return err -} - -// Interface contains values about the created interfaces -type Interface struct { - Name string `json:"name"` - Mac string `json:"mac,omitempty"` - Mtu int `json:"mtu,omitempty"` - Sandbox string `json:"sandbox,omitempty"` - SocketPath string `json:"socketPath,omitempty"` - PciID string `json:"pciID,omitempty"` -} - -func (i *Interface) String() string { - return fmt.Sprintf("%+v", *i) -} - -func (i *Interface) Copy() *Interface { - if i == nil { - return nil - } - newIntf := *i - return &newIntf -} - -// Int returns a pointer to the int value passed in. Used to -// set the IPConfig.Interface field. -func Int(v int) *int { - return &v -} - -// IPConfig contains values necessary to configure an IP address on an interface -type IPConfig struct { - // Index into Result structs Interfaces list - Interface *int - Address net.IPNet - Gateway net.IP -} - -func (i *IPConfig) String() string { - return fmt.Sprintf("%+v", *i) -} - -func (i *IPConfig) Copy() *IPConfig { - if i == nil { - return nil - } - - ipc := &IPConfig{ - Address: i.Address, - Gateway: i.Gateway, - } - if i.Interface != nil { - intf := *i.Interface - ipc.Interface = &intf - } - return ipc -} - -// JSON (un)marshallable types -type ipConfig struct { - Interface *int `json:"interface,omitempty"` - Address types.IPNet `json:"address"` - Gateway net.IP `json:"gateway,omitempty"` -} - -func (c *IPConfig) MarshalJSON() ([]byte, error) { - ipc := ipConfig{ - Interface: c.Interface, - Address: types.IPNet(c.Address), - Gateway: c.Gateway, - } - - return json.Marshal(ipc) -} - -func (c *IPConfig) UnmarshalJSON(data []byte) error { - ipc := ipConfig{} - if err := json.Unmarshal(data, &ipc); err != nil { - return err - } - - c.Interface = ipc.Interface - c.Address = net.IPNet(ipc.Address) - c.Gateway = ipc.Gateway - return nil -} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/args.go b/vendor/github.com/containernetworking/cni/pkg/types/args.go deleted file mode 100644 index 68a602bfdb4..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/types/args.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2015 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types - -import ( - "encoding" - "fmt" - "reflect" - "strings" -) - -// UnmarshallableBool typedef for builtin bool -// because builtin type's methods can't be declared -type UnmarshallableBool bool - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -// Returns boolean true if the string is "1" or "true" or "True" -// Returns boolean false if the string is "0" or "false" or "False” -func (b *UnmarshallableBool) UnmarshalText(data []byte) error { - s := strings.ToLower(string(data)) - switch s { - case "1", "true": - *b = true - case "0", "false": - *b = false - default: - return fmt.Errorf("boolean unmarshal error: invalid input %s", s) - } - return nil -} - -// UnmarshallableString typedef for builtin string -type UnmarshallableString string - -// UnmarshalText implements the encoding.TextUnmarshaler interface. -// Returns the string -func (s *UnmarshallableString) UnmarshalText(data []byte) error { - *s = UnmarshallableString(data) - return nil -} - -// CommonArgs contains the IgnoreUnknown argument -// and must be embedded by all Arg structs -type CommonArgs struct { - IgnoreUnknown UnmarshallableBool `json:"ignoreunknown,omitempty"` -} - -// GetKeyField is a helper function to receive Values -// Values that represent a pointer to a struct -func GetKeyField(keyString string, v reflect.Value) reflect.Value { - return v.Elem().FieldByName(keyString) -} - -// UnmarshalableArgsError is used to indicate error unmarshalling args -// from the args-string in the form "K=V;K2=V2;..." -type UnmarshalableArgsError struct { - error -} - -// LoadArgs parses args from a string in the form "K=V;K2=V2;..." -func LoadArgs(args string, container interface{}) error { - if args == "" { - return nil - } - - containerValue := reflect.ValueOf(container) - - pairs := strings.Split(args, ";") - unknownArgs := []string{} - for _, pair := range pairs { - kv := strings.Split(pair, "=") - if len(kv) != 2 { - return fmt.Errorf("ARGS: invalid pair %q", pair) - } - keyString := kv[0] - valueString := kv[1] - keyField := GetKeyField(keyString, containerValue) - if !keyField.IsValid() { - unknownArgs = append(unknownArgs, pair) - continue - } - - var keyFieldInterface interface{} - switch { - case keyField.Kind() == reflect.Ptr: - keyField.Set(reflect.New(keyField.Type().Elem())) - keyFieldInterface = keyField.Interface() - case keyField.CanAddr() && keyField.Addr().CanInterface(): - keyFieldInterface = keyField.Addr().Interface() - default: - return UnmarshalableArgsError{fmt.Errorf("field '%s' has no valid interface", keyString)} - } - u, ok := keyFieldInterface.(encoding.TextUnmarshaler) - if !ok { - return UnmarshalableArgsError{fmt.Errorf( - "ARGS: cannot unmarshal into field '%s' - type '%s' does not implement encoding.TextUnmarshaler", - keyString, reflect.TypeOf(keyFieldInterface))} - } - err := u.UnmarshalText([]byte(valueString)) - if err != nil { - return fmt.Errorf("ARGS: error parsing value of pair %q: %w", pair, err) - } - } - - isIgnoreUnknown := GetKeyField("IgnoreUnknown", containerValue).Bool() - if len(unknownArgs) > 0 && !isIgnoreUnknown { - return fmt.Errorf("ARGS: unknown args %q", unknownArgs) - } - return nil -} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/create/create.go b/vendor/github.com/containernetworking/cni/pkg/types/create/create.go deleted file mode 100644 index 452cb62201d..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/types/create/create.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package create - -import ( - "encoding/json" - "fmt" - - "github.com/containernetworking/cni/pkg/types" - _ "github.com/containernetworking/cni/pkg/types/020" - _ "github.com/containernetworking/cni/pkg/types/040" - _ "github.com/containernetworking/cni/pkg/types/100" - convert "github.com/containernetworking/cni/pkg/types/internal" -) - -// DecodeVersion returns the CNI version from CNI configuration or result JSON, -// or an error if the operation could not be performed. -func DecodeVersion(jsonBytes []byte) (string, error) { - var conf struct { - CNIVersion string `json:"cniVersion"` - } - err := json.Unmarshal(jsonBytes, &conf) - if err != nil { - return "", fmt.Errorf("decoding version from network config: %w", err) - } - if conf.CNIVersion == "" { - return "0.1.0", nil - } - return conf.CNIVersion, nil -} - -// Create creates a CNI Result using the given JSON with the expected -// version, or an error if the creation could not be performed -func Create(version string, bytes []byte) (types.Result, error) { - return convert.Create(version, bytes) -} - -// CreateFromBytes creates a CNI Result from the given JSON, automatically -// detecting the CNI spec version of the result. An error is returned if the -// operation could not be performed. -func CreateFromBytes(bytes []byte) (types.Result, error) { - version, err := DecodeVersion(bytes) - if err != nil { - return nil, err - } - return convert.Create(version, bytes) -} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/internal/convert.go b/vendor/github.com/containernetworking/cni/pkg/types/internal/convert.go deleted file mode 100644 index bdbe4b0a59a..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/types/internal/convert.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package convert - -import ( - "fmt" - - "github.com/containernetworking/cni/pkg/types" -) - -// ConvertFn should convert from the given arbitrary Result type into a -// Result implementing CNI specification version passed in toVersion. -// The function is guaranteed to be passed a Result type matching the -// fromVersion it was registered with, and is guaranteed to be -// passed a toVersion matching one of the toVersions it was registered with. -type ConvertFn func(from types.Result, toVersion string) (types.Result, error) - -type converter struct { - // fromVersion is the CNI Result spec version that convertFn accepts - fromVersion string - // toVersions is a list of versions that convertFn can convert to - toVersions []string - convertFn ConvertFn -} - -var converters []*converter - -func findConverter(fromVersion, toVersion string) *converter { - for _, c := range converters { - if c.fromVersion == fromVersion { - for _, v := range c.toVersions { - if v == toVersion { - return c - } - } - } - } - return nil -} - -// Convert converts a CNI Result to the requested CNI specification version, -// or returns an error if the conversion could not be performed or failed -func Convert(from types.Result, toVersion string) (types.Result, error) { - if toVersion == "" { - toVersion = "0.1.0" - } - - fromVersion := from.Version() - - // Shortcut for same version - if fromVersion == toVersion { - return from, nil - } - - // Otherwise find the right converter - c := findConverter(fromVersion, toVersion) - if c == nil { - return nil, fmt.Errorf("no converter for CNI result version %s to %s", - fromVersion, toVersion) - } - return c.convertFn(from, toVersion) -} - -// RegisterConverter registers a CNI Result converter. SHOULD NOT BE CALLED -// EXCEPT FROM CNI ITSELF. -func RegisterConverter(fromVersion string, toVersions []string, convertFn ConvertFn) { - // Make sure there is no converter already registered for these - // from and to versions - for _, v := range toVersions { - if findConverter(fromVersion, v) != nil { - panic(fmt.Sprintf("converter already registered for %s to %s", - fromVersion, v)) - } - } - converters = append(converters, &converter{ - fromVersion: fromVersion, - toVersions: toVersions, - convertFn: convertFn, - }) -} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/internal/create.go b/vendor/github.com/containernetworking/cni/pkg/types/internal/create.go deleted file mode 100644 index 96363091259..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/types/internal/create.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package convert - -import ( - "fmt" - - "github.com/containernetworking/cni/pkg/types" -) - -type ResultFactoryFunc func([]byte) (types.Result, error) - -type creator struct { - // CNI Result spec versions that createFn can create a Result for - versions []string - createFn ResultFactoryFunc -} - -var creators []*creator - -func findCreator(version string) *creator { - for _, c := range creators { - for _, v := range c.versions { - if v == version { - return c - } - } - } - return nil -} - -// Create creates a CNI Result using the given JSON, or an error if the creation -// could not be performed -func Create(version string, bytes []byte) (types.Result, error) { - if c := findCreator(version); c != nil { - return c.createFn(bytes) - } - return nil, fmt.Errorf("unsupported CNI result version %q", version) -} - -// RegisterCreator registers a CNI Result creator. SHOULD NOT BE CALLED -// EXCEPT FROM CNI ITSELF. -func RegisterCreator(versions []string, createFn ResultFactoryFunc) { - // Make sure there is no creator already registered for these versions - for _, v := range versions { - if findCreator(v) != nil { - panic(fmt.Sprintf("creator already registered for %s", v)) - } - } - creators = append(creators, &creator{ - versions: versions, - createFn: createFn, - }) -} diff --git a/vendor/github.com/containernetworking/cni/pkg/types/types.go b/vendor/github.com/containernetworking/cni/pkg/types/types.go deleted file mode 100644 index f4b3ce3535e..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/types/types.go +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2015 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types - -import ( - "encoding/json" - "fmt" - "io" - "net" - "os" -) - -// like net.IPNet but adds JSON marshalling and unmarshalling -type IPNet net.IPNet - -// ParseCIDR takes a string like "10.2.3.1/24" and -// return IPNet with "10.2.3.1" and /24 mask -func ParseCIDR(s string) (*net.IPNet, error) { - ip, ipn, err := net.ParseCIDR(s) - if err != nil { - return nil, err - } - - ipn.IP = ip - return ipn, nil -} - -func (n IPNet) MarshalJSON() ([]byte, error) { - return json.Marshal((*net.IPNet)(&n).String()) -} - -func (n *IPNet) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - - tmp, err := ParseCIDR(s) - if err != nil { - return err - } - - *n = IPNet(*tmp) - return nil -} - -// Use PluginConf instead of NetConf, the NetConf -// backwards-compat alias will be removed in a future release. -type NetConf = PluginConf - -// PluginConf describes a plugin configuration for a specific network. -type PluginConf struct { - CNIVersion string `json:"cniVersion,omitempty"` - - Name string `json:"name,omitempty"` - Type string `json:"type,omitempty"` - Capabilities map[string]bool `json:"capabilities,omitempty"` - IPAM IPAM `json:"ipam,omitempty"` - DNS DNS `json:"dns,omitempty"` - - RawPrevResult map[string]interface{} `json:"prevResult,omitempty"` - PrevResult Result `json:"-"` - - // ValidAttachments is only supplied when executing a GC operation - ValidAttachments []GCAttachment `json:"cni.dev/valid-attachments,omitempty"` -} - -// GCAttachment is the parameters to a GC call -- namely, -// the container ID and ifname pair that represents a -// still-valid attachment. -type GCAttachment struct { - ContainerID string `json:"containerID"` - IfName string `json:"ifname"` -} - -// Note: DNS should be omit if DNS is empty but default Marshal function -// will output empty structure hence need to write a Marshal function -func (n *PluginConf) MarshalJSON() ([]byte, error) { - bytes, err := json.Marshal(*n) - if err != nil { - return nil, err - } - - fixupObj := make(map[string]interface{}) - if err := json.Unmarshal(bytes, &fixupObj); err != nil { - return nil, err - } - - if n.DNS.IsEmpty() { - delete(fixupObj, "dns") - } - - return json.Marshal(fixupObj) -} - -type IPAM struct { - Type string `json:"type,omitempty"` -} - -// IsEmpty returns true if IPAM structure has no value, otherwise return false -func (i *IPAM) IsEmpty() bool { - return i.Type == "" -} - -// NetConfList describes an ordered list of networks. -type NetConfList struct { - CNIVersion string `json:"cniVersion,omitempty"` - - Name string `json:"name,omitempty"` - DisableCheck bool `json:"disableCheck,omitempty"` - DisableGC bool `json:"disableGC,omitempty"` - Plugins []*PluginConf `json:"plugins,omitempty"` -} - -// Result is an interface that provides the result of plugin execution -type Result interface { - // The highest CNI specification result version the result supports - // without having to convert - Version() string - - // Returns the result converted into the requested CNI specification - // result version, or an error if conversion failed - GetAsVersion(version string) (Result, error) - - // Prints the result in JSON format to stdout - Print() error - - // Prints the result in JSON format to provided writer - PrintTo(writer io.Writer) error -} - -func PrintResult(result Result, version string) error { - newResult, err := result.GetAsVersion(version) - if err != nil { - return err - } - return newResult.Print() -} - -// DNS contains values interesting for DNS resolvers -type DNS struct { - Nameservers []string `json:"nameservers,omitempty"` - Domain string `json:"domain,omitempty"` - Search []string `json:"search,omitempty"` - Options []string `json:"options,omitempty"` -} - -// IsEmpty returns true if DNS structure has no value, otherwise return false -func (d *DNS) IsEmpty() bool { - if len(d.Nameservers) == 0 && d.Domain == "" && len(d.Search) == 0 && len(d.Options) == 0 { - return true - } - return false -} - -func (d *DNS) Copy() *DNS { - if d == nil { - return nil - } - - to := &DNS{Domain: d.Domain} - to.Nameservers = append(to.Nameservers, d.Nameservers...) - to.Search = append(to.Search, d.Search...) - to.Options = append(to.Options, d.Options...) - return to -} - -type Route struct { - Dst net.IPNet - GW net.IP - MTU int - AdvMSS int - Priority int - Table *int - Scope *int -} - -func (r *Route) String() string { - table := "" - if r.Table != nil { - table = fmt.Sprintf("%d", *r.Table) - } - - scope := "" - if r.Scope != nil { - scope = fmt.Sprintf("%d", *r.Scope) - } - - return fmt.Sprintf("{Dst:%+v GW:%v MTU:%d AdvMSS:%d Priority:%d Table:%s Scope:%s}", r.Dst, r.GW, r.MTU, r.AdvMSS, r.Priority, table, scope) -} - -func (r *Route) Copy() *Route { - if r == nil { - return nil - } - - route := &Route{ - Dst: r.Dst, - GW: r.GW, - MTU: r.MTU, - AdvMSS: r.AdvMSS, - Priority: r.Priority, - Scope: r.Scope, - } - - if r.Table != nil { - table := *r.Table - route.Table = &table - } - - if r.Scope != nil { - scope := *r.Scope - route.Scope = &scope - } - - return route -} - -// Well known error codes -// see https://github.com/containernetworking/cni/blob/main/SPEC.md#well-known-error-codes -const ( - ErrUnknown uint = iota // 0 - ErrIncompatibleCNIVersion // 1 - ErrUnsupportedField // 2 - ErrUnknownContainer // 3 - ErrInvalidEnvironmentVariables // 4 - ErrIOFailure // 5 - ErrDecodingFailure // 6 - ErrInvalidNetworkConfig // 7 - ErrInvalidNetNS // 8 - ErrTryAgainLater uint = 11 - ErrInternal uint = 999 -) - -type Error struct { - Code uint `json:"code"` - Msg string `json:"msg"` - Details string `json:"details,omitempty"` -} - -func NewError(code uint, msg, details string) *Error { - return &Error{ - Code: code, - Msg: msg, - Details: details, - } -} - -func (e *Error) Error() string { - details := "" - if e.Details != "" { - details = fmt.Sprintf("; %v", e.Details) - } - return fmt.Sprintf("%v%v", e.Msg, details) -} - -func (e *Error) Print() error { - return prettyPrint(e) -} - -// net.IPNet is not JSON (un)marshallable so this duality is needed -// for our custom IPNet type - -// JSON (un)marshallable types -type route struct { - Dst IPNet `json:"dst"` - GW net.IP `json:"gw,omitempty"` - MTU int `json:"mtu,omitempty"` - AdvMSS int `json:"advmss,omitempty"` - Priority int `json:"priority,omitempty"` - Table *int `json:"table,omitempty"` - Scope *int `json:"scope,omitempty"` -} - -func (r *Route) UnmarshalJSON(data []byte) error { - rt := route{} - if err := json.Unmarshal(data, &rt); err != nil { - return err - } - - r.Dst = net.IPNet(rt.Dst) - r.GW = rt.GW - r.MTU = rt.MTU - r.AdvMSS = rt.AdvMSS - r.Priority = rt.Priority - r.Table = rt.Table - r.Scope = rt.Scope - - return nil -} - -func (r Route) MarshalJSON() ([]byte, error) { - rt := route{ - Dst: IPNet(r.Dst), - GW: r.GW, - MTU: r.MTU, - AdvMSS: r.AdvMSS, - Priority: r.Priority, - Table: r.Table, - Scope: r.Scope, - } - - return json.Marshal(rt) -} - -func prettyPrint(obj interface{}) error { - data, err := json.MarshalIndent(obj, "", " ") - if err != nil { - return err - } - _, err = os.Stdout.Write(data) - return err -} diff --git a/vendor/github.com/containernetworking/cni/pkg/utils/utils.go b/vendor/github.com/containernetworking/cni/pkg/utils/utils.go deleted file mode 100644 index 1981d255691..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/utils/utils.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2019 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "bytes" - "fmt" - "regexp" - "unicode" - - "github.com/containernetworking/cni/pkg/types" -) - -const ( - // cniValidNameChars is the regexp used to validate valid characters in - // containerID and networkName - cniValidNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.\-]` - - // maxInterfaceNameLength is the length max of a valid interface name - maxInterfaceNameLength = 15 -) - -var cniReg = regexp.MustCompile(`^` + cniValidNameChars + `*$`) - -// ValidateContainerID will validate that the supplied containerID is not empty does not contain invalid characters -func ValidateContainerID(containerID string) *types.Error { - if containerID == "" { - return types.NewError(types.ErrUnknownContainer, "missing containerID", "") - } - if !cniReg.MatchString(containerID) { - return types.NewError(types.ErrInvalidEnvironmentVariables, "invalid characters in containerID", containerID) - } - return nil -} - -// ValidateNetworkName will validate that the supplied networkName does not contain invalid characters -func ValidateNetworkName(networkName string) *types.Error { - if networkName == "" { - return types.NewError(types.ErrInvalidNetworkConfig, "missing network name:", "") - } - if !cniReg.MatchString(networkName) { - return types.NewError(types.ErrInvalidNetworkConfig, "invalid characters found in network name", networkName) - } - return nil -} - -// ValidateInterfaceName will validate the interface name based on the four rules below -// 1. The name must not be empty -// 2. The name must be less than 16 characters -// 3. The name must not be "." or ".." -// 4. The name must not contain / or : or any whitespace characters -// ref to https://github.com/torvalds/linux/blob/master/net/core/dev.c#L1024 -func ValidateInterfaceName(ifName string) *types.Error { - if len(ifName) == 0 { - return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name is empty", "") - } - if len(ifName) > maxInterfaceNameLength { - return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name is too long", fmt.Sprintf("interface name should be less than %d characters", maxInterfaceNameLength+1)) - } - if ifName == "." || ifName == ".." { - return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name is . or ..", "") - } - for _, r := range bytes.Runes([]byte(ifName)) { - if r == '/' || r == ':' || unicode.IsSpace(r) { - return types.NewError(types.ErrInvalidEnvironmentVariables, "interface name contains / or : or whitespace characters", "") - } - } - - return nil -} diff --git a/vendor/github.com/containernetworking/cni/pkg/version/conf.go b/vendor/github.com/containernetworking/cni/pkg/version/conf.go deleted file mode 100644 index 808c33b8382..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/version/conf.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package version - -import ( - "github.com/containernetworking/cni/pkg/types/create" -) - -// ConfigDecoder can decode the CNI version available in network config data -type ConfigDecoder struct{} - -func (*ConfigDecoder) Decode(jsonBytes []byte) (string, error) { - return create.DecodeVersion(jsonBytes) -} diff --git a/vendor/github.com/containernetworking/cni/pkg/version/plugin.go b/vendor/github.com/containernetworking/cni/pkg/version/plugin.go deleted file mode 100644 index e3bd375bca1..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/version/plugin.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package version - -import ( - "encoding/json" - "fmt" - "io" - "strconv" - "strings" -) - -// PluginInfo reports information about CNI versioning -type PluginInfo interface { - // SupportedVersions returns one or more CNI spec versions that the plugin - // supports. If input is provided in one of these versions, then the plugin - // promises to use the same CNI version in its response - SupportedVersions() []string - - // Encode writes this CNI version information as JSON to the given Writer - Encode(io.Writer) error -} - -type pluginInfo struct { - CNIVersion_ string `json:"cniVersion"` - SupportedVersions_ []string `json:"supportedVersions,omitempty"` -} - -// pluginInfo implements the PluginInfo interface -var _ PluginInfo = &pluginInfo{} - -func (p *pluginInfo) Encode(w io.Writer) error { - return json.NewEncoder(w).Encode(p) -} - -func (p *pluginInfo) SupportedVersions() []string { - return p.SupportedVersions_ -} - -// PluginSupports returns a new PluginInfo that will report the given versions -// as supported -func PluginSupports(supportedVersions ...string) PluginInfo { - if len(supportedVersions) < 1 { - panic("programmer error: you must support at least one version") - } - return &pluginInfo{ - CNIVersion_: Current(), - SupportedVersions_: supportedVersions, - } -} - -// PluginDecoder can decode the response returned by a plugin's VERSION command -type PluginDecoder struct{} - -func (*PluginDecoder) Decode(jsonBytes []byte) (PluginInfo, error) { - var info pluginInfo - err := json.Unmarshal(jsonBytes, &info) - if err != nil { - return nil, fmt.Errorf("decoding version info: %w", err) - } - if info.CNIVersion_ == "" { - return nil, fmt.Errorf("decoding version info: missing field cniVersion") - } - if len(info.SupportedVersions_) == 0 { - if info.CNIVersion_ == "0.2.0" { - return PluginSupports("0.1.0", "0.2.0"), nil - } - return nil, fmt.Errorf("decoding version info: missing field supportedVersions") - } - return &info, nil -} - -// ParseVersion parses a version string like "3.0.1" or "0.4.5" into major, -// minor, and micro numbers or returns an error -func ParseVersion(version string) (int, int, int, error) { - var major, minor, micro int - if version == "" { // special case: no version declared == v0.1.0 - return 0, 1, 0, nil - } - - parts := strings.Split(version, ".") - if len(parts) >= 4 { - return -1, -1, -1, fmt.Errorf("invalid version %q: too many parts", version) - } - - major, err := strconv.Atoi(parts[0]) - if err != nil { - return -1, -1, -1, fmt.Errorf("failed to convert major version part %q: %w", parts[0], err) - } - - if len(parts) >= 2 { - minor, err = strconv.Atoi(parts[1]) - if err != nil { - return -1, -1, -1, fmt.Errorf("failed to convert minor version part %q: %w", parts[1], err) - } - } - - if len(parts) >= 3 { - micro, err = strconv.Atoi(parts[2]) - if err != nil { - return -1, -1, -1, fmt.Errorf("failed to convert micro version part %q: %w", parts[2], err) - } - } - - return major, minor, micro, nil -} - -// GreaterThanOrEqualTo takes two string versions, parses them into major/minor/micro -// numbers, and compares them to determine whether the first version is greater -// than or equal to the second -func GreaterThanOrEqualTo(version, otherVersion string) (bool, error) { - firstMajor, firstMinor, firstMicro, err := ParseVersion(version) - if err != nil { - return false, err - } - - secondMajor, secondMinor, secondMicro, err := ParseVersion(otherVersion) - if err != nil { - return false, err - } - - if firstMajor > secondMajor { - return true, nil - } else if firstMajor == secondMajor { - if firstMinor > secondMinor { - return true, nil - } else if firstMinor == secondMinor && firstMicro >= secondMicro { - return true, nil - } - } - return false, nil -} - -// GreaterThan returns true if the first version is greater than the second -func GreaterThan(version, otherVersion string) (bool, error) { - firstMajor, firstMinor, firstMicro, err := ParseVersion(version) - if err != nil { - return false, err - } - - secondMajor, secondMinor, secondMicro, err := ParseVersion(otherVersion) - if err != nil { - return false, err - } - - if firstMajor > secondMajor { - return true, nil - } else if firstMajor == secondMajor { - if firstMinor > secondMinor { - return true, nil - } else if firstMinor == secondMinor && firstMicro > secondMicro { - return true, nil - } - } - return false, nil -} diff --git a/vendor/github.com/containernetworking/cni/pkg/version/reconcile.go b/vendor/github.com/containernetworking/cni/pkg/version/reconcile.go deleted file mode 100644 index 25c3810b2aa..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/version/reconcile.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package version - -import "fmt" - -type ErrorIncompatible struct { - Config string - Supported []string -} - -func (e *ErrorIncompatible) Details() string { - return fmt.Sprintf("config is %q, plugin supports %q", e.Config, e.Supported) -} - -func (e *ErrorIncompatible) Error() string { - return fmt.Sprintf("incompatible CNI versions: %s", e.Details()) -} - -type Reconciler struct{} - -func (r *Reconciler) Check(configVersion string, pluginInfo PluginInfo) *ErrorIncompatible { - return r.CheckRaw(configVersion, pluginInfo.SupportedVersions()) -} - -func (*Reconciler) CheckRaw(configVersion string, supportedVersions []string) *ErrorIncompatible { - for _, supportedVersion := range supportedVersions { - if configVersion == supportedVersion { - return nil - } - } - - return &ErrorIncompatible{ - Config: configVersion, - Supported: supportedVersions, - } -} diff --git a/vendor/github.com/containernetworking/cni/pkg/version/version.go b/vendor/github.com/containernetworking/cni/pkg/version/version.go deleted file mode 100644 index cfb6a12fa35..00000000000 --- a/vendor/github.com/containernetworking/cni/pkg/version/version.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2016 CNI authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package version - -import ( - "encoding/json" - "fmt" - - "github.com/containernetworking/cni/pkg/types" - "github.com/containernetworking/cni/pkg/types/create" -) - -// Current reports the version of the CNI spec implemented by this library -func Current() string { - return "1.1.0" -} - -// Legacy PluginInfo describes a plugin that is backwards compatible with the -// CNI spec version 0.1.0. In particular, a runtime compiled against the 0.1.0 -// library ought to work correctly with a plugin that reports support for -// Legacy versions. -// -// Any future CNI spec versions which meet this definition should be added to -// this list. -var ( - Legacy = PluginSupports("0.1.0", "0.2.0") - All = PluginSupports("0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0", "1.0.0", "1.1.0") -) - -// VersionsFrom returns a list of versions starting from min, inclusive -func VersionsStartingFrom(min string) PluginInfo { - out := []string{} - // cheat, just assume ordered - ok := false - for _, v := range All.SupportedVersions() { - if !ok && v == min { - ok = true - } - if ok { - out = append(out, v) - } - } - return PluginSupports(out...) -} - -// Finds a Result object matching the requested version (if any) and asks -// that object to parse the plugin result, returning an error if parsing failed. -func NewResult(version string, resultBytes []byte) (types.Result, error) { - return create.Create(version, resultBytes) -} - -// ParsePrevResult parses a prevResult in a NetConf structure and sets -// the NetConf's PrevResult member to the parsed Result object. -func ParsePrevResult(conf *types.PluginConf) error { - if conf.RawPrevResult == nil { - return nil - } - - // Prior to 1.0.0, Result types may not marshal a CNIVersion. Since the - // result version must match the config version, if the Result's version - // is empty, inject the config version. - if ver, ok := conf.RawPrevResult["CNIVersion"]; !ok || ver == "" { - conf.RawPrevResult["CNIVersion"] = conf.CNIVersion - } - - resultBytes, err := json.Marshal(conf.RawPrevResult) - if err != nil { - return fmt.Errorf("could not serialize prevResult: %w", err) - } - - conf.RawPrevResult = nil - conf.PrevResult, err = create.Create(conf.CNIVersion, resultBytes) - if err != nil { - return fmt.Errorf("could not parse prevResult: %w", err) - } - - return nil -} diff --git a/vendor/github.com/containers/buildah/.cirrus.yml b/vendor/github.com/containers/buildah/.cirrus.yml index 2c71589ffb9..c181ae0d8c9 100644 --- a/vendor/github.com/containers/buildah/.cirrus.yml +++ b/vendor/github.com/containers/buildah/.cirrus.yml @@ -36,7 +36,7 @@ env: DEBIAN_NAME: "debian-14" # Image identifiers - IMAGE_SUFFIX: "c20251211t152018z-f43f42d14" + IMAGE_SUFFIX: "c20260310t170224z-f43f42d14" FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}" PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}" RAWHIDE_CACHE_IMAGE_NAME: "rawhide-${IMAGE_SUFFIX}" # Used temporarily for rust-podman-sequoia. After that RPM is available in stable Fedora releases, we can stop testing against Rawhide again. @@ -127,7 +127,7 @@ vendor_task: # Runs within Cirrus's "community cluster" container: - image: docker.io/library/golang:1.24.6 + image: docker.io/library/golang:1.25 cpu: 1 memory: 1 @@ -178,6 +178,15 @@ unit_task: setup_script: '${SCRIPT_BASE}/setup.sh |& ${_TIMESTAMP}' unit_test_script: '${SCRIPT_BASE}/test.sh unit |& ${_TIMESTAMP}' + always: &standardlogs + audit_log_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh audit' + df_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh df' + journal_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh journal' + podman_system_info_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh podman' + buildah_version_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh buildah_version' + buildah_info_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh buildah_info' + package_versions_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh packages' + golang_version_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh golang' conformance_task: name: 'Debian Conformance w/ $STORAGE_DRIVER' @@ -199,6 +208,8 @@ conformance_task: setup_script: '${SCRIPT_BASE}/setup.sh conformance |& ${_TIMESTAMP}' conformance_test_script: '${SCRIPT_BASE}/test.sh conformance |& ${_TIMESTAMP}' + always: + <<: *standardlogs integration_task: name: "Integration $DISTRO_NV$RUNTIME_N w/ $STORAGE_DRIVER" @@ -284,15 +295,8 @@ integration_task: binary_artifacts: path: ./bin/* - always: &standardlogs - audit_log_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh audit' - df_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh df' - journal_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh journal' - podman_system_info_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh podman' - buildah_version_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh buildah_version' - buildah_info_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh buildah_info' - package_versions_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh packages' - golang_version_script: '$GOSRC/$SCRIPT_BASE/logcollector.sh golang' + always: + <<: *standardlogs integration_rootless_task: name: "Integration rootless $DISTRO_NV$RUNTIME_N w/ $STORAGE_DRIVER" diff --git a/vendor/github.com/containers/buildah/Makefile b/vendor/github.com/containers/buildah/Makefile index 65084fa07f9..a822f38830e 100644 --- a/vendor/github.com/containers/buildah/Makefile +++ b/vendor/github.com/containers/buildah/Makefile @@ -5,8 +5,6 @@ STORAGETAGS := $(shell ./btrfs_installed_tag.sh) $(shell ./hack/libsubid_tag.sh) SECURITYTAGS ?= seccomp $(APPARMORTAG) TAGS ?= $(SECURITYTAGS) $(STORAGETAGS) $(shell ./hack/systemd_tag.sh) $(shell ./hack/sqlite_tag.sh) ifeq ($(shell uname -s),FreeBSD) -# FreeBSD needs CNI until netavark is supported -TAGS += cni endif BUILDTAGS += $(TAGS) $(EXTRA_BUILD_TAGS) PREFIX := /usr/local @@ -35,11 +33,9 @@ SOURCE_DATE_EPOCH ?= $(if $(shell date +%s),$(shell date +%s),$(error "date fail # strings, while the 4.x we have on Linux doesn't. this is the documented # workaround COMMENT := \# -CNI_COMMIT := $(shell sed -n 's;^$(COMMENT) github.com/containernetworking/cni \([^ \n]*\).*$$;\1;p' vendor/modules.txt) - SEQUOIA_SONAME_DIR = EXTRA_LDFLAGS ?= -BUILDAH_LDFLAGS := $(GO_LDFLAGS) '-X main.GitCommit=$(GIT_COMMIT) -X main.buildInfo=$(SOURCE_DATE_EPOCH) -X main.cniVersion=$(CNI_COMMIT) -X go.podman.io/image/v5/signature/internal/sequoia.sequoiaLibraryDir="$(SEQUOIA_SONAME_DIR)" $(EXTRA_LDFLAGS)' +BUILDAH_LDFLAGS := $(GO_LDFLAGS) '-X main.GitCommit=$(GIT_COMMIT) -X main.buildInfo=$(SOURCE_DATE_EPOCH) -X go.podman.io/image/v5/signature/internal/sequoia.sequoiaLibraryDir="$(SEQUOIA_SONAME_DIR)" $(EXTRA_LDFLAGS)' # This isn't what we actually build; it's a superset, used for target # dependencies. Basically: all *.go and *.c files, except *_test.go, @@ -54,13 +50,13 @@ ifeq ($(BUILDDEBUG), 1) endif # Managed by renovate. -export GOLANGCI_LINT_VERSION := 2.9.0 +export GOLANGCI_LINT_VERSION := 2.11.1 # make all BUILDDEBUG=1 # Note: Uses the -N -l go compiler options to disable compiler optimizations # and inlining. Using these build options allows you to subsequently # use source debugging tools like delve. -all: bin/buildah bin/imgtype bin/copy bin/inet bin/tutorial bin/dumpspec bin/passwd bin/crash bin/wait docs +all: bin/buildah bin/imgtype bin/copy bin/inet bin/tutorial bin/dumpspec bin/passwd bin/crash bin/wait bin/grpcnoop docs bin/buildah: $(SOURCES) internal/mkcw/embed/entrypoint_amd64.gz $(GO_BUILD) $(BUILDAH_LDFLAGS) $(GO_GCFLAGS) "$(GOGCFLAGS)" -o $@ $(BUILDFLAGS) ./cmd/buildah @@ -131,6 +127,9 @@ bin/inet: tests/inet/inet.go bin/passwd: tests/passwd/passwd.go $(GO_BUILD) $(BUILDAH_LDFLAGS) -o $@ $(BUILDFLAGS) ./tests/passwd/passwd.go +bin/grpcnoop: tests/rpc/noop/noop.go + $(GO_BUILD) $(BUILDAH_LDFLAGS) -o $@ $(BUILDFLAGS) ./tests/rpc/noop/noop.go + .PHONY: clean clean: $(RM) -r bin tests/testreport/testreport tests/conformance/testdata/mount-targets/true internal/mkcw/embed/entrypoint_amd64 internal/mkcw/embed/entrypoint_arm64 internal/mkcw/embed/entrypoint_ppc64le internal/mkcw/embed/entrypoint_s390x internal/mkcw/embed/*.gz internal/mkcw/embed/asm/*.o diff --git a/vendor/github.com/containers/buildah/buildah.go b/vendor/github.com/containers/buildah/buildah.go index 27d67b63316..44a78649230 100644 --- a/vendor/github.com/containers/buildah/buildah.go +++ b/vendor/github.com/containers/buildah/buildah.go @@ -147,14 +147,13 @@ type Builder struct { // namespace), effectively deciding whether or not the process has a // usable network. ConfigureNetwork define.NetworkConfigurationPolicy - // CNIPluginPath is the location of CNI plugin helpers, if they should be - // run from a location other than the default location. + // Deprecated: CNIPluginPath was the location of CNI plugin helpers. + // It is no longer used and is expected to be empty. CNIPluginPath string - // CNIConfigDir is the location of CNI configuration files, if the files in - // the default configuration directory shouldn't be used. + // Deprecated: CNIConfigDir was the location of CNI configuration files. + // It is no longer used and is expected to be empty. CNIConfigDir string - - // NetworkInterface is the libnetwork network interface used to setup CNI or netavark networks. + // NetworkInterface is the libnetwork network interface used to setup netavark networks. NetworkInterface nettypes.ContainerNetwork `json:"-"` // GroupAdd is a list of groups to add to the primary process when Run() is @@ -224,13 +223,15 @@ type BuilderInfo struct { NamespaceOptions define.NamespaceOptions Capabilities []string ConfigureNetwork string - CNIPluginPath string - CNIConfigDir string - IDMappingOptions define.IDMappingOptions - History []v1.History - Devices define.ContainerDevices - DeviceSpecs []string - CDIConfigDir string + // Deprecated: CNIPluginPath is no longer used and is expected to be empty. + CNIPluginPath string + // Deprecated: CNIConfigDir is no longer used and is expected to be empty. + CNIConfigDir string + IDMappingOptions define.IDMappingOptions + History []v1.History + Devices define.ContainerDevices + DeviceSpecs []string + CDIConfigDir string } // GetBuildInfo gets a pointer to a Builder object and returns a BuilderInfo object from it. @@ -261,8 +262,6 @@ func GetBuildInfo(b *Builder) BuilderInfo { Isolation: b.Isolation.String(), NamespaceOptions: b.NamespaceOptions, ConfigureNetwork: fmt.Sprintf("%v", b.ConfigureNetwork), - CNIPluginPath: b.CNIPluginPath, - CNIConfigDir: b.CNIConfigDir, IDMappingOptions: b.IDMappingOptions, Capabilities: b.Capabilities, History: history, @@ -333,14 +332,13 @@ type BuilderOptions struct { // namespace), effectively deciding whether or not the process has a // usable network. ConfigureNetwork define.NetworkConfigurationPolicy - // CNIPluginPath is the location of CNI plugin helpers, if they should be - // run from a location other than the default location. + // Deprecated: CNIPluginPath was the location of CNI plugin helpers. + // It is no longer used and is expected to be empty. CNIPluginPath string - // CNIConfigDir is the location of CNI configuration files, if the files in - // the default configuration directory shouldn't be used. + // Deprecated: CNIConfigDir was the location of CNI configuration files. + // It is no longer used and is expected to be empty. CNIConfigDir string - - // NetworkInterface is the libnetwork network interface used to setup CNI or netavark networks. + // NetworkInterface is the libnetwork network interface used to setup netavark networks. NetworkInterface nettypes.ContainerNetwork `json:"-"` // ID mapping options to use if we're setting up our own user namespace. @@ -462,7 +460,7 @@ func OpenBuilder(store storage.Store, container string) (*Builder, error) { return nil, fmt.Errorf("container %q is not a %s container (is a %q container)", container, define.Package, b.Type) } - netInt, err := getNetworkInterface(store, b.CNIConfigDir, b.CNIPluginPath) + netInt, err := getNetworkInterface(store) if err != nil { return nil, err } diff --git a/vendor/github.com/containers/buildah/chroot/run_common.go b/vendor/github.com/containers/buildah/chroot/run_common.go index fbd0689f6af..c6d4825be58 100644 --- a/vendor/github.com/containers/buildah/chroot/run_common.go +++ b/vendor/github.com/containers/buildah/chroot/run_common.go @@ -35,8 +35,6 @@ const ( runUsingChrootCommand = "buildah-chroot-runtime" // runUsingChrootExec is a command we use as a key for reexec runUsingChrootExecCommand = "buildah-chroot-exec" - // containersConfEnv is an environment variable that we need to pass down except for the command itself - containersConfEnv = "CONTAINERS_CONF" ) func init() { @@ -133,9 +131,6 @@ func RunUsingChroot(spec *specs.Spec, bundlePath, homeDir string, stdin io.Reade cmd.Stdin, cmd.Stdout, cmd.Stderr = stdin, stdout, stderr cmd.Dir = "/" cmd.Env = []string{fmt.Sprintf("LOGLEVEL=%d", logrus.GetLevel())} - if _, ok := os.LookupEnv(containersConfEnv); ok { - cmd.Env = append(cmd.Env, containersConfEnv+"="+os.Getenv(containersConfEnv)) - } interrupted := make(chan os.Signal, 100) cmd.Hook = func(int) error { @@ -521,9 +516,6 @@ func runUsingChroot(spec *specs.Spec, bundlePath string, ctty *os.File, stdin io cmd.Stdin, cmd.Stdout, cmd.Stderr = stdin, stdout, stderr cmd.Dir = "/" cmd.Env = []string{fmt.Sprintf("LOGLEVEL=%d", logrus.GetLevel())} - if _, ok := os.LookupEnv(containersConfEnv); ok { - cmd.Env = append(cmd.Env, containersConfEnv+"="+os.Getenv(containersConfEnv)) - } if ctty != nil { cmd.Setsid = true cmd.Ctty = ctty diff --git a/vendor/github.com/containers/buildah/config.go b/vendor/github.com/containers/buildah/config.go index a5381972265..a3f3b604474 100644 --- a/vendor/github.com/containers/buildah/config.go +++ b/vendor/github.com/containers/buildah/config.go @@ -383,10 +383,11 @@ func (b *Builder) Shell() []string { // commands in the container, or in a container built using an image built from // this container. // Note: this setting is not present in the OCIv1 image format, so it is -// discarded when writing images using OCIv1 formats. +// discarded when writing images using OCIv1 formats, even though it is used +// for subsequent RUN instructions while building this image. func (b *Builder) SetShell(shell []string) { if len(shell) > 0 && b.Format != define.Dockerv2ImageManifest { - b.Logger.Warnf("SHELL is not supported for OCI image format, %s will be ignored. Must use `docker` format", shell) + b.Logger.Warnf("SHELL is not persisted in the OCI image format, %s will be used for RUN subsequent instructions to build this image but will not be present in saved image which may affect any images that use this as a base. Must use `docker` format to persist in saved image", shell) } b.Docker.Config.Shell = slices.Clone(shell) diff --git a/vendor/github.com/containers/buildah/define/build.go b/vendor/github.com/containers/buildah/define/build.go index 90c76f592bd..3861fe23611 100644 --- a/vendor/github.com/containers/buildah/define/build.go +++ b/vendor/github.com/containers/buildah/define/build.go @@ -236,14 +236,13 @@ type BuildOptions struct { // namespace), effectively deciding whether or not the process has a // usable network. ConfigureNetwork NetworkConfigurationPolicy - // CNIPluginPath is the location of CNI plugin helpers, if they should be - // run from a location other than the default location. + // Deprecated: CNIPluginPath was the location of CNI plugin helpers. + // It is no longer used and is expected to be empty. CNIPluginPath string - // CNIConfigDir is the location of CNI configuration files, if the files in - // the default configuration directory shouldn't be used. + // Deprecated: CNIConfigDir was the location of CNI configuration files. + // It is no longer used and is expected to be empty. CNIConfigDir string - - // NetworkInterface is the libnetwork network interface used to setup CNI or netavark networks. + // NetworkInterface is the libnetwork network interface used to setup netavark networks. NetworkInterface nettypes.ContainerNetwork `json:"-"` // ID mapping options to use if we're setting up our own user namespace diff --git a/vendor/github.com/containers/buildah/define/namespace.go b/vendor/github.com/containers/buildah/define/namespace.go index d0247fe9165..74592210e96 100644 --- a/vendor/github.com/containers/buildah/define/namespace.go +++ b/vendor/github.com/containers/buildah/define/namespace.go @@ -17,8 +17,8 @@ type NamespaceOption struct { // is not set. If Host is not set and Path is also empty, a new // namespace will be created for the process that we're starting. // If Name is specs.NetworkNamespace, if Path doesn't look like an - // absolute path, it is treated as a comma-separated list of CNI - // configuration names which will be selected from among all of the CNI + // absolute path, it is treated as a comma-separated list of network + // configuration names which will be selected from among all of the // network configurations which we find. Path string } diff --git a/vendor/github.com/containers/buildah/define/types.go b/vendor/github.com/containers/buildah/define/types.go index 9c7da4cd849..49b66d517e3 100644 --- a/vendor/github.com/containers/buildah/define/types.go +++ b/vendor/github.com/containers/buildah/define/types.go @@ -109,6 +109,21 @@ type Secret struct { SourceType string } +func (s Secret) ResolveValue() ([]byte, error) { + switch s.SourceType { + case "env": + return []byte(os.Getenv(s.Source)), nil + case "file": + rv, err := os.ReadFile(s.Source) + if err != nil { + return nil, fmt.Errorf("reading file for secret ID %s: %w", s.ID, err) + } + return rv, nil + default: + return nil, fmt.Errorf("invalid secret type: %s for secret ID: %s", s.SourceType, s.ID) + } +} + // BuildOutputOptions contains the the outcome of parsing the value of a build --output flag // Deprecated: This structure is now internal type BuildOutputOption struct { diff --git a/vendor/github.com/containers/buildah/image.go b/vendor/github.com/containers/buildah/image.go index 469db661079..659675727c9 100644 --- a/vendor/github.com/containers/buildah/image.go +++ b/vendor/github.com/containers/buildah/image.go @@ -14,6 +14,7 @@ import ( "path/filepath" "slices" "strings" + "syscall" "time" "github.com/containers/buildah/copier" @@ -59,6 +60,37 @@ const ( // create uniquely-named files, but we don't want to try to use their // contents until after they've been written to containerExcludesSubstring = ".tmp" + + // Windows-specific PAX record keys + keyFileAttr = "MSWINDOWS.fileattr" + keySDRaw = "MSWINDOWS.rawsd" + keyCreationTime = "LIBARCHIVE.creationtime" + // FILE_ATTRIBUTE_ values + fileAttributeDirectory = "16" + fileAttributeArchive = "32" + + // Windows Security Descriptors (base64-encoded) + // SDDL: O:BAG:SYD:(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)(A;;FA;;;BA)(A;OICIIO;GA;;;CO)(A;OICI;0x1200a9;;;BU)(A;CI;LC;;;BU)(A;CI;DC;;;BU) + // Owner: Built-in Administrators (BA) + // Group: Local System (SY) + // DACL: + // - Allow OBJECT_INHERIT+CONTAINER_INHERIT Full Access to Built-in Administrators (BA) + // - Allow OBJECT_INHERIT+CONTAINER_INHERIT Full Access to Local System (SY) + // - Allow Full Access to Built-in Administrators (BA) + // - Allow OBJECT_INHERIT+CONTAINER_INHERIT+INHERIT_ONLY Generic All to Creator Owner (CO) + // - Allow OBJECT_INHERIT+CONTAINER_INHERIT Read/Execute permissions to Built-in Users (BU) + // - Allow CONTAINER_INHERIT List Contents to Built-in Users (BU) + // - Allow CONTAINER_INHERIT Delete Child to Built-in Users (BU) + winSecurityDescriptorDirectory = "AQAEgBQAAAAkAAAAAAAAADAAAAABAgAAAAAABSAAAAAgAgAAAQEAAAAAAAUSAAAAAgCoAAcAAAAAAxgA/wEfAAECAAAAAAAFIAAAACACAAAAAxQA/wEfAAEBAAAAAAAFEgAAAAAAGAD/AR8AAQIAAAAAAAUgAAAAIAIAAAALFAAAAAAQAQEAAAAAAAMAAAAAAAMYAKkAEgABAgAAAAAABSAAAAAhAgAAAAIYAAQAAAABAgAAAAAABSAAAAAhAgAAAAIYAAIAAAABAgAAAAAABSAAAAAhAgAA" + + // SDDL: O:BAG:SYD:(A;;FA;;;BA)(A;;FA;;;SY)(A;;0x1200a9;;;BU) + // Owner: Built-in Administrators (BA) + // Group: Local System (SY) + // DACL: + // - Allow Full Access to Built-in Administrators (BA) + // - Allow Full Access to Local System (SY) + // - Allow Read/Execute permissions to Built-in Users (BU) + winSecurityDescriptorFile = "AQAEgBQAAAAkAAAAAAAAADAAAAABAgAAAAAABSAAAAAgAgAAAQEAAAAAAAUSAAAAAgBMAAMAAAAAABgA/wEfAAECAAAAAAAFIAAAACACAAAAABQA/wEfAAEBAAAAAAAFEgAAAAAAGACpABIAAQIAAAAAAAUgAAAAIQIAAA==" ) // ExtractRootfsOptions is consumed by ExtractRootfs() which allows users to @@ -112,6 +144,7 @@ type containerImageRef struct { unsetAnnotations []string setAnnotations []string createdAnnotation types.OptionalBool + os string } type blobLayerInfo struct { @@ -1084,6 +1117,7 @@ func (i *containerImageRef) NewImageSource(ctx context.Context, _ *types.SystemC diffBeingAltered := i.compression != archive.Uncompressed diffBeingAltered = diffBeingAltered || i.layerModTime != nil || i.layerLatestModTime != nil diffBeingAltered = diffBeingAltered || len(layerExclusions) != 0 + diffBeingAltered = diffBeingAltered || i.os == "windows" if diffBeingAltered { destHasher = digest.Canonical.Digester() multiWriter = io.MultiWriter(counter, destHasher.Hash()) @@ -1099,11 +1133,13 @@ func (i *containerImageRef) NewImageSource(ctx context.Context, _ *types.SystemC return nil, fmt.Errorf("compressing %s: %w", what, err) } writer := io.MultiWriter(writeCloser, srcHasher.Hash()) - // Use specified timestamps in the layer, if we're doing that for history // entries. nestedWriteCloser := ioutils.NewWriteCloserWrapper(writer, writeCloser.Close) - writeCloser = makeFilteredLayerWriteCloser(nestedWriteCloser, i.layerModTime, i.layerLatestModTime, layerExclusions) + writeCloser, err = makeFilteredLayerWriteCloser(nestedWriteCloser, i.layerModTime, i.layerLatestModTime, layerExclusions, i.os == "windows") + if err != nil { + return nil, fmt.Errorf("creating filter write closer %s: %w", what, err) + } writer = writeCloser // Okay, copy from the raw diff through the filter, compressor, and counter and // digesters. @@ -1373,9 +1409,9 @@ func (i *containerImageRef) makeExtraImageContentDiff(includeFooter bool, timest // no later than layerLatestModTime (if a value is provided for it). // This implies that if both values are provided, the archive's timestamps will // be set to the earlier of the two values. -func makeFilteredLayerWriteCloser(wc io.WriteCloser, layerModTime, layerLatestModTime *time.Time, exclusions []copier.ConditionalRemovePath) io.WriteCloser { - if layerModTime == nil && layerLatestModTime == nil && len(exclusions) == 0 { - return wc +func makeFilteredLayerWriteCloser(wc io.WriteCloser, layerModTime, layerLatestModTime *time.Time, exclusions []copier.ConditionalRemovePath, windows bool) (io.WriteCloser, error) { + if layerModTime == nil && layerLatestModTime == nil && len(exclusions) == 0 && !windows { + return wc, nil } exclusionsMap := make(map[string]copier.ConditionalRemovePath) for _, exclusionSpec := range exclusions { @@ -1385,19 +1421,22 @@ func makeFilteredLayerWriteCloser(wc io.WriteCloser, layerModTime, layerLatestMo } exclusionsMap[pathSpec] = exclusionSpec } + var initialized bool wc = newTarFilterer(wc, func(hdr *tar.Header) (skip, replaceContents bool, replacementContents io.Reader) { - // Changing a zeroed field to a non-zero field can affect the - // format that the library uses for writing the header, so only - // change fields that are already set to avoid changing the - // format (and as a result, changing the length) of the header - // that we write. modTime := hdr.ModTime - nameSpec := strings.Trim(path.Clean(hdr.Name), "/") - if conditions, ok := exclusionsMap[nameSpec]; ok { - if (conditions.ModTime == nil || conditions.ModTime.Equal(modTime)) && - (conditions.Owner == nil || (conditions.Owner.UID == hdr.Uid && conditions.Owner.GID == hdr.Gid)) && - (conditions.Mode == nil || (*conditions.Mode&os.ModePerm == os.FileMode(hdr.Mode)&os.ModePerm)) { - return true, false, nil + if layerModTime != nil || layerLatestModTime != nil || len(exclusions) != 0 { + // Changing a zeroed field to a non-zero field can affect the + // format that the library uses for writing the header, so only + // change fields that are already set to avoid changing the + // format (and as a result, changing the length) of the header + // that we write. + nameSpec := strings.Trim(path.Clean(hdr.Name), "/") + if conditions, ok := exclusionsMap[nameSpec]; ok { + if (conditions.ModTime == nil || conditions.ModTime.Equal(modTime)) && + (conditions.Owner == nil || (conditions.Owner.UID == hdr.Uid && conditions.Owner.GID == hdr.Gid)) && + (conditions.Mode == nil || (*conditions.Mode&os.ModePerm == os.FileMode(hdr.Mode)&os.ModePerm)) { + return true, false, nil + } } } if layerModTime != nil { @@ -1415,9 +1454,70 @@ func makeFilteredLayerWriteCloser(wc io.WriteCloser, layerModTime, layerLatestMo if !hdr.ChangeTime.IsZero() { hdr.ChangeTime = modTime } + if windows { + isDir := hdr.Typeflag == tar.TypeDir + if initialized { + hdr.Name = path.Join("Files", hdr.Name) + if isDir { + hdr.Name += "/" + } + if hdr.Linkname != "" { + hdr.Linkname = path.Join("Files", hdr.Linkname) + if isDir { + hdr.Linkname += "/" + } + } + } + // ensure all header fields are set in a way that is expected for Windows images + if hdr.PAXRecords == nil { + hdr.PAXRecords = map[string]string{} + } + hdr.Format = tar.FormatPAX + if isDir { + hdr.Mode |= syscall.S_IFDIR + hdr.PAXRecords[keyFileAttr] = fileAttributeDirectory + hdr.PAXRecords[keySDRaw] = winSecurityDescriptorDirectory + } else if hdr.Typeflag == tar.TypeReg { + hdr.Mode |= syscall.S_IFREG + hdr.PAXRecords[keyFileAttr] = fileAttributeArchive + hdr.PAXRecords[keySDRaw] = winSecurityDescriptorFile + } + if !hdr.ModTime.IsZero() { + hdr.PAXRecords[keyCreationTime] = fmt.Sprintf("%d.%09d", hdr.ModTime.Unix(), hdr.ModTime.Nanosecond()) + } + } return false, false, nil }) - return wc + if windows { + // prep the archive by writing the Files/ and Hives/ directories to the writer. + // This fulfills a requirement of Windows images + winTarWriter := tar.NewWriter(wc) + now := time.Now() + h := &tar.Header{ + Name: "Hives/", + Typeflag: tar.TypeDir, + ModTime: now, + Mode: 0o755, + } + if err := winTarWriter.WriteHeader(h); err != nil { + return nil, err + } + h = &tar.Header{ + Name: "Files/", + Typeflag: tar.TypeDir, + ModTime: now, + Mode: 0o755, + } + if err := winTarWriter.WriteHeader(h); err != nil { + return nil, err + } + // As we plan to continue to add to the archive, Flush() needs to be used, rather than Close(). + if err := winTarWriter.Flush(); err != nil { + return nil, err + } + } + initialized = true + return wc, nil } // makeLinkedLayerInfos calculates the size and digest information for a layer @@ -1475,7 +1575,10 @@ func (b *Builder) makeLinkedLayerInfos(layers []LinkedLayer, layerType string, l digester := digest.Canonical.Digester() sizeCountedFile := ioutils.NewWriteCounter(io.MultiWriter(digester.Hash(), f)) - wc := makeFilteredLayerWriteCloser(ioutils.NopWriteCloser(sizeCountedFile), layerModTime, layerLatestModTime, nil) + wc, err := makeFilteredLayerWriteCloser(ioutils.NopWriteCloser(sizeCountedFile), layerModTime, layerLatestModTime, nil, false) + if err != nil { + return err + } _, copyErr := io.Copy(wc, rc) wcErr := wc.Close() if err := rc.Close(); err != nil { @@ -1677,6 +1780,7 @@ func (b *Builder) makeContainerImageRef(options CommitOptions) (*containerImageR layerMountTargets: layerMountTargets, layerPullUps: layerPullUps, createdAnnotation: options.CreatedAnnotation, + os: b.OCIv1.OS, } if ref.created != nil { for i := range ref.preEmptyLayers { diff --git a/vendor/github.com/containers/buildah/imagebuildah/executor.go b/vendor/github.com/containers/buildah/imagebuildah/executor.go index faa52c4eaca..9022fc9895a 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/executor.go +++ b/vendor/github.com/containers/buildah/imagebuildah/executor.go @@ -101,9 +101,7 @@ type executor struct { isolation define.Isolation namespaceOptions []define.NamespaceOption configureNetwork define.NetworkConfigurationPolicy - cniPluginPath string - cniConfigDir string - // NetworkInterface is the libnetwork network interface used to setup CNI or netavark networks. + // networkInterface is the libnetwork network interface used to setup netavark networks. networkInterface nettypes.ContainerNetwork idmappingOptions *define.IDMappingOptions commonBuildOptions *define.CommonBuildOptions @@ -302,8 +300,6 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o inheritAnnotations: options.InheritAnnotations, namespaceOptions: options.NamespaceOptions, configureNetwork: options.ConfigureNetwork, - cniPluginPath: options.CNIPluginPath, - cniConfigDir: options.CNIConfigDir, networkInterface: options.NetworkInterface, idmappingOptions: options.IDMappingOptions, commonBuildOptions: options.CommonBuildOpts, @@ -545,6 +541,7 @@ func (b *executor) getImageTypeAndHistoryAndDiffIDs(ctx context.Context, imageID } func (b *executor) buildStage(ctx context.Context, cleanupStages map[int]*stageExecutor, stages imagebuilder.Stages, stageIndex int) (imageID string, commitResults *buildah.CommitResults, onlyBaseImage bool, err error) { + var prependInstructions, appendInstructions []string stage := stages[stageIndex] ib := stage.Builder node := stage.Node @@ -569,36 +566,29 @@ func (b *executor) buildStage(ctx context.Context, cleanupStages map[int]*stageE output := "" if stageIndex == len(stages)-1 { output = b.output - // Check if any labels were passed in via the API, and add a final line - // to the Dockerfile that would provide the same result. + // Check if any labels were passed in via the API, and add an instruction at + // the end of the Dockerfile stage that would provide the intended result. // Reason: Docker adds label modification as a last step which can be // processed like regular steps, and if no modification is done to // layers, its easier to reuse cached layers. if len(b.labels) > 0 { - var labelLine string - labels := slices.Clone(b.labels) - for _, labelSpec := range labels { + labelLine := "LABEL" + for _, labelSpec := range b.labels { key, value, _ := strings.Cut(labelSpec, "=") // check only for an empty key since docker allows empty values if key != "" { labelLine += fmt.Sprintf(" %q=%q", key, value) } } - if len(labelLine) > 0 { - additionalNode, err := imagebuilder.ParseDockerfile(strings.NewReader("LABEL" + labelLine + "\n")) - if err != nil { - return "", nil, false, fmt.Errorf("while adding additional LABEL step: %w", err) - } - stage.Node.Children = append(stage.Node.Children, additionalNode.Children...) - } + appendInstructions = slices.Concat(appendInstructions, []string{labelLine}) } } - // If this stage is starting out with environment variables that were - // passed in via our API, we should include them in the history, since - // they affect RUN instructions in this stage. + // If we were given environment variables to set via the API, add them as instructions + // at the beginning of the stage so that they affect subsequent RUN instructions and + // factor into the image history. if len(b.envs) > 0 { - var envLine string + envLine := "ENV" for _, envSpec := range b.envs { key, value, hasValue := strings.Cut(envSpec, "=") if hasValue { @@ -607,14 +597,25 @@ func (b *executor) buildStage(ctx context.Context, cleanupStages map[int]*stageE return "", nil, false, fmt.Errorf("BUG: unresolved environment variable: %q", key) } } - if len(envLine) > 0 { - additionalNode, err := imagebuilder.ParseDockerfile(strings.NewReader("ENV" + envLine + "\n")) - if err != nil { - return "", nil, false, fmt.Errorf("while adding additional ENV step: %w", err) - } - // make this the first instruction in the stage after its FROM instruction - stage.Node.Children = append(additionalNode.Children, stage.Node.Children...) + prependInstructions = slices.Concat([]string{envLine}, prependInstructions) + } + + // If we're supposed to be appending or prepending instructions to this stage, add them now. + if len(prependInstructions) > 0 { + addLines := strings.Join(prependInstructions, "\n") + additionalNodes, err := imagebuilder.ParseDockerfile(strings.NewReader(addLines)) + if err != nil { + return "", nil, false, fmt.Errorf("while adding additional steps %q: %w", prependInstructions, err) + } + stage.Node.Children = append(additionalNodes.Children, stage.Node.Children...) + } + if len(appendInstructions) > 0 { + addLines := strings.Join(appendInstructions, "\n") + additionalNodes, err := imagebuilder.ParseDockerfile(strings.NewReader(addLines)) + if err != nil { + return "", nil, false, fmt.Errorf("while adding additional steps %q: %w", appendInstructions, err) } + stage.Node.Children = append(stage.Node.Children, additionalNodes.Children...) } b.stagesLock.Lock() diff --git a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go index d7d94316d19..0afee4bd9c1 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go +++ b/vendor/github.com/containers/buildah/imagebuildah/stage_executor.go @@ -811,7 +811,7 @@ func (s *stageExecutor) Run(run imagebuilder.Run, config docker.Config) error { args = []string{full} } } - stageMountPoints, err := s.runStageMountPoints(run.Mounts) + stageMountPoints, err := s.runStageMountPoints(slices.Concat(run.Mounts, s.executor.transientRunMounts)) if err != nil { return err } @@ -876,7 +876,7 @@ func (s *stageExecutor) Run(run imagebuilder.Run, config docker.Config) error { } if run.Shell { - if len(config.Shell) > 0 && s.builder.Format == define.Dockerv2ImageManifest { + if len(config.Shell) > 0 { args = append(config.Shell, args...) } else { args = append([]string{"/bin/sh", "-c"}, args...) @@ -1084,8 +1084,6 @@ func (s *stageExecutor) prepare(ctx context.Context, from string, initializeIBCo Isolation: s.executor.isolation, NamespaceOptions: s.executor.namespaceOptions, ConfigureNetwork: s.executor.configureNetwork, - CNIPluginPath: s.executor.cniPluginPath, - CNIConfigDir: s.executor.cniConfigDir, NetworkInterface: s.executor.networkInterface, IDMappingOptions: s.executor.idmappingOptions, CommonBuildOpts: s.executor.commonBuildOptions, @@ -1412,6 +1410,7 @@ func (s *stageExecutor) execute(ctx context.Context, base string) (imgID string, logImageID(imgID) } + executedLayerStep := false for i, node := range children { logRusage() moreInstructions := i < len(children)-1 @@ -1521,6 +1520,9 @@ func (s *stageExecutor) execute(ctx context.Context, base string) (imgID string, // instruction. if !s.executor.layers { s.didExecute = true + if s.stepRequiresLayer(step) { + executedLayerStep = true + } err := ib.Run(step, s, noRunsRemaining) if err != nil { logrus.Debugf("Error building at step %+v: %v", *step, err) @@ -1555,7 +1557,7 @@ func (s *stageExecutor) execute(ctx context.Context, base string) (imgID string, if err != nil { return "", nil, false, fmt.Errorf("unable to get createdBy for the node: %w", err) } - imgID, commitResults, err = s.commit(ctx, createdBy, false, s.output, s.executor.squash, lastStage && lastInstruction) + imgID, commitResults, err = s.commit(ctx, createdBy, !executedLayerStep, s.output, s.executor.squash, lastStage && lastInstruction) if err != nil { return "", nil, false, fmt.Errorf("committing container for step %+v: %w", *step, err) } diff --git a/vendor/github.com/containers/buildah/import.go b/vendor/github.com/containers/buildah/import.go index d0b5655382f..961936dc228 100644 --- a/vendor/github.com/containers/buildah/import.go +++ b/vendor/github.com/containers/buildah/import.go @@ -87,7 +87,7 @@ func importBuilderDataFromImage(ctx context.Context, store storage.Store, system return nil, err } - netInt, err := getNetworkInterface(store, "", "") + netInt, err := getNetworkInterface(store) if err != nil { return nil, err } diff --git a/vendor/github.com/containers/buildah/install.md b/vendor/github.com/containers/buildah/install.md index df8a82560e7..e8713baf274 100644 --- a/vendor/github.com/containers/buildah/install.md +++ b/vendor/github.com/containers/buildah/install.md @@ -116,38 +116,6 @@ encounters a `RUN` instruction, so you'll also need to build and install a compa [runc](https://github.com/opencontainers/runc) for Buildah to call for those cases. If Buildah is installed via a package manager such as yum, dnf or apt-get, runc will be installed as part of that process. -### CNI Requirement - -When Buildah uses `runc` to run commands, it defaults to running those commands -in the host's network namespace. If the command is being run in a separate -user namespace, though, for example when ID mapping is used, then the command -will also be run in a separate network namespace. - -A newly-created network namespace starts with no network interfaces, so -commands which are run in that namespace are effectively disconnected from the -network unless additional setup is done. Buildah relies on the CNI -[library](https://github.com/containernetworking/cni) and -[plugins](https://github.com/containernetworking/plugins) to set up interfaces -and routing for network namespaces. - -If Buildah is installed via a package manager such as yum, dnf or apt-get, a -package containing CNI plugins may be available (in Fedora, the package is -named `containernetworking-cni`). If not, they will need to be installed, -for example using: -``` - git clone https://github.com/containernetworking/plugins - ( cd ./plugins; ./build_linux.sh ) - sudo mkdir -p /opt/cni/bin - sudo install -v ./plugins/bin/* /opt/cni/bin -``` - -The CNI library needs to be configured so that it will know which plugins to -call to set up namespaces. Usually, this configuration takes the form of one -or more configuration files in the `/etc/cni/net.d` directory. A set of example -configuration files is included in the -[`docs/cni-examples`](https://github.com/containers/buildah/tree/main/docs/cni-examples) -directory of this source tree. - ## Package Installation Buildah is available on several software repositories and can be installed via a package manager such diff --git a/vendor/github.com/containers/buildah/internal/mkcw/embed/entrypoint_amd64.gz b/vendor/github.com/containers/buildah/internal/mkcw/embed/entrypoint_amd64.gz index c2399f9e90498614417059bc4e59aa87229a23e9..5c5f81c18e406e2044c4037815a4350077b3b852 100644 GIT binary patch literal 378756 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

`l3fa5rJfib zRONVH&=dc#YVqGN=~fUbsg)JmVGLtD&Z!R3WL>Q z7rPns9Jla47}OYRhMd3vcD<@TH2+z99>7OimH6+2G%&UBd#2Se-VJz@s;a63RiWx8 zx7NcMblocP=eZ%zt_jvQ*3?$Ip<&go8w`!FwyWIgP}PL$aFr*12jJ^eh2a~no(|y( z2(PxLH`G?V6bSq%5DZsVhH#o*a;km^Fzo%naj&(#pSyv{wTnEb;Q_Dqqn`7C=l#xe zfA59E?x#HWV#j^N34h%4{$+>WvF(e81^-#^EFb2CD{8(yEDW2+y{OJTYZ~ioVU30jcN>D<_>uM~cVuYHgwf$~ z-dKB_J2o)E8}Cf=Y;SyELU{c2h&#DrsyAh|T*I%)WvdbY{VWa4D*SGwYZxxGhJo5S zYz;lJhBYPDaCTKttl>%4gElPU^IqUNuds;E+g0C!>Gi&8d$5Q6Y96$tP8wehbvfFQTL^KV+H^1xcguMr`glJ@u3Y9T7pjK zF5A1!wr{oF_t=4tINpa~SK6PjaREQ*1nzLcw>!9iRSk8xfRlqGU;*cO^Kk*ID(jZd z)C>3*v4H10Cp&jJ?o3?3o$fAgmiu+v>!b_l4Y+`TnmKF%J+Xi_B^PjZBq$c}B+Cia zhYr~%Txi#=w!+uj*23Xlb>$4FqHY!T&jGZ1hBL*oPVnkoh#BskZ#j#s6V#SQB&HBU zNNjhp=_OFyiEuE|^1f{15T*ZjsZD=W`^wvhAIPr z3xiJGIZm#^sR%jeg(^nsM!sr0Kn&wfFH{9>1l(@}=~@O9#&+85k={tyCL`Pll5{;* zg|y3Zo~p7k;p#d^{IAv($WH$SgFu?Zs8o8rq$d@@fOj5z&vPoAyp#9x;)~()aMr3d z^{K%BRaQEcii*kqY1$HC|ErMyL*xr&4%cpeEle}?_jt=YUanZ!p6pcPQdPO*kv7k^ z9sqiHZ2mH082a)g>7-zx98)rEq zAYz2|NMM8o9}npJNQf9|eI_u{!i5=WIoQ^0>kEO|7JQ&(XD&p{wZ0UXYr)5xE4w^V zbol{bNWL1Vbtc>6b;p~r<5P9Vm&n}HAopa*eX{lKK&^l^AmK1K!vd3Zx#O^0Bb1wj z@YM;3kmUB;?_-}>y?}FWpQ1dZgx5HnvFSD&*1R8(^s&E3|3xr>S&0Fma z8(kG%P}QiR=RGz|g0;q5=Qbkr+zGIA3`9fGi-TBHtk~ZI;s3y1hr%PPDi_o=ipKXm z?CgdXGt<%|tkV`X1u}uPRZZRzJNP5J`XxK?nB6$7diu|8>w%gEr!qJ)5csqg_>L2J zIOJA_{}%9m83;b;R)5?L{Gw`db;TFM)!zF%|TcbsJ{!Y;a1L1bL2?Lerpy1EM56;r(wraEk$Hm1>DQ9Y&s{#!Gq z#=4_+v}gaN%Ko=q{YK3&$NpHQ{VBKRNKFuLe%5f|!;>@-oW(*L|YQRCZQxmEY z`{;SQ|2Z4R4ue(SCE{y6VLxMAZDFUfy29BMtZ}Nmu(u33)z8^@$4ClU)z8VU?b!;m zR{$ib&Ux6tWM?dl4u|uweZTXN=>O;KM;&WU^|dm7MF`YdZ~s19yL916M9OylyMD`FZuP(NGZ)5InApwO^a5|1E1TXkTfop4ZSnE&zt#nB13q-aPRI+oZUd0V%HW(T7;tE# zv#I{1N;hyu(3#mV9;i-*QyUzKC@UvA^mmx#Yi#dq>`ubT+Y=?6UhIm>7o{gzsr@@E zPwj2>TK*|y=B%oycbpH~-bd_-wQh}5)8ILO ztoB~3o;aq?nG6kAI$mwX`r#D-p%s%fgnrG%CAiM^#yTh1U$DK#&?E%ZGo1Szd%I=r zcPi~(pyi8z*L=zr<8K?j0*9QMXgv+%sT0DC#N#O7AOeCB9JV(bp>VbI;ietki?{2zy0f&L8aK+{MSj&+0kgI1NrkWaMOLL-;}f-SeFO;6Bd@ZydI*-Wj#s-5l5w*j#a)4I3wLz1whKrE^&o zve990j5F-*$`FtUKo{YWPBk#*VOW>SijgoYfk@DCAFFa7ubTK&rF*zC4FCN?rSoKE zpr)d>roZw=01W3-ZuR590|W$zQR#%kwO+srghoTC-WwKzUMNm{G6-=Yr|N-ml?srB8C)JM*PJ?2eGsgCSC{;Kky+B2v za-suVcx|w{3ZN(KeajC2()J#4E1i14C}9*{5J6Nv;8snU?NnWBS2@GH;S+~lX4{J~ z{%vRYiV@QmXdrmA5+of9#L2lJI=&%^e5 z*yxVrN`QviyWnRa&;YQ1Z1@rzn4*aeFhn8T42{)*g=&6i*T?Ie`s3>YBSORN2HU9^ zew8x{hC6!BIAAu$Uu;i;&*am@KCB;6hx;%!MgT#L^<8(&Ea-6HYPUvj$MLuw$KsSq zJQsi@1i8%JP8#6okUiSCNwXP41!foLrkg3??@lHMBF2psf0N2cbjcvUzSUak+qQV&w9PI>0 z9;5T0>I}22`QB)!DsT+q#Y$(lEVv8`&bCtftOtU%wUq(DB_MbQYi9Xa7z)l31!u{E z?-EmUy?tBgI^1M;+KWB}lql6CrgsiZkv%cIJaEQu9oTJS3c&}QybAijRdV z>_E5zsN?Lv1_Q4LhdGnI@b80x-vN)>^a|{}a=Wk6871~z&Fdf{d-wGOKGb91S*SVm zT(BYtd#NH&Jw7vFR`rb{^^H>X)jw6~9ImYTdC>lxi#y=&AW~O3_JU)d z=n22O$8qe3dtg1C+K=}H&$XX(Fw5n^;Z>u3TK>}z((+ke*16Mlu5g^Y>xEFQ7XqjWREND0HT8kvdi75N z*3z2cG}*&(?MJ#bUaLUZf;$C-J;wTL2oaS)*!7lGBN2AJ0FmeI&)AAFn5@3<6%o!6 zyIMtjR_BskXX8$<}>YUbSF9v4^~P-y*& zE&$(+wsk|ep}wMiWZj4{6;60U;Mnl?aECLsY6^T?U}FyVMubLGRRW*y)ieb5hJjgL z?@X(lUh9m{x_bk?fxQ*5x&W2G2-p6=3w#d*QTxLIT*w#0AR2hJ7a`IHX$LU>jdrc) zJrqKud0R!@trdYgD(bx9&IpY>e=W-0R#EemUHKJUqSrB^=AMd5g6?O-oFkI22cBc3 zSLF?JswzUBMEO-uxD!!yAjm%O4cGaCOOXA~+&}~b$w`5Rz!$@TyTgII!l66E_ERB1 z{db3l2PXzcgIogy#%%;lRpE?5i32dsIB2)ZK`5#pKkN~=wk*^G4f|Wb{d-`f*h>}P z_uLme=X+jYcwmG(JW$!})Ldqdm{O2|zgCTWb-Qzxv(jz_R&IiGxeb%j5?B`gyW^bV z%m(J7=JQHCZgrmoPS*WT*js8@4>$t$YXSB{VSwCjbU@wzOi*lQ`#rH^Mba0DZ)j z5@_T);0#me16TzBto|VpeaobT^=4&*GbbDZX}n^7pgvF)SO7zv>RnP%0qgwN%D`VL z1Aniq3rg6uwMj%ZCNN_dMU;<`?Q-h{J9@i4{tnx@-45Mh zFTLJwxXuQW;az9Xy4|k2!(L_m07U&sUPCxgKYF}-$Ql2R?R>%xeZ~$rFn3<{y>`PR zcIcD9fY?nz`w_e9Av-v;Ku7NubacLRp|i~y9S~%6f_sm+$ZkB0AmlC$HUvVzU(O0w zg;q(7^(&==guczc-5z^~ofmzJ+-`e!*u$(Fop5cn*ANT@1NYct9|H)R1VnGK6S&(B z-DQvQLP0y_?G4rmjr*U0#UA1O%$8dBO6RvW_GYY|cS3dqSleNiQ(s?sz4NGhor5IO zneicKEHr$bXFczX10+%laIwxA1uXT7U={4h08|nZiyR2ga)t-%jF?7qp9D|}hVS~t#{S(Xto6l-i5-slZl5tnkU!-S%*2vOQTVomwT>RpE_{!@U#y z%rmU;PLR(q^D#Q}0^~g~^D&rtjTH`BzW@M%$qv}~9}lF5;V@+Hxxniljx_LQ;2p2U z3g1+1{neT1%!FAUR~@dat`FCRt7kdKK;fX!=l~D}0NZ)v0`&lGbxmQQ1>sq!eF-=f zHi{q>lbzuqXWCTY>+J9ppdLUK5kH25znzL6yUK z+YV0{a}yu~_Xjq}hVHLy7vleDyRX`nzp&k(+cUzIFWHqpvMZcnFWLd%Y+tme{?HD; zXdnASJMf|%t`L2jE?O8h@hXtMN0+T@3azU~)HSYbU1Qw9Whl#E?Nn7&)zrB4c8g_I zi)H?K6@aVtu;V@G+J|jtle5!(QhwHAritFaU>p1d(Ley!e2Fv51_Fq`?Iy1}P~kPY zV?3A)h?$9s#84z$14!6)T`ve+d?kG6yOrKJ0PlKtD%5Z+fO*)KwH+HCXV*XuksC^3 z?%5)D4dfoDa@Whe!Eu4OKs`t7pM-v9qiP_0ZP+>t2zcxX$2iBV2sDpzM$8M;j&(-W z1;&kW#*PoHI>w2t4$K5haj|((RamEY}OoBX<153s`BbNr&jdlX- z15?L1qo)OcogNViRE}^)R|RH_a7N5@T1Plz7C4&%Cpq4PO~I3u_&dgaIfUZx9`E`P zsvxF%e+VgV=qEMLsUFr^H+z%45#E&Q)4e?<{}=Ukd#8AtR?h-%eBzqZz2MG*c>P)p z)<4}@0Z_Wxu6Irbh6?}M;Wz)=Y7Z;?-UfN_Z#Vp{hQEkY7ntkK^QJrF10$6x?U4Nw zTT(<2a3{e=a;(1t8gx(z0vl?)GpnXmsKe^RgDo|;KXRWF^?SxzHXM(G0R*tl82~6~At`57GdzDWHYMuGt2+jtkV>t7|?`UFBA4aQzI3z^Jf$mvbh_ zYF>wXyJri&+O;da6M&V6{*APp$6V_bd&AQ3GHKma=J zj|AQ4f^G}^-s9XH3_cmGI1YYy**6EBCxh;Cr^0oHIn`@ItDTUyY4il(sn8-Z(SAPY zz8nnwH0Zq?gxxaTO}b~fvpvsV;?%i&y)AAH#D;<=KueX+1%m-+Watk;?{~qf-v`~- zf}uYKz1M>7C{^y!p!aIfU0nSr=5QBPFNMvy4(h45;Z)V*r z%n!J9Ufn`(LDfQcL1?jeTyTkdyt~BpyyfuUpo{3h^H#fU>i60}t1Peoy!Ep!rxg|~ z1dG&Uy~hqc8gxDttZ8tapk3p*BSFL;Z(DY&1tN(R@*KA&SmD%%plzTH&Uw}!>~}q8 z*FFwX382+6Q!71KwmJuJyFJ?R?sjWG?ApiH0xhx6v%K>x>s?MQWOY_q^^>o+!`A_$ zbHonbZU^s#5)N>Y?l|{rcK8t+jjDlQl><1)0yf55Wmy0Y_He*P)p0fZ{ub{b{|AVyULsCo@6=et@=4)xWlcN08@uP=mgQZz`;drbf*EC z{kRi;*a_4IDp3frhrxWUx4iWr>A|4K!k~u>uH!Js08b&S^StvTNBx-eoHNm?pA>8g z2&;18FTldUGGA}I*V#3}xC`9Ort+yUuaG>3H98oWoAw zDaX0g@h)+k+Z^v!$9dEC{$V>WI^GX~<8|v%nzH}xxQE=Dm+ZPf1KtR{>IB||6=|q+ z9JjTu#eD(jXW(OYAOs80TD2O0%?_*yw*=~{9q$&W<|e29OLoH-?FOd?h5k{~oH0)2 z130(gv4Q*T%6nn&EErWkEbtNAd9RHo`I=)#gTU^>A5JDP9v*PJBOkJBFLf#}aoVN_ zrlA1}R_lJd4%+=|p!W5^aTS5ez_?LO;bB#ws<9I_U-lD0bH43(lcDu-&KBoKwsVa0 z8QVVA8$WC!vS!!V?&CqP(Xu9?(iXOkBNT4>FTlc{T@M=*D2-hQ3)Tz_O(3+RvZg{T z2*6y8Q)!tdUg+;OXma)NW*k4AD-%p%WgoY3|-RLjZ;v$_Hah7Ih>ijaD zmcoqw+5;Gs@PBs(^do>j1tfHTgn{o2=<{)Z2Gp5}lKQBJGJ->~tP%H2MYr}9sp|x; za#(jY&5GJocR)Ks zjAcOh#|~e%`0YBBK_Sw`Y$(HsH_zuE+&wC6> zrfUWybbXRR&BRYri;$r{M%|H*S6E0;V(ps*F`y2fw%fuDUfc?MwtF8y z>o42(p7~3&_us&qLkxhjrS$UgRgZG79hU)F*3!fkvBxIwXeQJL<46TEeEXVn)bAV!JB zG_VRJF$j8Uf}L8n=At}O#=n8>P6q;Chj?sV>n!@F3`*3=K{^*qnjb9rt%-FFBOIH=z!(2{r%ltuf_t&dV|=}1A&tyjiw-crjJiK=UwG#Ob$qk~A>58A==*5zI9bJ#X@V~rtB zTAyOJ(C z5FU}<;3zYPUh<39`1%c*1tgaPy8_JRFlC~dbTr>I-UK#n+GNs1Qc5RQC#^{bHQms>nmz{XeP&W^4x23| zhLdgp`VmfSrt9)aO%wH`tI=CxT1*ptg1VNgt2kWA!|Qk$5=Iu2&u=>071@nF-vTte`Br!eTc6Q^>v%y zsxR02M|!!hXEshQLA{o!3TeLN>^qLr*ryOKK{3;Bs?e83VUy$GhRUDM(hq^VgQ0&4 zHZMgy1@kko>2%cRpps)#pCE#m9nH%!V_`z^S4e1h>Ig!;GDhOZyW^d9MEF=@2o{d3 zMdtS~jSu?72b<+jMW;X2V$~+RHnvtq1tg+i9%&gZG7}SYrZzK)&j|ldA;@_&=P|*G zCN?RKh=t|RMs!fq#m%V>=ob1_qZScy7~KH$Bg~sK%=4_Ns0-Bm4ptmfmv6pXYg&)- zcGzG}VRqAMnlyj0`bOTtQBFWKB}foY3g1zMx0JMaM!>Q_UltH1ygU%s1nKmEnbuKv zqMMvMQ4c>6>i$Fq?-1w_hL|3cT68xw zj_l+u$?|6ue?h@>)LQ%_WiC$?7qMjOm4tJBc&LvGb*|40^*JH&&vQd|ehAA#esNf6 zcuJc`wEwt<$E?wS>xZ@0{2#&q^Q{&$ash>dFn(WjtS)3*sCW~=r!{C3`yPi{=-8{$4?w`mfMH9tda!)pC z8>@x-XlD3gftX(MxoM>%867zWMw`WZxR4)f_(=wiCsfWaHs;N&(F(6+`X5p8-KhDU z$b1mBa&uU~7Y8B2;emJz<>SbX3d(;LE9<*(cPPHg@M^*C3-SJNm5RSi;J2B$S&1u* zh?VyLmGS*^y(NMF4FqFj+2y%-EvFV3qYujQ(3~FEXn|r=fm$FhiX=HX@RtT~O5j>x zNnpKA1DWn^Si}qq`Ugk#GJ#D_EY3&j;bTNU)fF|xr{X_bK~pRAYNPt81tJo#5}03( z*YQaoj2YF@vfk;$7z8i+KIZ;JUX0ly=F+vwBz^MN^~&}g7< zm|mJRUmnVL0nh} zcA*||V?kU~kc!P>Q^g@hd}OF)W{OJ+?6QK7kvk%M@um^S*)kt)#7Xp9N_DKsPBQ-1 zbdHJjWRDmtHmas0J!!NZ9|--2LwG23?f9T=W803~N9_@d$Bd3iUoI_keiHfmxE_86 zI1xJnH~xG!;wuam{6}LFr*GC$*+>s+M%5CotEd@6Mz~={fIOjQEKn1cY%|8hqB&z_ z+8SD{XGR`p(M=;wdl)o&+X1rC+Xm16uckH8oTSm)#At8ZdbGD0*TCGg`=mut^P*{U z%^OP)tyKS9mgmH?f7WQ>Bf-0>oPQkhFGBc~Duo{xnTLvv7QVO0x&K(2Jef8>k(y^y z>VzLh;**Fv;iplf!M}(qm*|mBNHt9j{#FrB*Z)r^T%z&KqM-&~5|JLD{eKksyG66D z*oXi&V%&@@mvO*{%5C+sMB`1PAf(`Z6#joKRT^(t<70G7okXOphH_K5|hTRd3nl{ zGBxa9_f)SzB299o}`-0u@@%O4PAnM zjVqbWi0Me%^y%KamHg6}UlqgUR0I6>*nC@RG^y`X3)~xv4~ycXqV4YyHJ!vJ+xss{ z`SR39k;{6gnI>9ow@F)wkeZWI6aS0^PETBwo{><6zEf6Tlp~%$6pDvKr1huBpH1Ky zy2QUX*2e+9rB5I8A9lt)8zI|J3h?f!686-Y4`9dge_Pbw@=$Qc>&6 z#T5+9=VftdMObz1$TB;kj39XSbt(9+1mBi8MjUR&_+aK=E#MmA>VHKln@5oVEkM%0 zl;CD~uMR z-xi|A6YD);4R1$-Gq>amZOqj^@N|7#O{*R?e< zxkxHh%mYl%V`>>IVC|(^_^>)(?Gx^v=zeYM zEp5w9Oym*CrZ}vcDdOZ3KePmgl!#p{E@c>SIJZWsOMGFQm?CZ~iC39;t4VSHou`W#X1w!P!<`y-ePY#qYWo!B2)RwfR7`ErG&G9Z;$P`Gxp;Nz&2El zCVqgo0HnAaVQbIZ$+4vbTB#06wYIK$ergK-wmMJ{GSOMGYx(KQA~x5US^SlShb zw3w4x0xY2aP8%%c#gn;sug#iJeePGZ7&X8@0ai!&KfVcb#`g{I$JVL3gfY}eOHSR$ zV!tHv2O+koTQf_}j=31yy|>ZYFq{u(#q)}FAI?hss^-R3-QIyrn^OI%swGu-RkeQA zT8*o+k3oF`)4eB2{q%1^bt{IX_B7S+q5_S>CUp1JScOvqWW>d$*NOYbbtzN%}Zb!*m?K6LGJ;&FvPfXZuHdeVF<{F3))~y$9 zZ^uPqx2~?-_qGlP*|>BN$JOS>^TN4$-d5hTsAGPRbc;w%PivL3M^GGZ;rYBCm9J+qv8 zJy)`H!%-*PMrm+v;z}~fyNc?XKPuQG0*^&s%i|E0ITG~}V!7DRPw8bgX6)n9~cQ?-fMRBgn1SSy=qriF)behk+~bE)|e)C%Ho zu215kMKlY+q_{U@*Jmsfn4Zc5&ClStnV69r#Px;N?+%=Sn6?UgxQ)r0$-~V^GK3+4 zk(53z!x=m%r31=-_j3edt^tHnvZU9C&7AXWPb>H?}2j>%qZ}aX2`3T$~m1cn~D-lhkzv*Awf{ z=qR;s(2=%7hu_}TA=(EzOuM9G-E>USv1U4EXh~?9pOx~Ry?dp`vW%X`>@wgoIE3R; zu5^f`IbOsGJYHz&U#g2B-T+SF{Ch6<;(O{?u9nXWK1T5gA`wQ)3A%44FXaY<^98Z< zXh0V)66taQmk9qHQ6w=TE)e1@(HvTD2XPTKg&^#6w{Ukzzx7;uwWO=h6V_HH&KBYv zVNMs~3}H1P`}=Vo5-X{oJk6EKKOHJ)|ETAVDcO#3I}zjO!0!Ou71rciA)#^42DRV< z;+O9u+)BR(c}CTUI2K}A5V59?+T(NopS z=whJCr%v(=;=8CU>yhc3C<>%YzR3LVnXTZwRlaX4>kLViC9|_-dY*)HrGJ_mRXl@ zjjBbz5BzD6MS~{fS4e(62}-z5>dU3gETK^rSb2)<xwR!oV7&nDp#A(@X&GH)a*9_Jen#<-5dy9>JQ4@cCUgN8}$n`f` z)WneR*)kMYAYni*KMUEXA*1!Hq-!=`iKMpjSCPM9W2;GZ2fD=A(#aa;7nt%n#tvQ= ziP6SdS6Gw0+ys}=v0972iTbx@`;#8UIHM+Zv~V8L!Z3d4hFrTzp?$^fx$vu+jlp)J z!@6eKZ?u8;+vxxUe|{JQL)1pY-qxHXXW|``@kfjJNRh5dZG^bT5h1DTU^AQ!wkfS~ z-Y#z6xOG0a=xu!)dRJw6JS1HBgz#ZRJWd^v$5_?X3qo^YxEoIh&JgNUTVQY0+dc}uj&j}) zefTm1hrWvJcoGJ?A)sPwQfKQ_jMd3`0&(YGcLc-&QpW-UVhJJrwp>}z@3zLV zs&`jOhly`P^%xJX&BS$?bvX=g65y=%U;_f0vqHY9x8~7 z?bT1%tM4yRZIcvrNbYc=p4)-%g*!Urh2Nm{e;1B&s6&c*79A7!u$&_xP7;!8Ds6lb zaql)-0#ov@3{dy1?#%Wyf*t z(pqQV>k<1l-j+>cNpmZAx^?1RL*f(mwV~h#Ly?dm++|16!(U6^A7R=XBhhpRABF(@ zk!bKvVw9n(_xJ5?ss|V^+OyT$as~7U1KW3oU8kbAoOHM@Qm&0D@jUX2RhwDi1{qu{ zIVsA9wDm+<*G$brnIk-k;eEtaTM70WUz7;{8vGK1AUZv|ig+w+i}ijD675Y|VUhK_|nZ_C;1s&%^hVPMD3 ztZTI`YdQgQwgs+Up4Ega4faHeQRR+2>#hAyQ;Sd1dL3$k0FsyklA z+G}XuW&SfPw2mbu)0wsAY;*+SL}t~_?eGe$4;^&i{Rp!?Z#DtME(F+7W@0s6Q-(Ur zuU%2Ef~#1gW5jW?Dc20x@4{j}i>QFnvjZoM6G_$}A!47$=z-t`ObV38B6)+FGqADs0llV3yd z9Y_Lq{AlD$ac#`2qi?*<4OLFSqZ+KcjrH+;J#Q^)LXr{e7Y%RvTUjGM@LS&4iC?B0 zu7c8jxIYZfj^^NOJtv$U%z@d-h?%au`X*}A$ej~&^lUaK`LFYfHi3RQko4yRW>efm zZhAOtTrB8f`!KP}#R;7o@10LA*PFKfJoGR>Kzc=0@U~Z zXF>lZ4T^IhI@`McT@CTdIM^q&ZSr~8jfVlO!~c(+&E>XYQoa3K*;(2;QX} zx!}wR6(F)6v3C~I_Qd2Wi^_CO!A5uLCRRyWf@WwLy{dIlZj&Ma zDR=+4kN28B*&Fwjdw(#H_pdpQo-_ujV~Jrl6ix`niwUDonw$(rL*whje*`p;O&ihQ z!`3G`$3WAUNfJ>m22|XF{2s(|`WzOBo%{uh52GT*Gc3zZayDv&zT8<(cft+88KG}= zIczvF{{kppU<+3|*EamnHjWo&^v-NQzCY~XeZgX6iv>SS*qBgfC&PeN@k%S}4iUnb^!)R5Ou`DUe1I77~)0ihywz z#r~-1dESYhhf?8_m#d|e+>)Q_IfHaFjewVp$^b-55iz zc|dfcOHq45JaLe^a#eQl0L#s5k3_7Tz_8o%P6qxlu(fT#$_aqW&_a8XYCL1~e3va~ zqDvNZ9M+t)wmQo>#*nUFL!g*B)QLcg%B;JrD2> zB=3Us-Tqlp3L*%-Sj zFRn}su#PMG#@E#SKe%0ceRqL3P9q6rB>W<6#wo(ZNSL|~2yX_PNoASSxNdGBnTP5o zr{0C_Uf%`G`ymO_SYjbDQ-VYUJ`RpEV+4=Ql$vQq9>rbSfE}_;sD4SMUg@%X5VJ0s z`{4(G&CGf1uEEYkKDk~sk$cNjx9(op=JlNn-g43d{UYh~<kYf@LCCZ7Y3gsgq5? zaagGjP!#c3^=JLiRdZk4zS-|L_U@sFgqoklLJpB-=MYu>qIr%k+T zTwB4RVaGw?5Zygm_T63C2{<%~wz?1eFYDP9H>snrZ5;?(4tr8f+>G9X1ilP`J3FF~ z%(1s$&RyLbJ9A4yjFl^q zHc17-B)AT!rgH2n!VfKeTn^S>ti=v^VAi1=L{e14h7{Jgo?K8h5j>$kWuZVl{}sFh zgg29C0Zzc=Sd^K`N>ISzF?li?^m{6|LBI3yR>b3gxuD-Zb~occ@VuE0jb3RxZlXvg z_}4W?@78iOyq8-~TvYU~gX7R!LPZQoklEB`QVA3AxFTvc2woB|B8kU+ZU-Rk$O8SI z*p9gv6;+=(bh0)d2NU=hm{|9Z+>q_g*YdDJ&#!n-Lf}*k@N7EFiYrJu$=L=rN-VY? zS6G4hji^>2zY+KJp69uQ(|LXtS7&k}H>>RiJkU*|Ae%>Uy$^>u=32l5!20QeGpQtt+#Xr~2{? zpGzOxgx2x_DIb*)4=UkPTs_OfXf!$D{a|z3U2SdLE;ZqcV6%}(7{?`>N&0+`R%()S z@_dwCjE~qb|u5vc3ZVO+oQDmk+6qPKWe+LyA&&@ z;CgNiZk?_jt%YlgwanUVtz_+ZEm%7p0cE>4EyeT{TmtlgZ7Z;RBQ8qgq}!za<=`Hk z-w&geFG%>))6+{Jqcg3$>pjpdK~LBX?m2IO_ntpykWYiDq&rR<9>XWWL^YQ6M_f-T znn9cr=qMfIkAp#y^;{45Q^t+Sr@*(OSoYu0X@3+y%2$KSReF``pA}+zD0nNk8O7w~Qe7i$ zKMP+p<=3n~FY(Y>MjXe8zK>+BbR`_5(xX(rEE{8u(LHdojXDbCFL9a2&sb z{1b$aZT7H#>HNDueH-xa0&%d*VW1Acbz0ydKfP6ECoxiET&a#jeXNbM(kCLGgjO#` zI9`QI6};@HulWO?6VTfmJ5IJVV!c31a8YFG=5g!FMmpIa;AYNW1@NNOu<XVlXGi=op33@6Q=mI@!t>RmiTU9_7XafCDJezp+~qoOdkx5X(x{3FSD%F z5=ICwNXy-Z@GsJGw<=a(KF?V{K>}jUrsn72!XS>bNT$`~P{`x#cg14CZz6_Ynomt# zAN=0#=Op}6Z(L;+{_0Z~U(GuysXP+rPsZwrm_Hf&n>m`^qHMEvM9E0A{LU7k!hgyV z3j*u>)u&RdR+p?t*a51@8@KxpIyb6$-^5kyAt7PCyVcRA^B6;q(30A6MAdivdV4#k9-ji6l*7jBgV)(Jr%w78gOSzihcuTN8lZ z^v`;lH*RO*ZJNIEJ|Kp+0>k^j?B2JB-u)SHd@*Y9#8E|c_cc?M^sd0R8}Tfl`dGt+ zq&d}>bPJN_rGi^`YMXtl15?1Ubu~C0&=YY|G%=fmv_eSeYquhK?GB|3{|mj%umON#4_F)`CmBK&7$_GO=ij*-3| z#&3o2X81pK(DT)F9{oeAPo&bV5*|t09#5?cn@yt@(O)wGlek#=yw3GL!%R;M;nFm` zB8AJ-@VXSPO~Vx_p9 zdFpiX_Y(X#k)S?H6q?Ty{31cO4mf_D;5UiXCqV~kZnCuoOQJ1bZS`MEad-BIa!6(5 zHepEDJ-%?bieZn-RxPZ>>~+8VhOhtb$1nNizx%Cl09f^3|5ycDt9JCIW(4+`FdY(Z z$xFBA4B^kYT9H?A3{QEtk1d-w562;|(e=bku~yP8nu#xCb!ZYElBffdnOL9#6n*-5 zI?a>UbE@e#a(F$rWq=o)J9 zB!iPPD_34I@Un4@^se!r)JYOOWeP021oA^*+DNGX+f{37{|z1vcs`I`cRj#GK3|jF z1tcdvMp}I$7Ds&ZEbQlyJNqeG9BHz{2rgJ0O0i)hy|%0f)zu-LpMn#|~yR ze$R8iC+?nl_ZRc9d~(1q3*gd#K=5Tjc6Jb-7r?o7U+vRKJYiK%3AL;WmR}q28v?lA zUU@?>?~)*P_k~#D@jZduX!H|qNBaru@^x@F?x*PRK*P%?a}g!2Y=-27Hxe;V#|rdB zmDazmY7+@|WZt+nyswID)GIfGW(#R-D!wKwt=0bcA)%t8H|{)W=8K_@YiYM-{2n9w ze#>yPXaR>#%SJ7z%~uO>gZ>pLZp77`>=xY~O8UParC-;m{FTVD?Og%Mm3(b4m1oBJ2%DUVF{VlLjw z;ihu=)^fgaRl7R~U3Eei@BCn76yVXuC_sKJB;L4f zh?xd94Fqk+Tk#c(ZqZ{6ziW2a#hIm%)x4#Z9&1pPvP;_G$G=H)uT505OvdL+(HR^q z&2cghYY1nSEC)R4XX49+;<6u!Q-03g*iqc90+KVNeR6fTvZnBb@I=9~%o8ebsZ3T# z!T{s*_GE-u-*F?E!+Z)(#u}aktjJoaw4N)i_3e^|Y6PskFR&w7j0qeMX<*Z0h6N}m zrPUf1^Jhjf>YXU8rF`6X@Pqb^z7*bTO*uwV$$sNY5e}xcnj9I;2I&zI^i#rAuP zd{&#yHz$oQq1-^=kFg|&c}7cuncv}eFIbM-vRC)C}5@;#}5y{^*rBlK|!>Y4_=E&ewYxS~QQ)@ej`J6A+*D{2TIvSaUmtk+J?USzz_I!Rc=h9;R3C|3hv zNaP+yKp&Q5Pz+p7mar1G0LG;2(0+RlNv5=W)4o+?Qvb9%-@gGGHe-UZ?XJ3--TJ45 z-UhtWs<{kf__zD8?^~J>uD2f*zSoix#rCiW106h8R!^1{${?;rBVX_UpteS+DR>Bg zgvi@L>Jnu8qI5ZA_eh?ol9)gy<;nj|6iRm?I%M3e=HMai!UIixB{smbP^J zskgM2Thya#cUHw+RT7MkRQ-pm=7Fktu$s^@AD^xgE6d@O7F+tIHJ^A#NF>|LyAhsg zvfpu14KBB5(`(#Wo7S*m&wlLAUR;wuGOL&zNkVkuy2N6?bq1HY1YD@w0-!1XScy>)60-)B{00*ZWAxmpa1AfE*L}niyY!F*$P9CS#VGgk4NZ2%QbB zQ`&pXI^%th)+5dC50R?1J4q!bc^hFv`qqxRQ}$YoAnAT@pN{!#!5_T)Ax3r*OAY~c zG+K1z=az4ABMa7++CKs<{%8j@XYv88h<(=36^J)WNs0L(&?0t%%^935UXjkT!0#{)H{B5dCi5V~f%;9~ZRF_ZMvB-EYme zCn0?+0d>@p%fMzIh9js9{?5d*jV0F+1R#_P=YSi+0+$u?$9MV7tIeB7}|%f;m!%(+b*o% z*D=Clpq>SI6ZqRUmEAIs1cGO=iSRM-&+L&aL0$#858Imnn-&jBex`)8q&i(Toh5@a zB~F$*NUTj@JVv>b9u|XQSd2HzrMN_z?ZkS*MkLsYA94<2eX*8JNkea5U#v$k1N|o; ze97j&IYS1ANH~;GGa;+vWxf?v2bF0PJe?@2-X^=UX?!j_1g%|Jfo+mNN?|h-1V;KT zArA<52TfrR>_C!wQ5q&D4kCz$BdR~D*nP%R)c_HTCTg7O_QeA5mhvE#(nh)J3Twej zkzYYf8DNpR3N=CgV*nynj<{~7vodODJvIw5-iQ1_gn!a?{84L{r5Cu?8*hzF&P_*4 zCZ-yfv<_)qr`uzoK`njWK0Q>91+E;vD-(D7askqIb34S1tk-sy%OD9gb#R-%pP$J1 z5(d{JEYeGv{utONHj&n;jGw{a7CI`NiAe&cfP* ze}tKK5Y+ao1r`ChES)yelgB)=EJ!%9KrNTZG)rcBq$GL!>@+`FQ1TwP(*mra)~3^2 zwc7Ek?R;e0W2tg5K$ZOkk~i$bA{j{!=q^r+=WK<%kC7rxotx`K)$_0uS6gMQ|2LLp zjGLb=m`^mD(BjhzfwmWecd*LsoEX1Xf6$D53)y1Clfk|I4AMB*nSj>-F==0X$zf6W zyu~gd=i+z)n}u)NkxPVs(V65G0WXX2BO%*mEt|`KC;qe^=D}!O(SvAt&}%?M=K_kJ z14}_(i%WBrkw(@h2p0?Ecy;U&i0g*@3=5sa*X!9-E@MgT4VP=>YR@l&y}N1Iwkz&@ z6ujTYss752T}$<)EMxo~4~`TfC&4e{PwYO_NalCU!{97GKH8t?ywdulO>k1CzXIak z(a8K-S28Oq=`i%j00e6@0f5>jjDtt(M7P~shkv%&(|E%-gZB~G*hU{aYI0(Pb1)a9 zGHRJq#MZ@KMzpKJl>>I${S_7!z2ObIpjoPitY=rM2!PR^t0O)uvz1bZRr38QQnQi|&}P zL$dZ5y)zmZ$wlzF!m{VR3;Zhv+w$L&);(a;4wTvF$|fr=zz{F66M&?^$d}aBg?Ag_ z>1lmaK9*{Jc$oP1x8PmD%7%n;DDH{X-EkBoMmScQ7gG|Gu^**&NWM7ePataLvN=R4 z%j3-|V{p`%zvQ!U0Ncf6i#ROf{I)SmM(&7WwM90!?(no@+G{jNw0aqZivb54fDzs0ssbIJ&OlBEnu9)yKN1 z&6&0JQl-b0T7JO(W?*4eX_&2nB!`C7LY)C~Hg`{W- z!#@<8oniT;O@p(|Wory00F=q4mJSyTD@Ubv&2)(^1nw$>_BdH&WS3w-=62r+3sikc17LlBU zs=F#8F&3*)#Hc6mhk-u>>>Fes66Hj?r$A@BL_xF*J`=NVnfQQB!YoKSBZyQ4e*fqg z`H3z8+yRU?<8N)oq`yNwx79g-*9utZdG$(g6DuTyH;3u7&j1p`EN0OXNJVlkG|U$_ zz`t$v9f!QJ{flhu+%aFGJ?;allYmDh~cz%|7h zEo-th`qvEBfHgVCc)x{}VRjSKSsalx3zx!`}C8{0US{*QC>ya#2sOl2z-fH*b5 z>x`BZdz+~%PQvK~MV>_c4={&GSfI9KcW^n26wiNyIuONnu)W=Tg8+55qu4FW;R&g3 zm#UBN68(xbV@>cLX_JAn3uL%l`VxobfVftw_2oSRZxiArX?`zyS*oAl?5`YSKOy3g z$t^s%ox^SXe~$3&&Gt3FpBd(aBN=A2*f~XnET=xg)hxM=>Dz!M=3$Uc`Kh2^6!f+w z0*@8q20`!YFxPXolw+Guw4&4G6ds($;ne^AuCt-@JkS>@dc^G#ZK&u5&7<9^jJ z03~pCV5QFEj8DZS0ABvHHw+Nbu=C7no!JMUw?{R06J&*&wC zVM#nduxhyMJCV7v_zgU1MH-3@~%k4h;`@ zujw+iCNY;0zT9L@vSnwI9bU(KPp&%tS63kBH}r-JM-qPh*(ngi+ueZq^_bs){Bm@* zL)CQyihqJwZ*!vdHSTauRyf&RmC{w$V?a#YUtg_B@OTI*1@vA>L-~n$Cy#wO=;@z8NK^ zo5QsxUt!W44Zp$8k0IWY{@=K|pW`h?+-?dszaC2wF7?AJ{18(vCp*g^&t_XKcWun4 zk7|22NtaC-A7Qu!-Uz~J7aOr}g*}+t$&2_ZmcO9O@@%zvN+c1jQ8ZA>CYSS4TIQvo zNmP8U7?wq8xFu})OIqByCq$Wj34R(*m+G)fu|$O5RmLj&P7~CGO%NCgDn@J8j1R!*6$E-|y!CYd3b_&*6Zdhll*~SAo4N1&$bNLi8_v6QXFwF^>bIb2 zZ(Nt@)LlKDl~q38(Bju(I%{aD!;G4DV3^;tgT8YIENXyDlqI;!M9krRTMyxTflA`^% zd5kL0uf#RFw%NFGB)Yz{<_39><8QNLZ4&!)_#L9La~nUK6MpIKlAXpO`K^2WZtMxV zQR^D-CfwRiLcLkmTIV*+w?%~~QR`Xhmd(PQF8>6lV?}(@s^(S0@%*`j<>JP^m z>b|m|lhl{g54Ft_qAuqCGLBdA;7X1!TOWXX5`GKEO9SIJEWsZVI0>7puH;c`Fq(Zlk3}Sv2S%=2U5x)U!!{4wYY^(wvWgCP~VrxP> z9sso3#op0Mu=8Ue{3x#g@qv&hFl!Z-V2Jrhv9#Ii%BEH&nA{pR1zatM zvM$xit)&w6P}zJ7)MWJvY)f0AEosd=bUSq9?Qs`#!y=9hI>z%=h@hAkTKeeD{RMBsc7OWH+F3Ya3mbIJ>8@1K>Z*Bp1F` z*r|D$AZ{u$j$K8;gsN!qe*$^UTGj;?3~}^{Vu4sg4o9+MvYKV*ZXRHmnPg*mv#9zYp-&}Sf-`& zbzqti?#sgKQhzB}mv+QVigQ7oXD1vY1}1pyld@4UuO{M#*xrrUq$?cMLb0i^Gm%^h z;yj>BhQx`$?gDD5sdz|zkEGGZ_SrVxmJmY3<>yKCY}~vA#Ni-z5x+7+eAwKX>Mhy3 zNxw}zL!GMQU=X)}xXWh473-~H;XOrLnSU4Z$Lv_(831e5Jz#Ubh@GPN1ka;S(6Abz zh^i(KC>GFO8y{r9H=(~f?f;xu@Bok4JUiEK)F9eI5vU}zDOl&X%p-`?cr+&S0s zDQL{Na|OBKT|4YQj=c#N3DxX0_0DZU=^H$wTGiQYE;i7`JdmhT(!jS2h3+IqN< z@F#M8SB}@`E(yWKIkAeld51_e(LGDEPGO_8rxmbux*?!%@?jY ztjdE)VyY+=pDQpV%@z5h1$1d(%yR|(K|v(=L?ODNkonnDCRt(HM@FvC5|));1$YWr z&)kcEPqSRR!gt4y8EkCLN*QxiLF~>|1yPo(3K!cK`p;S=d{NvH5&DT#97Xl2sGDd0 z#zx1dsZGC!VH-(Y8Dhi!pd7~slW}b54e*Yut$A>DzHgsJKYN|;|#Hr|9iJm@S?NeY={M!_w(}+zlqSodO zqxB+Kf!-TUInO>7{M{VG_}h?r^MO(L_Y!|YN1=I98e4`53Xgu4FGEXA_ z(axU+v5n2APofiI#(7BMvtn!tJBuNhFH>p_;#iz#6)X>wupF2Ca$2gju;ytsQDwD` zYI7|TQE3G>W@vq8Bs0b9Zfe$Pg#U3S)ny0#0)04@c$m}#`nXzPCly!kGVjsm{L{GQ zYMb?d$>56^Uyqfh4kF_x;}EBlaI1cv`CnwG!UF|3h3mH}Wt{$x3V*LMQ~Q6nhu9Yt zqp8%I)W7Z;%C3^`<`@X#%Qd+_VK72xNxPuainsz%5w>x;`P7kGdPdpAw7D-&yc=2)eaJAeF1tB1d-fct*y-^?Mo!|}k4eLQ1 z7Y`PRuGp|}G*xkPTG=7qIkfHeRsBu#o(K3O)cX|)?1zb?ZB0ZD+-J^TouIkPUT1T##(tzyo;(J5mNgem!B~T} zjT33Uv)*+!K9()CmeeKK>}q7Rjw-JJdl{6AZY{h5f!o(^{dK+8!2M|Po~FJk054U1 zg@P~9{|4b}^q*q!44cVo}yu7p$gckZx0JLVhj^s+$8*T!?THr!FjyhSAZZ(_OUiruf)su<$v| zdWP_kYO%hKJ_}Xg$98}~WkFFDbXk?Yh9(=jAga)&T3Z?(OLvcWEM4Pf1)W0Gv!nak zAy-N5Za;e&;*m;X?)d%qGR%L4fSWsWJ^V5L6a3M-C8tlqOz#RmFPC28;(ZdtHgjF& zO0BNaEgiZuc!u*=c&u0lvEN6udQ@kR==dm~9qB7tUoZFyG0jez9J}-;KayJ}M5L-D zV;RX>$xhKsVtB9X{V`9orq_gJcdv{1EpZ`Wa+A-|-0Z_m{z@;|^aLX>h0!UKPt?}8 zwI7d__!KZVLvjgE(e{vl=>+122t%|J8_Nh6ser{QVnkH;V{VbA`)fW8YH{^?Xp2e1 zv+kp5=gd0zo$s(OUuE5J2CDz?7Z#~<_wDMZ-oj|9bpD_Bw#mz(_H`R!bvtB7e`QY6 z!JvLXl8VaXB1X3=c8g*+D|VA=WU;@CR8X|@4g@0ivxHlxG?IOZKYf%;&T(dxkAZYA zM<&aOTkVU8y(9C!xh(Vl*T|pwuaWtblE!w+#`dI<6Mc>CgChrWo5pwvj{iYN1 zcR>(&EQrp6a{U*rf6%#+dKa)iyc0_A!t8z=puWXcK={jGZ!y67TW*B#6(~5eqPxW_ zz+HE{6b?eMU35N>aw*P-&Sjv_hte_#&IecqqX{AZu#vYSAXOrz#y%`4pC5=9Lh)%R zZZhf^h%WO<+LY~~S3~hyC>|?xK3-7&4DlZ(bavD)!z67_358!8;4wk)fMIi~bIc27 z!s;-SJ#W}Ere#X_o)LuI0|Q5siW!Jw1F;M+`z29wXV{)*bU@DClltKl8}KXX%_&(d39m3#(gNUYclWREi3 z5j*jClHtrHHmKms!X`Etk7cM&VyPe!W$qM7*(r!v!cdji>=>gUXDqZCLnHyIh{Y{D z%tVSwkUG;o6_4vondDq(5!UaaiUdA7J9K-=xyX!WyzJd*m6VfxP}}( zqL)G9TG5;jVi~aWA^U$@vBz5+<#tYnt^L?vDm=pbAi4Q0H|FcdXWwN?*>L2Ia^fO+>9qS6-#X8@>`W2HCK5TzvSLtx;%Hq|dg|8g^&8>WLsT8DjvemdT^Ge%qW@wL zzY-86w^<@>$`~zKUK&~%3{$k@#;t6~qHCKytCf(;9(88&fn^H5u<~0e;~<5J!-1=IMrz3f`CZyB?A58DI-2Gq9i-S-FC(^xIh7cvv);~xnQI$Mt&4r-By zfz`}3 z)Gw?r)N0o6i_A6INQT3fu62h8`b4| z;)K~g-jYOJV&cn4S0^!gxlvacaj4DMe@McYBoY{*bZlWpQmx$#)|D_oWhdn@I*gCSgnDU~CUlqwj8TV3T73>Ok^($gKQ5Gf9vLUXI`F^8p|8>XqD>nV_#SP~Y!QLj` zzb63%dKLcLR)KsODvEE-|es2sOVLXr1;->DiiN_T6ET)u`s|#Wm z`;+Zm}zU+nEB^!Al4<63pq5OXadL2PbM%-6Y50)~NV@9K>Uv_HC7@UP$!!Wq$6d<_a zvu>m8$d(qI*$J&|is=z9kW~nyc6xX$^LCptSx*s@vngz{neq$_#lxk>52P)4ui$jc zcl4Lm-6K25Mse!` zAbW?%9O$K-7H@`|Y&WwGzv3CNgvyw*>E&5!5<-AkV>t6Cj!o@WYJ$09Ae=0wWX<7h zv8Cx313<^*K*f7k##T|dja!eETO~2pyP3G3@zh6t|1JT-`#%@wGjq2T_ewaC5m1%) zOWB{ToFPluq3iW9WDQ2PtF@oo>Doi$q?yea>DvtWc1&JIl?IG^z=5;L-fqXEcdyBL z5q#_75HmYl3aWXei zQ-L*H;SOhR5Yk`N@9ow*R2vS5%~c3|W20kTvkBiBjD2w|5~V@t!n~4cjd_gkl6D?r_z1=}w&f4$<9FMJ8cz*uX1y_) zA%QW4&!PPm*2-tNrk;Bt$mbw@9`psUtv#YTC$!TQ)?>Ym75SjMYK&WJLV>G!HwSsz zQNvcB`)O*_jdoB~-4KMWNl%<;Q*4!O`am8Yz;Q7*hjIT+U){>0TbQ_&=}VYg&Z4Vi zL5l6tMM4;(PB!5Z({ht+{i_VHO(w_M(Nl46&?1YZh3g9fc>@oxC7~T;m=Pv5He}r- zhZ#$SUx5pt4fE`174EP6_oewrwjH2~i&YJi2i&6$CUri+}_gixQZqUF*b8YPyq zl_i#K@ohnvvl+YVnUFi!Qe}f>tds9%G9*>R5OES1C7RP*vPjK|!>A=~O=jdo!2nA@ zw7-S9WgCvHOWU^C0p!ls_KvXK?=qcjJ;m<9K04MvW-P4-wT@Ihu%_d84r9Fx4XD-T z?REz9J__@(cB&?NN7S7P#f{7cib6?dXaAC=?k1V=TsC*th{3jYcW9KIwI1kZbNWj8 zdZT#oTbG;TD;v$?;NTI=+I6}i;RCE9yG5$Il{Vde9M*`ESg=LI6!TppvT4L+@pQ21 z4tHCBT09k|v8lJfQfxT|2bW@U3Qk&z>J%LBV#zn53w*lZYw*60Z2Ge}7uM7Iavfiz z;cCt9&}@D78}VDQ3FpNhh>Z;IKq+*am>|X*g6zFEfxyXO%hJ#$kd#0;{**AeD`ee5 znVfWu?x07vh`U2|MaWhca}BYgrc1;83hD-;D1Z%!ib@hxu}U!YV}6kzFZV$U%`WxX z#XfLhByk}|P>zu%zzB*Yzlxfp?(vwZ@tCj7iG7x|1aSr6(+p39Iyng37_a1TEeXZ- z3C~)NdkauE8kC8cL=bzt&ebL+_I;|$uN!lj4v}D<;O!Puud&H6gUNi#Ebr+w{#P6w zobZDZerQ5C_8*47XM$+_%AERT8zvdB@s>w!YxD9%HUJI+dde(^EB1$7>#cKAqqQd0 zH(`B4tg?Q zrc2Q#+qY8>Okk4}&L?Ev2PqMn9TMVjV+5C=z5)f;yl_S2Umls8BT{K@w6kx()rq-* zdYehv*@?Ir#9NWi(+fiWRRmu~{=Kmsc8%8e&jff3svjZmkXJHX!K7BYs)H+;Pb~(2 zPSk6_UWxF`SRr;KN5n+n&m_SofHy&MMdJ6tQ!zXR>{$@9cpDhPE|11WWmm`WDX=d< z92nE}$qT@j$BbcbXkpYB)Cay|F7Xhz`xUgKfgL1H3_XVENgHL|Z$;3Y+PF?1ySPt1 zzFOwaA#8FXX(H7Vu*Hv(fY*WqA@NO{C5C3={n%P<0mFRJ%=+kjbA3L7jW4LX@nnkz zyxqpR+GkUKJK4tNu_<%C=d&DJK5WzvyEl%ge#~ZY7!)xNyI%qh7QVBGV*W*hpGWKy zo7X=ISB_6V*qEDOEzIh36IAeIfGKv;Q2P;#xH!OiCPwS;%YwP}LY zbuf_x&*(=oneoB|HQv5jPJr?G1fZiEcwbRjdybC&qpZPZuxk+u*e}cHrs}+u-Lp!O zkBFjQ*g`*og%=V6HL-2BOORiK^3fQch?!RBf_3Um*jq7tp7L)}*)CYTa)Q{0(DubY z;tha>dQa?RhajJ4^B~nfubn>cr&=i%(kDidvENA;EM&HL7^mM!VO%dvlHHi~m`d>W6YOwHY)Q5$*tS8x;4| z|JC|WM-n3D(iC4vtmt&$1xw9#zo}6lHk}Ts{7|w9Lc_e?>`|=_;Ma5jevi3*-fr)K z4U@)-7WFK#s5Vhsz~=17vf1E9Sh3+FJMf>fzWTfXcHXyj+{}8+W=M8V8+1?mnSI)W z;Jrsr(~YO;pQ$}yceaO;>xvGLr?z$O2!%^mPg z!b8wo!g6e~bAFS)#C;KK6rn+%8=G!P3T0JDVUx^p-PCL|FfcPdXQMsjC9rDLPJDYR zi0dI^@HlAXiQ6A;YDl`i`X)OTiuBgg(0hU2I@``?uNC@4S0po~sEDzo)H2`A79dQB zEu>{=jJS!i!BJJ}d#6hMo^J;|RNjWddQc-P*2ncQm|^#Ie@E{up7X@ckm^2=p4=g- zYuMbzrvBSEb`}_Vo1G4sWwy^*!_pxrjI@-aH`hma z1Z>y%=Bt~*9*uorx-baKoV%=f$ei0>cm&powHx{i&Tyw0Gl~ZB7?HJD_n+Dvy zCdNwuVr3(Hj)+LTELp-%fZza<+@XwY|M0fe-ZGz!5+-{ztEqyQH(ATOpXF&V z7Yg#HVH%Piqz_>oP1$?Y8#J2389$iiWzwZl4(6SsgKqaY?KQ`}sa@9uH=(1A%IT6F zgng>iv(~CBfs-8+)vK&6EZz1nu+y=l)Tz#7%#1Rs;eAri%1%ggM=t9*@qXW+uwM{m zQ8&99M{zJAIp2@6^9!kA&zL4nmEj07^ z`eLIJ_d9%S?SKfbWbr*L!QgAozh@eE!hE%Oq|%miBu2X!_zHyIQQ^H#97)mPJkemL zCZ^>t42yy9D5}VF#-lBZfN`mXDC+1&GPwtBW8!ub8WOkYZ99uTI;W3*8oZNKt~s`S z%<(M2P8W?2ew(wq*+>@F?>K(V zF@Q@OscLZW&1N5rlY{B7%icUx7)Ck= zv>h`fhGSbaVmUL0N_1?S1%4r*FR1|^WW&>ja5x>}!}EqDUB}nt^I<`>MrDwV8*gW& zLP5tPx_6+c3X6!Yf`LB~m#Gky0sZ0w^GJv9p?B;|pFiA;b&Fm3W!7!Q@lMmJ;1-UOtS+M{qct|4&QTO(2H!5sdD7 z0{K{VJPS`?NiWIOz7%m0$?%gvK3)wDulYRs5!+Ir+KC?(@ON__s#kOQTArTXO0BlS zut5GjUaW0A-#dabmS@&1N{%qh5V{W02 z!hw!y(_t2}ebcAFx-XQ$CXSC-NV>3{=4sp`E&gH^tnlTve(f5?Un^4EpIK`|v3e5o zzgF=t)%34b{+DVMjTF~n{lhjAXM?eG){w;J$LTUw~bfY$iokn9$-80n56P$QZ@R@GX)tcb( zB`mm%NfYblqfPA?V-q^4%YA+q4?o~=y@0P7U*S(J2T!4Sff#r2DGNSh)OO-slDHvG zC0SCsTZT8IxtNPDjd;n(FeW{>_@$|RWl~-|F{qssmpu}B+H7T*>5bMfLDriQ z=f-TV)R)tys!rtLNyJk5tyR3Gs&B2bTdI-GE6vPE4ZB(r$0Oe0>myBy8MV-jey>}T zLVu!COB6vFE|w{^zIsXGGd8M2l*GkQzxx{@mIt z#t7*8kpj>oP9boF)D@oO`Vk)<^=;a4L- z{&1B&P=yCAwLVY{g5*+Q$FK&$J_jOX*Hnp&i?>&U7pny$P6mDwF`Y1kN9`^DsNxq@ z_D&VvwZGn}2B(4;z5Qztv6(8?I>bgf}ows(Ob4)I>xQBH^kLjKjwpN4HBdCyuGk#_`OUx8>Jep-@4$M z5JX|;AA}nv8;gZgHm)snO!tRtZZ>O++U9F*S^QD?$K1|AzikTQCv3a*7v05n(A#G} z#U1s|Y^SO83bl*=S?6wY*WO>qpXYn1-P2zxPpt=CV4u;d z_`eQ!CipcP{YUuI*pmJk>@qgYH>&jZ?GJoEeju;|01kx00noBPu>G13hTtG59ty!B z&_u%iFvyR9!r{)X{z!nMpl~Dvi><5iyLEBC*C96Bb>vOB0KD6q2;bXzmtFeduqCrx zdg5p*Kb!2{^Lnre2VoL~^?VZBHd1~QvK#DyxnZr_t-HKCf?O7aAhzbhRL-#WPK2ji z0M1c?404-sYBIXe)1r5&pA#RFwBPm?3&IOda#n~?e@6mn6WXpx%Wr4_ zAQ%Jf*yk;ca-)^NGvGB5zbpzbu{u}1uc?H%LW&z@7Zsoh$Gsx-%hdIV#WEdyDHE1JDYaP=0#QFhu?OOc{tg#SBY(wh+SSu+*MZ-|N^uPH(Opxv)e&a&Oj z_3_9%EPQYGww>GnCn?G1+zoTDl+6~*+X)fo_ltoc+7@VOao6iY=&l_Ze{Nf?$2&OA zvGW-_^1L*_;{$O*AZHLyd&02OjC1!r+yqA%IMV!2hV_|^TN}iZ+|+#Ns~dc{-d8Jp z)#JA_>Vw$R^|CKs@tduHVdC$;dd(+R^183y^Aiy)3+b)z1^8wl_GKTqw}}@`;F8|` zzk}N;*QW`&>!=y{Xg9^h0_?>D5!UD1)O`aw8F4Ym?A$$*>j@#;U^WxEn}21rGX=F+ zMUbjwKGphAuCfB5o|Y!Mql9I_S#wwms!$sl_HJwM@$h)?wnc)sWvWoqsN{9~%>a1E zByfm!gLCqO05OW;CZldOOiKd~8TF`vfBNbJp9Qk$3l?D-@fs=(PZ{%q0T1ZOZc0#a zBX7joG?84xr(xZgq@nF!lahkB?}py}q}2)1m7RkDe&J+xKDSJ&F}HhP3=3iRsZH6G@Gamwg;t z3r#5FNs)-{G&qUPx(hCBz|MXI!ngudBlNKZ%#hT}igDaOX(V0!SCM7!i}RVUu|wP7mVV5 z3uoX7O^BKr5T3yBY1&h>M_I>B&d4%mRLP0hHhe43yU=<_)}2$+nJ$g>>Tb;w>nFJ{ zaqYXf&07{|o3N1E^c)fOH;hx?&N$XCSEeF6+`VB6u8#%Qc*QSx%YS>9y#!|yOWwER z*XmcTnppXascyZtTjy>)V?Dn9roXlxVr{>g=-owVmr(7eTpcQWZu2h@i?=NQ8eu0L zAe_hHW1H7JTrM^^#J%jevUA2LEfcc?XDe0_zHHr_W<0 z%(4r_D&Ak%{5I7pRMl9oFKBHdJMnpj5Fu)6}F8(^IqqD&6 z`vdP986zA7>QK@v;HXEgx99rZ-cc$?c-fA0&a^aW$5m_d>;}+yzblI#hLJ(CCEl5CJiul z6*flUpJjHZ-J4J(C8v8gzANmO^vCmYffz`3EiYj6%L{_}u)rb{W6{R0dN;A_JStg8 z*Eh+Opmri!tfSecFjr)=sX7F~L?a^+(UnsALfSK1ivGksRrIs@p?l^Cf*GWDw(i>F zofqaY-mTO6OUF zIIQ93Y5xZGzfl~_az=8hUA`*Wfhs&esY4Z^1079dN6PdH$#a>hGBv<$D!D_Y?P8pG zK#4~cJmJRhpAUyf46r{deTO1;@qjE`EJcgBMMbwNF;gGJ=mnw&zE%Fg+Im>SGT)Bm zAL@&Px63h~5Okv6E(K5ga>#=6sP~V}CD)c&u{MvO zXGox_shpOIO-ZGtNmRgk2vlbi&=hTjRzsjOqATqjezFVfI7S;`uwJy&YjvB<(I9?ixA- z7equRdj1d*jmatt;s)_KSiGwxvLM?Z-N`1m{+0x0)D_~n0p1X>YlFIllKUjpOAQ0% zg#j)L-h{2K7l{@h zi#8z&5*>2F4gLCuVo=iWA`@%tHEi05LRt4}i>21oa|JbTfx*e{Z4XA_tY9+y(=rD0 zNz^{JeJ#3{oW&%SJSHV)6pojmiB#?8{jo+TTbnv) z-PuU=wAYTr3J1Iir-8SB5^EnfNrUG8mGjmVZAR5r=&xV=V>c(kgl2McZl0iZtwRIC+V#k%bL!47HE+US!Fw{%m&p7IDY2PZmnYI~ZQ7Q=qBBwxZ^b|(7pdFvei7%Wip<$~C;mZD=SBhsg9*X_LP@|L#tX5OT3jP=cN z;q+XbZ{0;PyfU>C;Ih0E;q{pMUUXEhi80Eeuv4c8GSkhdo&*~3Ys>@|`x*_u=oSUeN6PuD<{?L4zsB02Z@U6$?{<#jNP3Uwo2JZsC z1HnsxFGBDj5T**KSjtRHioTMk7xS}i>O?|y5gUtwj(GKG9a0g9 z$clh@X$N9gQFF1T>M57nO^@ns?o++NSm(~zzt3r6Z+s(5IotXO=tf|(J>ypg1Q}}SUUU9>C1K4mxGIlL&kJD&kW5kWS5x3q& zYk3p?`yF5qkN~p-z&gB3;y#( z@p3A@N%XfNz88kMn{=3zfmRg%4*C8O>im+TIS{#X(@EnM*|5!r$9ch~?ZmRr^JZ*nu3%GC37X=Hsm0Z>$yBy$MAp4N zGJEDp@JJok_U{$%scAVHX(hrquz76GLhpo1-X^NpL~Ttpctb|Y{GTl?=8-68=!ZpF zG6a9xgieS80%GZ{b*sW0F`KlexO_?;FU`e=QG9WvFN(tD(F};}tb#wFYx+cQh$?Q? z?oQoAL=c?263HDQERx#;cf?x(_Q$#lq`;Gejfsn?Tg2>WBpR@;9m;PM*zxc$t;-I{ zjSk1pEL8I6mk6bo2vM_9p4Pf+$zh}VddNGfIp^_XW%YPjzFH<2b6OcsEc+LhMMeM~ z#6=}`M#&=6_{dUlOo<&``k%=3Ve8OrN47sLJLJ(+M7X465y>k}vO4M~e3TPItK&r6 z115~P3ZH;=rCm1034B)4^{^DSN?1yXdMA~ddZ#H3HS8D{@P-{@8J-Peyb0SAwcLTU zGPJCIFcb~~I2c+Fg2&OjtT|8P2v0A-IR$2X;#8el9Z>Mka$|NEr+6e0Q_E2?9v(+W z#KB>4VR7uY6VDp9vA{mI5)adM&fXB~L65}9>^$$G%$Mc-W#J#(L|VtOMd}~^CrLnz zoOr_t8voo>SdqewsUk{Iw>HU>b+|%h9oeyQ^nFx#G4o%_E^(976~>Iz(u>miQGNqN z0k|08ETnI9HT9;nQ(6Gbu>)H?^HEnxxI`+@1@$6OPw*2vobTf-0*eJ8j8GuGKI@`O z3T40aImzB_y$PFHcO=`lycb$H*KR`czCY)#yD(b8958&*jlesMX*?H5_uxA~0L|HaoIGJGS3iP(^f0)l~h}ya~ysF8f=% z1zKSic^7uY2w%64W`8?uBbWW{>NaZ#dArkQe{*bR8wV0g3#qwV-L1J>Z|xn?lZVEK z7d!1EUg#zneqx8c_x^6*MU_ididIf==`78?*p6-3BO12m!=dip6SCY54{cqig>!ks zqllQ>7WA_CmvOygPo#a4Omzc8xXRHm>->MNTkXHDNi(+U5n8+NnCE@flh;IZ*di-_ z7)Pu{QZvIpyXdRp^B}&r8~)bqI`etfni)UcBQkzsyI9f=FWYNEy5`nyxMh`V!u#o( zD#8;Z&$y}^u3YsQxA%w^I|E~+eM8lDba&%9?{>pGt6Z0U)kFCG+mW|C+YQgu&pz1= zS9iK>w7pW~8;qj<`y9<|%)exHZ#sd`a;r^&9bzZhYU|qiecSm&tbxj^Y_9%GolWkV zD%9LH?W=XU^S#h#f2U*EIQQF49|x0YfAYL~XS=+ScVxJ}X{~QmeKUW*k~iTLZ~*>b zSNmDFTW9XjZr(k8xy`8B-qxi$2^4o>XN;x;D-4Te-zO1Mgv)!ZrS6(OHM>*IPEM(g5ShSfR#COy00q6~v=adU>HEvRpYfmO(tbvq+u zUob|GaBE-CE)d@7vPk=!zM$mK%YHP$lt$CyxzWF~0dL_@a(VIG>nltHR1=5Pf=gn{O9C>>(Ubqopb6aS49AU6R49Om|j#!w6zw zAb@(R!Soji!NZQucH>PbP_1Rzx~>K%dC&Ie2$%L+i{SEp8yT;P&XEG)U+#mh>sJL5 z5tx-mjjAU$jH-vNVpLt%^}I>-zW%Gmysn`)VV-+Un_CZg2M^>t%WeG$o4WPr9{YxS z`U`Go1>Ur!2tVleQ`w#eq0JsRh#lZ&I-ckHcbj|5P{ZQ*I&WAU+dm}rbms}Px@W!$ zgQangle{pO0CVf3ND7F2AnnDbP*&pbT%Lb#C6N|#k|FqeDsNxPnGH8OlgH-~vsGq- zN#10ox2Q4Vb;a~>M|BDFmot7G=s|y6IG7`wCZ_vmb9ElCoXf>ITxb&PGE*Y;j}_(w zL45TvyR94v@)9O);3928Ih6VFk48J$QeivU&v-X1VSGazt6W!0(ZbjXSfK{U#R38k z1(lI<zXP&UlxVCG?va`Uq z$5G^`JSo$+G{>X}76cI>FRktr{#S50f7$B!AK}r^*g0N&h;zN2F9^H`RZFTPl=@pS z?|T9#{z1||Sh5_al~62`>J!1Q$LK87P1*IB-HKE6CcWW+kOURe(le;z#)KZDW31j%z%P|+e`_`BHs4kpLYH#hXve;Vv?(?}3|e}eHHVH*C$&U#f8bFI3n z@l3$4YfJHcubS;?YeW6>@rU-euObwOOA7-V8So|m}V5QGM59VL8=nW=Vd^Pbj(e#$e zRm;mvzrvV}{ioZ{Qt&D%qD;KZLRY)~8>|!ICX6lze1MA+AiP+?Kbijli{57~AF$&4 zEdGdvBuip0K4#GaTtoaYZ(6}dbL4-hY)?KIc^94p(1letEVqFJfbS~W>Ans*xt=t? ziTzVqGeR>Kool0=JeVt=R8yeB5ld8UrskJS?5{`t8>nBj#MP)2$I))IUm)(@R2Wy* zrMyX1pd6M&Ii%|MOI>+nkf3+i2_1fW)X~yj?1fP(-)_B<;jV+Dw$L3|fV6*Z|6D4sl3YQl6yOY;*5l(HGHe=--a% zZD?M?;6=P0a6Fb@LGwC_Cow9C+pLiKyNYg*tj4z0zxS=I)EH2=-A=D1MBCqeb4?UK z#p1vFO)vQ7QC50@SW)qQMzw!8!~0ouA7j@sb}jRBaUK(oFfoin{&11@JMcs1&%oQ6 z`JC}tO+~$r`j#3iPsx9L%nble53hT*%mvR*~=8qylSLieD<7-O0T2Qqa46N{NSj0v6{ z0(vOF5k|AQt|(jd{vPAoL(c!n@nw$JBA$X`1Njb$_IeW6l&v5&_DUp7M2r>|k$NA| zqaCYZ6Akw}TpGY~b^X`Wcrg_fGA_R+SBwsUAn+mhC&Qy#0vh_PnO!n*FU_sG;D)Wezwi{s>A#pTYEZeNaj54=Nz zGP1{X@o_Ext@&`_aZ-2LA--Ph%jdKi;$8A>E&riujj^ma2bgp%+z#{7XlK0Fg}j~w z{3oz=U47jLUj~~+stBa-VnNtkZc-Ynp4-5Z=)Hz=du=26-%sirzrJ}E_M`HCj?_Ju zqDwx4S{)RY4h}2t2j;t=NtV8W=xf0JG59x#_XFF>-eh8FD6ZD|b-IAYaO7u({uws- znuHIt6Jl9|ZCK!eW;RsN2tPOBVPVta5K-}XtDtFp%nlFZBf_;XyG2LW=&*J46AyNF zt;YcWhPY>)=S*cUA`jRXZX)#(R7e9HBDq9gD1;4HwoXDiSG}Ph>>D>le@x?K3mvJk z4b*tg2x`0q9c-*ple}cZA`iA!*G*7?9XKHb4AY6RtwvROvQ4h@bML`8w_|^ogvI5y zksmJiTfYp|D@ge4yKqlf(TVV~XNtK0qRBmTfK z{>ogxPIw)M{1N~nq`hGoP~YsRM~%&4|CF|pi!jH|V{4_BPYM!p-zUs~p_5vEHOvE^ z>SRWdG=)6MDtVT1l25HIs+l^TGt8-W)&?lsWfvEmhwallA{B`!*A~xqhXa6xF@rs< zI~k`2bx$0Ivw3Dve_u@m9@wcXJO`>vt#&TEx!^1X4~WEsWqDr{yH@ zX9jj&xVzBv?n4_w8*#heOnAmlj=3vurbqTO>zaVFQxqHK;^X~>x%dQlnaFF>Qkc>_ znN1m0GVEmde=)pR%gE-Cd=V^Au13R+bQU3ma{_d|~3w$(j6zd$ zKO2ykrIj&aDynzKOhz(hcQS$T1_2j~2_5>EFxUi;FXk*_Uo-zUP4;!Q!hqEe38RN^tj zB@EmOavshN=lPS(6fv1Kjf4_0NAm%Gqcay2;osv>v{yNk?G~HLhJO@uiLQTna=ej90KC zELkEkMPrE+81zBOYLHO_BQ5sS-ohs9sEKIk6qL&JhexPy(+!(zxL zIhiwD=B?O-E8e&ZwX35s8 ztr=;Csn6EHO%q$;o2VbUw2MhpWEgE_Q}eDfY=+9A366sXrT>jLDE;Rz!z6Fg>Qh=K z3p;z=9@*}=2ira4jCBxi-a@xJYx4-*_BgsNuR^ykg0%-^#3*dHwW*0Cx}r-h2XB8u zP-8EFmivLe?lR(17(9tG3hqXH9N7cNiX`!^N6Hzuhv}u3iMIkjQet>tTdQ_zj?L!UmNrMcsqvpg0?| zbI?B%@hlXlqB#xuLoB+%-WCO6IQsB=A?i0XH^B1BlnW0DJLveV&G3V70`4p()d}YW z5En6dCfMVL2-K767HLDN8+RqbUiNvKeH7mB^d%GHsko@!NHmVt>55tIVg+`#J z+C>7-5@APli!d@kPO5OrF*drzWoMW4{qzlXcG5}^tTfsm?0^qJ^!4hn=WIK%_69c9 z&J<$K&9Dw(^J+V}8>J%N%no;nANC&_#e17$Vumsh$;e(Ud73vUW^dBE78c zO#_40Nu7QtW6ap;cH(=mNvF?({AXg1kN_$hE|leb7#EgwWtT69f>N#hPMnHqT!BHDlkf>}ytugmva>655@eEkg5Svz0|j z70gh+!J=z9$^OL7bunTP=N3}G4fq_8hTmB?iDzsEq2+s+4S=OD;RWg-U}ql_Llz(@ zu5(E&hFFA&R2)X_sR#_S*}t=#&L=F*l0oXa&ilG(3e(ewU{#{p8y2R+v0+)-pEY)Z z#&*%4q3He8!m>jfopbz<)L=|P$~v=xS9S4n0A)BB4@T}X*1|=6pd9Ah*ciJ`X6EDPT)t` z(WZkL9}7fU$DuwJ`7y}0=jUpy{Ch=SM^i`lMvcm5fNPr11ll2kkc;z3~h=|iDIPAxWJ zx_9({X0zlC$gW_?@gh1wL^raqv~m(bY3;##;CF;@!RFuoaXol`HhYxVAlr<0)KTt+ zJmQMbO}|au9uZR@X=@@Ka~no(=Q7WF%c=y$C=+?L;5V6yDP{#zvlVTsx-GQur{-6) zF5VgUXqP#`^cSt~zPSFQeNTG-G2DBa-fsxwTm6gps~xJ>H6pjfx~nK= zv!^K1L&Ej_aXFC!C#FoaO!|t8#7Ov>q>)5^u2!ZGaOti{yZ$-u4BOzedf67>R`5qW z6JQ+=pJd)H3r@rGsZ`toB6Q%Q#`Z|?PM})1F7I}tPyp%{ZdkJ%Xeyqn=i50jD*P+N zgCjWtV-JaV5R?gUq;bY_iSgQMD)p%jY$w4==mD36g(E{eAsoHq#E{Qq!cO>y^i3g# zf(>M7=Yg?#IS3zDh<#Tb`_6rgJ)kmkTD%2V2J7{Xyn`)rptwUESr;i2I!DC<%$qXa zCdAz3H1Hm$ZZ2yiwJRjvc#s=AmMnu_pI%B;)5kZoHDm*{Y6Q4vd-xf6yBrU$em3&X zBHTmwF>5!KGSkd5jYq-f>H)yVA?(l}f;<+>OHf2{9y|>z#g32a83;X~=W$xRo$T!A zPG=@bhTS%9?GW^K+3PecoQnE13oZIr*`MUS$D66QSsZ60IHas-dbn>>uEHZ&cpUX( z$ey%@U?(%_=&M+G1NH039!AzgC}|>_L_ICHo=nOEdKtG90Plqbpn8UWszy!ha#B6M zU=nqUK5v(wc~8q&6U0IP5<6!}k(ANil{u6$&+DdM5(wvXXmFu*Tof?3-U3@RoEF=> zDNDe+pEM$)w3cozY>Oi7SgS1LYBa~e@2!Mgk2Ecp#)xkmYXfVT++AsLe$9W&I z*fA6T&!mkqpXDlB=?1B+yP&KGG|aIHJvof4Kc~`oPQjbf{0sf_LGNIyEG79fOh3=0 z$XUTg{z>Z{-%O7htl!n)?kd~2chOx#-V(YimHZv1-=n+AZ1mj=?7LSdqIU0I&pJS8 z7;yl3hBX{Oj>X2#2951Vv{L)o)E%dcx9%lBfVp90EdU)Pe(Jw2wSa0CRqizVGtjUB z?VoQso9#Ekc2C-ZyVlN{+v4_YYb*utVxIFFz;~#=wu$ln4R+LJe-59a`j`$-Q%E?F zMNgsVhqdgO%lTZii%FcSMizP5@=j%5Y5e|2U@8H1#;w1lF z3Ok)hG(OMP8MS9A?6DT|b@4U8;}Lhq2f$y)&7gvhDw`si+QY@@fSsbiM80%UI+qey zPX_Y@MZpk=Ddk}%ZQ6LI3-enDa8=7KQS$*%(^b~ST1AI!2OApPLznahEoHi(Wq|g_ z1bI{A5r;P%Tu)my^LMZ?@TL?U9!#OvwW)1c5gA&WsNUXP-u`w9n-38JdeDM&E;9WA z;)m8!T1I%;g*Ck-T3&UtpuS?~P&>tr(wm0`oa%=C9~Cl_B#wiTOq|!a@z(9IgK)rD z2UyqZWcS!vsqJ_CP#d=H~58nAQ=Mlmm)bB~t z(jiX|;DTrn*tg7bg6KP@Bi~xktrN3*;?6jq#OP!`M~$_GUC1uB z5e*eS+2#(jv3dzw0(I`3t!^xm$}?raJ4cmm@E@x?u2^RxiwdGWiFGznwXg3!pv5)$ zMDH?{YjG{T*j&cNm0VuND^k`=e7LYBUaS)94|At2vH408Bv5UuL=GmFGi`vq&@|$* zcXcBW$XLA==DOmwQ1MJK(IaKio01=ly$2yX7}q`s#lff!!isl-&i}?;miZN&-N>B< z2HDzjJr(gdz-V2zUj2yph>4rHx|#T<%?k(gKu!z2*=CftW_pD++Ve^AvPlXm4J~Sa zURR$Qn;mS9#3>7Q<~za82?^a(F|B@xJE!!seW!E4yG-Yp8{;RrAWZv5_!H6bBf?)1 zrmrf*vK(N&rny|h9|^&H-a;BjHJ-6$x;bp2Y((!?axJ+aP$47}$6}t0D$NHurTGHj zUm>-M)0lH?7SGtsMxF9kqb^O>aY%fKF7J1{ItLnauG|TYIamHZveWqptnN)Y2hT^g z3~B8jjpi8aUWUP5>7MJHk7gOJ>mBOnP31{!V$L}y;5R@VWsE3_f`x=OL1_ziC8Vi_ ztW9)^K7YO-9esQ=wLwi()vJnqukcRAQQRD`^X*i0uZN`28F8Hrr8&w^kMvEqi`uo3 zRh`_XRjW~TbqD7v^P~#rj!qBsvYQ_0H~iQ52w+vMUN;!LPuS}z%MS<@J53c`S~lON zK!$D+glS-PEKVIMA-G}0x^-Rs%(@j-&TaChOc)`l^dQoikR60QS7G@|>^&F<4?^XL zY+dgKLy9uDu?hTi<%sPF#ST}DT94j!g5pOjc8s#~2@+@|XeLfI<%^B4bZk?I;zi1l zq9sjx2eKtfovPGnR1NK1Mlxy|?ZGaa&xyd#vengOzwZ1CCi`pXzC>cSXR4{a&tQQ!y@U|9I`{ z>Pf|(P^`XQwQJh?SeLEiI_Diq9IjV6zF4!v^#9MR?^5DOt&Y(`OTkIrK$}I-#PN{S zBAc?0ip**8*5fOui?AKM%kI@XIPdbA`H!PYgen;8@K!n{fu!b5S>zoN#x^8H3LxG{ zja41NS!>zY=VsnP)m61fDnwFaq=5=_JB zaqfuGBeOP+DY@f)!A`%}S?sje&N1z`?lkCq7UtJ8eg}iwm_mL#Nkt2=+sn+?jY${F z6>&EckGp{KDn?Q&K3JWWfmAg;97C0%8S=~tR2X+x~ zn^nzmy#Rhe-E1!&TgPWMSRd$n#zu@1l%4Mc?h$p2vZ1#ksuYtfwT^7Z+n}%Tw5Wx5 zTK8VGUAIIhN;dQ9o4%XaHIjpCk3`ph3D*67B5%S|00JB9RpAL9X~U(QbI%dryn8mR zXP@qG_+S!Z|FL&o#iDg{tG4KV~k=aQYvbbNTH$mRUIp;Ea~_&19#BX23Pdx~%=frecDwHO+6a?G!Y z;qsUo=)J(g*B1*-ONw}TEUt<*!b1pOX6Zde@y{ZAuP92QESAOPIS2UfVI0h}RWsmv)opI#V;=@=x8rtt!m=j4PzMM;3!4Je zLRlZ|G!b+~l9w~chqFiuv0X!FIbuXr;s3SW+U8T3GPM>|Et^m2^Y2CPn5G=NkC(y4 z(l_u#IeWI8K2sK7ly~3-oNPn>o8>e;el}KCW)MHxWlb2c)AQ|tTZu*%aXX3XR3a_I zGnNv}qi4H-x&`$SW4WL59&cJS(v}Nt)Z98$4At=7`a4>utxdcs>(o>gYUS!{=$+Qm zRqnmds0R%^V9HOLlzOSgCRU^VFb>CJ00H|tsO z_RVjF(oKLjL*Uko)^?Wpl5|I;OjKZ{pTXtK>{9jBod5eFokKq}v)h zYbSQ{);qC$7m7QvULr|dgP@(j0yn|`N7;XX$5kDF!0??p<@UR~cl%1KW=XD+EcYfC z+>OD)6q^pALlQ_YkUz#40|pxdrUtMv9Zc_p-a~Jphu(XK5Xv`m?n-tN-uHbz`?+PW zZartt%x~sQaR{;Zo3NiWD7YS}Y14h_L#Pw1eM!V8@1oV-H70zrQ)9xf6M`FNO}Nps z)~ony?4RH{g8+j1RC=#T_f@H$0PhUpVAtWCB@$6J*^O;S2)SHvy;gy)k%+<>q<@R* zZ^FA-lr9&UD`)_6$A}#2{PiNdL2zDgyDXZb+eGSip#~@^2gM|8e@g>I%}$MBExbuj z#lyfG`M&6zKoZ}PE=42Qbs+6z!EYncYAeX7kN{Ocs=wB*zaz$V!}<$anK{J8c)7yA z1MDDQ2Q`daViG>?aPnCmi#*+oDe;bwJOw1e zT7=K=BcO)#8mtMofVIqyF{e3wMn#rs-9j&^Q~gTG8Kyg?lTwmN{4H`~gxssv{vQ}2 z*koM=6ApF{5nZGN9aN^ZItUJq4hasHhqwo;LlzwD9fAkjhYUQp?hrUo9prZ5a6H&K z1nBRM**b@`StmoB_WT%q4VOvxB1vQTc26nyC!DD8cluoIkW4!joJ*Abm;MI%0TV5auzNFhU?)yVLgYPhI5Ecw zG^_=&77kJ?lOC>I2qNDnUM^E^TBR1`ye!1T@v{R|WLUP8#)MR6nj zg~0ax=uLuah4=u|HzMX#LHlqoaO+(n;ao+nN1b=EbdCf#3d99mxc5|%?5db|PX+Zg z27d*oLydr==mK@Lghv4W0qR)@9)#%3jdk(9H*vt9fvhEj#P6NKY65JaW9m`?zpgceuXcye0FDE_E4&2y1<=LV&-_-6 zQ;(8lE!rmO`A|HvRuE_l(I{_*{??%n^tocLXTCqhEhAD4v}gclqXKi}y>sfkv6z?Q2asAFOjdM=Hn?ch_nwuD9mES#-r@xi1Si zg{LJ|iiRI#uIaTVl~r2jXTcP$rjc4R)jEM^n+OBi>BnqGsI>DXXQtC%`Hk4}sx6!IXP zM>?q$juSYqnqnQN2l_Neu5tz^Wsv^Qvc}6T_!d}#X zY~<$(q&r%wzmgg|=ay<&$0kK~NaH1I9g-!KYp4By)Xc0Uv*u&dgG}D3R$g0&EVdp& z#|cRRhG-3FuSs(q0_`!z7qySNz0C1= zQ`JyX4DzX|Y9OvknQFxLtFd}54*uN?>jLpDic?b9OnRrhyW zJY+`?+U_HEnrMR&$ucDmSBS;&-c+vCSC3+vGnG@PyGMdOL2sFsglkpkIyc$j^^R}% zQ}nx%Df$2syHnsp#Bm8>4;Gh5p4I;VOp#%mpmrcg*9BqM2V8_A&S1JeCDIW|m2|3{ zli5ol9i|#B{Eanvuq~Xtogx4!oqFpHba^_GlwHZHv%-VKez6hCLIw$KyfIuz7 z3C@s|H4A=Y$=`5ZF#&m^F;ZGZeWL%*NpaeY$&sxcHG`)*wBy;41H3On>pBs2=@CR~ z$C*itr%+Ge$3Z@-z$jK6myr@{b9~cSPAe6$fr`!dsBMq)c^cz=n2^rT4C$-`Yw{H0 zSr9utVwmdR^LUSgv+TT6j-3pe-!}cOIK?>3DC;Gg5RD9PW$(=!A-sWe8>=_=5wGq8 zukB-Vr6#dTs+aZ=FYE&^)()(Z-n09N^Y(^+3Q79*gCK5${JDawdJ*z{9q^rfoVWL( zb#ji~cTR=R@%Wr~0YBO&{BR$|l)Vgjr1H8-4a-wTAxTe{RX&1S!d3+C!J|Fj(*l@> zX(7^ipO7fEFVYXrJV<~vSIOkL9+Xlw!{zmT_R72AQSf+Xd>K{`$MiC6J{&ui;lRVO zxD3_dIMJ*poAoSfSS+eM$LBzObJ=w=Iw16-oPb?r8~oWo@UXZ2dW}L+KEJ-lWBw{=|_488Ew78tdpS2S-VF3mOB=AIs>eu zAbtXi50iXwB`F_40hQ)bgxb?(nH!Grz>OKm%>=_1xIbqfkFiK-)I=40QeF)omzgad2e-+VnjxPHrOpGR70oL;v4_6&Q&Si(Yu_wvS7?#OVKME((zVr0L=pPGr zB}$4#%jkZ-`lGRrEtF&N2k0w6v5WwE2Qi;6IZ70Cq^?Nba<_$MN{3*UdDmZAUtj^J zYPK>uoC0VfcJV7R2W(Fz=k!=-=?IlqO_BsfIEc@nCOhcY2PO^GJlY+z(7Kn{5KlkA zVYYj$9Y_e^pE(h! z>655)`pqIcvRR~rL$D<3k_rEvYYDfW>C3aVZ*6PWwoAm11cr`Y(6CrZ5QcqFp_MWZ$(q#b22Ji?ge(NtFc zNXfTrC-|6IhV~Jp<~p1)@&ku`mr~Nf5d>ykJrQL(e$}zxaNuwUcD3Jf+}+*z(rLnq zx{5}($~uMpq@+Pxj{EGx|FD@y?Jn<Fn1NC&ruIjj5)oYmhZ3 zHdX|e+B1DSX79lLtzXACr@b4~?lpl}F7=IRygi*hE|cxWsG>E!TwS& zBpys2o^8|+x~CK-w{8eRXVw0RL9R8)QQ1{z&DoZe{;U>QqI+t$MtmWRVd5Jl4LN4z zX2}@c=fFm5&Kj`Z04CM~&K8XuEAFNkuFU7iA|};CtWP#MX$fxJKX#M-Q#aW^ca!~V zHrc;@ll_M_**61d+!WiIvxW7Th_Hyw8yQ;*?w16vF3DTNI}jxvC8;yCL`iMSl@9hZp!5#3yrHmtpr#F;ty&Mbq&IA zyaUnkG^@WTG@)BAmeWRqgu~kOMpk&UQJQAS|Ldz9dk3)dgfiv_o@k`MyX>F+hng$* zDNu9eez$MuRD2nV)|_80lv}~V^j7w0HD=sGwbfpDjq44Q9^4#DlF%d0eDq2#C*l!GQhF%+9eG4uoFDxD7u+GM-d`-yEe|_DW1nW z0_6t89iU43agm$iYQ^lAXG_usV~-;+vllI$+9QzGpiTqhO0i`Wgq&_z2g+}T-hp5XxMr(!F zfSCeOS4c0(4ub^fJK5Ehp4RG2l!DONL`V4Pa;-;G@Q@L1yU9`5gNF*EUYF(5iG8o> z-X!~*Y~)nKbG`)YW-mteTg+mej&wbNA0L}Y6zPMaIsQtON!eKX2b!bx7Gw!4shr<#d4&#n33+>yAi>}u8y zt+BUj0k!01a1**W;v-<)9ui6;vhf@*T`jAM;G#GvataBE&xnr>+(&#)kSb&@;I!7B zT_7mqdIaHQ+VOuAV8)Hz{u~YOAPeX-KoSBTh=XjCr(p(r{mw8&5?y$th9in*FwfrA zH2e`@JrQNO*q<|bp1*B=Bku9pNxmxb%&q=Vn~uC0c{&na!4z+OYt9|8liqOyST98l zB;Q#BahsgBAQ(W*CT{lzr0a$4-017`eVwzNI+A%U)a*XG-PEZ0{@Kf?kkR`Qz;zYq z;2oTHaYHTYZ(f2i_DMG1)U@uIhmK&0K!lI2(7+}?>RX>XfhQqoKcXc|%M?s)rxvjT z)HaKqMa1(jOU0iE=R<*Cv1_+*1Dm6okCe*s9QC-wyQT9oh*weG;)&b26qT0i9dWk9 z_6s3>+dbbA=Q;W=PpnSCgEFL@6H>~N|CIQwbWTi(yFI}(+k7FL>dj?2zAW`_tnT)5 zFQWGYQ>38fl&5k*(I1?4QbU50T@te`>>@61{g9H9 z%dimz?(+!tp4A?u|h~G}!objF~{>1qqJxHo{ za>-ocW!BCA@d^oRI#ndR>1vFWOEoa2F_&OX?a>+Xq~)7E@u@9MMh^AX7~n3sX%0d2WCF z|6yiPyj8!y$32oOWWNFO3a)mUIDFg;VmZj;i6KnJ80fXQv3A>kSJPI%wcf}&+6B@h zNsFA?;wISo=QPf+nH%BfiLgC_eYc3C9Ta%}Q0v=l2eF@etz?NZ{20?cPi2i6X`p~T9uCp1|!x5DJP_^@HokAplDl$E)-C>+%XbIZR2f zRh|c)`nwx`?Q7YLnMk?fn!IyM-oHIhidDfS_7D>t!wYWR8?JgTFQ3l4q4BW$$HpT$ z&Vx;RujJv{nC(zYWc*Qvz})dU{`A!aIFWZ!P4>5Wy>-7d`og4S`I&5jQ>5HJ34x8p zSBgviv7==kR-z1XDyjay+FI6`*sK9goz2@OPL0N1gcyg)WQ}JZ%v8!&ofdmX%uxiJ zf`u+&q3Tv67YfEiTZx6at)v5G0)4f=h}u?LFBXXNof#6-J3kCg3*9q9_-klfLrx8a z9)394Z!rJ;L82$v@pYzW1bp?hlxwQ9+YsplWJ8U(_Hg% zx2CDNDSJ;fLsI1PTv>{|Janv91AEqdE>#o6Vo8W+__!NJ}p*qs&>s zBT)Y^Ofvhk=_v56D#zihvDQkgOZE|u^$gP(5T2-h5I8qc=2v5RFAx;)`CnH{>)a@#DHF9L4oigVQprxKZ z|5s|5Y!z2T>Xt~|8mSYb%a6a@b-5%n7c#|v`Fl;V}5aE(ZvMw(<)AMTv`z*pb<@JWil^eF!b_(b?0ibH?& zGu@j^PkrGTPeqjb;!_B#glxd$0DtY99vvjE@MJrut7C8D?P+Y?0gkkH^$M=<30Vio z;NPFmDU@jWBQ3qOj7k?$L0q4ilq+Os7nI3?t;G>QOy|)2*#FcjYVNqF(^K0`m+M)x z`upqOFl(H(Toy45;Jr}49A=RCSDoF0G9z`HUgD|GU3e=@zVKl4fxr9GjkE22?o7*# zEA=eWbh?S@E(fta*R?Im(*=K(hFL_Ttnh1bFumRH#JI#=Wg4ps^g5ecFG*7=mJ?pe zngMJ&NA|SUTm%oTc?4c9YCAo(ZB*Mo6Slhz?^R{|9jG!l<2b+ue?VJ1a-OUHh zpLi$8mFTR(ww373$IZRlvGO@ozJR9B0lxtCIry9G+g||vb?419^B3L;!5wtFXBFqB z488Ov(6IruS4J^y!IFc3}!4gq0tbl4QSt?_eG-kf;; ziq`{2mbLsO@YXtbzT^Eps+>!LI(?pQx=`Zw6 z({CL>TBc~HK6CXTHIWU9q+_>fFQgB}N~#jqp~@l=pPwT!m*PD;Ep;Kkb173?==5cJ z>)qK{``?CLJFHWoeRut{5rkcX?M_FlH`Xbku0ee{7H1H2?S>H>fosr8UxJMs!-8Fe zxJQ_f3dJ)LU_;68==+xEO)>0doXN0#7-mIBQr?%nTHA>Li^kiLF>YX=UULAO+Q@qP zsgS%%$yx@H37b!&REkS)Fb3GoXKlDo2+d}teS$2oO=pDhVk{-HZfJ_}KlgN8H?LU{2gik6~-k+S&z2>{jJ-wUf>j-J;|r%Yo9)h z*fblTHnG0f^Cwp5J#Fj7{=b=vI_aVeU9=^e+UV=@%pLqR&(JnOI{BCd=Kb?#o#eK; zlFO-==(6icV}MxZbUjfr-PX>a8^xRo7HK`to{n7jm|lT&h5hL7BY1?QJziHL!NtTi z_YUm^A}6!#QXi1aBV96Z=`J?IZV*lpZ6IZYo)Dvb4D?rDI$g4Qy%_&4l48i`$>ggR z(pR<8>ycKzOc48l&FG5<^tHxbJdIz$IWT}xM<5Pht=wKhnhjfdU^Qlsqb5HUo(Jn# zQ6xP(Fo9hoN!u96QEBX!>uyq$=|aE;7UM;ES1pQu7(JiqWee+k5h1q>Pm^fB-|ux? ztx{eRq2`IQtgpSq`F$^uPhR33ux=7XNiX5?gglqqDR3n;lYp1&4SB*Z_P@}5=7p{S z>OAv8k0&pbW~i34UZR)bsm82v)~3xHn;anO$eNRvz`R3wvfxzso%MmpV)-6Y1nK{s zwCSHT2w^+6+b*En7`yGyILllEB(8!}m$OzGg+9 zM%oj7K?jdx_mu9Ms&R}=RE<;N8r(u`nckvf%TvJ&!%pjT8GEtK<-q%#(9ro;No$ zPaO$rGK9fYuY3D>E*)%`do{7XDM54x%u{n6>kQjjkDNg71kS5`Jbi{oFzq6x&Jb{z z9efAgdSz3)bFR=v%%c4jxE}+20;UY!=isVXC?(L(D0`S}qK~ktajLd*{w(1>6En5M z&f;aT4Au8w0P|yt8Q*yTSAqO3?2Nx>0BwT9!PJry^lhY(ZST1*cn$8=Xy)wiphIqA zzqp;$#@Zy_S;Few$$V{kuHB<1|AjuPo4%Ys^c*lB+8YLuqQh#0>RtxcJDfmGd)iO_ zJ5if@8aNfv#q{RxMPUCZ)KXaE3knDA5 zWTxBJD%U}HP-Pxb#yVZ%RDCpH-NZke-{WdXUc@OwMU)Gb_OesabZzzrD1Q$?dnM~; z*Vz_!5D!A(AqK3>)}^8@`h&fm*fSidGb?ngVXa$U@51pqvxY{V`5cb7A124(j@*d+ zgX=;I60+@t7;Rg788;i0eTXt)srJ#Q_c^)OuO;Ty+i7U#JlNOWN9|j;Pi%gUu{L<| z6L$2d9XfEN!~MM6TS0Ii;dR%2%~dbEftPyG%^=*PndHB7wd=X@#v*rj8r^FQku7%O zz+|qtP8@@b)d}g50>CDZ^T2UABa9uJ*uXJ~N$;R3Z0qgK(W|7RIp&4xtfict5a1vD zGU=zhb{afI4ab=}ruTZb-|rsx7k+R(j>Q&wfN_yiVkvNpJNrH-Idtoi2kkh8s>aP+#cd1wOBN9>bP64&#kBsilUzX5zfW0VE>Ek6Nn(lDV)UwRm#d z>fPG9JBoDPVXox6Tq&;hwbL1L3?Xg47D@Sp+?9QYduN$u8#$?W;>>+p_emJT4QRa- zk(5wU6UWkU8y7bUZjV@X$Y@u>=gx3!`oeJupmsQLTja8d@wy1k^i3#eLG?`K+xen_C%VnFue*P zF9-f>0lXUgcR?wK z+36WJLH={>=zJT_vyGK#z0Fw}A3-=55)JWBi3#$kVc`45bg++McgYQUY0l8C#9 z1CvnJPPGj6-;o^)G$$k^sP1ufO|HPoNt@I_&v8qEPvE()>3@L3P+St*OyaS(mdf)KK69V z4M-Ls9pBaO%VYhZsg5@W>HBIy)sfgkbBM`S3Bmp$DXyyzY_)o~EsF}NvWs2Q7w>87 z*f`FGz!8Po(R7XQqDLd~bcD}ke_CFTOYL|Y8!(PZ1~rprO4X!d6Jc$2l+ zn`qYa>C%X9QMQ(39RkK(O<_u>^Ub0q`g=+|K>Kc})~5Bkw92VWRmik*B&e&?>aw)@ zI4*n^lW6}kuKOy^d-0EPVQDsSNafg9?kqVlQs&W?DVfeGVm|gsra-J9q!z<-*}{w2 z^j&dqZ|oOjNEodOw`B`=X0zxIm!^!ZU#4rWHuEZY1v?LZoGpBojdC`@xHtv>$`-!M z2C?2pcMy?6#=O;a>FCwHeM_C0KWrpsNV!$%@{h-K9oKI9XYsbg>U zM4T9VcZ+WBYzdm<7SUX1$i0z{I<(~I2-06Sl^I~hPGrt&83ElM;qJ6K_Ls6>Nz;=u zQ6hL>W@Fps&}Cg$s@#&d-^y1m=XyTxn@g;j{wr-|q_SEOQC?h;$20SK zT^`ove^RQwl!6aSb)S^z=8pZZQsKK2JHL9U((qs&9>{y&mx3Qk+VPGq*R3!6uZr{= z0!f)n#h&h-svayki^T&)Oos}-E^>{8ugdT*-U+@fD|FJNHbix@DdiV^(4mM#NYtTJ zYre|a8?p_$A_l7|%FZL4SB|bJt6#)ZN_|uH$9M@29g2U#6(CLmeH*C3PKW&=cr)B* zff0L!H2zhlUc3#JzRKlNsGO-=p6Rb!UNI#gAdWLSb~AR4q*#7(h0ZTxNfo>6bzNtD zP!~6dY8@#FhIHyxogp3i8`P&rJz*8Eu?+^*4UC2q2Dc1@pM)lmMs zpomyWZV~-BHo##;ds)%bS&!#WE9EaL*{fA}9Z_pa2FI6)m>(+PJtZ0`j}%QM)?14H z?M1k)_>=Xnmd5JHI65|lV`B4rMeI+Dr%mh+c2S(*VX8cp1UPc zTB3@*MBn=h&z~pdMuy*(%vxtj@mN}osSC0~m89{7jghBtgNSrd9hp3mG*V_}S;)*_ zUABSM-r3eG)yOgPxY9ti5u&vV~FJlHa}784dh?MWH%9lqZ!G2B(+ky}ZGW((t#2;5&%!tk2V@ zw+@02>-Hs1!g;>KhqsWvaJLJ?zp{WcLa!RD4S4o$*AnHh0L(U6| znE^o5(N@dc^R8XX*fZ*5R=_L9Or_@r^P(d`9mEaxCe*~q)-7&xp7_Yl#6xty_~DAq zLkEhQaN9VBx4nXMM2s4>kpK8)rN^UpLtE@UjNd+-!A0gSxPR zkZ_%KXCc>Drg-V&ql&^I7_Z@%-p<`hR*O1P2he`P*t))~FgVztbe z6gI;JY*LtMH1B53iKq)T`_JWliP=siO?imb+mS%Oxr5A8*WkSNxkJltWwWxZD3g>Q zCOVa46UowLz0nfKsZ?-YSzb|w%gcoBt|B2#U(LMxA5HvzPq$<@3$VeIS0&vON6FE$ zg^h=v67HFm6!*#L6(W&+vJ#GHa*t}_*#{d3AYXyUH_2n0)ay<57ftwF6KtUu<6}*P z<}<3^ak>YnVY$(20`>HLji#*D0JT?tR;qt0uFf|IJMaL!8gMEe54aL+PYkKeXeka= zNb-0LG6twM=(O8IJ=fjLlP)J^A#}`)KXq)9-79f2YpOGIKGzLkmrpaNW4xE%Fs@xz zZ{v*2^Z^pajheU=YDlt^SfJZ)XNdcUXu-O>)xkmp$2Dh8Xf79A`i>0zH5m0))%Ltt z>mbc4bjk}f@$g^SOTjs9013b+TJXUZ^-zmA97xCW>^g*3ThmVsuulMdx!HNG8L{wq zv;R~xJlQM>(f!W|T3w$`B*B;Am$U&F2C?GeIZE&j3=d3cLj)`Eu*(8mst zlGEC-!6c<>1}qomu>q?K+t`MiqJEJkyOI`(YgX^|JOxH$;xp(GlYw9iEv>mqNbTEb zt!s~i67ryP%zw7T6aVl69F1+97V`ZT@lgwW*kXUu0;jatzs_CQYMa{(&RR zxbe+cZYKFTny$ziTG7_610BbWGUv5X2fx&c&$OynTDh8Yfv5~VZcl&F?tVDH`D6eQ z|H}jX*9O3=1Aekj`ArSJlX|<&{;Un3X)^=nkv2@jVeKaC;UF5A*S8u@F)#=MY9ctU zh4{w_Ep-lO1mfvGSdOr^J-xo&JsiCY@^E!9>ZN8wE=winp=sku?$ZFaWY@JCK!)); ztz5?;b(j#6*I!ROtfcJ};Rqf^1}Oz)pJZXC+T4_B9M!_seYe?bCrTTr6NCEQ#`W3i ztrC{VQTxCT(C|HAxvnB6#S=qX3f6an9eP{Ep*oSgqt(8lRXfV(il5Sf$J^4+w!!;@ z8$KG0-w&u;+DaVz=mGI3Eq1*c0B^U@o}*N~%OAvL-nTVy&QhGvRBDkj}2jBgJas$tJ>{4__QtkMH}4J>b=s+NqD)L zJe<#g**ud0#>3CEYw^32k{hDGpb~GA*Hl|h$ZjjYmtnu@RaQ_yD`r2vORL!28H)w8541TKh%Fwt;-O(a%Xn|{6 zXh`1LB9#BaK=slwq&Sqo9MSNhWU2ScB=+$ z%k-dB9JgnZfcD*1Cm8~Vnsxp_!cDX2`z{CT&S5+WNz|tW+HVh1?+hZ^jshIQVNcDf zJwR?*-Im`N9sH7+z1@RE(n!HBk-4PGk{Bchv$0yiu#4Id+`==2&=VtTHnj;>fXTXB>$8<0(Vc z=|ka}q1;d#_EYEW#wQ;X>%#Bw5WQ-Gx@&@$4nw%wobXlWz-`?vNiLt%!4Evcjeck& z25vatw{3ban^nythSp%;4Q+6J^0#Z+^qyMUj}Nt<80wte9$nZD7qlCL#kuYJyYXB~ z*Cw6TK4k);nVj4`9@#%>ezkE^ohpam4n(!H#o4IG`$H3}YgM)AC5o|OQrgusNWvp= zN$QNPIEvq^cm4j-oyt}A=vZY+22qSG8SuyDJL}R7W}ieywK>~r4{*#pccZQ2A(>w% zO5XK}lJ{$~UTD@&Cx>=1>n5|_&8$O{Q=)e}5<_k<4Ua#mHEV$JhvTy^ci8WBxQ}+QNK*H9$oqyw%iZ9GfPO6tByVvUF>tt1 z!yoL=25}ZQt=-Fqwmy+{UMk|1UEcFW)Y&JB9N?)R8n5ozFIYNU-#uQOw_owKF1qrt z4u4q($#Drsce0LmKhQnj>Cm~d=^MI~@yMs)cw3jcw=2ASxW09G@MM?s z6#WH09>#=o{_q&}*)4E=Xx|jVjbU(en7XjVK}Inhe8Nq`L(a)J7+y8!pE{ffx-Iy+ ztMF}CfHgS&p!pNM;COo5u%FvJZL-hb2J)W(w*&qWA}m4=4oU)ou0nB)lmnQ{cSBa% z!qqG}l`SK#oD(>-uVg?B!4;f`rLLvPZd6Sro}p;*M84X9M2_?_8by0?pcvv0E({|X z!P2)Y&)EjX=+UFbsL|m#JvNx&jMv7jR2pRv4yiGzk;TpE$n^3oTF-8pSD4!|pZ2yG zTvHcrhnl)@lvoRq)%z5XVlbO{$-QWO*3C?CfFRJqN$sR}bdFl$*c==~+uX6a^l?r4 zgr?9-Gxs~COCH-b7SmUDs*64Knb04LCAImO<*k{z*zONde^N4EoFm(DHmn3$#~A+C z9IU>R38XFqeVrJqrJBw8;z`yoF_SKC;?**|*9?XMQ%FV(ruVETUN+CVcm!wg(%So1 zhg#a{aVbB5vpel`JK3{^6hsxP{w_N-$%oR6BNN%caoB@NF4R;1%u60}2h^StTD>ue z@(O9ESu+rVO$Nn8>yZ)hlf$FMNMxZywBPNHKk0THf@HT0H|%pnaM6guh7tWl^nIr( z2s?t_shkO8JM4R>_W>O)5S+y=2_}T5!ZaXMbgZ(*HzEiMeuuG8PD~<^PUcJ>4OZ_8 ztf5uaA`DU$o7fCCv(}7^wJTidIwg;kthgN;>1Bv95|eToh_m^KDX#C0UaT(aCan6@ zaC~^UdVaWixl26VWh`>{bouvpiTk>KQhQ%Eq!IPZYJb?E;Ly^E@^*j`axW~|RsI-P zY#=RU1@^;Bj=&5Y-xf~44()Gd5*0kA?#Vu?*biGpwe90j+nHV49*wmf|G&1&`u=dF zsO=nF+YYa7Pd9%couh{tV2?9-U_V1WF%h733CANI>6hz$Y(Ecrijzx3Yoii&Y1Z{a zoWaCK*+Z|kwkxCPSex+?uq(sL8Dlxyj*ks#+`_Ig=4$KKXMs8seoc1?i6s{j&6}>u z8pxPfc~eo3IX;x=&NaW2sf}&SIjPE`vfKY;o1RiGhm}c&GDCXy>^0bMBJ$H2f(}hA z4d(i3wP%cN>6}*TlHR1nUGse7SL+#8q^Xr#qLGWw;SJYvo^%HX`f(ZjYFZ!x@O*LFX}a)+!f^=stvk zemsiKjo5;4-UuGZ=Z>l%yfB;x?+K$aSD~|Jv~$-8=O1JAE8WidD6SkyFNPaNq%pO= z_Q&v3iM0P$8f}fI_Z_=?giRpAxqRPL=-j(+5#hdl)v4Y1J7s&G`fbi5;Ps4o;M1e% zk1M-PapzIFCFqR_dH6bn?}2j49|`|(;k?;RSEuRQ zkB0EL?#3sw_N`SsezcL)byroJSAcUkI8TZ2If2_b+q#ICk5!>#^RqW1S4%I>xC;f6`R&(vZ@Uag5O%?PKGsWBk$bu5RbvZn%E} zN3Ey+J|TnfBx$!i$8#FeQ?46@)rv86LIO-=K|3znhrX#s9xZ}X_hMw*pOYgJxKkok4 zsQlSL2fj8`ec71&8i@BN#o`#qY@g{8hmEl}W_CMjq&Q+^{a2%dtyC!_Sf=tm$_qv~ zR|CD?$s_T&k>2W&NzVqSjBrjLL9cl9i0If6aLkCGe8qc*<*#Pgk|e$Px|t!=U^yB| z$@~M{0WbmEJ-4kesD0o%kmKXQxm7UK<9JR^!l8+G4|HtX^$cqDPXrT|S7%h6a>*%@1TFgw z^?-E)>DLytgr%I5LdPw6s(F;LhnGxYi26>aBOJl7701weB#yJk4wxXuM|8YxlAef@ z?Vi@D4nsg0Oy7==b~b`N6lZzm>d>v{sM)`s2N?2eZBbZAcig&bJH4&H*f9nZe@EDb zl(k)Zenx-UW9Z)TUhcm1d%w!h>Gv;Y9F#U^rGB&Mk1imqp@4s~|1bDUc?pDvPFf0u z!ysG&_Mx+vLBrty%ON;|GckHcg0}+PqoH&xA=AuCD6Hmq;NzjN2DmX!hUCWnX)yLI zAZYVfz%xMo6{sZsjxd`AwC|&^Z25`BA4d}}OuK;y9 zv|a;5C*|uPx)$KNjo01?UAKaB3&71#_#4Ex_g!}v;N76^g4X-Nxev+@K=gNj2R2^! zFbsH%&wU)6rwM$iC&7Id>}O!g^L=msPsqN;Z~rpjE1+J6);A!09m;P(^d`Vt8}IZk zjQN1S|3ipA>AUuGX#0wfeGR{y6I=uS)$9iiSAv)==G4!g@B@cyf&P&T-g-Ym>oRl> z$MSNFjzCzB{dYbZlfr1j8x8LM`6dCoT=FQedbcmz|ADn88g$WYeKS5rSNorJ;g?>Y@FwF8ucxdp=$_1`iv{?Ea=M{B)fC*|;nQw~rRLjYdMBoOKqi?Mk@L{iA*U z*PmFyxVEhT>}A)scI1R_M9(HmBzo+Bi-GMoMuJ#2wQi=l=5+sLUqYq_WNjy3+y1<^ z?c_vFz11Fna{e7?dmF?%AkIT^K6-D1{SL^t;Xxp5`W*D+Cg%xut`pXU6Jqp_ALE}f zM#W+qv6uJm7?TnI_Oar&v0}355nzAxOZ(kl$`5`SQO5{OpEORLJkCFHTu$Pz)4v+M zp5#J!&Ny-IINxep@M^gH|vD&fMkCSJQt4B8_N4QsXc+$PP!@i~?eRYTGP@V1o zwVl_Mk>z1d7d6&~?!ZyEbc=tD$=$FouIzSKb-M<{oI6(K2-NSK4%9-8Y7e!W{n%Lf zuxCs6hz@&sNBW2kEmM%+UG16L)tt1m()k^VOFR6Nr8dz90hX@s4sxzgVRlVN_)Ld$ z`Z$%1K(8G~YT8FaeggPwaWW*ap6}Rf+w~!zB{d$qYDXtanuSk%NJrFF zewdc25wV>S?AZ~gGmCSXtSAs0%epyIZi^Eu64P~deY$Q1)cf|BY)2es2pU4JR+V=6 zo`x8=H|tVTJa@`0tM`mVWk~$012ZeWy>;`%dQ3e(Og}eFzBDZN!Z7=)PV};W>-6iL zQ#*Oyo0PBXJK@CfjPy>JXtO#Lz>{NHuB@2o+wd^&rk7209vkMrJgk;CK87Dn-uQDt zHj4)aWxsw9)_UPv#Cz?!vhmh3E!-+tBGnlyvN4eSHf_6M8svLDx+V6@mOdIj) z8}Zr@1?<-Af!h%J#uufPy$zb1d2((zTLL{|gSzZihFQycybmYZpG;I9{A;57-9#D+ z0pW&bjtj?#2aIRxKDnY+J1nV1IH1e6dIyk-Io`UshvU{E@r}736HIA=2JZw|*cUUI+tAg_mz2JZzwOgX=ReHS1tu1O-HMyB|wk#dN zn#-N+_jzbA5idYXk+k7V(#t(!ax!1uNXKWuG{QL()cF(Oyb0>U3HBf#)ym0w{bbEGKZ~$( z5)bY*`=}!a!_C9hDF=u*_E0z3Jg3D4@9ev1S06nX?wY_<^KDNaby}Q09F90ZeL%0= z<$TH(&^w2lbj$2Dbl-4TG2BP*-}{Rn_IJPE-(PwFt{m>(H9_4xf%^UOzURF;NS?mw z^TJJ@_x2!=;k)LEXH3p}-m_i$IeJW{i8}k*jR~aB(TShTZwOf6GQ{(U=h}wrro~jL z#WRWxni~8~{Lm}X6RljR-fxbaFq>8>Obf2_=t_@0<2(+2%Gzu;FQ|O6q>Gt~F`rj~ zo-TwU!pc;Wf?^GvWO}d~<_r}8Pe8E0olPAuDDMb@ppGp72fCxwNIk|}IbKdmuIz%$ z_-HB}o7Ol(Pp`$*E=>YPNA2oay^pgzP3CG7ex1_mJpsR>?(6MG~m-|Qh7x~hld?HxVFS#Ap4Wp*B#5}}%==7cx2r><`o zv(+3@EM7K$TCsO@NjqNFp1QPMdT@Vd8iT$b6-y6*!w&G4A3#K4Uo(ja?CeP2r+}=fXVc3wWlq#?y*4!> z-H+eRIcuuFF&Sbjhe>6r^-L`-?t>2t#vLnjvg%S&pS_0iP$%O3Sjk9)^tVgcXvApKf1SyeeVm=~C_ zR8Y2eT8~=MV;|ikPUu0WrPby){$NHyD!Z#+tlapY@B#H9# zNdyTWn`F<=v^niuc(9e^EGPcJ4zE)kHie#l(`3AQvbtunhq>;6G*LBL9o^&H-Gi9B zy2rn+2d?e;NvrB7V^hzI0{uF&9Dp`qV8+dQo{H@TuV zH+d-@2UYID9Ce1<>{Ev{8K#c3q}dGJT>Ag$NhcBFKQRnb5eHk{g4XlX;#ViDx$Zpu z#$WGwjYcjmtrC;kx3GekD@ktMUJQ=^4jIT~ezcB$Nd^#ch&4kk7 zlbz+0@$(-4s~-6B|E*i^<*xY8ZruRz+!QnOI}KK}!6Wwn(_p=94}EkS95GEfYXG*9(=drkQPpG;J+Jcmf}}^$ zHT~&wLQNW*yeV_B6AlmY(yj>7e#vnNSNb7D|Ix!mDD?Mm7R-PK8qohU*lpbm!-$wV z%EOby{#q-_}XD#YJGWYK7vToRnBfa&;+C~))49m*e)y@B1 zN$O<5rKEbNDxpVgLRfZ$FhyKEg)?5~E}!CDH3ipB@z+m* zv#0zov1O$5;&>vB@4G8kbx*{Moq2MUx_uNpJUk(i+Kk!nZXFeG^k=xs4EYIoFy?S~ zY{MqlSvKHNptiSbqyB!C#D}#|e-6~t=Pog!zCI^@&jEcZ<>f@SCFf+Z;OC*xA1zk) z>nn9TH?SP$K3~Fp{<~_zsCQd}yVlrr&a`Kh5S=hXJJ;gw(717ochr^l~PH6!<} zsrd3#^$O>92M_)Grl>~o-W2+@7bc}&nUwo-iucVFd~=Hb&J=ii%1;I%Bt!JNDRADD z|Lln~1jktG#{Ski7L%NeqwxYl)qPovkH<|%k%B4>P+xJbs$`vp9XKnLayus(h17A^!_1`M2lxN8HMz+3x9YH41|rgd z9Z>%thLIhn7#gI5R6|UVw$}B^bp5SK#GT3T0mECZ-kq%5XR=>i6muY&lG3rY7Vzk# z%ng%F`1>~Oms>PZ@2oCmICrp#*}Fm;ws+}bD)pDvb7C*=j5OZc3pYv-gA$I)vPkDBTD1K^V;34cnQ#}RX! zin}&wR-g{lR>t&oIRwIQNYidOCkg-hWf!M;>23QjkJ#AyY*rn5?{4OQuo=9+*-tvJ zp4+2Uz)@v;h=45!J^=PRqpDgin2TXo8hQ_a^~S6MJGaK7-=W}Y<7hP!j|PaWXE*ut za6Fa|nK3fmWFa@WHSnEH0%$_(t=WWOZ=7kI%z5tW)R`nz51$FU`ftq)Bz!sDI5N#P zS<6`{c`yf!d)uVMtCd75qie;bgnd6Wlk`d2*WH$hT@A}<=rOMU!$abos=1w{5(l9b z{}a1D0P%@vuR(bt4*Q>gwCdbMbIDrY%;w~hwuHB**Bt!6V_kQ}OmX;3wS1-v0xSQT zE>_R5^Zqe2#Htx2-%IJ^X80$}fa7QUB-lL8jbEH?zc5?U8U+pN=+YVDsu{R;hF(7d z&Ytm;jO#^$J2SXx-kYt*Z{%Ns`PWdnKW+z`!2!&{8WP`nhNQM|l-*9W6GtK}8n@$q zfQfP5F39|_k|<)JnIT8?7doR_m%x^6;`s0a97-zP*I=D6w-ImVuI|@=}^Q|eIO|PFkSD1nf%+a?aupRvrN8jiI(U4@tooMpv_b#+fpEt-;t{tG4 zlDbUfHb|C$GY}m+FE&YMlB^X69gRsQS~uDBm4neH7k+PvzRxDYn_MF+wFy}r{1X^G zYpvPbk?D8mIP>(ybI?_%%~9vh5t#Nx5OW$}Vx#UQv&F5m@sip4vf1j=**{4lA53G_ zxm(-BPW{22CT?=&Z0DNUc=l}n+}Uu>Pha)YG{0yvtDI|U58MMd9uG6V>}?{HpK&m} zbciRh-IUEO#1w6{iBvo|azZq;)qgCTB;`pL6E4tc-Mx8%ivny+?$p3Tx*#((_y64v zGaji{?+|LTU98tO50Ndb>iyZ`liBD@kFsp@47t3}PO^*kIMK-v!qmGY9XL7Zz-_Hh zHgDB=P8sXk8_RVf=W0)xel&sPha~yk8x60>8h?$T>{lXUQi-*5gtdHrOrmx!Pc1*Y zIeq!@^YmhM(_9IPOVpe6)`gi`jRYGygSO{#UabxP{!(D<|A`Y`>Nl z8Z9qx&e+MiVt#!6Ty^tYIC>6TFVZ(NFS~Uv(y<%nCV-JR>=AR|4v}6ioV(}HNch_v z|JFHh%bcGaeF;=Nb`Jb|_J2af&wN-rFEPQmn18>FXg@k%K0V)inVJ$$pT~Zt^Qal$ znU~J1iY&qnm7h}i!hV(Sl8T>`hs`yP3iF+MZtp<4o-(y>Xl(A@4@yrofoJ0gl@J?R zEDr-QSm*n&$*D5ICLH2VfJr67wuOzt=!BX7Vv>YS%TVgarg<U z-BesVwQ$x{rHAV*I|AqXzwScd{9#qx5yvN9k5XK2vgL1jSEJ@Nn?Rf1an`B@mH*7G zHpt{wlf_y_wcgDZ7=>^TYr_K4H|1DDG5spxmaGy^kflT=+}65^ZpQdBFFD(p&bTac zCW2eDHC@`5*s$$#m}2$LthrCKv3WC60Uv{MdQUZX1q})Gmtu=?GfKY=rF&s?KR`B= zuLr5QbIWmMT1&pUj-cD7IHxbbc7N-!1u-^Y{=`}G^jUD)ERF8zv+TPzSNCqtL_xrr zSYG^o4=a2h%y+pqO(B<;B~GstnWaRhj4@NAaQ%Yxi;ntXmRCp0A`X#m0B25wuQPtV zDcJFj67MQgutV5i%-04L*iUZ8xV-cqxcqQIgX*;{@P#e(V_L15O%m)xu#W|lb+#9z z9r)Yk@vWN^I+qab+36roy87n$e{@jMRI;|;0r@5{*7yzyP$Z?9wk0vd z=!>n?+*tG%0DaClg>H*)0iF#>P1GLIDvuONx~N`aR7ASO{4x?nGnamGvZS6V7f3tj zcr7+*5~*uN%&_kW2hC7d6iA2_bM*r1%ef|6SJ_@24H%sSd7PO<&}g$hZ~;f;Chnak ziCh!4^4;78ds}xejL~j^_xbgM^$S(Ax3nq_tK!nC)4xVIWg+K~yS*2dR(WP7dw5l^ zT%gu0&{%PXMZP5FSPFWajQ*nD{~*9>>I9iYVYDHR*Cn$0~D;se+Sp(9UN| zb`eV1B3A4&RI=qHAy(7Cg#AvoPT0E0N#r-O-%e(~RavRAUz7AIu$Iti5mOnV7vk^@ zvO)MYrg|pU4EVcjLa+Z#yMdwIAgWk5Y#nPul4(rY%j?AvBrW0MdTzq#l6oS_<#p=t zI#^cs6Qrlqj}=(*Q-AroLPUAdRxHym+&cF`rH>Aetk1pI|Ko^yBFfhnaIc=ewH~}N zMz}A1^wFl3hZ0c?psxe|g^Fju-SENpmVAvKFff|R;FAekCtPR5QpbCG@4BG)4&Ms_Qo zSdUF(RL}_yI8m$g(5;4J3DP1$Fq1ah|$nm#*a zuTR;3O*t2*)I}-#;*@(qN?(}rLI>2}Q@Kok3bfY{GbU%yrGP_|Qri+2sZ*(c*K%@# zPC{q4S!_cpwseJ-9)vJ5fn8V0#G<-+E#NhzrLnf}({c|w!|dtS8QaGaS4H~BD5Bx# zpPRSW=Ha^#&b9l;f&Ib$B&k2#-@bPb{8t#9k+)CF<5&NEidQ>De;N8k)zqXp4ks=1 zdI~49rRItBI2@L9Pg^|fjKv|UL2R?rM{b-9zSW4eX8=FO#PjB20!V^WZPzrA?}Sz=77@#-l!$8+LEQcvxoo#v-|nwRjinc_?xv?kK=4hw&BdjTp~ZSf*nn<2%m4ug+DIdUi-dE^|J#LHF&TrKpU7^)e#6RnK<%{iXFhvZ88~&mWT&3 zKXOK*)#6GxP86-)iM7dw45^9*bHClq`W5JrlX16{;A4yM?~Bxni%8Fv-jmyjC$>Xyr~|w^wu|oG4({6Sr*p1s1;_6Yui3#q zaR<3(2ZfdSa<({a2X*=mwyY!F+tsdy+ZHn)zI6w}p0ZW9;G98rbBemPUPQ6u26~LF z$T1SmUSu+U?BK5gRaVad?u~cs;NQ7}4(x4YCms5YgIP!tLZt8)zILt{qgE~!&o9ytdhm~JqGz{hdwfy! z)FOCt(NBKaRSSK-Zftb`4chi1fjf@;RkzWd^*4+0)5Yq~;@d^YL;2lB(Fcp*{Y5|N z4zgjPuYKc)N!*Psfsq|Lm=Ds@0eE|RZke}sY(oAIXD>D_u%q1~o3lgw!7c&JOuHCB z#CvC`yx{L4$(JbnE^oh`m(5B#?M|J#-LwDZ!L6Q&wYkSARAcHVg>pZPQ&p_Cb!TUXF)3*xOjj>Gc`^8AAT zFDG$I%RC;dHxyZ^tBOZrj=i1OKPjEz>f_i3>dH-`(TtMTh>(B(y#}5H!{||iafp(lBQ-qgg5iC+ zI~qp*j=e|5?mmIm6Ms87)03NOPiff9o(7whr@;(49cIaydTQGgoQjTT?=wYCjixwL zGgHRS(X#~|!`X6<@3!|Go`ew(KOw0sZ_Fe~Y>W3lhQx~X+D`Gi+pCYZC#B@B9f-Pq z*dD*$-u|;#vb`}Ve!STKY%zSg_$R4!!`8am&yUYCjEaF-8}8IMzjY2IHiT?{6QllL z<6~`}sSQqbH;Q1bTD3)xs(NKGvG1T^O zuG+*DJM}nzDSx9Ww(h?s67tslJIAN(XwS2s*a08hfyU)irsZ;XZSUW^J>0YXPfjf? z*~Z_PJLP0Za_?2l)SCC7hS)mOR{hGOpJZX$ZGo|p+z1CoR_`9vUU!1^;?C?BRB||V zjL$x%EHGc*UOlz_@xWEkHby$0XsQ7nB^3hiV0TkU~GCj>oB!3-M(g1UN_6Ch}wN_pEWOMTzv91n7+END1`if z*zQ!@w%4}*B>gn7dWV&DrGb`Z$)v+-;QR=LPMVFdO+@Z+UN)^ruQ@yDpDfmFN_q(JVade@h7qJ`kXp3rNG&u`mp>yY z13|s-MQP3yl4>U0A7*1xIm6=c3Sg>^YdPPT%uh5Vw7=?Ta0kHX_}jMiR=0Y{4-|2x5&k~SKn}dk@G?mGd?;g zE!Cdb%ywO1)VtqX@9YuDAzUduEp1X2Qz?fu#%w>f+MBV}JlR&Ouh{gfe(Q6xCSJCv zoNGvlF6-nyd9Ep~ZBwR^i_uVDyt!NMWW-!}=Po{}>dwZ%+Lh)_eEcp=C-(}j5&Ghv!9_pgCU|Wxtio};8{NB?u4k8(GRFKDNR&Tzu%QI=IE-6a{*yPcopC)p+`dVOHk z>b;N+9m~ObYM)p$lo6aR&B-9Wn=$@N?KtUmw*6OIoMnrPY}{b8dxn3Ht-jtvow27t z9N-M{1u3*b3FlPXKFNkt4fj(Ro?`1Z9ac9HB#}unuoddWIqYm|iQm)v2~*O!fgwcF zCb~@}vHeYNBntA3t_G`jn>ARt6#dH8{dty5h^@U@{WQCBfc4bA@jB?w?Qk}Gmz@BL zg!7sE7VbpqYNrAAjcFMNxG}7V|U*bF}j%$03v^cIG2sYLbnoNff6LJw!#|j<0Sn<-3v1@s! zOz9Qat$o*87J(!O@;%%tyIHIDi&-Fjzo%Nd7pb$)>|1zoU;7W`KiYp1=q8`~d;53J zAMt?l&+T6%$Eep1Vn<8+K>z1H!qxkxuiG~*3%{Yy^wXgC&hd=jDF{u84*ek}DF-wc z%+Y1Ku$dP2(Bw~Rv9t7P?48o?q@lneD1B}|N!2(a=f-kWDO>mM7il6lV$g8G-qFQ- zJDL7jl5R9b)(0lVQO0o!un5Wt*qUyvp=Gn4MC&1J$8#n(_GBkdv(Dc?ZgN{}r3i>K zO{6^+wJT8^wvV%PA3D-3jM0S1_8)s^U)-BWGA*Ra(X1YdDN_k&>sab!|ZKsEj^%$+C#UbNo-=; z$$*(8)Y=z8MteCd`jsr$ng;ii`>3b)asIK7dT}2(X}_9#{1OS*h@W!D_fY>J;K6-N zmX8CX@o_k^&sy~kvO~|CAeVs{$wsOlsrw%2vj&=I8&odIpPC4yZeJ75dVn6=pRwsMld07!=OJfsdv)LVwS7751o7TgxJf)iGP{~tet`Tdi%gqIj~Ycgtyov|b1n4q z72xoQb^A$foTp)vi@l`>;4?h595~&0FY&q_V~AwFe!F%Kb$LE->SBg#0-=s#a>?I^*j0mlUK0E!ujT;HCAVpn?B5*iQj`4)R-&&w-uu z?*+$`k3#Sm4L<54dOcx^3p+ZXXA{2&NsZ)39YH|#a1$OTCGXoND2$o1jm+T!cMd=F z2Bp49Sa43;4=9IgkYi8*8i=@pXRgs`r5 zl?c3M%t*QwJ)bkc-3pTT<(>cY{5(DX5Cc$G<5hSZ1Jrf6Qq^|uf!fa9uom~E7yI2> zkn6x*3u+zASPKq`OmhUx`W^Zq`hKL>LbMJ_=A?YzNu-Yz)vY9t;_J&4ncynbc)WILfwog94Q^R7U5!)7a&}S@;p=-@fhZI=|6J|JcZB$eULm8 z)i>adfQy9KAm9=q9~1HA!hRaX4uXi!HklV)A*CIZG?6grW)7EImcvXB7D!*Nv%`9o zZ6YAU^F!&h3YFMOrorq5GGv(KATvcfk}IXVN;;2iu<2L&u4S5lge(i7? zZ{HVcf%qQa2asQa%qcCO05K%`H^}cm{74E^1h531*hlwjF51MUn^q%f5O<*RqE#q{ zq_0O($phR^oFH5xHwRmO=6orfCq%6U-W1Lc7`uBWh`J6w@o^l-Tt`8v0Pg7G?zwVQUq73@Oqw6~}hwuQKOm zokAA<;%cZc)R2A{iux#&p@=eEqq&hZ@OoKCiX@80tP<_%Mq3NNhwe6r?sPB_Qo+#0 zaO-4(8Kk^?jLv6lL$G6po(-~*Hw7A`!xOnb(MbHKVJB;Y<}$^^MTNLhMmI>hhFV=0 zGn~xKxX82JdRXGV^UK5q>|ZrkuyV3_P$b)Rwe5v)Xan8*0vM7WJi<__y$QW4v;PnE zKO}sMuwLXGrjCr@NF`S&CFO_G|3Hdor2D*d>qNctoOGU-;yEc^l&Y?dP@4UJS%hot z^bNL`6;~_qiG*{M9F_S@5{ROKP9xzp`X+cz_EWq~6hBp7A(cbuZa?v=3{&DIl81z@ z|3bgguPFVovOiNwm8x|kGAlu>0%6wENw~Pwq67gWVK)%AirU3M9OR#={ao~cqDSgf zLF5H3lUT%V<_#oZ<5sEh}D5Geo+l%bAco)SDzIOJ&J*y0SOT+$4x z{m6KO&&c>}z`GURjkpW-S^|*&EN&!n29|Y_gMQdCkHBz_h*>zoo=FfgWb%z9Wc+|M zNBWdpLgY5rUM?5wiG0IsL%OOXJNy!wj33H?OQ5}>?R=8;Ihln5QF1Yx6~od+TZzz* zMEJX$%61Cq5~cG0OkM38FncY)l+0H!_#)6316%~HwB}>MSCHp2hX~`?xOFeV z=v)+B0{UElvw=+u*)ssX1%@j(gP-#H+|~{^X1hB41Dos;BiCTfE={c}DI1oj$EIqJ z7*gA&tTpUFV{+KPMUTozf($R3n?Daabo)Gcw?xUt)Xl)HdGd-O#(~wG58lj>0+=if^iqaQ0rT+;|1)slLGNI5c{R~;#@V^C1@XpY>i4`<_E~2<^Zi> zxVjd+uEdSNg_IOwm=Zzhaa{6`C&qT{PkB(WZpI;TKGSP8kS^k7y?jP7WMJLW@l)kK znEwaXkvniML3>jR>kxKB%tLRY=iC7O#;Clt2I8Gzm+a2YF44|vm+f}W?&9t2?J~%E z0OO|=Jgx|2w8&=Ccpg#k2m48q73x{39+nxLd7*ND3%_yK(jZbK1>hz+!@ZUr1FCvs zDc=W-{b!DB#vL(A+}nnTr63t&B0!d7!WAhjYCDgOr>^S}7IVWvNhP&knL=u7VDp{z zF7D3uE*0xB;do5UO{llk+Yt)-3hYnmNs%^&=-)6^Y|Fl94!!ICmbE$Y4jKfaV#R~4 zcQR}dF7dr{bloQEA2yziD_V)~(Vj=0V3?G{TJ_k>#;|Cct!XuHw7obi%A`Fdj5|94YkxGB?aQ$GJ~$tMcM0GI z(3cRMst;hmUs0ZcQ2XU~q&w5rdZdAP z^tYS=AJQj)ZuB-LxZ~M#l0lu)!+H)5txAV5At!X9!DJ8cq$zr!LO-2OCG|<0PE5dW z+*P1gt^XS2H<0-nQs3|ko0qG+541L~>MnNI0GtTbHKaB?L}S|9QSL;|y>n`B>8c18 z(y&vU*hFD)8mO}XPBt$aaapHVZFnsykM*Xl>ta>lj%&v`!W17JD>~%%2|uGTD?IbU z6%HHrSQ(OuM|i5!x*Iq99Ml&eK8Nlvpw;@ulw@s^VzpAoDOz{0RK&tr@12JwW|xu7 zh(U5OdxI-rZKk#6lr^>Hll5a?0glbM0LR_9UaZ70aF$XFBVm#8pF_hJu-{5_S0U%z znc^+Q>%lq;*+yFQIP{3$P|LL_)?suaYQLeudk}($Ks*TEWgsqvrbmeNDrx@%($7LY zfv%7mK-H<2K)nfSgg2TK^DC@+eMkQZa!52FdJDpnq;n0zYY?Rf1wRftDq`@hX!u(A zw}QGB92;*YKF=lji1UZHa^XrszU6-a@jdrBfK|->yqk$F))QHfn7Ix(o%DSDBb}$35SUP)1z<;-&E1qO`NFY7M9h?Opnk;rwmAZd9*Z%P^QI} zG`_c`rO64=alwfotp*1TzE8*4j2`P@#K@=@W8xOso+wMesTgii%SZWIU-?4$U)yDb zJ_b^s%vg!3RT!*9u?m}3qFROSVMsW06%I307 zWDkP%n2d2Saw2g@2{ZqsHJ2@+4-h~f5}>=2!}iTRgx0cwZ5P;V{u9|s7puBj+o!YW zynK?qT{)ZsPP+sds!o|n6FC8^*7{>G&a6j)IFfK1(wHL#eH4mg&_0%S%jh2g-ZIuP zbrYXY(mPCRH-7>2*XzF2<{H;uYdMGnjH%VVLF4Jva!)91F*Z^`qJcC-cra0*d;cwr zVBEp1?}l9)s5Kte7FXWnBEzCpv;~}3h(9#+>U~ey1-8_V5V4x>j!@l7*3swneRi_8 zae!>#v4z@`l9ejS!EZDYad!CIa(_cOrX)+M%Nwq`@>tNG;J9>+jj~Zw6CMp4fuCmJ zcYwS_;*p>Xk_ zF(zGOV54QNW7=%AKKlRT8rGH{!;Ab!ks-x;YTg`n5hv@UrJI%!P@vxh9AcJoZTtVW zl<8VNkFTxA4qE0}O_gCzb5=vx<GeL($YlY5UJyWa2DEm&)3gppD zL+WW=9@10-s19kR{pKNqXx%ns7_A2n8BXhtA){#BJ!BlMM-Q1q>+wUT(z<8J47zGs z=Nwwk95SEoJat860Nq z8F#9E(m8t@!Ij&(VNx3H{nG!(wj0<7e(oG9m(ufKioc8=2tD?1QP>B%JX`QvJ-(ei z?td=Y6H^hFqAf}eRv;z`#UL#>8o_ZA?*m&(BdzVMTVkAN7l#>yw+@EZW|^1wO-qN? zHV2QZj=c;%1NAA;y8ctx_A@&C7I2WI?YW_h{E!$0eGocn9#BM}DoQWW46oJUIyJ(@ zVi!)RjK_J!xwzfnZGD~l7S!heUqGHNAb>zGTF2hKipwPp^@kBzzrg`84%{i&n@^Hv zup7fj{&_G~Aw|LrWrda^ErUg)@d~Xc!In5UOnr>oy~Wxl-mG;dl=W`8X>v1f1tB47 zhX)~ksMZT&V=p`ibFB?3)~yc(?EAj~TaHwI&Mr`k33y5R(q5@H_J;WH-Z)hiFz|G9 zb02GX)s&0;J^m7!xl^_fKa(?9RB#OeEx2B@=h01VbALB3Bz+|QyN{}KP2ao%KVU6= z&(^hVrMBI!ww1N*B5Rv9;vsNOgv!|HA@gzc$uENS3aPtox-vku199!v`4wWO^@NEU zbk3EzdaTRaC43`t(0e_CHzJ#BSz+*Iqz?>MYKKrZad-NB>R$IGj2_g%5TeudT1l4# zgouez4isY$D>6ILnTlADdVzk&i@tZ^2X_pb;M?;R|E)G=)$b{wdvC<@q#k)#aIu%zcCPBOEMn4E8I;}9Q|gy8sde_qwoGWofjV9*+4px=l}V^;mP=V=(ej?uS?446N;Z4z-;ov$eK4LyS{n z9|!AM8j)$P(#}D@G+qYF0&v-LxH#mp?*&ZL|16DX&fuNJ;Fi$W0}3V72dH1dQ9pgo zUqio*Zs_9h9GW1#_eg=>QLZ#zqWrk$>G!38=K#z%lOyMV>PVV&chjWXSliqN)`hO4 zv!cRx(j_im_MYv3Zo?OLts@CnTLW+;?#DOHigW4b0VXhbPA$#exqWH&Ce*ff_SH}y zSliy;mw&HsySTP>Yun${w$#Vk!#aVKudI+)!hX|tMCOM^Qe8>V1MfnTj;0O0-`_{HxuH;&huI6~5`IheCKTly7+f13gCD`FbbyqwOzs z;4sJjo6vXqG}v_AdA^p!{UbYNpYIbJQR+NjUgoPO{h*JfUhD@?`ub_V={v>z_B*HG zDP;@!4`08;DKao)r!bhB8|~fZJNNqfLBIGkjbIY@a;Cm+TQ2T>zN=sM@f9Cm_T{&J z9hU#?`%41!;G#f(;;Tuj1a}4Ay@5K8P`}Q{w|VZJo=s~7_j~rgJ<~W(cs8d&*`8>; zn{@C8UE&-3x%3$|Zs+IJdA7Y+e5P?U3CZwqum2;ScS+ZKnyY@68J@v|fxb5&mFi9r z{Y_v8p*B@U_wqnr6PO@dTV4{>Uj7L;ceN9~q(=2eVg)?CbRx*xCCM_O9VjOXQ)(3j@ z7~$|EHTsG(!A5=gBJ=IsBI9!T@dcn|Ag(g_?h0_ z-80%_*xq`t;=bmN2jmK2epD@4-8HHv#SVv$Nq^Yp6?h0*lR@;mhX~5ju(}dRN9P0X zLr{7UPD5*T$YOPx9I0I_>)c&IZfu&n_OW13%+N0d4+U)mhlXIC&Ws7WGxc2cl12$E z4c$w_(q$pho~UPL=cUm16%Hh%AiyJCqbxGMp53p>JgK>p7ReMGE#zvz?QuFZ%am`F znnv*uiH27Ib2`nfpnezR2zFk{A##v%<5GrR)=bR)t1rppHmlG&D&>%rQluP}qZsKw zsWoMpGkZi?Ls`hca_aX0mts;mX=$Qe4ByV!BX>3HS^Zu^Rco6K)NcNX5RCn`b$2Sp zDDrh0BS%+NLmG9X9HTHUx!ul)fEK(uKH4%5i-(t~j@6W1)nB_X3 z*Kod2gIFW+P_1E>C&j3?X`7mvvV-+f#=&|A&WSSTM;tQZVWd+mjkrbFtlo_axYDvC zJ@J2>nj!-`B(m(cMwX2->yevG!&c0?(X2Z*9=EpH#jt2+>~~eI4-z7;)rcN<0Ffn<7aNL-&HZ7#&=D3a;tPIDj4z+|6!!aj^n!j~h%L;J}*m8_W zYIpS>X!PUA+9r!b0mh9QOC!p&~2KjIh|3SW=R5Vxpt^YG?1Znv)I@>0XA`E4kPtJ88wbs~~j| zxEGtyfCQ2F$TS?>2tG$?dph5506oPx-j0_~kv^p8=-!wjk@+WvP^|plomj=AT|H}? zU*Iqh+$eW1*Ra}j(SvQ(>9`PjC*{y? zgv!xv*q&CfM!3fdKLNhWJo1&+3*S9IN==r=~`aAM6qxT?=Sm|sim`&iubOAuc{ z_$8>X;4cS=pC4pxN$*V>I=dqb(Y|M2h2k_69cs8b71afZjjA)mJg9U-lh=qTMerd7 zN{Z=Xh8kCv{`OGK#r^#FR%FZ4Q6NWS6&s-}8&N0BcxSvCsJpB^k#= z@`T+UVvj*Q=u|kcU@cq^TBxm>Ws9KgabPVYZ6-rK?vPsPdUb4Q(s_qqTO`k9+cCRs zcH)png!?dnrh521VziRrQd(Z_UCD~2*7 zwd)NI?aa+~`VPC%vMvI=1;E769R@fA?q^e{%#dX3kf2J`rqnXf#;C>-TnaM{NtW>4 zZcW@VqXVnf!f7dYDs~m=B}Wg3DPDS!wNA!y*N?*e4)7@Sba;*s>qzf)*+(r>p%X;_ zoYTkqR+LG_(b*`|?`ioWu)%Gb+>P{m<7inB#Bzr6A(w=#c?_w2p1UZSWPhVJyB-}% zt+z+YNqfVwD^F*Qs=drZGIm-?g9$M_M>-esn7R@1CKM|EyAXG?+o%k+3d4v1)PDR{ z>tvDNsuEJ4N$-Itv;wJC4+sdScI+^;$(5pmgUc2cY zIBCMeMD8j!9_z*fEaF8NZT@#vpTZngr7Zx~nQlp}?1wMxEkZ53*22o06o;2AJ^m=L~rQt)t^T8je?1g#%g1o*kFKEqT zHSlb>h^MH6x0ELf=sKsD9K{pJ!6%tJ(7zkyUHFq> zJ8xtC=uFX@h={`W3SQ_*H+v7ig1TF!5H45Ix!T@Y9gl>&LN?gEDaAX~6I^V|!B`68 z;ESJ1@d*KSXEV{GQl9Hg$*9=x=cND8%t?<1JRGqJ4+F8SuBba9VXGrVlUyKGr5CXvG0_gT%mbL&V@cYn}gZtaZMuZ66mu61^^*(_}a5S`T~F!!hTQZ0b)pG`rf| z(=zE+5X24Yg6F}%1**hS^{`7A3S`#@2M=O)*iz?$!@1sWBr&DJ(O# zQ1?jt1F8Sbopz1HOQrfus-fyZA+8hLZT@+}zfiyh;wRG&y$)(_2MQd_(H4Z5tBgHvapTjQ^vYfi#RJxeN6lD^3!mKy(8 zY1e8T!w?DCfd$NGsrR80fL{y>8KqL%q#z$;;s}CPcR)|tOD$?AY8c3>kT-OCr|O71 zMaS;7$fIp)7T$aDa+qW-TtuH4dde+tDYvlMQJxldn%{OywS{lzovXpR-;E0%I2q$o zh#V}G4(xNaJVz5+9H-w?>T*rolc%J3Lg#O;yxk>u_pGh%v$2zu`*pVZhpkHPRYF`Y zN{V_@sa!Nzj6m7&PggzQ`q$a{tL?oo9zUtC-EI;*(|IAv6emTJlk7=}h5JcCS{Pwd zmh7Z@3!8{7LrX->wkwbf*$G_pL!{|B_tskeGEEl7%RWy*pfy+ z`rkXjdrp9L?>iwDiAw~i&O=5$y3?1Ja@s~$K8AQ7?>*0TO2=AqEIUsWkeC!nBWj65 zt%ZkL-}&-wKIt9Ie2Vf5g!hw+ze4yh+4~0JW7-Qp?;$$+dV#B$Tb3v5%lP~XZc5* zft94LZJm(RPF!+fXP(3(`r>Rc?Cw!gza;ARs7t$(DKc@oepE0qh$rA>YR-jA;BFY! zpHQg&La6iVFUN(Ity&i9t*%7ty0C%)jZN2fbdD6xvg>=^aP_}AHXWzI=ei|AT*6Kk z={O+1A35>gAag6^|Lxn0#kszY;7#cN=p1HNtAdxu{CO(4P{G*<-(wzA>r{wYr^tpK zOzG-MOwU-{?3ahja0tv&?} z&dKO3Qf(RAr2>%KAzQE@J7GRP8R*_A3i4D^%YY9QgB&&~VCakxUmvQqE z2|m*5lD2KjOf3YQl@nX@e=b#uEfrmk>eF?kmDDxVXX-NE2zM%RlP!~|0(qhPsN|NH zXGbqf&sx|vMNGXOW(=Hug94rd@o*4vo(JjHWv~99Nc*qLh3T#8Xb0>;&LgSn} zm8#OvlUMrUDnAmASBld^h8v$Q`tJqxoO@Z`;}5*oM;&3k<7Ay&prwwan{u=h1UMWU z#51JIcQ~D?4ts*eysmS&#Ddb!aHpc?x~N|4cAo5pr@FldyK{l-`u7R(1knKLKa%ue z8vS0$4pWgGVic8%PM$ie1>M0Rj&si9%mnkQ0-};vRO3ktxEbK<$h#~gFt9sjs+s-F z`$|&m#0i)qN*c=Vq)roF7E4En^ihJ~$#?9!2H!yOWs!LgQZf{3aOm6#I2oIs;o+X~ zO@8?#6ymWWYu0C>ycP(=B0cG3q&8bbs+se9d$_X_?3=;60B`_4hhm{S#B0#=a1ti5 z?+2ELvC`Z|T<3a_1H}#05;WjFHHg^igVG~G;{TIyW%#-zz*iTG48%puWFO(2#U0i{ zZ9S490n6ruEmQT@!nze09gVO8ha8Pn>)8y~DGhEk62!hW1Gi*^(LkDR%3!Ll&)l#h zr>6G+Pe8E0SkT1?VO+4KD98DibcP}-R&k<5COkM z_{$_!(0d>bl)qyCDV_!FB2Aj~Rb}cG0XGhZ7|~zcI?}6^nv)aRV<1jt#@1$4?(dsb zSx@XGirxpm$!2>SO@iN;wQz?PV%D>aBx!E)4mg2s&S1b z{&}JnP`HeMBMBn9j`804-NH^pZSMhF;SoLcHh3uw{Q2oTYS&aE`b3}%-a)LHy18V z)&Dg$95bh<>R%RxC;b}$TkI@ZC& zwGhP4D(F}X;X3d)`OB7TNr=&3(EO!roa1S~Z5_1D4d&53O6!O)&1OxqxiZ;Y3)an? z$BOF>1-TWzcZ8oI5nTGYwr&=lkD&8F;xKm`~*1Mo`6?k3FM`7v1a0793-~T2o zeH|W*nZeGwsI)escF3F+l`f5zQ~zyV?USf$1D2=@@D#+$1eQo5>?w8-1H1uhZ>I&f zcefM+(gXZGIa0JDi}-g16}(1s)(#K$;6&U6qC3Pyq8P{R2twbFeDHmYI>If}X>>BA z4Ep7Ov1FUymJ70b6iWH~p;Riafl8@-CFqj67XF)K45@8T?>o@)D2%Wk!f%8%rs!0L z2_Xii2sw*ELW(w&Sx00Dm`Jx6wl}`VdM>+o5fH_8!lsE_@)A zLv1RQ>s|)A5^y3m+9TLYY!RTI){>Ila8I*_?3&Ss_Y-h_Nscl8HeK4}8Gel2r23JbOg zzMPL+Pz&Ta7N6&Iwn>WXO=+V065o894c5Rf$i^@> zUhc?;V$w4Q5y#8HILjJ=&5$>{Y`R_zEj0`6ugsPnvKFj69fHea@)E~7vxtk@N|ohM zG;;>05bOOdTi6^)yX(LuUCFjqGg7+>Gnb=nP~8>s1@Cf3b+^kGMQ!IzxJ~A)dGGS< z$4bnuV&BjsVTb1JFLaC>VT+)g_XobQQqSPNi7lvlwz-%q>Q(Dr%?PIw%M zqo5gK3(})+O5R((PT;i8Q&Xd*>C$28aBiu)KXc{9X_f~sf&3Fb1T>=MEc_I3sir|x zwXXyxoysLH_t-kZ{TT2>uL4M0zpbC^oEdgW$aphh7KwW;Mas5}|i<&Bv)d>-v1z~yj_p@cOiCYc#a24Rk&b=I2qYwNloS_bM+ ze4k_oexSYgNwSAd<{R5N9&Eoq^k8QWJ=j(TN$A0z9PXXO_<2Mm4vF$4U)lUxy0Y(} zwsWMc?W_>Bo#V{TL~CAKuUvq={(|weKyTZE4UpBj4}p$CueV^(N08*l&3*{MM__*l zf9`eZFVzJho%W`pQ=qqD!F21wRK=4S`(-7UX^?OvDLwKiZF~MmF(zzIZ)4x6{hKxX zjgF^f^pp_qpiZZMQOu|%;QS)}%gTd@4`KE}^d4bbsE!5xPV9!qg!?4{vEN2*~F zr=_?5YP)CIaAp#laF!juAL?&I=V9<30ljtpC}3;za@yI!c9Oy==es8l)^ zJB#hsJ4F4RqJvmOrs#Bgw0HtAhrh_=9Ue2OBYiMVo8dWml;%OAvWZKmkkOwsnTu{O4VXW>U2kaTiuJ$;8$}E zs(L3h)i+)XEnYLUG&E07W{DOVQcrKX-nHGDH_MRy-q!P(_)00RBYsoC{M8N-|5b!i z<1i-u&iDJL<_XYbEo+vX3u!Pj^H&@9b^+Zq@b<2m)86azXLH$#Ht#%Sl}b+hn9bms zkEQ<^JK(dOFbHkVOQ56_-oIt$JED35z$usQ3;W2!0jgk3UMJE3-hv*&bLpECpxrqc z!;$%n9Id;oc|Wt>iA{nIS94u8x3h1MO~wM}YVbKgz5z8%-t^)Wt;bpO_O`xBE-vc^ zQn=i)8!xV~(&F>ne8izAe22}FJ8&zad3>ieZ%=DQmhTV^)x*EP?P zv#e&iz9(^I7-D$FNr|TiVUl^vg>`2(BvxT&4KT$SS6ltYEH=rAYpmvMMxjt3%5fTG zRm5p&4-lQ9Q41_Mb&>Fg$)TdjllEw%Xz}0Lh>24>t9GwD#aZwFMGg80$QytY z-}8^n=oPn=w&>=$MOmaJD;#3GWfPd4F-wL3MG{tb&>xdYGbh=k4{f)e#RV(TTZO-| zZXlc^*`7p{WUmgq(Lgx(XJj@H>%UxGN!(B@66=S&ZtIhXJxve z(7r4aot+Ur+DZm#=_!)kdVm^&d#Jr5H!z9{dnenH_&jE0fSJuIJ-8i>!a(k!5PqY6 z@7;>{H-yL3=m(YlAYJ!rrn7H6+#xu##C0Ig0vwGa?N0u#^?)A&%w-prJWL=|Ii9#v zMWdSGRY>9$i9$IlnVLL3I;CYuLbx+gSzAq{@T~kKm_jPGSr@H`Aaaz#-FS-OEcO_@ z*u-KT3)=3NB*R&f6iD-|)!9;F1p6d#QIpU_U=;%(GccoCZ?3n;e4(QZ+cWCn-$+$>|MS=NGD56%h5QTOMn@oSY1Hz|2_ zrwJr1V=poF&c38q_tkRT@$5yJ;Fqg}W?!9>BHh#_fN4W8-cN#`hp$R<9BH#|HS2*> zO4f|SA*At50--MSqOGk}Y`)daPAaWA{qz9U%JI4IQbf)4c}AZs@I@Lr^6QK|S@_zi z+6Y$)?;7EvA9!_eLMC%!#<%+w>(9-5A4DQ_T%t&S5A32%Btrv|_4hi*vm3pPJD}#y zaCVDciUJ}UIn>?0T`mD5#DEFNHGLm)2-;9(`7P+ECz zoEfl53W*fg@u7w-iUIrvo=GCXY-cI5jh&ioX3|9GqG^_KQ}Wh~qP z3*unk0#3uxycf$?K@{X6mh~g&wcw0H8a!$loAl%)U&?MPM2*Pk#fsa>ZDG6Awi719 z6bA!ZdpIL>BcONPjTQ(o0y?VD3q`WGIHD`6+fL=Vmy$XhO9y!CKwDu@AHld2$_8Cp`sa!H~rlb&zNNDv=u zgcecTk9d-G;M5w)trhEdfav2a$&8Lw6$}qA06koCphq~YxgzYg?=dg zktrH`wH|R!@Hsn972z2#^}N@E;fJQpA8_IC?#4FvRjW?vv9xqL;KanQXZG`wca4qo zVvy}P0?!6$lY`wFNBKyY0`H{7XxGG&Qycpc;b&rvVB$?vgJN?uKc~< z@TIT5@nNN}R}&=k^$9*4>8cg3JlYkjT-DV-q4&1Y!k2^GGl~Dt3eMN_3~`xzz~sl$ zf@9EueP%pSV>3%&K_UrHkjZwzaWK%DQKl~SO&7|j97fSN+BQ*FhS)}(y8-)p7Zj!@ ztDa(wLmXl~5X2G#iExi^-|u^$0F4#dH&!x-ia)4p{pgASf1!VyG3CI`JjR>8{K(g# zO8gsU$u2m@OFB8cJFL@O{4Gqa3OVH^&wO_e7DLj6X(bLEDuy{)D2K_aOAL3Y!`J~) z5cAKXH_@AnJ!+0STm8#r(pVF~i2;+wX+oV4dUMoyo;u$n7D}-3LkS-dpJ&#-D#SPB z|Bt=@0F$EV-oVkS>Nq`lW^)`^7M8r^3=5J`vJymCF`=L$Cj3k*A|e7JAcBIdf{KEG z0Yyb!F`=Sj#=I&5DhOgi4BYp0*KGF;eEPfJ|GCd|pXXlj%)3)_`t9nf>Z()elv8QV z59*CkY7D{tgEqZ7sDX|5ik{`85Cx128a^3*w+<0Q^flYT>@iiulU z{*K7_;s_O;V7xRdoViB0@29R6h6}WOUqUP92^!oN2{a8QjT%NvdpqXQM!Be{s{`BQ z*Z8$4VcB>kn^u!IH!Y;2a5aFG+b`g)^u{WXe#x3p^ks)au@dCelR@8>V7N>XzQ$Tx z&5ttrLMSU+`#Gff`JRySUC7i6ZVM<&0#SP>uTVoe|2|+>k=l_^E?GD&W8>B40X5zv z8r0%yM((PxvO2818c<#f_=E^(zL;g*6g1}qLpKH0SwX%wP*(*m31{}<3-#C&dR;;O z)Sj6hB=!i=+$qW}#3qjN_6JX%)EI`Xg3g1UCCD|JVl+U3ZW*97)xx*(7>yn(@n%_O zW++R|hw!W4uVwL91G4Vg8;%&hSlo=R3aM*C{H*}F@=RX* zT{x`6X6hC!<1@AB-C9<>n6b97cuqt!(90-x+U^GgxpeUf)!9f!4`{TqRA1Ci2Q%D_ z{By);;==wdyGdR&x1C(-{#SCT`+x)J2KD}v!{UhrgQ1}3xh)Z{D=haq5C{fBlkC4P zvp>&gZ$`+;y;a~N_clJ-w~LZ4wB|}{rIpe;BB-4ZA*E-y0bXuZ)2ss3-XWxsD-qS4 z&vS3!+9>V*i1l|wh{%(X;Ik3)t)PYkeI(2u4ky#Znj0~%5`To$ze9XgsIK%NbS7%( z7}v})5$~d(teqlYYU(XSbG;WGJR5?DhU(XLY26hKtcnKKMNP|RHM^1PbGi7En_uyu z{Ry-2>5wG-j)%VG%6H`dm$o?_;O0RdwLkqj5_Dd~DgJ9>dZ&yY(dN+}e6t$+M6D~r zAKH6!-{b0RMYMqR-cOA5+a-Co&e)%5rg;ptKONXe%Nd*;viufm1|E@xHGVJ8qHLoB zI499*7=@Q6>;hiWtzoRxDa8r9hv#R#|!tTSRRbo?~a$0x-utjoZ^>^kU> zQ0Gf;I&)RV-cdvxaiaALwqKA!yTT~3y@T{VgU!hd!OF1go(I|tVb4R5)5Uh8(DAew zR$$;M?HyBgx^2m}vp-dj3(-dCK=p2jSI=+1V|ulStrP{-LR~4elqhRSAU4}+hX2YXJe+Wx6<`Oy%9eU zm6t8Z3<)!&{TQXzvnI};i`S{o$fU&zVGF%sErX7zX@}}*5O1!w<+;hDX&aBuml-z|E0cB;Jr_{l3GlZAExtF@nhd@tB`MbVj1OqO zRMk7_7QZw`E;?JNi@9jvbU63gK9=n`YdvV!tl2{DnN3#2hLIbKMIGOP(FUC#8cx9Y2;m-{IM@C&lpUpCg5yO{w>~Wsy znU2BR+CUv9N;SK~K#th!yU`Ui%qJrn3`JsL>Cb$D(}BPE!VtTMmyrQ7AUl`ELgQ)i8hb1@2Me@9D@Q3w_K_bmLQ9=>FRUzuZ`$ z7*Fa{ugtMfRs_r^7`OaugHH%-Geve(iy1M^Jr2`e`QMRt8;7W?%DJfqL|iK}4cpdJAIt-@hhlK!P4fnO)#rCcQ`);jlWV$`uf@EAB!Rs9ip z7!%n>^l`yI6KZF%%h2D}%)Er?-8m*UbJf?+7tc%%QPTyK4c|Ipssu-WM{LMQ>W68IL_w7c&LiU4}k2f}EhO_YY;erUQ zzc#c(ep(N+P@&^#ERm;XzzotmSe}j#?cP=|qBDy%+k5|PZm)5MH-z-4nNdvo}mkRId=1i1OsAjDO-0&IK8t9GVh9+NyXv z6o_wf_LKm-C&b@2L$iE=PXhXAZDv3v6f^0G@G4wx{7qAX&uRRktVi&g=!(ktxs1_S zjD|dKQw`ACdDvdUi26`9W@UnvpT?GiLzZTkg4SFIh3>Om0XB8VguS&Z0~Zvb ztm>7y__Qi>+5AW-q#6Eif+&jmci~XT3h}1{wsV@W-ZaiwvF+o-Z^Rw4A&xt3UCBjc zEF-s$u$BFGWwY&(P(sW1-yI^t`yxJcVKs~IC(6+3h+Z5e%2u>`kj4@nu2$d*$pOO! ze1=^D8nca}%Te@w)Fb>Fwv}gRYkA>ZUkl?YmEW$aLy!$Q8L(xW;QF%Ubp9fHD!ZXN zm4dR-;L^zxv}~N4c*`oXocKxC-Svbl)wy-&c^N z7N8za%=OhS6hd3c&S$I+dZ?9r#1Gdwi@oW zTXpaZr&R~-)d8XvQnt0@8RKP6XBy^+GG&qzxdDh=L(p9V)6kBV6|tjKnvBv|+Tu}P z?LZ+ErLz$wyeR!-7k;|ab&uV`TZ3f>XUj!)eYIFigbTwNk+{|%y99Jav68xYRon6E zq@JbNamo>=(Gmz6QbLEG!;nHhJe$`SF)*$Xsd2Jv8s#(PIhv#0q3q`JkJ7i4erz>= zkB?Et*1wf23;EkBn}gT2pgz6FDz&FVkI*T@$_Y8W$xRVCQqn@2T+)TH0q;`QK%Zez!Vv}&px3S;mv$EacvH_B3f9j4#rmo1G*VfR&ebOu6MQia7!oG zK`Xha=E1hUce!|v>t-NEE0qmcDP|e@*EO@qtCBCr%2a0<#&t$^f&MjFPRo7DELDHk z-$`Wd^!q>Zn_uv{Nw>}R2nLMqN&FYCq6Om}w1!TXJ1*7<{vzjov4GPcnY|ob<@FqY z$;w%JT-(mkFqcsa>KknNeJ$i9-G|9Zx|-zTcb~*1{0p9qbnbC0*A{XUCFM;%MjLBD zVn|pqCOCGU!Vc+n*TD=K8ab6+q-d)Z^B!GUsq1ZvL*zCjsQPJ8-|?Cx%tS!w7n9%R zl7+fXR&btmI~O^bMndz6OeIg~v`|}b2Wb`!S!!RA zd4kg0FJi;8lj-xaCW6$qEaT#0-b(GN^x_G%6+csCYuWZZlX6r+UxL;M_ON|^E6STR z!e&5X=+@8}UQoj`*%nq)+rZk#Vc{p!;1A9gm@#3V;-}rKmVS$-&C)C}MNAN}(~vb| z)yu@GWOWk#AI|EbL_50|WEN9BznYhzSaxJ{d?As!O*LLoLsn3;v^cG$ZNlx^Jfsw> zmQqODK@D1qLw59J$Jdv~S#)4X8?b%O*=pELg@LHw3i$0b4*AVMSkU%tUpPRn&z(wS zynD}@8YxXKZeuE1N3)F? z!@o$djnY~}?9}2S(=@uNrecz_UZhp%NmF^s)c-P2lH@uU?dyP{HnX%thJS|{dCL@8 zW~N3Sy&{3I=2P%zlYzSWT9 z70K_SPSdW`BH9$~GetWr^xuU3xsr1#zfSSZQjk(+uAbip^`RcVL_bL@&J)HY<(zPl z5Ct8;HXZfXAko}LsxTGuysqW?edvkggT0{m^yEGLxtdydZt`0&q(_5|LT9z9TcK)F zvAdD0w;Jdgw4t}KGhR+zEHh|$(2o|ggtkV(m^P3uCCYF*e#26H9W6x^`V&alY)erK zgY;Lvm4M}CA<^+o)eViral;OY(# zXJtagIQtc9W`8!dKYc?I$mE|n+wPB{k5-D_GE5UK54A!Zym7U;-xo~KDrPF1N3tt@J%kMuDX`` z0IPW!>eoU(G%bghWI|b3l!3uw`=Mdkn4aXrtyUEvXK@(5}=D8e7!^1`WBJw{ZHS8yFVz z^8*)LGa@|lI+Yy^6snhn_`ANq2R`z#SVC?H)ZjHa7n-}&@b_xa-nXTwnRr*ViOOU# zMNyCy%3@wDCbi8K+0e+)1By>=LtaRA-`BjZD*8#IstC2vV!Tu^fz|d-ZDfiIv_)K> zt=enR0{j{^tRO06s2vn<(&3zluVNe!PJ1y+VRJ%xXu0d5?kf@&k3?gjNyFM&auJaXt8;T)aq+oi0e0r`!-eLnfe5h4G`-{5PH8_wmv z5|{_!8@aiV_x73Ai{#(evfBdRV?1EH>NMwx;Cyk?qdd!}SOa~&A=cQ-ZIi%1Uuci= z$YVV6C`V(F|0r+q7}p==kK&8*D7Wk{I*MM#n1Zoy67$`P-KMl>Uxj+;1L~_!hIBOq zLsJPGn?wF5LgD#}`Ji7zcQN*o-+a$+z8W%Tg|%A(+RJ|0@|!I>jVuujbjt{tTI<|- z{1nxEDdgK4vc3r_yMw+5f^};rKMR<<0>Q5X5w)Re@A?wj9l;>dRedF-ycY6lmflb? z72oqA-{O#_YvptjklCiNt7t>YK{eb=l!O~ts@c;wP@Ld@KY;5a%Yu>RL4Id2|Gr>M z6ucYMKL`p@jQY70El;OSLF4hD^>t9+9n}Bg*;OLrC@+{H`s*g|An05y#jH@x@E~$^ zKsVkR(qi#}1tN44FPiJP4W>Ist`ZkVE(xo;p_QpVHQv$}DMEA$HN8+3@nD%~6wI(- zd8?MH(b4BY5pNtk8Vnr_v`-eu*-?5C|KjS0LcF1f5-|=hWPfG8W(gpdn%sm zxbjPwG2FU@(-|bD(pI-!U2-Id_LLBGN{?dT4OPi=jftA=BwrS4nSsI=vcln5VN}E# zLc-Bl#1|G3zpBL}=-BX#{CEpX_dQCdTU+=;&&tls$SKHvlQ?_j73GS&MvzGEEVS$> zilRSCV}G_cL>i2qMOLL zS#g&9?&57kF6_vJ9$Z1b1W>2`#I0X>7>@>vLksIj;S#*2oy5iB3cQ+rdS`36O6y~< zBi|1Z(=x7xYwX$13xF5~QN#AJ z3w;^;JQDjc6#F@pBlxQ!t0_ulvZ!ji0?O9`Q_ZLHnTYQQkQ;ff_bXIL;QgQ2Wo9}&WZPW|)Y6eIqhCa z@QaOQS;g!&X+4x1vQmqFHZ6)g4j2#BcQWEbpn$ z*fpY3^yc-bHy=}{pe^{zo-?h-VcjVfZTTYqvWmu=;r;4q78zMEYfg3+4Gyz=6<;{h zIAnW-cJnUZaMh0SQNEjp*x%8h%0G+dzs$9lxVoKZ-xE>qj;O06B4|c5o~@JH#s+Gs z$g-@s$mk#TasS##h}H$ZEf{-FsKvA_kp2#-`PBR6+2jfr^yCT19u?Z7-(nBeQ7RT& z{t^1fAuv@I^60HRV19O8R&9qx@weKSw6(uF`b^^8$6F%jMicfXEpKI0r!!9h*`Q{Sii)ypJSS)T2Weq zcB7HA+-Or@cUQ8!V2}BaS5FrKXNuwkWsus#i9|6>yVANvkd>qCl6uVq=fXMG*{*o5eI`X<57+ndD4kA$3LE`Cq=4TF|4v&-^+ORqDvN;1pD^NE486E63SZk% z7$U9|^_=;i4oU$YpB!AahRr`tr5;!ZGj8O`TJ}%dD`M*Vjq*# zRvd+y(gL?=!QRZEH61X!0(1nQV(5y_5Ue_*7Kv7NvCptSqxNU(I)_O`ASgu}(B^#o zg5a1~jmZ0kH)n@4kWD=NuAzKj2t7{Dq5Vco=;kdkeQ_-KjS{;hns+3_EHsTeA2RpZ zi*yRrd0Z)U4u~fw-n8kp4bmz|eiY3-qq$6>dCC1!!=97nWVT@2b7CTrRV0kefZ4>z z6=<_9&CDy7KOWS^ZSBVfU|75?N}$sf5aeJd32AXpQypRtCQ+|Q@2;q~t4 zp*6Hu_c6|@a${=PUNxKzvxizWOT@nj=L&0gxSm>sDmDINxZcm<(2rs3P`Eql+K4b4 z`Hi}5N6#v>Qn{6A4Fe&poGsd`VeKkzZ$AnvFDi8OZ3&;I)K9-z`RsV(5J*f|> z6`XyZn=SkwW$9mKH3(@+PF7SHjr0tEcHOuJZ0J1Nf0d`$qZ;e&*)yH5;Bphw(&Q?+ zGuceuua?KY;K5q1e#T>bjsgoj7|S#o=zKzKB6{0rs2yWX6diTkr$YTqC?@|v=wAzc z7ji0)rG78``$P*N0)9UpKM3nnRk;~b{}LI03w#Fll9z{X$tT-h(Ue|AZmMFx$UG#R zD*`C$&9a@9*9y&2=88FrXh*edrr4#>*i}qHrvs7m>nb^H*L2&9g5Nyd$gosjfX+_0 zy7)4!6QC1zw!(C?eT?Dh*bLhJa!7=JgyAN*3Wgxvt21Nm)EM2RGgUGn-pDzqV`59^ z!YS-7^jKSke6)tyq`hsOMQdl)oR-{}P|4{T>=m#NTH!qcy@IS7b~iu3gNJy)5{6IZ z@7PDO?BcrLps9o$PTOx;jv7>GF2%Cl)JT`hn;i%ClZLbc@u-w6`AB1%QLDFVz?X^G zavA_xA&@7#P|KKfxT|SKMMl^(gf^EK3YAWj(Pnd`(2ZQ1#UnRxeHOJ-u$q^mLM&TG zW3tw<8Mc;dRxv{c=CoYRLK9^V}!$7V-hv#c%Ugb>2sGvaNfI z`I?xhv?9Nc$$T7ud^Ged%|K0|SrMNO3rh<$^J{@_el27Mwb1E7Eix^v#RAciNG{L8 zKMVi-S}SKhda1MaDb^!^)GDx(zpMSJ;4|E-4|@uE$7!M{Fjs^`NY{9P24n^7Daw+C zs9*Vd`ZGLRjnOgO!uQgB!5Nwb(7f zx=&FoQklzFygWbuS(sUnt&Vow1( z=YAxfNS=5SWIv18b;6h-jAumnS;6hkwVW;Gu_fGqfsw_R82rl6?K)pfc$@8fJfw&8 z9P(SVnZi8Wyl&IrqXB9^M~gLzSYz=T-3$KWQE?>VZy z06UY9RRao5osfH)lkD|egTzolPDuv|+JMnFh&rT=Xd;@6HlhdK-x$xp8yQqA6h5a; ztT?d;wRS&?^VuB4DH|219B1-S-23*Ly}-&x+h|RwS^WhkoD{`?>Z5&woaQo)r!7 z_mBq93jZ@A`mBiT=jsovqG`8hO#wE-WA4GsN9wd<9bvLuouI>;FBA_b6?Y( z`-F9`$mz~kDOu~4z%L?nSOoQ`>QjRvaHFElRbsm6sYdYr?-QXtLT{w|^og=!RwI0WQxD8Ikzek+1{W_Eq1%Oi6M5C7mp8)K zs-lFkWgHzzbV9`m+Cb`8UZcz*rzI85lKc8g9CO*@6+!FZ@~kR~Pz(N-y(w6ma{U8h~IPCH?1H-Hoe zTd|*cwurvQt)tks~&PN7k0k#-%){l1`x-^Sxhc)Y1* z6*r8R7U#4|8f7=y&Efm#x+x+X4H*nGG((rdni40_n6&+vYEa8F^YGB*PJyGMXac)6 zs7AR6c8bNL@r=fCElbNR%(60-Ec98kv-0vpcAa*;q;_$lLA)g1ut90OVK5qtw~|f) zDxIPE&@Ctpm*s>qg1Mp6ppMKO$mWQgyLrZHp4&;Y60P-Cp%w#^9s}laDllEuUdlkS zUTFLwM`Z9^wNxRmu+E~5si)ct6fRrD*@HCSu4XB@s!z#xmnBT0ftP%BsIx4gip$c` zQx=Z>$yui0N_$PkK5_0Qp*$|KH;K^WB6pLp9v2b&Z)KD4KQ20N658Wp9Gi`5IYSTA zXmnW7HA@7o;eJ{NuuW5L)V21CrSuR9t)8|-4gIKOWN6j8_Pn4epsF4039bP?bm zX#Tgg+)OP?g(;|6+ItFVWNHb`&_pyE?p8)k?v{y4w z-?edkwPnz<5ZmZ%YcJB=C+cky#^Zw9Nl=e16!!KvHSmaLJgV_s!v7_8pxnK06;$<> z*e8q2H8#CypCzq-^(*z9_?>IdCR}BIj<7$6OekVMh}aw4e3NHCA(YKRe}ijpa{h!+ z@%IxVuvs+!o=#3%ClKbd!=jr-&J#l0EPQJP!lU1Fv5&X5f91(fKR)R?Yn_i%1F=S(^45`Si9rj;KIN41z% zw_J9)yGzs z$+QaCp9s%mukqMjT)UHtuF*Au{6j}DbrH2dfj)yQMhO!llW$<~d9c|=2Z zXj&foRjB=pfpoH(efDt{dDA9)klG3+VB1dPWojc{W;F_R33cUNjIMgp1!kiFzHzot z;p=pDg^oPbg?hUl%tCK71l#skZu~?i0q(PXRoV|??g`F{l)r zts3@uU4ulFkCV0DbgJZv*|eew+C)D(YdI)lufc9I+Gsuf*JNFtb4?REVK2!!(;ju{ zs1Cq;TttkE?7i|D%=0WYM;UC_5tYp**zudlK2_s-3G%98vhM9h^Q?txF-0e?4smMi z!Kkqd*t9FyK{YPA>jrtwau;j`=z^X~K3#CO9B{dOgA?m^NP#ohEG^rDU9ew7e-It* z%j@EMy&d0%YQE^mZEtyK>^QBkj`B0ua?QP+ld`WQhlxUOp&vdiyI!DvxL!_ut6oOK zZc6)lq56&3IxTxgB=Bk^{8}XE)rj?4B;(0=S)+ItOGWZa-MUM+4u97cp z^f|VT-i=LbNn1HYq+3SUQFs)TmY4NBJwoe3jtZ+v!Dpl}<1Qs%@A`xq-K-8p+`A@C z+Is}GoO8KaPn<3MhCNXd5gP@$u(w%7hB8WzY74pCJ~ShF9#rH2M|mDCN_h*U(rui5 zuIHgplLwpJc}nR5rNtXU+kyV@NMvQiU!1(-oq}A_4p2`MXNi2;(3GdH71YxL5vp1c z9Zq@B9msg^%-FOk=yV}fmKfRMG4)=ldjCopkzDA@mUT1^uu@^kGQ-^@GP_b>$u=o+A{}Ex- zTaxr+o3taFcD6mdc)E#wsml#ZY%{J{DbrX(h-_k%!8iw6l6l)UIW1(nk z_Awq!yHmB6tIC~fq*JJ~vRu`#Q)6V6YaZhsR=JQ?`74U?lP><$!++@UKlP$pVI!8# z)%Bb8(BE3!deR!(75)*f_I4JOek5oB$SFG^I!WD((dfTzWjCTiPHiY1%@7Vp;$b&_ zPVstzf8kV=O;D%=GAtqLqnAF09WwIhpdO)qp=h;=xLXa}gKW)RrPhC%M{BiqZXFsS zw}5z!2CLoByhIG!tLR&tMqQ`{4=4#0l-d~A_(q{Z`Ce$o^@v%dHV}HeQSybHOl9dr zRA7zhWxQ6_x_cD2)@|ozhresAi-IgM>?~1bmdM^#%Vsh1nTf7QtSoHu9-@R-;KAFm z$INV1M3fsfYc}j|Ez-#klT`R0)s)W4Y|Ys3WRaShMahoSC&C}rA_ZRU=(if7oqD^v23MuLTP@TJ#c3kfXh-??EEfeR zY&Uc2TqQHouf$XZnQ7RWsmjchT_%4sWTqdPi6;|gyhlb!+<7uPfxFwin`xJ^pG~Ut z%DwBYhdYa#n(}dE7n;n4XseM`_yJdKF*(4vtCp+Q-596UWNsf)h&ZYetL~#>ql4(j z_mQ${ILoOS`rN_;D2gou6~1u02=5UnAH@z@`GP-Z1^(o|m(8#!jq#fe8pYje>2b1W zHPaL^pUJg=2nVRQGl(})8)`I!3k%K1+u1|7qnts>=vH+@lm;cEGnMDixPB+5E)zW0 zcuZtHDzwMMLKx zVfHmIjOoVb!un8X3&OEm!lFnMW>Z)v_3fho?-JTF>g_ER)(eQT@v_i9qVRkr;S<48 z%INT5Q#1PsC3iSbQMm%^mL{qcwOsgka5fFO8_}19+Kcub1{d4kUk|Thh8dL)A8fYtUO|G3=8A46;g5{TY}eGLv;Ko zgypXJlubJj{7SjZ>-oH{87RVK7ktAT?B!kx-#lA&hNlq zfvmC(Jg|}GssjOgP#1*;)r>Es#mET3}uBK>KQ=e9?nzzwjyoFq|e0~+ZU`;4hig}%qBSKc7Zs%^&D}d4(mZ|<39Y@M4cdBxA;XU#KP|VW!oFZi$$3h z(0d7VTg}#nX0|mfOZ6E6)9*t>f}zr&LJf_NCCGfmlC7Lw|9o&mW)xZpGgj zSNKCE+!PH(Q_;*g$;{#TJV(png*=FVS2&9V)otoZm5ieA#K@K6(rWR(!tPRN!FQJ6 zfAPkMSqa21vStXA{NbQSN5_1%5bts%p)O*<4#`(?uiakt6`2A}{4Opgk;PP~CX_E# zashQIe_xR=%2s+&@^H@sFozXd`D&?}>LZ_tdJC2OzeTj5l_PSBb3Ict79FZQSQKix z^p>-V4v_!OkMh2_&mv(T?>-;KN=%RX<_Z6N)VKbZc>HDFC2GY^ zWE)|2_{bJ+8!A+a@*4Lu%+_XDiDNcQ;W!b$cBms*2WXD_WPTH1oIee=V$CLND#>q)HCoq0tcLom{z1J-G3}nBv+3Jc_nC<_&asmi32oY+#nqxGtJXr~^>vo1TyKga zLG!1e_%ldNyDy;ADXjBCnjTa9hP?*D8QHr~*gM)QX-bF2^)8_#U1d}pP1D5}Cj<*_ z!Gi^N3y|QtEDpilT^E<2!Ciy9J0Up1-90#q+aljS@AqfU**!fyJzZ7z-s)*l)kgkB zT~*8u^j>jE*4&}n`=r@i0O&C7HX`~m=MAses5VykDoib>*;OkLgY|_!{bX08T$Q%G z>|eQuQ*pRU+DT!bL9h{jZ1fTxYX^b*VzKekFWp8V0TxE)?KbcGwk(n1V9Dpdc-a_2 zM@)A)T@2SA)s#1pFQPo`4t^noyS6(qr3n?`f16oWRsJC4w_G;mrF*>!>J-a{ti+oi z9YJcpMo3o6k5$Ex+)i`iNy8^a8+iyrsf4;oAB&x}zlyn!jFHLssf=TC-{^9B8_+h; z@yJTNek@5oSX?#O7?%2Hb>&&#Z#K-Jx{;&rJbI*!$EDmt&nuN_dYnRsc@nf=8tYIrA|qdQ|H=jqm6 zxeH5((O|#Q?r$Te{N%@yk|*(5${JmE|I~E{8Kow(qSnoZGGgnAbQh$pJ?pVr1E^iDw<_rl3!JbI;`8_uo?r3`#DD<&rYmHj%|7 zErQI-S{Qx7GcpgS=6{_RKlIOgq370cXO6{ylWRf%3JYJ?_oXt7@)X4YK z&{o-_`N{^&>rZhU$Xm#0DQ#)dLxH}+l|zUVG@5fF+yqF!1q>)=RqaxL^k!kPoXH1D zj}+y8@4#z@c1z#5qkQpj?Zb)kPI3j`(#U>Kv-`3bZz$c6#pT(&#lAYktvHWGX%aKf zzd}W+eZt+AZlYUfED-Nn7;n~j#4rvH!pmbJ=KkWSrhUU zxs{9Vg94TPjT3q2%oBd}>r&MzsyKkoxqf#uaU8^aPN>n=e;PwDcSX3&3V9sm=LsLW z{FzN6;-dneHE_b@S+s!*GyYOI`L^$o_b&T-;E{SZJ(s08cw| z%V7#4T=Z&XF$(W@Tp)BWCYB!RFM{V0bosO?fipXizKGru)-vmkL;q**Iq>E zqqdl%ix}h)5ob5{pn_&f5$H_o06?<-;#YsO0jO0dcs7@A9XO!zyO zaFkH>sga`v_04}NQ0(Hjt*_sn9Dl`^yu)%n7T@Y1(@7QSS)t@!=Y4*8_Z_n_{Oj0V z*fFZrA*sw*qQ$;q=gBQhD~Y>?ZC}yYei2=INpE_eMuRrYdfvZDMD`Sc*jZNOqrxUh zj71r4?g>7;V7R*FOdOnyj_*ycjb2${xL%`>vo8ZXOEras9s=LX6dSMlI=wc1gB)Al z;2X~MGin5NQ_OuD8W5o$Z~MDHvtv_+G-qG?pwLCSu~NGXx4l01S%>qZ2FRx>$h$P= z@O^9{(=U-yoe<%)L*t$^GGJuN;NMcQ_aDcUsK?j1{)RUds+s#$GB$5sSOiz zA6Qm3P6+Vh-#t;azb`my_~aJIaVn+~8kY!LLfc;Tqf^*2K;|^8o9b8ck)(PYt@rw- zI*1@{T+43}&8>OZzT!1MYB|HZQ0Ba&8z|lMt9q{gyP|$kWOn&eJ~MXt6TGIa*8HMo zos#;ZwY87peP+h5GUG9|K4aBlYgvM;FXR7Qn!0As?x@?Y&aNe53A)Z5lJ9wW3YR#^ z9uDe%n!l?JlDBZa_V!2fNze4k*d%&~mE;{ojQa37xibwn+Ugd86PMGX;$I9idG_2u z6lzyl9LaBo%c$G%{rMan3B~2mnp7GOvc>CtCm$Yt2|Qj>E#eK7PjTfDWF_!E?^GEp zRJ`|qha%o^(MvKq0HtQ^)5fLPyen&!UbbC9^4Q3NCr_0Cp3(z?_&A_?i?SRiat$`K z2a1aoCynCmntbkYm$N*mx*S#d#F$wofoxEBe4p{sZA6Toa?7mJD9`**%O>L$V9{`K z^AB{ZR?Juc;AXX)JHThxC!pD5nLU<9ul(hoPhgJL6{(tc09~1WAZTxP%~Jyxm;Ov< zGFK5&BrV&wTqcpc5Kk{q&?+Dw{$?i534M5)F&7W80-9?(+t#jZ3|zd^QpW8Ps7h|O zykJuHQ*e5opHs)$x7MG{*s?lIs*xKzAf>j8wG|MUlHa)=Sq>WbPRDMJoSHrE6Cx*n zNzABUQ=2;fp^_3L?D>d56W6Jb;SCzw)t`b$AXBbXrl4-jiMoDvj5~&%)YIKQiHR3S{L}LiOp9pqrd2q(1(x$5`*vJ_NMBAxo{$-1}26C;BzuvfVm2*Jj9| zf<1Q!Y#PqC=~dF53IR@m+dM-MVAEg8_q~<+Fzy6sVqTgPs$PooiJPIYm;TZ>1=*=vD11xH)4KF73k07IJQ=pRC5X z*V_Gi!qvZ4A0xa^*jAzocePJSkTvf@b#oNwWURVSZkmmZuxr_dwWPC1g2LBr;nVaWS-grAblzGTCr_5vN zk{RE<3tbU=DJK*mnfMe@#Pl*;lUbJ3?X{ziAw*O&-x2<8fp`AA@Nro$-JXzA{3wOB zT~#iuc#_&Vq^~M4ZdG)SOj%Vupi1a7FX?@36J~OB3b1WnEn#=zu%w9tohvFR6szFX zxyfu@ApMuY2j)?8P2j2BpAVLQIr|mEe%WwgNq^uYl?$lIoe`U1TGH+;E%a&po9dLx z{!ofGYu|ODb#$zH);gr`KF61qKTjVc7BxFSmeE(&MPbS;G4DPY!4_yNMjg|b=rJ6D znh0fK`9p-s{ccaP@f>xelmhjUe34xp0%R-7BF_+i({ddGwoPeCJiSj+u{)5G1yie&v_Kexs@TYNq?a!un#o`FX?i5McKRwL9ak zva^At6BhwpO8C!ZC7Wxpc*u7eY!daHPd-W>YVdpsAAKba0~vG2RYiv1q|qC8N_NEG zIgH(zhkU7?eXtOO6x&4}$VvI~VqQ|6ypdSAR0${Zsy^McT85z1oA9Ttv9v50Btc$G{x|kltpni`T&RuL&omN_)((xh9f?=1ZE$~BEYY2 z{-V-`{3w`5_M1bU-=n_8Y_GtvG8|szCs=4q(GbsI-9DZCpcyT?R;is=7ayA+u|vY_ zwfx=L`T5X$B4ZzR%J!tIXt1penaIpNZ4wG(;NoDsIbfiQvx6vArD5M4MHw=8)G2)k z;-s_z4yIVB+%Gvg^Tb!$L6>6JGPB3cLnH-sG%yAsvGYcO3}OiBKfEjAN=dfi;E z8A8?(8Ly1{JMWni!R)H^ft*g{6UdJHBp9kAR{K4 zSs%%FA+ZuUSL_qou)YoYDD;P+K645!P-lr|@$QBwDz2HPbe#a-A@oLBDrjLN#4YJT z{EJPPpj`hau?^=pH@!(rnUkDnRSBTK%_S!hUDQkI@+c$=yQB-eS^?)O$QL*oB0^7R zB12wA+2({wzIMxvR0Eyho_MFjj~_#)&^5>AZ!zWm3yHY)*NV!w($KjQo>F-Q#BMFm zL7!VR?EUYZU&_l?W)t#x76v; zE@E1o5A#-UA{GpXn5E%76rQx^L*pL$DFiJDl_|<#>8(w-megLv*<_k1d+7wuljiyr z&*EsIweW{gHA+Ic>Hwj{%!+Pz0rQZ%@M&Y?JCa8mCbgTEZ-{7&6t`!)1Ji#RG&V=z zkqITmEYSVpMM5|3KHpW~N*YGqVVdpiGpgKL`qu+VW#`@7EJv@;bQH6;lPVZmMGBUh z2NYDjyHw242VN^%4J^5=PQ;aY#qhbX6zhETIB!xv@gz|P@uXa372DP&m5gAB8~O#p zn+&iAy(GimNr?M38Tzfbq^O!$(a6sKakJ5HS;mmhp_L`Qqx#?la>!3%-UFa!TR_)> z5Cr9AsR6ZN3+hki&w5`sf9NK+e8JT@E2Z#Bkfp7=Q~WX5QhKTwfR}%(<{hQ!{~{Uy zC!^kv>B?rCj*E^WS?5?PplwM>oG^)XbILj!fqI!b3Hpv^95TEer~H7jziWmXZ7I~i zXlS}!;|uC~$kDe97>i=K@X_nPicV|@^H`0Ink1ZbRHd$$CU&S!iL8_R!H28pi7}nU zmw$_|IOi@0ehQTdJ`@Z{DBQP=V~{F3L*ds@@LKG_^Wl8oqTjT@x;s`#7F~grO|!Pj z*7pKv5SY%}U^Y^H#G2vk8J~ONj+>e##w-7J-gW#tY|xf;oa7=GEV@c46x>xggpF|v zht*dg@tBbHQguy=^MG-SaFaTG_UpwV_rgzpzI6RLKv@cU32F^L;D|*sshPRb@cG%; z@M+;oOTgzg=pqJ>b~DK`!JqNi$>oGQ3)_fL&;4UBYkT*cbaN>bmxe1}id9bWfbasu zY=_%rzpC#&sVACMbL^uHHe;bv_k3z^_Wf_xMU$U)7n8qLI6JXu2t!gW&OY(Ez1q82 zNlETLeTI6KkKW{^4D~bzXm2ok>uMjye(wJJ==3e!-~&t5b!^+{9i^a7m&}*x#rY8- zdg38wW~o_<;YI4^d9tb;`JJ`6 zI{pd?;89{AhsaDSj`4K-m0rSbUR zha*bboxqVm2H{l&Ghg><;o0#nk<+?G^HXImr;6c*^4fy3?#yI+LyfbRA$3OdL}V+8 ze_2giRn5}eVow`;KmnwVyr|TgqB`&3vMhx{4Qu}1%6|_}Fa`2Y6dda3DpCockpN8` zVr-1q(SA>r3$O3$AFv>EP+?FkNhgenTfnMjarML!kZeoOq$ly}iGwYwRClTs`zuLD z7?E?l*M}rT#2Xz2XnmzRz_|zl7{A$uuJ0Dcv~$WiiY?mXKW#Smc}1Rh*!g=3{v~aAM=RQmMSta*}b1acu0l{A+Z_D zOYTL9SHgXUS5lu`UjgkK9_9KZ(kmQ&3LaOz0Fnl zfR>i7trQz2mQFEQH%J+!s)hThQL}IZlxQht z?ifv6kUs^T-F@pouY7&(^i(OKCD*!q5D}I-V1cb}WlIwDVDwnU==ZKDVZN(QQOsJX z9rU63PI)yZMnT|kNzpo+-s5TZlj%{h$8shvI} zc7=?i<j!()_qeo zZ00=NW7!K;qe$OU^v9@Xjhy|_@vMn>UVHVRyJ9Cjl3MmNZh2e?+8b0SoH*(sm`#MH zF*oG0AVf!|I4t z{90CEqgNCs<*|fdgaRi$vP&|2WAC4|JcYSjRRmt?MmEXp#o4=`fXJft;0N_JdG7lu zGy@jP*sm>dT#|Ov`eXUcdQ8~n|JH}Apsgt;Y`de#J3#yDf4B+bOmohwZLT}ys=GsJ04BUn=SvaC|1v$|beoadU%Cxi&U$UI-($KzJ{QTo#t5du>Q7foI=-?^(S*}Cx ze|AbxiGm)u&8(1QH!8^?t^`PsH+&$?8Oj;u$kz7uHAO8UB+hWi%;-9stVDyQVXWr& zxg$aa=2sYg2k8e$ZM>|EG(=|E+I;aYA|CCte$x37^n7c7n_GmZrrdx03EWnCV|7Zg zBVQX9=|y4tSAwMUn%K}2{ELGvHmXv-adQMSE&t*qp~lhy8-pcmg4^2Zdez9tkfV~1 zn{_%~H>?<$h{>z5a_X}NiDFZg>lJEk+;_7T*_D^y1D}-KPa$`5Q8IdkBHVjq*j^mb z6@T#MvDMy&h?6H0mAq<-k<er4GVBnJ*O;11ZZ*OT^Z?C4?u8?bFL$jVAIDD9tPbwIo0p0hz2_&bj7j zmAD%V_2K9sLpudDO^M{%E}gp2Jb zv@@Ntx7a~B%U20^n3ZPv$Oy7ZeMQSKYmQZ=P?)y*9)^jb zH$dMLF6&4%HwGcQ{{ND;OV!fPyh6?AVf z#{oSLt+^V#EkAef9^dQLt%rafRw1@u4cL;*`Z8)*u5a>ivyGWIuk*~9_Hti5N04kF z-)K7qrz9o%#ZrFvaMs_G_!=)9o-{mAdYk^jeH@GU%L5?Otdiw+BGp=Sd40FYclAzm z@ekbCa-lXev21779&QOPU{48kEHEsm;w-Z9Kkr3;WEM zNZV^Z#~A5^d^U=akyeN{w+Q|01zbnYN*kKU_{}OgM z96m7Zn;m}Pj^&Bw&K}a;noPmdl&{mVsS+%e!x$6&$T%!rkxnK-cQ&?CbwECk-C4Mi zPs}l+eO4r1c}_ohp6A-w&Zr-3t)VW6?4vE>Ra1}yWH*+t^|(VDe=@({ev!T3MWjWf zVUR(|76yq#;w&hmORQkVU|M}%BN+@&Js4UY*cZ&By9=v#Ka4kDJ=cCSdEB)l&Xgtp z)2xv`4X29igD%E&_p$X1U#dMD7-|%b=o*;5J3!h+EMcF>O_H`@R>$LHVMX`yYnu;x zBhIvU5|V|DzDi!oVP!d4+r<4C2XGZqXbBkb$iOctoB<0y;>|P(>W_=sWeFpeeYSTm z9sl(Q!DFYYTn+lc)nEDZ$G3E*H*Sd7`oE^!Kd&V=Ry`*)`?*i-o9ZSUW>M=vF1LZ zf5`)sEio)ozn3omI`;9&Vuo6$d@A-Wj&;r|v%qhRQCBuxew&!PJ)j5mEM4}2@s24+ zuMR(bw_HC_qr>&5jd&E?)4!rcOAPGW6HSV{8hQ&GCH!E*i*Ancft2rGzF{O&e>zxP?}r9 z2VbSeGcEZh95NRJAw}ixz>H$LfT4NO$J(UNK7L7RHOP#=ipI3<;EoFFYJ#Hh!cXEA z6T&>#f+e6dnrO=@DE=P4SDsQejAPs9Odo`>Sz%OY`q`JF%~Fa6oIiwXawK%F01A~X=G5vI5ndMt)glJB z90mNjH%Z{!%|-vP=7Ekhz0_x>#K`TBUqAm6w&IBV=*+XO@D(;Gz$$JQ@5InwiwR}O zx|k>@0IE;OR!_*-r6E0Ug{3B|se{j5FM*P0&v$8BzLeX(?!7=DE!`TxRL|t0HUjw69}4R|0WuQJ4q>|1yEFHL#Mrb10z$`~<>2`Q>*wZ)#NwH=l%f@!o!qDnd(E z!u6b1<4bLIDQvVI5MHzTM5jplCM5Oqh0+5TBNoi+uNezW&lFlxm1c>&NtYVdjAyg7 zf+O{sgDc7;xDOWwDa`TKm#77o>d&>F=3E(w5{hjjeKh^t<6fle#6lJHqWTDl6Q5sy zNd@YZDeKf<(tSCJK;{vOSr0%UC+3`x0m}oMEnR0m(3w z!j^f$UIba-OIk@hLr;SaHMCBpC&%m;^(SbGkf3uW#XdAM{ok6JPmQh|;f(oz<-L^s z1fp3b)i1*)-Zlwh{RY0Jp5iOJ@D9b25l@=NKG|MRajLipd0{C>Y=?!L{>-;YG10V{ z@Un96`V?S7igf_a{oL3NQk@YX!^g9-K{ve8?pU5|U*s@*)DVfQ7+o7gYH=3MzXp$nJOCNpD~45*s9 z?KZOV23xH{zB)^L@Q2QteT}@(Pf?dVix4|cYL=uI-K`wPe=}HWZ11Db{i-ZV>c*QW ztz0LR7gkZcvi@^yN@&D{rh!q1G3v7w9ur4lt*AQJV)UVuq%i$wN`g^u{GC&VP)~G) z-v`4yzVVyAb}fV4^GX5cQH+9y=^WnE+V6WnELQvg^By??3<08*hW|*C+;%8_Y7k)*0tzD$#ap&c|jR5wir47$Tj#TK* z4trtn$YHzG&r3}7g&;W7=u?<|=P2YC$QYmruk$W9EK|-PPa`oAmWfLXy(;+^Pckl# zYSB)e=%Dq~D90K>c{Z~6-sdVgoeZoBn|=p8{`+xa=kAHIj#x`P(SPKOfR-VOVj`?L zZAFJz!G;D?AR!v#-*%9faNCp_^O07>cU&jlULN%fhTH2i5&Z&obtrvP<}^)o$i-}Z z+IfM$^P-+#G2+?Fk5#dy#XHApk+`yhHj2g(zMqz7pUUczwiV_~tVIS-1X3{@*b_$a zzInBh0B!d%I>T3wCrsAjhFW{h+botR^_3Om+Sj_Yt7%{>7<1^^EROd_gtGp9DUtmw zh?i#hXO8z%8%IMApP&iZKHIl_b@J?A*k?=%B6MZT$=tAyVlA59lE^roxa#aQ3=YO# z4{DFt(}_y@@A()NLWhSQW;SBl6QhSNg@4icUM@%; zq&Lg?Im{v*y%NbDX#rsz_@Fd7GaC8F+=%Cbg9Ge?Wp~zZj8*#!>s)b$a1yIhoE3;w ziLiiR117)JEkK;X0nOtc$u6O_pXIG0Pr_Fof^P~Ty|1ldnp+M=2%aB6u%$7K{LBDY zL(7d(0YDsCe*OxT{!|1Onc(nlMCdMsEv9Q=a_^tsmAWYiW|#VJ#L6r<^8S26eiBe* zP+P*g+p=YX#hl2V|Mk$o@)kV(1iUhzu$Uv(_Qwm?AwSjpA1L)BTkt?cMPc>t=$^33 z#(Og`RC6wEZJ9^8YEeK^{8*1Ocuz#T3`VyB@o~N7EVv68_dV#3Up=v|aMN0`_g|2F zbJ56+Zetj6di%#2ak?)3C}6ibi{`+C+%T>Rab8i_;DD^+{%|&g{8oB?EHk*EhIdD( z3ZEne@BZBOF8B7o*OT`Y@_gDQ*+MWPaAdC~1aZP`rUn5(b(q4vBt`*y`a4Q%h@dWn zBUDolT5`ZPROG9y(RYGAB_te2?pkjiSe0IsGnXGP5Lm!G_q62TQ;8y4oyOy)ud;pN z7o@e$A~)fI0DgSXCC3B!RCQQonEnFM222W0R+gYNE8nqt#;Sz3r(X;5RD0lhm(l)2cR^K)vJ`;SXXEH#L~y}Td*!ue{;|)n*AL7i9`>tqM|zD2gt&%U>5FzRyfihdFv4=Ar6xhZgBZ{q+zElu z3Z1!l-lJP2%sLq+H+<`r%WjD24f(w+VH7%|{T8Va-~w|_w7x@RU>JV|KjK&U(8)aS zj0PR5vHeQgjeYbj*a2d&4y$~3FBW~QI1z?W5yh{IZi==B08OLb|L!oH|8Nh#z*uc{p)oj^Iulh2yeE3b{4V+tx_b^#3h%gCIxaqxyw*iMUJtJM@otGYA zQBaZgo(UFxr}7M(X8?yga(JqQYhZ4>>#OnL3ybq&9=VEE1C$VeKg7f196wqJ5N-K0 zxbPATD{b47))J;DYq<3 z6W)ex$Cjbioy1~4mHPSp9&NmSm@h2i$BbAt^|Aeo&Iq;u^wmgju7{KGZ?5G4TxFP9 zIclxhMh6HqaA*R+JT0(GGDbqrTfTSPs+;{8&Ef3*YCL>vyKB z&;`|mO8{7hd2SP>4u7HY#R=zqfImn49hZNN&O1fH_-|>CzKZ+vC z+V_JdN(996U&UZ=%vDSHK_c7m8tw*c%X$Ng`z&J54cR=g;A6fbK`SBt;W*C?xSXmf0PLA-;&%HWENOnrM z?)`u?PrOU`h3@Ewzk`16G@>wEp!6PeM5QfE$`X_08bI$$SzI+V(~8_5AR;1 z9`aZ#P$p0oUc+2b=wqp}4|dvn;wM4^cDn!zWYVt%;}!cstjG(DLF7olg2^RHJELNH z5KpZf(J4nfaS&El=;@c=3vlUZh7B2|MF0YG@ZP32qW z83GU&$x%DXVs6v{3jN^r;~~__vl|e&d+7_au!Iq^pzw?F>|9RlGdxfc2`4@q?WIX$ zQ<4&dER1S;KqayO2Jn-nrGB$tRTX&+HdP4 zp;}toKmDJRCQF862VAD^g&ZlDB6!ANNIigF1f4Zqq**uS0&38%qd^Fpv9z7oZ$`p8 zah`hngQoyMgmH^93fXp;sG0BW7c3I0Md8QirT0O)L|zc49|nC-&Wt|~iNjd^R|&r` zbo)CZ3QtCxhNCwJU%34qHR`D6bEGsvXbtOzh(8;R0lT7~k?V0n>{fw@IEXf)Upftc z-^ZyK1oCWBXQTB1HhH(;*C>bm`(I$9$a$$hS#0|iW@2okfk{uLrGCvG*w2;C%d8sJ zj=%%o>{G=(u5Hz#u@mm4yxOd@DS*Lc=FSx#2NepY9acn!Uy#w%ur2O z@bNgP3*~d%Vc)(H@REQq^w29uflCrk*q<15#Q>eACkITnfLeM(V>5{A8|9@}+zQUc z^u6RoSKQ_a7$%~`jY-i+ng2cq4zl3`(JB#uFlukY-$1%7>_&`#dZ*b7YpxNJUj)gP zr4ehbH$#l^RvQ@2NZ<)yla+v%G|duO^l1admvR;aw}Vw_75xBT(N60pmhVk@1Vy{O zccL_6oqEQT9`{^V>w6{Ec>oNA!^de7L%ZUqyi(X$TpF}C|*TbP}QPA^3C-@>9 zKf{Oz$k1&xE-V!6BHsM#U2xwhdt2UL0)U#due})^38H|!7W5;Rz^B`rS3?!m#Ebl7o@9gzDE9 zeyJxW1;G_2+Af5ZINSAPyV0!3K@i&}gq3~L7GA7*AaA|VI^NuE3*_O6m~?1`$a}K& zwdCU{z?IeLVrBWK9Si+ORh0WAew#W*bhSH(oo~JUvYr7`MAc6S5T@uxQE8`VJ3xwgK{Lk^Fa)t9tQ47I# z$!ADFIF~8enmG+#0#HQ-OuCF}Xe0RD$;q3|f;Hij&)|T7--YnBThu?m;n;tNRkQ`3 z?lhN~GqEa%VLT^D^mKT#xF8ncORtiV9GQ@QVi8L>;abT zH1!_;+rpvF)(NBp&7&UyDs3z3qd01VM^g|ggkWs{g(3MiZtFE$vk2{cR?#dROwgsl z%Z)A!f5~uK^;yOq?Wxq3n`2tpj1)XC{&SEQrM&Vz$gNKB!*|&y#rvN8yLmGnl7@`c?Zu6dp!_3SXYV^A=RE%e`E%j7E_3zZ~F=EF?Gh z0nvt@`ZeT$`n4@$$h4m_EiLHbU>k}YAqGneIpYSY-sRwk8U;{weE3hXu!b52J>YM( z%i~h^jm5tr&mG7-V>rFc|F3j#w-$9z)P>$+#oY&`0fj?Yfb0*T<|6wU4aC6gk0?a{ z&L8gq94X*wV1&$}inHDOP28Pp2SWjF{0YWw??IeIM_8uU@f&ogFkM>z$Xo%x0Ovv? z4k1iZH`+&lU9dP*qb_t+Hv%I=BgEoaC7(%Y40@TVbbmY`vN%XRlWw=uMTl`Y3GFDi z;$N~OPJZsE1i1lra7@P%3}e77@j2Y)Fm|ofk94(1=(gS?ieHa;Mp%Fg=SAKW8D^(~ zZPH_f;s<+KT|}7D{VzL#Kja&7BhAC9^hJ7N4UB^+PR%&luE0o!cmr14p7F2jMz=p< zmwENCHO?VoF*gYG%~V~1$>Iy>_b`0}Qxq~r1t|B(K#@3TvrK28JeWZDQcwI2VP_fT z(hK<#31}NE%5lkjvx;CSB@9mP?Yen!D^eEHyGQX1)N}v?K$qB_E4%miy@-{*l(71Y zhOk@N9R)cq;d2l{$Uj_>{3Bq<2jhKPhI7Qq2h{r`q!(ovchNaAY?lmAPQb_orcd|~ zY(%Am15aI^H;@-$8IKJ(6MTxXR>N`*$U;(>qgg)`nmP?T0l$C=3~4BOoUl{@qsAecZUh$nJJECH+E^G?V!%=t+fxdqYx-Y=-f5U<$ zFJv<9aLc({hzkhecLOh)F;%eq`5u9VJ4W-S@J`l59t|r7re!lpPBtkQq1>>vD#{9$ z6@9L*%SVI_WuUhr!h~ExMV*cjjj~As_yL;?s}c#;FM&S)$#sdX@kJ2b|Asj**3c?H zO@Vg493nEnSdtXX^PgAOo_@3*;)VeT;+pUKCJPdi;G@4N{iGmxJ-AAw1-J?@09Gzm zs&pL|RF$wmK!OP|_#c=9ZZLsN;CQTJO?gT7KgMT`AB@$OG}(uhc>n)*&!jmMz`BJb z?L+JdSSnmyC>n}WQb^?(V1xj|sH~2I#=$8|jZ;KdTmFFJrR=`a9tu;zlovWk^!-!s z5iClvY6&fKFuQnLabRi{AA|<$Zp1Mqu&5*KB-2*n;guaP8ET5&*Ix9kAl1278biiT z@*OdfO_&&i4Gh5=WlUug_Yf<=@5oyV8y~U4Y+4L0dVSXY8yac`bU{VU#CA1$ck=vWs*Fz7k~t zLEB@^0-+BEfdsHo4!JF3n7|L9djQLWD*+FIXhsu9Q-IiCoW5IXMg%X|mA^I_Xee%k z-m&Aae%%EBBc6gp9-zSVG7Kpaxbhb%qHv+ zksF?`4I|aRuXBSpVYE>$8ZjxbXN)>2hUN_$@j(C2YnLwd4iSmqw8fHWjgV`1grBkX zyeS0GrMux+z%LB66tD>T4hN%su6O&^=;Xh`pfg!Wu#A>s3YyE5Af*2AX;s_X=#6g? zJ~)LoX@nyqik&Ey?DpA%q|fB9_I>=xwjI_H+R^T|{=do`4*K0)XOhpsQyRamgX>}w zTWo{?T&;iPaXUBu_y`@19VyLUV`^{tVLcG;(OR@~gtlnM2LCbjwbDny8k6}rWWcmp za;fGUa8X41(mnkr^BE#LB7Y*BbJd^PH!Wh)^UXjm=Yon-DE!6>l~3#^h8$GOdcuXSvSq~~fA_Ewg%NcTdNsXU~ za$yOc7YV+^=;KG2-Z%B<;qepdKHf6B@+)+cKGR6O7khvj3~!c?`9$sckvT1)KYpm! zm)}2o(_v<>QYR^Bzx_reY$-NOwZ0uw+b;ZBNn+`!{o3q(t=MNv^6E|PO~ttC<@#rx zz2r*N~r+Ky}a;yvXNCd;r)1ucx)MF$f1nYtwvy7SO(PhPreYv=V`~`(v9;i*0@$w zMbNs>J?RY+O>ugxTKzXI~mm!8xqfNFHhkMBdqrqz(5GnS1}xj z(TLD6-sbPO_l7ziE!+H;Lu?Yq=7)0Q-1ShP=`b|D@R9`Uts3 zU1e+Ad}+BscHqK+C>;i1E$?oN=w7`l8H>tJLZGRxa1L?17c#zVki9o>>Ow+JWyhJS z-=RnF&HaT^awi_HJN%y9aB)1VL5JE(0IjLdmlL%bVQk1P#YXuXA|%qPvvK0qeBBNJ zlng-JbHjm*MExQCqML+agbSIK-JQ>>z7;a`e#rJD z4@;x7?>yds3J^oORJ!2%7zVu|8-%wUby$(8#jkG_J`r7pdhyT;uWXPFu%&+WWBfXwZhp z|Lx~Fx#Mn=>|g~?pCC#W`#N}DbSUSl+u<;1#gAXdaDCMEI-l}JR$}7fg8r-!3)P3@ zieisvc+xd4?~jo5-L8MqQ=@@TO1KA+D~>p}muCeX1UG~{`I63}@C{TG>```^dE5)r&5-`O_)yzLbEA0E@AHedEk#v=3W=NF`wK9@>`$$$z9LA*C2de z4`Kc4AD`5{7gX|G2P#?W9`Sa`gZ_x0v4w`pRa#b*y^JRT%CakBj&1vcHXoNq;=gh7 z8ElSvz5tB*`u9G_pXNgG8Y#C?#{3NJqXn9;m~kMGL=VL_B+=@23jNGK>t{F^8Q^c2 z!t2bud+_PrPk><25H3C8Xb@sW+!Oci4(qaT`~|s{Y_gW^eDC_o{TwPe)?@iLc=rZ) zRDg=!d0x>H-P^)hrS6Yd5Z5H2X2PXo3J9_Ah+*G3o=C4^!$USHHf-_&@Jy@2`54ba z2T*m>_Yc=oZ`s}P1Vf#AGGlG>-#+f);Xu6V4Sp10e+o&G8l}SeWYHPzkM!V{@ za`1T(ve5D}e9Ld@+&m^Ed$kc(D@1KWT|u=fe7XJ!+U9ei6lXfoo!;bsFXD~<w0HG&P5UK z`}`a7Z!h!ruyr)@G z(~?S&O4$=Ivu)ppfzQ5e=MVO?<+ee*&9KK(5-Rd*{SEey5bqF?WQgx_My}4p%&t7N zlF-MqMdA%{c<9kyWXt0iUIdAh1*aa_ZPa}jA#R-ons?`4g+3DOYoUZejbeuvZOL|=Y8^eBTmMI@3+?FX zo%_TqXFYY|qsx2OFo}Nz6gE9dOo@K3TXO|-zMF(wOfO_BalEvLqW7wY7)#%Qbz?q3 zdsXa0_-4H`I~p4?1ZB6>XAZjO+h<5G)$!dF8!mK^^u&ANEdi@eb!Rm%tDZGNWkEfp z7kMfemNUq2Bq!b*Y>5n%y>w;As6l-iiH^jlstkE0-{^*QDK^p*TRuF_;LlLb5Z8ae zX%pOOED4_-e6bWW{28B#ojfH*yWRNv+XmnxauGn~_d?JlAx zU23f3w$9a`k71rofjh9dt3Fl1pVG1MKEO_x?Ld3ti6=Uy6k@yM?GsH- zKIiKtio2$mYl_=i-`!pZylhg*3d3y9-UPjTFTk#HHQCunbP^HXg7hRswV2Y{S!L?u z|IRo-@-u0keV}kyw84+zyH1*_T(0RlyTmgSz~Oy()>7}ji2T(?aP4h85tTBpzf2ZSdd>PFAJwVt_{ zRA0Uyc(}YI&TM;_!v=Fw>ZU!_ofbM?K~AC^J1K8A`C^pL9pNn%dwxj9lad=jooX3R z-AZTaycwSO`|d3lWA$BI)7*GGj`=W|gxbHsQw9{7>}&GKux_w)>I z{gsz6`zGJAt3y@!lgzZt()HQ3v;s$U+3xD%4*dFc_yZ24IPu;$L@~8<@dbnZ48wo^ zXSYjU0E209_`Uf^2b!_+w~Ygmwq4SpGaN;UHO$m|v%?;&N0@HN+*=Q>mHI!9&OM&# z{{7>Xb7VToair1#D>*ZBs3@Uwm)kivlE|5vvE^J5DS4PsW!9*rN$w=1Wx!`C6-3u~&9q`yCqh zmdFw9o6btL-8LBY=DcXuP#=G^5oR-bUIwgoYfuY$Nld(TGDyaU{!t@9h?!_|Gcw|& z1JK4|?00u?f%w=-Y9MSA`_65%iMFW`$Cnl&io{rQ1mbu@E-F`9SL@bmYH{+=pu6n) z$;~nP05Wl3P%8))khQ$&%I~=a39QzvRY5%cg$$vK4!gkOo_{`T&vB9PMJi zBTuK+m{h#lfw0Gtd1;UaJ^ z!pqTK%`Iq8RTMBTL6IoCgca+3LZxxlU~Z;k?I@~}8^1~g=#R{x24nNSz6w^9&@)XN zXcAZn$32%U*t_O!GpQ%;E*%!QQwr5XV9W8Y-{G`cRm`XfQj)9;poaFcMZTw`J}Fc_ ziu=cw-Lxam==cx>rcDM~C9++2o^wrbw-j86u(yoRcF}UL;N)K;^uJs(f!UaZNxET-8>{ETgO7s(mnqWzs7G>9dGIZTe z3m1z(_5}_xuH+YtitYNTX6de_aO4D}!ZpeAIHpbcE_bl5Vehk(%w>G&Jp9Oxx5-0T z#N;g^IA1rC|$3p9_O;S8lqj+*e!s_ z?odl&hKn7$eR^KW;idKdG>l(2%ILQQ(Nx@-2L-ih{^EPQH_GUKijDDN(|q zFb~aW;LWk)s4OKyD73pdoxY~m%hpkhQVZE1ayIio_cG0RfEUru))RVv1w1RQ zhkE+pfA5Ns5jal#m8u1b=>tKM@eEy^{Jz9ll{>GVLaD53P`M`SpQ1e>V_tN1vZf3 z5=8Of>7D5mU*p&)e(ZM+Ho4OYCtBcbclIa*muiwMY;S zIBZwIL`ZVFP_YONYE*CgA@>R;kh$UpWrwF|l{%j{)19?=2!|aODG1^LKOhC?R;j7F zePM-9L*m2E03A5_lrnm>R$?o-XUmqJpX4nX+HHoXZ>D4#>Fz+I{M1(qAC4BxFq_X< zWcCI(2pi-ogXqx0kf1t*!nc3zEFqSY2g~>B>VGSg74K$78Jt*brSDoU6$-RIe%{9} zCr2M~2b%1f8QadQpU!*=wNn8b5Y!7Tih!!vM*=QHlVGBpd%bd>QnTcp1#sTOY80f} z3XEo$@_cZ8io}Aq43T(+80H_7m!{=t{ntY)CpV2(XZvFja=4DT)O;+9c75yu>f5cE zgdJ7;BfZ?|Hw|0w%I?~e+xMCdv(gI4Of4&*8&}dDYj(o(x0`B7ceBTQLr`~_OuGT; zb%4aER_r@KI4tdK59p}Q;b39U{h5D=wnN=^IN-$FsAhD526_<+?2<~mM|}Zy zQN0#o{fu*c3kw5SG0lLb+HGHkvR^(q+H(ogY(@4Cc%!PIV~&*bY)`V6T$iypx|jv> zU93SW7M{aKGvE=)MWj=MLGQi6HDrZXHFkUv%ll@v5VL>4czHHog46du^=fOotDE=+ zBL2hUy@x#vrdx((fHZgcQLRc9OtS887d(bM9aCfL8HHtKg(^W3;6`Zp2i|e=izH|{ z`G|zKn%v-v{j-wLo>d=+nUbzHhRhgnTcR~RM?fvBXEmrDZ=r|2p9f^I)t*n@E8CFZ zW(Co+{&Y*X?f#Hh0>w{3_Q!VqTFl5=s#q#}eknt|*Zke6y0*LUU>KO-zqfvvQDZ{U0OIw(H%P>{&I?30wx_N8a_HWSDogY{Sf<@~9n*Zo+*BB0fayhCV zWMNRR72>M&sa68m_r!`RZtkAH;RBKkH>2|7j2Q_UH+C0tXQM zmedlbmS@M$z;u+?U^ty#yGOr_;Z^g{oxC}Zq3z16{*hJpxbVog*uhH#I&ikl1qCix zwN|AHj`w0;2TgnkZcTi>pEo!W?+G#akY32|fb!J|&qd91xkGo6rY!Tw{Kd7s$)wTJ4mLD&H75bd3+;?ckPAmmkbMKZ7{ zpTZj5Vtdak0IPc=v<8Y_#?}O(LeA?oZD}|p0gXDhK!#IY*F+4O%{Si9bbm^IOm)+y znvDq@PYsYh%Y&==^u#b|kp*F@E&k$XKMnTtF6MN&5tzr^*~$j8FR(F3b9Cb*65Mrs z;1hb?rVUr=)6CSL+7$E5ybWW*EWlyeYTU_AM2+rZQ7} z!BTg%b832k+1NIUplqmW;1hATboOPd4=2;@^w4c*B3~)U4N_A)DB{KzV^B}Q!j~<1 zZycrXKv26=NpA|yZG-^6YnPd6@J)@4b;;`6zE?*~bqce8wR*ju2S&ssQNos@L~HTE zuzeea4>smw+9-YR*04r}=1V=;%`e9o9HL;p0*ZkTF5Et=Pn_cTbw`>f4mzgP+pQOL z4Hg)5sZJhkxSV@?Dx9jex3|v`nVhLoOGS_fr3c?rv|A0>^gi($V2Cq@howUK1u`+4ws)%jaNvxPB1qjSXql~ z8$jJQN`7xyfNO@WlQssZLNb8`eegnZ$8`;@*28)nbVFE_&$3mrQ~~`56zDPS<`hzWmrj$56U5Znqg(5U0&TM6b-boskCDhtS~1r zBV8c}43OqOPBgn>ruJ_2n*GbUSnlCME@ST|`h$m0V;RpS-p|QEtg9-nkA>poaVZze z38S^QCZaIC;}u7y_y3jPh$s4Nhq{=ozVX}w3h@xfUa8t;Ez{g5{RKm6_vg>@ z@WXp>Ue&!XE*LojlIz;ULN2p5Tz@ZVw9knBqo^=Q?AOq_jcsRT_C@5G-`68gm}!En zD{V)N-t7{lgCG98*zJ92hY;rsD=$;XV4H04=Q8SbRw<@%KG6zES1h0uZ6E#7_IqLP zE-f#)#!A`VEwk?}{onj9=wn!LP{0$ekC?}*0%c^0pyBSWt4=$bX{ z_tX=v({@{rErPE((G5LnljND|{wC4KP5Jc?e#Nn*4m z{%=Y`Rd~0d=G*mYFQ0Xn5d5p07PP_;Oe24I!1P$@vX%suns#1Cx zouHfBvcM4C(QcR>P93eZ&)D@p^?k)fb#%gwL6}btMRb)}Pi-wO4gkd*R%V~^!-d}_ z`C|G4nh}ZhP)rqPVr^#J@~(kqGCuC}la+}|-y-Zu8lCTb$oIl!WpN?Ox+YZ^<3^)9 zS<92dAX4*2UjEc@Jy4OAt6b+WrJ9b}N=57VeUh_-d1IHWavLbCB7qO9v*k#b7QSZJt_SZnkfY_?3r#Ue zQP&LndAHiYTBv%{{wWq}I{xDU*zWl(#_?Wwk9_fEG7NV-Brj}L%%|Ots})udgIDkw zm{PZ`^uGy<`Hdd;P{l>=!s9u@e<%j{+Rq%TRCp>z_nB+-mAT2O*8#dqg`)aiRegpx zX|Ay~zRDrW^^2vIZ0ic_vh%w>Fgp1I_82WD3Hp}2egzPeloBUVki~Lc?@)WjnZAqP z@Y`6Nd_CYM+Ui~4E$>Y8H|M((AY~xI>NRzzAxg#jTy@wm{;619$9Q55LkX_rR=lNQD`&6dhWM#I#ZMMuK}=}@ zK``Ju^rwI~9xmU4nu|Mn#O)YA2lTZY3Up;it3_DB;KC%v*>Md&i!nnKK?zv8rD1L5 zX25uylLQ6rAmiSP8?pD!28hRpCGN!SIHPn(Zwms-0-Gk%B~?B^j%xOI8QRe_ZvLz7 z2_|#3i1}|BfN|r&RwH23Ce!da*9z4o?hN;DmA99TH;6ppIagV}%ONJge%KNK{$P`+BTY*b-kZu1)~y#cXRG)&hDH6D5u-0Vy|!ckSSB`wmzQS@G* z=(S8GYo*z9KI^;|EyIvA-ql&{ThGKfMW~9b7WC-Z)xVSXs?EAh6Q>GvY=Uy+Nd3R{ zA(yZjeQ<>xirEHwdg0lb)pTo7KGl+hKIE`gTP>-3%UZ-BZRN*9e}kyt_G|a_qssdx zU1{A}MR2i;2`4~Sm&*!EM(jc{e?2OvX;+c}=sDo4IkDN`|htha>F$@9~SzrWlP&He(o66Et#H z;1+R+8XAf}SOD{$Fo>D;;f{QR!{l_My-kn@Ju{M^8D!2eceoP7bhm6P)mZnLBK)wo z(?rX1Zmm4^Qt_YQEPK4_*gTXYg*fcFN&ANw*1EyWpQh>+*4rAPj~5}2lJ5fo413!} z-7hPzDllMD{}*m z*bm5DOQAc=(l)Zt_DXBQz3q<@JbHE#r(MGGILuJY#Bu>sBY`W6Ggl;{zG9K4r?KKe ziA-wn%DAV2pKX2n61qvw2)#EDAhH~lRYrV+o!nL7v2F47PYj#)!@IT3myNz;Xi&j#84u$tpMQ;; zYSwHtT1#J*iEH!gxqBt2aXZD%6lq9K&+un=SV@YpzT9J&9sBFE%3|qJCargVR38Zy zHczw%w%aoO;$6<>AF{6IQt0xbuEaaG`&Eg?`PC2X*1H2@Zt9f;<*W0k8L*G9ghBDRuYK@tGNm=woOcITQQ=Gko}=DB zeWgMe_&x&YIV9lUhE$${?WIY%vP~vrUm4@~5*#gbrvWAufaP+WBG#@> z!8M`g2ufPnNilTJoV)w$9w4*dvVss0(=qnPnqfXLIx?64?<&nz7539$_$aCy6&q#) zL4KBJth8u9n_7K{Z-dXVflF=ztAl8!;t>K*T@r_`GiBSM~y24O)o z_h760Cw75b=QQ`by4=tRZ-$kbKSgnhB~cRwvSDHKg0#IRrL~i|c9gDeX(l7uXZa@O z)kFCtMhJik=7|s?LlMh)gULn&_!E_9?>hqk?aNIMOP##q=`nfCzzNqBW4wOZHSm_9 zfWeSb7I>}O7GHguZ^({z1xHVH@r<~)DWw{_Kd8z}5CItBI5x|3|4iBk<5;bTv(H}d z!0@dVB-q^Oaf2>pY2&$WDp&@qEee;Qo$<7i9d#W~vtosmg*c}lFW(_$rRgoecq;y| zz3Z7-o1bcu6|L1lpg7d&~(YpL^yBhg$v7Ay_E zcC{D&=XecB32Npaqa{8&zMwZh*evf?xWJ4q+V;;14`1)$3_v9Iw#Bj-`n|p%=TDQ= z)=l-PS#eE_njWI{ZvFE9)RBVy-mb6`6s@0sdVjCVL+*La8nMYD5N$tMcc?BjX15u?qz29guE@!oaoG~rxZJ{yMKPF zS4*2BPkHjmmlSgJVRw+ZaUz=T`7}qT&&sJCV_ zq^&n}XV5};*&ufd?r$59`iSnuF6z2hRnQ4g&uPqMGN zb`4`XmiCs7+vY{33gknh(~|7JxxO~7YidK2EQuqctC$BHplKEfwoca}1nquRRj`TW zM&RxMs8X$x>a0T^2`C*@DX6%r?1EF?B8Udtv1>1>I{rT1w<@Bu5_>9#hqigNCrUA* zKAfJSxTda-niWKLzAoI+el~o@4@ka1ZkE1Jx$%o#`dT~|`bd}2Y7Y9I8TUKl&%*i{ z7#sa#>yk$aIn*^h*iBxLDZ(?;C8AKb+ER?iVwioI|~UyZnulTsQs?;(ho z^_c26?^mP>-ga~UDpovn**_9N-TdOMymkh6vbs3fW_>je$*1M6$^Fks+1?EFuB^Vz z>10T8e_k%94t8Vkd&||ZL8{2oi)S?+O|ZrB^zAHBxO|-gZBD0bD&^h6-C!Kx<;dH&#+yw~@2x~` zl!5MBM(*gQTro53hk&MJ*v?r8Tk5;L;Hw+;3Hp?ujP;GuE{P?QBy1*(fbsPaaWSJX z%|-_HI#6Ms)0-{fUj3;Jk)EpFh2hY?=vg_O08T6*V!z9ZICM1Jm<&N#5iJb^ESl_f zRY`sMQ^cA~a>qfIuW}kJBH$ew+BpJ~qMah2#J!ZUOqM7k)P~wlFew^i?TSSGhyp{U zw6#E3^KBwfDqQebgdDab-?3>Vk1}JX&%GCS2R76-DaaB~Rv{XPyY4)Tj~3>SO~!gd z(CV@e!g%*1>2Fs(gsgzJLR}+nePz5wR}#Ix%6Y1JGTVK)XoPKU&veiD=fea9Y>9Vh zkK;nnD`^n1fdQ7qinh~KF@_?&_7TtKTX2naO+-N zLnw}Nkt;f8o98kx^qRT{)C^Z3cLBh={1f#+RiX#Z5G4&QWp#|Tk2cQx5#99LOUiNs zq9OmSY2lWEt>}{93L^Ui3tn^3x2K!NOS2u4qv{_!jwuptZeg87*^A9 zb;e{;$uBDcMHxkv$c1Ey&q*8A#k1?TFhnjEaoA00WOXQPZRpa9NJ3njL zxXF=UV7Q6FwxJjIV*ke1VL_*bS%pKKqbTvGE<~N)pi{lt{8;e8{3su` zc{xj016Ih%sU1~nS1L4X>N>yo&&0XVCIk0EwK1U|a#CyQ#43)Se72TY@V3S%0{t-6 zw$F_{ZbbkSh^@~pji}|6ypyu5$eo>Acr;qwQE*uV<3f|@bTpkgUAB&FER2x>^OYv

s}9o!EX@>QoHJ8(8M*->}0gV;fpGymU$N}eOD*f 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 I73dKF0FPF*hyVZp diff --git a/vendor/github.com/containers/buildah/new.go b/vendor/github.com/containers/buildah/new.go index 1f8bb87b8a1..dbf5a9d3c2f 100644 --- a/vendor/github.com/containers/buildah/new.go +++ b/vendor/github.com/containers/buildah/new.go @@ -129,10 +129,7 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions if options.NetworkInterface == nil { // create the network interface - // Note: It is important to do this before we pull any images/create containers. - // The default backend detection logic needs an empty store to correctly detect - // that we can use netavark, if the store was not empty it will use CNI to not break existing installs. - options.NetworkInterface, err = getNetworkInterface(store, options.CNIConfigDir, options.CNIPluginPath) + options.NetworkInterface, err = getNetworkInterface(store) if err != nil { return nil, err } @@ -307,8 +304,6 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions Isolation: options.Isolation, NamespaceOptions: namespaceOptions, ConfigureNetwork: options.ConfigureNetwork, - CNIPluginPath: options.CNIPluginPath, - CNIConfigDir: options.CNIConfigDir, IDMappingOptions: define.IDMappingOptions{ HostUIDMapping: len(uidmap) == 0, HostGIDMapping: len(uidmap) == 0, diff --git a/vendor/github.com/containers/buildah/pkg/cli/build.go b/vendor/github.com/containers/buildah/pkg/cli/build.go index e2df822848f..8db26a6c195 100644 --- a/vendor/github.com/containers/buildah/pkg/cli/build.go +++ b/vendor/github.com/containers/buildah/pkg/cli/build.go @@ -331,7 +331,7 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) ( } } - if c.Flag("network").Changed && c.Flag("isolation").Changed { + if c.Flag("network").Changed { if isolation == define.IsolationChroot { if ns := namespaceOptions.Find(string(specs.NetworkNamespace)); ns != nil { if !ns.Host { @@ -390,8 +390,6 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) ( CacheTo: cacheTo, CacheTTL: cacheTTL, CDIConfigDir: iopts.CDIConfigDir, - CNIConfigDir: iopts.CNIConfigDir, - CNIPluginPath: iopts.CNIPlugInPath, CompatVolumes: compatVolumes, ConfidentialWorkload: confidentialWorkloadOptions, CPPFlags: iopts.CPPFlags, diff --git a/vendor/github.com/containers/buildah/pkg/cli/common.go b/vendor/github.com/containers/buildah/pkg/cli/common.go index fe41c0d0977..7eee472b073 100644 --- a/vendor/github.com/containers/buildah/pkg/cli/common.go +++ b/vendor/github.com/containers/buildah/pkg/cli/common.go @@ -42,10 +42,12 @@ type UserNSResults struct { // NameSpaceResults represents the results for Namespace flags type NameSpaceResults struct { - Cgroup string - IPC string - Network string - CNIConfigDir string + Cgroup string + IPC string + Network string + // Deprecated: CNIConfigDir is no longer used and is expected to be empty. + CNIConfigDir string + // Deprecated: CNIPlugInPath is no longer used and is expected to be empty. CNIPlugInPath string PID string UTS string @@ -195,10 +197,6 @@ func GetNameSpaceFlags(flags *NameSpaceResults) pflag.FlagSet { fs.StringVar(&flags.Cgroup, "cgroupns", "", "'private', or 'host'") fs.StringVar(&flags.IPC, string(specs.IPCNamespace), "", "'private', `path` of IPC namespace to join, or 'host'") fs.StringVar(&flags.Network, string(specs.NetworkNamespace), "", "'private', 'none', 'ns:path' of network namespace to join, or 'host'") - fs.StringVar(&flags.CNIConfigDir, "cni-config-dir", "", "`directory` of CNI configuration files") - _ = fs.MarkHidden("cni-config-dir") - fs.StringVar(&flags.CNIPlugInPath, "cni-plugin-path", "", "`path` of CNI network plugins") - _ = fs.MarkHidden("cni-plugin-path") fs.StringVar(&flags.PID, string(specs.PIDNamespace), "", "private, `path` of PID namespace to join, or 'host'") fs.StringVar(&flags.UTS, string(specs.UTSNamespace), "", "private, :`path` of UTS namespace to join, or 'host'") return fs diff --git a/vendor/github.com/containers/buildah/pkg/overlay/overlay.go b/vendor/github.com/containers/buildah/pkg/overlay/overlay.go index 4353c7bbaf2..0eafdbbac42 100644 --- a/vendor/github.com/containers/buildah/pkg/overlay/overlay.go +++ b/vendor/github.com/containers/buildah/pkg/overlay/overlay.go @@ -61,7 +61,7 @@ type Options struct { // beneath it, and then returns the path of the new directory. func TempDir(containerDir string, rootUID, rootGID int) (string, error) { contentDir := filepath.Join(containerDir, "overlay") - if err := idtools.MkdirAllAs(contentDir, 0o700, rootUID, rootGID); err != nil { + if err := idtools.MkdirAllAndChown(contentDir, 0o700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { return "", fmt.Errorf("failed to create the overlay %s directory: %w", contentDir, err) } @@ -76,7 +76,7 @@ func TempDir(containerDir string, rootUID, rootGID int) (string, error) { // GenerateStructure generates an overlay directory structure for container content func GenerateStructure(containerDir, containerID, name string, rootUID, rootGID int) (string, error) { contentDir := filepath.Join(containerDir, "overlay-containers", containerID, name) - if err := idtools.MkdirAllAs(contentDir, 0o700, rootUID, rootGID); err != nil { + if err := idtools.MkdirAllAndChown(contentDir, 0o700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { return "", fmt.Errorf("failed to create the overlay %s directory: %w", contentDir, err) } @@ -87,14 +87,14 @@ func GenerateStructure(containerDir, containerID, name string, rootUID, rootGID func generateOverlayStructure(containerDir string, rootUID, rootGID int) error { upperDir := filepath.Join(containerDir, "upper") workDir := filepath.Join(containerDir, "work") - if err := idtools.MkdirAllAs(upperDir, 0o700, rootUID, rootGID); err != nil { + if err := idtools.MkdirAllAndChown(upperDir, 0o700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { return fmt.Errorf("creating overlay upper directory %s: %w", upperDir, err) } - if err := idtools.MkdirAllAs(workDir, 0o700, rootUID, rootGID); err != nil { + if err := idtools.MkdirAllAndChown(workDir, 0o700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { return fmt.Errorf("creating overlay work directory %s: %w", workDir, err) } mergeDir := filepath.Join(containerDir, "merge") - if err := idtools.MkdirAllAs(mergeDir, 0o700, rootUID, rootGID); err != nil { + if err := idtools.MkdirAllAndChown(mergeDir, 0o700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { return fmt.Errorf("creating overlay merge directory %s: %w", mergeDir, err) } return nil @@ -216,7 +216,7 @@ func recreate(contentDir string) error { return err } - if err := idtools.MkdirAllAs(contentDir, os.FileMode(st.Mode()), int(st.UID()), int(st.GID())); err != nil { + if err := idtools.MkdirAllAndChown(contentDir, os.FileMode(st.Mode()), idtools.IDPair{UID: int(st.UID()), GID: int(st.GID())}); err != nil { return fmt.Errorf("failed to create overlay directory: %w", err) } return nil diff --git a/vendor/github.com/containers/buildah/pull.go b/vendor/github.com/containers/buildah/pull.go index 8fd715794b0..89a4defd543 100644 --- a/vendor/github.com/containers/buildah/pull.go +++ b/vendor/github.com/containers/buildah/pull.go @@ -87,14 +87,6 @@ func Pull(_ context.Context, imageName string, options PullOptions) (imageID str return "", err } - // Note: It is important to do this before we pull any images/create containers. - // The default backend detection logic needs an empty store to correctly detect - // that we can use netavark, if the store was not empty it will use CNI to not break existing installs. - _, err = getNetworkInterface(options.Store, "", "") - if err != nil { - return "", err - } - runtime, err := libimage.RuntimeFromStore(options.Store, &libimage.RuntimeOptions{SystemContext: options.SystemContext}) if err != nil { return "", err diff --git a/vendor/github.com/containers/buildah/run.go b/vendor/github.com/containers/buildah/run.go index 4f20f9c1b80..0efa4d8b03e 100644 --- a/vendor/github.com/containers/buildah/run.go +++ b/vendor/github.com/containers/buildah/run.go @@ -129,11 +129,11 @@ type RunOptions struct { // namespace), effectively deciding whether or not the process has a // usable network. ConfigureNetwork define.NetworkConfigurationPolicy - // CNIPluginPath is the location of CNI plugin helpers, if they should be - // run from a location other than the default location. + // Deprecated: CNIPluginPath was the location of CNI plugin helpers. + // It is no longer used and is expected to be empty. CNIPluginPath string - // CNIConfigDir is the location of CNI configuration files, if the files in - // the default configuration directory shouldn't be used. + // Deprecated: CNIConfigDir was the location of CNI configuration files. + // It is no longer used and is expected to be empty. CNIConfigDir string // Terminal provides a way to specify whether or not the command should // be run with a pseudoterminal. By default (DefaultTerminal), a @@ -199,12 +199,12 @@ type runMountArtifacts struct { MountedImages []string // Agents are the ssh agents started, which should have their Shutdown() methods called Agents []*sshagent.AgentServer - // SSHAuthSock is the path to the ssh auth sock inside the container - SSHAuthSock string // Lock files, which should have their Unlock() methods called TargetLocks []*lockfile.LockFile // Intermediate mount points, which should be Unmount()ed and Removed()d IntermediateMounts []string + // Environment variables that should be set for RUN that may contain secrets, each is name=value form + EnvVars []string } // RunMountInfo are the available run mounts for this run diff --git a/vendor/github.com/containers/buildah/run_common.go b/vendor/github.com/containers/buildah/run_common.go index d9f1b35939c..640e375c417 100644 --- a/vendor/github.com/containers/buildah/run_common.go +++ b/vendor/github.com/containers/buildah/run_common.go @@ -331,22 +331,13 @@ func (b *Builder) configureEnvironment(g *generate.Generator, options RunOptions } // getNetworkInterface creates the network interface -func getNetworkInterface(store storage.Store, cniConfDir, cniPluginPath string) (netTypes.ContainerNetwork, error) { +func getNetworkInterface(store storage.Store) (netTypes.ContainerNetwork, error) { conf, err := config.Default() if err != nil { return nil, err } - // copy the config to not modify the default by accident - newconf := *conf - if len(cniConfDir) > 0 { - newconf.Network.NetworkConfigDir = cniConfDir - } - if len(cniPluginPath) > 0 { - plugins := strings.Split(cniPluginPath, string(os.PathListSeparator)) - newconf.Network.CNIPluginDirs.Set(plugins) - } - _, netInt, err := network.NetworkBackend(store, &newconf, false) + _, netInt, err := network.NetworkBackend(store, conf, false) if err != nil { return nil, err } @@ -478,15 +469,7 @@ func runUsingRuntime(options RunOptions, configureNetwork bool, moreCreateArgs [ logrus.Debugf("config = %v", string(specbytes)) - // Decide which runtime to use. runtime := options.Runtime - if runtime == "" { - runtime = util.Runtime() - } - localRuntime := util.FindLocalRuntime(runtime) - if localRuntime != "" { - runtime = localRuntime - } // Default to just passing down our stdio. getCreateStdio := func() (io.ReadCloser, io.WriteCloser, io.WriteCloser) { @@ -1165,6 +1148,17 @@ func runUsingRuntimeMain() { func (b *Builder) runUsingRuntimeSubproc(isolation define.Isolation, options RunOptions, configureNetwork bool, networkString string, moreCreateArgs []string, spec *specs.Spec, rootPath, bundlePath, containerName, buildContainerName, hostsFile, resolvFile string, ) (err error) { + // Decide which runtime to use in case it was empty. + ociRuntime := options.Runtime + if ociRuntime == "" { + ociRuntime = util.Runtime() + } + localRuntime := util.FindLocalRuntime(ociRuntime) + if localRuntime != "" { + ociRuntime = localRuntime + } + options.Runtime = ociRuntime + // Lock the caller to a single OS-level thread. runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -1433,6 +1427,9 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st mounts = append(mounts, mount) } + // Some mounts require env vars to be set, do these here + spec.Process.Env = append(spec.Process.Env, mountArtifacts.EnvVars...) + // Set the list in the spec. spec.Mounts = mounts succeeded = true @@ -1522,7 +1519,7 @@ func (b *Builder) runSetupRunMounts(bundlePath string, mounts []string, sources intermediateMounts := make([]string, 0, len(mounts)) finalMounts := make([]specs.Mount, 0, len(mounts)) agents := make([]*sshagent.AgentServer, 0, len(mounts)) - defaultSSHSock := "" + var envVars []string targetLocks := []*lockfile.LockFile{} var overlayDirs []string succeeded := false @@ -1561,11 +1558,7 @@ func (b *Builder) runSetupRunMounts(bundlePath string, mounts []string, sources } }() for _, mount := range mounts { - var mountSpec *specs.Mount - var err error - var envFile, image, bundleMountsDir, overlayDir, intermediateMount string - var agent *sshagent.AgentServer - var tl *lockfile.LockFile + var bundleMountsDir string tokens := strings.Split(mount, ",") @@ -1583,35 +1576,39 @@ func (b *Builder) runSetupRunMounts(bundlePath string, mounts []string, sources } switch mountType { case "secret": - mountSpec, envFile, err = b.getSecretMount(tokens, sources.Secrets, idMaps, sources.WorkDir) + mountOrEnvSpec, err := b.getSecretMount(tokens, sources.Secrets, idMaps, sources.WorkDir) if err != nil { return nil, nil, err } - if mountSpec != nil { - finalMounts = append(finalMounts, *mountSpec) - if envFile != "" { - tmpFiles = append(tmpFiles, envFile) - } + if mountOrEnvSpec.Mount != nil { + finalMounts = append(finalMounts, *mountOrEnvSpec.Mount) + } + if mountOrEnvSpec.EnvFile != "" { + tmpFiles = append(tmpFiles, mountOrEnvSpec.EnvFile) + } + if mountOrEnvSpec.EnvVariable != "" { + envVars = append(envVars, mountOrEnvSpec.EnvVariable) } case "ssh": - mountSpec, agent, err = b.getSSHMount(tokens, len(agents), sources.SSHSources, idMaps) + mountSpec, agent, err := b.getSSHMount(tokens, len(agents), sources.SSHSources, idMaps) if err != nil { return nil, nil, err } if mountSpec != nil { finalMounts = append(finalMounts, *mountSpec) if len(agents) == 0 { - defaultSSHSock = mountSpec.Destination + envVars = append(envVars, "SSH_AUTH_SOCK="+mountSpec.Destination) } agents = append(agents, agent) } case define.TypeBind: if bundleMountsDir == "" { + var err error if bundleMountsDir, err = os.MkdirTemp(bundlePath, "mounts"); err != nil { return nil, nil, err } } - mountSpec, image, intermediateMount, overlayDir, err = b.getBindMount(tokens, sources.SystemContext, sources.ContextDir, sources.StageMountPoints, idMaps, sources.WorkDir, bundleMountsDir) + mountSpec, image, intermediateMount, overlayDir, err := b.getBindMount(tokens, sources.SystemContext, sources.ContextDir, sources.StageMountPoints, idMaps, sources.WorkDir, bundleMountsDir) if err != nil { return nil, nil, err } @@ -1626,18 +1623,19 @@ func (b *Builder) runSetupRunMounts(bundlePath string, mounts []string, sources } finalMounts = append(finalMounts, *mountSpec) case "tmpfs": - mountSpec, err = b.getTmpfsMount(tokens, idMaps, sources.WorkDir) + mountSpec, err := b.getTmpfsMount(tokens, idMaps, sources.WorkDir) if err != nil { return nil, nil, err } finalMounts = append(finalMounts, *mountSpec) case "cache": if bundleMountsDir == "" { + var err error if bundleMountsDir, err = os.MkdirTemp(bundlePath, "mounts"); err != nil { return nil, nil, err } } - mountSpec, image, intermediateMount, overlayDir, tl, err = b.getCacheMount(tokens, sources.SystemContext, sources.StageMountPoints, idMaps, sources.WorkDir, bundleMountsDir) + mountSpec, image, intermediateMount, overlayDir, tl, err := b.getCacheMount(tokens, sources.SystemContext, sources.StageMountPoints, idMaps, sources.WorkDir, bundleMountsDir) if err != nil { return nil, nil, err } @@ -1663,9 +1661,9 @@ func (b *Builder) runSetupRunMounts(bundlePath string, mounts []string, sources RunOverlayDirs: overlayDirs, Agents: agents, MountedImages: mountImages, - SSHAuthSock: defaultSSHSock, TargetLocks: targetLocks, IntermediateMounts: intermediateMounts, + EnvVars: envVars, } return finalMounts, artifacts, nil } @@ -1731,16 +1729,27 @@ func (b *Builder) getTmpfsMount(tokens []string, idMaps IDMaps, workDir string) return &volumes[0], nil } -func (b *Builder) getSecretMount(tokens []string, secrets map[string]define.Secret, idMaps IDMaps, workdir string) (_ *specs.Mount, _ string, retErr error) { - errInvalidSyntax := errors.New("secret should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint") +type secretMountOrEnv struct { + // set if mount created + Mount *specs.Mount + + // set if caller mount created from temp created env file + EnvFile string + + // set if caller should add to env variable list + EnvVariable string +} + +func (b *Builder) getSecretMount(tokens []string, secrets map[string]define.Secret, idMaps IDMaps, workdir string) (_ secretMountOrEnv, retErr error) { + errInvalidSyntax := errors.New("secret should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint,env=dstVarName") if len(tokens) == 0 { - return nil, "", errInvalidSyntax + return secretMountOrEnv{}, errInvalidSyntax } - var err error - var id, target string + var id, target, env string var required bool var uid, gid uint32 var mode uint32 = 0o400 + var rv secretMountOrEnv for _, val := range tokens { kv := strings.SplitN(val, "=", 2) switch kv[0] { @@ -1757,110 +1766,133 @@ func (b *Builder) getSecretMount(tokens []string, secrets map[string]define.Secr case "required": required = true if len(kv) > 1 { + var err error required, err = strconv.ParseBool(kv[1]) if err != nil { - return nil, "", errInvalidSyntax + return secretMountOrEnv{}, errInvalidSyntax } } case "mode": mode64, err := strconv.ParseUint(kv[1], 8, 32) if err != nil { - return nil, "", errInvalidSyntax + return secretMountOrEnv{}, errInvalidSyntax } mode = uint32(mode64) case "uid": uid64, err := strconv.ParseUint(kv[1], 10, 32) if err != nil { - return nil, "", errInvalidSyntax + return secretMountOrEnv{}, errInvalidSyntax } uid = uint32(uid64) case "gid": gid64, err := strconv.ParseUint(kv[1], 10, 32) if err != nil { - return nil, "", errInvalidSyntax + return secretMountOrEnv{}, errInvalidSyntax } gid = uint32(gid64) + case "env": + if kv[1] == "" { + return secretMountOrEnv{}, errInvalidSyntax + } + env = kv[1] default: - return nil, "", errInvalidSyntax + return secretMountOrEnv{}, errInvalidSyntax } } - if id == "" { - return nil, "", errInvalidSyntax - } - // Default location for secrets is /run/secrets/id + // apply defaults, matching documented behaviour if target == "" { - target = "/run/secrets/" + id + if env == "" { + target = "/run/secrets/" + id + } + } else { + if id == "" { + id = filepath.Base(target) + } } + if id == "" { + return secretMountOrEnv{}, errInvalidSyntax + } + + // first fetch the secret data secr, ok := secrets[id] if !ok { if required { - return nil, "", fmt.Errorf("secret required but no secret with id %q found", id) + return secretMountOrEnv{}, fmt.Errorf("secret required but no secret with id %q found", id) } - return nil, "", nil + return rv, nil } - var data []byte - var envFile string + data, err := secr.ResolveValue() + if err != nil { + return secretMountOrEnv{}, err + } + + // if env is set, then we set that + if env != "" { + rv.EnvVariable = env + "=" + string(data) + } + + // if no target needs to be mounted, then return now, we're done + if target == "" { + return rv, nil + } + var ctrFileOnHost string switch secr.SourceType { case "env": - data = []byte(os.Getenv(secr.Source)) tmpFile, err := os.CreateTemp(tmpdir.GetTempDir(), "buildah*") if err != nil { - return nil, "", err + return secretMountOrEnv{}, err } + tmpFile.Close() defer func() { if retErr != nil { os.Remove(tmpFile.Name()) } }() - envFile = tmpFile.Name() + rv.EnvFile = tmpFile.Name() ctrFileOnHost = tmpFile.Name() case "file": containerWorkingDir, err := b.store.ContainerDirectory(b.ContainerID) if err != nil { - return nil, "", err - } - data, err = os.ReadFile(secr.Source) - if err != nil { - return nil, "", err + return secretMountOrEnv{}, err } ctrFileOnHost = filepath.Join(containerWorkingDir, "secrets", digest.FromString(id).Encoded()[:16]) default: - return nil, "", errors.New("invalid source secret type") + return secretMountOrEnv{}, errors.New("invalid source secret type") } // Copy secrets to container working dir (or tmp dir if it's an env), since we need to chmod, // chown and relabel it for the container user and we don't want to mess with the original file if err := os.MkdirAll(filepath.Dir(ctrFileOnHost), 0o755); err != nil { - return nil, "", err + return secretMountOrEnv{}, err } if err := os.WriteFile(ctrFileOnHost, data, 0o644); err != nil { - return nil, "", err + return secretMountOrEnv{}, err } if err := relabel(ctrFileOnHost, b.MountLabel, false); err != nil { - return nil, "", err + return secretMountOrEnv{}, err } hostUID, hostGID, err := util.GetHostIDs(idMaps.uidmap, idMaps.gidmap, uid, gid) if err != nil { - return nil, "", err + return secretMountOrEnv{}, err } if err := os.Lchown(ctrFileOnHost, int(hostUID), int(hostGID)); err != nil { - return nil, "", err + return secretMountOrEnv{}, err } if err := os.Chmod(ctrFileOnHost, os.FileMode(mode)); err != nil { - return nil, "", err + return secretMountOrEnv{}, err } - newMount := specs.Mount{ + rv.Mount = &specs.Mount{ Destination: target, Type: define.TypeBind, Source: ctrFileOnHost, Options: append(define.BindOptions, "rprivate", "ro"), } - return &newMount, envFile, nil + return rv, nil } // getSSHMount parses the --mount type=ssh flag in the Containerfile, checks if there's an ssh source provided, and creates and starts an ssh-agent to be forwarded into the container diff --git a/vendor/github.com/containers/buildah/run_freebsd.go b/vendor/github.com/containers/buildah/run_freebsd.go index 74771a2664f..6d0d57223d3 100644 --- a/vendor/github.com/containers/buildah/run_freebsd.go +++ b/vendor/github.com/containers/buildah/run_freebsd.go @@ -276,10 +276,6 @@ func (b *Builder) Run(command []string, options RunOptions) error { if err != nil { return fmt.Errorf("resolving mountpoints for container %q: %w", b.ContainerID, err) } - if runArtifacts.SSHAuthSock != "" { - sshenv := "SSH_AUTH_SOCK=" + runArtifacts.SSHAuthSock - spec.Process.Env = append(spec.Process.Env, sshenv) - } // following run was called from `buildah run` // and some images were mounted for this run diff --git a/vendor/github.com/containers/buildah/run_linux.go b/vendor/github.com/containers/buildah/run_linux.go index d3b12eede8e..c3dbaf7972a 100644 --- a/vendor/github.com/containers/buildah/run_linux.go +++ b/vendor/github.com/containers/buildah/run_linux.go @@ -513,10 +513,6 @@ rootless=%d if err != nil { return fmt.Errorf("resolving mountpoints for container %q: %w", b.ContainerID, err) } - if runArtifacts.SSHAuthSock != "" { - sshenv := "SSH_AUTH_SOCK=" + runArtifacts.SSHAuthSock - spec.Process.Env = append(spec.Process.Env, sshenv) - } // Create any mount points that we need that aren't already present in // the rootfs. diff --git a/vendor/github.com/containers/buildah/run_unix.go b/vendor/github.com/containers/buildah/run_unix.go index 61e18910c64..f2129aab179 100644 --- a/vendor/github.com/containers/buildah/run_unix.go +++ b/vendor/github.com/containers/buildah/run_unix.go @@ -38,6 +38,6 @@ func DefaultNamespaceOptions() (NamespaceOptions, error) { } // getNetworkInterface creates the network interface -func getNetworkInterface(store storage.Store, cniConfDir, cniPluginPath string) (nettypes.ContainerNetwork, error) { +func getNetworkInterface(store storage.Store) (nettypes.ContainerNetwork, error) { return nil, nil } diff --git a/vendor/github.com/containers/buildah/run_unsupported.go b/vendor/github.com/containers/buildah/run_unsupported.go index 5530a465f46..59e463f9288 100644 --- a/vendor/github.com/containers/buildah/run_unsupported.go +++ b/vendor/github.com/containers/buildah/run_unsupported.go @@ -24,6 +24,6 @@ func DefaultNamespaceOptions() (NamespaceOptions, error) { } // getNetworkInterface creates the network interface -func getNetworkInterface(store storage.Store, cniConfDir, cniPluginPath string) (nettypes.ContainerNetwork, error) { +func getNetworkInterface(store storage.Store) (nettypes.ContainerNetwork, error) { return nil, errors.New("function not supported on non-linux systems") } diff --git a/vendor/github.com/containers/buildah/util.go b/vendor/github.com/containers/buildah/util.go index 10cd6f597e0..5bb77f386b3 100644 --- a/vendor/github.com/containers/buildah/util.go +++ b/vendor/github.com/containers/buildah/util.go @@ -94,17 +94,17 @@ func convertRuntimeIDMaps(UIDMap, GIDMap []rspec.LinuxIDMapping) ([]idtools.IDMa func isRegistryBlocked(registry string, sc *types.SystemContext) (bool, error) { reginfo, err := sysregistriesv2.FindRegistry(sc, registry) if err != nil { - return false, fmt.Errorf("unable to parse the registries configuration (%s): %w", sysregistriesv2.ConfigPath(sc), err) + return false, fmt.Errorf("unable to parse the registries configuration (%s): %w", sysregistriesv2.ConfigurationSourceDescription(sc), err) } if reginfo != nil { if reginfo.Blocked { - logrus.Debugf("registry %q is marked as blocked in registries configuration %q", registry, sysregistriesv2.ConfigPath(sc)) + logrus.Debugf("registry %q is marked as blocked in registries configuration %q", registry, sysregistriesv2.ConfigurationSourceDescription(sc)) } else { - logrus.Debugf("registry %q is not marked as blocked in registries configuration %q", registry, sysregistriesv2.ConfigPath(sc)) + logrus.Debugf("registry %q is not marked as blocked in registries configuration %q", registry, sysregistriesv2.ConfigurationSourceDescription(sc)) } return reginfo.Blocked, nil } - logrus.Debugf("registry %q is not listed in registries configuration %q, assuming it's not blocked", registry, sysregistriesv2.ConfigPath(sc)) + logrus.Debugf("registry %q is not listed in registries configuration %q, assuming it's not blocked", registry, sysregistriesv2.ConfigurationSourceDescription(sc)) return false, nil } diff --git a/vendor/github.com/coreos/go-oidc/v3/oidc/oidc.go b/vendor/github.com/coreos/go-oidc/v3/oidc/oidc.go index f6a7ea8a580..2659518cc48 100644 --- a/vendor/github.com/coreos/go-oidc/v3/oidc/oidc.go +++ b/vendor/github.com/coreos/go-oidc/v3/oidc/oidc.go @@ -162,7 +162,7 @@ var supportedAlgorithms = map[string]bool{ // parsing. // // // Directly fetch the metadata document. -// resp, err := http.Get("https://login.example.com/custom-metadata-path") +// resp, err := http.Get("https://login.example.com/custom-metadata-path") // if err != nil { // // ... // } @@ -267,7 +267,7 @@ func NewProvider(ctx context.Context, issuer string) (*Provider, error) { issuerURL = issuer } if p.Issuer != issuerURL && !skipIssuerValidation { - return nil, fmt.Errorf("oidc: issuer did not match the issuer returned by provider, expected %q got %q", issuer, p.Issuer) + return nil, fmt.Errorf("oidc: issuer URL provided to client (%q) did not match the issuer URL returned by provider (%q)", issuer, p.Issuer) } var algs []string for _, a := range p.Algorithms { diff --git a/vendor/github.com/docker/docker/api/types/blkiodev/blkio.go b/vendor/github.com/docker/docker/api/types/blkiodev/blkio.go deleted file mode 100644 index 931ae10ab1e..00000000000 --- a/vendor/github.com/docker/docker/api/types/blkiodev/blkio.go +++ /dev/null @@ -1,23 +0,0 @@ -package blkiodev - -import "fmt" - -// WeightDevice is a structure that holds device:weight pair -type WeightDevice struct { - Path string - Weight uint16 -} - -func (w *WeightDevice) String() string { - return fmt.Sprintf("%s:%d", w.Path, w.Weight) -} - -// ThrottleDevice is a structure that holds device:rate_per_second pair -type ThrottleDevice struct { - Path string - Rate uint64 -} - -func (t *ThrottleDevice) String() string { - return fmt.Sprintf("%s:%d", t.Path, t.Rate) -} diff --git a/vendor/github.com/docker/docker/api/types/common/id_response.go b/vendor/github.com/docker/docker/api/types/common/id_response.go deleted file mode 100644 index 22e8c60a48d..00000000000 --- a/vendor/github.com/docker/docker/api/types/common/id_response.go +++ /dev/null @@ -1,13 +0,0 @@ -package common - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// IDResponse Response to an API call that returns just an Id -// swagger:model IDResponse -type IDResponse struct { - - // The id of the newly created object. - // Required: true - ID string `json:"Id"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/change_type.go b/vendor/github.com/docker/docker/api/types/container/change_type.go deleted file mode 100644 index fe8d6d36966..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/change_type.go +++ /dev/null @@ -1,15 +0,0 @@ -package container - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// ChangeType Kind of change -// -// Can be one of: -// -// - `0`: Modified ("C") -// - `1`: Added ("A") -// - `2`: Deleted ("D") -// -// swagger:model ChangeType -type ChangeType uint8 diff --git a/vendor/github.com/docker/docker/api/types/container/change_types.go b/vendor/github.com/docker/docker/api/types/container/change_types.go deleted file mode 100644 index 3a3a83866ec..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/change_types.go +++ /dev/null @@ -1,23 +0,0 @@ -package container - -const ( - // ChangeModify represents the modify operation. - ChangeModify ChangeType = 0 - // ChangeAdd represents the add operation. - ChangeAdd ChangeType = 1 - // ChangeDelete represents the delete operation. - ChangeDelete ChangeType = 2 -) - -func (ct ChangeType) String() string { - switch ct { - case ChangeModify: - return "C" - case ChangeAdd: - return "A" - case ChangeDelete: - return "D" - default: - return "" - } -} diff --git a/vendor/github.com/docker/docker/api/types/container/commit.go b/vendor/github.com/docker/docker/api/types/container/commit.go deleted file mode 100644 index 6fd1b0ead13..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/commit.go +++ /dev/null @@ -1,7 +0,0 @@ -package container - -import "github.com/docker/docker/api/types/common" - -// CommitResponse response for the commit API call, containing the ID of the -// image that was produced. -type CommitResponse = common.IDResponse diff --git a/vendor/github.com/docker/docker/api/types/container/config.go b/vendor/github.com/docker/docker/api/types/container/config.go deleted file mode 100644 index 0555416540b..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/config.go +++ /dev/null @@ -1,73 +0,0 @@ -package container - -import ( - "time" - - "github.com/docker/docker/api/types/strslice" - "github.com/docker/go-connections/nat" - dockerspec "github.com/moby/docker-image-spec/specs-go/v1" -) - -// MinimumDuration puts a minimum on user configured duration. -// This is to prevent API error on time unit. For example, API may -// set 3 as healthcheck interval with intention of 3 seconds, but -// Docker interprets it as 3 nanoseconds. -const MinimumDuration = 1 * time.Millisecond - -// StopOptions holds the options to stop or restart a container. -type StopOptions struct { - // Signal (optional) is the signal to send to the container to (gracefully) - // stop it before forcibly terminating the container with SIGKILL after the - // timeout expires. If not value is set, the default (SIGTERM) is used. - Signal string `json:",omitempty"` - - // Timeout (optional) is the timeout (in seconds) to wait for the container - // to stop gracefully before forcibly terminating it with SIGKILL. - // - // - Use nil to use the default timeout (10 seconds). - // - Use '-1' to wait indefinitely. - // - Use '0' to not wait for the container to exit gracefully, and - // immediately proceeds to forcibly terminating the container. - // - Other positive values are used as timeout (in seconds). - Timeout *int `json:",omitempty"` -} - -// HealthConfig holds configuration settings for the HEALTHCHECK feature. -type HealthConfig = dockerspec.HealthcheckConfig - -// Config contains the configuration data about a container. -// It should hold only portable information about the container. -// Here, "portable" means "independent from the host we are running on". -// Non-portable information *should* appear in HostConfig. -// All fields added to this struct must be marked `omitempty` to keep getting -// predictable hashes from the old `v1Compatibility` configuration. -type Config struct { - Hostname string // Hostname - Domainname string // Domainname - User string // User that will run the command(s) inside the container, also support user:group - AttachStdin bool // Attach the standard input, makes possible user interaction - AttachStdout bool // Attach the standard output - AttachStderr bool // Attach the standard error - ExposedPorts nat.PortSet `json:",omitempty"` // List of exposed ports - Tty bool // Attach standard streams to a tty, including stdin if it is not closed. - OpenStdin bool // Open stdin - StdinOnce bool // If true, close stdin after the 1 attached client disconnects. - Env []string // List of environment variable to set in the container - Cmd strslice.StrSlice // Command to run when starting the container - Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy - ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific). - Image string // Name of the image as it was passed by the operator (e.g. could be symbolic) - Volumes map[string]struct{} // List of volumes (mounts) used for the container - WorkingDir string // Current directory (PWD) in the command will be launched - Entrypoint strslice.StrSlice // Entrypoint to run when starting the container - NetworkDisabled bool `json:",omitempty"` // Is network disabled - // Mac Address of the container. - // - // Deprecated: this field is deprecated since API v1.44. Use EndpointSettings.MacAddress instead. - MacAddress string `json:",omitempty"` - OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile - Labels map[string]string // List of labels set to this container - StopSignal string `json:",omitempty"` // Signal to stop a container - StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container - Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT -} diff --git a/vendor/github.com/docker/docker/api/types/container/container.go b/vendor/github.com/docker/docker/api/types/container/container.go deleted file mode 100644 index a191ca8bdb7..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/container.go +++ /dev/null @@ -1,188 +0,0 @@ -package container - -import ( - "io" - "os" - "time" - - "github.com/docker/docker/api/types/mount" - "github.com/docker/docker/api/types/storage" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" -) - -// ContainerUpdateOKBody OK response to ContainerUpdate operation -// -// Deprecated: use [UpdateResponse]. This alias will be removed in the next release. -type ContainerUpdateOKBody = UpdateResponse - -// ContainerTopOKBody OK response to ContainerTop operation -// -// Deprecated: use [TopResponse]. This alias will be removed in the next release. -type ContainerTopOKBody = TopResponse - -// PruneReport contains the response for Engine API: -// POST "/containers/prune" -type PruneReport struct { - ContainersDeleted []string - SpaceReclaimed uint64 -} - -// PathStat is used to encode the header from -// GET "/containers/{name:.*}/archive" -// "Name" is the file or directory name. -type PathStat struct { - Name string `json:"name"` - Size int64 `json:"size"` - Mode os.FileMode `json:"mode"` - Mtime time.Time `json:"mtime"` - LinkTarget string `json:"linkTarget"` -} - -// CopyToContainerOptions holds information -// about files to copy into a container -type CopyToContainerOptions struct { - AllowOverwriteDirWithFile bool - CopyUIDGID bool -} - -// StatsResponseReader wraps an io.ReadCloser to read (a stream of) stats -// for a container, as produced by the GET "/stats" endpoint. -// -// The OSType field is set to the server's platform to allow -// platform-specific handling of the response. -// -// TODO(thaJeztah): remove this wrapper, and make OSType part of [StatsResponse]. -type StatsResponseReader struct { - Body io.ReadCloser `json:"body"` - OSType string `json:"ostype"` -} - -// MountPoint represents a mount point configuration inside the container. -// This is used for reporting the mountpoints in use by a container. -type MountPoint struct { - // Type is the type of mount, see `Type` definitions in - // github.com/docker/docker/api/types/mount.Type - Type mount.Type `json:",omitempty"` - - // Name is the name reference to the underlying data defined by `Source` - // e.g., the volume name. - Name string `json:",omitempty"` - - // Source is the source location of the mount. - // - // For volumes, this contains the storage location of the volume (within - // `/var/lib/docker/volumes/`). For bind-mounts, and `npipe`, this contains - // the source (host) part of the bind-mount. For `tmpfs` mount points, this - // field is empty. - Source string - - // Destination is the path relative to the container root (`/`) where the - // Source is mounted inside the container. - Destination string - - // Driver is the volume driver used to create the volume (if it is a volume). - Driver string `json:",omitempty"` - - // Mode is a comma separated list of options supplied by the user when - // creating the bind/volume mount. - // - // The default is platform-specific (`"z"` on Linux, empty on Windows). - Mode string - - // RW indicates whether the mount is mounted writable (read-write). - RW bool - - // Propagation describes how mounts are propagated from the host into the - // mount point, and vice-versa. Refer to the Linux kernel documentation - // for details: - // https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt - // - // This field is not used on Windows. - Propagation mount.Propagation -} - -// State stores container's running state -// it's part of ContainerJSONBase and returned by "inspect" command -type State struct { - Status ContainerState // String representation of the container state. Can be one of "created", "running", "paused", "restarting", "removing", "exited", or "dead" - Running bool - Paused bool - Restarting bool - OOMKilled bool - Dead bool - Pid int - ExitCode int - Error string - StartedAt string - FinishedAt string - Health *Health `json:",omitempty"` -} - -// Summary contains response of Engine API: -// GET "/containers/json" -type Summary struct { - ID string `json:"Id"` - Names []string - Image string - ImageID string - ImageManifestDescriptor *ocispec.Descriptor `json:"ImageManifestDescriptor,omitempty"` - Command string - Created int64 - Ports []Port - SizeRw int64 `json:",omitempty"` - SizeRootFs int64 `json:",omitempty"` - Labels map[string]string - State ContainerState - Status string - HostConfig struct { - NetworkMode string `json:",omitempty"` - Annotations map[string]string `json:",omitempty"` - } - NetworkSettings *NetworkSettingsSummary - Mounts []MountPoint -} - -// ContainerJSONBase contains response of Engine API GET "/containers/{name:.*}/json" -// for API version 1.18 and older. -// -// TODO(thaJeztah): combine ContainerJSONBase and InspectResponse into a single struct. -// The split between ContainerJSONBase (ContainerJSONBase) and InspectResponse (InspectResponse) -// was done in commit 6deaa58ba5f051039643cedceee97c8695e2af74 (https://github.com/moby/moby/pull/13675). -// ContainerJSONBase contained all fields for API < 1.19, and InspectResponse -// held fields that were added in API 1.19 and up. Given that the minimum -// supported API version is now 1.24, we no longer use the separate type. -type ContainerJSONBase struct { - ID string `json:"Id"` - Created string - Path string - Args []string - State *State - Image string - ResolvConfPath string - HostnamePath string - HostsPath string - LogPath string - Name string - RestartCount int - Driver string - Platform string - MountLabel string - ProcessLabel string - AppArmorProfile string - ExecIDs []string - HostConfig *HostConfig - GraphDriver storage.DriverData - SizeRw *int64 `json:",omitempty"` - SizeRootFs *int64 `json:",omitempty"` -} - -// InspectResponse is the response for the GET "/containers/{name:.*}/json" -// endpoint. -type InspectResponse struct { - *ContainerJSONBase - Mounts []MountPoint - Config *Config - NetworkSettings *NetworkSettings - // ImageManifestDescriptor is the descriptor of a platform-specific manifest of the image used to create the container. - ImageManifestDescriptor *ocispec.Descriptor `json:"ImageManifestDescriptor,omitempty"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/create_request.go b/vendor/github.com/docker/docker/api/types/container/create_request.go deleted file mode 100644 index e98dd6ad449..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/create_request.go +++ /dev/null @@ -1,13 +0,0 @@ -package container - -import "github.com/docker/docker/api/types/network" - -// CreateRequest is the request message sent to the server for container -// create calls. It is a config wrapper that holds the container [Config] -// (portable) and the corresponding [HostConfig] (non-portable) and -// [network.NetworkingConfig]. -type CreateRequest struct { - *Config - HostConfig *HostConfig `json:"HostConfig,omitempty"` - NetworkingConfig *network.NetworkingConfig `json:"NetworkingConfig,omitempty"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/create_response.go b/vendor/github.com/docker/docker/api/types/container/create_response.go deleted file mode 100644 index aa0e7f7d078..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/create_response.go +++ /dev/null @@ -1,19 +0,0 @@ -package container - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// CreateResponse ContainerCreateResponse -// -// OK response to ContainerCreate operation -// swagger:model CreateResponse -type CreateResponse struct { - - // The ID of the created container - // Required: true - ID string `json:"Id"` - - // Warnings encountered when creating the container - // Required: true - Warnings []string `json:"Warnings"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/disk_usage.go b/vendor/github.com/docker/docker/api/types/container/disk_usage.go deleted file mode 100644 index d77538c2ab5..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/disk_usage.go +++ /dev/null @@ -1,10 +0,0 @@ -package container - -// DiskUsage contains disk usage for containers. -// -// Deprecated: this type is no longer used and will be removed in the next release. -type DiskUsage struct { - TotalSize int64 - Reclaimable int64 - Items []*Summary -} diff --git a/vendor/github.com/docker/docker/api/types/container/errors.go b/vendor/github.com/docker/docker/api/types/container/errors.go deleted file mode 100644 index 32c978037ea..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/errors.go +++ /dev/null @@ -1,9 +0,0 @@ -package container - -type errInvalidParameter struct{ error } - -func (e *errInvalidParameter) InvalidParameter() {} - -func (e *errInvalidParameter) Unwrap() error { - return e.error -} diff --git a/vendor/github.com/docker/docker/api/types/container/exec.go b/vendor/github.com/docker/docker/api/types/container/exec.go deleted file mode 100644 index e455cd27b27..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/exec.go +++ /dev/null @@ -1,53 +0,0 @@ -package container - -import "github.com/docker/docker/api/types/common" - -// ExecCreateResponse is the response for a successful exec-create request. -// It holds the ID of the exec that was created. -// -// TODO(thaJeztah): make this a distinct type. -type ExecCreateResponse = common.IDResponse - -// ExecOptions is a small subset of the Config struct that holds the configuration -// for the exec feature of docker. -type ExecOptions struct { - User string // User that will run the command - Privileged bool // Is the container in privileged mode - Tty bool // Attach standard streams to a tty. - ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width] - AttachStdin bool // Attach the standard input, makes possible user interaction - AttachStderr bool // Attach the standard error - AttachStdout bool // Attach the standard output - DetachKeys string // Escape keys for detach - Env []string // Environment variables - WorkingDir string // Working directory - Cmd []string // Execution commands and args - - // Deprecated: the Detach field is not used, and will be removed in a future release. - Detach bool -} - -// ExecStartOptions is a temp struct used by execStart -// Config fields is part of ExecConfig in runconfig package -type ExecStartOptions struct { - // ExecStart will first check if it's detached - Detach bool - // Check if there's a tty - Tty bool - // Terminal size [height, width], unused if Tty == false - ConsoleSize *[2]uint `json:",omitempty"` -} - -// ExecAttachOptions is a temp struct used by execAttach. -// -// TODO(thaJeztah): make this a separate type; ContainerExecAttach does not use the Detach option, and cannot run detached. -type ExecAttachOptions = ExecStartOptions - -// ExecInspect holds information returned by exec inspect. -type ExecInspect struct { - ExecID string `json:"ID"` - ContainerID string - Running bool - ExitCode int - Pid int -} diff --git a/vendor/github.com/docker/docker/api/types/container/filesystem_change.go b/vendor/github.com/docker/docker/api/types/container/filesystem_change.go deleted file mode 100644 index 9e9c2ad1d58..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/filesystem_change.go +++ /dev/null @@ -1,19 +0,0 @@ -package container - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// FilesystemChange Change in the container's filesystem. -// -// swagger:model FilesystemChange -type FilesystemChange struct { - - // kind - // Required: true - Kind ChangeType `json:"Kind"` - - // Path to file or directory that has changed. - // - // Required: true - Path string `json:"Path"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/health.go b/vendor/github.com/docker/docker/api/types/container/health.go deleted file mode 100644 index 96e91cc8d8a..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/health.go +++ /dev/null @@ -1,50 +0,0 @@ -package container - -import ( - "fmt" - "strings" - "time" -) - -// HealthStatus is a string representation of the container's health. -// -// It currently is an alias for string, but may become a distinct type in future. -type HealthStatus = string - -// Health states -const ( - NoHealthcheck HealthStatus = "none" // Indicates there is no healthcheck - Starting HealthStatus = "starting" // Starting indicates that the container is not yet ready - Healthy HealthStatus = "healthy" // Healthy indicates that the container is running correctly - Unhealthy HealthStatus = "unhealthy" // Unhealthy indicates that the container has a problem -) - -// Health stores information about the container's healthcheck results -type Health struct { - Status HealthStatus // Status is one of [Starting], [Healthy] or [Unhealthy]. - FailingStreak int // FailingStreak is the number of consecutive failures - Log []*HealthcheckResult // Log contains the last few results (oldest first) -} - -// HealthcheckResult stores information about a single run of a healthcheck probe -type HealthcheckResult struct { - Start time.Time // Start is the time this check started - End time.Time // End is the time this check ended - ExitCode int // ExitCode meanings: 0=healthy, 1=unhealthy, 2=reserved (considered unhealthy), else=error running probe - Output string // Output from last check -} - -var validHealths = []string{ - NoHealthcheck, Starting, Healthy, Unhealthy, -} - -// ValidateHealthStatus checks if the provided string is a valid -// container [HealthStatus]. -func ValidateHealthStatus(s HealthStatus) error { - switch s { - case NoHealthcheck, Starting, Healthy, Unhealthy: - return nil - default: - return errInvalidParameter{error: fmt.Errorf("invalid value for health (%s): must be one of %s", s, strings.Join(validHealths, ", "))} - } -} diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig.go b/vendor/github.com/docker/docker/api/types/container/hostconfig.go deleted file mode 100644 index 7a41436cc70..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/hostconfig.go +++ /dev/null @@ -1,506 +0,0 @@ -package container - -import ( - "errors" - "fmt" - "strings" - - "github.com/docker/docker/api/types/blkiodev" - "github.com/docker/docker/api/types/mount" - "github.com/docker/docker/api/types/network" - "github.com/docker/docker/api/types/strslice" - "github.com/docker/go-connections/nat" - "github.com/docker/go-units" -) - -// CgroupnsMode represents the cgroup namespace mode of the container -type CgroupnsMode string - -// cgroup namespace modes for containers -const ( - CgroupnsModeEmpty CgroupnsMode = "" - CgroupnsModePrivate CgroupnsMode = "private" - CgroupnsModeHost CgroupnsMode = "host" -) - -// IsPrivate indicates whether the container uses its own private cgroup namespace -func (c CgroupnsMode) IsPrivate() bool { - return c == CgroupnsModePrivate -} - -// IsHost indicates whether the container shares the host's cgroup namespace -func (c CgroupnsMode) IsHost() bool { - return c == CgroupnsModeHost -} - -// IsEmpty indicates whether the container cgroup namespace mode is unset -func (c CgroupnsMode) IsEmpty() bool { - return c == CgroupnsModeEmpty -} - -// Valid indicates whether the cgroup namespace mode is valid -func (c CgroupnsMode) Valid() bool { - return c.IsEmpty() || c.IsPrivate() || c.IsHost() -} - -// Isolation represents the isolation technology of a container. The supported -// values are platform specific -type Isolation string - -// Isolation modes for containers -const ( - IsolationEmpty Isolation = "" // IsolationEmpty is unspecified (same behavior as default) - IsolationDefault Isolation = "default" // IsolationDefault is the default isolation mode on current daemon - IsolationProcess Isolation = "process" // IsolationProcess is process isolation mode - IsolationHyperV Isolation = "hyperv" // IsolationHyperV is HyperV isolation mode -) - -// IsDefault indicates the default isolation technology of a container. On Linux this -// is the native driver. On Windows, this is a Windows Server Container. -func (i Isolation) IsDefault() bool { - // TODO consider making isolation-mode strict (case-sensitive) - v := Isolation(strings.ToLower(string(i))) - return v == IsolationDefault || v == IsolationEmpty -} - -// IsHyperV indicates the use of a Hyper-V partition for isolation -func (i Isolation) IsHyperV() bool { - // TODO consider making isolation-mode strict (case-sensitive) - return Isolation(strings.ToLower(string(i))) == IsolationHyperV -} - -// IsProcess indicates the use of process isolation -func (i Isolation) IsProcess() bool { - // TODO consider making isolation-mode strict (case-sensitive) - return Isolation(strings.ToLower(string(i))) == IsolationProcess -} - -// IpcMode represents the container ipc stack. -type IpcMode string - -// IpcMode constants -const ( - IPCModeNone IpcMode = "none" - IPCModeHost IpcMode = "host" - IPCModeContainer IpcMode = "container" - IPCModePrivate IpcMode = "private" - IPCModeShareable IpcMode = "shareable" -) - -// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared. -func (n IpcMode) IsPrivate() bool { - return n == IPCModePrivate -} - -// IsHost indicates whether the container shares the host's ipc namespace. -func (n IpcMode) IsHost() bool { - return n == IPCModeHost -} - -// IsShareable indicates whether the container's ipc namespace can be shared with another container. -func (n IpcMode) IsShareable() bool { - return n == IPCModeShareable -} - -// IsContainer indicates whether the container uses another container's ipc namespace. -func (n IpcMode) IsContainer() bool { - _, ok := containerID(string(n)) - return ok -} - -// IsNone indicates whether container IpcMode is set to "none". -func (n IpcMode) IsNone() bool { - return n == IPCModeNone -} - -// IsEmpty indicates whether container IpcMode is empty -func (n IpcMode) IsEmpty() bool { - return n == "" -} - -// Valid indicates whether the ipc mode is valid. -func (n IpcMode) Valid() bool { - // TODO(thaJeztah): align with PidMode, and consider container-mode without a container name/ID to be invalid. - return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer() -} - -// Container returns the name of the container ipc stack is going to be used. -func (n IpcMode) Container() (idOrName string) { - idOrName, _ = containerID(string(n)) - return idOrName -} - -// NetworkMode represents the container network stack. -type NetworkMode string - -// IsNone indicates whether container isn't using a network stack. -func (n NetworkMode) IsNone() bool { - return n == network.NetworkNone -} - -// IsDefault indicates whether container uses the default network stack. -func (n NetworkMode) IsDefault() bool { - return n == network.NetworkDefault -} - -// IsPrivate indicates whether container uses its private network stack. -func (n NetworkMode) IsPrivate() bool { - return !n.IsHost() && !n.IsContainer() -} - -// IsContainer indicates whether container uses a container network stack. -func (n NetworkMode) IsContainer() bool { - _, ok := containerID(string(n)) - return ok -} - -// ConnectedContainer is the id of the container which network this container is connected to. -func (n NetworkMode) ConnectedContainer() (idOrName string) { - idOrName, _ = containerID(string(n)) - return idOrName -} - -// UserDefined indicates user-created network -func (n NetworkMode) UserDefined() string { - if n.IsUserDefined() { - return string(n) - } - return "" -} - -// UsernsMode represents userns mode in the container. -type UsernsMode string - -// IsHost indicates whether the container uses the host's userns. -func (n UsernsMode) IsHost() bool { - return n == "host" -} - -// IsPrivate indicates whether the container uses the a private userns. -func (n UsernsMode) IsPrivate() bool { - return !n.IsHost() -} - -// Valid indicates whether the userns is valid. -func (n UsernsMode) Valid() bool { - return n == "" || n.IsHost() -} - -// CgroupSpec represents the cgroup to use for the container. -type CgroupSpec string - -// IsContainer indicates whether the container is using another container cgroup -func (c CgroupSpec) IsContainer() bool { - _, ok := containerID(string(c)) - return ok -} - -// Valid indicates whether the cgroup spec is valid. -func (c CgroupSpec) Valid() bool { - // TODO(thaJeztah): align with PidMode, and consider container-mode without a container name/ID to be invalid. - return c == "" || c.IsContainer() -} - -// Container returns the ID or name of the container whose cgroup will be used. -func (c CgroupSpec) Container() (idOrName string) { - idOrName, _ = containerID(string(c)) - return idOrName -} - -// UTSMode represents the UTS namespace of the container. -type UTSMode string - -// IsPrivate indicates whether the container uses its private UTS namespace. -func (n UTSMode) IsPrivate() bool { - return !n.IsHost() -} - -// IsHost indicates whether the container uses the host's UTS namespace. -func (n UTSMode) IsHost() bool { - return n == "host" -} - -// Valid indicates whether the UTS namespace is valid. -func (n UTSMode) Valid() bool { - return n == "" || n.IsHost() -} - -// PidMode represents the pid namespace of the container. -type PidMode string - -// IsPrivate indicates whether the container uses its own new pid namespace. -func (n PidMode) IsPrivate() bool { - return !n.IsHost() && !n.IsContainer() -} - -// IsHost indicates whether the container uses the host's pid namespace. -func (n PidMode) IsHost() bool { - return n == "host" -} - -// IsContainer indicates whether the container uses a container's pid namespace. -func (n PidMode) IsContainer() bool { - _, ok := containerID(string(n)) - return ok -} - -// Valid indicates whether the pid namespace is valid. -func (n PidMode) Valid() bool { - return n == "" || n.IsHost() || validContainer(string(n)) -} - -// Container returns the name of the container whose pid namespace is going to be used. -func (n PidMode) Container() (idOrName string) { - idOrName, _ = containerID(string(n)) - return idOrName -} - -// DeviceRequest represents a request for devices from a device driver. -// Used by GPU device drivers. -type DeviceRequest struct { - Driver string // Name of device driver - Count int // Number of devices to request (-1 = All) - DeviceIDs []string // List of device IDs as recognizable by the device driver - Capabilities [][]string // An OR list of AND lists of device capabilities (e.g. "gpu") - Options map[string]string // Options to pass onto the device driver -} - -// DeviceMapping represents the device mapping between the host and the container. -type DeviceMapping struct { - PathOnHost string - PathInContainer string - CgroupPermissions string -} - -// RestartPolicy represents the restart policies of the container. -type RestartPolicy struct { - Name RestartPolicyMode - MaximumRetryCount int -} - -type RestartPolicyMode string - -const ( - RestartPolicyDisabled RestartPolicyMode = "no" - RestartPolicyAlways RestartPolicyMode = "always" - RestartPolicyOnFailure RestartPolicyMode = "on-failure" - RestartPolicyUnlessStopped RestartPolicyMode = "unless-stopped" -) - -// IsNone indicates whether the container has the "no" restart policy. -// This means the container will not automatically restart when exiting. -func (rp *RestartPolicy) IsNone() bool { - return rp.Name == RestartPolicyDisabled || rp.Name == "" -} - -// IsAlways indicates whether the container has the "always" restart policy. -// This means the container will automatically restart regardless of the exit status. -func (rp *RestartPolicy) IsAlways() bool { - return rp.Name == RestartPolicyAlways -} - -// IsOnFailure indicates whether the container has the "on-failure" restart policy. -// This means the container will automatically restart of exiting with a non-zero exit status. -func (rp *RestartPolicy) IsOnFailure() bool { - return rp.Name == RestartPolicyOnFailure -} - -// IsUnlessStopped indicates whether the container has the -// "unless-stopped" restart policy. This means the container will -// automatically restart unless user has put it to stopped state. -func (rp *RestartPolicy) IsUnlessStopped() bool { - return rp.Name == RestartPolicyUnlessStopped -} - -// IsSame compares two RestartPolicy to see if they are the same -func (rp *RestartPolicy) IsSame(tp *RestartPolicy) bool { - return rp.Name == tp.Name && rp.MaximumRetryCount == tp.MaximumRetryCount -} - -// ValidateRestartPolicy validates the given RestartPolicy. -func ValidateRestartPolicy(policy RestartPolicy) error { - switch policy.Name { - case RestartPolicyAlways, RestartPolicyUnlessStopped, RestartPolicyDisabled: - if policy.MaximumRetryCount != 0 { - msg := "invalid restart policy: maximum retry count can only be used with 'on-failure'" - if policy.MaximumRetryCount < 0 { - msg += " and cannot be negative" - } - return &errInvalidParameter{errors.New(msg)} - } - return nil - case RestartPolicyOnFailure: - if policy.MaximumRetryCount < 0 { - return &errInvalidParameter{errors.New("invalid restart policy: maximum retry count cannot be negative")} - } - return nil - case "": - // Versions before v25.0.0 created an empty restart-policy "name" as - // default. Allow an empty name with "any" MaximumRetryCount for - // backward-compatibility. - return nil - default: - return &errInvalidParameter{fmt.Errorf("invalid restart policy: unknown policy '%s'; use one of '%s', '%s', '%s', or '%s'", policy.Name, RestartPolicyDisabled, RestartPolicyAlways, RestartPolicyOnFailure, RestartPolicyUnlessStopped)} - } -} - -// LogMode is a type to define the available modes for logging -// These modes affect how logs are handled when log messages start piling up. -type LogMode string - -// Available logging modes -const ( - LogModeUnset LogMode = "" - LogModeBlocking LogMode = "blocking" - LogModeNonBlock LogMode = "non-blocking" -) - -// LogConfig represents the logging configuration of the container. -type LogConfig struct { - Type string - Config map[string]string -} - -// Ulimit is an alias for [units.Ulimit], which may be moving to a different -// location or become a local type. This alias is to help transitioning. -// -// Users are recommended to use this alias instead of using [units.Ulimit] directly. -type Ulimit = units.Ulimit - -// Resources contains container's resources (cgroups config, ulimits...) -type Resources struct { - // Applicable to all platforms - CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers) - Memory int64 // Memory limit (in bytes) - NanoCPUs int64 `json:"NanoCpus"` // CPU quota in units of 10-9 CPUs. - - // Applicable to UNIX platforms - CgroupParent string // Parent cgroup. - BlkioWeight uint16 // Block IO weight (relative weight vs. other containers) - BlkioWeightDevice []*blkiodev.WeightDevice - BlkioDeviceReadBps []*blkiodev.ThrottleDevice - BlkioDeviceWriteBps []*blkiodev.ThrottleDevice - BlkioDeviceReadIOps []*blkiodev.ThrottleDevice - BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice - CPUPeriod int64 `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period - CPUQuota int64 `json:"CpuQuota"` // CPU CFS (Completely Fair Scheduler) quota - CPURealtimePeriod int64 `json:"CpuRealtimePeriod"` // CPU real-time period - CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime"` // CPU real-time runtime - CpusetCpus string // CpusetCpus 0-2, 0,1 - CpusetMems string // CpusetMems 0-2, 0,1 - Devices []DeviceMapping // List of devices to map inside the container - DeviceCgroupRules []string // List of rule to be added to the device cgroup - DeviceRequests []DeviceRequest // List of device requests for device drivers - - // KernelMemory specifies the kernel memory limit (in bytes) for the container. - // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes. - KernelMemory int64 `json:",omitempty"` - // Hard limit for kernel TCP buffer memory (in bytes). - // - // Deprecated: This field is deprecated and will be removed in the next release. - // Starting with 6.12, the kernel has deprecated kernel memory tcp accounting - // for cgroups v1. - KernelMemoryTCP int64 `json:",omitempty"` // Hard limit for kernel TCP buffer memory (in bytes) - MemoryReservation int64 // Memory soft limit (in bytes) - MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap - MemorySwappiness *int64 // Tuning container memory swappiness behaviour - OomKillDisable *bool // Whether to disable OOM Killer or not - PidsLimit *int64 // Setting PIDs limit for a container; Set `0` or `-1` for unlimited, or `null` to not change. - Ulimits []*Ulimit // List of ulimits to be set in the container - - // Applicable to Windows - CPUCount int64 `json:"CpuCount"` // CPU count - CPUPercent int64 `json:"CpuPercent"` // CPU percent - IOMaximumIOps uint64 // Maximum IOps for the container system drive - IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive -} - -// UpdateConfig holds the mutable attributes of a Container. -// Those attributes can be updated at runtime. -type UpdateConfig struct { - // Contains container's resources (cgroups, ulimits) - Resources - RestartPolicy RestartPolicy -} - -// HostConfig the non-portable Config structure of a container. -// Here, "non-portable" means "dependent of the host we are running on". -// Portable information *should* appear in Config. -type HostConfig struct { - // Applicable to all platforms - Binds []string // List of volume bindings for this container - ContainerIDFile string // File (path) where the containerId is written - LogConfig LogConfig // Configuration of the logs for this container - NetworkMode NetworkMode // Network mode to use for the container - PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host - RestartPolicy RestartPolicy // Restart policy to be used for the container - AutoRemove bool // Automatically remove container when it exits - VolumeDriver string // Name of the volume driver used to mount volumes - VolumesFrom []string // List of volumes to take from other container - ConsoleSize [2]uint // Initial console size (height,width) - Annotations map[string]string `json:",omitempty"` // Arbitrary non-identifying metadata attached to container and provided to the runtime - - // Applicable to UNIX platforms - CapAdd strslice.StrSlice // List of kernel capabilities to add to the container - CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container - CgroupnsMode CgroupnsMode // Cgroup namespace mode to use for the container - DNS []string `json:"Dns"` // List of DNS server to lookup - DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for - DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for - ExtraHosts []string // List of extra hosts - GroupAdd []string // List of additional groups that the container process will run as - IpcMode IpcMode // IPC namespace to use for the container - Cgroup CgroupSpec // Cgroup to use for the container - Links []string // List of links (in the name:alias form) - OomScoreAdj int // Container preference for OOM-killing - PidMode PidMode // PID namespace to use for the container - Privileged bool // Is the container in privileged mode - PublishAllPorts bool // Should docker publish all exposed port for the container - ReadonlyRootfs bool // Is the container root filesystem in read-only - SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux. - StorageOpt map[string]string `json:",omitempty"` // Storage driver options per container. - Tmpfs map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container - UTSMode UTSMode // UTS namespace to use for the container - UsernsMode UsernsMode // The user namespace to use for the container - ShmSize int64 // Total shm memory usage - Sysctls map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container - Runtime string `json:",omitempty"` // Runtime to use with this container - - // Applicable to Windows - Isolation Isolation // Isolation technology of the container (e.g. default, hyperv) - - // Contains container's resources (cgroups, ulimits) - Resources - - // Mounts specs used by the container - Mounts []mount.Mount `json:",omitempty"` - - // MaskedPaths is the list of paths to be masked inside the container (this overrides the default set of paths) - MaskedPaths []string - - // ReadonlyPaths is the list of paths to be set as read-only inside the container (this overrides the default set of paths) - ReadonlyPaths []string - - // Run a custom init inside the container, if null, use the daemon's configured settings - Init *bool `json:",omitempty"` -} - -// containerID splits "container:" values. It returns the container -// ID or name, and whether an ID/name was found. It returns an empty string and -// a "false" if the value does not have a "container:" prefix. Further validation -// of the returned, including checking if the value is empty, should be handled -// by the caller. -func containerID(val string) (idOrName string, ok bool) { - k, v, hasSep := strings.Cut(val, ":") - if !hasSep || k != "container" { - return "", false - } - return v, true -} - -// validContainer checks if the given value is a "container:" mode with -// a non-empty name/ID. -func validContainer(val string) bool { - id, ok := containerID(val) - return ok && id != "" -} diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go b/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go deleted file mode 100644 index cd6a7a9be22..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/hostconfig_unix.go +++ /dev/null @@ -1,45 +0,0 @@ -//go:build !windows - -package container - -import "github.com/docker/docker/api/types/network" - -// IsValid indicates if an isolation technology is valid -func (i Isolation) IsValid() bool { - return i.IsDefault() -} - -// IsBridge indicates whether container uses the bridge network stack -func (n NetworkMode) IsBridge() bool { - return n == network.NetworkBridge -} - -// IsHost indicates whether container uses the host network stack. -func (n NetworkMode) IsHost() bool { - return n == network.NetworkHost -} - -// IsUserDefined indicates user-created network -func (n NetworkMode) IsUserDefined() bool { - return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() -} - -// NetworkName returns the name of the network stack. -func (n NetworkMode) NetworkName() string { - switch { - case n.IsDefault(): - return network.NetworkDefault - case n.IsBridge(): - return network.NetworkBridge - case n.IsHost(): - return network.NetworkHost - case n.IsNone(): - return network.NetworkNone - case n.IsContainer(): - return "container" - case n.IsUserDefined(): - return n.UserDefined() - default: - return "" - } -} diff --git a/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go b/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go deleted file mode 100644 index db63e190d19..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/hostconfig_windows.go +++ /dev/null @@ -1,47 +0,0 @@ -package container - -import "github.com/docker/docker/api/types/network" - -// IsValid indicates if an isolation technology is valid -func (i Isolation) IsValid() bool { - return i.IsDefault() || i.IsHyperV() || i.IsProcess() -} - -// IsBridge indicates whether container uses the bridge network stack -// in windows it is given the name NAT -func (n NetworkMode) IsBridge() bool { - return n == network.NetworkNat -} - -// IsHost indicates whether container uses the host network stack. -// returns false as this is not supported by windows -func (n NetworkMode) IsHost() bool { - return false -} - -// IsUserDefined indicates user-created network -func (n NetworkMode) IsUserDefined() bool { - return !n.IsDefault() && !n.IsNone() && !n.IsBridge() && !n.IsContainer() -} - -// NetworkName returns the name of the network stack. -func (n NetworkMode) NetworkName() string { - switch { - case n.IsDefault(): - return network.NetworkDefault - case n.IsBridge(): - return network.NetworkNat - case n.IsHost(): - // Windows currently doesn't support host network-mode, so - // this would currently never happen.. - return network.NetworkHost - case n.IsNone(): - return network.NetworkNone - case n.IsContainer(): - return "container" - case n.IsUserDefined(): - return n.UserDefined() - default: - return "" - } -} diff --git a/vendor/github.com/docker/docker/api/types/container/network_settings.go b/vendor/github.com/docker/docker/api/types/container/network_settings.go deleted file mode 100644 index 687145f2953..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/network_settings.go +++ /dev/null @@ -1,85 +0,0 @@ -package container - -import ( - "github.com/docker/docker/api/types/network" - "github.com/docker/go-connections/nat" -) - -// NetworkSettings exposes the network settings in the api -type NetworkSettings struct { - NetworkSettingsBase - DefaultNetworkSettings - Networks map[string]*network.EndpointSettings -} - -// NetworkSettingsBase holds networking state for a container when inspecting it. -// -// Deprecated: Most fields in NetworkSettingsBase are deprecated. Fields which aren't deprecated will move to -// NetworkSettings in v29.0, and this struct will be removed. -type NetworkSettingsBase struct { - Bridge string // Deprecated: This field is only set when the daemon is started with the --bridge flag specified. - SandboxID string // SandboxID uniquely represents a container's network stack - SandboxKey string // SandboxKey identifies the sandbox - Ports nat.PortMap // Ports is a collection of PortBinding indexed by Port - - // HairpinMode specifies if hairpin NAT should be enabled on the virtual interface - // - // Deprecated: This field is never set and will be removed in a future release. - HairpinMode bool - // LinkLocalIPv6Address is an IPv6 unicast address using the link-local prefix - // - // Deprecated: This field is never set and will be removed in a future release. - LinkLocalIPv6Address string - // LinkLocalIPv6PrefixLen is the prefix length of an IPv6 unicast address - // - // Deprecated: This field is never set and will be removed in a future release. - LinkLocalIPv6PrefixLen int - SecondaryIPAddresses []network.Address // Deprecated: This field is never set and will be removed in a future release. - SecondaryIPv6Addresses []network.Address // Deprecated: This field is never set and will be removed in a future release. -} - -// DefaultNetworkSettings holds the networking state for the default bridge, if the container is connected to that -// network. -// -// Deprecated: this struct is deprecated since Docker v1.11 and will be removed in v29. You should look for the default -// network in NetworkSettings.Networks instead. -type DefaultNetworkSettings struct { - // EndpointID uniquely represents a service endpoint in a Sandbox - // - // Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead. - EndpointID string - // Gateway holds the gateway address for the network - // - // Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead. - Gateway string - // GlobalIPv6Address holds network's global IPv6 address - // - // Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead. - GlobalIPv6Address string - // GlobalIPv6PrefixLen represents mask length of network's global IPv6 address - // - // Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead. - GlobalIPv6PrefixLen int - // IPAddress holds the IPv4 address for the network - // - // Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead. - IPAddress string - // IPPrefixLen represents mask length of network's IPv4 address - // - // Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead. - IPPrefixLen int - // IPv6Gateway holds gateway address specific for IPv6 - // - // Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead. - IPv6Gateway string - // MacAddress holds the MAC address for the network - // - // Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead. - MacAddress string -} - -// NetworkSettingsSummary provides a summary of container's networks -// in /containers/json -type NetworkSettingsSummary struct { - Networks map[string]*network.EndpointSettings -} diff --git a/vendor/github.com/docker/docker/api/types/container/options.go b/vendor/github.com/docker/docker/api/types/container/options.go deleted file mode 100644 index 7a230057692..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/options.go +++ /dev/null @@ -1,67 +0,0 @@ -package container - -import "github.com/docker/docker/api/types/filters" - -// ResizeOptions holds parameters to resize a TTY. -// It can be used to resize container TTYs and -// exec process TTYs too. -type ResizeOptions struct { - Height uint - Width uint -} - -// AttachOptions holds parameters to attach to a container. -type AttachOptions struct { - Stream bool - Stdin bool - Stdout bool - Stderr bool - DetachKeys string - Logs bool -} - -// CommitOptions holds parameters to commit changes into a container. -type CommitOptions struct { - Reference string - Comment string - Author string - Changes []string - Pause bool - Config *Config -} - -// RemoveOptions holds parameters to remove containers. -type RemoveOptions struct { - RemoveVolumes bool - RemoveLinks bool - Force bool -} - -// StartOptions holds parameters to start containers. -type StartOptions struct { - CheckpointID string - CheckpointDir string -} - -// ListOptions holds parameters to list containers with. -type ListOptions struct { - Size bool - All bool - Latest bool - Since string - Before string - Limit int - Filters filters.Args -} - -// LogsOptions holds parameters to filter logs with. -type LogsOptions struct { - ShowStdout bool - ShowStderr bool - Since string - Until string - Timestamps bool - Follow bool - Tail string - Details bool -} diff --git a/vendor/github.com/docker/docker/api/types/container/port.go b/vendor/github.com/docker/docker/api/types/container/port.go deleted file mode 100644 index 895043cfe94..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/port.go +++ /dev/null @@ -1,23 +0,0 @@ -package container - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// Port An open port on a container -// swagger:model Port -type Port struct { - - // Host IP address that the container's port is mapped to - IP string `json:"IP,omitempty"` - - // Port on the container - // Required: true - PrivatePort uint16 `json:"PrivatePort"` - - // Port exposed on the host - PublicPort uint16 `json:"PublicPort,omitempty"` - - // type - // Required: true - Type string `json:"Type"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/state.go b/vendor/github.com/docker/docker/api/types/container/state.go deleted file mode 100644 index 78d5c4fe85c..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/state.go +++ /dev/null @@ -1,64 +0,0 @@ -package container - -import ( - "fmt" - "strings" -) - -// ContainerState is a string representation of the container's current state. -// -// It currently is an alias for string, but may become a distinct type in the future. -type ContainerState = string - -const ( - StateCreated ContainerState = "created" // StateCreated indicates the container is created, but not (yet) started. - StateRunning ContainerState = "running" // StateRunning indicates that the container is running. - StatePaused ContainerState = "paused" // StatePaused indicates that the container's current state is paused. - StateRestarting ContainerState = "restarting" // StateRestarting indicates that the container is currently restarting. - StateRemoving ContainerState = "removing" // StateRemoving indicates that the container is being removed. - StateExited ContainerState = "exited" // StateExited indicates that the container exited. - StateDead ContainerState = "dead" // StateDead indicates that the container failed to be deleted. Containers in this state are attempted to be cleaned up when the daemon restarts. -) - -var validStates = []ContainerState{ - StateCreated, StateRunning, StatePaused, StateRestarting, StateRemoving, StateExited, StateDead, -} - -// ValidateContainerState checks if the provided string is a valid -// container [ContainerState]. -func ValidateContainerState(s ContainerState) error { - switch s { - case StateCreated, StateRunning, StatePaused, StateRestarting, StateRemoving, StateExited, StateDead: - return nil - default: - return errInvalidParameter{error: fmt.Errorf("invalid value for state (%s): must be one of %s", s, strings.Join(validStates, ", "))} - } -} - -// StateStatus is used to return container wait results. -// Implements exec.ExitCode interface. -// This type is needed as State include a sync.Mutex field which make -// copying it unsafe. -type StateStatus struct { - exitCode int - err error -} - -// ExitCode returns current exitcode for the state. -func (s StateStatus) ExitCode() int { - return s.exitCode -} - -// Err returns current error for the state. Returns nil if the container had -// exited on its own. -func (s StateStatus) Err() error { - return s.err -} - -// NewStateStatus returns a new StateStatus with the given exit code and error. -func NewStateStatus(exitCode int, err error) StateStatus { - return StateStatus{ - exitCode: exitCode, - err: err, - } -} diff --git a/vendor/github.com/docker/docker/api/types/container/stats.go b/vendor/github.com/docker/docker/api/types/container/stats.go deleted file mode 100644 index 3bfeb4849f9..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/stats.go +++ /dev/null @@ -1,177 +0,0 @@ -package container - -import "time" - -// ThrottlingData stores CPU throttling stats of one running container. -// Not used on Windows. -type ThrottlingData struct { - // Number of periods with throttling active - Periods uint64 `json:"periods"` - // Number of periods when the container hits its throttling limit. - ThrottledPeriods uint64 `json:"throttled_periods"` - // Aggregate time the container was throttled for in nanoseconds. - ThrottledTime uint64 `json:"throttled_time"` -} - -// CPUUsage stores All CPU stats aggregated since container inception. -type CPUUsage struct { - // Total CPU time consumed. - // Units: nanoseconds (Linux) - // Units: 100's of nanoseconds (Windows) - TotalUsage uint64 `json:"total_usage"` - - // Total CPU time consumed per core (Linux). Not used on Windows. - // Units: nanoseconds. - PercpuUsage []uint64 `json:"percpu_usage,omitempty"` - - // Time spent by tasks of the cgroup in kernel mode (Linux). - // Time spent by all container processes in kernel mode (Windows). - // Units: nanoseconds (Linux). - // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers. - UsageInKernelmode uint64 `json:"usage_in_kernelmode"` - - // Time spent by tasks of the cgroup in user mode (Linux). - // Time spent by all container processes in user mode (Windows). - // Units: nanoseconds (Linux). - // Units: 100's of nanoseconds (Windows). Not populated for Hyper-V Containers - UsageInUsermode uint64 `json:"usage_in_usermode"` -} - -// CPUStats aggregates and wraps all CPU related info of container -type CPUStats struct { - // CPU Usage. Linux and Windows. - CPUUsage CPUUsage `json:"cpu_usage"` - - // System Usage. Linux only. - SystemUsage uint64 `json:"system_cpu_usage,omitempty"` - - // Online CPUs. Linux only. - OnlineCPUs uint32 `json:"online_cpus,omitempty"` - - // Throttling Data. Linux only. - ThrottlingData ThrottlingData `json:"throttling_data,omitempty"` -} - -// MemoryStats aggregates all memory stats since container inception on Linux. -// Windows returns stats for commit and private working set only. -type MemoryStats struct { - // Linux Memory Stats - - // current res_counter usage for memory - Usage uint64 `json:"usage,omitempty"` - // maximum usage ever recorded. - MaxUsage uint64 `json:"max_usage,omitempty"` - // TODO(vishh): Export these as stronger types. - // all the stats exported via memory.stat. - Stats map[string]uint64 `json:"stats,omitempty"` - // number of times memory usage hits limits. - Failcnt uint64 `json:"failcnt,omitempty"` - Limit uint64 `json:"limit,omitempty"` - - // Windows Memory Stats - // See https://technet.microsoft.com/en-us/magazine/ff382715.aspx - - // committed bytes - Commit uint64 `json:"commitbytes,omitempty"` - // peak committed bytes - CommitPeak uint64 `json:"commitpeakbytes,omitempty"` - // private working set - PrivateWorkingSet uint64 `json:"privateworkingset,omitempty"` -} - -// BlkioStatEntry is one small entity to store a piece of Blkio stats -// Not used on Windows. -type BlkioStatEntry struct { - Major uint64 `json:"major"` - Minor uint64 `json:"minor"` - Op string `json:"op"` - Value uint64 `json:"value"` -} - -// BlkioStats stores All IO service stats for data read and write. -// This is a Linux specific structure as the differences between expressing -// block I/O on Windows and Linux are sufficiently significant to make -// little sense attempting to morph into a combined structure. -type BlkioStats struct { - // number of bytes transferred to and from the block device - IoServiceBytesRecursive []BlkioStatEntry `json:"io_service_bytes_recursive"` - IoServicedRecursive []BlkioStatEntry `json:"io_serviced_recursive"` - IoQueuedRecursive []BlkioStatEntry `json:"io_queue_recursive"` - IoServiceTimeRecursive []BlkioStatEntry `json:"io_service_time_recursive"` - IoWaitTimeRecursive []BlkioStatEntry `json:"io_wait_time_recursive"` - IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive"` - IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive"` - SectorsRecursive []BlkioStatEntry `json:"sectors_recursive"` -} - -// StorageStats is the disk I/O stats for read/write on Windows. -type StorageStats struct { - ReadCountNormalized uint64 `json:"read_count_normalized,omitempty"` - ReadSizeBytes uint64 `json:"read_size_bytes,omitempty"` - WriteCountNormalized uint64 `json:"write_count_normalized,omitempty"` - WriteSizeBytes uint64 `json:"write_size_bytes,omitempty"` -} - -// NetworkStats aggregates the network stats of one container -type NetworkStats struct { - // Bytes received. Windows and Linux. - RxBytes uint64 `json:"rx_bytes"` - // Packets received. Windows and Linux. - RxPackets uint64 `json:"rx_packets"` - // Received errors. Not used on Windows. Note that we don't `omitempty` this - // field as it is expected in the >=v1.21 API stats structure. - RxErrors uint64 `json:"rx_errors"` - // Incoming packets dropped. Windows and Linux. - RxDropped uint64 `json:"rx_dropped"` - // Bytes sent. Windows and Linux. - TxBytes uint64 `json:"tx_bytes"` - // Packets sent. Windows and Linux. - TxPackets uint64 `json:"tx_packets"` - // Sent errors. Not used on Windows. Note that we don't `omitempty` this - // field as it is expected in the >=v1.21 API stats structure. - TxErrors uint64 `json:"tx_errors"` - // Outgoing packets dropped. Windows and Linux. - TxDropped uint64 `json:"tx_dropped"` - // Endpoint ID. Not used on Linux. - EndpointID string `json:"endpoint_id,omitempty"` - // Instance ID. Not used on Linux. - InstanceID string `json:"instance_id,omitempty"` -} - -// PidsStats contains the stats of a container's pids -type PidsStats struct { - // Current is the number of pids in the cgroup - Current uint64 `json:"current,omitempty"` - // Limit is the hard limit on the number of pids in the cgroup. - // A "Limit" of 0 means that there is no limit. - Limit uint64 `json:"limit,omitempty"` -} - -// Stats is Ultimate struct aggregating all types of stats of one container -// -// Deprecated: use [StatsResponse] instead. This type will be removed in the next release. -type Stats = StatsResponse - -// StatsResponse aggregates all types of stats of one container. -type StatsResponse struct { - Name string `json:"name,omitempty"` - ID string `json:"id,omitempty"` - - // Common stats - Read time.Time `json:"read"` - PreRead time.Time `json:"preread"` - - // Linux specific stats, not populated on Windows. - PidsStats PidsStats `json:"pids_stats,omitempty"` - BlkioStats BlkioStats `json:"blkio_stats,omitempty"` - - // Windows specific stats, not populated on Linux. - NumProcs uint32 `json:"num_procs"` - StorageStats StorageStats `json:"storage_stats,omitempty"` - - // Shared stats - CPUStats CPUStats `json:"cpu_stats,omitempty"` - PreCPUStats CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous" - MemoryStats MemoryStats `json:"memory_stats,omitempty"` - Networks map[string]NetworkStats `json:"networks,omitempty"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/top_response.go b/vendor/github.com/docker/docker/api/types/container/top_response.go deleted file mode 100644 index b4bae5ef036..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/top_response.go +++ /dev/null @@ -1,18 +0,0 @@ -package container - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// TopResponse ContainerTopResponse -// -// Container "top" response. -// swagger:model TopResponse -type TopResponse struct { - - // Each process running in the container, where each process - // is an array of values corresponding to the titles. - Processes [][]string `json:"Processes"` - - // The ps column titles - Titles []string `json:"Titles"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/update_response.go b/vendor/github.com/docker/docker/api/types/container/update_response.go deleted file mode 100644 index e2b5bf5ac0e..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/update_response.go +++ /dev/null @@ -1,14 +0,0 @@ -package container - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// UpdateResponse ContainerUpdateResponse -// -// Response for a successful container-update. -// swagger:model UpdateResponse -type UpdateResponse struct { - - // Warnings encountered when updating the container. - Warnings []string `json:"Warnings"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/wait_exit_error.go b/vendor/github.com/docker/docker/api/types/container/wait_exit_error.go deleted file mode 100644 index ab56d4eed8e..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/wait_exit_error.go +++ /dev/null @@ -1,12 +0,0 @@ -package container - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// WaitExitError container waiting error, if any -// swagger:model WaitExitError -type WaitExitError struct { - - // Details of an error - Message string `json:"Message,omitempty"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/wait_response.go b/vendor/github.com/docker/docker/api/types/container/wait_response.go deleted file mode 100644 index 84fc6afddc6..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/wait_response.go +++ /dev/null @@ -1,18 +0,0 @@ -package container - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// WaitResponse ContainerWaitResponse -// -// OK response to ContainerWait operation -// swagger:model WaitResponse -type WaitResponse struct { - - // error - Error *WaitExitError `json:"Error,omitempty"` - - // Exit code of the container - // Required: true - StatusCode int64 `json:"StatusCode"` -} diff --git a/vendor/github.com/docker/docker/api/types/container/waitcondition.go b/vendor/github.com/docker/docker/api/types/container/waitcondition.go deleted file mode 100644 index 64820fe3583..00000000000 --- a/vendor/github.com/docker/docker/api/types/container/waitcondition.go +++ /dev/null @@ -1,22 +0,0 @@ -package container - -// WaitCondition is a type used to specify a container state for which -// to wait. -type WaitCondition string - -// Possible WaitCondition Values. -// -// WaitConditionNotRunning (default) is used to wait for any of the non-running -// states: "created", "exited", "dead", "removing", or "removed". -// -// WaitConditionNextExit is used to wait for the next time the state changes -// to a non-running state. If the state is currently "created" or "exited", -// this would cause Wait() to block until either the container runs and exits -// or is removed. -// -// WaitConditionRemoved is used to wait for the container to be removed. -const ( - WaitConditionNotRunning WaitCondition = "not-running" - WaitConditionNextExit WaitCondition = "next-exit" - WaitConditionRemoved WaitCondition = "removed" -) diff --git a/vendor/github.com/docker/docker/api/types/filters/errors.go b/vendor/github.com/docker/docker/api/types/filters/errors.go deleted file mode 100644 index b8a690d67ab..00000000000 --- a/vendor/github.com/docker/docker/api/types/filters/errors.go +++ /dev/null @@ -1,24 +0,0 @@ -package filters - -import "fmt" - -// invalidFilter indicates that the provided filter or its value is invalid -type invalidFilter struct { - Filter string - Value []string -} - -func (e invalidFilter) Error() string { - msg := "invalid filter" - if e.Filter != "" { - msg += " '" + e.Filter - if e.Value != nil { - msg = fmt.Sprintf("%s=%s", msg, e.Value) - } - msg += "'" - } - return msg -} - -// InvalidParameter marks this error as ErrInvalidParameter -func (e invalidFilter) InvalidParameter() {} diff --git a/vendor/github.com/docker/docker/api/types/filters/filters_deprecated.go b/vendor/github.com/docker/docker/api/types/filters/filters_deprecated.go deleted file mode 100644 index 4504cd7a7fe..00000000000 --- a/vendor/github.com/docker/docker/api/types/filters/filters_deprecated.go +++ /dev/null @@ -1,61 +0,0 @@ -package filters - -import ( - "encoding/json" - - "github.com/docker/docker/api/types/versions" -) - -// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22 -// then the encoded format will use an older legacy format where the values are a -// list of strings, instead of a set. -// -// Deprecated: do not use in any new code; use ToJSON instead -func ToParamWithVersion(version string, a Args) (string, error) { - out, err := ToJSON(a) - if out == "" || err != nil { - return "", nil - } - if version != "" && versions.LessThan(version, "1.22") { - return encodeLegacyFilters(out) - } - return out, nil -} - -// encodeLegacyFilters encodes Args in the legacy format as used in API v1.21 and older. -// where values are a list of strings, instead of a set. -// -// Don't use in any new code; use [filters.ToJSON]] instead. -func encodeLegacyFilters(currentFormat string) (string, error) { - // The Args.fields field is not exported, but used to marshal JSON, - // so we'll marshal to the new format, then unmarshal to get the - // fields, and marshal again. - // - // This is far from optimal, but this code is only used for deprecated - // API versions, so should not be hit commonly. - var argsFields map[string]map[string]bool - err := json.Unmarshal([]byte(currentFormat), &argsFields) - if err != nil { - return "", err - } - - buf, err := json.Marshal(convertArgsToSlice(argsFields)) - if err != nil { - return "", err - } - return string(buf), nil -} - -func convertArgsToSlice(f map[string]map[string]bool) map[string][]string { - m := map[string][]string{} - for k, v := range f { - values := []string{} - for kk := range v { - if v[kk] { - values = append(values, kk) - } - } - m[k] = values - } - return m -} diff --git a/vendor/github.com/docker/docker/api/types/filters/parse.go b/vendor/github.com/docker/docker/api/types/filters/parse.go deleted file mode 100644 index 396657bb192..00000000000 --- a/vendor/github.com/docker/docker/api/types/filters/parse.go +++ /dev/null @@ -1,302 +0,0 @@ -/* -Package filters provides tools for encoding a mapping of keys to a set of -multiple values. -*/ -package filters - -import ( - "encoding/json" - "regexp" - "strings" -) - -// Args stores a mapping of keys to a set of multiple values. -type Args struct { - fields map[string]map[string]bool -} - -// KeyValuePair are used to initialize a new Args -type KeyValuePair struct { - Key string - Value string -} - -// Arg creates a new KeyValuePair for initializing Args -func Arg(key, value string) KeyValuePair { - return KeyValuePair{Key: key, Value: value} -} - -// NewArgs returns a new Args populated with the initial args -func NewArgs(initialArgs ...KeyValuePair) Args { - args := Args{fields: map[string]map[string]bool{}} - for _, arg := range initialArgs { - args.Add(arg.Key, arg.Value) - } - return args -} - -// Keys returns all the keys in list of Args -func (args Args) Keys() []string { - keys := make([]string, 0, len(args.fields)) - for k := range args.fields { - keys = append(keys, k) - } - return keys -} - -// MarshalJSON returns a JSON byte representation of the Args -func (args Args) MarshalJSON() ([]byte, error) { - if len(args.fields) == 0 { - return []byte("{}"), nil - } - return json.Marshal(args.fields) -} - -// ToJSON returns the Args as a JSON encoded string -func ToJSON(a Args) (string, error) { - if a.Len() == 0 { - return "", nil - } - buf, err := json.Marshal(a) - return string(buf), err -} - -// FromJSON decodes a JSON encoded string into Args -func FromJSON(p string) (Args, error) { - args := NewArgs() - - if p == "" { - return args, nil - } - - raw := []byte(p) - err := json.Unmarshal(raw, &args) - if err == nil { - return args, nil - } - - // Fallback to parsing arguments in the legacy slice format - deprecated := map[string][]string{} - if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil { - return args, &invalidFilter{} - } - - args.fields = deprecatedArgs(deprecated) - return args, nil -} - -// UnmarshalJSON populates the Args from JSON encode bytes -func (args Args) UnmarshalJSON(raw []byte) error { - return json.Unmarshal(raw, &args.fields) -} - -// Get returns the list of values associated with the key -func (args Args) Get(key string) []string { - values := args.fields[key] - if values == nil { - return make([]string, 0) - } - slice := make([]string, 0, len(values)) - for key := range values { - slice = append(slice, key) - } - return slice -} - -// Add a new value to the set of values -func (args Args) Add(key, value string) { - if _, ok := args.fields[key]; ok { - args.fields[key][value] = true - } else { - args.fields[key] = map[string]bool{value: true} - } -} - -// Del removes a value from the set -func (args Args) Del(key, value string) { - if _, ok := args.fields[key]; ok { - delete(args.fields[key], value) - if len(args.fields[key]) == 0 { - delete(args.fields, key) - } - } -} - -// Len returns the number of keys in the mapping -func (args Args) Len() int { - return len(args.fields) -} - -// MatchKVList returns true if all the pairs in sources exist as key=value -// pairs in the mapping at key, or if there are no values at key. -func (args Args) MatchKVList(key string, sources map[string]string) bool { - fieldValues := args.fields[key] - - // do not filter if there is no filter set or cannot determine filter - if len(fieldValues) == 0 { - return true - } - - if len(sources) == 0 { - return false - } - - for value := range fieldValues { - testK, testV, hasValue := strings.Cut(value, "=") - - v, ok := sources[testK] - if !ok { - return false - } - if hasValue && testV != v { - return false - } - } - - return true -} - -// Match returns true if any of the values at key match the source string -func (args Args) Match(field, source string) bool { - if args.ExactMatch(field, source) { - return true - } - - fieldValues := args.fields[field] - for name2match := range fieldValues { - match, err := regexp.MatchString(name2match, source) - if err != nil { - continue - } - if match { - return true - } - } - return false -} - -// GetBoolOrDefault returns a boolean value of the key if the key is present -// and is interpretable as a boolean value. Otherwise the default value is returned. -// Error is not nil only if the filter values are not valid boolean or are conflicting. -func (args Args) GetBoolOrDefault(key string, defaultValue bool) (bool, error) { - fieldValues, ok := args.fields[key] - if !ok { - return defaultValue, nil - } - - if len(fieldValues) == 0 { - return defaultValue, &invalidFilter{key, nil} - } - - isFalse := fieldValues["0"] || fieldValues["false"] - isTrue := fieldValues["1"] || fieldValues["true"] - if isFalse == isTrue { - // Either no or conflicting truthy/falsy value were provided - return defaultValue, &invalidFilter{key, args.Get(key)} - } - return isTrue, nil -} - -// ExactMatch returns true if the source matches exactly one of the values. -func (args Args) ExactMatch(key, source string) bool { - fieldValues, ok := args.fields[key] - // do not filter if there is no filter set or cannot determine filter - if !ok || len(fieldValues) == 0 { - return true - } - - // try to match full name value to avoid O(N) regular expression matching - return fieldValues[source] -} - -// UniqueExactMatch returns true if there is only one value and the source -// matches exactly the value. -func (args Args) UniqueExactMatch(key, source string) bool { - fieldValues := args.fields[key] - // do not filter if there is no filter set or cannot determine filter - if len(fieldValues) == 0 { - return true - } - if len(args.fields[key]) != 1 { - return false - } - - // try to match full name value to avoid O(N) regular expression matching - return fieldValues[source] -} - -// FuzzyMatch returns true if the source matches exactly one value, or the -// source has one of the values as a prefix. -func (args Args) FuzzyMatch(key, source string) bool { - if args.ExactMatch(key, source) { - return true - } - - fieldValues := args.fields[key] - for prefix := range fieldValues { - if strings.HasPrefix(source, prefix) { - return true - } - } - return false -} - -// Contains returns true if the key exists in the mapping -func (args Args) Contains(field string) bool { - _, ok := args.fields[field] - return ok -} - -// Validate compared the set of accepted keys against the keys in the mapping. -// An error is returned if any mapping keys are not in the accepted set. -func (args Args) Validate(accepted map[string]bool) error { - for name := range args.fields { - if !accepted[name] { - return &invalidFilter{name, nil} - } - } - return nil -} - -// WalkValues iterates over the list of values for a key in the mapping and calls -// op() for each value. If op returns an error the iteration stops and the -// error is returned. -func (args Args) WalkValues(field string, op func(value string) error) error { - if _, ok := args.fields[field]; !ok { - return nil - } - for v := range args.fields[field] { - if err := op(v); err != nil { - return err - } - } - return nil -} - -// Clone returns a copy of args. -func (args Args) Clone() (newArgs Args) { - newArgs.fields = make(map[string]map[string]bool, len(args.fields)) - for k, m := range args.fields { - var mm map[string]bool - if m != nil { - mm = make(map[string]bool, len(m)) - for kk, v := range m { - mm[kk] = v - } - } - newArgs.fields[k] = mm - } - return newArgs -} - -func deprecatedArgs(d map[string][]string) map[string]map[string]bool { - m := map[string]map[string]bool{} - for k, v := range d { - values := map[string]bool{} - for _, vv := range v { - values[vv] = true - } - m[k] = values - } - return m -} diff --git a/vendor/github.com/docker/docker/api/types/mount/mount.go b/vendor/github.com/docker/docker/api/types/mount/mount.go deleted file mode 100644 index 090d436c626..00000000000 --- a/vendor/github.com/docker/docker/api/types/mount/mount.go +++ /dev/null @@ -1,157 +0,0 @@ -package mount - -import ( - "os" -) - -// Type represents the type of a mount. -type Type string - -// Type constants -const ( - // TypeBind is the type for mounting host dir - TypeBind Type = "bind" - // TypeVolume is the type for remote storage volumes - TypeVolume Type = "volume" - // TypeTmpfs is the type for mounting tmpfs - TypeTmpfs Type = "tmpfs" - // TypeNamedPipe is the type for mounting Windows named pipes - TypeNamedPipe Type = "npipe" - // TypeCluster is the type for Swarm Cluster Volumes. - TypeCluster Type = "cluster" - // TypeImage is the type for mounting another image's filesystem - TypeImage Type = "image" -) - -// Mount represents a mount (volume). -type Mount struct { - Type Type `json:",omitempty"` - // Source specifies the name of the mount. Depending on mount type, this - // may be a volume name or a host path, or even ignored. - // Source is not supported for tmpfs (must be an empty value) - Source string `json:",omitempty"` - Target string `json:",omitempty"` - ReadOnly bool `json:",omitempty"` // attempts recursive read-only if possible - Consistency Consistency `json:",omitempty"` - - BindOptions *BindOptions `json:",omitempty"` - VolumeOptions *VolumeOptions `json:",omitempty"` - ImageOptions *ImageOptions `json:",omitempty"` - TmpfsOptions *TmpfsOptions `json:",omitempty"` - ClusterOptions *ClusterOptions `json:",omitempty"` -} - -// Propagation represents the propagation of a mount. -type Propagation string - -const ( - // PropagationRPrivate RPRIVATE - PropagationRPrivate Propagation = "rprivate" - // PropagationPrivate PRIVATE - PropagationPrivate Propagation = "private" - // PropagationRShared RSHARED - PropagationRShared Propagation = "rshared" - // PropagationShared SHARED - PropagationShared Propagation = "shared" - // PropagationRSlave RSLAVE - PropagationRSlave Propagation = "rslave" - // PropagationSlave SLAVE - PropagationSlave Propagation = "slave" -) - -// Propagations is the list of all valid mount propagations -var Propagations = []Propagation{ - PropagationRPrivate, - PropagationPrivate, - PropagationRShared, - PropagationShared, - PropagationRSlave, - PropagationSlave, -} - -// Consistency represents the consistency requirements of a mount. -type Consistency string - -const ( - // ConsistencyFull guarantees bind mount-like consistency - ConsistencyFull Consistency = "consistent" - // ConsistencyCached mounts can cache read data and FS structure - ConsistencyCached Consistency = "cached" - // ConsistencyDelegated mounts can cache read and written data and structure - ConsistencyDelegated Consistency = "delegated" - // ConsistencyDefault provides "consistent" behavior unless overridden - ConsistencyDefault Consistency = "default" -) - -// BindOptions defines options specific to mounts of type "bind". -type BindOptions struct { - Propagation Propagation `json:",omitempty"` - NonRecursive bool `json:",omitempty"` - CreateMountpoint bool `json:",omitempty"` - // ReadOnlyNonRecursive makes the mount non-recursively read-only, but still leaves the mount recursive - // (unless NonRecursive is set to true in conjunction). - ReadOnlyNonRecursive bool `json:",omitempty"` - // ReadOnlyForceRecursive raises an error if the mount cannot be made recursively read-only. - ReadOnlyForceRecursive bool `json:",omitempty"` -} - -// VolumeOptions represents the options for a mount of type volume. -type VolumeOptions struct { - NoCopy bool `json:",omitempty"` - Labels map[string]string `json:",omitempty"` - Subpath string `json:",omitempty"` - DriverConfig *Driver `json:",omitempty"` -} - -type ImageOptions struct { - Subpath string `json:",omitempty"` -} - -// Driver represents a volume driver. -type Driver struct { - Name string `json:",omitempty"` - Options map[string]string `json:",omitempty"` -} - -// TmpfsOptions defines options specific to mounts of type "tmpfs". -type TmpfsOptions struct { - // Size sets the size of the tmpfs, in bytes. - // - // This will be converted to an operating system specific value - // depending on the host. For example, on linux, it will be converted to - // use a 'k', 'm' or 'g' syntax. BSD, though not widely supported with - // docker, uses a straight byte value. - // - // Percentages are not supported. - SizeBytes int64 `json:",omitempty"` - // Mode of the tmpfs upon creation - Mode os.FileMode `json:",omitempty"` - // Options to be passed to the tmpfs mount. An array of arrays. Flag - // options should be provided as 1-length arrays. Other types should be - // provided as 2-length arrays, where the first item is the key and the - // second the value. - Options [][]string `json:",omitempty"` - // TODO(stevvooe): There are several more tmpfs flags, specified in the - // daemon, that are accepted. Only the most basic are added for now. - // - // From https://github.com/moby/sys/blob/mount/v0.1.1/mount/flags.go#L47-L56 - // - // var validFlags = map[string]bool{ - // "": true, - // "size": true, X - // "mode": true, X - // "uid": true, - // "gid": true, - // "nr_inodes": true, - // "nr_blocks": true, - // "mpol": true, - // } - // - // Some of these may be straightforward to add, but others, such as - // uid/gid have implications in a clustered system. -} - -// ClusterOptions specifies options for a Cluster volume. -type ClusterOptions struct { - // intentionally empty -} diff --git a/vendor/github.com/docker/docker/api/types/network/create_response.go b/vendor/github.com/docker/docker/api/types/network/create_response.go deleted file mode 100644 index c32b35bff52..00000000000 --- a/vendor/github.com/docker/docker/api/types/network/create_response.go +++ /dev/null @@ -1,19 +0,0 @@ -package network - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// CreateResponse NetworkCreateResponse -// -// OK response to NetworkCreate operation -// swagger:model CreateResponse -type CreateResponse struct { - - // The ID of the created network. - // Required: true - ID string `json:"Id"` - - // Warnings encountered when creating the container - // Required: true - Warning string `json:"Warning"` -} diff --git a/vendor/github.com/docker/docker/api/types/network/endpoint.go b/vendor/github.com/docker/docker/api/types/network/endpoint.go deleted file mode 100644 index cdc06c6c900..00000000000 --- a/vendor/github.com/docker/docker/api/types/network/endpoint.go +++ /dev/null @@ -1,151 +0,0 @@ -package network - -import ( - "errors" - "fmt" - "net" -) - -// EndpointSettings stores the network endpoint details -type EndpointSettings struct { - // Configurations - IPAMConfig *EndpointIPAMConfig - Links []string - Aliases []string // Aliases holds the list of extra, user-specified DNS names for this endpoint. - // MacAddress may be used to specify a MAC address when the container is created. - // Once the container is running, it becomes operational data (it may contain a - // generated address). - MacAddress string - DriverOpts map[string]string - - // GwPriority determines which endpoint will provide the default gateway - // for the container. The endpoint with the highest priority will be used. - // If multiple endpoints have the same priority, they are lexicographically - // sorted based on their network name, and the one that sorts first is picked. - GwPriority int - // Operational data - NetworkID string - EndpointID string - Gateway string - IPAddress string - IPPrefixLen int - IPv6Gateway string - GlobalIPv6Address string - GlobalIPv6PrefixLen int - // DNSNames holds all the (non fully qualified) DNS names associated to this endpoint. First entry is used to - // generate PTR records. - DNSNames []string -} - -// Copy makes a deep copy of `EndpointSettings` -func (es *EndpointSettings) Copy() *EndpointSettings { - epCopy := *es - if es.IPAMConfig != nil { - epCopy.IPAMConfig = es.IPAMConfig.Copy() - } - - if es.Links != nil { - links := make([]string, 0, len(es.Links)) - epCopy.Links = append(links, es.Links...) - } - - if es.Aliases != nil { - aliases := make([]string, 0, len(es.Aliases)) - epCopy.Aliases = append(aliases, es.Aliases...) - } - - if len(es.DNSNames) > 0 { - epCopy.DNSNames = make([]string, len(es.DNSNames)) - copy(epCopy.DNSNames, es.DNSNames) - } - - return &epCopy -} - -// EndpointIPAMConfig represents IPAM configurations for the endpoint -type EndpointIPAMConfig struct { - IPv4Address string `json:",omitempty"` - IPv6Address string `json:",omitempty"` - LinkLocalIPs []string `json:",omitempty"` -} - -// Copy makes a copy of the endpoint ipam config -func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig { - cfgCopy := *cfg - cfgCopy.LinkLocalIPs = make([]string, 0, len(cfg.LinkLocalIPs)) - cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, cfg.LinkLocalIPs...) - return &cfgCopy -} - -// NetworkSubnet describes a user-defined subnet for a specific network. It's only used to validate if an -// EndpointIPAMConfig is valid for a specific network. -type NetworkSubnet interface { - // Contains checks whether the NetworkSubnet contains [addr]. - Contains(addr net.IP) bool - // IsStatic checks whether the subnet was statically allocated (ie. user-defined). - IsStatic() bool -} - -// IsInRange checks whether static IP addresses are valid in a specific network. -func (cfg *EndpointIPAMConfig) IsInRange(v4Subnets []NetworkSubnet, v6Subnets []NetworkSubnet) error { - var errs []error - - if err := validateEndpointIPAddress(cfg.IPv4Address, v4Subnets); err != nil { - errs = append(errs, err) - } - if err := validateEndpointIPAddress(cfg.IPv6Address, v6Subnets); err != nil { - errs = append(errs, err) - } - - return errJoin(errs...) -} - -func validateEndpointIPAddress(epAddr string, ipamSubnets []NetworkSubnet) error { - if epAddr == "" { - return nil - } - - var staticSubnet bool - parsedAddr := net.ParseIP(epAddr) - for _, subnet := range ipamSubnets { - if subnet.IsStatic() { - staticSubnet = true - if subnet.Contains(parsedAddr) { - return nil - } - } - } - - if staticSubnet { - return fmt.Errorf("no configured subnet or ip-range contain the IP address %s", epAddr) - } - - return errors.New("user specified IP address is supported only when connecting to networks with user configured subnets") -} - -// Validate checks whether cfg is valid. -func (cfg *EndpointIPAMConfig) Validate() error { - if cfg == nil { - return nil - } - - var errs []error - - if cfg.IPv4Address != "" { - if addr := net.ParseIP(cfg.IPv4Address); addr == nil || addr.To4() == nil || addr.IsUnspecified() { - errs = append(errs, fmt.Errorf("invalid IPv4 address: %s", cfg.IPv4Address)) - } - } - if cfg.IPv6Address != "" { - if addr := net.ParseIP(cfg.IPv6Address); addr == nil || addr.To4() != nil || addr.IsUnspecified() { - errs = append(errs, fmt.Errorf("invalid IPv6 address: %s", cfg.IPv6Address)) - } - } - for _, addr := range cfg.LinkLocalIPs { - if parsed := net.ParseIP(addr); parsed == nil || parsed.IsUnspecified() { - errs = append(errs, fmt.Errorf("invalid link-local IP address: %s", addr)) - } - } - - return errJoin(errs...) -} diff --git a/vendor/github.com/docker/docker/api/types/network/ipam.go b/vendor/github.com/docker/docker/api/types/network/ipam.go deleted file mode 100644 index f9a9ff9b358..00000000000 --- a/vendor/github.com/docker/docker/api/types/network/ipam.go +++ /dev/null @@ -1,173 +0,0 @@ -package network - -import ( - "errors" - "fmt" - "net/netip" - "strings" -) - -// IPAM represents IP Address Management -type IPAM struct { - Driver string - Options map[string]string // Per network IPAM driver options - Config []IPAMConfig -} - -// IPAMConfig represents IPAM configurations -type IPAMConfig struct { - Subnet string `json:",omitempty"` - IPRange string `json:",omitempty"` - Gateway string `json:",omitempty"` - AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"` -} - -type ipFamily string - -const ( - ip4 ipFamily = "IPv4" - ip6 ipFamily = "IPv6" -) - -// ValidateIPAM checks whether the network's IPAM passed as argument is valid. It returns a joinError of the list of -// errors found. -func ValidateIPAM(ipam *IPAM, enableIPv6 bool) error { - if ipam == nil { - return nil - } - - var errs []error - for _, cfg := range ipam.Config { - subnet, err := netip.ParsePrefix(cfg.Subnet) - if err != nil { - errs = append(errs, fmt.Errorf("invalid subnet %s: invalid CIDR block notation", cfg.Subnet)) - continue - } - subnetFamily := ip4 - if subnet.Addr().Is6() { - subnetFamily = ip6 - } - - if !enableIPv6 && subnetFamily == ip6 { - continue - } - - if subnet != subnet.Masked() { - errs = append(errs, fmt.Errorf("invalid subnet %s: it should be %s", subnet, subnet.Masked())) - } - - if ipRangeErrs := validateIPRange(cfg.IPRange, subnet, subnetFamily); len(ipRangeErrs) > 0 { - errs = append(errs, ipRangeErrs...) - } - - if err := validateAddress(cfg.Gateway, subnet, subnetFamily); err != nil { - errs = append(errs, fmt.Errorf("invalid gateway %s: %w", cfg.Gateway, err)) - } - - for auxName, aux := range cfg.AuxAddress { - if err := validateAddress(aux, subnet, subnetFamily); err != nil { - errs = append(errs, fmt.Errorf("invalid auxiliary address %s: %w", auxName, err)) - } - } - } - - if err := errJoin(errs...); err != nil { - return fmt.Errorf("invalid network config:\n%w", err) - } - - return nil -} - -func validateIPRange(ipRange string, subnet netip.Prefix, subnetFamily ipFamily) []error { - if ipRange == "" { - return nil - } - prefix, err := netip.ParsePrefix(ipRange) - if err != nil { - return []error{fmt.Errorf("invalid ip-range %s: invalid CIDR block notation", ipRange)} - } - family := ip4 - if prefix.Addr().Is6() { - family = ip6 - } - - if family != subnetFamily { - return []error{fmt.Errorf("invalid ip-range %s: parent subnet is an %s block", ipRange, subnetFamily)} - } - - var errs []error - if prefix.Bits() < subnet.Bits() { - errs = append(errs, fmt.Errorf("invalid ip-range %s: CIDR block is bigger than its parent subnet %s", ipRange, subnet)) - } - if prefix != prefix.Masked() { - errs = append(errs, fmt.Errorf("invalid ip-range %s: it should be %s", prefix, prefix.Masked())) - } - if !subnet.Overlaps(prefix) { - errs = append(errs, fmt.Errorf("invalid ip-range %s: parent subnet %s doesn't contain ip-range", ipRange, subnet)) - } - - return errs -} - -func validateAddress(address string, subnet netip.Prefix, subnetFamily ipFamily) error { - if address == "" { - return nil - } - addr, err := netip.ParseAddr(address) - if err != nil { - return errors.New("invalid address") - } - family := ip4 - if addr.Is6() { - family = ip6 - } - - if family != subnetFamily { - return fmt.Errorf("parent subnet is an %s block", subnetFamily) - } - if !subnet.Contains(addr) { - return fmt.Errorf("parent subnet %s doesn't contain this address", subnet) - } - - return nil -} - -func errJoin(errs ...error) error { - n := 0 - for _, err := range errs { - if err != nil { - n++ - } - } - if n == 0 { - return nil - } - e := &joinError{ - errs: make([]error, 0, n), - } - for _, err := range errs { - if err != nil { - e.errs = append(e.errs, err) - } - } - return e -} - -type joinError struct { - errs []error -} - -func (e *joinError) Error() string { - if len(e.errs) == 1 { - return strings.TrimSpace(e.errs[0].Error()) - } - stringErrs := make([]string, 0, len(e.errs)) - for _, subErr := range e.errs { - stringErrs = append(stringErrs, strings.ReplaceAll(subErr.Error(), "\n", "\n\t")) - } - return "* " + strings.Join(stringErrs, "\n* ") -} - -func (e *joinError) Unwrap() []error { - return e.errs -} diff --git a/vendor/github.com/docker/docker/api/types/network/network.go b/vendor/github.com/docker/docker/api/types/network/network.go deleted file mode 100644 index 4a0cb479848..00000000000 --- a/vendor/github.com/docker/docker/api/types/network/network.go +++ /dev/null @@ -1,168 +0,0 @@ -package network - -import ( - "time" - - "github.com/docker/docker/api/types/filters" -) - -const ( - // NetworkDefault is a platform-independent alias to choose the platform-specific default network stack. - NetworkDefault = "default" - // NetworkHost is the name of the predefined network used when the NetworkMode host is selected (only available on Linux) - NetworkHost = "host" - // NetworkNone is the name of the predefined network used when the NetworkMode none is selected (available on both Linux and Windows) - NetworkNone = "none" - // NetworkBridge is the name of the default network on Linux - NetworkBridge = "bridge" - // NetworkNat is the name of the default network on Windows - NetworkNat = "nat" -) - -// CreateRequest is the request message sent to the server for network create call. -type CreateRequest struct { - CreateOptions - Name string // Name is the requested name of the network. - - // Deprecated: CheckDuplicate is deprecated since API v1.44, but it defaults to true when sent by the client - // package to older daemons. - CheckDuplicate *bool `json:",omitempty"` -} - -// CreateOptions holds options to create a network. -type CreateOptions struct { - Driver string // Driver is the driver-name used to create the network (e.g. `bridge`, `overlay`) - Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level). - EnableIPv4 *bool `json:",omitempty"` // EnableIPv4 represents whether to enable IPv4. - EnableIPv6 *bool `json:",omitempty"` // EnableIPv6 represents whether to enable IPv6. - IPAM *IPAM // IPAM is the network's IP Address Management. - Internal bool // Internal represents if the network is used internal only. - Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. - Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. - ConfigOnly bool // ConfigOnly creates a config-only network. Config-only networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services. - ConfigFrom *ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. The specified network must be a config-only network; see [CreateOptions.ConfigOnly]. - Options map[string]string // Options specifies the network-specific options to use for when creating the network. - Labels map[string]string // Labels holds metadata specific to the network being created. -} - -// ListOptions holds parameters to filter the list of networks with. -type ListOptions struct { - Filters filters.Args -} - -// InspectOptions holds parameters to inspect network. -type InspectOptions struct { - Scope string - Verbose bool -} - -// ConnectOptions represents the data to be used to connect a container to the -// network. -type ConnectOptions struct { - Container string - EndpointConfig *EndpointSettings `json:",omitempty"` -} - -// DisconnectOptions represents the data to be used to disconnect a container -// from the network. -type DisconnectOptions struct { - Container string - Force bool -} - -// Inspect is the body of the "get network" http response message. -type Inspect struct { - Name string // Name is the name of the network - ID string `json:"Id"` // ID uniquely identifies a network on a single machine - Created time.Time // Created is the time the network created - Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level) - Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`) - EnableIPv4 bool // EnableIPv4 represents whether IPv4 is enabled - EnableIPv6 bool // EnableIPv6 represents whether IPv6 is enabled - IPAM IPAM // IPAM is the network's IP Address Management - Internal bool // Internal represents if the network is used internal only - Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode. - Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster. - ConfigFrom ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. - ConfigOnly bool // ConfigOnly networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services. - Containers map[string]EndpointResource // Containers contains endpoints belonging to the network - Options map[string]string // Options holds the network specific options to use for when creating the network - Labels map[string]string // Labels holds metadata specific to the network being created - Peers []PeerInfo `json:",omitempty"` // List of peer nodes for an overlay network - Services map[string]ServiceInfo `json:",omitempty"` -} - -// Summary is used as response when listing networks. It currently is an alias -// for [Inspect], but may diverge in the future, as not all information may -// be included when listing networks. -type Summary = Inspect - -// Address represents an IP address -type Address struct { - Addr string - PrefixLen int -} - -// PeerInfo represents one peer of an overlay network -type PeerInfo struct { - Name string - IP string -} - -// Task carries the information about one backend task -type Task struct { - Name string - EndpointID string - EndpointIP string - Info map[string]string -} - -// ServiceInfo represents service parameters with the list of service's tasks -type ServiceInfo struct { - VIP string - Ports []string - LocalLBIndex int - Tasks []Task -} - -// EndpointResource contains network resources allocated and used for a -// container in a network. -type EndpointResource struct { - Name string - EndpointID string - MacAddress string - IPv4Address string - IPv6Address string -} - -// NetworkingConfig represents the container's networking configuration for each of its interfaces -// Carries the networking configs specified in the `docker run` and `docker network connect` commands -type NetworkingConfig struct { - EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each connecting network -} - -// ConfigReference specifies the source which provides a network's configuration -type ConfigReference struct { - Network string -} - -var acceptedFilters = map[string]bool{ - "dangling": true, - "driver": true, - "id": true, - "label": true, - "name": true, - "scope": true, - "type": true, -} - -// ValidateFilters validates the list of filter args with the available filters. -func ValidateFilters(filter filters.Args) error { - return filter.Validate(acceptedFilters) -} - -// PruneReport contains the response for Engine API: -// POST "/networks/prune" -type PruneReport struct { - NetworksDeleted []string -} diff --git a/vendor/github.com/docker/docker/api/types/registry/authconfig.go b/vendor/github.com/docker/docker/api/types/registry/authconfig.go deleted file mode 100644 index 4c6d7ab2bad..00000000000 --- a/vendor/github.com/docker/docker/api/types/registry/authconfig.go +++ /dev/null @@ -1,112 +0,0 @@ -package registry - -import ( - "context" - "encoding/base64" - "encoding/json" - "fmt" - "io" - "strings" -) - -// AuthHeader is the name of the header used to send encoded registry -// authorization credentials for registry operations (push/pull). -const AuthHeader = "X-Registry-Auth" - -// RequestAuthConfig is a function interface that clients can supply -// to retry operations after getting an authorization error. -// -// The function must return the [AuthHeader] value ([AuthConfig]), encoded -// in base64url format ([RFC4648, section 5]), which can be decoded by -// [DecodeAuthConfig]. -// -// It must return an error if the privilege request fails. -// -// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5 -type RequestAuthConfig func(context.Context) (string, error) - -// AuthConfig contains authorization information for connecting to a Registry. -type AuthConfig struct { - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - Auth string `json:"auth,omitempty"` - - // Email is an optional value associated with the username. - // - // Deprecated: This field is deprecated since docker 1.11 (API v1.23) and will be removed in the next release. - Email string `json:"email,omitempty"` - - ServerAddress string `json:"serveraddress,omitempty"` - - // IdentityToken is used to authenticate the user and get - // an access token for the registry. - IdentityToken string `json:"identitytoken,omitempty"` - - // RegistryToken is a bearer token to be sent to a registry - RegistryToken string `json:"registrytoken,omitempty"` -} - -// EncodeAuthConfig serializes the auth configuration as a base64url encoded -// ([RFC4648, section 5]) JSON string for sending through the X-Registry-Auth header. -// -// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5 -func EncodeAuthConfig(authConfig AuthConfig) (string, error) { - buf, err := json.Marshal(authConfig) - if err != nil { - return "", errInvalidParameter{err} - } - return base64.URLEncoding.EncodeToString(buf), nil -} - -// DecodeAuthConfig decodes base64url encoded ([RFC4648, section 5]) JSON -// authentication information as sent through the X-Registry-Auth header. -// -// This function always returns an [AuthConfig], even if an error occurs. It is up -// to the caller to decide if authentication is required, and if the error can -// be ignored. -// -// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5 -func DecodeAuthConfig(authEncoded string) (*AuthConfig, error) { - if authEncoded == "" { - return &AuthConfig{}, nil - } - - authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded)) - return decodeAuthConfigFromReader(authJSON) -} - -// DecodeAuthConfigBody decodes authentication information as sent as JSON in the -// body of a request. This function is to provide backward compatibility with old -// clients and API versions. Current clients and API versions expect authentication -// to be provided through the X-Registry-Auth header. -// -// Like [DecodeAuthConfig], this function always returns an [AuthConfig], even if an -// error occurs. It is up to the caller to decide if authentication is required, -// and if the error can be ignored. -// -// Deprecated: this function is no longer used and will be removed in the next release. -func DecodeAuthConfigBody(rdr io.ReadCloser) (*AuthConfig, error) { - return decodeAuthConfigFromReader(rdr) -} - -func decodeAuthConfigFromReader(rdr io.Reader) (*AuthConfig, error) { - authConfig := &AuthConfig{} - if err := json.NewDecoder(rdr).Decode(authConfig); err != nil { - // always return an (empty) AuthConfig to increase compatibility with - // the existing API. - return &AuthConfig{}, invalid(err) - } - return authConfig, nil -} - -func invalid(err error) error { - return errInvalidParameter{fmt.Errorf("invalid X-Registry-Auth header: %w", err)} -} - -type errInvalidParameter struct{ error } - -func (errInvalidParameter) InvalidParameter() {} - -func (e errInvalidParameter) Cause() error { return e.error } - -func (e errInvalidParameter) Unwrap() error { return e.error } diff --git a/vendor/github.com/docker/docker/api/types/registry/authenticate.go b/vendor/github.com/docker/docker/api/types/registry/authenticate.go deleted file mode 100644 index 42cac4430a6..00000000000 --- a/vendor/github.com/docker/docker/api/types/registry/authenticate.go +++ /dev/null @@ -1,21 +0,0 @@ -package registry - -// ---------------------------------------------------------------------------- -// DO NOT EDIT THIS FILE -// This file was generated by `swagger generate operation` -// -// See hack/generate-swagger-api.sh -// ---------------------------------------------------------------------------- - -// AuthenticateOKBody authenticate o k body -// swagger:model AuthenticateOKBody -type AuthenticateOKBody struct { - - // An opaque token used to authenticate a user after a successful login - // Required: true - IdentityToken string `json:"IdentityToken"` - - // The status of the authentication - // Required: true - Status string `json:"Status"` -} diff --git a/vendor/github.com/docker/docker/api/types/registry/registry.go b/vendor/github.com/docker/docker/api/types/registry/registry.go deleted file mode 100644 index 9319c964cdb..00000000000 --- a/vendor/github.com/docker/docker/api/types/registry/registry.go +++ /dev/null @@ -1,122 +0,0 @@ -// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: -//go:build go1.23 - -package registry - -import ( - "encoding/json" - "net" - - ocispec "github.com/opencontainers/image-spec/specs-go/v1" -) - -// ServiceConfig stores daemon registry services configuration. -type ServiceConfig struct { - AllowNondistributableArtifactsCIDRs []*NetIPNet `json:"AllowNondistributableArtifactsCIDRs,omitempty"` // Deprecated: non-distributable artifacts are deprecated and enabled by default. This field will be removed in the next release. - AllowNondistributableArtifactsHostnames []string `json:"AllowNondistributableArtifactsHostnames,omitempty"` // Deprecated: non-distributable artifacts are deprecated and enabled by default. This field will be removed in the next release. - - InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"` - IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"` - Mirrors []string - - // ExtraFields is for internal use to include deprecated fields on older API versions. - ExtraFields map[string]any `json:"-"` -} - -// MarshalJSON implements a custom marshaler to include legacy fields -// in API responses. -func (sc *ServiceConfig) MarshalJSON() ([]byte, error) { - type tmp ServiceConfig - base, err := json.Marshal((*tmp)(sc)) - if err != nil { - return nil, err - } - var merged map[string]any - _ = json.Unmarshal(base, &merged) - - for k, v := range sc.ExtraFields { - merged[k] = v - } - return json.Marshal(merged) -} - -// NetIPNet is the net.IPNet type, which can be marshalled and -// unmarshalled to JSON -type NetIPNet net.IPNet - -// String returns the CIDR notation of ipnet -func (ipnet *NetIPNet) String() string { - return (*net.IPNet)(ipnet).String() -} - -// MarshalJSON returns the JSON representation of the IPNet -func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) { - return json.Marshal((*net.IPNet)(ipnet).String()) -} - -// UnmarshalJSON sets the IPNet from a byte array of JSON -func (ipnet *NetIPNet) UnmarshalJSON(b []byte) error { - var ipnetStr string - if err := json.Unmarshal(b, &ipnetStr); err != nil { - return err - } - _, cidr, err := net.ParseCIDR(ipnetStr) - if err != nil { - return err - } - *ipnet = NetIPNet(*cidr) - return nil -} - -// IndexInfo contains information about a registry -// -// RepositoryInfo Examples: -// -// { -// "Index" : { -// "Name" : "docker.io", -// "Mirrors" : ["https://registry-2.docker.io/v1/", "https://registry-3.docker.io/v1/"], -// "Secure" : true, -// "Official" : true, -// }, -// "RemoteName" : "library/debian", -// "LocalName" : "debian", -// "CanonicalName" : "docker.io/debian" -// "Official" : true, -// } -// -// { -// "Index" : { -// "Name" : "127.0.0.1:5000", -// "Mirrors" : [], -// "Secure" : false, -// "Official" : false, -// }, -// "RemoteName" : "user/repo", -// "LocalName" : "127.0.0.1:5000/user/repo", -// "CanonicalName" : "127.0.0.1:5000/user/repo", -// "Official" : false, -// } -type IndexInfo struct { - // Name is the name of the registry, such as "docker.io" - Name string - // Mirrors is a list of mirrors, expressed as URIs - Mirrors []string - // Secure is set to false if the registry is part of the list of - // insecure registries. Insecure registries accept HTTP and/or accept - // HTTPS with certificates from unknown CAs. - Secure bool - // Official indicates whether this is an official registry - Official bool -} - -// DistributionInspect describes the result obtained from contacting the -// registry to retrieve image metadata -type DistributionInspect struct { - // Descriptor contains information about the manifest, including - // the content addressable digest - Descriptor ocispec.Descriptor - // Platforms contains the list of platforms supported by the image, - // obtained by parsing the manifest - Platforms []ocispec.Platform -} diff --git a/vendor/github.com/docker/docker/api/types/registry/search.go b/vendor/github.com/docker/docker/api/types/registry/search.go deleted file mode 100644 index 994ca4c6f96..00000000000 --- a/vendor/github.com/docker/docker/api/types/registry/search.go +++ /dev/null @@ -1,48 +0,0 @@ -package registry - -import ( - "context" - - "github.com/docker/docker/api/types/filters" -) - -// SearchOptions holds parameters to search images with. -type SearchOptions struct { - RegistryAuth string - - // PrivilegeFunc is a function that clients can supply to retry operations - // after getting an authorization error. This function returns the registry - // authentication header value in base64 encoded format, or an error if the - // privilege request fails. - // - // For details, refer to [github.com/docker/docker/api/types/registry.RequestAuthConfig]. - PrivilegeFunc func(context.Context) (string, error) - Filters filters.Args - Limit int -} - -// SearchResult describes a search result returned from a registry -type SearchResult struct { - // StarCount indicates the number of stars this repository has - StarCount int `json:"star_count"` - // IsOfficial is true if the result is from an official repository. - IsOfficial bool `json:"is_official"` - // Name is the name of the repository - Name string `json:"name"` - // IsAutomated indicates whether the result is automated. - // - // Deprecated: the "is_automated" field is deprecated and will always be "false". - IsAutomated bool `json:"is_automated"` - // Description is a textual description of the repository - Description string `json:"description"` -} - -// SearchResults lists a collection search results returned from a registry -type SearchResults struct { - // Query contains the query string that generated the search results - Query string `json:"query"` - // NumResults indicates the number of results the query returned - NumResults int `json:"num_results"` - // Results is a slice containing the actual results for the search - Results []SearchResult `json:"results"` -} diff --git a/vendor/github.com/docker/docker/api/types/storage/driver_data.go b/vendor/github.com/docker/docker/api/types/storage/driver_data.go deleted file mode 100644 index 009e2130950..00000000000 --- a/vendor/github.com/docker/docker/api/types/storage/driver_data.go +++ /dev/null @@ -1,23 +0,0 @@ -package storage - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// DriverData Information about the storage driver used to store the container's and -// image's filesystem. -// -// swagger:model DriverData -type DriverData struct { - - // Low-level storage metadata, provided as key/value pairs. - // - // This information is driver-specific, and depends on the storage-driver - // in use, and should be used for informational purposes only. - // - // Required: true - Data map[string]string `json:"Data"` - - // Name of the storage driver. - // Required: true - Name string `json:"Name"` -} diff --git a/vendor/github.com/docker/docker/api/types/strslice/strslice.go b/vendor/github.com/docker/docker/api/types/strslice/strslice.go deleted file mode 100644 index bad493fb89f..00000000000 --- a/vendor/github.com/docker/docker/api/types/strslice/strslice.go +++ /dev/null @@ -1,30 +0,0 @@ -package strslice - -import "encoding/json" - -// StrSlice represents a string or an array of strings. -// We need to override the json decoder to accept both options. -type StrSlice []string - -// UnmarshalJSON decodes the byte slice whether it's a string or an array of -// strings. This method is needed to implement json.Unmarshaler. -func (e *StrSlice) UnmarshalJSON(b []byte) error { - if len(b) == 0 { - // With no input, we preserve the existing value by returning nil and - // leaving the target alone. This allows defining default values for - // the type. - return nil - } - - p := make([]string, 0, 1) - if err := json.Unmarshal(b, &p); err != nil { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - p = append(p, s) - } - - *e = p - return nil -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/common.go b/vendor/github.com/docker/docker/api/types/swarm/common.go deleted file mode 100644 index b42812e03f1..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/common.go +++ /dev/null @@ -1,48 +0,0 @@ -package swarm - -import ( - "strconv" - "time" -) - -// Version represents the internal object version. -type Version struct { - Index uint64 `json:",omitempty"` -} - -// String implements fmt.Stringer interface. -func (v Version) String() string { - return strconv.FormatUint(v.Index, 10) -} - -// Meta is a base object inherited by most of the other once. -type Meta struct { - Version Version `json:",omitempty"` - CreatedAt time.Time `json:",omitempty"` - UpdatedAt time.Time `json:",omitempty"` -} - -// Annotations represents how to describe an object. -type Annotations struct { - Name string `json:",omitempty"` - Labels map[string]string `json:"Labels"` -} - -// Driver represents a driver (network, logging, secrets backend). -type Driver struct { - Name string `json:",omitempty"` - Options map[string]string `json:",omitempty"` -} - -// TLSInfo represents the TLS information about what CA certificate is trusted, -// and who the issuer for a TLS certificate is -type TLSInfo struct { - // TrustRoot is the trusted CA root certificate in PEM format - TrustRoot string `json:",omitempty"` - - // CertIssuer is the raw subject bytes of the issuer - CertIssuerSubject []byte `json:",omitempty"` - - // CertIssuerPublicKey is the raw public key bytes of the issuer - CertIssuerPublicKey []byte `json:",omitempty"` -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/config.go b/vendor/github.com/docker/docker/api/types/swarm/config.go deleted file mode 100644 index 80a6ffdb9aa..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/config.go +++ /dev/null @@ -1,62 +0,0 @@ -package swarm - -import ( - "os" - - "github.com/docker/docker/api/types/filters" -) - -// Config represents a config. -type Config struct { - ID string - Meta - Spec ConfigSpec -} - -// ConfigSpec represents a config specification from a config in swarm -type ConfigSpec struct { - Annotations - - // Data is the data to store as a config. - // - // The maximum allowed size is 1000KB, as defined in [MaxConfigSize]. - // - // [MaxConfigSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/manager/controlapi#MaxConfigSize - Data []byte `json:",omitempty"` - - // Templating controls whether and how to evaluate the config payload as - // a template. If it is not set, no templating is used. - Templating *Driver `json:",omitempty"` -} - -// ConfigReferenceFileTarget is a file target in a config reference -type ConfigReferenceFileTarget struct { - Name string - UID string - GID string - Mode os.FileMode -} - -// ConfigReferenceRuntimeTarget is a target for a config specifying that it -// isn't mounted into the container but instead has some other purpose. -type ConfigReferenceRuntimeTarget struct{} - -// ConfigReference is a reference to a config in swarm -type ConfigReference struct { - File *ConfigReferenceFileTarget `json:",omitempty"` - Runtime *ConfigReferenceRuntimeTarget `json:",omitempty"` - ConfigID string - ConfigName string -} - -// ConfigCreateResponse contains the information returned to a client -// on the creation of a new config. -type ConfigCreateResponse struct { - // ID is the id of the created config. - ID string -} - -// ConfigListOptions holds parameters to list configs -type ConfigListOptions struct { - Filters filters.Args -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/container.go b/vendor/github.com/docker/docker/api/types/swarm/container.go deleted file mode 100644 index f9416bacca6..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/container.go +++ /dev/null @@ -1,119 +0,0 @@ -package swarm - -import ( - "time" - - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/mount" -) - -// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) -// Detailed documentation is available in: -// http://man7.org/linux/man-pages/man5/resolv.conf.5.html -// `nameserver`, `search`, `options` have been supported. -// TODO: `domain` is not supported yet. -type DNSConfig struct { - // Nameservers specifies the IP addresses of the name servers - Nameservers []string `json:",omitempty"` - // Search specifies the search list for host-name lookup - Search []string `json:",omitempty"` - // Options allows certain internal resolver variables to be modified - Options []string `json:",omitempty"` -} - -// SELinuxContext contains the SELinux labels of the container. -type SELinuxContext struct { - Disable bool - - User string - Role string - Type string - Level string -} - -// SeccompMode is the type used for the enumeration of possible seccomp modes -// in SeccompOpts -type SeccompMode string - -const ( - SeccompModeDefault SeccompMode = "default" - SeccompModeUnconfined SeccompMode = "unconfined" - SeccompModeCustom SeccompMode = "custom" -) - -// SeccompOpts defines the options for configuring seccomp on a swarm-managed -// container. -type SeccompOpts struct { - // Mode is the SeccompMode used for the container. - Mode SeccompMode `json:",omitempty"` - // Profile is the custom seccomp profile as a json object to be used with - // the container. Mode should be set to SeccompModeCustom when using a - // custom profile in this manner. - Profile []byte `json:",omitempty"` -} - -// AppArmorMode is type used for the enumeration of possible AppArmor modes in -// AppArmorOpts -type AppArmorMode string - -const ( - AppArmorModeDefault AppArmorMode = "default" - AppArmorModeDisabled AppArmorMode = "disabled" -) - -// AppArmorOpts defines the options for configuring AppArmor on a swarm-managed -// container. Currently, custom AppArmor profiles are not supported. -type AppArmorOpts struct { - Mode AppArmorMode `json:",omitempty"` -} - -// CredentialSpec for managed service account (Windows only) -type CredentialSpec struct { - Config string - File string - Registry string -} - -// Privileges defines the security options for the container. -type Privileges struct { - CredentialSpec *CredentialSpec - SELinuxContext *SELinuxContext - Seccomp *SeccompOpts `json:",omitempty"` - AppArmor *AppArmorOpts `json:",omitempty"` - NoNewPrivileges bool -} - -// ContainerSpec represents the spec of a container. -type ContainerSpec struct { - Image string `json:",omitempty"` - Labels map[string]string `json:",omitempty"` - Command []string `json:",omitempty"` - Args []string `json:",omitempty"` - Hostname string `json:",omitempty"` - Env []string `json:",omitempty"` - Dir string `json:",omitempty"` - User string `json:",omitempty"` - Groups []string `json:",omitempty"` - Privileges *Privileges `json:",omitempty"` - Init *bool `json:",omitempty"` - StopSignal string `json:",omitempty"` - TTY bool `json:",omitempty"` - OpenStdin bool `json:",omitempty"` - ReadOnly bool `json:",omitempty"` - Mounts []mount.Mount `json:",omitempty"` - StopGracePeriod *time.Duration `json:",omitempty"` - Healthcheck *container.HealthConfig `json:",omitempty"` - // The format of extra hosts on swarmkit is specified in: - // http://man7.org/linux/man-pages/man5/hosts.5.html - // IP_address canonical_hostname [aliases...] - Hosts []string `json:",omitempty"` - DNSConfig *DNSConfig `json:",omitempty"` - Secrets []*SecretReference `json:",omitempty"` - Configs []*ConfigReference `json:",omitempty"` - Isolation container.Isolation `json:",omitempty"` - Sysctls map[string]string `json:",omitempty"` - CapabilityAdd []string `json:",omitempty"` - CapabilityDrop []string `json:",omitempty"` - Ulimits []*container.Ulimit `json:",omitempty"` - OomScoreAdj int64 `json:",omitempty"` -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/network.go b/vendor/github.com/docker/docker/api/types/swarm/network.go deleted file mode 100644 index 4b880723399..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/network.go +++ /dev/null @@ -1,121 +0,0 @@ -package swarm - -import ( - "github.com/docker/docker/api/types/network" -) - -// Endpoint represents an endpoint. -type Endpoint struct { - Spec EndpointSpec `json:",omitempty"` - Ports []PortConfig `json:",omitempty"` - VirtualIPs []EndpointVirtualIP `json:",omitempty"` -} - -// EndpointSpec represents the spec of an endpoint. -type EndpointSpec struct { - Mode ResolutionMode `json:",omitempty"` - Ports []PortConfig `json:",omitempty"` -} - -// ResolutionMode represents a resolution mode. -type ResolutionMode string - -const ( - // ResolutionModeVIP VIP - ResolutionModeVIP ResolutionMode = "vip" - // ResolutionModeDNSRR DNSRR - ResolutionModeDNSRR ResolutionMode = "dnsrr" -) - -// PortConfig represents the config of a port. -type PortConfig struct { - Name string `json:",omitempty"` - Protocol PortConfigProtocol `json:",omitempty"` - // TargetPort is the port inside the container - TargetPort uint32 `json:",omitempty"` - // PublishedPort is the port on the swarm hosts - PublishedPort uint32 `json:",omitempty"` - // PublishMode is the mode in which port is published - PublishMode PortConfigPublishMode `json:",omitempty"` -} - -// PortConfigPublishMode represents the mode in which the port is to -// be published. -type PortConfigPublishMode string - -const ( - // PortConfigPublishModeIngress is used for ports published - // for ingress load balancing using routing mesh. - PortConfigPublishModeIngress PortConfigPublishMode = "ingress" - // PortConfigPublishModeHost is used for ports published - // for direct host level access on the host where the task is running. - PortConfigPublishModeHost PortConfigPublishMode = "host" -) - -// PortConfigProtocol represents the protocol of a port. -type PortConfigProtocol string - -const ( - // TODO(stevvooe): These should be used generally, not just for PortConfig. - - // PortConfigProtocolTCP TCP - PortConfigProtocolTCP PortConfigProtocol = "tcp" - // PortConfigProtocolUDP UDP - PortConfigProtocolUDP PortConfigProtocol = "udp" - // PortConfigProtocolSCTP SCTP - PortConfigProtocolSCTP PortConfigProtocol = "sctp" -) - -// EndpointVirtualIP represents the virtual ip of a port. -type EndpointVirtualIP struct { - NetworkID string `json:",omitempty"` - Addr string `json:",omitempty"` -} - -// Network represents a network. -type Network struct { - ID string - Meta - Spec NetworkSpec `json:",omitempty"` - DriverState Driver `json:",omitempty"` - IPAMOptions *IPAMOptions `json:",omitempty"` -} - -// NetworkSpec represents the spec of a network. -type NetworkSpec struct { - Annotations - DriverConfiguration *Driver `json:",omitempty"` - IPv6Enabled bool `json:",omitempty"` - Internal bool `json:",omitempty"` - Attachable bool `json:",omitempty"` - Ingress bool `json:",omitempty"` - IPAMOptions *IPAMOptions `json:",omitempty"` - ConfigFrom *network.ConfigReference `json:",omitempty"` - Scope string `json:",omitempty"` -} - -// NetworkAttachmentConfig represents the configuration of a network attachment. -type NetworkAttachmentConfig struct { - Target string `json:",omitempty"` - Aliases []string `json:",omitempty"` - DriverOpts map[string]string `json:",omitempty"` -} - -// NetworkAttachment represents a network attachment. -type NetworkAttachment struct { - Network Network `json:",omitempty"` - Addresses []string `json:",omitempty"` -} - -// IPAMOptions represents ipam options. -type IPAMOptions struct { - Driver Driver `json:",omitempty"` - Configs []IPAMConfig `json:",omitempty"` -} - -// IPAMConfig represents ipam configuration. -type IPAMConfig struct { - Subnet string `json:",omitempty"` - Range string `json:",omitempty"` - Gateway string `json:",omitempty"` -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/node.go b/vendor/github.com/docker/docker/api/types/swarm/node.go deleted file mode 100644 index 2018a031bbf..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/node.go +++ /dev/null @@ -1,151 +0,0 @@ -package swarm - -import "github.com/docker/docker/api/types/filters" - -// Node represents a node. -type Node struct { - ID string - Meta - // Spec defines the desired state of the node as specified by the user. - // The system will honor this and will *never* modify it. - Spec NodeSpec `json:",omitempty"` - // Description encapsulates the properties of the Node as reported by the - // agent. - Description NodeDescription `json:",omitempty"` - // Status provides the current status of the node, as seen by the manager. - Status NodeStatus `json:",omitempty"` - // ManagerStatus provides the current status of the node's manager - // component, if the node is a manager. - ManagerStatus *ManagerStatus `json:",omitempty"` -} - -// NodeSpec represents the spec of a node. -type NodeSpec struct { - Annotations - Role NodeRole `json:",omitempty"` - Availability NodeAvailability `json:",omitempty"` -} - -// NodeRole represents the role of a node. -type NodeRole string - -const ( - // NodeRoleWorker WORKER - NodeRoleWorker NodeRole = "worker" - // NodeRoleManager MANAGER - NodeRoleManager NodeRole = "manager" -) - -// NodeAvailability represents the availability of a node. -type NodeAvailability string - -const ( - // NodeAvailabilityActive ACTIVE - NodeAvailabilityActive NodeAvailability = "active" - // NodeAvailabilityPause PAUSE - NodeAvailabilityPause NodeAvailability = "pause" - // NodeAvailabilityDrain DRAIN - NodeAvailabilityDrain NodeAvailability = "drain" -) - -// NodeDescription represents the description of a node. -type NodeDescription struct { - Hostname string `json:",omitempty"` - Platform Platform `json:",omitempty"` - Resources Resources `json:",omitempty"` - Engine EngineDescription `json:",omitempty"` - TLSInfo TLSInfo `json:",omitempty"` - CSIInfo []NodeCSIInfo `json:",omitempty"` -} - -// Platform represents the platform (Arch/OS). -type Platform struct { - Architecture string `json:",omitempty"` - OS string `json:",omitempty"` -} - -// EngineDescription represents the description of an engine. -type EngineDescription struct { - EngineVersion string `json:",omitempty"` - Labels map[string]string `json:",omitempty"` - Plugins []PluginDescription `json:",omitempty"` -} - -// NodeCSIInfo represents information about a CSI plugin available on the node -type NodeCSIInfo struct { - // PluginName is the name of the CSI plugin. - PluginName string `json:",omitempty"` - // NodeID is the ID of the node as reported by the CSI plugin. This is - // different from the swarm node ID. - NodeID string `json:",omitempty"` - // MaxVolumesPerNode is the maximum number of volumes that may be published - // to this node - MaxVolumesPerNode int64 `json:",omitempty"` - // AccessibleTopology indicates the location of this node in the CSI - // plugin's topology - AccessibleTopology *Topology `json:",omitempty"` -} - -// PluginDescription represents the description of an engine plugin. -type PluginDescription struct { - Type string `json:",omitempty"` - Name string `json:",omitempty"` -} - -// NodeStatus represents the status of a node. -type NodeStatus struct { - State NodeState `json:",omitempty"` - Message string `json:",omitempty"` - Addr string `json:",omitempty"` -} - -// Reachability represents the reachability of a node. -type Reachability string - -const ( - // ReachabilityUnknown UNKNOWN - ReachabilityUnknown Reachability = "unknown" - // ReachabilityUnreachable UNREACHABLE - ReachabilityUnreachable Reachability = "unreachable" - // ReachabilityReachable REACHABLE - ReachabilityReachable Reachability = "reachable" -) - -// ManagerStatus represents the status of a manager. -type ManagerStatus struct { - Leader bool `json:",omitempty"` - Reachability Reachability `json:",omitempty"` - Addr string `json:",omitempty"` -} - -// NodeState represents the state of a node. -type NodeState string - -const ( - // NodeStateUnknown UNKNOWN - NodeStateUnknown NodeState = "unknown" - // NodeStateDown DOWN - NodeStateDown NodeState = "down" - // NodeStateReady READY - NodeStateReady NodeState = "ready" - // NodeStateDisconnected DISCONNECTED - NodeStateDisconnected NodeState = "disconnected" -) - -// Topology defines the CSI topology of this node. This type is a duplicate of -// github.com/docker/docker/api/types.Topology. Because the type definition -// is so simple and to avoid complicated structure or circular imports, we just -// duplicate it here. See that type for full documentation -type Topology struct { - Segments map[string]string `json:",omitempty"` -} - -// NodeListOptions holds parameters to list nodes with. -type NodeListOptions struct { - Filters filters.Args -} - -// NodeRemoveOptions holds parameters to remove nodes with. -type NodeRemoveOptions struct { - Force bool -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime.go b/vendor/github.com/docker/docker/api/types/swarm/runtime.go deleted file mode 100644 index 3fda4ca65d1..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/runtime.go +++ /dev/null @@ -1,37 +0,0 @@ -package swarm - -import "github.com/docker/docker/api/types/swarm/runtime" - -// RuntimeType is the type of runtime used for the TaskSpec -type RuntimeType string - -// RuntimeURL is the proto type url -type RuntimeURL string - -const ( - // RuntimeContainer is the container based runtime - RuntimeContainer RuntimeType = "container" - // RuntimePlugin is the plugin based runtime - RuntimePlugin RuntimeType = "plugin" - // RuntimeNetworkAttachment is the network attachment runtime - RuntimeNetworkAttachment RuntimeType = "attachment" - - // RuntimeURLContainer is the proto url for the container type - RuntimeURLContainer RuntimeURL = "types.docker.com/RuntimeContainer" - // RuntimeURLPlugin is the proto url for the plugin type - RuntimeURLPlugin RuntimeURL = "types.docker.com/RuntimePlugin" -) - -// NetworkAttachmentSpec represents the runtime spec type for network -// attachment tasks -type NetworkAttachmentSpec struct { - ContainerID string -} - -// RuntimeSpec defines the base payload which clients can specify for creating -// a service with the plugin runtime. -type RuntimeSpec = runtime.PluginSpec - -// RuntimePrivilege describes a permission the user has to accept -// upon installing a plugin. -type RuntimePrivilege = runtime.PluginPrivilege diff --git a/vendor/github.com/docker/docker/api/types/swarm/runtime/runtime.go b/vendor/github.com/docker/docker/api/types/swarm/runtime/runtime.go deleted file mode 100644 index 95176b26818..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/runtime/runtime.go +++ /dev/null @@ -1,27 +0,0 @@ -package runtime - -import "fmt" - -// PluginSpec defines the base payload which clients can specify for creating -// a service with the plugin runtime. -type PluginSpec struct { - Name string `json:"name,omitempty"` - Remote string `json:"remote,omitempty"` - Privileges []*PluginPrivilege `json:"privileges,omitempty"` - Disabled bool `json:"disabled,omitempty"` - Env []string `json:"env,omitempty"` -} - -// PluginPrivilege describes a permission the user has to accept -// upon installing a plugin. -type PluginPrivilege struct { - Name string `json:"name,omitempty"` - Description string `json:"description,omitempty"` - Value []string `json:"value,omitempty"` -} - -var ( - ErrInvalidLengthPlugin = fmt.Errorf("proto: negative length found during unmarshaling") // Deprecated: this error was only used internally and is no longer used. - ErrIntOverflowPlugin = fmt.Errorf("proto: integer overflow") // Deprecated: this error was only used internally and is no longer used. - ErrUnexpectedEndOfGroupPlugin = fmt.Errorf("proto: unexpected end of group") // Deprecated: this error was only used internally and is no longer used. -) diff --git a/vendor/github.com/docker/docker/api/types/swarm/secret.go b/vendor/github.com/docker/docker/api/types/swarm/secret.go deleted file mode 100644 index d9482ab56d1..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/secret.go +++ /dev/null @@ -1,66 +0,0 @@ -package swarm - -import ( - "os" - - "github.com/docker/docker/api/types/filters" -) - -// Secret represents a secret. -type Secret struct { - ID string - Meta - Spec SecretSpec -} - -// SecretSpec represents a secret specification from a secret in swarm -type SecretSpec struct { - Annotations - - // Data is the data to store as a secret. It must be empty if a - // [Driver] is used, in which case the data is loaded from an external - // secret store. The maximum allowed size is 500KB, as defined in - // [MaxSecretSize]. - // - // This field is only used to create the secret, and is not returned - // by other endpoints. - // - // [MaxSecretSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/api/validation#MaxSecretSize - Data []byte `json:",omitempty"` - - // Driver is the name of the secrets driver used to fetch the secret's - // value from an external secret store. If not set, the default built-in - // store is used. - Driver *Driver `json:",omitempty"` - - // Templating controls whether and how to evaluate the secret payload as - // a template. If it is not set, no templating is used. - Templating *Driver `json:",omitempty"` -} - -// SecretReferenceFileTarget is a file target in a secret reference -type SecretReferenceFileTarget struct { - Name string - UID string - GID string - Mode os.FileMode -} - -// SecretReference is a reference to a secret in swarm -type SecretReference struct { - File *SecretReferenceFileTarget - SecretID string - SecretName string -} - -// SecretCreateResponse contains the information returned to a client -// on the creation of a new secret. -type SecretCreateResponse struct { - // ID is the id of the created secret. - ID string -} - -// SecretListOptions holds parameters to list secrets -type SecretListOptions struct { - Filters filters.Args -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/service.go b/vendor/github.com/docker/docker/api/types/swarm/service.go deleted file mode 100644 index 56c660c1f0c..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/service.go +++ /dev/null @@ -1,272 +0,0 @@ -package swarm - -import ( - "time" - - "github.com/docker/docker/api/types/filters" -) - -// Service represents a service. -type Service struct { - ID string - Meta - Spec ServiceSpec `json:",omitempty"` - PreviousSpec *ServiceSpec `json:",omitempty"` - Endpoint Endpoint `json:",omitempty"` - UpdateStatus *UpdateStatus `json:",omitempty"` - - // ServiceStatus is an optional, extra field indicating the number of - // desired and running tasks. It is provided primarily as a shortcut to - // calculating these values client-side, which otherwise would require - // listing all tasks for a service, an operation that could be - // computation and network expensive. - ServiceStatus *ServiceStatus `json:",omitempty"` - - // JobStatus is the status of a Service which is in one of ReplicatedJob or - // GlobalJob modes. It is absent on Replicated and Global services. - JobStatus *JobStatus `json:",omitempty"` -} - -// ServiceSpec represents the spec of a service. -type ServiceSpec struct { - Annotations - - // TaskTemplate defines how the service should construct new tasks when - // orchestrating this service. - TaskTemplate TaskSpec `json:",omitempty"` - Mode ServiceMode `json:",omitempty"` - UpdateConfig *UpdateConfig `json:",omitempty"` - RollbackConfig *UpdateConfig `json:",omitempty"` - - // Networks specifies which networks the service should attach to. - // - // Deprecated: This field is deprecated since v1.44. The Networks field in TaskSpec should be used instead. - Networks []NetworkAttachmentConfig `json:",omitempty"` - EndpointSpec *EndpointSpec `json:",omitempty"` -} - -// ServiceMode represents the mode of a service. -type ServiceMode struct { - Replicated *ReplicatedService `json:",omitempty"` - Global *GlobalService `json:",omitempty"` - ReplicatedJob *ReplicatedJob `json:",omitempty"` - GlobalJob *GlobalJob `json:",omitempty"` -} - -// UpdateState is the state of a service update. -type UpdateState string - -const ( - // UpdateStateUpdating is the updating state. - UpdateStateUpdating UpdateState = "updating" - // UpdateStatePaused is the paused state. - UpdateStatePaused UpdateState = "paused" - // UpdateStateCompleted is the completed state. - UpdateStateCompleted UpdateState = "completed" - // UpdateStateRollbackStarted is the state with a rollback in progress. - UpdateStateRollbackStarted UpdateState = "rollback_started" - // UpdateStateRollbackPaused is the state with a rollback in progress. - UpdateStateRollbackPaused UpdateState = "rollback_paused" - // UpdateStateRollbackCompleted is the state with a rollback in progress. - UpdateStateRollbackCompleted UpdateState = "rollback_completed" -) - -// UpdateStatus reports the status of a service update. -type UpdateStatus struct { - State UpdateState `json:",omitempty"` - StartedAt *time.Time `json:",omitempty"` - CompletedAt *time.Time `json:",omitempty"` - Message string `json:",omitempty"` -} - -// ReplicatedService is a kind of ServiceMode. -type ReplicatedService struct { - Replicas *uint64 `json:",omitempty"` -} - -// GlobalService is a kind of ServiceMode. -type GlobalService struct{} - -// ReplicatedJob is the a type of Service which executes a defined Tasks -// in parallel until the specified number of Tasks have succeeded. -type ReplicatedJob struct { - // MaxConcurrent indicates the maximum number of Tasks that should be - // executing simultaneously for this job at any given time. There may be - // fewer Tasks that MaxConcurrent executing simultaneously; for example, if - // there are fewer than MaxConcurrent tasks needed to reach - // TotalCompletions. - // - // If this field is empty, it will default to a max concurrency of 1. - MaxConcurrent *uint64 `json:",omitempty"` - - // TotalCompletions is the total number of Tasks desired to run to - // completion. - // - // If this field is empty, the value of MaxConcurrent will be used. - TotalCompletions *uint64 `json:",omitempty"` -} - -// GlobalJob is the type of a Service which executes a Task on every Node -// matching the Service's placement constraints. These tasks run to completion -// and then exit. -// -// This type is deliberately empty. -type GlobalJob struct{} - -const ( - // UpdateFailureActionPause PAUSE - UpdateFailureActionPause = "pause" - // UpdateFailureActionContinue CONTINUE - UpdateFailureActionContinue = "continue" - // UpdateFailureActionRollback ROLLBACK - UpdateFailureActionRollback = "rollback" - - // UpdateOrderStopFirst STOP_FIRST - UpdateOrderStopFirst = "stop-first" - // UpdateOrderStartFirst START_FIRST - UpdateOrderStartFirst = "start-first" -) - -// UpdateConfig represents the update configuration. -type UpdateConfig struct { - // Maximum number of tasks to be updated in one iteration. - // 0 means unlimited parallelism. - Parallelism uint64 - - // Amount of time between updates. - Delay time.Duration `json:",omitempty"` - - // FailureAction is the action to take when an update failures. - FailureAction string `json:",omitempty"` - - // Monitor indicates how long to monitor a task for failure after it is - // created. If the task fails by ending up in one of the states - // REJECTED, COMPLETED, or FAILED, within Monitor from its creation, - // this counts as a failure. If it fails after Monitor, it does not - // count as a failure. If Monitor is unspecified, a default value will - // be used. - Monitor time.Duration `json:",omitempty"` - - // MaxFailureRatio is the fraction of tasks that may fail during - // an update before the failure action is invoked. Any task created by - // the current update which ends up in one of the states REJECTED, - // COMPLETED or FAILED within Monitor from its creation counts as a - // failure. The number of failures is divided by the number of tasks - // being updated, and if this fraction is greater than - // MaxFailureRatio, the failure action is invoked. - // - // If the failure action is CONTINUE, there is no effect. - // If the failure action is PAUSE, no more tasks will be updated until - // another update is started. - MaxFailureRatio float32 - - // Order indicates the order of operations when rolling out an updated - // task. Either the old task is shut down before the new task is - // started, or the new task is started before the old task is shut down. - Order string -} - -// ServiceStatus represents the number of running tasks in a service and the -// number of tasks desired to be running. -type ServiceStatus struct { - // RunningTasks is the number of tasks for the service actually in the - // Running state - RunningTasks uint64 - - // DesiredTasks is the number of tasks desired to be running by the - // service. For replicated services, this is the replica count. For global - // services, this is computed by taking the number of tasks with desired - // state of not-Shutdown. - DesiredTasks uint64 - - // CompletedTasks is the number of tasks in the state Completed, if this - // service is in ReplicatedJob or GlobalJob mode. This field must be - // cross-referenced with the service type, because the default value of 0 - // may mean that a service is not in a job mode, or it may mean that the - // job has yet to complete any tasks. - CompletedTasks uint64 -} - -// JobStatus is the status of a job-type service. -type JobStatus struct { - // JobIteration is a value increased each time a Job is executed, - // successfully or otherwise. "Executed", in this case, means the job as a - // whole has been started, not that an individual Task has been launched. A - // job is "Executed" when its ServiceSpec is updated. JobIteration can be - // used to disambiguate Tasks belonging to different executions of a job. - // - // Though JobIteration will increase with each subsequent execution, it may - // not necessarily increase by 1, and so JobIteration should not be used to - // keep track of the number of times a job has been executed. - JobIteration Version - - // LastExecution is the time that the job was last executed, as observed by - // Swarm manager. - LastExecution time.Time `json:",omitempty"` -} - -// ServiceCreateOptions contains the options to use when creating a service. -type ServiceCreateOptions struct { - // EncodedRegistryAuth is the encoded registry authorization credentials to - // use when updating the service. - // - // This field follows the format of the X-Registry-Auth header. - EncodedRegistryAuth string - - // QueryRegistry indicates whether the service update requires - // contacting a registry. A registry may be contacted to retrieve - // the image digest and manifest, which in turn can be used to update - // platform or other information about the service. - QueryRegistry bool -} - -// Values for RegistryAuthFrom in ServiceUpdateOptions -const ( - RegistryAuthFromSpec = "spec" - RegistryAuthFromPreviousSpec = "previous-spec" -) - -// ServiceUpdateOptions contains the options to be used for updating services. -type ServiceUpdateOptions struct { - // EncodedRegistryAuth is the encoded registry authorization credentials to - // use when updating the service. - // - // This field follows the format of the X-Registry-Auth header. - EncodedRegistryAuth string - - // TODO(stevvooe): Consider moving the version parameter of ServiceUpdate - // into this field. While it does open API users up to racy writes, most - // users may not need that level of consistency in practice. - - // RegistryAuthFrom specifies where to find the registry authorization - // credentials if they are not given in EncodedRegistryAuth. Valid - // values are "spec" and "previous-spec". - RegistryAuthFrom string - - // Rollback indicates whether a server-side rollback should be - // performed. When this is set, the provided spec will be ignored. - // The valid values are "previous" and "none". An empty value is the - // same as "none". - Rollback string - - // QueryRegistry indicates whether the service update requires - // contacting a registry. A registry may be contacted to retrieve - // the image digest and manifest, which in turn can be used to update - // platform or other information about the service. - QueryRegistry bool -} - -// ServiceListOptions holds parameters to list services with. -type ServiceListOptions struct { - Filters filters.Args - - // Status indicates whether the server should include the service task - // count of running and desired tasks. - Status bool -} - -// ServiceInspectOptions holds parameters related to the "service inspect" -// operation. -type ServiceInspectOptions struct { - InsertDefaults bool -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/service_create_response.go b/vendor/github.com/docker/docker/api/types/swarm/service_create_response.go deleted file mode 100644 index 9a268ff1b93..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/service_create_response.go +++ /dev/null @@ -1,20 +0,0 @@ -package swarm - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// ServiceCreateResponse contains the information returned to a client on the -// creation of a new service. -// -// swagger:model ServiceCreateResponse -type ServiceCreateResponse struct { - - // The ID of the created service. - ID string `json:"ID,omitempty"` - - // Optional warning message. - // - // FIXME(thaJeztah): this should have "omitempty" in the generated type. - // - Warnings []string `json:"Warnings"` -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/service_update_response.go b/vendor/github.com/docker/docker/api/types/swarm/service_update_response.go deleted file mode 100644 index 0417467dae3..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/service_update_response.go +++ /dev/null @@ -1,12 +0,0 @@ -package swarm - -// This file was generated by the swagger tool. -// Editing this file might prove futile when you re-run the swagger generate command - -// ServiceUpdateResponse service update response -// swagger:model ServiceUpdateResponse -type ServiceUpdateResponse struct { - - // Optional warning messages - Warnings []string `json:"Warnings"` -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/swarm.go b/vendor/github.com/docker/docker/api/types/swarm/swarm.go deleted file mode 100644 index 38f3e6666d1..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/swarm.go +++ /dev/null @@ -1,244 +0,0 @@ -package swarm - -import ( - "time" -) - -// ClusterInfo represents info about the cluster for outputting in "info" -// it contains the same information as "Swarm", but without the JoinTokens -type ClusterInfo struct { - ID string - Meta - Spec Spec - TLSInfo TLSInfo - RootRotationInProgress bool - DefaultAddrPool []string - SubnetSize uint32 - DataPathPort uint32 -} - -// Swarm represents a swarm. -type Swarm struct { - ClusterInfo - JoinTokens JoinTokens -} - -// JoinTokens contains the tokens workers and managers need to join the swarm. -type JoinTokens struct { - // Worker is the join token workers may use to join the swarm. - Worker string - // Manager is the join token managers may use to join the swarm. - Manager string -} - -// Spec represents the spec of a swarm. -type Spec struct { - Annotations - - Orchestration OrchestrationConfig `json:",omitempty"` - Raft RaftConfig `json:",omitempty"` - Dispatcher DispatcherConfig `json:",omitempty"` - CAConfig CAConfig `json:",omitempty"` - TaskDefaults TaskDefaults `json:",omitempty"` - EncryptionConfig EncryptionConfig `json:",omitempty"` -} - -// OrchestrationConfig represents orchestration configuration. -type OrchestrationConfig struct { - // TaskHistoryRetentionLimit is the number of historic tasks to keep per instance or - // node. If negative, never remove completed or failed tasks. - TaskHistoryRetentionLimit *int64 `json:",omitempty"` -} - -// TaskDefaults parameterizes cluster-level task creation with default values. -type TaskDefaults struct { - // LogDriver selects the log driver to use for tasks created in the - // orchestrator if unspecified by a service. - // - // Updating this value will only have an affect on new tasks. Old tasks - // will continue use their previously configured log driver until - // recreated. - LogDriver *Driver `json:",omitempty"` -} - -// EncryptionConfig controls at-rest encryption of data and keys. -type EncryptionConfig struct { - // AutoLockManagers specifies whether or not managers TLS keys and raft data - // should be encrypted at rest in such a way that they must be unlocked - // before the manager node starts up again. - AutoLockManagers bool -} - -// RaftConfig represents raft configuration. -type RaftConfig struct { - // SnapshotInterval is the number of log entries between snapshots. - SnapshotInterval uint64 `json:",omitempty"` - - // KeepOldSnapshots is the number of snapshots to keep beyond the - // current snapshot. - KeepOldSnapshots *uint64 `json:",omitempty"` - - // LogEntriesForSlowFollowers is the number of log entries to keep - // around to sync up slow followers after a snapshot is created. - LogEntriesForSlowFollowers uint64 `json:",omitempty"` - - // ElectionTick is the number of ticks that a follower will wait for a message - // from the leader before becoming a candidate and starting an election. - // ElectionTick must be greater than HeartbeatTick. - // - // A tick currently defaults to one second, so these translate directly to - // seconds currently, but this is NOT guaranteed. - ElectionTick int - - // HeartbeatTick is the number of ticks between heartbeats. Every - // HeartbeatTick ticks, the leader will send a heartbeat to the - // followers. - // - // A tick currently defaults to one second, so these translate directly to - // seconds currently, but this is NOT guaranteed. - HeartbeatTick int -} - -// DispatcherConfig represents dispatcher configuration. -type DispatcherConfig struct { - // HeartbeatPeriod defines how often agent should send heartbeats to - // dispatcher. - HeartbeatPeriod time.Duration `json:",omitempty"` -} - -// CAConfig represents CA configuration. -type CAConfig struct { - // NodeCertExpiry is the duration certificates should be issued for - NodeCertExpiry time.Duration `json:",omitempty"` - - // ExternalCAs is a list of CAs to which a manager node will make - // certificate signing requests for node certificates. - ExternalCAs []*ExternalCA `json:",omitempty"` - - // SigningCACert and SigningCAKey specify the desired signing root CA and - // root CA key for the swarm. When inspecting the cluster, the key will - // be redacted. - SigningCACert string `json:",omitempty"` - SigningCAKey string `json:",omitempty"` - - // If this value changes, and there is no specified signing cert and key, - // then the swarm is forced to generate a new root certificate and key. - ForceRotate uint64 `json:",omitempty"` -} - -// ExternalCAProtocol represents type of external CA. -type ExternalCAProtocol string - -// ExternalCAProtocolCFSSL CFSSL -const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl" - -// ExternalCA defines external CA to be used by the cluster. -type ExternalCA struct { - // Protocol is the protocol used by this external CA. - Protocol ExternalCAProtocol - - // URL is the URL where the external CA can be reached. - URL string - - // Options is a set of additional key/value pairs whose interpretation - // depends on the specified CA type. - Options map[string]string `json:",omitempty"` - - // CACert specifies which root CA is used by this external CA. This certificate must - // be in PEM format. - CACert string -} - -// InitRequest is the request used to init a swarm. -type InitRequest struct { - ListenAddr string - AdvertiseAddr string - DataPathAddr string - DataPathPort uint32 - ForceNewCluster bool - Spec Spec - AutoLockManagers bool - Availability NodeAvailability - DefaultAddrPool []string - SubnetSize uint32 -} - -// JoinRequest is the request used to join a swarm. -type JoinRequest struct { - ListenAddr string - AdvertiseAddr string - DataPathAddr string - RemoteAddrs []string - JoinToken string // accept by secret - Availability NodeAvailability -} - -// UnlockRequest is the request used to unlock a swarm. -type UnlockRequest struct { - // UnlockKey is the unlock key in ASCII-armored format. - UnlockKey string -} - -// LocalNodeState represents the state of the local node. -type LocalNodeState string - -const ( - // LocalNodeStateInactive INACTIVE - LocalNodeStateInactive LocalNodeState = "inactive" - // LocalNodeStatePending PENDING - LocalNodeStatePending LocalNodeState = "pending" - // LocalNodeStateActive ACTIVE - LocalNodeStateActive LocalNodeState = "active" - // LocalNodeStateError ERROR - LocalNodeStateError LocalNodeState = "error" - // LocalNodeStateLocked LOCKED - LocalNodeStateLocked LocalNodeState = "locked" -) - -// Info represents generic information about swarm. -type Info struct { - NodeID string - NodeAddr string - - LocalNodeState LocalNodeState - ControlAvailable bool - Error string - - RemoteManagers []Peer - Nodes int `json:",omitempty"` - Managers int `json:",omitempty"` - - Cluster *ClusterInfo `json:",omitempty"` - - Warnings []string `json:",omitempty"` -} - -// Status provides information about the current swarm status and role, -// obtained from the "Swarm" header in the API response. -type Status struct { - // NodeState represents the state of the node. - NodeState LocalNodeState - - // ControlAvailable indicates if the node is a swarm manager. - ControlAvailable bool -} - -// Peer represents a peer. -type Peer struct { - NodeID string - Addr string -} - -// UpdateFlags contains flags for SwarmUpdate. -type UpdateFlags struct { - RotateWorkerToken bool - RotateManagerToken bool - RotateManagerUnlockKey bool -} - -// UnlockKeyResponse contains the response for Engine API: -// GET /swarm/unlockkey -type UnlockKeyResponse struct { - // UnlockKey is the unlock key in ASCII-armored format. - UnlockKey string -} diff --git a/vendor/github.com/docker/docker/api/types/swarm/task.go b/vendor/github.com/docker/docker/api/types/swarm/task.go deleted file mode 100644 index e143f844fa8..00000000000 --- a/vendor/github.com/docker/docker/api/types/swarm/task.go +++ /dev/null @@ -1,230 +0,0 @@ -package swarm - -import ( - "time" - - "github.com/docker/docker/api/types/filters" -) - -// TaskState represents the state of a task. -type TaskState string - -const ( - // TaskStateNew NEW - TaskStateNew TaskState = "new" - // TaskStateAllocated ALLOCATED - TaskStateAllocated TaskState = "allocated" - // TaskStatePending PENDING - TaskStatePending TaskState = "pending" - // TaskStateAssigned ASSIGNED - TaskStateAssigned TaskState = "assigned" - // TaskStateAccepted ACCEPTED - TaskStateAccepted TaskState = "accepted" - // TaskStatePreparing PREPARING - TaskStatePreparing TaskState = "preparing" - // TaskStateReady READY - TaskStateReady TaskState = "ready" - // TaskStateStarting STARTING - TaskStateStarting TaskState = "starting" - // TaskStateRunning RUNNING - TaskStateRunning TaskState = "running" - // TaskStateComplete COMPLETE - TaskStateComplete TaskState = "complete" - // TaskStateShutdown SHUTDOWN - TaskStateShutdown TaskState = "shutdown" - // TaskStateFailed FAILED - TaskStateFailed TaskState = "failed" - // TaskStateRejected REJECTED - TaskStateRejected TaskState = "rejected" - // TaskStateRemove REMOVE - TaskStateRemove TaskState = "remove" - // TaskStateOrphaned ORPHANED - TaskStateOrphaned TaskState = "orphaned" -) - -// Task represents a task. -type Task struct { - ID string - Meta - Annotations - - Spec TaskSpec `json:",omitempty"` - ServiceID string `json:",omitempty"` - Slot int `json:",omitempty"` - NodeID string `json:",omitempty"` - Status TaskStatus `json:",omitempty"` - DesiredState TaskState `json:",omitempty"` - NetworksAttachments []NetworkAttachment `json:",omitempty"` - GenericResources []GenericResource `json:",omitempty"` - - // JobIteration is the JobIteration of the Service that this Task was - // spawned from, if the Service is a ReplicatedJob or GlobalJob. This is - // used to determine which Tasks belong to which run of the job. This field - // is absent if the Service mode is Replicated or Global. - JobIteration *Version `json:",omitempty"` - - // Volumes is the list of VolumeAttachments for this task. It specifies - // which particular volumes are to be used by this particular task, and - // fulfilling what mounts in the spec. - Volumes []VolumeAttachment -} - -// TaskSpec represents the spec of a task. -type TaskSpec struct { - // ContainerSpec, NetworkAttachmentSpec, and PluginSpec are mutually exclusive. - // PluginSpec is only used when the `Runtime` field is set to `plugin` - // NetworkAttachmentSpec is used if the `Runtime` field is set to - // `attachment`. - ContainerSpec *ContainerSpec `json:",omitempty"` - PluginSpec *RuntimeSpec `json:",omitempty"` - NetworkAttachmentSpec *NetworkAttachmentSpec `json:",omitempty"` - - Resources *ResourceRequirements `json:",omitempty"` - RestartPolicy *RestartPolicy `json:",omitempty"` - Placement *Placement `json:",omitempty"` - Networks []NetworkAttachmentConfig `json:",omitempty"` - - // LogDriver specifies the LogDriver to use for tasks created from this - // spec. If not present, the one on cluster default on swarm.Spec will be - // used, finally falling back to the engine default if not specified. - LogDriver *Driver `json:",omitempty"` - - // ForceUpdate is a counter that triggers an update even if no relevant - // parameters have been changed. - ForceUpdate uint64 - - Runtime RuntimeType `json:",omitempty"` -} - -// Resources represents resources (CPU/Memory) which can be advertised by a -// node and requested to be reserved for a task. -type Resources struct { - NanoCPUs int64 `json:",omitempty"` - MemoryBytes int64 `json:",omitempty"` - GenericResources []GenericResource `json:",omitempty"` -} - -// Limit describes limits on resources which can be requested by a task. -type Limit struct { - NanoCPUs int64 `json:",omitempty"` - MemoryBytes int64 `json:",omitempty"` - Pids int64 `json:",omitempty"` -} - -// GenericResource represents a "user defined" resource which can -// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1) -type GenericResource struct { - NamedResourceSpec *NamedGenericResource `json:",omitempty"` - DiscreteResourceSpec *DiscreteGenericResource `json:",omitempty"` -} - -// NamedGenericResource represents a "user defined" resource which is defined -// as a string. -// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...) -// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...) -type NamedGenericResource struct { - Kind string `json:",omitempty"` - Value string `json:",omitempty"` -} - -// DiscreteGenericResource represents a "user defined" resource which is defined -// as an integer -// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...) -// Value is used to count the resource (SSD=5, HDD=3, ...) -type DiscreteGenericResource struct { - Kind string `json:",omitempty"` - Value int64 `json:",omitempty"` -} - -// ResourceRequirements represents resources requirements. -type ResourceRequirements struct { - Limits *Limit `json:",omitempty"` - Reservations *Resources `json:",omitempty"` -} - -// Placement represents orchestration parameters. -type Placement struct { - Constraints []string `json:",omitempty"` - Preferences []PlacementPreference `json:",omitempty"` - MaxReplicas uint64 `json:",omitempty"` - - // Platforms stores all the platforms that the image can run on. - // This field is used in the platform filter for scheduling. If empty, - // then the platform filter is off, meaning there are no scheduling restrictions. - Platforms []Platform `json:",omitempty"` -} - -// PlacementPreference provides a way to make the scheduler aware of factors -// such as topology. -type PlacementPreference struct { - Spread *SpreadOver -} - -// SpreadOver is a scheduling preference that instructs the scheduler to spread -// tasks evenly over groups of nodes identified by labels. -type SpreadOver struct { - // label descriptor, such as engine.labels.az - SpreadDescriptor string -} - -// RestartPolicy represents the restart policy. -type RestartPolicy struct { - Condition RestartPolicyCondition `json:",omitempty"` - Delay *time.Duration `json:",omitempty"` - MaxAttempts *uint64 `json:",omitempty"` - Window *time.Duration `json:",omitempty"` -} - -// RestartPolicyCondition represents when to restart. -type RestartPolicyCondition string - -const ( - // RestartPolicyConditionNone NONE - RestartPolicyConditionNone RestartPolicyCondition = "none" - // RestartPolicyConditionOnFailure ON_FAILURE - RestartPolicyConditionOnFailure RestartPolicyCondition = "on-failure" - // RestartPolicyConditionAny ANY - RestartPolicyConditionAny RestartPolicyCondition = "any" -) - -// TaskStatus represents the status of a task. -type TaskStatus struct { - Timestamp time.Time `json:",omitempty"` - State TaskState `json:",omitempty"` - Message string `json:",omitempty"` - Err string `json:",omitempty"` - ContainerStatus *ContainerStatus `json:",omitempty"` - PortStatus PortStatus `json:",omitempty"` -} - -// ContainerStatus represents the status of a container. -type ContainerStatus struct { - ContainerID string - PID int - ExitCode int -} - -// PortStatus represents the port status of a task's host ports whose -// service has published host ports -type PortStatus struct { - Ports []PortConfig `json:",omitempty"` -} - -// VolumeAttachment contains the associating a Volume to a Task. -type VolumeAttachment struct { - // ID is the Swarmkit ID of the Volume. This is not the CSI VolumeId. - ID string `json:",omitempty"` - - // Source, together with Target, indicates the Mount, as specified in the - // ContainerSpec, that this volume fulfills. - Source string `json:",omitempty"` - - // Target, together with Source, indicates the Mount, as specified - // in the ContainerSpec, that this volume fulfills. - Target string `json:",omitempty"` -} - -// TaskListOptions holds parameters to list tasks with. -type TaskListOptions struct { - Filters filters.Args -} diff --git a/vendor/github.com/docker/docker/api/types/versions/compare.go b/vendor/github.com/docker/docker/api/types/versions/compare.go deleted file mode 100644 index 1a0325c7eda..00000000000 --- a/vendor/github.com/docker/docker/api/types/versions/compare.go +++ /dev/null @@ -1,65 +0,0 @@ -package versions - -import ( - "strconv" - "strings" -) - -// compare compares two version strings -// returns -1 if v1 < v2, 1 if v1 > v2, 0 otherwise. -func compare(v1, v2 string) int { - if v1 == v2 { - return 0 - } - var ( - currTab = strings.Split(v1, ".") - otherTab = strings.Split(v2, ".") - ) - - maxVer := len(currTab) - if len(otherTab) > maxVer { - maxVer = len(otherTab) - } - for i := 0; i < maxVer; i++ { - var currInt, otherInt int - - if len(currTab) > i { - currInt, _ = strconv.Atoi(currTab[i]) - } - if len(otherTab) > i { - otherInt, _ = strconv.Atoi(otherTab[i]) - } - if currInt > otherInt { - return 1 - } - if otherInt > currInt { - return -1 - } - } - return 0 -} - -// LessThan checks if a version is less than another -func LessThan(v, other string) bool { - return compare(v, other) == -1 -} - -// LessThanOrEqualTo checks if a version is less than or equal to another -func LessThanOrEqualTo(v, other string) bool { - return compare(v, other) <= 0 -} - -// GreaterThan checks if a version is greater than another -func GreaterThan(v, other string) bool { - return compare(v, other) == 1 -} - -// GreaterThanOrEqualTo checks if a version is greater than or equal to another -func GreaterThanOrEqualTo(v, other string) bool { - return compare(v, other) >= 0 -} - -// Equal checks if a version is equal to another -func Equal(v, other string) bool { - return compare(v, other) == 0 -} diff --git a/vendor/github.com/docker/docker/pkg/homedir/homedir_linux.go b/vendor/github.com/docker/docker/pkg/homedir/homedir_linux.go deleted file mode 100644 index 469395f16e2..00000000000 --- a/vendor/github.com/docker/docker/pkg/homedir/homedir_linux.go +++ /dev/null @@ -1,105 +0,0 @@ -package homedir - -import ( - "errors" - "os" - "path/filepath" - "strings" -) - -// GetRuntimeDir returns XDG_RUNTIME_DIR. -// XDG_RUNTIME_DIR is typically configured via pam_systemd. -// GetRuntimeDir returns non-nil error if XDG_RUNTIME_DIR is not set. -// -// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html -func GetRuntimeDir() (string, error) { - if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" { - return xdgRuntimeDir, nil - } - return "", errors.New("could not get XDG_RUNTIME_DIR") -} - -// StickRuntimeDirContents sets the sticky bit on files that are under -// XDG_RUNTIME_DIR, so that the files won't be periodically removed by the system. -// -// StickyRuntimeDir returns slice of sticked files. -// StickyRuntimeDir returns nil error if XDG_RUNTIME_DIR is not set. -// -// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html -func StickRuntimeDirContents(files []string) ([]string, error) { - runtimeDir, err := GetRuntimeDir() - if err != nil { - // ignore error if runtimeDir is empty - return nil, nil - } - runtimeDir, err = filepath.Abs(runtimeDir) - if err != nil { - return nil, err - } - var sticked []string - for _, f := range files { - f, err = filepath.Abs(f) - if err != nil { - return sticked, err - } - if strings.HasPrefix(f, runtimeDir+"/") { - if err = stick(f); err != nil { - return sticked, err - } - sticked = append(sticked, f) - } - } - return sticked, nil -} - -func stick(f string) error { - st, err := os.Stat(f) - if err != nil { - return err - } - m := st.Mode() - m |= os.ModeSticky - return os.Chmod(f, m) -} - -// GetDataHome returns XDG_DATA_HOME. -// GetDataHome returns $HOME/.local/share and nil error if XDG_DATA_HOME is not set. -// If HOME and XDG_DATA_HOME are not set, getpwent(3) is consulted to determine the users home directory. -// -// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html -func GetDataHome() (string, error) { - if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" { - return xdgDataHome, nil - } - home := Get() - if home == "" { - return "", errors.New("could not get either XDG_DATA_HOME or HOME") - } - return filepath.Join(home, ".local", "share"), nil -} - -// GetConfigHome returns XDG_CONFIG_HOME. -// GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set. -// If HOME and XDG_CONFIG_HOME are not set, getpwent(3) is consulted to determine the users home directory. -// -// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html -func GetConfigHome() (string, error) { - if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" { - return xdgConfigHome, nil - } - home := Get() - if home == "" { - return "", errors.New("could not get either XDG_CONFIG_HOME or HOME") - } - return filepath.Join(home, ".config"), nil -} - -// GetLibHome returns $HOME/.local/lib -// If HOME is not set, getpwent(3) is consulted to determine the users home directory. -func GetLibHome() (string, error) { - home := Get() - if home == "" { - return "", errors.New("could not get HOME") - } - return filepath.Join(home, ".local/lib"), nil -} diff --git a/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go b/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go deleted file mode 100644 index 13df228c622..00000000000 --- a/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go +++ /dev/null @@ -1,314 +0,0 @@ -package jsonmessage - -import ( - "encoding/json" - "fmt" - "io" - "strings" - "time" - - "github.com/docker/go-units" - "github.com/moby/term" - "github.com/morikuni/aec" -) - -// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to -// ensure the formatted time isalways the same number of characters. -const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00" - -// JSONError wraps a concrete Code and Message, Code is -// an integer error code, Message is the error message. -type JSONError struct { - Code int `json:"code,omitempty"` - Message string `json:"message,omitempty"` -} - -func (e *JSONError) Error() string { - return e.Message -} - -// JSONProgress describes a progress message in a JSON stream. -type JSONProgress struct { - // Current is the current status and value of the progress made towards Total. - Current int64 `json:"current,omitempty"` - // Total is the end value describing when we made 100% progress for an operation. - Total int64 `json:"total,omitempty"` - // Start is the initial value for the operation. - Start int64 `json:"start,omitempty"` - // HideCounts. if true, hides the progress count indicator (xB/yB). - HideCounts bool `json:"hidecounts,omitempty"` - // Units is the unit to print for progress. It defaults to "bytes" if empty. - Units string `json:"units,omitempty"` - - // terminalFd is the fd of the current terminal, if any. It is used - // to get the terminal width. - terminalFd uintptr - - // nowFunc is used to override the current time in tests. - nowFunc func() time.Time - - // winSize is used to override the terminal width in tests. - winSize int -} - -func (p *JSONProgress) String() string { - var ( - width = p.width() - pbBox string - numbersBox string - ) - if p.Current <= 0 && p.Total <= 0 { - return "" - } - if p.Total <= 0 { - switch p.Units { - case "": - return fmt.Sprintf("%8v", units.HumanSize(float64(p.Current))) - default: - return fmt.Sprintf("%d %s", p.Current, p.Units) - } - } - - percentage := int(float64(p.Current)/float64(p.Total)*100) / 2 - if percentage > 50 { - percentage = 50 - } - if width > 110 { - // this number can't be negative gh#7136 - numSpaces := 0 - if 50-percentage > 0 { - numSpaces = 50 - percentage - } - pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces)) - } - - switch { - case p.HideCounts: - case p.Units == "": // no units, use bytes - current := units.HumanSize(float64(p.Current)) - total := units.HumanSize(float64(p.Total)) - - numbersBox = fmt.Sprintf("%8v/%v", current, total) - - if p.Current > p.Total { - // remove total display if the reported current is wonky. - numbersBox = fmt.Sprintf("%8v", current) - } - default: - numbersBox = fmt.Sprintf("%d/%d %s", p.Current, p.Total, p.Units) - - if p.Current > p.Total { - // remove total display if the reported current is wonky. - numbersBox = fmt.Sprintf("%d %s", p.Current, p.Units) - } - } - - // Show approximation of remaining time if there's enough width. - var timeLeftBox string - if width > 50 { - if p.Current > 0 && p.Start > 0 && percentage < 50 { - fromStart := p.now().Sub(time.Unix(p.Start, 0)) - perEntry := fromStart / time.Duration(p.Current) - left := time.Duration(p.Total-p.Current) * perEntry - timeLeftBox = " " + left.Round(time.Second).String() - } - } - return pbBox + numbersBox + timeLeftBox -} - -// now returns the current time in UTC, but can be overridden in tests -// by setting JSONProgress.nowFunc to a custom function. -func (p *JSONProgress) now() time.Time { - if p.nowFunc != nil { - return p.nowFunc() - } - return time.Now().UTC() -} - -// width returns the current terminal's width, but can be overridden -// in tests by setting JSONProgress.winSize to a non-zero value. -func (p *JSONProgress) width() int { - if p.winSize != 0 { - return p.winSize - } - ws, err := term.GetWinsize(p.terminalFd) - if err == nil { - return int(ws.Width) - } - return 200 -} - -// JSONMessage defines a message struct. It describes -// the created time, where it from, status, ID of the -// message. It's used for docker events. -type JSONMessage struct { - Stream string `json:"stream,omitempty"` - Status string `json:"status,omitempty"` - Progress *JSONProgress `json:"progressDetail,omitempty"` - - // ProgressMessage is a pre-formatted presentation of [Progress]. - // - // Deprecated: this field is deprecated since docker v0.7.1 / API v1.8. Use the information in [Progress] instead. This field will be omitted in a future release. - ProgressMessage string `json:"progress,omitempty"` - ID string `json:"id,omitempty"` - From string `json:"from,omitempty"` // Deprecated: this field is no longer set in stream responses and should not be used. - Time int64 `json:"time,omitempty"` // Deprecated: this field is no longer set in stream responses and should not be used. - TimeNano int64 `json:"timeNano,omitempty"` // Deprecated: this field is no longer set in stream responses and should not be used. - Error *JSONError `json:"errorDetail,omitempty"` - - // ErrorMessage contains errors encountered during the operation. - // - // Deprecated: this field is deprecated since docker v0.6.0 / API v1.4. Use [Error.Message] instead. This field will be omitted in a future release. - ErrorMessage string `json:"error,omitempty"` // deprecated - // Aux contains out-of-band data, such as digests for push signing and image id after building. - Aux *json.RawMessage `json:"aux,omitempty"` -} - -func clearLine(out io.Writer) { - eraseMode := aec.EraseModes.All - cl := aec.EraseLine(eraseMode) - fmt.Fprint(out, cl) -} - -func cursorUp(out io.Writer, l uint) { - fmt.Fprint(out, aec.Up(l)) -} - -func cursorDown(out io.Writer, l uint) { - fmt.Fprint(out, aec.Down(l)) -} - -// Display prints the JSONMessage to out. If isTerminal is true, it erases -// the entire current line when displaying the progressbar. It returns an -// error if the [JSONMessage.Error] field is non-nil. -func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error { - if jm.Error != nil { - return jm.Error - } - var endl string - if isTerminal && jm.Stream == "" && jm.Progress != nil { - clearLine(out) - endl = "\r" - fmt.Fprint(out, endl) - } else if jm.Progress != nil && jm.Progress.String() != "" { // disable progressbar in non-terminal - return nil - } - if jm.TimeNano != 0 { - fmt.Fprintf(out, "%s ", time.Unix(0, jm.TimeNano).Format(RFC3339NanoFixed)) - } else if jm.Time != 0 { - fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(RFC3339NanoFixed)) - } - if jm.ID != "" { - fmt.Fprintf(out, "%s: ", jm.ID) - } - if jm.From != "" { - fmt.Fprintf(out, "(from %s) ", jm.From) - } - if jm.Progress != nil && isTerminal { - fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl) - } else if jm.ProgressMessage != "" { // deprecated - fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl) - } else if jm.Stream != "" { - fmt.Fprintf(out, "%s%s", jm.Stream, endl) - } else { - fmt.Fprintf(out, "%s%s\n", jm.Status, endl) - } - return nil -} - -// DisplayJSONMessagesStream reads a JSON message stream from in, and writes -// each [JSONMessage] to out. It returns an error if an invalid JSONMessage -// is received, or if a JSONMessage containers a non-zero [JSONMessage.Error]. -// -// Presentation of the JSONMessage depends on whether a terminal is attached, -// and on the terminal width. Progress bars ([JSONProgress]) are suppressed -// on narrower terminals (< 110 characters). -// -// - isTerminal describes if out is a terminal, in which case it prints -// a newline ("\n") at the end of each line and moves the cursor while -// displaying. -// - terminalFd is the fd of the current terminal (if any), and used -// to get the terminal width. -// - auxCallback allows handling the [JSONMessage.Aux] field. It is -// called if a JSONMessage contains an Aux field, in which case -// DisplayJSONMessagesStream does not present the JSONMessage. -func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(JSONMessage)) error { - var ( - dec = json.NewDecoder(in) - ids = make(map[string]uint) - ) - - for { - var diff uint - var jm JSONMessage - if err := dec.Decode(&jm); err != nil { - if err == io.EOF { - break - } - return err - } - - if jm.Aux != nil { - if auxCallback != nil { - auxCallback(jm) - } - continue - } - - if jm.Progress != nil { - jm.Progress.terminalFd = terminalFd - } - if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") { - line, ok := ids[jm.ID] - if !ok { - // NOTE: This approach of using len(id) to - // figure out the number of lines of history - // only works as long as we clear the history - // when we output something that's not - // accounted for in the map, such as a line - // with no ID. - line = uint(len(ids)) - ids[jm.ID] = line - if isTerminal { - fmt.Fprintf(out, "\n") - } - } - diff = uint(len(ids)) - line - if isTerminal { - cursorUp(out, diff) - } - } else { - // When outputting something that isn't progress - // output, clear the history of previous lines. We - // don't want progress entries from some previous - // operation to be updated (for example, pull -a - // with multiple tags). - ids = make(map[string]uint) - } - err := jm.Display(out, isTerminal) - if jm.ID != "" && isTerminal { - cursorDown(out, diff) - } - if err != nil { - return err - } - } - return nil -} - -// Stream is an io.Writer for output with utilities to get the output's file -// descriptor and to detect whether it's a terminal. -// -// it is subset of the streams.Out type in -// https://pkg.go.dev/github.com/docker/cli@v20.10.17+incompatible/cli/streams#Out -type Stream interface { - io.Writer - FD() uintptr - IsTerminal() bool -} - -// DisplayJSONMessagesToStream prints json messages to the output Stream. It is -// used by the Docker CLI to print JSONMessage streams. -func DisplayJSONMessagesToStream(in io.Reader, stream Stream, auxCallback func(JSONMessage)) error { - return DisplayJSONMessagesStream(in, stream, stream.FD(), stream.IsTerminal(), auxCallback) -} diff --git a/vendor/github.com/fsouza/go-dockerclient/client.go b/vendor/github.com/fsouza/go-dockerclient/client.go index e1a42001771..16ae3dbf087 100644 --- a/vendor/github.com/fsouza/go-dockerclient/client.go +++ b/vendor/github.com/fsouza/go-dockerclient/client.go @@ -30,9 +30,9 @@ import ( "sync/atomic" "time" - "github.com/docker/docker/pkg/homedir" - "github.com/docker/docker/pkg/jsonmessage" - "github.com/docker/docker/pkg/stdcopy" + "github.com/moby/moby/api/pkg/stdcopy" + "github.com/moby/moby/client/pkg/jsonmessage" + "github.com/moby/moby/v2/pkg/homedir" ) const ( @@ -654,7 +654,7 @@ func handleStreamResponse(resp *http.Response, streamOptions *streamOptions) err return err } if st, ok := streamOptions.stdout.(stream); ok { - err = jsonmessage.DisplayJSONMessagesToStream(resp.Body, st, nil) + err = jsonmessage.DisplayJSONMessagesStream(resp.Body, st, st.FD(), st.IsTerminal(), nil) } else { err = jsonmessage.DisplayJSONMessagesStream(resp.Body, streamOptions.stdout, 0, false, nil) } diff --git a/vendor/github.com/fsouza/go-dockerclient/container.go b/vendor/github.com/fsouza/go-dockerclient/container.go index e5dafe0faa7..c62807149cd 100644 --- a/vendor/github.com/fsouza/go-dockerclient/container.go +++ b/vendor/github.com/fsouza/go-dockerclient/container.go @@ -185,6 +185,7 @@ type ContainerNetwork struct { Gateway string `json:"Gateway,omitempty" yaml:"Gateway,omitempty" toml:"Gateway,omitempty"` EndpointID string `json:"EndpointID,omitempty" yaml:"EndpointID,omitempty" toml:"EndpointID,omitempty"` NetworkID string `json:"NetworkID,omitempty" yaml:"NetworkID,omitempty" toml:"NetworkID,omitempty"` + DNSNames []string `json:"DNSNames,omitempty" yaml:"DNSNames,omitempty" toml:"DNSNames,omitempty"` } // NetworkSettings contains network-related information about a container @@ -485,79 +486,80 @@ type BlockLimit struct { // HostConfig contains the container options related to starting a container on // a given host type HostConfig struct { - Binds []string `json:"Binds,omitempty" yaml:"Binds,omitempty" toml:"Binds,omitempty"` - CapAdd []string `json:"CapAdd,omitempty" yaml:"CapAdd,omitempty" toml:"CapAdd,omitempty"` - CapDrop []string `json:"CapDrop,omitempty" yaml:"CapDrop,omitempty" toml:"CapDrop,omitempty"` - Capabilities []string `json:"Capabilities,omitempty" yaml:"Capabilities,omitempty" toml:"Capabilities,omitempty"` // Mutually exclusive w.r.t. CapAdd and CapDrop API v1.40 - GroupAdd []string `json:"GroupAdd,omitempty" yaml:"GroupAdd,omitempty" toml:"GroupAdd,omitempty"` - ContainerIDFile string `json:"ContainerIDFile,omitempty" yaml:"ContainerIDFile,omitempty" toml:"ContainerIDFile,omitempty"` - LxcConf []KeyValuePair `json:"LxcConf,omitempty" yaml:"LxcConf,omitempty" toml:"LxcConf,omitempty"` - PortBindings map[Port][]PortBinding `json:"PortBindings,omitempty" yaml:"PortBindings,omitempty" toml:"PortBindings,omitempty"` - Links []string `json:"Links,omitempty" yaml:"Links,omitempty" toml:"Links,omitempty"` - DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty" toml:"Dns,omitempty"` // For Docker API v1.10 and above only - DNSOptions []string `json:"DnsOptions,omitempty" yaml:"DnsOptions,omitempty" toml:"DnsOptions,omitempty"` - DNSSearch []string `json:"DnsSearch,omitempty" yaml:"DnsSearch,omitempty" toml:"DnsSearch,omitempty"` - ExtraHosts []string `json:"ExtraHosts,omitempty" yaml:"ExtraHosts,omitempty" toml:"ExtraHosts,omitempty"` - VolumesFrom []string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty" toml:"VolumesFrom,omitempty"` - UsernsMode string `json:"UsernsMode,omitempty" yaml:"UsernsMode,omitempty" toml:"UsernsMode,omitempty"` - NetworkMode string `json:"NetworkMode,omitempty" yaml:"NetworkMode,omitempty" toml:"NetworkMode,omitempty"` - IpcMode string `json:"IpcMode,omitempty" yaml:"IpcMode,omitempty" toml:"IpcMode,omitempty"` - Isolation string `json:"Isolation,omitempty" yaml:"Isolation,omitempty" toml:"Isolation,omitempty"` // Windows only - ConsoleSize [2]int `json:"ConsoleSize,omitempty" yaml:"ConsoleSize,omitempty" toml:"ConsoleSize,omitempty"` // Windows only height x width - PidMode string `json:"PidMode,omitempty" yaml:"PidMode,omitempty" toml:"PidMode,omitempty"` - UTSMode string `json:"UTSMode,omitempty" yaml:"UTSMode,omitempty" toml:"UTSMode,omitempty"` - RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty" yaml:"RestartPolicy,omitempty" toml:"RestartPolicy,omitempty"` - Devices []Device `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"` - DeviceCgroupRules []string `json:"DeviceCgroupRules,omitempty" yaml:"DeviceCgroupRules,omitempty" toml:"DeviceCgroupRules,omitempty"` - DeviceRequests []DeviceRequest `json:"DeviceRequests,omitempty" yaml:"DeviceRequests,omitempty" toml:"DeviceRequests,omitempty"` - LogConfig LogConfig `json:"LogConfig,omitempty" yaml:"LogConfig,omitempty" toml:"LogConfig,omitempty"` - SecurityOpt []string `json:"SecurityOpt,omitempty" yaml:"SecurityOpt,omitempty" toml:"SecurityOpt,omitempty"` - CgroupnsMode string `json:"CgroupnsMode,omitempty" yaml:"CgroupnsMode,omitempty" toml:"CgroupnsMode,omitempty"` // v1.40+ - Cgroup string `json:"Cgroup,omitempty" yaml:"Cgroup,omitempty" toml:"Cgroup,omitempty"` - CgroupParent string `json:"CgroupParent,omitempty" yaml:"CgroupParent,omitempty" toml:"CgroupParent,omitempty"` - Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty" toml:"Memory,omitempty"` - MemoryReservation int64 `json:"MemoryReservation,omitempty" yaml:"MemoryReservation,omitempty" toml:"MemoryReservation,omitempty"` - KernelMemory int64 `json:"KernelMemory,omitempty" yaml:"KernelMemory,omitempty" toml:"KernelMemory,omitempty"` - MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty" toml:"MemorySwap,omitempty"` - CPUShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty" toml:"CpuShares,omitempty"` - CPUSet string `json:"Cpuset,omitempty" yaml:"Cpuset,omitempty" toml:"Cpuset,omitempty"` - CPUSetCPUs string `json:"CpusetCpus,omitempty" yaml:"CpusetCpus,omitempty" toml:"CpusetCpus,omitempty"` - CPUSetMEMs string `json:"CpusetMems,omitempty" yaml:"CpusetMems,omitempty" toml:"CpusetMems,omitempty"` - CPUQuota int64 `json:"CpuQuota,omitempty" yaml:"CpuQuota,omitempty" toml:"CpuQuota,omitempty"` - CPUPeriod int64 `json:"CpuPeriod,omitempty" yaml:"CpuPeriod,omitempty" toml:"CpuPeriod,omitempty"` - CPURealtimePeriod int64 `json:"CpuRealtimePeriod,omitempty" yaml:"CpuRealtimePeriod,omitempty" toml:"CpuRealtimePeriod,omitempty"` - CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime,omitempty" yaml:"CpuRealtimeRuntime,omitempty" toml:"CpuRealtimeRuntime,omitempty"` - NanoCPUs int64 `json:"NanoCpus,omitempty" yaml:"NanoCpus,omitempty" toml:"NanoCpus,omitempty"` - BlkioWeight int64 `json:"BlkioWeight,omitempty" yaml:"BlkioWeight,omitempty" toml:"BlkioWeight,omitempty"` - BlkioWeightDevice []BlockWeight `json:"BlkioWeightDevice,omitempty" yaml:"BlkioWeightDevice,omitempty" toml:"BlkioWeightDevice,omitempty"` - BlkioDeviceReadBps []BlockLimit `json:"BlkioDeviceReadBps,omitempty" yaml:"BlkioDeviceReadBps,omitempty" toml:"BlkioDeviceReadBps,omitempty"` - BlkioDeviceReadIOps []BlockLimit `json:"BlkioDeviceReadIOps,omitempty" yaml:"BlkioDeviceReadIOps,omitempty" toml:"BlkioDeviceReadIOps,omitempty"` - BlkioDeviceWriteBps []BlockLimit `json:"BlkioDeviceWriteBps,omitempty" yaml:"BlkioDeviceWriteBps,omitempty" toml:"BlkioDeviceWriteBps,omitempty"` - BlkioDeviceWriteIOps []BlockLimit `json:"BlkioDeviceWriteIOps,omitempty" yaml:"BlkioDeviceWriteIOps,omitempty" toml:"BlkioDeviceWriteIOps,omitempty"` - Ulimits []ULimit `json:"Ulimits,omitempty" yaml:"Ulimits,omitempty" toml:"Ulimits,omitempty"` - VolumeDriver string `json:"VolumeDriver,omitempty" yaml:"VolumeDriver,omitempty" toml:"VolumeDriver,omitempty"` - OomScoreAdj int `json:"OomScoreAdj,omitempty" yaml:"OomScoreAdj,omitempty" toml:"OomScoreAdj,omitempty"` - MemorySwappiness *int64 `json:"MemorySwappiness,omitempty" yaml:"MemorySwappiness,omitempty" toml:"MemorySwappiness,omitempty"` - PidsLimit *int64 `json:"PidsLimit,omitempty" yaml:"PidsLimit,omitempty" toml:"PidsLimit,omitempty"` - OOMKillDisable *bool `json:"OomKillDisable,omitempty" yaml:"OomKillDisable,omitempty" toml:"OomKillDisable,omitempty"` - ShmSize int64 `json:"ShmSize,omitempty" yaml:"ShmSize,omitempty" toml:"ShmSize,omitempty"` - Tmpfs map[string]string `json:"Tmpfs,omitempty" yaml:"Tmpfs,omitempty" toml:"Tmpfs,omitempty"` - StorageOpt map[string]string `json:"StorageOpt,omitempty" yaml:"StorageOpt,omitempty" toml:"StorageOpt,omitempty"` - Sysctls map[string]string `json:"Sysctls,omitempty" yaml:"Sysctls,omitempty" toml:"Sysctls,omitempty"` - CPUCount int64 `json:"CpuCount,omitempty" yaml:"CpuCount,omitempty"` - CPUPercent int64 `json:"CpuPercent,omitempty" yaml:"CpuPercent,omitempty"` - IOMaximumBandwidth int64 `json:"IOMaximumBandwidth,omitempty" yaml:"IOMaximumBandwidth,omitempty"` - IOMaximumIOps int64 `json:"IOMaximumIOps,omitempty" yaml:"IOMaximumIOps,omitempty"` - Mounts []HostMount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"` - MaskedPaths []string `json:"MaskedPaths,omitempty" yaml:"MaskedPaths,omitempty" toml:"MaskedPaths,omitempty"` - ReadonlyPaths []string `json:"ReadonlyPaths,omitempty" yaml:"ReadonlyPaths,omitempty" toml:"ReadonlyPaths,omitempty"` - Runtime string `json:"Runtime,omitempty" yaml:"Runtime,omitempty" toml:"Runtime,omitempty"` - Init bool `json:",omitempty" yaml:",omitempty"` - Privileged bool `json:"Privileged,omitempty" yaml:"Privileged,omitempty" toml:"Privileged,omitempty"` - PublishAllPorts bool `json:"PublishAllPorts,omitempty" yaml:"PublishAllPorts,omitempty" toml:"PublishAllPorts,omitempty"` - ReadonlyRootfs bool `json:"ReadonlyRootfs,omitempty" yaml:"ReadonlyRootfs,omitempty" toml:"ReadonlyRootfs,omitempty"` - AutoRemove bool `json:"AutoRemove,omitempty" yaml:"AutoRemove,omitempty" toml:"AutoRemove,omitempty"` - Annotations map[string]string `json:"Annotations,omitempty" yaml:"Annotations,omitempty" toml:"Annotations,omitempty"` + Binds []string `json:"Binds,omitempty" yaml:"Binds,omitempty" toml:"Binds,omitempty"` + CapAdd []string `json:"CapAdd,omitempty" yaml:"CapAdd,omitempty" toml:"CapAdd,omitempty"` + CapDrop []string `json:"CapDrop,omitempty" yaml:"CapDrop,omitempty" toml:"CapDrop,omitempty"` + Capabilities []string `json:"Capabilities,omitempty" yaml:"Capabilities,omitempty" toml:"Capabilities,omitempty"` // Mutually exclusive w.r.t. CapAdd and CapDrop API v1.40 + GroupAdd []string `json:"GroupAdd,omitempty" yaml:"GroupAdd,omitempty" toml:"GroupAdd,omitempty"` + ContainerIDFile string `json:"ContainerIDFile,omitempty" yaml:"ContainerIDFile,omitempty" toml:"ContainerIDFile,omitempty"` + LxcConf []KeyValuePair `json:"LxcConf,omitempty" yaml:"LxcConf,omitempty" toml:"LxcConf,omitempty"` + PortBindings map[Port][]PortBinding `json:"PortBindings,omitempty" yaml:"PortBindings,omitempty" toml:"PortBindings,omitempty"` + Links []string `json:"Links,omitempty" yaml:"Links,omitempty" toml:"Links,omitempty"` + DNS []string `json:"Dns,omitempty" yaml:"Dns,omitempty" toml:"Dns,omitempty"` // For Docker API v1.10 and above only + DNSOptions []string `json:"DnsOptions,omitempty" yaml:"DnsOptions,omitempty" toml:"DnsOptions,omitempty"` + DNSSearch []string `json:"DnsSearch,omitempty" yaml:"DnsSearch,omitempty" toml:"DnsSearch,omitempty"` + ExtraHosts []string `json:"ExtraHosts,omitempty" yaml:"ExtraHosts,omitempty" toml:"ExtraHosts,omitempty"` + VolumesFrom []string `json:"VolumesFrom,omitempty" yaml:"VolumesFrom,omitempty" toml:"VolumesFrom,omitempty"` + UsernsMode string `json:"UsernsMode,omitempty" yaml:"UsernsMode,omitempty" toml:"UsernsMode,omitempty"` + NetworkMode string `json:"NetworkMode,omitempty" yaml:"NetworkMode,omitempty" toml:"NetworkMode,omitempty"` + IpcMode string `json:"IpcMode,omitempty" yaml:"IpcMode,omitempty" toml:"IpcMode,omitempty"` + Isolation string `json:"Isolation,omitempty" yaml:"Isolation,omitempty" toml:"Isolation,omitempty"` // Windows only + ConsoleSize [2]int `json:"ConsoleSize,omitempty" yaml:"ConsoleSize,omitempty" toml:"ConsoleSize,omitempty"` // Windows only height x width + PidMode string `json:"PidMode,omitempty" yaml:"PidMode,omitempty" toml:"PidMode,omitempty"` + UTSMode string `json:"UTSMode,omitempty" yaml:"UTSMode,omitempty" toml:"UTSMode,omitempty"` + RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty" yaml:"RestartPolicy,omitempty" toml:"RestartPolicy,omitempty"` + Devices []Device `json:"Devices,omitempty" yaml:"Devices,omitempty" toml:"Devices,omitempty"` + DeviceCgroupRules []string `json:"DeviceCgroupRules,omitempty" yaml:"DeviceCgroupRules,omitempty" toml:"DeviceCgroupRules,omitempty"` + DeviceRequests []DeviceRequest `json:"DeviceRequests,omitempty" yaml:"DeviceRequests,omitempty" toml:"DeviceRequests,omitempty"` + LogConfig LogConfig `json:"LogConfig,omitempty" yaml:"LogConfig,omitempty" toml:"LogConfig,omitempty"` + SecurityOpt []string `json:"SecurityOpt,omitempty" yaml:"SecurityOpt,omitempty" toml:"SecurityOpt,omitempty"` + CgroupnsMode string `json:"CgroupnsMode,omitempty" yaml:"CgroupnsMode,omitempty" toml:"CgroupnsMode,omitempty"` // v1.40+ + Cgroup string `json:"Cgroup,omitempty" yaml:"Cgroup,omitempty" toml:"Cgroup,omitempty"` + CgroupParent string `json:"CgroupParent,omitempty" yaml:"CgroupParent,omitempty" toml:"CgroupParent,omitempty"` + Memory int64 `json:"Memory,omitempty" yaml:"Memory,omitempty" toml:"Memory,omitempty"` + MemoryReservation int64 `json:"MemoryReservation,omitempty" yaml:"MemoryReservation,omitempty" toml:"MemoryReservation,omitempty"` + // Deprecated: KernelMemory is deprecated as of API 1.42 and removed in API 1.52. + KernelMemory int64 `json:"KernelMemory,omitempty" yaml:"KernelMemory,omitempty" toml:"KernelMemory,omitempty"` + MemorySwap int64 `json:"MemorySwap,omitempty" yaml:"MemorySwap,omitempty" toml:"MemorySwap,omitempty"` + CPUShares int64 `json:"CpuShares,omitempty" yaml:"CpuShares,omitempty" toml:"CpuShares,omitempty"` + CPUSet string `json:"Cpuset,omitempty" yaml:"Cpuset,omitempty" toml:"Cpuset,omitempty"` + CPUSetCPUs string `json:"CpusetCpus,omitempty" yaml:"CpusetCpus,omitempty" toml:"CpusetCpus,omitempty"` + CPUSetMEMs string `json:"CpusetMems,omitempty" yaml:"CpusetMems,omitempty" toml:"CpusetMems,omitempty"` + CPUQuota int64 `json:"CpuQuota,omitempty" yaml:"CpuQuota,omitempty" toml:"CpuQuota,omitempty"` + CPUPeriod int64 `json:"CpuPeriod,omitempty" yaml:"CpuPeriod,omitempty" toml:"CpuPeriod,omitempty"` + CPURealtimePeriod int64 `json:"CpuRealtimePeriod,omitempty" yaml:"CpuRealtimePeriod,omitempty" toml:"CpuRealtimePeriod,omitempty"` + CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime,omitempty" yaml:"CpuRealtimeRuntime,omitempty" toml:"CpuRealtimeRuntime,omitempty"` + NanoCPUs int64 `json:"NanoCpus,omitempty" yaml:"NanoCpus,omitempty" toml:"NanoCpus,omitempty"` + BlkioWeight int64 `json:"BlkioWeight,omitempty" yaml:"BlkioWeight,omitempty" toml:"BlkioWeight,omitempty"` + BlkioWeightDevice []BlockWeight `json:"BlkioWeightDevice,omitempty" yaml:"BlkioWeightDevice,omitempty" toml:"BlkioWeightDevice,omitempty"` + BlkioDeviceReadBps []BlockLimit `json:"BlkioDeviceReadBps,omitempty" yaml:"BlkioDeviceReadBps,omitempty" toml:"BlkioDeviceReadBps,omitempty"` + BlkioDeviceReadIOps []BlockLimit `json:"BlkioDeviceReadIOps,omitempty" yaml:"BlkioDeviceReadIOps,omitempty" toml:"BlkioDeviceReadIOps,omitempty"` + BlkioDeviceWriteBps []BlockLimit `json:"BlkioDeviceWriteBps,omitempty" yaml:"BlkioDeviceWriteBps,omitempty" toml:"BlkioDeviceWriteBps,omitempty"` + BlkioDeviceWriteIOps []BlockLimit `json:"BlkioDeviceWriteIOps,omitempty" yaml:"BlkioDeviceWriteIOps,omitempty" toml:"BlkioDeviceWriteIOps,omitempty"` + Ulimits []ULimit `json:"Ulimits,omitempty" yaml:"Ulimits,omitempty" toml:"Ulimits,omitempty"` + VolumeDriver string `json:"VolumeDriver,omitempty" yaml:"VolumeDriver,omitempty" toml:"VolumeDriver,omitempty"` + OomScoreAdj int `json:"OomScoreAdj,omitempty" yaml:"OomScoreAdj,omitempty" toml:"OomScoreAdj,omitempty"` + MemorySwappiness *int64 `json:"MemorySwappiness,omitempty" yaml:"MemorySwappiness,omitempty" toml:"MemorySwappiness,omitempty"` + PidsLimit *int64 `json:"PidsLimit,omitempty" yaml:"PidsLimit,omitempty" toml:"PidsLimit,omitempty"` + OOMKillDisable *bool `json:"OomKillDisable,omitempty" yaml:"OomKillDisable,omitempty" toml:"OomKillDisable,omitempty"` + ShmSize int64 `json:"ShmSize,omitempty" yaml:"ShmSize,omitempty" toml:"ShmSize,omitempty"` + Tmpfs map[string]string `json:"Tmpfs,omitempty" yaml:"Tmpfs,omitempty" toml:"Tmpfs,omitempty"` + StorageOpt map[string]string `json:"StorageOpt,omitempty" yaml:"StorageOpt,omitempty" toml:"StorageOpt,omitempty"` + Sysctls map[string]string `json:"Sysctls,omitempty" yaml:"Sysctls,omitempty" toml:"Sysctls,omitempty"` + CPUCount int64 `json:"CpuCount,omitempty" yaml:"CpuCount,omitempty"` + CPUPercent int64 `json:"CpuPercent,omitempty" yaml:"CpuPercent,omitempty"` + IOMaximumBandwidth int64 `json:"IOMaximumBandwidth,omitempty" yaml:"IOMaximumBandwidth,omitempty"` + IOMaximumIOps int64 `json:"IOMaximumIOps,omitempty" yaml:"IOMaximumIOps,omitempty"` + Mounts []HostMount `json:"Mounts,omitempty" yaml:"Mounts,omitempty" toml:"Mounts,omitempty"` + MaskedPaths []string `json:"MaskedPaths,omitempty" yaml:"MaskedPaths,omitempty" toml:"MaskedPaths,omitempty"` + ReadonlyPaths []string `json:"ReadonlyPaths,omitempty" yaml:"ReadonlyPaths,omitempty" toml:"ReadonlyPaths,omitempty"` + Runtime string `json:"Runtime,omitempty" yaml:"Runtime,omitempty" toml:"Runtime,omitempty"` + Init bool `json:",omitempty" yaml:",omitempty"` + Privileged bool `json:"Privileged,omitempty" yaml:"Privileged,omitempty" toml:"Privileged,omitempty"` + PublishAllPorts bool `json:"PublishAllPorts,omitempty" yaml:"PublishAllPorts,omitempty" toml:"PublishAllPorts,omitempty"` + ReadonlyRootfs bool `json:"ReadonlyRootfs,omitempty" yaml:"ReadonlyRootfs,omitempty" toml:"ReadonlyRootfs,omitempty"` + AutoRemove bool `json:"AutoRemove,omitempty" yaml:"AutoRemove,omitempty" toml:"AutoRemove,omitempty"` + Annotations map[string]string `json:"Annotations,omitempty" yaml:"Annotations,omitempty" toml:"Annotations,omitempty"` } // NetworkingConfig represents the container's networking configuration for each of its interfaces diff --git a/vendor/github.com/fsouza/go-dockerclient/container_update.go b/vendor/github.com/fsouza/go-dockerclient/container_update.go index d2116dbd738..b44fc8478bb 100644 --- a/vendor/github.com/fsouza/go-dockerclient/container_update.go +++ b/vendor/github.com/fsouza/go-dockerclient/container_update.go @@ -10,20 +10,21 @@ import ( // // See https://goo.gl/Y6fXUy for more details. type UpdateContainerOptions struct { - BlkioWeight int `json:"BlkioWeight"` - CPUShares int `json:"CpuShares"` - CPUPeriod int `json:"CpuPeriod"` - CPURealtimePeriod int64 `json:"CpuRealtimePeriod"` - CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime"` - CPUQuota int `json:"CpuQuota"` - CpusetCpus string `json:"CpusetCpus"` - CpusetMems string `json:"CpusetMems"` - Memory int `json:"Memory"` - MemorySwap int `json:"MemorySwap"` - MemoryReservation int `json:"MemoryReservation"` - KernelMemory int `json:"KernelMemory"` - RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty"` - Context context.Context + BlkioWeight int `json:"BlkioWeight"` + CPUShares int `json:"CpuShares"` + CPUPeriod int `json:"CpuPeriod"` + CPURealtimePeriod int64 `json:"CpuRealtimePeriod"` + CPURealtimeRuntime int64 `json:"CpuRealtimeRuntime"` + CPUQuota int `json:"CpuQuota"` + CpusetCpus string `json:"CpusetCpus"` + CpusetMems string `json:"CpusetMems"` + Memory int `json:"Memory"` + MemorySwap int `json:"MemorySwap"` + MemoryReservation int `json:"MemoryReservation"` + // Deprecated: KernelMemory is deprecated as of API 1.42 and removed in API 1.52. + KernelMemory int `json:"KernelMemory"` + RestartPolicy RestartPolicy `json:"RestartPolicy,omitempty"` + Context context.Context } // UpdateContainer updates the container at ID with the options diff --git a/vendor/github.com/fsouza/go-dockerclient/distribution.go b/vendor/github.com/fsouza/go-dockerclient/distribution.go index 6e5e12f7dd3..e892be5d87f 100644 --- a/vendor/github.com/fsouza/go-dockerclient/distribution.go +++ b/vendor/github.com/fsouza/go-dockerclient/distribution.go @@ -8,7 +8,7 @@ import ( "encoding/json" "net/http" - "github.com/docker/docker/api/types/registry" + "github.com/moby/moby/api/types/registry" ) // InspectDistribution returns image digest and platform information by contacting the registry diff --git a/vendor/github.com/fsouza/go-dockerclient/image.go b/vendor/github.com/fsouza/go-dockerclient/image.go index 614908c6606..5998ea70dd7 100644 --- a/vendor/github.com/fsouza/go-dockerclient/image.go +++ b/vendor/github.com/fsouza/go-dockerclient/image.go @@ -20,10 +20,11 @@ import ( // APIImages represent an image returned in the ListImages call. type APIImages struct { - ID string `json:"Id" yaml:"Id" toml:"Id"` - RepoTags []string `json:"RepoTags,omitempty" yaml:"RepoTags,omitempty" toml:"RepoTags,omitempty"` - Created int64 `json:"Created,omitempty" yaml:"Created,omitempty" toml:"Created,omitempty"` - Size int64 `json:"Size,omitempty" yaml:"Size,omitempty" toml:"Size,omitempty"` + ID string `json:"Id" yaml:"Id" toml:"Id"` + RepoTags []string `json:"RepoTags,omitempty" yaml:"RepoTags,omitempty" toml:"RepoTags,omitempty"` + Created int64 `json:"Created,omitempty" yaml:"Created,omitempty" toml:"Created,omitempty"` + Size int64 `json:"Size,omitempty" yaml:"Size,omitempty" toml:"Size,omitempty"` + // Deprecated: VirtualSize is deprecated as of API 1.44. Use Size instead. VirtualSize int64 `json:"VirtualSize,omitempty" yaml:"VirtualSize,omitempty" toml:"VirtualSize,omitempty"` ParentID string `json:"ParentId,omitempty" yaml:"ParentId,omitempty" toml:"ParentId,omitempty"` RepoDigests []string `json:"RepoDigests,omitempty" yaml:"RepoDigests,omitempty" toml:"RepoDigests,omitempty"` @@ -50,10 +51,11 @@ type Image struct { Config *Config `json:"Config,omitempty" yaml:"Config,omitempty" toml:"Config,omitempty"` Architecture string `json:"Architecture,omitempty" yaml:"Architecture,omitempty"` Size int64 `json:"Size,omitempty" yaml:"Size,omitempty" toml:"Size,omitempty"` - VirtualSize int64 `json:"VirtualSize,omitempty" yaml:"VirtualSize,omitempty" toml:"VirtualSize,omitempty"` - RepoDigests []string `json:"RepoDigests,omitempty" yaml:"RepoDigests,omitempty" toml:"RepoDigests,omitempty"` - RootFS *RootFS `json:"RootFS,omitempty" yaml:"RootFS,omitempty" toml:"RootFS,omitempty"` - OS string `json:"Os,omitempty" yaml:"Os,omitempty" toml:"Os,omitempty"` + // Deprecated: VirtualSize is deprecated as of API 1.44. Use Size instead. + VirtualSize int64 `json:"VirtualSize,omitempty" yaml:"VirtualSize,omitempty" toml:"VirtualSize,omitempty"` + RepoDigests []string `json:"RepoDigests,omitempty" yaml:"RepoDigests,omitempty" toml:"RepoDigests,omitempty"` + RootFS *RootFS `json:"RootFS,omitempty" yaml:"RootFS,omitempty" toml:"RootFS,omitempty"` + OS string `json:"Os,omitempty" yaml:"Os,omitempty" toml:"Os,omitempty"` } // ImagePre012 serves the same purpose as the Image type except that it is for diff --git a/vendor/github.com/fsouza/go-dockerclient/misc.go b/vendor/github.com/fsouza/go-dockerclient/misc.go index 827cd29dfc1..7fd5f841a16 100644 --- a/vendor/github.com/fsouza/go-dockerclient/misc.go +++ b/vendor/github.com/fsouza/go-dockerclient/misc.go @@ -10,8 +10,6 @@ import ( "net" "net/http" "strings" - - "github.com/docker/docker/api/types/swarm" ) // Version returns version information about the docker server. @@ -78,21 +76,24 @@ type DockerInfo struct { Isolation string InitBinary string DefaultRuntime string - Swarm swarm.Info + Swarm SwarmInfo LiveRestoreEnabled bool MemoryLimit bool SwapLimit bool - KernelMemory bool - CPUCfsPeriod bool `json:"CpuCfsPeriod"` - CPUCfsQuota bool `json:"CpuCfsQuota"` - CPUShares bool - CPUSet bool - IPv4Forwarding bool - BridgeNfIptables bool - BridgeNfIP6tables bool `json:"BridgeNfIp6tables"` - Debug bool - OomKillDisable bool - ExperimentalBuild bool + // Deprecated: KernelMemory is deprecated as of API 1.42 and removed in API 1.52. + KernelMemory bool + CPUCfsPeriod bool `json:"CpuCfsPeriod"` + CPUCfsQuota bool `json:"CpuCfsQuota"` + CPUShares bool + CPUSet bool + IPv4Forwarding bool + BridgeNfIptables bool + BridgeNfIP6tables bool `json:"BridgeNfIp6tables"` + Debug bool + OomKillDisable bool + ExperimentalBuild bool + CDISpecDirs []string `json:"CDISpecDirs,omitempty"` + Containerd *ContainerdInfo `json:"Containerd,omitempty"` } // Runtime describes an OCI runtime @@ -103,6 +104,22 @@ type Runtime struct { Args []string `json:"runtimeArgs"` } +// ContainerdInfo contains information about the containerd instance. +type ContainerdInfo struct { + Address string `json:"Address,omitempty"` + Namespaces struct { + Containers string `json:"Containers,omitempty"` + Plugins string `json:"Plugins,omitempty"` + } `json:"Namespaces,omitempty"` +} + +// SwarmInfo contains basic swarm information from docker info. +// Deprecated: Docker Swarm is deprecated. +type SwarmInfo struct { + NodeID string + NodeAddr string +} + // PluginsInfo is a struct with the plugins registered with the docker daemon // // for more information, see: https://goo.gl/bHUoz9 diff --git a/vendor/github.com/fsouza/go-dockerclient/network.go b/vendor/github.com/fsouza/go-dockerclient/network.go index 6932c8d8721..8bb77322ac8 100644 --- a/vendor/github.com/fsouza/go-dockerclient/network.go +++ b/vendor/github.com/fsouza/go-dockerclient/network.go @@ -123,6 +123,7 @@ type CreateNetworkOptions struct { CheckDuplicate bool `json:"CheckDuplicate" yaml:"CheckDuplicate" toml:"CheckDuplicate"` Internal bool `json:"Internal" yaml:"Internal" toml:"Internal"` EnableIPv6 bool `json:"EnableIPv6" yaml:"EnableIPv6" toml:"EnableIPv6"` + EnableIPv4 bool `json:"EnableIPv4,omitempty" yaml:"EnableIPv4,omitempty" toml:"EnableIPv4,omitempty"` Attachable bool `json:"Attachable" yaml:"Attachable" toml:"Attachable"` ConfigOnly bool `json:"ConfigOnly" yaml:"ConfigOnly" toml:"ConfigOnly"` Ingress bool `json:"Ingress" yaml:"Ingress" toml:"Ingress"` @@ -239,6 +240,7 @@ type EndpointConfig struct { GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen,omitempty" yaml:"GlobalIPv6PrefixLen,omitempty" toml:"GlobalIPv6PrefixLen,omitempty"` MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty" toml:"MacAddress,omitempty"` DriverOpts map[string]string `json:"DriverOpts,omitempty" yaml:"DriverOpts,omitempty" toml:"DriverOpts,omitempty"` + GwPriority int `json:"GwPriority,omitempty" yaml:"GwPriority,omitempty" toml:"GwPriority,omitempty"` } // EndpointIPAMConfig represents IPAM configurations for an diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm.go b/vendor/github.com/fsouza/go-dockerclient/swarm.go deleted file mode 100644 index ae37cd1e8c3..00000000000 --- a/vendor/github.com/fsouza/go-dockerclient/swarm.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2016 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "context" - "encoding/json" - "errors" - "net/http" - "net/url" - "strconv" - - "github.com/docker/docker/api/types/swarm" -) - -var ( - // ErrNodeAlreadyInSwarm is the error returned by InitSwarm and JoinSwarm - // when the node is already part of a Swarm. - ErrNodeAlreadyInSwarm = errors.New("node already in a Swarm") - - // ErrNodeNotInSwarm is the error returned by LeaveSwarm and UpdateSwarm - // when the node is not part of a Swarm. - ErrNodeNotInSwarm = errors.New("node is not in a Swarm") -) - -// InitSwarmOptions specify parameters to the InitSwarm function. -// See https://goo.gl/hzkgWu for more details. -type InitSwarmOptions struct { - swarm.InitRequest - Context context.Context -} - -// InitSwarm initializes a new Swarm and returns the node ID. -// See https://goo.gl/ZWyG1M for more details. -func (c *Client) InitSwarm(opts InitSwarmOptions) (string, error) { - path := "/swarm/init" - resp, err := c.do(http.MethodPost, path, doOptions{ - data: opts.InitRequest, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - var e *Error - if errors.As(err, &e) && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { - return "", ErrNodeAlreadyInSwarm - } - return "", err - } - defer resp.Body.Close() - var response string - if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { - return "", err - } - return response, nil -} - -// JoinSwarmOptions specify parameters to the JoinSwarm function. -// See https://goo.gl/TdhJWU for more details. -type JoinSwarmOptions struct { - swarm.JoinRequest - Context context.Context -} - -// JoinSwarm joins an existing Swarm. -// See https://goo.gl/N59IP1 for more details. -func (c *Client) JoinSwarm(opts JoinSwarmOptions) error { - path := "/swarm/join" - resp, err := c.do(http.MethodPost, path, doOptions{ - data: opts.JoinRequest, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - var e *Error - if errors.As(err, &e) && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { - return ErrNodeAlreadyInSwarm - } - } - resp.Body.Close() - return err -} - -// LeaveSwarmOptions specify parameters to the LeaveSwarm function. -// See https://goo.gl/UWDlLg for more details. -type LeaveSwarmOptions struct { - Force bool - Context context.Context -} - -// LeaveSwarm leaves a Swarm. -// See https://goo.gl/FTX1aD for more details. -func (c *Client) LeaveSwarm(opts LeaveSwarmOptions) error { - params := make(url.Values) - params.Set("force", strconv.FormatBool(opts.Force)) - path := "/swarm/leave?" + params.Encode() - resp, err := c.do(http.MethodPost, path, doOptions{ - context: opts.Context, - }) - if err != nil { - var e *Error - if errors.As(err, &e) && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { - return ErrNodeNotInSwarm - } - } - resp.Body.Close() - return err -} - -// UpdateSwarmOptions specify parameters to the UpdateSwarm function. -// See https://goo.gl/vFbq36 for more details. -type UpdateSwarmOptions struct { - Version int - RotateWorkerToken bool - RotateManagerToken bool - Swarm swarm.Spec - Context context.Context -} - -// UpdateSwarm updates a Swarm. -// See https://goo.gl/iJFnsw for more details. -func (c *Client) UpdateSwarm(opts UpdateSwarmOptions) error { - params := make(url.Values) - params.Set("version", strconv.Itoa(opts.Version)) - params.Set("rotateWorkerToken", strconv.FormatBool(opts.RotateWorkerToken)) - params.Set("rotateManagerToken", strconv.FormatBool(opts.RotateManagerToken)) - path := "/swarm/update?" + params.Encode() - resp, err := c.do(http.MethodPost, path, doOptions{ - data: opts.Swarm, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - var e *Error - if errors.As(err, &e) && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { - return ErrNodeNotInSwarm - } - } - resp.Body.Close() - return err -} - -// InspectSwarm inspects a Swarm. -// See https://goo.gl/MFwgX9 for more details. -func (c *Client) InspectSwarm(ctx context.Context) (swarm.Swarm, error) { - response := swarm.Swarm{} - resp, err := c.do(http.MethodGet, "/swarm", doOptions{ - context: ctx, - }) - if err != nil { - var e *Error - if errors.As(err, &e) && (e.Status == http.StatusNotAcceptable || e.Status == http.StatusServiceUnavailable) { - return response, ErrNodeNotInSwarm - } - return response, err - } - defer resp.Body.Close() - err = json.NewDecoder(resp.Body).Decode(&response) - return response, err -} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go b/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go deleted file mode 100644 index 055e99544aa..00000000000 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_configs.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2017 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "context" - "encoding/json" - "errors" - "net/http" - "net/url" - "strconv" - - "github.com/docker/docker/api/types/swarm" -) - -// NoSuchConfig is the error returned when a given config does not exist. -type NoSuchConfig struct { - ID string - Err error -} - -func (err *NoSuchConfig) Error() string { - if err.Err != nil { - return err.Err.Error() - } - return "No such config: " + err.ID -} - -// CreateConfigOptions specify parameters to the CreateConfig function. -// -// See https://goo.gl/KrVjHz for more details. -type CreateConfigOptions struct { - Auth AuthConfiguration `qs:"-"` - swarm.ConfigSpec - Context context.Context -} - -// CreateConfig creates a new config, returning the config instance -// or an error in case of failure. -// -// See https://goo.gl/KrVjHz for more details. -func (c *Client) CreateConfig(opts CreateConfigOptions) (*swarm.Config, error) { - headers, err := headersWithAuth(opts.Auth) - if err != nil { - return nil, err - } - path := "/configs/create?" + queryString(opts) - resp, err := c.do(http.MethodPost, path, doOptions{ - headers: headers, - data: opts.ConfigSpec, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var config swarm.Config - if err := json.NewDecoder(resp.Body).Decode(&config); err != nil { - return nil, err - } - return &config, nil -} - -// RemoveConfigOptions encapsulates options to remove a config. -// -// See https://goo.gl/Tqrtya for more details. -type RemoveConfigOptions struct { - ID string `qs:"-"` - Context context.Context -} - -// RemoveConfig removes a config, returning an error in case of failure. -// -// See https://goo.gl/Tqrtya for more details. -func (c *Client) RemoveConfig(opts RemoveConfigOptions) error { - path := "/configs/" + opts.ID - resp, err := c.do(http.MethodDelete, path, doOptions{context: opts.Context}) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return &NoSuchConfig{ID: opts.ID} - } - return err - } - resp.Body.Close() - return nil -} - -// UpdateConfigOptions specify parameters to the UpdateConfig function. -// -// See https://goo.gl/wu3MmS for more details. -type UpdateConfigOptions struct { - Auth AuthConfiguration `qs:"-"` - swarm.ConfigSpec - Context context.Context - Version uint64 -} - -// UpdateConfig updates the config at ID with the options -// -// Only label can be updated -// https://docs.docker.com/engine/api/v1.33/#operation/ConfigUpdate -// See https://goo.gl/wu3MmS for more details. -func (c *Client) UpdateConfig(id string, opts UpdateConfigOptions) error { - headers, err := headersWithAuth(opts.Auth) - if err != nil { - return err - } - params := make(url.Values) - params.Set("version", strconv.FormatUint(opts.Version, 10)) - resp, err := c.do(http.MethodPost, "/configs/"+id+"/update?"+params.Encode(), doOptions{ - headers: headers, - data: opts.ConfigSpec, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return &NoSuchConfig{ID: id} - } - return err - } - defer resp.Body.Close() - return nil -} - -// InspectConfig returns information about a config by its ID. -// -// See https://goo.gl/dHmr75 for more details. -func (c *Client) InspectConfig(id string) (*swarm.Config, error) { - path := "/configs/" + id - resp, err := c.do(http.MethodGet, path, doOptions{}) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return nil, &NoSuchConfig{ID: id} - } - return nil, err - } - defer resp.Body.Close() - var config swarm.Config - if err := json.NewDecoder(resp.Body).Decode(&config); err != nil { - return nil, err - } - return &config, nil -} - -// ListConfigsOptions specify parameters to the ListConfigs function. -// -// See https://goo.gl/DwvNMd for more details. -type ListConfigsOptions struct { - Filters map[string][]string - Context context.Context -} - -// ListConfigs returns a slice of configs matching the given criteria. -// -// See https://goo.gl/DwvNMd for more details. -func (c *Client) ListConfigs(opts ListConfigsOptions) ([]swarm.Config, error) { - path := "/configs?" + queryString(opts) - resp, err := c.do(http.MethodGet, path, doOptions{context: opts.Context}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var configs []swarm.Config - if err := json.NewDecoder(resp.Body).Decode(&configs); err != nil { - return nil, err - } - return configs, nil -} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_node.go b/vendor/github.com/fsouza/go-dockerclient/swarm_node.go deleted file mode 100644 index 8538a167b96..00000000000 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_node.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2016 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "context" - "encoding/json" - "errors" - "net/http" - "net/url" - "strconv" - - "github.com/docker/docker/api/types/swarm" -) - -// NoSuchNode is the error returned when a given node does not exist. -type NoSuchNode struct { - ID string - Err error -} - -func (err *NoSuchNode) Error() string { - if err.Err != nil { - return err.Err.Error() - } - return "No such node: " + err.ID -} - -// ListNodesOptions specify parameters to the ListNodes function. -// -// See http://goo.gl/3K4GwU for more details. -type ListNodesOptions struct { - Filters map[string][]string - Context context.Context -} - -// ListNodes returns a slice of nodes matching the given criteria. -// -// See http://goo.gl/3K4GwU for more details. -func (c *Client) ListNodes(opts ListNodesOptions) ([]swarm.Node, error) { - path := "/nodes?" + queryString(opts) - resp, err := c.do(http.MethodGet, path, doOptions{context: opts.Context}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var nodes []swarm.Node - if err := json.NewDecoder(resp.Body).Decode(&nodes); err != nil { - return nil, err - } - return nodes, nil -} - -// InspectNode returns information about a node by its ID. -// -// See http://goo.gl/WjkTOk for more details. -func (c *Client) InspectNode(id string) (*swarm.Node, error) { - resp, err := c.do(http.MethodGet, "/nodes/"+id, doOptions{}) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return nil, &NoSuchNode{ID: id} - } - return nil, err - } - defer resp.Body.Close() - var node swarm.Node - if err := json.NewDecoder(resp.Body).Decode(&node); err != nil { - return nil, err - } - return &node, nil -} - -// UpdateNodeOptions specify parameters to the NodeUpdate function. -// -// See http://goo.gl/VPBFgA for more details. -type UpdateNodeOptions struct { - swarm.NodeSpec - Version uint64 - Context context.Context -} - -// UpdateNode updates a node. -// -// See http://goo.gl/VPBFgA for more details. -func (c *Client) UpdateNode(id string, opts UpdateNodeOptions) error { - params := make(url.Values) - params.Set("version", strconv.FormatUint(opts.Version, 10)) - path := "/nodes/" + id + "/update?" + params.Encode() - resp, err := c.do(http.MethodPost, path, doOptions{ - context: opts.Context, - forceJSON: true, - data: opts.NodeSpec, - }) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return &NoSuchNode{ID: id} - } - return err - } - resp.Body.Close() - return nil -} - -// RemoveNodeOptions specify parameters to the RemoveNode function. -// -// See http://goo.gl/0SNvYg for more details. -type RemoveNodeOptions struct { - ID string - Force bool - Context context.Context -} - -// RemoveNode removes a node. -// -// See http://goo.gl/0SNvYg for more details. -func (c *Client) RemoveNode(opts RemoveNodeOptions) error { - params := make(url.Values) - params.Set("force", strconv.FormatBool(opts.Force)) - path := "/nodes/" + opts.ID + "?" + params.Encode() - resp, err := c.do(http.MethodDelete, path, doOptions{context: opts.Context}) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return &NoSuchNode{ID: opts.ID} - } - return err - } - resp.Body.Close() - return nil -} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go b/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go deleted file mode 100644 index 375e6e5ba37..00000000000 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_secrets.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2016 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "context" - "encoding/json" - "errors" - "net/http" - "net/url" - "strconv" - - "github.com/docker/docker/api/types/swarm" -) - -// NoSuchSecret is the error returned when a given secret does not exist. -type NoSuchSecret struct { - ID string - Err error -} - -func (err *NoSuchSecret) Error() string { - if err.Err != nil { - return err.Err.Error() - } - return "No such secret: " + err.ID -} - -// CreateSecretOptions specify parameters to the CreateSecret function. -// -// See https://goo.gl/KrVjHz for more details. -type CreateSecretOptions struct { - Auth AuthConfiguration `qs:"-"` - swarm.SecretSpec - Context context.Context -} - -// CreateSecret creates a new secret, returning the secret instance -// or an error in case of failure. -// -// See https://goo.gl/KrVjHz for more details. -func (c *Client) CreateSecret(opts CreateSecretOptions) (*swarm.Secret, error) { - headers, err := headersWithAuth(opts.Auth) - if err != nil { - return nil, err - } - path := "/secrets/create?" + queryString(opts) - resp, err := c.do(http.MethodPost, path, doOptions{ - headers: headers, - data: opts.SecretSpec, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var secret swarm.Secret - if err := json.NewDecoder(resp.Body).Decode(&secret); err != nil { - return nil, err - } - return &secret, nil -} - -// RemoveSecretOptions encapsulates options to remove a secret. -// -// See https://goo.gl/Tqrtya for more details. -type RemoveSecretOptions struct { - ID string `qs:"-"` - Context context.Context -} - -// RemoveSecret removes a secret, returning an error in case of failure. -// -// See https://goo.gl/Tqrtya for more details. -func (c *Client) RemoveSecret(opts RemoveSecretOptions) error { - path := "/secrets/" + opts.ID - resp, err := c.do(http.MethodDelete, path, doOptions{context: opts.Context}) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return &NoSuchSecret{ID: opts.ID} - } - return err - } - resp.Body.Close() - return nil -} - -// UpdateSecretOptions specify parameters to the UpdateSecret function. -// -// Only label can be updated -// See https://docs.docker.com/engine/api/v1.33/#operation/SecretUpdate -// See https://goo.gl/wu3MmS for more details. -type UpdateSecretOptions struct { - Auth AuthConfiguration `qs:"-"` - swarm.SecretSpec - Context context.Context - Version uint64 -} - -// UpdateSecret updates the secret at ID with the options -// -// See https://goo.gl/wu3MmS for more details. -func (c *Client) UpdateSecret(id string, opts UpdateSecretOptions) error { - headers, err := headersWithAuth(opts.Auth) - if err != nil { - return err - } - params := make(url.Values) - params.Set("version", strconv.FormatUint(opts.Version, 10)) - resp, err := c.do(http.MethodPost, "/secrets/"+id+"/update?"+params.Encode(), doOptions{ - headers: headers, - data: opts.SecretSpec, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return &NoSuchSecret{ID: id} - } - return err - } - defer resp.Body.Close() - return nil -} - -// InspectSecret returns information about a secret by its ID. -// -// See https://goo.gl/dHmr75 for more details. -func (c *Client) InspectSecret(id string) (*swarm.Secret, error) { - path := "/secrets/" + id - resp, err := c.do(http.MethodGet, path, doOptions{}) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return nil, &NoSuchSecret{ID: id} - } - return nil, err - } - defer resp.Body.Close() - var secret swarm.Secret - if err := json.NewDecoder(resp.Body).Decode(&secret); err != nil { - return nil, err - } - return &secret, nil -} - -// ListSecretsOptions specify parameters to the ListSecrets function. -// -// See https://goo.gl/DwvNMd for more details. -type ListSecretsOptions struct { - Filters map[string][]string - Context context.Context -} - -// ListSecrets returns a slice of secrets matching the given criteria. -// -// See https://goo.gl/DwvNMd for more details. -func (c *Client) ListSecrets(opts ListSecretsOptions) ([]swarm.Secret, error) { - path := "/secrets?" + queryString(opts) - resp, err := c.do(http.MethodGet, path, doOptions{context: opts.Context}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var secrets []swarm.Secret - if err := json.NewDecoder(resp.Body).Decode(&secrets); err != nil { - return nil, err - } - return secrets, nil -} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_service.go b/vendor/github.com/fsouza/go-dockerclient/swarm_service.go deleted file mode 100644 index 0d0f007b722..00000000000 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_service.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2016 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "context" - "encoding/json" - "errors" - "io" - "net/http" - "time" - - "github.com/docker/docker/api/types/swarm" -) - -// NoSuchService is the error returned when a given service does not exist. -type NoSuchService struct { - ID string - Err error -} - -func (err *NoSuchService) Error() string { - if err.Err != nil { - return err.Err.Error() - } - return "No such service: " + err.ID -} - -// CreateServiceOptions specify parameters to the CreateService function. -// -// See https://goo.gl/KrVjHz for more details. -type CreateServiceOptions struct { - Auth AuthConfiguration `qs:"-"` - swarm.ServiceSpec - Context context.Context -} - -// CreateService creates a new service, returning the service instance -// or an error in case of failure. -// -// See https://goo.gl/KrVjHz for more details. -func (c *Client) CreateService(opts CreateServiceOptions) (*swarm.Service, error) { - headers, err := headersWithAuth(opts.Auth) - if err != nil { - return nil, err - } - path := "/services/create?" + queryString(opts) - resp, err := c.do(http.MethodPost, path, doOptions{ - headers: headers, - data: opts.ServiceSpec, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var service swarm.Service - if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { - return nil, err - } - return &service, nil -} - -// RemoveServiceOptions encapsulates options to remove a service. -// -// See https://goo.gl/Tqrtya for more details. -type RemoveServiceOptions struct { - ID string `qs:"-"` - Context context.Context -} - -// RemoveService removes a service, returning an error in case of failure. -// -// See https://goo.gl/Tqrtya for more details. -func (c *Client) RemoveService(opts RemoveServiceOptions) error { - path := "/services/" + opts.ID - resp, err := c.do(http.MethodDelete, path, doOptions{context: opts.Context}) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return &NoSuchService{ID: opts.ID} - } - return err - } - resp.Body.Close() - return nil -} - -// UpdateServiceOptions specify parameters to the UpdateService function. -// -// See https://goo.gl/wu3MmS for more details. -type UpdateServiceOptions struct { - Auth AuthConfiguration `qs:"-"` - swarm.ServiceSpec `qs:"-"` - Context context.Context - Version uint64 - Rollback string -} - -// UpdateService updates the service at ID with the options -// -// See https://goo.gl/wu3MmS for more details. -func (c *Client) UpdateService(id string, opts UpdateServiceOptions) error { - headers, err := headersWithAuth(opts.Auth) - if err != nil { - return err - } - resp, err := c.do(http.MethodPost, "/services/"+id+"/update?"+queryString(opts), doOptions{ - headers: headers, - data: opts.ServiceSpec, - forceJSON: true, - context: opts.Context, - }) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return &NoSuchService{ID: id} - } - return err - } - defer resp.Body.Close() - return nil -} - -// InspectService returns information about a service by its ID. -// -// See https://goo.gl/dHmr75 for more details. -func (c *Client) InspectService(id string) (*swarm.Service, error) { - path := "/services/" + id - resp, err := c.do(http.MethodGet, path, doOptions{}) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return nil, &NoSuchService{ID: id} - } - return nil, err - } - defer resp.Body.Close() - var service swarm.Service - if err := json.NewDecoder(resp.Body).Decode(&service); err != nil { - return nil, err - } - return &service, nil -} - -// ListServicesOptions specify parameters to the ListServices function. -// -// See https://goo.gl/DwvNMd for more details. -type ListServicesOptions struct { - Filters map[string][]string - Status bool - Context context.Context -} - -// ListServices returns a slice of services matching the given criteria. -// -// See https://goo.gl/DwvNMd for more details. -func (c *Client) ListServices(opts ListServicesOptions) ([]swarm.Service, error) { - path := "/services?" + queryString(opts) - resp, err := c.do(http.MethodGet, path, doOptions{context: opts.Context}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var services []swarm.Service - if err := json.NewDecoder(resp.Body).Decode(&services); err != nil { - return nil, err - } - return services, nil -} - -// LogsServiceOptions represents the set of options used when getting logs from a -// service. -type LogsServiceOptions struct { - Context context.Context - Service string `qs:"-"` - OutputStream io.Writer `qs:"-"` - ErrorStream io.Writer `qs:"-"` - InactivityTimeout time.Duration `qs:"-"` - Tail string - Since int64 - - // Use raw terminal? Usually true when the container contains a TTY. - RawTerminal bool `qs:"-"` - Follow bool - Stdout bool - Stderr bool - Timestamps bool - Details bool -} - -// GetServiceLogs gets stdout and stderr logs from the specified service. -// -// When LogsServiceOptions.RawTerminal is set to false, go-dockerclient will multiplex -// the streams and send the containers stdout to LogsServiceOptions.OutputStream, and -// stderr to LogsServiceOptions.ErrorStream. -// -// When LogsServiceOptions.RawTerminal is true, callers will get the raw stream on -// LogsServiceOptions.OutputStream. -func (c *Client) GetServiceLogs(opts LogsServiceOptions) error { - if opts.Service == "" { - return &NoSuchService{ID: opts.Service} - } - if opts.Tail == "" { - opts.Tail = "all" - } - path := "/services/" + opts.Service + "/logs?" + queryString(opts) - return c.stream(http.MethodGet, path, streamOptions{ - setRawTerminal: opts.RawTerminal, - stdout: opts.OutputStream, - stderr: opts.ErrorStream, - inactivityTimeout: opts.InactivityTimeout, - context: opts.Context, - }) -} diff --git a/vendor/github.com/fsouza/go-dockerclient/swarm_task.go b/vendor/github.com/fsouza/go-dockerclient/swarm_task.go deleted file mode 100644 index 9321368d3f3..00000000000 --- a/vendor/github.com/fsouza/go-dockerclient/swarm_task.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2016 go-dockerclient authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package docker - -import ( - "context" - "encoding/json" - "errors" - "net/http" - - "github.com/docker/docker/api/types/swarm" -) - -// NoSuchTask is the error returned when a given task does not exist. -type NoSuchTask struct { - ID string - Err error -} - -func (err *NoSuchTask) Error() string { - if err.Err != nil { - return err.Err.Error() - } - return "No such task: " + err.ID -} - -// ListTasksOptions specify parameters to the ListTasks function. -// -// See http://goo.gl/rByLzw for more details. -type ListTasksOptions struct { - Filters map[string][]string - Context context.Context -} - -// ListTasks returns a slice of tasks matching the given criteria. -// -// See http://goo.gl/rByLzw for more details. -func (c *Client) ListTasks(opts ListTasksOptions) ([]swarm.Task, error) { - path := "/tasks?" + queryString(opts) - resp, err := c.do(http.MethodGet, path, doOptions{context: opts.Context}) - if err != nil { - return nil, err - } - defer resp.Body.Close() - var tasks []swarm.Task - if err := json.NewDecoder(resp.Body).Decode(&tasks); err != nil { - return nil, err - } - return tasks, nil -} - -// InspectTask returns information about a task by its ID. -// -// See http://goo.gl/kyziuq for more details. -func (c *Client) InspectTask(id string) (*swarm.Task, error) { - resp, err := c.do(http.MethodGet, "/tasks/"+id, doOptions{}) - if err != nil { - var e *Error - if errors.As(err, &e) && e.Status == http.StatusNotFound { - return nil, &NoSuchTask{ID: id} - } - return nil, err - } - defer resp.Body.Close() - var task swarm.Task - if err := json.NewDecoder(resp.Body).Decode(&task); err != nil { - return nil, err - } - return &task, nil -} diff --git a/vendor/github.com/fsouza/go-dockerclient/tar.go b/vendor/github.com/fsouza/go-dockerclient/tar.go index 0d40c644abd..434a5b3d6af 100644 --- a/vendor/github.com/fsouza/go-dockerclient/tar.go +++ b/vendor/github.com/fsouza/go-dockerclient/tar.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/moby/go-archive" + "github.com/moby/go-archive/compression" "github.com/moby/patternmatcher" ) @@ -59,7 +60,7 @@ func createTarStream(srcPath, dockerfilePath string) (io.ReadCloser, error) { tarOpts := &archive.TarOptions{ ExcludePatterns: excludes, IncludeFiles: includes, - Compression: archive.Uncompressed, + Compression: compression.None, NoLchown: true, } return archive.TarWithOptions(srcPath, tarOpts) diff --git a/vendor/github.com/google/go-containerregistry/pkg/v1/config.go b/vendor/github.com/google/go-containerregistry/pkg/v1/config.go index 960c93b5f41..b62d8482691 100644 --- a/vendor/github.com/google/go-containerregistry/pkg/v1/config.go +++ b/vendor/github.com/google/go-containerregistry/pkg/v1/config.go @@ -27,10 +27,11 @@ import ( // docker_version and os.version are not part of the spec but included // for backwards compatibility. type ConfigFile struct { - Architecture string `json:"architecture"` - Author string `json:"author,omitempty"` - Container string `json:"container,omitempty"` - Created Time `json:"created,omitempty"` + Architecture string `json:"architecture"` + Author string `json:"author,omitempty"` + Container string `json:"container,omitempty"` + Created Time `json:"created,omitempty"` + // Deprecated: This field is deprecated and will be removed in the next release. DockerVersion string `json:"docker_version,omitempty"` History []History `json:"history,omitempty"` OS string `json:"os"` diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/directives.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/directives.go index b757e7548de..6638170cdb1 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/directives.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/directives.go @@ -4,9 +4,10 @@ import ( "bufio" "bytes" "encoding/json" - "fmt" "regexp" "strings" + "sync" + "unicode" "github.com/pkg/errors" ) @@ -32,14 +33,18 @@ type Directive struct { // DirectiveParser is a parser for Dockerfile directives that enforces the // quirks of the directive parser. type DirectiveParser struct { - line int - regexp *regexp.Regexp - seen map[string]struct{} - done bool + line int + comment *string + seen map[string]struct{} + done bool } -func (d *DirectiveParser) setComment(comment string) { - d.regexp = regexp.MustCompile(fmt.Sprintf(`^%s\s*([a-zA-Z][a-zA-Z0-9]*)\s*=\s*(.+?)\s*$`, comment)) +var directiveRegexp = sync.OnceValue(func() *regexp.Regexp { + return regexp.MustCompile(`^([a-zA-Z][a-zA-Z0-9]*)\s*=\s*(.+?)\s*$`) +}) + +func (d *DirectiveParser) SetComment(comment string) { + d.comment = &comment } func (d *DirectiveParser) ParseLine(line []byte) (*Directive, error) { @@ -47,11 +52,18 @@ func (d *DirectiveParser) ParseLine(line []byte) (*Directive, error) { if d.done { return nil, nil } - if d.regexp == nil { - d.setComment("#") + if d.comment == nil { + d.SetComment("#") + } + + line, ok := bytes.CutPrefix(line, []byte(*d.comment)) + if !ok { + d.done = true + return nil, nil } + line = bytes.TrimLeftFunc(line, unicode.IsSpace) - match := d.regexp.FindSubmatch(line) + match := directiveRegexp().FindSubmatch(line) if len(match) == 0 { d.done = true return nil, nil @@ -142,7 +154,7 @@ func parseDirective(key string, dt []byte, anyFormat bool) (string, string, []Ra // use directive with different comment prefix, and search for //key= directiveParser = DirectiveParser{line: line} - directiveParser.setComment("//") + directiveParser.SetComment("//") if syntax, cmdline, loc, ok := detectDirectiveFromParser(key, dt, directiveParser); ok { return syntax, cmdline, loc, true } diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/parser.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/parser.go index 2f0da0222ac..209562d35f6 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/parser.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/parser.go @@ -49,25 +49,29 @@ func (node *Node) Location() []Range { // Dump dumps the AST defined by `node` as a list of sexps. // Returns a string suitable for printing. func (node *Node) Dump() string { - str := strings.ToLower(node.Value) + var str strings.Builder + str.WriteString(strings.ToLower(node.Value)) if len(node.Flags) > 0 { - str += fmt.Sprintf(" %q", node.Flags) + fmt.Fprintf(&str, " %q", node.Flags) } for _, n := range node.Children { - str += "(" + n.Dump() + ")\n" + str.WriteByte('(') + str.WriteString(n.Dump()) + str.WriteString(")\n") } for n := node.Next; n != nil; n = n.Next { + str.WriteByte(' ') if len(n.Children) > 0 { - str += " " + n.Dump() + str.WriteString(n.Dump()) } else { - str += " " + strconv.Quote(n.Value) + str.WriteString(strconv.Quote(n.Value)) } } - return strings.TrimSpace(str) + return strings.TrimSpace(str.String()) } func (node *Node) lines(start, end int) { @@ -367,6 +371,8 @@ func Parse(rwc io.Reader) (*Result, error) { for _, heredoc := range heredocs { terminator := []byte(heredoc.Name) terminated := false + var content strings.Builder + content.WriteString(heredoc.Content) for scanner.Scan() { bytesRead := scanner.Bytes() currentLine++ @@ -379,12 +385,13 @@ func Parse(rwc io.Reader) (*Result, error) { terminated = true break } - heredoc.Content += string(bytesRead) + content.Write(bytesRead) } if !terminated { return nil, withLocation(errors.New("unterminated heredoc"), startLine, currentLine) } + heredoc.Content = content.String() child.Heredocs = append(child.Heredocs, heredoc) } } diff --git a/vendor/github.com/moby/buildkit/util/stack/stack.pb.go b/vendor/github.com/moby/buildkit/util/stack/stack.pb.go index 583565672bb..103e662ff35 100644 --- a/vendor/github.com/moby/buildkit/util/stack/stack.pb.go +++ b/vendor/github.com/moby/buildkit/util/stack/stack.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 +// protoc-gen-go v1.36.11 // protoc v3.11.4 // source: github.com/moby/buildkit/util/stack/stack.proto diff --git a/vendor/github.com/moby/go-archive/archive.go b/vendor/github.com/moby/go-archive/archive.go index 7a105aef189..8dce2e6e2af 100644 --- a/vendor/github.com/moby/go-archive/archive.go +++ b/vendor/github.com/moby/go-archive/archive.go @@ -36,10 +36,6 @@ import ( const ImpliedDirectoryMode = 0o755 type ( - // Compression is the state represents if compressed or not. - // - // Deprecated: use [compression.Compression]. - Compression = compression.Compression // WhiteoutFormat is the format of whiteouts unpacked WhiteoutFormat int @@ -95,14 +91,6 @@ func NewDefaultArchiver() *Archiver { // in order for the test to pass. type breakoutError error -const ( - Uncompressed = compression.None // Deprecated: use [compression.None]. - Bzip2 = compression.Bzip2 // Deprecated: use [compression.Bzip2]. - Gzip = compression.Gzip // Deprecated: use [compression.Gzip]. - Xz = compression.Xz // Deprecated: use [compression.Xz]. - Zstd = compression.Zstd // Deprecated: use [compression.Zstd]. -) - const ( AUFSWhiteoutFormat WhiteoutFormat = 0 // AUFSWhiteoutFormat is the default format for whiteouts OverlayWhiteoutFormat WhiteoutFormat = 1 // OverlayWhiteoutFormat formats whiteout according to the overlay standard. @@ -126,27 +114,6 @@ func IsArchivePath(path string) bool { return err == nil } -// DetectCompression detects the compression algorithm of the source. -// -// Deprecated: use [compression.Detect]. -func DetectCompression(source []byte) compression.Compression { - return compression.Detect(source) -} - -// DecompressStream decompresses the archive and returns a ReaderCloser with the decompressed archive. -// -// Deprecated: use [compression.DecompressStream]. -func DecompressStream(archive io.Reader) (io.ReadCloser, error) { - return compression.DecompressStream(archive) -} - -// CompressStream compresses the dest with specified compression algorithm. -// -// Deprecated: use [compression.CompressStream]. -func CompressStream(dest io.Writer, comp compression.Compression) (io.WriteCloser, error) { - return compression.CompressStream(dest, comp) -} - // TarModifierFunc is a function that can be passed to ReplaceFileTarWrapper to // modify the contents or header of an entry in the archive. If the file already // exists in the archive the TarModifierFunc will be called with the Header and @@ -235,13 +202,6 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi return pipeReader } -// FileInfoHeaderNoLookups creates a partially-populated tar.Header from fi. -// -// Deprecated: use [tarheader.FileInfoHeaderNoLookups]. -func FileInfoHeaderNoLookups(fi os.FileInfo, link string) (*tar.Header, error) { - return tarheader.FileInfoHeaderNoLookups(fi, link) -} - // FileInfoHeader creates a populated Header from fi. // // Compared to the archive/tar package, this function fills in less information diff --git a/vendor/github.com/moby/go-archive/xattr_supported_unix.go b/vendor/github.com/moby/go-archive/xattr_supported_unix.go index 4d8824158ea..58a03e4a637 100644 --- a/vendor/github.com/moby/go-archive/xattr_supported_unix.go +++ b/vendor/github.com/moby/go-archive/xattr_supported_unix.go @@ -1,4 +1,4 @@ -//go:build !linux && !windows +//go:build darwin || freebsd || netbsd package archive diff --git a/vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go b/vendor/github.com/moby/moby/api/pkg/stdcopy/stdcopy.go similarity index 50% rename from vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go rename to vendor/github.com/moby/moby/api/pkg/stdcopy/stdcopy.go index 611432a6261..948c6b6755d 100644 --- a/vendor/github.com/docker/docker/pkg/stdcopy/stdcopy.go +++ b/vendor/github.com/moby/moby/api/pkg/stdcopy/stdcopy.go @@ -1,12 +1,10 @@ package stdcopy import ( - "bytes" "encoding/binary" "errors" "fmt" "io" - "sync" ) // StdType is the type of standard stream @@ -14,16 +12,13 @@ import ( type StdType byte const ( - // Stdin represents standard input stream type. - Stdin StdType = iota - // Stdout represents standard output stream type. - Stdout - // Stderr represents standard error steam type. - Stderr - // Systemerr represents errors originating from the system that make it - // into the multiplexed stream. - Systemerr + Stdin StdType = 0 // Stdin represents standard input stream. It is present for completeness and should NOT be used. When reading the stream with [StdCopy] it is output on [Stdout]. + Stdout StdType = 1 // Stdout represents standard output stream. + Stderr StdType = 2 // Stderr represents standard error steam. + Systemerr StdType = 3 // Systemerr represents errors originating from the system. When reading the stream with [StdCopy] it is returned as an error. +) +const ( stdWriterPrefixLen = 8 stdWriterFdIndex = 0 stdWriterSizeIndex = 4 @@ -31,67 +26,28 @@ const ( startingBufLen = 32*1024 + stdWriterPrefixLen + 1 ) -var bufPool = &sync.Pool{New: func() interface{} { return bytes.NewBuffer(nil) }} - -// stdWriter is wrapper of io.Writer with extra customized info. -type stdWriter struct { - io.Writer - prefix byte -} - -// Write sends the buffer to the underneath writer. -// It inserts the prefix header before the buffer, -// so stdcopy.StdCopy knows where to multiplex the output. -// It makes stdWriter to implement io.Writer. -func (w *stdWriter) Write(p []byte) (int, error) { - if w == nil || w.Writer == nil { - return 0, errors.New("writer not instantiated") - } - if p == nil { - return 0, nil - } - - header := [stdWriterPrefixLen]byte{stdWriterFdIndex: w.prefix} - binary.BigEndian.PutUint32(header[stdWriterSizeIndex:], uint32(len(p))) - buf := bufPool.Get().(*bytes.Buffer) - buf.Write(header[:]) - buf.Write(p) - - n, err := w.Writer.Write(buf.Bytes()) - n -= stdWriterPrefixLen - if n < 0 { - n = 0 - } - - buf.Reset() - bufPool.Put(buf) - return n, err -} - -// NewStdWriter instantiates a new Writer. -// Everything written to it will be encapsulated using a custom format, -// and written to the underlying `w` stream. -// This allows multiple write streams (e.g. stdout and stderr) to be muxed into a single connection. -// `t` indicates the id of the stream to encapsulate. -// It can be stdcopy.Stdin, stdcopy.Stdout, stdcopy.Stderr. -func NewStdWriter(w io.Writer, t StdType) io.Writer { - return &stdWriter{ - Writer: w, - prefix: byte(t), - } -} - -// StdCopy is a modified version of io.Copy. +// StdCopy is a modified version of [io.Copy] to de-multiplex messages +// from "multiplexedSource" and copy them to destination streams +// "destOut" and "destErr". +// +// StdCopy demultiplexes "multiplexedSource", assuming that it contains +// two streams, previously multiplexed using a writer created with +// [NewStdWriter]. // -// StdCopy will demultiplex `src`, assuming that it contains two streams, -// previously multiplexed together using a StdWriter instance. -// As it reads from `src`, StdCopy will write to `dstout` and `dsterr`. +// As it reads from "multiplexedSource", StdCopy writes [Stdout] messages +// to "destOut", and [Stderr] message to "destErr]. For backward-compatibility, +// [Stdin] messages are output to "destOut". The [Systemerr] stream provides +// errors produced by the daemon. It is returned as an error, and terminates +// processing the stream. // -// StdCopy will read until it hits EOF on `src`. It will then return a nil error. -// In other words: if `err` is non nil, it indicates a real underlying error. +// StdCopy it reads until it hits [io.EOF] on "multiplexedSource", after +// which it returns a nil error. In other words: any error returned indicates +// a real underlying error, which may be when an unknown [StdType] stream +// is received. // -// `written` will hold the total number of bytes written to `dstout` and `dsterr`. -func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, _ error) { +// The "written" return holds the total number of bytes written to "destOut" +// and "destErr" combined. +func StdCopy(destOut, destErr io.Writer, multiplexedSource io.Reader) (written int64, _ error) { var ( buf = make([]byte, startingBufLen) bufLen = len(buf) @@ -105,7 +61,7 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, _ error) { // Make sure we have at least a full header for nr < stdWriterPrefixLen { var nr2 int - nr2, err = src.Read(buf[nr:]) + nr2, err = multiplexedSource.Read(buf[nr:]) nr += nr2 if errors.Is(err, io.EOF) { if nr < stdWriterPrefixLen { @@ -118,24 +74,24 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, _ error) { } } - stream := StdType(buf[stdWriterFdIndex]) // Check the first byte to know where to write + stream := StdType(buf[stdWriterFdIndex]) switch stream { case Stdin: fallthrough case Stdout: // Write on stdout - out = dstout + out = destOut case Stderr: // Write on stderr - out = dsterr + out = destErr case Systemerr: // If we're on Systemerr, we won't write anywhere. // NB: if this code changes later, make sure you don't try to write // to outstream if Systemerr is the stream out = nil default: - return 0, fmt.Errorf("Unrecognized input header: %d", buf[stdWriterFdIndex]) + return 0, fmt.Errorf("unrecognized stream: %d", stream) } // Retrieve the size of the frame @@ -151,7 +107,7 @@ func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, _ error) { // While the amount of bytes read is less than the size of the frame + header, we keep reading for nr < frameSize+stdWriterPrefixLen { var nr2 int - nr2, err = src.Read(buf[nr:]) + nr2, err = multiplexedSource.Read(buf[nr:]) nr += nr2 if errors.Is(err, io.EOF) { if nr < frameSize+stdWriterPrefixLen { diff --git a/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go new file mode 100644 index 00000000000..0ae74fe7252 --- /dev/null +++ b/vendor/github.com/moby/moby/client/pkg/jsonmessage/jsonmessage.go @@ -0,0 +1,245 @@ +package jsonmessage + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "iter" + "strings" + "time" + + "github.com/docker/go-units" + "github.com/moby/moby/api/types/jsonstream" + "github.com/moby/term" +) + +var timeNow = time.Now // For overriding in tests. + +// RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to +// ensure the formatted time is always the same number of characters. +const RFC3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00" + +func RenderTUIProgress(p jsonstream.Progress, width uint16) string { + var ( + pbBox string + numbersBox string + ) + if p.Current <= 0 && p.Total <= 0 { + return "" + } + if p.Total <= 0 { + switch p.Units { + case "": + return fmt.Sprintf("%8v", units.HumanSize(float64(p.Current))) + default: + return fmt.Sprintf("%d %s", p.Current, p.Units) + } + } + + percentage := int(float64(p.Current)/float64(p.Total)*100) / 2 + if percentage > 50 { + percentage = 50 + } + if width > 110 { + // this number can't be negative gh#7136 + numSpaces := 0 + if 50-percentage > 0 { + numSpaces = 50 - percentage + } + pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces)) + } + + switch { + case p.HideCounts: + case p.Units == "": // no units, use bytes + current := units.HumanSize(float64(p.Current)) + total := units.HumanSize(float64(p.Total)) + + numbersBox = fmt.Sprintf("%8v/%v", current, total) + + if p.Current > p.Total { + // remove total display if the reported current is wonky. + numbersBox = fmt.Sprintf("%8v", current) + } + default: + numbersBox = fmt.Sprintf("%d/%d %s", p.Current, p.Total, p.Units) + + if p.Current > p.Total { + // remove total display if the reported current is wonky. + numbersBox = fmt.Sprintf("%d %s", p.Current, p.Units) + } + } + + // Show approximation of remaining time if there's enough width. + var timeLeftBox string + if width > 50 { + if p.Current > 0 && p.Start > 0 && percentage < 50 { + fromStart := timeNow().UTC().Sub(time.Unix(p.Start, 0)) + perEntry := fromStart / time.Duration(p.Current) + left := time.Duration(p.Total-p.Current) * perEntry + timeLeftBox = " " + left.Round(time.Second).String() + } + } + return pbBox + numbersBox + timeLeftBox +} + +// We can probably use [aec.EmptyBuilder] for managing the output, but +// currently we're doing it all manually, so defining some consts for +// the basics we use. +// +// [aec.EmptyBuilder]: https://pkg.go.dev/github.com/morikuni/aec#EmptyBuilder +const ( + ansiEraseLine = "\x1b[2K" // Erase entire line + ansiCursorUpFmt = "\x1b[%dA" // Move cursor up N lines + ansiCursorDownFmt = "\x1b[%dB" // Move cursor down N lines +) + +func clearLine(out io.Writer) { + _, _ = out.Write([]byte(ansiEraseLine)) +} + +func cursorUp(out io.Writer, l uint) { + if l == 0 { + return + } + _, _ = fmt.Fprintf(out, ansiCursorUpFmt, l) +} + +func cursorDown(out io.Writer, l uint) { + if l == 0 { + return + } + _, _ = fmt.Fprintf(out, ansiCursorDownFmt, l) +} + +// Display prints the JSONMessage to out. If isTerminal is true, it erases +// the entire current line when displaying the progressbar. It returns an +// error if the [JSONMessage.Error] field is non-nil. +func Display(jm jsonstream.Message, out io.Writer, isTerminal bool, width uint16) error { + if jm.Error != nil { + return jm.Error + } + var endl string + if isTerminal && jm.Stream == "" && jm.Progress != nil { + clearLine(out) + endl = "\r" + _, _ = fmt.Fprint(out, endl) + } else if jm.Progress != nil && (jm.Progress.Current > 0 || jm.Progress.Total > 0) { // disable progressbar in non-terminal + return nil + } + if jm.ID != "" { + _, _ = fmt.Fprintf(out, "%s: ", jm.ID) + } + if jm.Progress != nil && isTerminal { + if width == 0 { + width = 200 + } + _, _ = fmt.Fprintf(out, "%s %s%s", jm.Status, RenderTUIProgress(*jm.Progress, width), endl) + } else if jm.Stream != "" { + _, _ = fmt.Fprintf(out, "%s%s", jm.Stream, endl) + } else { + _, _ = fmt.Fprintf(out, "%s%s\n", jm.Status, endl) + } + return nil +} + +type JSONMessagesStream = iter.Seq2[jsonstream.Message, error] + +// DisplayJSONMessagesStream reads a JSON message stream from in, and writes +// each [JSONMessage] to out. +// see DisplayJSONMessages for details +func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(jsonstream.Message)) error { + dec := json.NewDecoder(in) + f := func(yield func(jsonstream.Message, error) bool) { + for { + var jm jsonstream.Message + err := dec.Decode(&jm) + if errors.Is(err, io.EOF) { + break + } + if !yield(jm, err) { + return + } + } + } + + return DisplayJSONMessages(f, out, terminalFd, isTerminal, auxCallback) +} + +// DisplayJSONMessages writes each [JSONMessage] from stream to out. +// It returns an error if an invalid JSONMessage is received, or if +// a JSONMessage containers a non-zero [JSONMessage.Error]. +// +// Presentation of the JSONMessage depends on whether a terminal is attached, +// and on the terminal width. Progress bars ([JSONProgress]) are suppressed +// on narrower terminals (< 110 characters). +// +// - isTerminal describes if out is a terminal, in which case it prints +// a newline ("\n") at the end of each line and moves the cursor while +// displaying. +// - terminalFd is the fd of the current terminal (if any), and used +// to get the terminal width. +// - auxCallback allows handling the [JSONMessage.Aux] field. It is +// called if a JSONMessage contains an Aux field, in which case +// DisplayJSONMessagesStream does not present the JSONMessage. +func DisplayJSONMessages(messages iter.Seq2[jsonstream.Message, error], out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(jsonstream.Message)) error { + ids := make(map[string]uint) + var width uint16 = 200 + if isTerminal { + ws, err := term.GetWinsize(terminalFd) + if err == nil { + width = ws.Width + } + } + + for jm, err := range messages { + var diff uint + if err != nil { + return err + } + + if jm.Aux != nil { + if auxCallback != nil { + auxCallback(jm) + } + continue + } + + if jm.ID != "" && jm.Progress != nil { + line, ok := ids[jm.ID] + if !ok { + // NOTE: This approach of using len(id) to + // figure out the number of lines of history + // only works as long as we clear the history + // when we output something that's not + // accounted for in the map, such as a line + // with no ID. + line = uint(len(ids)) + ids[jm.ID] = line + if isTerminal { + _, _ = fmt.Fprintf(out, "\n") + } + } + diff = uint(len(ids)) - line + if isTerminal { + cursorUp(out, diff) + } + } else { + // When outputting something that isn't progress + // output, clear the history of previous lines. We + // don't want progress entries from some previous + // operation to be updated (for example, pull -a + // with multiple tags). + ids = make(map[string]uint) + } + err := Display(jm, out, isTerminal, width) + if jm.ID != "" && isTerminal { + cursorDown(out, diff) + } + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/docker/docker/AUTHORS b/vendor/github.com/moby/moby/v2/AUTHORS similarity index 99% rename from vendor/github.com/docker/docker/AUTHORS rename to vendor/github.com/moby/moby/v2/AUTHORS index c7c649471c2..cb9bc376936 100644 --- a/vendor/github.com/docker/docker/AUTHORS +++ b/vendor/github.com/moby/moby/v2/AUTHORS @@ -23,6 +23,7 @@ Abhishek Chanda Abhishek Sharma Abin Shahab Abirdcfly +Abubacarr Ceesay Ada Mancini Adam Avilla Adam Dobrawy @@ -49,6 +50,7 @@ Adrian Mouat Adrian Oprea Adrien Folie Adrien Gallouët +Adrien Pompée Ahmed Kamal Ahmet Alp Balkan Aidan Feldman @@ -81,6 +83,7 @@ Aleksandrs Fadins Alena Prokharchyk Alessandro Boch Alessio Biancalana +Alessio Perugini Alex Chan Alex Chen Alex Coventry @@ -171,6 +174,7 @@ Andrew Po Andrew Weiss Andrew Williams Andrews Medina +Andrey Epifanov Andrey Kolomentsev Andrey Petrov Andrey Stolbovsky @@ -200,6 +204,7 @@ Anthon van der Neut Anthony Baire Anthony Bishopric Anthony Dahanne +Anthony Nandaa Anthony Sottile Anton Löfgren Anton Nikitin @@ -345,6 +350,7 @@ Carlos Alexandro Becker Carlos de Paula Carlos Sanchez Carol Fager-Higgins +carsontham Cary Casey Bisson Catalin Pirvu @@ -871,6 +877,7 @@ haining.cao Hakan Özler Hamish Hutchings Hannes Ljungberg +Hannes Ortmeier Hans Kristian Flaatten Hans Rødtang Hao Shu Wei @@ -890,6 +897,7 @@ heartlock <21521209@zju.edu.cn> Hector Castro Helen Xie Henning Sprang +Henry Wang Hiroshi Hatake Hiroyuki Sasagawa Hobofan @@ -1089,6 +1097,7 @@ Jintao Zhang Jiri Appl Jiri Popelka Jiuyue Ma +Jiří Moravčík Jiří Župka jjimbo137 <115816493+jjimbo137@users.noreply.github.com> Joakim Roubert @@ -1320,6 +1329,7 @@ Leandro Motta Barros Leandro Siqueira Lee Calcote Lee Chao <932819864@qq.com> +Lee Gaines Lee, Meng-Han Lei Gong Lei Jitang @@ -1407,6 +1417,7 @@ Manuel Meurer Manuel Rüger Manuel Woelker mapk0y +Marat Abrarov Marat Radchenko Marc Abramowitz Marc Kuo @@ -1421,6 +1432,7 @@ Marcus Linke Marcus Martins Marcus Ramberg Marek Goldmann +Maria Glushenok Marian Marinov Marianna Tessel Mario Loriedo @@ -1504,6 +1516,7 @@ Maxime Petazzoni Maximiliano Maccanti Maxwell Meaglith Ma +Medhy DOHOU <52136144+PowerPixel@users.noreply.github.com> meejah Megan Kostick Mehul Kar @@ -1604,6 +1617,7 @@ Moysés Borges mrfly Mrunal Patel Muayyad Alsadi +Muhammad Daffa Dinaya Muhammad Zohaib Aslam Mustafa Akın Muthukumar R @@ -2023,12 +2037,14 @@ Sergey Alekseev Sergey Evstifeev Sergii Kabashniuk Sergio Lopez +Serhan Tutar Serhat Gülçiçek Serhii Nakon SeungUkLee Sevki Hasirci Shane Canon Shane da Silva +Shang Mu Shaun Kaasten Shaun Thompson shaunol @@ -2120,6 +2136,7 @@ Stéphane Este-Gracias Stig Larsson Su Wang Subhajit Ghosh +Sudheendra Gopinath Sujith Haridasan Sun Gengze <690388648@qq.com> Sun Jianbo @@ -2176,6 +2193,7 @@ Thomas Tanaka Thomas Texier Ti Zhou Tiago Seabra +Tiago Teixeira Tianon Gravi Tianyi Wang Tibor Vass @@ -2276,6 +2294,7 @@ Valentin Kulesh vanderliang Velko Ivanov Veres Lajos +Viacheslav Gagara Victor Algaze Victor Coisne Victor Costan @@ -2492,5 +2511,6 @@ Zunayed Ali 徐俊杰 慕陶 搏通 +纯真 <38834411+chunzhennn@users.noreply.github.com> 黄艳红00139573 정재영 diff --git a/vendor/github.com/docker/docker/LICENSE b/vendor/github.com/moby/moby/v2/LICENSE similarity index 100% rename from vendor/github.com/docker/docker/LICENSE rename to vendor/github.com/moby/moby/v2/LICENSE diff --git a/vendor/github.com/docker/docker/NOTICE b/vendor/github.com/moby/moby/v2/NOTICE similarity index 100% rename from vendor/github.com/docker/docker/NOTICE rename to vendor/github.com/moby/moby/v2/NOTICE diff --git a/vendor/github.com/docker/docker/pkg/homedir/homedir.go b/vendor/github.com/moby/moby/v2/pkg/homedir/homedir.go similarity index 100% rename from vendor/github.com/docker/docker/pkg/homedir/homedir.go rename to vendor/github.com/moby/moby/v2/pkg/homedir/homedir.go diff --git a/vendor/github.com/moby/moby/v2/pkg/homedir/homedir_linux.go b/vendor/github.com/moby/moby/v2/pkg/homedir/homedir_linux.go new file mode 100644 index 00000000000..aff85fadc7b --- /dev/null +++ b/vendor/github.com/moby/moby/v2/pkg/homedir/homedir_linux.go @@ -0,0 +1,125 @@ +package homedir + +import ( + "errors" + "os" + "path/filepath" + "strings" +) + +// GetRuntimeDir returns [XDG_RUNTIME_DIR]. It returns a non-nil error if +// XDG_RUNTIME_DIR is not set. XDG_RUNTIME_DIR is typically configured via +// [pam_systemd]. +// +// [XDG_RUNTIME_DIR]: https://specifications.freedesktop.org/basedir/0.8/#variables +// [pam_systemd]: https://man7.org/linux/man-pages/man8/pam_systemd.8.html +func GetRuntimeDir() (string, error) { + if xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR"); xdgRuntimeDir != "" { + return xdgRuntimeDir, nil + } + return "", errors.New("could not get XDG_RUNTIME_DIR") +} + +// StickRuntimeDirContents sets the sticky bit on files that are under +// [XDG_RUNTIME_DIR], so that the files won't be periodically removed by the +// system. +// +// It returns a slice of sticked files as absolute paths. The list of files may +// be empty (nil) if XDG_RUNTIME_DIR is not set, in which case no error is returned. +// StickyRuntimeDir produces an error when failing to resolve the absolute path +// for the returned files. +// +// [XDG_RUNTIME_DIR]: https://specifications.freedesktop.org/basedir/0.8/#variables +func StickRuntimeDirContents(files []string) ([]string, error) { + runtimeDir, err := GetRuntimeDir() + if err != nil { + // ignore error if runtimeDir is empty + return nil, nil + } + runtimeDir, err = filepath.Abs(runtimeDir) + if err != nil { + return nil, err + } + var sticked []string + for _, f := range files { + f, err = filepath.Abs(f) + if err != nil { + return sticked, err + } + if strings.HasPrefix(f, runtimeDir+"/") { + if err = stick(f); err != nil { + return sticked, err + } + sticked = append(sticked, f) + } + } + return sticked, nil +} + +func stick(f string) error { + st, err := os.Stat(f) + if err != nil { + return err + } + m := st.Mode() + m |= os.ModeSticky + return os.Chmod(f, m) +} + +// GetDataHome returns [XDG_DATA_HOME] or $HOME/.local/share and a nil error if +// [XDG_DATA_HOME] is not set. If neither HOME nor XDG_DATA_HOME are set, +// [getpwent(3)] is consulted to determine the users home directory. +// +// [XDG_DATA_HOME]: https://specifications.freedesktop.org/basedir/0.8/#variables +// [getpwent(3)]: https://man7.org/linux/man-pages/man3/getpwent.3.html +func GetDataHome() (string, error) { + if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" { + return xdgDataHome, nil + } + home := Get() + if home == "" { + return "", errors.New("could not get either XDG_DATA_HOME or HOME") + } + return filepath.Join(home, ".local", "share"), nil +} + +// GetConfigHome returns [XDG_CONFIG_HOME] or $HOME/.config and a nil error if +// XDG_CONFIG_HOME is not set. If neither HOME nor XDG_CONFIG_HOME are set, +// [getpwent(3)] is consulted to determine the users home directory. +// +// [XDG_CONFIG_HOME]: https://specifications.freedesktop.org/basedir/0.8/#variables +// [getpwent(3)]: https://man7.org/linux/man-pages/man3/getpwent.3.html +func GetConfigHome() (string, error) { + if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" { + return xdgConfigHome, nil + } + home := Get() + if home == "" { + return "", errors.New("could not get either XDG_CONFIG_HOME or HOME") + } + return filepath.Join(home, ".config"), nil +} + +// GetLibHome returns $HOME/.local/lib. If HOME is not set, [getpwent(3)] is +// consulted to determine the users home directory. +// +// [getpwent(3)]: https://man7.org/linux/man-pages/man3/getpwent.3.html +func GetLibHome() (string, error) { + home := Get() + if home == "" { + return "", errors.New("could not get HOME") + } + return filepath.Join(home, ".local/lib"), nil +} + +// GetLibexecHome returns $HOME/.local/libexec. If HOME is not set, +// [getpwent(3)] is consulted to determine the users home directory. +// +// [getpwent(3)]: https://man7.org/linux/man-pages/man3/getpwent.3.html +func GetLibexecHome() (string, error) { + home := Get() + if home == "" { + return "", errors.New("could not get HOME") + } + return filepath.Join(home, ".local/libexec"), nil +} diff --git a/vendor/github.com/docker/docker/pkg/homedir/homedir_others.go b/vendor/github.com/moby/moby/v2/pkg/homedir/homedir_others.go similarity index 84% rename from vendor/github.com/docker/docker/pkg/homedir/homedir_others.go rename to vendor/github.com/moby/moby/v2/pkg/homedir/homedir_others.go index 1e41e6aab51..ad4df82f7be 100644 --- a/vendor/github.com/docker/docker/pkg/homedir/homedir_others.go +++ b/vendor/github.com/moby/moby/v2/pkg/homedir/homedir_others.go @@ -30,3 +30,8 @@ func GetConfigHome() (string, error) { func GetLibHome() (string, error) { return "", errors.New("homedir.GetLibHome() is not supported on this system") } + +// GetLibexecHome is unsupported on non-linux system. +func GetLibexecHome() (string, error) { + return "", errors.New("homedir.GetLibexecHome() is not supported on this system") +} diff --git a/vendor/github.com/morikuni/aec/LICENSE b/vendor/github.com/morikuni/aec/LICENSE deleted file mode 100644 index 1c264016419..00000000000 --- a/vendor/github.com/morikuni/aec/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Taihei Morikuni - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/github.com/morikuni/aec/README.md b/vendor/github.com/morikuni/aec/README.md deleted file mode 100644 index 3cbc4343ee2..00000000000 --- a/vendor/github.com/morikuni/aec/README.md +++ /dev/null @@ -1,178 +0,0 @@ -# aec - -[![GoDoc](https://godoc.org/github.com/morikuni/aec?status.svg)](https://godoc.org/github.com/morikuni/aec) - -Go wrapper for ANSI escape code. - -## Install - -```bash -go get github.com/morikuni/aec -``` - -## Features - -ANSI escape codes depend on terminal environment. -Some of these features may not work. -Check supported Font-Style/Font-Color features with [checkansi](./checkansi). - -[Wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code) for more detail. - -### Cursor - -- `Up(n)` -- `Down(n)` -- `Right(n)` -- `Left(n)` -- `NextLine(n)` -- `PreviousLine(n)` -- `Column(col)` -- `Position(row, col)` -- `Save` -- `Restore` -- `Hide` -- `Show` -- `Report` - -### Erase - -- `EraseDisplay(mode)` -- `EraseLine(mode)` - -### Scroll - -- `ScrollUp(n)` -- `ScrollDown(n)` - -### Font Style - -- `Bold` -- `Faint` -- `Italic` -- `Underline` -- `BlinkSlow` -- `BlinkRapid` -- `Inverse` -- `Conceal` -- `CrossOut` -- `Frame` -- `Encircle` -- `Overline` - -### Font Color - -Foreground color. - -- `DefaultF` -- `BlackF` -- `RedF` -- `GreenF` -- `YellowF` -- `BlueF` -- `MagentaF` -- `CyanF` -- `WhiteF` -- `LightBlackF` -- `LightRedF` -- `LightGreenF` -- `LightYellowF` -- `LightBlueF` -- `LightMagentaF` -- `LightCyanF` -- `LightWhiteF` -- `Color3BitF(color)` -- `Color8BitF(color)` -- `FullColorF(r, g, b)` - -Background color. - -- `DefaultB` -- `BlackB` -- `RedB` -- `GreenB` -- `YellowB` -- `BlueB` -- `MagentaB` -- `CyanB` -- `WhiteB` -- `LightBlackB` -- `LightRedB` -- `LightGreenB` -- `LightYellowB` -- `LightBlueB` -- `LightMagentaB` -- `LightCyanB` -- `LightWhiteB` -- `Color3BitB(color)` -- `Color8BitB(color)` -- `FullColorB(r, g, b)` - -### Color Converter - -24bit RGB color to ANSI color. - -- `NewRGB3Bit(r, g, b)` -- `NewRGB8Bit(r, g, b)` - -### Builder - -To mix these features. - -```go -custom := aec.EmptyBuilder.Right(2).RGB8BitF(128, 255, 64).RedB().ANSI -custom.Apply("Hello World") -``` - -## Usage - -1. Create ANSI by `aec.XXX().With(aec.YYY())` or `aec.EmptyBuilder.XXX().YYY().ANSI` -2. Print ANSI by `fmt.Print(ansi, "some string", aec.Reset)` or `fmt.Print(ansi.Apply("some string"))` - -`aec.Reset` should be added when using font style or font color features. - -## Example - -Simple progressbar. - -![sample](./sample.gif) - -```go -package main - -import ( - "fmt" - "strings" - "time" - - "github.com/morikuni/aec" -) - -func main() { - const n = 20 - builder := aec.EmptyBuilder - - up2 := aec.Up(2) - col := aec.Column(n + 2) - bar := aec.Color8BitF(aec.NewRGB8Bit(64, 255, 64)) - label := builder.LightRedF().Underline().With(col).Right(1).ANSI - - // for up2 - fmt.Println() - fmt.Println() - - for i := 0; i <= n; i++ { - fmt.Print(up2) - fmt.Println(label.Apply(fmt.Sprint(i, "/", n))) - fmt.Print("[") - fmt.Print(bar.Apply(strings.Repeat("=", i))) - fmt.Println(col.Apply("]")) - time.Sleep(100 * time.Millisecond) - } -} -``` - -## License - -[MIT](./LICENSE) - - diff --git a/vendor/github.com/morikuni/aec/aec.go b/vendor/github.com/morikuni/aec/aec.go deleted file mode 100644 index 566be6eb1ef..00000000000 --- a/vendor/github.com/morikuni/aec/aec.go +++ /dev/null @@ -1,137 +0,0 @@ -package aec - -import "fmt" - -// EraseMode is listed in a variable EraseModes. -type EraseMode uint - -var ( - // EraseModes is a list of EraseMode. - EraseModes struct { - // All erase all. - All EraseMode - - // Head erase to head. - Head EraseMode - - // Tail erase to tail. - Tail EraseMode - } - - // Save saves the cursor position. - Save ANSI - - // Restore restores the cursor position. - Restore ANSI - - // Hide hides the cursor. - Hide ANSI - - // Show shows the cursor. - Show ANSI - - // Report reports the cursor position. - Report ANSI -) - -// Up moves up the cursor. -func Up(n uint) ANSI { - if n == 0 { - return empty - } - return newAnsi(fmt.Sprintf(esc+"%dA", n)) -} - -// Down moves down the cursor. -func Down(n uint) ANSI { - if n == 0 { - return empty - } - return newAnsi(fmt.Sprintf(esc+"%dB", n)) -} - -// Right moves right the cursor. -func Right(n uint) ANSI { - if n == 0 { - return empty - } - return newAnsi(fmt.Sprintf(esc+"%dC", n)) -} - -// Left moves left the cursor. -func Left(n uint) ANSI { - if n == 0 { - return empty - } - return newAnsi(fmt.Sprintf(esc+"%dD", n)) -} - -// NextLine moves down the cursor to head of a line. -func NextLine(n uint) ANSI { - if n == 0 { - return empty - } - return newAnsi(fmt.Sprintf(esc+"%dE", n)) -} - -// PreviousLine moves up the cursor to head of a line. -func PreviousLine(n uint) ANSI { - if n == 0 { - return empty - } - return newAnsi(fmt.Sprintf(esc+"%dF", n)) -} - -// Column set the cursor position to a given column. -func Column(col uint) ANSI { - return newAnsi(fmt.Sprintf(esc+"%dG", col)) -} - -// Position set the cursor position to a given absolute position. -func Position(row, col uint) ANSI { - return newAnsi(fmt.Sprintf(esc+"%d;%dH", row, col)) -} - -// EraseDisplay erases display by given EraseMode. -func EraseDisplay(m EraseMode) ANSI { - return newAnsi(fmt.Sprintf(esc+"%dJ", m)) -} - -// EraseLine erases lines by given EraseMode. -func EraseLine(m EraseMode) ANSI { - return newAnsi(fmt.Sprintf(esc+"%dK", m)) -} - -// ScrollUp scrolls up the page. -func ScrollUp(n int) ANSI { - if n == 0 { - return empty - } - return newAnsi(fmt.Sprintf(esc+"%dS", n)) -} - -// ScrollDown scrolls down the page. -func ScrollDown(n int) ANSI { - if n == 0 { - return empty - } - return newAnsi(fmt.Sprintf(esc+"%dT", n)) -} - -func init() { - EraseModes = struct { - All EraseMode - Head EraseMode - Tail EraseMode - }{ - Tail: 0, - Head: 1, - All: 2, - } - - Save = newAnsi(esc + "s") - Restore = newAnsi(esc + "u") - Hide = newAnsi(esc + "?25l") - Show = newAnsi(esc + "?25h") - Report = newAnsi(esc + "6n") -} diff --git a/vendor/github.com/morikuni/aec/ansi.go b/vendor/github.com/morikuni/aec/ansi.go deleted file mode 100644 index e60722e6e60..00000000000 --- a/vendor/github.com/morikuni/aec/ansi.go +++ /dev/null @@ -1,59 +0,0 @@ -package aec - -import ( - "fmt" - "strings" -) - -const esc = "\x1b[" - -// Reset resets SGR effect. -const Reset string = "\x1b[0m" - -var empty = newAnsi("") - -// ANSI represents ANSI escape code. -type ANSI interface { - fmt.Stringer - - // With adapts given ANSIs. - With(...ANSI) ANSI - - // Apply wraps given string in ANSI. - Apply(string) string -} - -type ansiImpl string - -func newAnsi(s string) *ansiImpl { - r := ansiImpl(s) - return &r -} - -func (a *ansiImpl) With(ansi ...ANSI) ANSI { - return concat(append([]ANSI{a}, ansi...)) -} - -func (a *ansiImpl) Apply(s string) string { - return a.String() + s + Reset -} - -func (a *ansiImpl) String() string { - return string(*a) -} - -// Apply wraps given string in ANSIs. -func Apply(s string, ansi ...ANSI) string { - if len(ansi) == 0 { - return s - } - return concat(ansi).Apply(s) -} - -func concat(ansi []ANSI) ANSI { - strs := make([]string, 0, len(ansi)) - for _, p := range ansi { - strs = append(strs, p.String()) - } - return newAnsi(strings.Join(strs, "")) -} diff --git a/vendor/github.com/morikuni/aec/builder.go b/vendor/github.com/morikuni/aec/builder.go deleted file mode 100644 index 13bd002d4e3..00000000000 --- a/vendor/github.com/morikuni/aec/builder.go +++ /dev/null @@ -1,388 +0,0 @@ -package aec - -// Builder is a lightweight syntax to construct customized ANSI. -type Builder struct { - ANSI ANSI -} - -// EmptyBuilder is an initialized Builder. -var EmptyBuilder *Builder - -// NewBuilder creates a Builder from existing ANSI. -func NewBuilder(a ...ANSI) *Builder { - return &Builder{concat(a)} -} - -// With is a syntax for With. -func (builder *Builder) With(a ...ANSI) *Builder { - return NewBuilder(builder.ANSI.With(a...)) -} - -// Up is a syntax for Up. -func (builder *Builder) Up(n uint) *Builder { - return builder.With(Up(n)) -} - -// Down is a syntax for Down. -func (builder *Builder) Down(n uint) *Builder { - return builder.With(Down(n)) -} - -// Right is a syntax for Right. -func (builder *Builder) Right(n uint) *Builder { - return builder.With(Right(n)) -} - -// Left is a syntax for Left. -func (builder *Builder) Left(n uint) *Builder { - return builder.With(Left(n)) -} - -// NextLine is a syntax for NextLine. -func (builder *Builder) NextLine(n uint) *Builder { - return builder.With(NextLine(n)) -} - -// PreviousLine is a syntax for PreviousLine. -func (builder *Builder) PreviousLine(n uint) *Builder { - return builder.With(PreviousLine(n)) -} - -// Column is a syntax for Column. -func (builder *Builder) Column(col uint) *Builder { - return builder.With(Column(col)) -} - -// Position is a syntax for Position. -func (builder *Builder) Position(row, col uint) *Builder { - return builder.With(Position(row, col)) -} - -// EraseDisplay is a syntax for EraseDisplay. -func (builder *Builder) EraseDisplay(m EraseMode) *Builder { - return builder.With(EraseDisplay(m)) -} - -// EraseLine is a syntax for EraseLine. -func (builder *Builder) EraseLine(m EraseMode) *Builder { - return builder.With(EraseLine(m)) -} - -// ScrollUp is a syntax for ScrollUp. -func (builder *Builder) ScrollUp(n int) *Builder { - return builder.With(ScrollUp(n)) -} - -// ScrollDown is a syntax for ScrollDown. -func (builder *Builder) ScrollDown(n int) *Builder { - return builder.With(ScrollDown(n)) -} - -// Save is a syntax for Save. -func (builder *Builder) Save() *Builder { - return builder.With(Save) -} - -// Restore is a syntax for Restore. -func (builder *Builder) Restore() *Builder { - return builder.With(Restore) -} - -// Hide is a syntax for Hide. -func (builder *Builder) Hide() *Builder { - return builder.With(Hide) -} - -// Show is a syntax for Show. -func (builder *Builder) Show() *Builder { - return builder.With(Show) -} - -// Report is a syntax for Report. -func (builder *Builder) Report() *Builder { - return builder.With(Report) -} - -// Bold is a syntax for Bold. -func (builder *Builder) Bold() *Builder { - return builder.With(Bold) -} - -// Faint is a syntax for Faint. -func (builder *Builder) Faint() *Builder { - return builder.With(Faint) -} - -// Italic is a syntax for Italic. -func (builder *Builder) Italic() *Builder { - return builder.With(Italic) -} - -// Underline is a syntax for Underline. -func (builder *Builder) Underline() *Builder { - return builder.With(Underline) -} - -// BlinkSlow is a syntax for BlinkSlow. -func (builder *Builder) BlinkSlow() *Builder { - return builder.With(BlinkSlow) -} - -// BlinkRapid is a syntax for BlinkRapid. -func (builder *Builder) BlinkRapid() *Builder { - return builder.With(BlinkRapid) -} - -// Inverse is a syntax for Inverse. -func (builder *Builder) Inverse() *Builder { - return builder.With(Inverse) -} - -// Conceal is a syntax for Conceal. -func (builder *Builder) Conceal() *Builder { - return builder.With(Conceal) -} - -// CrossOut is a syntax for CrossOut. -func (builder *Builder) CrossOut() *Builder { - return builder.With(CrossOut) -} - -// BlackF is a syntax for BlackF. -func (builder *Builder) BlackF() *Builder { - return builder.With(BlackF) -} - -// RedF is a syntax for RedF. -func (builder *Builder) RedF() *Builder { - return builder.With(RedF) -} - -// GreenF is a syntax for GreenF. -func (builder *Builder) GreenF() *Builder { - return builder.With(GreenF) -} - -// YellowF is a syntax for YellowF. -func (builder *Builder) YellowF() *Builder { - return builder.With(YellowF) -} - -// BlueF is a syntax for BlueF. -func (builder *Builder) BlueF() *Builder { - return builder.With(BlueF) -} - -// MagentaF is a syntax for MagentaF. -func (builder *Builder) MagentaF() *Builder { - return builder.With(MagentaF) -} - -// CyanF is a syntax for CyanF. -func (builder *Builder) CyanF() *Builder { - return builder.With(CyanF) -} - -// WhiteF is a syntax for WhiteF. -func (builder *Builder) WhiteF() *Builder { - return builder.With(WhiteF) -} - -// DefaultF is a syntax for DefaultF. -func (builder *Builder) DefaultF() *Builder { - return builder.With(DefaultF) -} - -// BlackB is a syntax for BlackB. -func (builder *Builder) BlackB() *Builder { - return builder.With(BlackB) -} - -// RedB is a syntax for RedB. -func (builder *Builder) RedB() *Builder { - return builder.With(RedB) -} - -// GreenB is a syntax for GreenB. -func (builder *Builder) GreenB() *Builder { - return builder.With(GreenB) -} - -// YellowB is a syntax for YellowB. -func (builder *Builder) YellowB() *Builder { - return builder.With(YellowB) -} - -// BlueB is a syntax for BlueB. -func (builder *Builder) BlueB() *Builder { - return builder.With(BlueB) -} - -// MagentaB is a syntax for MagentaB. -func (builder *Builder) MagentaB() *Builder { - return builder.With(MagentaB) -} - -// CyanB is a syntax for CyanB. -func (builder *Builder) CyanB() *Builder { - return builder.With(CyanB) -} - -// WhiteB is a syntax for WhiteB. -func (builder *Builder) WhiteB() *Builder { - return builder.With(WhiteB) -} - -// DefaultB is a syntax for DefaultB. -func (builder *Builder) DefaultB() *Builder { - return builder.With(DefaultB) -} - -// Frame is a syntax for Frame. -func (builder *Builder) Frame() *Builder { - return builder.With(Frame) -} - -// Encircle is a syntax for Encircle. -func (builder *Builder) Encircle() *Builder { - return builder.With(Encircle) -} - -// Overline is a syntax for Overline. -func (builder *Builder) Overline() *Builder { - return builder.With(Overline) -} - -// LightBlackF is a syntax for LightBlueF. -func (builder *Builder) LightBlackF() *Builder { - return builder.With(LightBlackF) -} - -// LightRedF is a syntax for LightRedF. -func (builder *Builder) LightRedF() *Builder { - return builder.With(LightRedF) -} - -// LightGreenF is a syntax for LightGreenF. -func (builder *Builder) LightGreenF() *Builder { - return builder.With(LightGreenF) -} - -// LightYellowF is a syntax for LightYellowF. -func (builder *Builder) LightYellowF() *Builder { - return builder.With(LightYellowF) -} - -// LightBlueF is a syntax for LightBlueF. -func (builder *Builder) LightBlueF() *Builder { - return builder.With(LightBlueF) -} - -// LightMagentaF is a syntax for LightMagentaF. -func (builder *Builder) LightMagentaF() *Builder { - return builder.With(LightMagentaF) -} - -// LightCyanF is a syntax for LightCyanF. -func (builder *Builder) LightCyanF() *Builder { - return builder.With(LightCyanF) -} - -// LightWhiteF is a syntax for LightWhiteF. -func (builder *Builder) LightWhiteF() *Builder { - return builder.With(LightWhiteF) -} - -// LightBlackB is a syntax for LightBlackB. -func (builder *Builder) LightBlackB() *Builder { - return builder.With(LightBlackB) -} - -// LightRedB is a syntax for LightRedB. -func (builder *Builder) LightRedB() *Builder { - return builder.With(LightRedB) -} - -// LightGreenB is a syntax for LightGreenB. -func (builder *Builder) LightGreenB() *Builder { - return builder.With(LightGreenB) -} - -// LightYellowB is a syntax for LightYellowB. -func (builder *Builder) LightYellowB() *Builder { - return builder.With(LightYellowB) -} - -// LightBlueB is a syntax for LightBlueB. -func (builder *Builder) LightBlueB() *Builder { - return builder.With(LightBlueB) -} - -// LightMagentaB is a syntax for LightMagentaB. -func (builder *Builder) LightMagentaB() *Builder { - return builder.With(LightMagentaB) -} - -// LightCyanB is a syntax for LightCyanB. -func (builder *Builder) LightCyanB() *Builder { - return builder.With(LightCyanB) -} - -// LightWhiteB is a syntax for LightWhiteB. -func (builder *Builder) LightWhiteB() *Builder { - return builder.With(LightWhiteB) -} - -// Color3BitF is a syntax for Color3BitF. -func (builder *Builder) Color3BitF(c RGB3Bit) *Builder { - return builder.With(Color3BitF(c)) -} - -// Color3BitB is a syntax for Color3BitB. -func (builder *Builder) Color3BitB(c RGB3Bit) *Builder { - return builder.With(Color3BitB(c)) -} - -// Color8BitF is a syntax for Color8BitF. -func (builder *Builder) Color8BitF(c RGB8Bit) *Builder { - return builder.With(Color8BitF(c)) -} - -// Color8BitB is a syntax for Color8BitB. -func (builder *Builder) Color8BitB(c RGB8Bit) *Builder { - return builder.With(Color8BitB(c)) -} - -// FullColorF is a syntax for FullColorF. -func (builder *Builder) FullColorF(r, g, b uint8) *Builder { - return builder.With(FullColorF(r, g, b)) -} - -// FullColorB is a syntax for FullColorB. -func (builder *Builder) FullColorB(r, g, b uint8) *Builder { - return builder.With(FullColorB(r, g, b)) -} - -// RGB3BitF is a syntax for Color3BitF with NewRGB3Bit. -func (builder *Builder) RGB3BitF(r, g, b uint8) *Builder { - return builder.Color3BitF(NewRGB3Bit(r, g, b)) -} - -// RGB3BitB is a syntax for Color3BitB with NewRGB3Bit. -func (builder *Builder) RGB3BitB(r, g, b uint8) *Builder { - return builder.Color3BitB(NewRGB3Bit(r, g, b)) -} - -// RGB8BitF is a syntax for Color8BitF with NewRGB8Bit. -func (builder *Builder) RGB8BitF(r, g, b uint8) *Builder { - return builder.Color8BitF(NewRGB8Bit(r, g, b)) -} - -// RGB8BitB is a syntax for Color8BitB with NewRGB8Bit. -func (builder *Builder) RGB8BitB(r, g, b uint8) *Builder { - return builder.Color8BitB(NewRGB8Bit(r, g, b)) -} - -func init() { - EmptyBuilder = &Builder{empty} -} diff --git a/vendor/github.com/morikuni/aec/sample.gif b/vendor/github.com/morikuni/aec/sample.gif deleted file mode 100644 index c6c613bb70645efa4e184726060ea1ff981eeceb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12548 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 Y(?6j)4M_L*quqaULH)mVw5$IA0FB)@mjD0& diff --git a/vendor/github.com/morikuni/aec/sgr.go b/vendor/github.com/morikuni/aec/sgr.go deleted file mode 100644 index 0ba3464e6db..00000000000 --- a/vendor/github.com/morikuni/aec/sgr.go +++ /dev/null @@ -1,202 +0,0 @@ -package aec - -import ( - "fmt" -) - -// RGB3Bit is a 3bit RGB color. -type RGB3Bit uint8 - -// RGB8Bit is a 8bit RGB color. -type RGB8Bit uint8 - -func newSGR(n uint) ANSI { - return newAnsi(fmt.Sprintf(esc+"%dm", n)) -} - -// NewRGB3Bit create a RGB3Bit from given RGB. -func NewRGB3Bit(r, g, b uint8) RGB3Bit { - return RGB3Bit((r >> 7) | ((g >> 6) & 0x2) | ((b >> 5) & 0x4)) -} - -// NewRGB8Bit create a RGB8Bit from given RGB. -func NewRGB8Bit(r, g, b uint8) RGB8Bit { - return RGB8Bit(16 + 36*(r/43) + 6*(g/43) + b/43) -} - -// Color3BitF set the foreground color of text. -func Color3BitF(c RGB3Bit) ANSI { - return newAnsi(fmt.Sprintf(esc+"%dm", c+30)) -} - -// Color3BitB set the background color of text. -func Color3BitB(c RGB3Bit) ANSI { - return newAnsi(fmt.Sprintf(esc+"%dm", c+40)) -} - -// Color8BitF set the foreground color of text. -func Color8BitF(c RGB8Bit) ANSI { - return newAnsi(fmt.Sprintf(esc+"38;5;%dm", c)) -} - -// Color8BitB set the background color of text. -func Color8BitB(c RGB8Bit) ANSI { - return newAnsi(fmt.Sprintf(esc+"48;5;%dm", c)) -} - -// FullColorF set the foreground color of text. -func FullColorF(r, g, b uint8) ANSI { - return newAnsi(fmt.Sprintf(esc+"38;2;%d;%d;%dm", r, g, b)) -} - -// FullColorB set the foreground color of text. -func FullColorB(r, g, b uint8) ANSI { - return newAnsi(fmt.Sprintf(esc+"48;2;%d;%d;%dm", r, g, b)) -} - -// Style -var ( - // Bold set the text style to bold or increased intensity. - Bold ANSI - - // Faint set the text style to faint. - Faint ANSI - - // Italic set the text style to italic. - Italic ANSI - - // Underline set the text style to underline. - Underline ANSI - - // BlinkSlow set the text style to slow blink. - BlinkSlow ANSI - - // BlinkRapid set the text style to rapid blink. - BlinkRapid ANSI - - // Inverse swap the foreground color and background color. - Inverse ANSI - - // Conceal set the text style to conceal. - Conceal ANSI - - // CrossOut set the text style to crossed out. - CrossOut ANSI - - // Frame set the text style to framed. - Frame ANSI - - // Encircle set the text style to encircled. - Encircle ANSI - - // Overline set the text style to overlined. - Overline ANSI -) - -// Foreground color of text. -var ( - // DefaultF is the default color of foreground. - DefaultF ANSI - - // Normal color - BlackF ANSI - RedF ANSI - GreenF ANSI - YellowF ANSI - BlueF ANSI - MagentaF ANSI - CyanF ANSI - WhiteF ANSI - - // Light color - LightBlackF ANSI - LightRedF ANSI - LightGreenF ANSI - LightYellowF ANSI - LightBlueF ANSI - LightMagentaF ANSI - LightCyanF ANSI - LightWhiteF ANSI -) - -// Background color of text. -var ( - // DefaultB is the default color of background. - DefaultB ANSI - - // Normal color - BlackB ANSI - RedB ANSI - GreenB ANSI - YellowB ANSI - BlueB ANSI - MagentaB ANSI - CyanB ANSI - WhiteB ANSI - - // Light color - LightBlackB ANSI - LightRedB ANSI - LightGreenB ANSI - LightYellowB ANSI - LightBlueB ANSI - LightMagentaB ANSI - LightCyanB ANSI - LightWhiteB ANSI -) - -func init() { - Bold = newSGR(1) - Faint = newSGR(2) - Italic = newSGR(3) - Underline = newSGR(4) - BlinkSlow = newSGR(5) - BlinkRapid = newSGR(6) - Inverse = newSGR(7) - Conceal = newSGR(8) - CrossOut = newSGR(9) - - BlackF = newSGR(30) - RedF = newSGR(31) - GreenF = newSGR(32) - YellowF = newSGR(33) - BlueF = newSGR(34) - MagentaF = newSGR(35) - CyanF = newSGR(36) - WhiteF = newSGR(37) - - DefaultF = newSGR(39) - - BlackB = newSGR(40) - RedB = newSGR(41) - GreenB = newSGR(42) - YellowB = newSGR(43) - BlueB = newSGR(44) - MagentaB = newSGR(45) - CyanB = newSGR(46) - WhiteB = newSGR(47) - - DefaultB = newSGR(49) - - Frame = newSGR(51) - Encircle = newSGR(52) - Overline = newSGR(53) - - LightBlackF = newSGR(90) - LightRedF = newSGR(91) - LightGreenF = newSGR(92) - LightYellowF = newSGR(93) - LightBlueF = newSGR(94) - LightMagentaF = newSGR(95) - LightCyanF = newSGR(96) - LightWhiteF = newSGR(97) - - LightBlackB = newSGR(100) - LightRedB = newSGR(101) - LightGreenB = newSGR(102) - LightYellowB = newSGR(103) - LightBlueB = newSGR(104) - LightMagentaB = newSGR(105) - LightCyanB = newSGR(106) - LightWhiteB = newSGR(107) -} diff --git a/vendor/github.com/opencontainers/runc/internal/linux/linux.go b/vendor/github.com/opencontainers/runc/internal/linux/linux.go index 88fe5e0dfdf..13713159328 100644 --- a/vendor/github.com/opencontainers/runc/internal/linux/linux.go +++ b/vendor/github.com/opencontainers/runc/internal/linux/linux.go @@ -16,7 +16,7 @@ func Dup3(oldfd, newfd, flags int) error { } // Exec wraps [unix.Exec]. -func Exec(cmd string, args []string, env []string) error { +func Exec(cmd string, args, env []string) error { err := retryOnEINTR(func() error { return unix.Exec(cmd, args, env) }) @@ -66,6 +66,22 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from unix.Sockaddr, err error return n, from, err } +// SchedSetaffinity wraps sched_setaffinity syscall without unix.CPUSet size limitation. +func SchedSetaffinity(pid int, buf []byte) error { + err := retryOnEINTR(func() error { + _, _, errno := unix.Syscall( + unix.SYS_SCHED_SETAFFINITY, + uintptr(pid), + uintptr(len(buf)), + uintptr((unsafe.Pointer)(&buf[0]))) + if errno != 0 { + return errno + } + return nil + }) + return os.NewSyscallError("sched_setaffinity", err) +} + // Sendmsg wraps [unix.Sendmsg]. func Sendmsg(fd int, p, oob []byte, to unix.Sockaddr, flags int) error { err := retryOnEINTR(func() error { @@ -75,13 +91,9 @@ func Sendmsg(fd int, p, oob []byte, to unix.Sockaddr, flags int) error { } // SetMempolicy wraps set_mempolicy. -func SetMempolicy(mode uint, mask *unix.CPUSet) error { +func SetMempolicy(mode int, mask *unix.CPUSet) error { err := retryOnEINTR(func() error { - _, _, errno := unix.Syscall(unix.SYS_SET_MEMPOLICY, uintptr(mode), uintptr(unsafe.Pointer(mask)), unsafe.Sizeof(*mask)*8) - if errno != 0 { - return errno - } - return nil + return unix.SetMemPolicy(mode, mask) }) return os.NewSyscallError("set_mempolicy", err) } diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go index c533eb1c67a..409e58e963d 100644 --- a/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go +++ b/vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go @@ -98,7 +98,7 @@ func GetDevices(path string) ([]*Device, error) { if errors.Is(err, ErrNotADevice) { continue } - if os.IsNotExist(err) { + if errors.Is(err, os.ErrNotExist) { continue } return nil, err diff --git a/vendor/github.com/sigstore/sigstore/pkg/cryptoutils/publickey.go b/vendor/github.com/sigstore/sigstore/pkg/cryptoutils/publickey.go index 63e789a8d2d..1182d0ca35f 100644 --- a/vendor/github.com/sigstore/sigstore/pkg/cryptoutils/publickey.go +++ b/vendor/github.com/sigstore/sigstore/pkg/cryptoutils/publickey.go @@ -19,6 +19,7 @@ import ( "crypto" "crypto/ecdsa" "crypto/ed25519" + "crypto/elliptic" "crypto/rsa" "crypto/sha1" // nolint:gosec "crypto/x509" @@ -28,6 +29,7 @@ import ( "encoding/pem" "errors" "fmt" + "slices" ) const ( @@ -130,3 +132,27 @@ func genErrMsg(first, second crypto.PublicKey, keyType string) string { } return fmt.Sprintf("%s (%s, %s)", msg, hex.EncodeToString(firstSKID), hex.EncodeToString(secondSKID)) } + +// ValidatePubKey validates the parameters of an RSA, ECDSA, or ED25519 public key. +// +// Deprecated: Prefer goodkey.ValidatePubKey. This function has been +// updated to verify only the size of the key for RSA or the curve +// for ECDSA. +func ValidatePubKey(pub crypto.PublicKey) error { + switch pk := pub.(type) { + case *rsa.PublicKey: + if !slices.Contains([]int{2048, 3072, 4096}, pk.Size()*8) { + return fmt.Errorf("rsa key size %d is not supported supported, modulus size must be 2048, 3072, or 4096", pk.Size()*8) + } + return nil + case *ecdsa.PublicKey: + if !slices.Contains([]elliptic.Curve{elliptic.P256(), elliptic.P384(), elliptic.P521()}, pk.Curve) { + return fmt.Errorf("ecdsa curve %T is not supported, must be NIST P-256, P-384 or P-521", pk.Curve) + } + return nil + case ed25519.PublicKey: + // Nothing to validate for Ed25519 + return nil + } + return fmt.Errorf("unsupported public key type: %T", pub) +} diff --git a/vendor/github.com/sigstore/sigstore/pkg/signature/signer.go b/vendor/github.com/sigstore/sigstore/pkg/signature/signer.go index 1122989ff65..50f432798d3 100644 --- a/vendor/github.com/sigstore/sigstore/pkg/signature/signer.go +++ b/vendor/github.com/sigstore/sigstore/pkg/signature/signer.go @@ -31,9 +31,6 @@ import ( "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature/options" - - // these ensure we have the implementations loaded - _ "golang.org/x/crypto/sha3" ) // Signer creates digital signatures over a message using a specified key pair diff --git a/vendor/go.podman.io/common/libnetwork/cni/README.md b/vendor/go.podman.io/common/libnetwork/cni/README.md deleted file mode 100644 index 6f57feff51b..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/README.md +++ /dev/null @@ -1,10 +0,0 @@ -This package abstracts CNI from libpod. -It implements the `ContainerNetwork` interface defined in [libpod/network/types/network.go](../types/network.go) for the CNI backend. - - -## Testing -Run the tests with: -``` -go test -v -mod=vendor -cover ./libpod/network/cni/ -``` -Run the tests as root to also test setup/teardown. This will execute CNI and therefore the cni plugins have to be installed. diff --git a/vendor/go.podman.io/common/libnetwork/cni/cni_conversion.go b/vendor/go.podman.io/common/libnetwork/cni/cni_conversion.go deleted file mode 100644 index c89a867453a..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/cni_conversion.go +++ /dev/null @@ -1,461 +0,0 @@ -//go:build (linux || freebsd) && cni - -package cni - -import ( - "encoding/json" - "errors" - "fmt" - "net" - "os" - "path/filepath" - "slices" - "strconv" - "strings" - "time" - - "github.com/containernetworking/cni/libcni" - "github.com/sirupsen/logrus" - internalutil "go.podman.io/common/libnetwork/internal/util" - "go.podman.io/common/libnetwork/types" - "go.podman.io/common/libnetwork/util" - "golang.org/x/sys/unix" -) - -func createNetworkFromCNIConfigList(conf *libcni.NetworkConfigList, confPath string) (*types.Network, error) { - network := types.Network{ - Name: conf.Name, - ID: getNetworkIDFromName(conf.Name), - Labels: map[string]string{}, - Options: map[string]string{}, - IPAMOptions: map[string]string{}, - } - - cniJSON := make(map[string]any) - err := json.Unmarshal(conf.Bytes, &cniJSON) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal network config %s: %w", conf.Name, err) - } - if args, ok := cniJSON["args"]; ok { - if key, ok := args.(map[string]any); ok { - // read network labels and options from the conf file - network.Labels = getNetworkArgsFromConfList(key, podmanLabelKey) - network.Options = getNetworkArgsFromConfList(key, podmanOptionsKey) - } - } - - t, err := fileTime(confPath) - if err != nil { - return nil, err - } - network.Created = t - - firstPlugin := conf.Plugins[0] - network.Driver = firstPlugin.Network.Type - - switch firstPlugin.Network.Type { - case types.BridgeNetworkDriver: - var bridge hostLocalBridge - err := json.Unmarshal(firstPlugin.Bytes, &bridge) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal the bridge plugin config in %s: %w", confPath, err) - } - network.NetworkInterface = bridge.BrName - - // if isGateway is false we have an internal network - if !bridge.IsGW { - network.Internal = true - } - - // set network options - if bridge.MTU != 0 { - network.Options[types.MTUOption] = strconv.Itoa(bridge.MTU) - } - if bridge.Vlan != 0 { - network.Options[types.VLANOption] = strconv.Itoa(bridge.Vlan) - } - - err = convertIPAMConfToNetwork(&network, &bridge.IPAM, confPath) - if err != nil { - return nil, err - } - - case types.MacVLANNetworkDriver, types.IPVLANNetworkDriver: - var vlan VLANConfig - err := json.Unmarshal(firstPlugin.Bytes, &vlan) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal the macvlan plugin config in %s: %w", confPath, err) - } - network.NetworkInterface = vlan.Master - - // set network options - if vlan.MTU != 0 { - network.Options[types.MTUOption] = strconv.Itoa(vlan.MTU) - } - - if vlan.Mode != "" { - network.Options[types.ModeOption] = vlan.Mode - } - - err = convertIPAMConfToNetwork(&network, &vlan.IPAM, confPath) - if err != nil { - return nil, err - } - - default: - // A warning would be good but users would get this warning every time so keep this at info level. - logrus.Infof("Unsupported CNI config type %s in %s, this network can still be used but inspect or list cannot show all information", - firstPlugin.Network.Type, confPath) - } - - // check if the dnsname plugin is configured - network.DNSEnabled = findPluginByName(conf.Plugins, "dnsname") != nil - - // now get isolation mode from firewall plugin - firewall := findPluginByName(conf.Plugins, "firewall") - if firewall != nil { - var firewallConf firewallConfig - err := json.Unmarshal(firewall.Bytes, &firewallConf) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal the firewall plugin config in %s: %w", confPath, err) - } - if firewallConf.IngressPolicy == ingressPolicySameBridge { - network.Options[types.IsolateOption] = "true" - } - } - - return &network, nil -} - -func findPluginByName(plugins []*libcni.NetworkConfig, name string) *libcni.NetworkConfig { - for i := range plugins { - if plugins[i].Network.Type == name { - return plugins[i] - } - } - return nil -} - -// convertIPAMConfToNetwork converts A cni IPAMConfig to libpod network subnets. -// It returns an array of subnets and an extra bool if dhcp is configured. -func convertIPAMConfToNetwork(network *types.Network, ipam *ipamConfig, confPath string) error { - switch ipam.PluginType { - case "": - network.IPAMOptions[types.Driver] = types.NoneIPAMDriver - case types.DHCPIPAMDriver: - network.IPAMOptions[types.Driver] = types.DHCPIPAMDriver - case types.HostLocalIPAMDriver: - network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver - for _, r := range ipam.Ranges { - for _, ipam := range r { - s := types.Subnet{} - - // Do not use types.ParseCIDR() because we want the ip to be - // the network address and not a random ip in the sub. - _, sub, err := net.ParseCIDR(ipam.Subnet) - if err != nil { - return err - } - s.Subnet = types.IPNet{IPNet: *sub} - - // gateway - var gateway net.IP - if ipam.Gateway != "" { - gateway = net.ParseIP(ipam.Gateway) - if gateway == nil { - return fmt.Errorf("failed to parse gateway ip %s", ipam.Gateway) - } - // convert to 4 byte if ipv4 - util.NormalizeIP(&gateway) - } else if !network.Internal { - // only add a gateway address if the network is not internal - gateway, err = util.FirstIPInSubnet(sub) - if err != nil { - return fmt.Errorf("failed to get first ip in subnet %s", sub.String()) - } - } - s.Gateway = gateway - - var rangeStart net.IP - var rangeEnd net.IP - if ipam.RangeStart != "" { - rangeStart = net.ParseIP(ipam.RangeStart) - if rangeStart == nil { - return fmt.Errorf("failed to parse range start ip %s", ipam.RangeStart) - } - } - if ipam.RangeEnd != "" { - rangeEnd = net.ParseIP(ipam.RangeEnd) - if rangeEnd == nil { - return fmt.Errorf("failed to parse range end ip %s", ipam.RangeEnd) - } - } - if rangeStart != nil || rangeEnd != nil { - s.LeaseRange = &types.LeaseRange{} - s.LeaseRange.StartIP = rangeStart - s.LeaseRange.EndIP = rangeEnd - } - if util.IsIPv6(s.Subnet.IP) { - network.IPv6Enabled = true - } - network.Subnets = append(network.Subnets, s) - } - } - default: - // This is not an error. While we only support certain ipam drivers, we - // cannot make it fail for unsupported ones. CNI is still able to use them, - // just our translation logic cannot convert this into a Network. - // For the same reason this is not warning, it would just be annoying for - // everyone using a unknown ipam driver. - logrus.Infof("unsupported ipam plugin %q in %s", ipam.PluginType, confPath) - network.IPAMOptions[types.Driver] = ipam.PluginType - } - return nil -} - -// getNetworkArgsFromConfList returns the map of args in a conflist, argType should be labels or options. -func getNetworkArgsFromConfList(args map[string]any, argType string) map[string]string { - if args, ok := args[argType]; ok { - if labels, ok := args.(map[string]any); ok { - result := make(map[string]string, len(labels)) - for k, v := range labels { - if v, ok := v.(string); ok { - result[k] = v - } - } - return result - } - } - return map[string]string{} -} - -// createCNIConfigListFromNetwork will create a cni config file from the given network. -// It returns the cni config and the path to the file where the config was written. -// Set writeToDisk to false to only add this network into memory. -func (n *cniNetwork) createCNIConfigListFromNetwork(network *types.Network, writeToDisk bool) (*libcni.NetworkConfigList, string, error) { - var ( - routes []ipamRoute - ipamRanges [][]ipamLocalHostRangeConf - ipamConf *ipamConfig - err error - ) - - ipamDriver := network.IPAMOptions[types.Driver] - switch ipamDriver { - case types.HostLocalIPAMDriver: - defIpv4Route := false - defIpv6Route := false - for _, subnet := range network.Subnets { - ipam := newIPAMLocalHostRange(subnet.Subnet, subnet.LeaseRange, subnet.Gateway) - ipamRanges = append(ipamRanges, []ipamLocalHostRangeConf{*ipam}) - - // only add default route for not internal networks - if !network.Internal { - ipv6 := util.IsIPv6(subnet.Subnet.IP) - if !ipv6 && defIpv4Route { - continue - } - if ipv6 && defIpv6Route { - continue - } - - if ipv6 { - defIpv6Route = true - } else { - defIpv4Route = true - } - route, err := newIPAMDefaultRoute(ipv6) - if err != nil { - return nil, "", err - } - routes = append(routes, route) - } - } - conf := newIPAMHostLocalConf(routes, ipamRanges) - ipamConf = &conf - case types.DHCPIPAMDriver: - ipamConf = &ipamConfig{PluginType: "dhcp"} - - case types.NoneIPAMDriver: - // do nothing - default: - return nil, "", fmt.Errorf("unsupported ipam driver %q", ipamDriver) - } - - opts, err := parseOptions(network.Options, network.Driver) - if err != nil { - return nil, "", err - } - - isGateway := true - ipMasq := true - if network.Internal { - isGateway = false - ipMasq = false - } - // create CNI plugin configuration - // explicitly use CNI version 0.4.0 here, to use v1.0.0 at least containernetwork-plugins-1.0.1 has to be installed - // the dnsname plugin also needs to be updated for 1.0.0 - // TODO change to 1.0.0 when most distros support it - ncList := newNcList(network.Name, "0.4.0", network.Labels, network.Options) - var plugins []any - - switch network.Driver { - case types.BridgeNetworkDriver: - bridge := newHostLocalBridge(network.NetworkInterface, isGateway, ipMasq, opts.mtu, opts.vlan, ipamConf) - plugins = append(plugins, bridge, newPortMapPlugin(), newFirewallPlugin(opts.isolate), newTuningPlugin()) - // if we find the dnsname plugin we add configuration for it - if hasDNSNamePlugin(n.cniPluginDirs) && network.DNSEnabled { - // Note: in the future we might like to allow for dynamic domain names - plugins = append(plugins, newDNSNamePlugin(defaultPodmanDomainName)) - } - - case types.MacVLANNetworkDriver: - plugins = append(plugins, newVLANPlugin(types.MacVLANNetworkDriver, network.NetworkInterface, opts.vlanPluginMode, opts.mtu, ipamConf)) - - case types.IPVLANNetworkDriver: - plugins = append(plugins, newVLANPlugin(types.IPVLANNetworkDriver, network.NetworkInterface, opts.vlanPluginMode, opts.mtu, ipamConf)) - - default: - return nil, "", fmt.Errorf("driver %q is not supported by cni", network.Driver) - } - ncList["plugins"] = plugins - b, err := json.MarshalIndent(ncList, "", " ") - if err != nil { - return nil, "", err - } - cniPathName := "" - if writeToDisk { - if err := os.MkdirAll(n.cniConfigDir, 0o755); err != nil { - return nil, "", err - } - cniPathName = filepath.Join(n.cniConfigDir, network.Name+".conflist") - err = os.WriteFile(cniPathName, b, 0o644) - if err != nil { - return nil, "", err - } - t, err := fileTime(cniPathName) - if err != nil { - return nil, "", err - } - network.Created = t - } else { - network.Created = time.Now() - } - config, err := libcni.ConfListFromBytes(b) - if err != nil { - return nil, "", err - } - return config, cniPathName, nil -} - -func convertSpecgenPortsToCNIPorts(ports []types.PortMapping) ([]cniPortMapEntry, error) { - cniPorts := make([]cniPortMapEntry, 0, len(ports)) - for _, port := range ports { - if port.Protocol == "" { - return nil, errors.New("port protocol should not be empty") - } - for protocol := range strings.SplitSeq(port.Protocol, ",") { - if !slices.Contains([]string{"tcp", "udp", "sctp"}, protocol) { - return nil, fmt.Errorf("unknown port protocol %s", protocol) - } - cniPort := cniPortMapEntry{ - HostPort: int(port.HostPort), - ContainerPort: int(port.ContainerPort), - HostIP: port.HostIP, - Protocol: protocol, - } - cniPorts = append(cniPorts, cniPort) - for i := 1; i < int(port.Range); i++ { - cniPort := cniPortMapEntry{ - HostPort: int(port.HostPort) + i, - ContainerPort: int(port.ContainerPort) + i, - HostIP: port.HostIP, - Protocol: protocol, - } - cniPorts = append(cniPorts, cniPort) - } - } - } - return cniPorts, nil -} - -func removeMachinePlugin(conf *libcni.NetworkConfigList) *libcni.NetworkConfigList { - plugins := make([]*libcni.NetworkConfig, 0, len(conf.Plugins)) - for _, net := range conf.Plugins { - if net.Network.Type != "podman-machine" { - plugins = append(plugins, net) - } - } - conf.Plugins = plugins - return conf -} - -type options struct { - vlan int - mtu int - vlanPluginMode string - isolate bool -} - -func parseOptions(networkOptions map[string]string, networkDriver string) (*options, error) { - opt := &options{} - var err error - for k, v := range networkOptions { - switch k { - case types.MTUOption: - opt.mtu, err = internalutil.ParseMTU(v) - if err != nil { - return nil, err - } - - case types.VLANOption: - opt.vlan, err = internalutil.ParseVlan(v) - if err != nil { - return nil, err - } - - case types.ModeOption: - switch networkDriver { - case types.MacVLANNetworkDriver: - if !slices.Contains(types.ValidMacVLANModes, v) { - return nil, fmt.Errorf("unknown macvlan mode %q", v) - } - case types.IPVLANNetworkDriver: - if !slices.Contains(types.ValidIPVLANModes, v) { - return nil, fmt.Errorf("unknown ipvlan mode %q", v) - } - default: - return nil, fmt.Errorf("cannot set option \"mode\" with driver %q", networkDriver) - } - opt.vlanPluginMode = v - - case types.IsolateOption: - if networkDriver != types.BridgeNetworkDriver { - return nil, errors.New("isolate option is only supported with the bridge driver") - } - opt.isolate, err = strconv.ParseBool(v) - if err != nil { - return nil, fmt.Errorf("failed to parse isolate option: %w", err) - } - - default: - return nil, fmt.Errorf("unsupported network option %s", k) - } - } - return opt, nil -} - -func fileTime(file string) (time.Time, error) { - var st unix.Stat_t - for { - err := unix.Stat(file, &st) - if err == nil { - break - } - if err != unix.EINTR { //nolint:errorlint // unix errors are bare - return time.Time{}, &os.PathError{Path: file, Op: "stat", Err: err} - } - } - return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec)), nil //nolint:unconvert // On some platforms Sec and Nsec are int32. -} diff --git a/vendor/go.podman.io/common/libnetwork/cni/cni_exec.go b/vendor/go.podman.io/common/libnetwork/cni/cni_exec.go deleted file mode 100644 index e4c47f5d73a..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/cni_exec.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2016 CNI authors -// Copyright 2021 Podman authors -// -// This code has been originally copied from github.com/containernetworking/cni -// but has been changed to better fit the Podman use case. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build (linux || freebsd) && cni - -package cni - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/containernetworking/cni/pkg/invoke" - "github.com/containernetworking/cni/pkg/version" - "go.podman.io/storage/pkg/unshare" -) - -type cniExec struct { - version.PluginDecoder -} - -type cniPluginError struct { - plugin string - Code uint `json:"code"` - Msg string `json:"msg"` - Details string `json:"details,omitempty"` -} - -// Error returns a nicely formatted error message for the cni plugin errors. -func (e *cniPluginError) Error() string { - err := fmt.Sprintf("cni plugin %s failed", e.plugin) - if e.Msg != "" { - err = fmt.Sprintf("%s: %s", err, e.Msg) - } else if e.Code > 0 { - err = fmt.Sprintf("%s with error code %d", err, e.Code) - } - if e.Details != "" { - err = fmt.Sprintf("%s: %s", err, e.Details) - } - return err -} - -// ExecPlugin execute the cni plugin. Returns the stdout of the plugin or an error. -func (e *cniExec) ExecPlugin(ctx context.Context, pluginPath string, stdinData []byte, environ []string) ([]byte, error) { - stdout := &bytes.Buffer{} - stderr := &bytes.Buffer{} - c := exec.CommandContext(ctx, pluginPath) - c.Env = environ - c.Stdin = bytes.NewBuffer(stdinData) - c.Stdout = stdout - c.Stderr = stderr - - // The dnsname plugin tries to use XDG_RUNTIME_DIR to store files. - // podman run will have XDG_RUNTIME_DIR set and thus the cni plugin can use - // it. The problem is that XDG_RUNTIME_DIR is unset for the conmon process - // for rootful users. This causes issues since the cleanup process is spawned - // by conmon and thus not have XDG_RUNTIME_DIR set to same value as podman run. - // Because of it dnsname will not find the config files and cannot correctly cleanup. - // To fix this we should also unset XDG_RUNTIME_DIR for the cni plugins as rootful. - if !unshare.IsRootless() { - c.Env = append(c.Env, "XDG_RUNTIME_DIR=") - } - - // The CNI plugins need access to iptables in $PATH. As it turns out debian doesn't put - // /usr/sbin in $PATH for rootless users. This will break rootless networking completely. - // We might break existing users and we cannot expect everyone to change their $PATH so - // let's add /usr/sbin to $PATH ourselves. - path := os.Getenv("PATH") - if !strings.Contains(path, "/usr/sbin") { - path += ":/usr/sbin" - c.Env = append(c.Env, "PATH="+path) - } - - err := c.Run() - if err != nil { - return nil, annotatePluginError(err, pluginPath, stdout.Bytes(), stderr.Bytes()) - } - return stdout.Bytes(), nil -} - -// annotatePluginError parses the common cni plugin error json. -func annotatePluginError(err error, plugin string, stdout, stderr []byte) error { - pluginName := filepath.Base(plugin) - emsg := cniPluginError{ - plugin: pluginName, - } - if len(stdout) == 0 { - if len(stderr) == 0 { - emsg.Msg = err.Error() - } else { - emsg.Msg = string(stderr) - } - } else if perr := json.Unmarshal(stdout, &emsg); perr != nil { - emsg.Msg = fmt.Sprintf("failed to unmarshal error message %q: %v", string(stdout), perr) - } - return &emsg -} - -// FindInPath finds the plugin in the given paths. -func (e *cniExec) FindInPath(plugin string, paths []string) (string, error) { - return invoke.FindInPath(plugin, paths) -} diff --git a/vendor/go.podman.io/common/libnetwork/cni/cni_types.go b/vendor/go.podman.io/common/libnetwork/cni/cni_types.go deleted file mode 100644 index e85a11b4934..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/cni_types.go +++ /dev/null @@ -1,286 +0,0 @@ -//go:build (linux || freebsd) && cni - -package cni - -import ( - "net" - "path/filepath" - - "go.podman.io/common/libnetwork/types" - "go.podman.io/storage/pkg/fileutils" -) - -const ( - defaultIPv4Route = "0.0.0.0/0" - defaultIPv6Route = "::/0" - // defaultPodmanDomainName is used for the dnsname plugin to define - // a localized domain name for a created network. - defaultPodmanDomainName = "dns.podman" - - // cniDeviceName is the default name for a new bridge, it should be suffixed with an integer. - cniDeviceName = "cni-podman" - - // podmanLabelKey key used to store the podman network label in a cni config. - podmanLabelKey = "podman_labels" - - // podmanOptionsKey key used to store the podman network options in a cni config. - podmanOptionsKey = "podman_options" - - // ingressPolicySameBridge is used to only allow connection on the same bridge network. - ingressPolicySameBridge = "same-bridge" -) - -// cniPortMapEntry struct is used by the portmap plugin -// https://github.com/containernetworking/plugins/blob/649e0181fe7b3a61e708f3e4249a798f57f25cc5/plugins/meta/portmap/main.go#L43-L50 -type cniPortMapEntry struct { - HostPort int `json:"hostPort"` - ContainerPort int `json:"containerPort"` - Protocol string `json:"protocol"` - HostIP string `json:"hostIP,omitempty"` -} - -// hostLocalBridge describes a configuration for a bridge plugin -// https://github.com/containernetworking/plugins/tree/master/plugins/main/bridge#network-configuration-reference -type hostLocalBridge struct { - PluginType string `json:"type"` - BrName string `json:"bridge,omitempty"` - IsGW bool `json:"isGateway"` - IsDefaultGW bool `json:"isDefaultGateway,omitempty"` - ForceAddress bool `json:"forceAddress,omitempty"` - IPMasq bool `json:"ipMasq,omitempty"` - MTU int `json:"mtu,omitempty"` - HairpinMode bool `json:"hairpinMode,omitempty"` - PromiscMode bool `json:"promiscMode,omitempty"` - Vlan int `json:"vlan,omitempty"` - IPAM ipamConfig `json:"ipam"` - Capabilities map[string]bool `json:"capabilities,omitempty"` -} - -// ipamConfig describes an IPAM configuration -// https://github.com/containernetworking/plugins/tree/master/plugins/ipam/host-local#network-configuration-reference -type ipamConfig struct { - PluginType string `json:"type"` - Routes []ipamRoute `json:"routes,omitempty"` - ResolveConf string `json:"resolveConf,omitempty"` - DataDir string `json:"dataDir,omitempty"` - Ranges [][]ipamLocalHostRangeConf `json:"ranges,omitempty"` -} - -// ipamLocalHostRangeConf describes the new style IPAM ranges. -type ipamLocalHostRangeConf struct { - Subnet string `json:"subnet"` - RangeStart string `json:"rangeStart,omitempty"` - RangeEnd string `json:"rangeEnd,omitempty"` - Gateway string `json:"gateway,omitempty"` -} - -// ipamRoute describes a route in an ipam config. -type ipamRoute struct { - Dest string `json:"dst"` -} - -// portMapConfig describes the default portmapping config. -type portMapConfig struct { - PluginType string `json:"type"` - Capabilities map[string]bool `json:"capabilities"` -} - -// VLANConfig describes the macvlan config. -type VLANConfig struct { - PluginType string `json:"type"` - Master string `json:"master"` - IPAM ipamConfig `json:"ipam"` - MTU int `json:"mtu,omitempty"` - Mode string `json:"mode,omitempty"` - Capabilities map[string]bool `json:"capabilities,omitempty"` -} - -// firewallConfig describes the firewall plugin. -type firewallConfig struct { - PluginType string `json:"type"` - Backend string `json:"backend"` - IngressPolicy string `json:"ingressPolicy,omitempty"` -} - -// tuningConfig describes the tuning plugin. -type tuningConfig struct { - PluginType string `json:"type"` -} - -// dnsNameConfig describes the dns container name resolution plugin config. -type dnsNameConfig struct { - PluginType string `json:"type"` - DomainName string `json:"domainName"` - Capabilities map[string]bool `json:"capabilities"` -} - -// ncList describes a generic map. -type ncList map[string]any - -// newNcList creates a generic map of values with string -// keys and adds in version and network name. -func newNcList(name, version string, labels, options map[string]string) ncList { - n := ncList{} - n["cniVersion"] = version - n["name"] = name - args := map[string]map[string]string{} - if len(labels) > 0 { - args[podmanLabelKey] = labels - } - if len(options) > 0 { - args[podmanOptionsKey] = options - } - if len(args) > 0 { - n["args"] = args - } - return n -} - -// newHostLocalBridge creates a new LocalBridge for host-local. -func newHostLocalBridge(name string, isGateWay, ipMasq bool, mtu, vlan int, ipamConf *ipamConfig) *hostLocalBridge { - bridge := hostLocalBridge{ - PluginType: "bridge", - BrName: name, - IsGW: isGateWay, - IPMasq: ipMasq, - MTU: mtu, - HairpinMode: true, - Vlan: vlan, - } - if ipamConf != nil { - bridge.IPAM = *ipamConf - // if we use host-local set the ips cap to ensure we can set static ips via runtime config - if ipamConf.PluginType == types.HostLocalIPAMDriver { - bridge.Capabilities = map[string]bool{"ips": true} - } - } - return &bridge -} - -// newIPAMHostLocalConf creates a new IPAMHostLocal configuration. -func newIPAMHostLocalConf(routes []ipamRoute, ipamRanges [][]ipamLocalHostRangeConf) ipamConfig { - ipamConf := ipamConfig{ - PluginType: "host-local", - Routes: routes, - } - - ipamConf.Ranges = ipamRanges - return ipamConf -} - -// newIPAMLocalHostRange create a new IPAM range. -func newIPAMLocalHostRange(subnet types.IPNet, leaseRange *types.LeaseRange, gw net.IP) *ipamLocalHostRangeConf { - hostRange := &ipamLocalHostRangeConf{ - Subnet: subnet.String(), - } - - // a user provided a range, we add it here - if leaseRange != nil { - if leaseRange.StartIP != nil { - hostRange.RangeStart = leaseRange.StartIP.String() - } - if leaseRange.EndIP != nil { - hostRange.RangeEnd = leaseRange.EndIP.String() - } - } - - if gw != nil { - hostRange.Gateway = gw.String() - } - return hostRange -} - -// newIPAMRoute creates a new IPAM route configuration -// nolint:interfacer -func newIPAMRoute(r *net.IPNet) ipamRoute { - return ipamRoute{Dest: r.String()} -} - -// newIPAMDefaultRoute creates a new IPAMDefault route of -// 0.0.0.0/0 for IPv4 or ::/0 for IPv6. -func newIPAMDefaultRoute(isIPv6 bool) (ipamRoute, error) { - route := defaultIPv4Route - if isIPv6 { - route = defaultIPv6Route - } - _, n, err := net.ParseCIDR(route) - if err != nil { - return ipamRoute{}, err - } - return newIPAMRoute(n), nil -} - -// newPortMapPlugin creates a predefined, default portmapping -// configuration. -func newPortMapPlugin() portMapConfig { - return portMapConfig{ - PluginType: "portmap", - Capabilities: map[string]bool{"portMappings": true}, - } -} - -// newFirewallPlugin creates a generic firewall plugin. -func newFirewallPlugin(isolate bool) firewallConfig { - fw := firewallConfig{ - PluginType: "firewall", - } - if isolate { - fw.IngressPolicy = ingressPolicySameBridge - } - return fw -} - -// newTuningPlugin creates a generic tuning section. -func newTuningPlugin() tuningConfig { - return tuningConfig{ - PluginType: "tuning", - } -} - -// newDNSNamePlugin creates the dnsname config with a given -// domainname. -func newDNSNamePlugin(domainName string) dnsNameConfig { - return dnsNameConfig{ - PluginType: "dnsname", - DomainName: domainName, - Capabilities: map[string]bool{"aliases": true}, - } -} - -// hasDNSNamePlugin looks to see if the dnsname cni plugin is present. -func hasDNSNamePlugin(paths []string) bool { - for _, p := range paths { - if err := fileutils.Exists(filepath.Join(p, "dnsname")); err == nil { - return true - } - } - return false -} - -// newVLANPlugin creates a macvlanconfig with a given device name. -func newVLANPlugin(pluginType, device, mode string, mtu int, ipam *ipamConfig) VLANConfig { - m := VLANConfig{ - PluginType: pluginType, - } - if ipam != nil { - m.IPAM = *ipam - } - if mtu > 0 { - m.MTU = mtu - } - if len(mode) > 0 { - m.Mode = mode - } - // CNI is supposed to use the default route if a - // parent device is not provided - if len(device) > 0 { - m.Master = device - } - caps := make(map[string]bool) - caps["ips"] = true - // if we use host-local set the ips cap to ensure we can set static ips via runtime config - if m.IPAM.PluginType == types.HostLocalIPAMDriver { - m.Capabilities = caps - } - return m -} diff --git a/vendor/go.podman.io/common/libnetwork/cni/config.go b/vendor/go.podman.io/common/libnetwork/cni/config.go deleted file mode 100644 index a8060bd7237..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/config.go +++ /dev/null @@ -1,246 +0,0 @@ -//go:build (linux || freebsd) && cni - -package cni - -import ( - "errors" - "fmt" - "net" - "os" - "slices" - - "github.com/sirupsen/logrus" - internalutil "go.podman.io/common/libnetwork/internal/util" - "go.podman.io/common/libnetwork/types" -) - -func (n *cniNetwork) NetworkUpdate(_ string, _ types.NetworkUpdateOptions) error { - return fmt.Errorf("NetworkUpdate is not supported for backend CNI: %w", types.ErrInvalidArg) -} - -// NetworkCreate will take a partial filled Network and fill the -// missing fields. It creates the Network and returns the full Network. -func (n *cniNetwork) NetworkCreate(net types.Network, options *types.NetworkCreateOptions) (types.Network, error) { - n.lock.Lock() - defer n.lock.Unlock() - err := n.loadNetworks() - if err != nil { - return types.Network{}, err - } - network, err := n.networkCreate(&net, false) - if err != nil { - if options != nil && options.IgnoreIfExists && errors.Is(err, types.ErrNetworkExists) { - if network, ok := n.networks[net.Name]; ok { - return *network.libpodNet, nil - } - } - return types.Network{}, err - } - // add the new network to the map - n.networks[network.libpodNet.Name] = network - return *network.libpodNet, nil -} - -// networkCreate will fill out the given network struct and return the new network entry. -// If defaultNet is true it will not validate against used subnets and it will not write the cni config to disk. -func (n *cniNetwork) networkCreate(newNetwork *types.Network, defaultNet bool) (*network, error) { - if len(newNetwork.NetworkDNSServers) > 0 { - return nil, fmt.Errorf("NetworkDNSServers cannot be configured for backend CNI: %w", types.ErrInvalidArg) - } - // if no driver is set use the default one - if newNetwork.Driver == "" { - newNetwork.Driver = types.DefaultNetworkDriver - } - - // FIXME: Should we use a different type for network create without the ID field? - // the caller is not allowed to set a specific ID - if newNetwork.ID != "" { - return nil, fmt.Errorf("ID can not be set for network create: %w", types.ErrInvalidArg) - } - - err := internalutil.CommonNetworkCreate(n, newNetwork) - if err != nil { - return nil, err - } - - err = validateIPAMDriver(newNetwork) - if err != nil { - return nil, err - } - - // Only get the used networks for validation if we do not create the default network. - // The default network should not be validated against used subnets, we have to ensure - // that this network can always be created even when a subnet is already used on the host. - // This could happen if you run a container on this net, then the cni interface will be - // created on the host and "block" this subnet from being used again. - // Therefore the next podman command tries to create the default net again and it would - // fail because it thinks the network is used on the host. - var usedNetworks []*net.IPNet - if !defaultNet && newNetwork.Driver == types.BridgeNetworkDriver { - usedNetworks, err = internalutil.GetUsedSubnets(n) - if err != nil { - return nil, err - } - } - - switch newNetwork.Driver { - case types.BridgeNetworkDriver: - internalutil.MapDockerBridgeDriverOptions(newNetwork) - err = internalutil.CreateBridge(n, newNetwork, usedNetworks, n.defaultsubnetPools, true) - if err != nil { - return nil, err - } - case types.MacVLANNetworkDriver, types.IPVLANNetworkDriver: - err = createIPMACVLAN(newNetwork) - if err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("unsupported driver %s: %w", newNetwork.Driver, types.ErrInvalidArg) - } - - err = internalutil.ValidateSubnets(newNetwork, !newNetwork.Internal, usedNetworks) - if err != nil { - return nil, err - } - - // generate the network ID - newNetwork.ID = getNetworkIDFromName(newNetwork.Name) - - // when we do not have ipam we must disable dns - internalutil.IpamNoneDisableDNS(newNetwork) - - // FIXME: Should this be a hard error? - if newNetwork.DNSEnabled && newNetwork.Internal && hasDNSNamePlugin(n.cniPluginDirs) { - logrus.Warnf("dnsname and internal networks are incompatible. dnsname plugin not configured for network %s", newNetwork.Name) - newNetwork.DNSEnabled = false - } - - cniConf, path, err := n.createCNIConfigListFromNetwork(newNetwork, !defaultNet) - if err != nil { - return nil, err - } - return &network{cniNet: cniConf, libpodNet: newNetwork, filename: path}, nil -} - -// NetworkRemove will remove the Network with the given name or ID. -// It does not ensure that the network is unused. -func (n *cniNetwork) NetworkRemove(nameOrID string) error { - n.lock.Lock() - defer n.lock.Unlock() - err := n.loadNetworks() - if err != nil { - return err - } - - network, err := n.getNetwork(nameOrID) - if err != nil { - return err - } - - // Removing the default network is not allowed. - if network.libpodNet.Name == n.defaultNetwork { - return fmt.Errorf("default network %s cannot be removed", n.defaultNetwork) - } - - // Remove the bridge network interface on the host. - if network.libpodNet.Driver == types.BridgeNetworkDriver { - deleteLink(network.libpodNet.NetworkInterface) - } - - file := network.filename - delete(n.networks, network.libpodNet.Name) - - // make sure to not error for ErrNotExist - if err := os.Remove(file); err != nil && !errors.Is(err, os.ErrNotExist) { - return err - } - return nil -} - -// NetworkList will return all known Networks. Optionally you can -// supply a list of filter functions. Only if a network matches all -// functions it is returned. -func (n *cniNetwork) NetworkList(filters ...types.FilterFunc) ([]types.Network, error) { - n.lock.Lock() - defer n.lock.Unlock() - err := n.loadNetworks() - if err != nil { - return nil, err - } - - networks := make([]types.Network, 0, len(n.networks)) -outer: - for _, net := range n.networks { - for _, filter := range filters { - // All filters have to match, if one does not match we can skip to the next network. - if !filter(*net.libpodNet) { - continue outer - } - } - networks = append(networks, *net.libpodNet) - } - return networks, nil -} - -// NetworkInspect will return the Network with the given name or ID. -func (n *cniNetwork) NetworkInspect(nameOrID string) (types.Network, error) { - n.lock.Lock() - defer n.lock.Unlock() - err := n.loadNetworks() - if err != nil { - return types.Network{}, err - } - - network, err := n.getNetwork(nameOrID) - if err != nil { - return types.Network{}, err - } - return *network.libpodNet, nil -} - -func createIPMACVLAN(network *types.Network) error { - if network.NetworkInterface != "" { - interfaceNames, err := internalutil.GetLiveNetworkNames() - if err != nil { - return err - } - if !slices.Contains(interfaceNames, network.NetworkInterface) { - return fmt.Errorf("parent interface %s does not exist", network.NetworkInterface) - } - } - - switch network.IPAMOptions[types.Driver] { - // set default - case "": - if len(network.Subnets) == 0 { - // if no subnets and no driver choose dhcp - network.IPAMOptions[types.Driver] = types.DHCPIPAMDriver - } else { - network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver - } - case types.HostLocalIPAMDriver: - if len(network.Subnets) == 0 { - return errors.New("host-local ipam driver set but no subnets are given") - } - } - - if network.IPAMOptions[types.Driver] == types.DHCPIPAMDriver && network.Internal { - return errors.New("internal is not supported with macvlan and dhcp ipam driver") - } - return nil -} - -func validateIPAMDriver(n *types.Network) error { - ipamDriver := n.IPAMOptions[types.Driver] - switch ipamDriver { - case "", types.HostLocalIPAMDriver: - case types.DHCPIPAMDriver, types.NoneIPAMDriver: - if len(n.Subnets) > 0 { - return fmt.Errorf("%s ipam driver is set but subnets are given", ipamDriver) - } - default: - return fmt.Errorf("unsupported ipam driver %q", ipamDriver) - } - return nil -} diff --git a/vendor/go.podman.io/common/libnetwork/cni/config_freebsd.go b/vendor/go.podman.io/common/libnetwork/cni/config_freebsd.go deleted file mode 100644 index ddee6d2e01e..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/config_freebsd.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build (linux || freebsd) && cni - -package cni - -import ( - "os/exec" - - "github.com/sirupsen/logrus" -) - -func deleteLink(name string) { - if output, err := exec.Command("ifconfig", name, "destroy").CombinedOutput(); err != nil { - // only log the error, it is not fatal - logrus.Infof("Failed to remove network interface %s: %v: %s", name, err, output) - } -} diff --git a/vendor/go.podman.io/common/libnetwork/cni/config_linux.go b/vendor/go.podman.io/common/libnetwork/cni/config_linux.go deleted file mode 100644 index efc920614c0..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/config_linux.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build (linux || freebsd) && cni - -package cni - -import ( - "github.com/sirupsen/logrus" - "github.com/vishvananda/netlink" -) - -func deleteLink(name string) { - link, err := netlink.LinkByName(name) - if err == nil { - err = netlink.LinkDel(link) - // only log the error, it is not fatal - if err != nil { - logrus.Infof("Failed to remove network interface %s: %v", name, err) - } - } -} diff --git a/vendor/go.podman.io/common/libnetwork/cni/network.go b/vendor/go.podman.io/common/libnetwork/cni/network.go deleted file mode 100644 index 33220a2827b..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/network.go +++ /dev/null @@ -1,359 +0,0 @@ -//go:build (linux || freebsd) && cni - -package cni - -import ( - "context" - "crypto/sha256" - "encoding/hex" - "errors" - "fmt" - "io/fs" - "os" - "path/filepath" - "strings" - "time" - - "github.com/containernetworking/cni/libcni" - "github.com/sirupsen/logrus" - "go.podman.io/common/libnetwork/internal/rootlessnetns" - "go.podman.io/common/libnetwork/types" - "go.podman.io/common/pkg/config" - "go.podman.io/common/pkg/version" - "go.podman.io/storage/pkg/fileutils" - "go.podman.io/storage/pkg/lockfile" - "go.podman.io/storage/pkg/unshare" -) - -const defaultRootLockPath = "/run/lock/podman-cni.lock" - -type cniNetwork struct { - // cniConfigDir is directory where the cni config files are stored. - cniConfigDir string - // cniPluginDirs is a list of directories where cni should look for the plugins. - cniPluginDirs []string - - cniConf *libcni.CNIConfig - - // defaultNetwork is the name for the default network. - defaultNetwork string - // defaultSubnet is the default subnet for the default network. - defaultSubnet types.IPNet - - // defaultsubnetPools contains the subnets which must be used to allocate a free subnet by network create - defaultsubnetPools []config.SubnetPool - - // isMachine describes whenever podman runs in a podman machine environment. - isMachine bool - - // lock is a internal lock for critical operations - lock *lockfile.LockFile - - // modTime is the timestamp when the config dir was modified - modTime time.Time - - // networks is a map with loaded networks, the key is the network name - networks map[string]*network - - // rootlessNetns is used for the rootless network setup/teardown - rootlessNetns *rootlessnetns.Netns -} - -type network struct { - // filename is the full path to the cni config file on disk - filename string - libpodNet *types.Network - cniNet *libcni.NetworkConfigList -} - -type InitConfig struct { - // CNIConfigDir is directory where the cni config files are stored. - CNIConfigDir string - // RunDir is a directory where temporary files can be stored. - RunDir string - - // IsMachine describes whenever podman runs in a podman machine environment. - IsMachine bool - - // Config containers.conf options - Config *config.Config -} - -// NewCNINetworkInterface creates the ContainerNetwork interface for the CNI backend. -// Note: The networks are not loaded from disk until a method is called. -func NewCNINetworkInterface(conf *InitConfig) (types.ContainerNetwork, error) { - var netns *rootlessnetns.Netns - var err error - // Do not use unshare.IsRootless() here. We only care if we are running re-exec in the userns, - // IsRootless() also returns true if we are root in a userns which is not what we care about and - // causes issues as this slower more complicated rootless-netns logic should not be used as root. - val, ok := os.LookupEnv(unshare.UsernsEnvName) - useRootlessNetns := ok && val == "done" - if useRootlessNetns { - netns, err = rootlessnetns.New(conf.RunDir, rootlessnetns.CNI, conf.Config) - if err != nil { - return nil, err - } - } - - // root needs to use a globally unique lock because there is only one host netns - lockPath := defaultRootLockPath - if useRootlessNetns { - lockPath = filepath.Join(conf.CNIConfigDir, "cni.lock") - } - - lock, err := lockfile.GetLockFile(lockPath) - if err != nil { - return nil, err - } - - defaultNetworkName := conf.Config.Network.DefaultNetwork - if defaultNetworkName == "" { - defaultNetworkName = types.DefaultNetworkName - } - - defaultSubnet := conf.Config.Network.DefaultSubnet - if defaultSubnet == "" { - defaultSubnet = types.DefaultSubnet - } - defaultNet, err := types.ParseCIDR(defaultSubnet) - if err != nil { - return nil, fmt.Errorf("failed to parse default subnet: %w", err) - } - - defaultSubnetPools := conf.Config.Network.DefaultSubnetPools - if defaultSubnetPools == nil { - defaultSubnetPools = config.DefaultSubnetPools - } - - cni := libcni.NewCNIConfig(conf.Config.Network.CNIPluginDirs.Values, &cniExec{}) - n := &cniNetwork{ - cniConfigDir: conf.CNIConfigDir, - cniPluginDirs: conf.Config.Network.CNIPluginDirs.Get(), - cniConf: cni, - defaultNetwork: defaultNetworkName, - defaultSubnet: defaultNet, - defaultsubnetPools: defaultSubnetPools, - isMachine: conf.IsMachine, - lock: lock, - rootlessNetns: netns, - } - - return n, nil -} - -// Drivers will return the list of supported network drivers -// for this interface. -func (n *cniNetwork) Drivers() []string { - return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver, types.IPVLANNetworkDriver} -} - -// DefaultNetworkName will return the default cni network name. -func (n *cniNetwork) DefaultNetworkName() string { - return n.defaultNetwork -} - -func (n *cniNetwork) loadNetworks() error { - // check the mod time of the config dir - var modTime time.Time - f, err := os.Stat(n.cniConfigDir) - // ignore error if the file does not exists - if err != nil && !errors.Is(err, os.ErrNotExist) { - return err - } - if err == nil { - modTime = f.ModTime() - } - - // skip loading networks if they are already loaded and - // if the config dir was not modified since the last call - if n.networks != nil && modTime.Equal(n.modTime) { - return nil - } - // make sure the remove all networks before we reload them - n.networks = nil - n.modTime = modTime - - // FIXME: do we have to support other file types as well, e.g. .conf? - files, err := libcni.ConfFiles(n.cniConfigDir, []string{".conflist"}) - if err != nil { - return err - } - networks := make(map[string]*network, len(files)) - for _, file := range files { - conf, err := libcni.ConfListFromFile(file) - if err != nil { - // do not log ENOENT errors - if !errors.Is(err, os.ErrNotExist) { - logrus.Warnf("Error loading CNI config file %s: %v", file, err) - } - continue - } - - if !types.NameRegex.MatchString(conf.Name) { - logrus.Warnf("CNI config list %s has invalid name, skipping: %v", file, types.ErrInvalidName) - continue - } - - // podman < v4.0 used the podman-machine cni plugin for podman machine port forwarding - // since this is now build into podman we no longer use the plugin - // old configs may still contain it so we just remove it here - if n.isMachine { - conf = removeMachinePlugin(conf) - } - - if _, err := n.cniConf.ValidateNetworkList(context.Background(), conf); err != nil { - logrus.Warnf("Error validating CNI config file %s: %v", file, err) - continue - } - - if val, ok := networks[conf.Name]; ok { - logrus.Warnf("CNI config list %s has the same network name as %s, skipping", file, val.filename) - continue - } - - net, err := createNetworkFromCNIConfigList(conf, file) - if err != nil { - // ignore ENOENT as the config has been removed in the meantime so we can just ignore this case - if !errors.Is(err, fs.ErrNotExist) { - logrus.Errorf("CNI config list %s could not be converted to a libpod config, skipping: %v", file, err) - } - continue - } - logrus.Debugf("Successfully loaded network %s: %v", net.Name, net) - networkInfo := network{ - filename: file, - cniNet: conf, - libpodNet: net, - } - networks[net.Name] = &networkInfo - } - - // create the default network in memory if it did not exists on disk - if networks[n.defaultNetwork] == nil { - networkInfo, err := n.createDefaultNetwork() - if err != nil { - return fmt.Errorf("failed to create default network %s: %w", n.defaultNetwork, err) - } - networks[n.defaultNetwork] = networkInfo - } - - logrus.Debugf("Successfully loaded %d networks", len(networks)) - n.networks = networks - return nil -} - -func (n *cniNetwork) createDefaultNetwork() (*network, error) { - net := types.Network{ - Name: n.defaultNetwork, - NetworkInterface: "cni-podman0", - Driver: types.BridgeNetworkDriver, - Subnets: []types.Subnet{ - {Subnet: n.defaultSubnet}, - }, - } - return n.networkCreate(&net, true) -} - -// getNetwork will lookup a network by name or ID. It returns an -// error when no network was found or when more than one network -// with the given (partial) ID exists. -// getNetwork will read from the networks map, therefore the caller -// must ensure that n.lock is locked before using it. -func (n *cniNetwork) getNetwork(nameOrID string) (*network, error) { - // fast path check the map key, this will only work for names - if val, ok := n.networks[nameOrID]; ok { - return val, nil - } - // If there was no match we might got a full or partial ID. - var net *network - for _, val := range n.networks { - // This should not happen because we already looked up the map by name but check anyway. - if val.libpodNet.Name == nameOrID { - return val, nil - } - - if strings.HasPrefix(val.libpodNet.ID, nameOrID) { - if net != nil { - return nil, fmt.Errorf("more than one result for network ID %s", nameOrID) - } - net = val - } - } - if net != nil { - return net, nil - } - return nil, fmt.Errorf("unable to find network with name or ID %s: %w", nameOrID, types.ErrNoSuchNetwork) -} - -// getNetworkIDFromName creates a network ID from the name. It is just the -// sha256 hash so it is not safe but it should be safe enough for our use case. -func getNetworkIDFromName(name string) string { - hash := sha256.Sum256([]byte(name)) - return hex.EncodeToString(hash[:]) -} - -// Implement the NetUtil interface for easy code sharing with other network interfaces. - -// ForEach call the given function for each network. -func (n *cniNetwork) ForEach(run func(types.Network)) { - for _, val := range n.networks { - run(*val.libpodNet) - } -} - -// Len return the number of networks. -func (n *cniNetwork) Len() int { - return len(n.networks) -} - -// DefaultInterfaceName return the default cni bridge name, must be suffixed with a number. -func (n *cniNetwork) DefaultInterfaceName() string { - return cniDeviceName -} - -// NetworkInfo return the network information about binary path, -// package version and program version. -func (n *cniNetwork) NetworkInfo() types.NetworkInfo { - path := "" - packageVersion := "" - for _, p := range n.cniPluginDirs { - ver := version.Package(p) - if ver != version.UnknownPackage { - path = p - packageVersion = ver - break - } - } - - info := types.NetworkInfo{ - Backend: types.CNI, - Package: packageVersion, - Path: path, - DefaultNetwork: n.defaultNetwork, - } - - dnsPath := filepath.Join(path, "dnsname") - dnsPackage := version.Package(dnsPath) - dnsProgram, err := version.ProgramDnsname(dnsPath) - if err != nil { - logrus.Infof("Failed to get the dnsname plugin version: %v", err) - } - if err := fileutils.Exists(dnsPath); err == nil { - info.DNS = types.DNSNetworkInfo{ - Path: dnsPath, - Package: dnsPackage, - Version: dnsProgram, - } - } - - return info -} - -func (n *cniNetwork) Network(nameOrID string) (*types.Network, error) { - network, err := n.getNetwork(nameOrID) - if err != nil { - return nil, err - } - return network.libpodNet, err -} diff --git a/vendor/go.podman.io/common/libnetwork/cni/run.go b/vendor/go.podman.io/common/libnetwork/cni/run.go deleted file mode 100644 index 7877891a9a2..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/run.go +++ /dev/null @@ -1,302 +0,0 @@ -//go:build (linux || freebsd) && cni - -package cni - -import ( - "context" - "fmt" - "net" - "os" - "strings" - - "github.com/containernetworking/cni/libcni" - cnitypes "github.com/containernetworking/cni/pkg/types" - types040 "github.com/containernetworking/cni/pkg/types/040" - "github.com/hashicorp/go-multierror" - "github.com/sirupsen/logrus" - "go.podman.io/common/libnetwork/internal/util" - "go.podman.io/common/libnetwork/types" -) - -// Setup will setup the container network namespace. It returns -// a map of StatusBlocks, the key is the network name. -func (n *cniNetwork) Setup(namespacePath string, options types.SetupOptions) (map[string]types.StatusBlock, error) { - n.lock.Lock() - defer n.lock.Unlock() - err := n.loadNetworks() - if err != nil { - return nil, err - } - - err = util.ValidateSetupOptions(n, namespacePath, options) - if err != nil { - return nil, err - } - - err = setupLoopback(namespacePath) - if err != nil { - return nil, fmt.Errorf("failed to set the loopback adapter up: %w", err) - } - - results := make(map[string]types.StatusBlock, len(options.Networks)) - - setup := func() error { - var retErr error - teardownOpts := options - teardownOpts.Networks = map[string]types.PerNetworkOptions{} - // make sure to teardown the already connected networks on error - defer func() { - if retErr != nil { - if len(teardownOpts.Networks) > 0 { - err := n.teardown(namespacePath, types.TeardownOptions(teardownOpts)) - if err != nil { - logrus.Warn(err) - } - } - } - }() - - ports, err := convertSpecgenPortsToCNIPorts(options.PortMappings) - if err != nil { - return err - } - - for name, netOpts := range options.Networks { - network := n.networks[name] - rt := getRuntimeConfig(namespacePath, options.ContainerName, options.ContainerID, name, ports, &netOpts) - - // If we have more than one static ip we need parse the ips via runtime config, - // make sure to add the ips capability to the first plugin otherwise it doesn't get the ips - if len(netOpts.StaticIPs) > 0 && !network.cniNet.Plugins[0].Network.Capabilities["ips"] { - caps := map[string]any{ - "capabilities": map[string]bool{"ips": true}, - } - network.cniNet.Plugins[0], retErr = libcni.InjectConf(network.cniNet.Plugins[0], caps) - if retErr != nil { - return retErr - } - } - - var res cnitypes.Result - res, retErr = n.cniConf.AddNetworkList(context.Background(), network.cniNet, rt) - // Add this network to teardown opts since it is now connected. - // Also add this if an errors was returned since we want to call teardown on this regardless. - teardownOpts.Networks[name] = netOpts - if retErr != nil { - return retErr - } - - logrus.Debugf("cni result for container %s network %s: %v", options.ContainerID, name, res) - var status types.StatusBlock - status, retErr = CNIResultToStatus(res) - if retErr != nil { - return retErr - } - results[name] = status - } - return nil - } - - if n.rootlessNetns != nil { - err = n.rootlessNetns.Setup(len(options.Networks), setup) - } else { - err = setup() - } - return results, err -} - -// CNIResultToStatus convert the cni result to status block -// nolint:golint,revive -func CNIResultToStatus(res cnitypes.Result) (types.StatusBlock, error) { - result := types.StatusBlock{} - cniResult, err := types040.GetResult(res) - if err != nil { - return result, err - } - nameservers := make([]net.IP, 0, len(cniResult.DNS.Nameservers)) - for _, nameserver := range cniResult.DNS.Nameservers { - ip := net.ParseIP(nameserver) - if ip == nil { - return result, fmt.Errorf("failed to parse cni nameserver ip %s", nameserver) - } - nameservers = append(nameservers, ip) - } - result.DNSServerIPs = nameservers - result.DNSSearchDomains = cniResult.DNS.Search - - interfaces := make(map[string]types.NetInterface) - for intIndex, netInterface := range cniResult.Interfaces { - // we are only interested about interfaces in the container namespace - if netInterface.Sandbox == "" { - continue - } - - mac, err := net.ParseMAC(netInterface.Mac) - if err != nil { - return result, err - } - subnets := make([]types.NetAddress, 0, len(cniResult.IPs)) - for _, ip := range cniResult.IPs { - if ip.Interface == nil { - // we do no expect ips without an interface - continue - } - if len(cniResult.Interfaces) <= *ip.Interface { - return result, fmt.Errorf("invalid cni result, interface index %d out of range", *ip.Interface) - } - - // when we have a ip for this interface add it to the subnets - if *ip.Interface == intIndex { - subnets = append(subnets, types.NetAddress{ - IPNet: types.IPNet{IPNet: ip.Address}, - Gateway: ip.Gateway, - }) - } - } - interfaces[netInterface.Name] = types.NetInterface{ - MacAddress: types.HardwareAddr(mac), - Subnets: subnets, - } - } - result.Interfaces = interfaces - return result, nil -} - -func getRuntimeConfig(netns, conName, conID, networkName string, ports []cniPortMapEntry, opts *types.PerNetworkOptions) *libcni.RuntimeConf { - rt := &libcni.RuntimeConf{ - ContainerID: conID, - NetNS: netns, - IfName: opts.InterfaceName, - Args: [][2]string{ - {"IgnoreUnknown", "1"}, - // Do not set the K8S env vars, see https://github.com/containers/podman/issues/12083. - // Only K8S_POD_NAME is used by dnsname to get the container name. - {"K8S_POD_NAME", conName}, - }, - CapabilityArgs: map[string]any{}, - } - - // Propagate environment CNI_ARGS - for kvpairs := range strings.SplitSeq(os.Getenv("CNI_ARGS"), ";") { - if key, val, ok := strings.Cut(kvpairs, "="); ok { - rt.Args = append(rt.Args, [2]string{key, val}) - } - } - - // Add mac address to cni args - if len(opts.StaticMAC) > 0 { - rt.Args = append(rt.Args, [2]string{"MAC", opts.StaticMAC.String()}) - } - - if len(opts.StaticIPs) == 1 { - // Add a single IP to the args field. CNI plugins < 1.0.0 - // do not support multiple ips via capability args. - rt.Args = append(rt.Args, [2]string{"IP", opts.StaticIPs[0].String()}) - } else if len(opts.StaticIPs) > 1 { - // Set the static ips in the capability args - // to support more than one static ip per network. - rt.CapabilityArgs["ips"] = opts.StaticIPs - } - - // Set network aliases for the dnsname plugin. - if len(opts.Aliases) > 0 { - rt.CapabilityArgs["aliases"] = map[string][]string{ - networkName: opts.Aliases, - } - } - - // Set PortMappings in Capabilities - if len(ports) > 0 { - rt.CapabilityArgs["portMappings"] = ports - } - - return rt -} - -// Teardown will teardown the container network namespace. -func (n *cniNetwork) Teardown(namespacePath string, options types.TeardownOptions) error { - n.lock.Lock() - defer n.lock.Unlock() - err := n.loadNetworks() - if err != nil { - return err - } - return n.teardown(namespacePath, options) -} - -func (n *cniNetwork) teardown(namespacePath string, options types.TeardownOptions) error { - // Note: An empty namespacePath is allowed because some plugins - // still need teardown, for example ipam should remove used ip allocations. - - ports, err := convertSpecgenPortsToCNIPorts(options.PortMappings) - if err != nil { - return err - } - - var multiErr *multierror.Error - teardown := func() error { - for name, netOpts := range options.Networks { - rt := getRuntimeConfig(namespacePath, options.ContainerName, options.ContainerID, name, ports, &netOpts) - - cniConfList, newRt, err := getCachedNetworkConfig(n.cniConf, name, rt) - if err == nil { - rt = newRt - } else { - logrus.Warnf("Failed to load cached network config: %v, falling back to loading network %s from disk", err, name) - network := n.networks[name] - if network == nil { - multiErr = multierror.Append(multiErr, fmt.Errorf("network %s: %w", name, types.ErrNoSuchNetwork)) - continue - } - cniConfList = network.cniNet - } - - err = n.cniConf.DelNetworkList(context.Background(), cniConfList, rt) - if err != nil { - multiErr = multierror.Append(multiErr, err) - } - } - return nil - } - - if n.rootlessNetns != nil { - err = n.rootlessNetns.Teardown(len(options.Networks), teardown) - } else { - err = teardown() - } - multiErr = multierror.Append(multiErr, err) - - return multiErr.ErrorOrNil() -} - -func getCachedNetworkConfig(cniConf *libcni.CNIConfig, name string, rt *libcni.RuntimeConf) (*libcni.NetworkConfigList, *libcni.RuntimeConf, error) { - cniConfList := &libcni.NetworkConfigList{ - Name: name, - } - confBytes, rt, err := cniConf.GetNetworkListCachedConfig(cniConfList, rt) - if err != nil { - return nil, nil, err - } else if confBytes == nil { - return nil, nil, fmt.Errorf("network %s not found in CNI cache", name) - } - - cniConfList, err = libcni.ConfListFromBytes(confBytes) - if err != nil { - return nil, nil, err - } - return cniConfList, rt, nil -} - -func (n *cniNetwork) RunInRootlessNetns(toRun func() error) error { - if n.rootlessNetns == nil { - return types.ErrNotRootlessNetns - } - return n.rootlessNetns.Run(n.lock, toRun) -} - -func (n *cniNetwork) RootlessNetnsInfo() (*types.RootlessNetnsInfo, error) { - if n.rootlessNetns == nil { - return nil, types.ErrNotRootlessNetns - } - return n.rootlessNetns.Info(), nil -} diff --git a/vendor/go.podman.io/common/libnetwork/cni/run_freebsd.go b/vendor/go.podman.io/common/libnetwork/cni/run_freebsd.go deleted file mode 100644 index cca00aa83fc..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/run_freebsd.go +++ /dev/null @@ -1,19 +0,0 @@ -package cni - -import ( - "os/exec" -) - -// FreeBSD vnet adds the lo0 interface automatically - we just need to -// add the default address. Note: this will also add ::1 as a side -// effect. -func setupLoopback(namespacePath string) error { - // Try to run the command using ifconfig's -j flag (supported in 13.3 and later) - if err := exec.Command("ifconfig", "-j", namespacePath, "lo0", "inet", "127.0.0.1").Run(); err == nil { - return nil - } - - // Fall back to using the jexec wrapper to run the ifconfig command - // inside the jail. - return exec.Command("jexec", namespacePath, "ifconfig", "lo0", "inet", "127.0.0.1").Run() -} diff --git a/vendor/go.podman.io/common/libnetwork/cni/run_linux.go b/vendor/go.podman.io/common/libnetwork/cni/run_linux.go deleted file mode 100644 index 735e4960e7d..00000000000 --- a/vendor/go.podman.io/common/libnetwork/cni/run_linux.go +++ /dev/null @@ -1,17 +0,0 @@ -package cni - -import ( - "github.com/containernetworking/plugins/pkg/ns" - "github.com/vishvananda/netlink" -) - -func setupLoopback(namespacePath string) error { - // set the loopback adapter up in the container netns - return ns.WithNetNSPath(namespacePath, func(_ ns.NetNS) error { - link, err := netlink.LinkByName("lo") - if err == nil { - err = netlink.LinkSetUp(link) - } - return err - }) -} diff --git a/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns.go b/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns.go deleted file mode 100644 index edc29f66fe3..00000000000 --- a/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns.go +++ /dev/null @@ -1,8 +0,0 @@ -package rootlessnetns - -type NetworkBackend int - -const ( - Netavark NetworkBackend = iota - CNI -) diff --git a/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns_freebsd.go b/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns_freebsd.go index 03322dc52b4..f1ae4bb00c5 100644 --- a/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns_freebsd.go +++ b/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns_freebsd.go @@ -12,7 +12,7 @@ var ErrNotSupported = errors.New("rootless netns only supported on linux") type Netns struct{} -func New(dir string, backend NetworkBackend, conf *config.Config) (*Netns, error) { +func New(dir string, conf *config.Config) (*Netns, error) { return nil, ErrNotSupported } diff --git a/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns_linux.go b/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns_linux.go index 05b3b16dd67..049df8dc357 100644 --- a/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns_linux.go +++ b/vendor/go.podman.io/common/libnetwork/internal/rootlessnetns/netns_linux.go @@ -11,7 +11,6 @@ import ( "strconv" "strings" - "github.com/containernetworking/plugins/pkg/ns" "github.com/hashicorp/go-multierror" "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux/label" @@ -41,9 +40,6 @@ const ( // rootlessNetNsConnPidFile is the name of the rootless netns slirp4netns/pasta pid file. rootlessNetNsConnPidFile = "rootless-netns-conn.pid" - // persistentCNIDir is the directory where the CNI files are stored. - persistentCNIDir = "/var/lib/cni" - tmpfs = "tmpfs" none = "none" resolvConfName = "resolv.conf" @@ -52,8 +48,6 @@ const ( type Netns struct { // dir used for the rootless netns dir string - // backend used for the network setup/teardown - backend NetworkBackend // config contains containers.conf options. config *config.Config @@ -88,15 +82,14 @@ func wrapError(msg string, err error) *rootlessNetnsError { } } -func New(dir string, backend NetworkBackend, conf *config.Config) (*Netns, error) { +func New(dir string, conf *config.Config) (*Netns, error) { netnsDir := filepath.Join(dir, rootlessNetnsDir) if err := os.MkdirAll(netnsDir, 0o700); err != nil { return nil, wrapError("", err) } return &Netns{ - dir: netnsDir, - backend: backend, - config: conf, + dir: netnsDir, + config: conf, }, nil } @@ -107,9 +100,9 @@ func (n *Netns) getPath(path string) string { // getOrCreateNetns returns the rootless netns, if it created a new one the // returned bool is set to true. -func (n *Netns) getOrCreateNetns() (ns.NetNS, bool, error) { +func (n *Netns) getOrCreateNetns() (netns.NetNS, bool, error) { nsPath := n.getPath(rootlessNetnsDir) - nsRef, err := ns.GetNS(nsPath) + nsRef, err := netns.GetNS(nsPath) if err == nil { pidPath := n.getPath(rootlessNetNsConnPidFile) pid, err := readPidFile(pidPath) @@ -140,7 +133,7 @@ func (n *Netns) getOrCreateNetns() (ns.NetNS, bool, error) { // the file and mounting it. Or if the file is not on tmpfs (deleted on boot) // you might run into it as well: https://github.com/containers/podman/issues/25144 // We have to do this because NewNSAtPath fails with EEXIST otherwise - if errors.As(err, &ns.NSPathNotNSErr{}) { + if errors.As(err, &netns.NSPathNotNSErr{}) { // We don't care if this fails, NewNSAtPath() should return the real error. _ = os.Remove(nsPath) } @@ -349,16 +342,15 @@ func (n *Netns) setupMounts() error { // we have to set up all mounts correctly. // The order of the mounts is IMPORTANT. - // The idea of the extra mount ns is to make /run and /var/lib/cni writeable - // for the cni plugins but not affecting the podman user namespace. + // The idea of the extra mount ns is to make /run writeable + // for the network plugins but not affecting the podman user namespace. // Because the plugins also need access to XDG_RUNTIME_DIR/netns some special setup is needed. // The following bind mounts are needed // 1. XDG_RUNTIME_DIR -> XDG_RUNTIME_DIR/rootless-netns/XDG_RUNTIME_DIR // 2. /run/systemd -> XDG_RUNTIME_DIR/rootless-netns/run/systemd (only if it exists) // 3. XDG_RUNTIME_DIR/rootless-netns/resolv.conf -> /etc/resolv.conf or XDG_RUNTIME_DIR/rootless-netns/run/symlink/target - // 4. XDG_RUNTIME_DIR/rootless-netns/var/lib/cni -> /var/lib/cni (if /var/lib/cni does not exist, use the parent dir) - // 5. XDG_RUNTIME_DIR/rootless-netns/run -> /run + // 4. XDG_RUNTIME_DIR/rootless-netns/run -> /run // Create a new mount namespace, // this must happen inside the netns thread. @@ -385,7 +377,7 @@ func (n *Netns) setupMounts() error { } newXDGRuntimeDir := n.getPath(xdgRuntimeDir) // 1. Mount the netns into the new run to keep them accessible. - // Otherwise cni setup will fail because it cannot access the netns files. + // Otherwise network setup will fail because it cannot access the netns files. err = mountAndMkdirDest(xdgRuntimeDir, newXDGRuntimeDir, none, unix.MS_BIND|unix.MS_REC) if err != nil { return err @@ -501,14 +493,7 @@ func (n *Netns) setupMounts() error { return wrapError(fmt.Sprintf("mount resolv.conf to %q", resolvePath), err) } - // 4. CNI plugins need access to /var/lib/cni - if n.backend == CNI { - if err := n.mountCNIVarDir(); err != nil { - return err - } - } - - // 5. Mount the new prepared run dir to /run, it has to be recursive to keep the other bind mounts. + // 4. Mount the new prepared run dir to /run, it has to be recursive to keep the other bind mounts. runDir := n.getPath("run") err = os.MkdirAll(runDir, 0o700) if err != nil { @@ -530,36 +515,6 @@ func (n *Netns) setupMounts() error { return nil } -func (n *Netns) mountCNIVarDir() error { - varDir := "" - varTarget := persistentCNIDir - // we can only mount to a target dir which exists, check /var/lib/cni recursively - // while we could always use /var there are cases where a user might store the cni - // configs under /var/custom and this would break - for { - if err := fileutils.Exists(varTarget); err == nil { - varDir = n.getPath(varTarget) - break - } - varTarget = filepath.Dir(varTarget) - if varTarget == "/" { - break - } - } - if varDir == "" { - return errors.New("failed to stat /var directory") - } - if err := os.MkdirAll(varDir, 0o700); err != nil { - return wrapError("create var dir", err) - } - // make sure to mount var first - err := unix.Mount(varDir, varTarget, none, unix.MS_BIND, "") - if err != nil { - return wrapError(fmt.Sprintf("mount %q to %q", varDir, varTarget), err) - } - return nil -} - func (n *Netns) runInner(toRun func() error, cleanup bool) (err error) { nsRef, newNs, err := n.getOrCreateNetns() if err != nil { @@ -577,7 +532,7 @@ func (n *Netns) runInner(toRun func() error, cleanup bool) (err error) { }() } - return nsRef.Do(func(_ ns.NetNS) error { + return nsRef.Do(func(_ netns.NetNS) error { if err := n.setupMounts(); err != nil { return err } diff --git a/vendor/go.podman.io/common/libnetwork/netavark/config.go b/vendor/go.podman.io/common/libnetwork/netavark/config.go index 7dcbe7bb3c7..f8631d2895d 100644 --- a/vendor/go.podman.io/common/libnetwork/netavark/config.go +++ b/vendor/go.podman.io/common/libnetwork/netavark/config.go @@ -153,7 +153,7 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo // Only get the used networks for validation if we do not create the default network. // The default network should not be validated against used subnets, we have to ensure // that this network can always be created even when a subnet is already used on the host. - // This could happen if you run a container on this net, then the cni interface will be + // This could happen if you run a container on this net, then the network interface will be // created on the host and "block" this subnet from being used again. // Therefore the next podman command tries to create the default net again and it would // fail because it thinks the network is used on the host. diff --git a/vendor/go.podman.io/common/libnetwork/netavark/network.go b/vendor/go.podman.io/common/libnetwork/netavark/network.go index 9dbe3b452da..3a35b2af82c 100644 --- a/vendor/go.podman.io/common/libnetwork/netavark/network.go +++ b/vendor/go.podman.io/common/libnetwork/netavark/network.go @@ -104,7 +104,7 @@ func NewNetworkInterface(conf *InitConfig) (types.ContainerNetwork, error) { val, ok := os.LookupEnv(unshare.UsernsEnvName) useRootlessNetns := ok && val == "done" if useRootlessNetns { - netns, err = rootlessnetns.New(conf.NetworkRunDir, rootlessnetns.Netavark, conf.Config) + netns, err = rootlessnetns.New(conf.NetworkRunDir, conf.Config) if err != nil { return nil, err } @@ -354,7 +354,7 @@ func (n *netavarkNetwork) Len() int { return len(n.networks) } -// DefaultInterfaceName return the default cni bridge name, must be suffixed with a number. +// DefaultInterfaceName return the default bridge name, must be suffixed with a number. func (n *netavarkNetwork) DefaultInterfaceName() string { return defaultBridgeName } diff --git a/vendor/go.podman.io/common/libnetwork/network/interface.go b/vendor/go.podman.io/common/libnetwork/network/interface.go index 82955b6edfb..4a08e85339f 100644 --- a/vendor/go.podman.io/common/libnetwork/network/interface.go +++ b/vendor/go.podman.io/common/libnetwork/network/interface.go @@ -3,51 +3,41 @@ package network import ( - "errors" "fmt" - "os" "path/filepath" - "github.com/sirupsen/logrus" "go.podman.io/common/libnetwork/netavark" "go.podman.io/common/libnetwork/types" "go.podman.io/common/pkg/config" "go.podman.io/storage" - "go.podman.io/storage/pkg/ioutils" "go.podman.io/storage/pkg/unshare" ) const ( - // defaultNetworkBackendFileName is the file name for sentinel file to store the backend. - defaultNetworkBackendFileName = "defaultNetworkBackend" - // netavarkBinary is the name of the netavark binary. netavarkBinary = "netavark" // aardvarkBinary is the name of the aardvark binary. aardvarkBinary = "aardvark-dns" ) -// NetworkBackend returns the network backend name and interface -// It returns either the CNI or netavark backend depending on what is set in the config. -// If the backend is set to "" we will automatically assign the backend on the following conditions: -// 1. read ${graphroot}/defaultNetworkBackend -// 2. find netavark binary (if not installed use CNI) -// 3. check containers, images and CNI networks and if there are some we have an existing install and should continue to use CNI +// NetworkBackend returns the network backend name and interface. +// It returns the netavark backend. If no backend is set in the config, +// it defaults to netavark. Any other backend value is an error. // // revive does not like the name because the package is already called network // //nolint:revive func NetworkBackend(store storage.Store, conf *config.Config, syslog bool) (types.NetworkBackend, types.ContainerNetwork, error) { backend := types.NetworkBackend(conf.Network.NetworkBackend) - if backend == "" { - var err error - backend, err = defaultNetworkBackend(store, conf) - if err != nil { - return "", nil, fmt.Errorf("failed to get default network backend: %w", err) - } + if backend != "" && backend != types.Netavark { + return "", nil, fmt.Errorf("unsupported network backend %q, only netavark is supported", backend) } - return backendFromType(backend, store, conf, syslog) + netInt, err := netavarkBackendFromConf(store, conf, syslog) + if err != nil { + return "", nil, err + } + return types.Netavark, netInt, nil } func netavarkBackendFromConf(store storage.Store, conf *config.Config, syslog bool) (types.ContainerNetwork, error) { @@ -83,60 +73,6 @@ func netavarkBackendFromConf(store storage.Store, conf *config.Config, syslog bo return netInt, err } -func defaultNetworkBackend(store storage.Store, conf *config.Config) (backend types.NetworkBackend, err error) { - err = nil - - file := filepath.Join(store.GraphRoot(), defaultNetworkBackendFileName) - - writeBackendToFile := func(backendT types.NetworkBackend) { - // only write when there is no error - if err == nil { - if err := ioutils.AtomicWriteFile(file, []byte(backendT), 0o644); err != nil { - logrus.Errorf("could not write network backend to file: %v", err) - } - } - } - - // read defaultNetworkBackend file - b, err := os.ReadFile(file) - if err == nil { - val := string(b) - - // if the network backend has been already set previously, - // handle the values depending on whether CNI is supported and - // whether the network backend is explicitly configured - if val == string(types.Netavark) { - // netavark is always good - return types.Netavark, nil - } else if val == string(types.CNI) { - if cniSupported { - return types.CNI, nil - } - // the user has *not* configured a network - // backend explicitly but used CNI in the past - // => we upgrade them in this case to netavark only - writeBackendToFile(types.Netavark) - logrus.Info("Migrating network backend to netavark as no backend has been configured previously") - return types.Netavark, nil - } - return "", fmt.Errorf("unknown network backend value %q in %q", val, file) - } - - // fail for all errors except ENOENT - if !errors.Is(err, os.ErrNotExist) { - return "", fmt.Errorf("could not read network backend value: %w", err) - } - - backend, err = networkBackendFromStore(store, conf) - if err != nil { - return "", err - } - // cache the network backend to make sure always the same one will be used - writeBackendToFile(backend) - - return backend, nil -} - // getDefaultNetavarkConfigDir return the netavark config dir. For rootful it will // use "/etc/containers/networks" and for rootless "$graphroot/networks". We cannot // use the graphroot for rootful since the network namespace is shared for all diff --git a/vendor/go.podman.io/common/libnetwork/network/interface_cni.go b/vendor/go.podman.io/common/libnetwork/network/interface_cni.go deleted file mode 100644 index a46ff251826..00000000000 --- a/vendor/go.podman.io/common/libnetwork/network/interface_cni.go +++ /dev/null @@ -1,119 +0,0 @@ -//go:build (linux || freebsd) && cni - -package network - -import ( - "errors" - "fmt" - "os" - "path/filepath" - - "go.podman.io/common/libnetwork/cni" - "go.podman.io/common/libnetwork/types" - "go.podman.io/common/pkg/config" - "go.podman.io/common/pkg/machine" - "go.podman.io/storage" - "go.podman.io/storage/pkg/homedir" - "go.podman.io/storage/pkg/unshare" -) - -const ( - // cniConfigDirRootless is the directory in XDG_CONFIG_HOME for cni plugins. - cniConfigDirRootless = "cni/net.d/" - - cniSupported = true -) - -func getCniInterface(conf *config.Config) (types.ContainerNetwork, error) { - confDir := conf.Network.NetworkConfigDir - if confDir == "" { - var err error - confDir, err = getDefaultCNIConfigDir() - if err != nil { - return nil, err - } - } - return cni.NewCNINetworkInterface(&cni.InitConfig{ - Config: conf, - CNIConfigDir: confDir, - RunDir: conf.Engine.TmpDir, - IsMachine: machine.IsGvProxyBased(), - }) -} - -func getDefaultCNIConfigDir() (string, error) { - if !unshare.IsRootless() { - return cniConfigDir, nil - } - - configHome, err := homedir.GetConfigHome() - if err != nil { - return "", err - } - - return filepath.Join(configHome, cniConfigDirRootless), nil -} - -func networkBackendFromStore(store storage.Store, conf *config.Config) (backend types.NetworkBackend, err error) { - _, err = conf.FindHelperBinary("netavark", false) - if err != nil { - // if we cannot find netavark use CNI - return types.CNI, nil - } - - // If there are any containers then return CNI - cons, err := store.Containers() - if err != nil { - return "", err - } - if len(cons) != 0 { - return types.CNI, nil - } - - // If there are any non ReadOnly images then return CNI - imgs, err := store.Images() - if err != nil { - return "", err - } - for _, i := range imgs { - if !i.ReadOnly { - return types.CNI, nil - } - } - - // If there are CNI Networks then return CNI - cniInterface, err := getCniInterface(conf) - if err == nil { - nets, err := cniInterface.NetworkList() - // there is always a default network so check > 1 - if err != nil && !errors.Is(err, os.ErrNotExist) { - return "", err - } - - if len(nets) > 1 { - // we do not have a fresh system so use CNI - return types.CNI, nil - } - } - return types.Netavark, nil -} - -func backendFromType(backend types.NetworkBackend, store storage.Store, conf *config.Config, syslog bool) (types.NetworkBackend, types.ContainerNetwork, error) { - switch backend { - case types.Netavark: - netInt, err := netavarkBackendFromConf(store, conf, syslog) - if err != nil { - return "", nil, err - } - return types.Netavark, netInt, err - case types.CNI: - netInt, err := getCniInterface(conf) - if err != nil { - return "", nil, err - } - return types.CNI, netInt, err - - default: - return "", nil, fmt.Errorf("unsupported network backend %q, check network_backend in containers.conf", backend) - } -} diff --git a/vendor/go.podman.io/common/libnetwork/network/interface_cni_unsupported.go b/vendor/go.podman.io/common/libnetwork/network/interface_cni_unsupported.go deleted file mode 100644 index 5d94fb8cadc..00000000000 --- a/vendor/go.podman.io/common/libnetwork/network/interface_cni_unsupported.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build (linux || freebsd) && !cni - -package network - -import ( - "fmt" - - "go.podman.io/common/libnetwork/types" - "go.podman.io/common/pkg/config" - "go.podman.io/storage" -) - -const ( - cniSupported = false -) - -func networkBackendFromStore(_store storage.Store, _conf *config.Config) (backend types.NetworkBackend, err error) { - return types.Netavark, nil -} - -func backendFromType(backend types.NetworkBackend, store storage.Store, conf *config.Config, syslog bool) (types.NetworkBackend, types.ContainerNetwork, error) { - if backend != types.Netavark { - return "", nil, fmt.Errorf("cni support is not enabled in this build, only netavark. Got unsupported network backend %q", backend) - } - cn, err := netavarkBackendFromConf(store, conf, syslog) - if err != nil { - return "", nil, err - } - return types.Netavark, cn, err -} diff --git a/vendor/go.podman.io/common/libnetwork/network/interface_freebsd.go b/vendor/go.podman.io/common/libnetwork/network/interface_freebsd.go index 4d60b25c7c5..42fa78bc713 100644 --- a/vendor/go.podman.io/common/libnetwork/network/interface_freebsd.go +++ b/vendor/go.podman.io/common/libnetwork/network/interface_freebsd.go @@ -1,8 +1,6 @@ package network const ( - // cniConfigDir is the directory where cni configuration is found - cniConfigDir = "/usr/local/etc/cni/net.d/" // netavarkConfigDir is the config directory for the rootful network files netavarkConfigDir = "/usr/local/etc/containers/networks" // netavarkRunDir is the run directory for the rootful temporary network files such as the ipam db diff --git a/vendor/go.podman.io/common/libnetwork/network/interface_linux.go b/vendor/go.podman.io/common/libnetwork/network/interface_linux.go index 7a5db69a58d..f89acfd1026 100644 --- a/vendor/go.podman.io/common/libnetwork/network/interface_linux.go +++ b/vendor/go.podman.io/common/libnetwork/network/interface_linux.go @@ -1,8 +1,6 @@ package network const ( - // cniConfigDir is the directory where cni configuration is found. - cniConfigDir = "/etc/cni/net.d/" // netavarkConfigDir is the config directory for the rootful network files. netavarkConfigDir = "/etc/containers/networks" // netavarkRunDir is the run directory for the rootful temporary network files such as the ipam db. diff --git a/vendor/go.podman.io/common/libnetwork/pasta/pasta_linux.go b/vendor/go.podman.io/common/libnetwork/pasta/pasta_linux.go index a72e7adfdec..91bbb165344 100644 --- a/vendor/go.podman.io/common/libnetwork/pasta/pasta_linux.go +++ b/vendor/go.podman.io/common/libnetwork/pasta/pasta_linux.go @@ -18,11 +18,11 @@ import ( "slices" "strings" - "github.com/containernetworking/plugins/pkg/ns" "github.com/sirupsen/logrus" "go.podman.io/common/libnetwork/types" "go.podman.io/common/libnetwork/util" "go.podman.io/common/pkg/config" + "go.podman.io/common/pkg/netns" ) const ( @@ -104,7 +104,7 @@ func Setup(opts *SetupOptions) (*SetupResult, error) { var ipv4, ipv6 bool result := &SetupResult{} - err = ns.WithNetNSPath(opts.Netns, func(_ ns.NetNS) error { + err = netns.WithNetNSPath(opts.Netns, func(_ netns.NetNS) error { addrs, err := net.InterfaceAddrs() if err != nil { return err diff --git a/vendor/go.podman.io/common/libnetwork/slirp4netns/slirp4netns.go b/vendor/go.podman.io/common/libnetwork/slirp4netns/slirp4netns.go index 397f55f505c..74126c608ca 100644 --- a/vendor/go.podman.io/common/libnetwork/slirp4netns/slirp4netns.go +++ b/vendor/go.podman.io/common/libnetwork/slirp4netns/slirp4netns.go @@ -18,10 +18,10 @@ import ( "syscall" "time" - "github.com/containernetworking/plugins/pkg/ns" "github.com/sirupsen/logrus" "go.podman.io/common/libnetwork/types" "go.podman.io/common/pkg/config" + "go.podman.io/common/pkg/netns" "go.podman.io/common/pkg/rootlessport" "go.podman.io/common/pkg/servicereaper" "go.podman.io/common/pkg/util" @@ -334,7 +334,7 @@ func Setup(opts *SetupOptions) (*SetupResult, error) { netnsReadyWg.Add(1) go func() { - err := ns.WithNetNSPath(opts.Netns, func(_ ns.NetNS) error { + err := netns.WithNetNSPath(opts.Netns, func(_ netns.NetNS) error { // Duplicate Address Detection slows the ipv6 setup down for 1-2 seconds. // Since slirp4netns is run in its own namespace and not directly routed // we can skip this to make the ipv6 address immediately available. diff --git a/vendor/go.podman.io/common/libnetwork/types/const.go b/vendor/go.podman.io/common/libnetwork/types/const.go index d8730dcdf04..c027d933b4b 100644 --- a/vendor/go.podman.io/common/libnetwork/types/const.go +++ b/vendor/go.podman.io/common/libnetwork/types/const.go @@ -19,9 +19,9 @@ const ( // NoneIPAMDriver do not provide ipam management. NoneIPAMDriver = "none" - // DefaultSubnet is the name that will be used for the default CNI network. + // DefaultNetworkName is the name that will be used for the default network. DefaultNetworkName = "podman" - // DefaultSubnet is the subnet that will be used for the default CNI network. + // DefaultSubnet is the subnet that will be used for the default network. DefaultSubnet = "10.88.0.0/16" BridgeModeManaged = "managed" @@ -52,7 +52,6 @@ const ( type NetworkBackend string const ( - CNI NetworkBackend = "cni" Netavark NetworkBackend = "netavark" ) diff --git a/vendor/go.podman.io/common/pkg/config/config.go b/vendor/go.podman.io/common/pkg/config/config.go index b434e011dea..445acdfbfe9 100644 --- a/vendor/go.podman.io/common/pkg/config/config.go +++ b/vendor/go.podman.io/common/pkg/config/config.go @@ -47,7 +47,7 @@ type Config struct { Engine EngineConfig `toml:"engine"` // Machine specifies configurations of podman machine VMs Machine MachineConfig `toml:"machine"` - // Network section defines the configuration of CNI Plugins + // Network section defines the configuration of network plugins Network NetworkConfig `toml:"network"` // Secret section defines configurations for the secret management Secrets SecretConfig `toml:"secrets"` @@ -590,9 +590,6 @@ type NetworkConfig struct { // networking. NetworkBackend string `toml:"network_backend,omitempty"` - // CNIPluginDirs is where CNI plugin binaries are stored. - CNIPluginDirs attributedstring.Slice `toml:"cni_plugin_dirs,omitempty"` - // NetavarkPluginDirs is a list of directories which contain netavark plugins. NetavarkPluginDirs attributedstring.Slice `toml:"netavark_plugin_dirs,omitempty"` diff --git a/vendor/go.podman.io/common/pkg/config/containers.conf b/vendor/go.podman.io/common/pkg/config/containers.conf index c2249c3740c..f07c9dbf31e 100644 --- a/vendor/go.podman.io/common/pkg/config/containers.conf +++ b/vendor/go.podman.io/common/pkg/config/containers.conf @@ -354,25 +354,10 @@ default_sysctls = [ [network] # Network backend determines what network driver will be used to set up and tear down container networks. -# Valid values are "cni" and "netavark". -# The default value is empty which means that it will automatically choose CNI or netavark. If there are -# already containers/images or CNI networks preset it will choose CNI. -# -# Before changing this value all containers must be stopped otherwise it is likely that -# firewall rules and network interfaces might leak on the host. A reboot will fix this. +# The only supported value is "netavark". # #network_backend = "" -# Path to directory where CNI plugin binaries are located. -# -#cni_plugin_dirs = [ -# "/usr/local/libexec/cni", -# "/usr/libexec/cni", -# "/usr/local/lib/cni", -# "/usr/lib/cni", -# "/opt/cni/bin", -#] - # List of directories that will be searched for netavark plugins. # #netavark_plugin_dirs = [ @@ -426,12 +411,10 @@ default_sysctls = [ #default_rootless_network_cmd = "pasta" # Path to the directory where network configuration files are located. -# For the CNI backend the default is "/etc/cni/net.d" as root -# and "$HOME/.config/cni/net.d" as rootless. -# For the netavark backend "/etc/containers/networks" is used as root +# The default is "/etc/containers/networks" as root # and "$graphroot/networks" as rootless. # -#network_config_dir = "/etc/cni/net.d/" +#network_config_dir = "/etc/containers/networks" # Port to use for dns forwarding daemon with netavark in rootful bridge # mode and dns enabled. diff --git a/vendor/go.podman.io/common/pkg/config/containers.conf-freebsd b/vendor/go.podman.io/common/pkg/config/containers.conf-freebsd index d76235a24d8..620bd0ca4f1 100644 --- a/vendor/go.podman.io/common/pkg/config/containers.conf-freebsd +++ b/vendor/go.podman.io/common/pkg/config/containers.conf-freebsd @@ -271,25 +271,10 @@ default_sysctls = [ [network] # Network backend determines what network driver will be used to set up and tear down container networks. -# Valid values are "cni" and "netavark". -# The default value is empty which means that it will automatically choose CNI or netavark. If there are -# already containers/images or CNI networks preset it will choose CNI. -# -# Before changing this value all containers must be stopped otherwise it is likely that -# iptables rules and network interfaces might leak on the host. A reboot will fix this. +# The only supported value is "netavark". # #network_backend = "" -# Path to directory where CNI plugin binaries are located. -# -#cni_plugin_dirs = [ -# "/usr/local/libexec/cni", -# "/usr/libexec/cni", -# "/usr/local/lib/cni", -# "/usr/lib/cni", -# "/opt/cni/bin", -#] - # List of directories that will be searched for netavark plugins. # #netavark_plugin_dirs = [ @@ -328,12 +313,10 @@ default_sysctls = [ #] # Path to the directory where network configuration files are located. -# For the CNI backend the default is "/etc/cni/net.d" as root -# and "$HOME/.config/cni/net.d" as rootless. -# For the netavark backend "/etc/containers/networks" is used as root +# The default is "/usr/local/etc/containers/networks" as root # and "$graphroot/networks" as rootless. # -#network_config_dir = "/usr/local/etc/cni/net.d/" +#network_config_dir = "/usr/local/etc/containers/networks" # The default host IPs to bind published container ports to when no host IP # is explicitly specified in the -p flag (e.g., -p 8000:8000). If empty, the default diff --git a/vendor/go.podman.io/common/pkg/config/default.go b/vendor/go.podman.io/common/pkg/config/default.go index ee4dd63791b..f7c425546f8 100644 --- a/vendor/go.podman.io/common/pkg/config/default.go +++ b/vendor/go.podman.io/common/pkg/config/default.go @@ -117,14 +117,6 @@ var ( "CAP_SYS_CHROOT", } - // Search these locations in which CNIPlugins can be installed. - DefaultCNIPluginDirs = []string{ - "/usr/local/libexec/cni", - "/usr/libexec/cni", - "/usr/local/lib/cni", - "/usr/lib/cni", - "/opt/cni/bin", - } DefaultNetavarkPluginDirs = []string{ "/usr/local/libexec/netavark", "/usr/libexec/netavark", @@ -272,7 +264,6 @@ func defaultConfig() (*Config, error) { DefaultSubnetPools: DefaultSubnetPools, DefaultRootlessNetworkCmd: "pasta", DNSBindPort: 0, - CNIPluginDirs: attributedstring.NewSlice(DefaultCNIPluginDirs), NetavarkPluginDirs: attributedstring.NewSlice(DefaultNetavarkPluginDirs), }, Engine: *defaultEngineConfig, diff --git a/vendor/go.podman.io/common/pkg/netns/netns_linux.go b/vendor/go.podman.io/common/pkg/netns/netns_linux.go index 4283ffd8d7b..c2ee879d628 100644 --- a/vendor/go.podman.io/common/pkg/netns/netns_linux.go +++ b/vendor/go.podman.io/common/pkg/netns/netns_linux.go @@ -1,4 +1,4 @@ -// Copyright 2018 CNI authors +// Copyright 2015-2018 CNI authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -29,9 +29,9 @@ import ( "runtime" "strings" "sync" + "syscall" "time" - "github.com/containernetworking/plugins/pkg/ns" "github.com/sirupsen/logrus" "go.podman.io/storage/pkg/homedir" "go.podman.io/storage/pkg/unshare" @@ -43,6 +43,209 @@ const threadNsPath = "/proc/thread-self/ns/net" var errNoFreeName = errors.New("failed to find free netns path name") +// NetNS defines a network namespace. +type NetNS interface { + // Do executes the passed closure in this object's network namespace, + // attempting to restore the original namespace before returning. + // However, since each OS thread can have a different network namespace, + // and Go's thread scheduling is highly variable, callers cannot + // guarantee any specific namespace is set unless operations that + // require that namespace are wrapped with Do(). Also, no code called + // from Do() should call runtime.UnlockOSThread(), or the risk + // of executing code in an incorrect namespace will be greater. See + // https://github.com/golang/go/wiki/LockOSThread for further details. + Do(toRun func(NetNS) error) error + + // Set sets the current network namespace to this object's network namespace. + // Note that since Go's thread scheduling is highly variable, callers + // cannot guarantee the requested namespace will be the current namespace + // after this function is called; to ensure this wrap operations that + // require the namespace with Do() instead. + Set() error + + // Path returns the filesystem path representing this object's network namespace. + Path() string + + // Fd returns a file descriptor representing this object's network namespace. + Fd() uintptr + + // Close cleans up this instance of the network namespace; if this instance + // is the last user the namespace will be destroyed. + Close() error +} + +type netNS struct { + file *os.File + closed bool +} + +// netNS implements the NetNS interface. +var _ NetNS = &netNS{} + +const ( + // https://github.com/torvalds/linux/blob/master/include/uapi/linux/magic.h + nsfsMagic = unix.NSFS_MAGIC + procfsMagic = unix.PROC_SUPER_MAGIC +) + +// NSPathNotExistErr is returned when the netns path does not exist. +type NSPathNotExistErr struct{ msg string } + +func (e NSPathNotExistErr) Error() string { return e.msg } + +// NSPathNotNSErr is returned when the path exists but is not a network namespace. +type NSPathNotNSErr struct{ msg string } + +func (e NSPathNotNSErr) Error() string { return e.msg } + +// IsNSorErr checks whether the given path is a network namespace. +func IsNSorErr(nspath string) error { + stat := syscall.Statfs_t{} + if err := syscall.Statfs(nspath, &stat); err != nil { + if os.IsNotExist(err) { + err = NSPathNotExistErr{msg: fmt.Sprintf("failed to Statfs %q: %v", nspath, err)} + } else { + err = fmt.Errorf("failed to Statfs %q: %v", nspath, err) + } + return err + } + + switch stat.Type { + case procfsMagic, nsfsMagic: + return nil + default: + return NSPathNotNSErr{msg: fmt.Sprintf("unknown FS magic on %q: %x", nspath, stat.Type)} + } +} + +// GetNS returns an object representing the namespace referred to by @path. +func GetNS(nspath string) (NetNS, error) { + err := IsNSorErr(nspath) + if err != nil { + return nil, err + } + + fd, err := os.Open(nspath) + if err != nil { + return nil, err + } + + return &netNS{file: fd}, nil +} + +// GetCurrentNS returns an object representing the current OS thread's network namespace. +func GetCurrentNS() (NetNS, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + return GetNS(threadNsPath) +} + +// WithNetNSPath executes the passed closure under the given network +// namespace, restoring the original namespace afterwards. +func WithNetNSPath(nspath string, toRun func(NetNS) error) error { + ns, err := GetNS(nspath) + if err != nil { + return err + } + defer ns.Close() + return ns.Do(toRun) +} + +func (ns *netNS) Path() string { + return ns.file.Name() +} + +func (ns *netNS) Fd() uintptr { + return ns.file.Fd() +} + +func (ns *netNS) errorIfClosed() error { + if ns.closed { + return fmt.Errorf("%q has already been closed", ns.file.Name()) + } + return nil +} + +func (ns *netNS) Close() error { + if err := ns.errorIfClosed(); err != nil { + return err + } + + if err := ns.file.Close(); err != nil { + return fmt.Errorf("failed to close %q: %v", ns.file.Name(), err) + } + ns.closed = true + + return nil +} + +func (ns *netNS) Set() error { + if err := ns.errorIfClosed(); err != nil { + return err + } + + if err := unix.Setns(int(ns.Fd()), unix.CLONE_NEWNET); err != nil { + return fmt.Errorf("error switching to ns %v: %v", ns.file.Name(), err) + } + + return nil +} + +func (ns *netNS) Do(toRun func(NetNS) error) error { + if err := ns.errorIfClosed(); err != nil { + return err + } + + containedCall := func(hostNS NetNS) error { + threadNS, err := GetNS(threadNsPath) + if err != nil { + return fmt.Errorf("failed to open current netns: %v", err) + } + defer threadNS.Close() + + // switch to target namespace + if err = ns.Set(); err != nil { + return fmt.Errorf("error switching to ns %v: %v", ns.file.Name(), err) + } + defer func() { + err := threadNS.Set() // switch back + if err == nil { + // Unlock the current thread only when we successfully switched back + // to the original namespace; otherwise leave the thread locked which + // will force the runtime to scrap the current thread, that is maybe + // not as optimal but at least always safe to do. + runtime.UnlockOSThread() + } + }() + + return toRun(hostNS) + } + + // save a handle to current network namespace + hostNS, err := GetCurrentNS() + if err != nil { + return fmt.Errorf("failed to open current namespace: %v", err) + } + defer hostNS.Close() + + var wg sync.WaitGroup + wg.Add(1) + + // Start the callback in a new green thread so that if we later fail + // to switch the namespace back to the original one, we can safely + // leave the thread locked to die without a risk of the current thread + // left lingering with incorrect namespace. + var innerError error + go func() { + defer wg.Done() + runtime.LockOSThread() + innerError = containedCall(hostNS) + }() + wg.Wait() + + return innerError +} + // GetNSRunDir returns the dir of where to create the netNS. When running // rootless, it needs to be at a location writable by user. func GetNSRunDir() (string, error) { @@ -56,13 +259,15 @@ func GetNSRunDir() (string, error) { return "/run/netns", nil } -func NewNSAtPath(nsPath string) (ns.NetNS, error) { +// NewNSAtPath creates a new persistent (bind-mounted) network namespace +// at the given path and returns an object representing that namespace. +func NewNSAtPath(nsPath string) (NetNS, error) { return newNSPath(nsPath) } // NewNS creates a new persistent (bind-mounted) network namespace and returns // an object representing that namespace, without switching to it. -func NewNS() (ns.NetNS, error) { +func NewNS() (NetNS, error) { nsRunDir, err := GetNSRunDir() if err != nil { return nil, err @@ -208,7 +413,7 @@ func createNetnsFile(path string) error { return mountPointFd.Close() } -func newNSPath(nsPath string) (ns.NetNS, error) { +func newNSPath(nsPath string) (NetNS, error) { // create an empty file to use as at the mount point err := createNetnsFile(nsPath) if err != nil { @@ -253,7 +458,7 @@ func newNSPath(nsPath string) (ns.NetNS, error) { return nil, fmt.Errorf("failed to create namespace: %v", err) } - return ns.GetNS(nsPath) + return GetNS(nsPath) } // UnmountNS unmounts the given netns path. diff --git a/vendor/golang.org/x/crypto/sha3/hashes.go b/vendor/golang.org/x/crypto/sha3/hashes.go deleted file mode 100644 index a51269d91aa..00000000000 --- a/vendor/golang.org/x/crypto/sha3/hashes.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package sha3 implements the SHA-3 hash algorithms and the SHAKE extendable -// output functions defined in FIPS 202. -// -// Most of this package is a wrapper around the crypto/sha3 package in the -// standard library. The only exception is the legacy Keccak hash functions. -package sha3 - -import ( - "crypto/sha3" - "hash" -) - -// New224 creates a new SHA3-224 hash. -// Its generic security strength is 224 bits against preimage attacks, -// and 112 bits against collision attacks. -// -// It is a wrapper for the [sha3.New224] function in the standard library. -// -//go:fix inline -func New224() hash.Hash { - return sha3.New224() -} - -// New256 creates a new SHA3-256 hash. -// Its generic security strength is 256 bits against preimage attacks, -// and 128 bits against collision attacks. -// -// It is a wrapper for the [sha3.New256] function in the standard library. -// -//go:fix inline -func New256() hash.Hash { - return sha3.New256() -} - -// New384 creates a new SHA3-384 hash. -// Its generic security strength is 384 bits against preimage attacks, -// and 192 bits against collision attacks. -// -// It is a wrapper for the [sha3.New384] function in the standard library. -// -//go:fix inline -func New384() hash.Hash { - return sha3.New384() -} - -// New512 creates a new SHA3-512 hash. -// Its generic security strength is 512 bits against preimage attacks, -// and 256 bits against collision attacks. -// -// It is a wrapper for the [sha3.New512] function in the standard library. -// -//go:fix inline -func New512() hash.Hash { - return sha3.New512() -} - -// Sum224 returns the SHA3-224 digest of the data. -// -// It is a wrapper for the [sha3.Sum224] function in the standard library. -// -//go:fix inline -func Sum224(data []byte) [28]byte { - return sha3.Sum224(data) -} - -// Sum256 returns the SHA3-256 digest of the data. -// -// It is a wrapper for the [sha3.Sum256] function in the standard library. -// -//go:fix inline -func Sum256(data []byte) [32]byte { - return sha3.Sum256(data) -} - -// Sum384 returns the SHA3-384 digest of the data. -// -// It is a wrapper for the [sha3.Sum384] function in the standard library. -// -//go:fix inline -func Sum384(data []byte) [48]byte { - return sha3.Sum384(data) -} - -// Sum512 returns the SHA3-512 digest of the data. -// -// It is a wrapper for the [sha3.Sum512] function in the standard library. -// -//go:fix inline -func Sum512(data []byte) [64]byte { - return sha3.Sum512(data) -} diff --git a/vendor/golang.org/x/crypto/sha3/legacy_hash.go b/vendor/golang.org/x/crypto/sha3/legacy_hash.go deleted file mode 100644 index b8784536e01..00000000000 --- a/vendor/golang.org/x/crypto/sha3/legacy_hash.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// This implementation is only used for NewLegacyKeccak256 and -// NewLegacyKeccak512, which are not implemented by crypto/sha3. -// All other functions in this package are wrappers around crypto/sha3. - -import ( - "crypto/subtle" - "encoding/binary" - "errors" - "hash" - "unsafe" - - "golang.org/x/sys/cpu" -) - -const ( - dsbyteKeccak = 0b00000001 - - // rateK[c] is the rate in bytes for Keccak[c] where c is the capacity in - // bits. Given the sponge size is 1600 bits, the rate is 1600 - c bits. - rateK256 = (1600 - 256) / 8 - rateK512 = (1600 - 512) / 8 - rateK1024 = (1600 - 1024) / 8 -) - -// NewLegacyKeccak256 creates a new Keccak-256 hash. -// -// Only use this function if you require compatibility with an existing cryptosystem -// that uses non-standard padding. All other users should use New256 instead. -func NewLegacyKeccak256() hash.Hash { - return &state{rate: rateK512, outputLen: 32, dsbyte: dsbyteKeccak} -} - -// NewLegacyKeccak512 creates a new Keccak-512 hash. -// -// Only use this function if you require compatibility with an existing cryptosystem -// that uses non-standard padding. All other users should use New512 instead. -func NewLegacyKeccak512() hash.Hash { - return &state{rate: rateK1024, outputLen: 64, dsbyte: dsbyteKeccak} -} - -// spongeDirection indicates the direction bytes are flowing through the sponge. -type spongeDirection int - -const ( - // spongeAbsorbing indicates that the sponge is absorbing input. - spongeAbsorbing spongeDirection = iota - // spongeSqueezing indicates that the sponge is being squeezed. - spongeSqueezing -) - -type state struct { - a [1600 / 8]byte // main state of the hash - - // a[n:rate] is the buffer. If absorbing, it's the remaining space to XOR - // into before running the permutation. If squeezing, it's the remaining - // output to produce before running the permutation. - n, rate int - - // dsbyte contains the "domain separation" bits and the first bit of - // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the - // SHA-3 and SHAKE functions by appending bitstrings to the message. - // Using a little-endian bit-ordering convention, these are "01" for SHA-3 - // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the - // padding rule from section 5.1 is applied to pad the message to a multiple - // of the rate, which involves adding a "1" bit, zero or more "0" bits, and - // a final "1" bit. We merge the first "1" bit from the padding into dsbyte, - // giving 00000110b (0x06) and 00011111b (0x1f). - // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf - // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and - // Extendable-Output Functions (May 2014)" - dsbyte byte - - outputLen int // the default output size in bytes - state spongeDirection // whether the sponge is absorbing or squeezing -} - -// BlockSize returns the rate of sponge underlying this hash function. -func (d *state) BlockSize() int { return d.rate } - -// Size returns the output size of the hash function in bytes. -func (d *state) Size() int { return d.outputLen } - -// Reset clears the internal state by zeroing the sponge state and -// the buffer indexes, and setting Sponge.state to absorbing. -func (d *state) Reset() { - // Zero the permutation's state. - for i := range d.a { - d.a[i] = 0 - } - d.state = spongeAbsorbing - d.n = 0 -} - -func (d *state) clone() *state { - ret := *d - return &ret -} - -// permute applies the KeccakF-1600 permutation. -func (d *state) permute() { - var a *[25]uint64 - if cpu.IsBigEndian { - a = new([25]uint64) - for i := range a { - a[i] = binary.LittleEndian.Uint64(d.a[i*8:]) - } - } else { - a = (*[25]uint64)(unsafe.Pointer(&d.a)) - } - - keccakF1600(a) - d.n = 0 - - if cpu.IsBigEndian { - for i := range a { - binary.LittleEndian.PutUint64(d.a[i*8:], a[i]) - } - } -} - -// pads appends the domain separation bits in dsbyte, applies -// the multi-bitrate 10..1 padding rule, and permutes the state. -func (d *state) padAndPermute() { - // Pad with this instance's domain-separator bits. We know that there's - // at least one byte of space in the sponge because, if it were full, - // permute would have been called to empty it. dsbyte also contains the - // first one bit for the padding. See the comment in the state struct. - d.a[d.n] ^= d.dsbyte - // This adds the final one bit for the padding. Because of the way that - // bits are numbered from the LSB upwards, the final bit is the MSB of - // the last byte. - d.a[d.rate-1] ^= 0x80 - // Apply the permutation - d.permute() - d.state = spongeSqueezing -} - -// Write absorbs more data into the hash's state. It panics if any -// output has already been read. -func (d *state) Write(p []byte) (n int, err error) { - if d.state != spongeAbsorbing { - panic("sha3: Write after Read") - } - - n = len(p) - - for len(p) > 0 { - x := subtle.XORBytes(d.a[d.n:d.rate], d.a[d.n:d.rate], p) - d.n += x - p = p[x:] - - // If the sponge is full, apply the permutation. - if d.n == d.rate { - d.permute() - } - } - - return -} - -// Read squeezes an arbitrary number of bytes from the sponge. -func (d *state) Read(out []byte) (n int, err error) { - // If we're still absorbing, pad and apply the permutation. - if d.state == spongeAbsorbing { - d.padAndPermute() - } - - n = len(out) - - // Now, do the squeezing. - for len(out) > 0 { - // Apply the permutation if we've squeezed the sponge dry. - if d.n == d.rate { - d.permute() - } - - x := copy(out, d.a[d.n:d.rate]) - d.n += x - out = out[x:] - } - - return -} - -// Sum applies padding to the hash state and then squeezes out the desired -// number of output bytes. It panics if any output has already been read. -func (d *state) Sum(in []byte) []byte { - if d.state != spongeAbsorbing { - panic("sha3: Sum after Read") - } - - // Make a copy of the original hash so that caller can keep writing - // and summing. - dup := d.clone() - hash := make([]byte, dup.outputLen, 64) // explicit cap to allow stack allocation - dup.Read(hash) - return append(in, hash...) -} - -const ( - magicKeccak = "sha\x0b" - // magic || rate || main state || n || sponge direction - marshaledSize = len(magicKeccak) + 1 + 200 + 1 + 1 -) - -func (d *state) MarshalBinary() ([]byte, error) { - return d.AppendBinary(make([]byte, 0, marshaledSize)) -} - -func (d *state) AppendBinary(b []byte) ([]byte, error) { - switch d.dsbyte { - case dsbyteKeccak: - b = append(b, magicKeccak...) - default: - panic("unknown dsbyte") - } - // rate is at most 168, and n is at most rate. - b = append(b, byte(d.rate)) - b = append(b, d.a[:]...) - b = append(b, byte(d.n), byte(d.state)) - return b, nil -} - -func (d *state) UnmarshalBinary(b []byte) error { - if len(b) != marshaledSize { - return errors.New("sha3: invalid hash state") - } - - magic := string(b[:len(magicKeccak)]) - b = b[len(magicKeccak):] - switch { - case magic == magicKeccak && d.dsbyte == dsbyteKeccak: - default: - return errors.New("sha3: invalid hash state identifier") - } - - rate := int(b[0]) - b = b[1:] - if rate != d.rate { - return errors.New("sha3: invalid hash state function") - } - - copy(d.a[:], b) - b = b[len(d.a):] - - n, state := int(b[0]), spongeDirection(b[1]) - if n > d.rate { - return errors.New("sha3: invalid hash state") - } - d.n = n - if state != spongeAbsorbing && state != spongeSqueezing { - return errors.New("sha3: invalid hash state") - } - d.state = state - - return nil -} diff --git a/vendor/golang.org/x/crypto/sha3/legacy_keccakf.go b/vendor/golang.org/x/crypto/sha3/legacy_keccakf.go deleted file mode 100644 index 101588c16cc..00000000000 --- a/vendor/golang.org/x/crypto/sha3/legacy_keccakf.go +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -// This implementation is only used for NewLegacyKeccak256 and -// NewLegacyKeccak512, which are not implemented by crypto/sha3. -// All other functions in this package are wrappers around crypto/sha3. - -import "math/bits" - -// rc stores the round constants for use in the ι step. -var rc = [24]uint64{ - 0x0000000000000001, - 0x0000000000008082, - 0x800000000000808A, - 0x8000000080008000, - 0x000000000000808B, - 0x0000000080000001, - 0x8000000080008081, - 0x8000000000008009, - 0x000000000000008A, - 0x0000000000000088, - 0x0000000080008009, - 0x000000008000000A, - 0x000000008000808B, - 0x800000000000008B, - 0x8000000000008089, - 0x8000000000008003, - 0x8000000000008002, - 0x8000000000000080, - 0x000000000000800A, - 0x800000008000000A, - 0x8000000080008081, - 0x8000000000008080, - 0x0000000080000001, - 0x8000000080008008, -} - -// keccakF1600 applies the Keccak permutation to a 1600b-wide -// state represented as a slice of 25 uint64s. -func keccakF1600(a *[25]uint64) { - // Implementation translated from Keccak-inplace.c - // in the keccak reference code. - var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64 - - for i := 0; i < 24; i += 4 { - // Combines the 5 steps in each round into 2 steps. - // Unrolls 4 rounds per loop and spreads some steps across rounds. - - // Round 1 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[6] ^ d1 - bc1 = bits.RotateLeft64(t, 44) - t = a[12] ^ d2 - bc2 = bits.RotateLeft64(t, 43) - t = a[18] ^ d3 - bc3 = bits.RotateLeft64(t, 21) - t = a[24] ^ d4 - bc4 = bits.RotateLeft64(t, 14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i] - a[6] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc2 = bits.RotateLeft64(t, 3) - t = a[16] ^ d1 - bc3 = bits.RotateLeft64(t, 45) - t = a[22] ^ d2 - bc4 = bits.RotateLeft64(t, 61) - t = a[3] ^ d3 - bc0 = bits.RotateLeft64(t, 28) - t = a[9] ^ d4 - bc1 = bits.RotateLeft64(t, 20) - a[10] = bc0 ^ (bc2 &^ bc1) - a[16] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc4 = bits.RotateLeft64(t, 18) - t = a[1] ^ d1 - bc0 = bits.RotateLeft64(t, 1) - t = a[7] ^ d2 - bc1 = bits.RotateLeft64(t, 6) - t = a[13] ^ d3 - bc2 = bits.RotateLeft64(t, 25) - t = a[19] ^ d4 - bc3 = bits.RotateLeft64(t, 8) - a[20] = bc0 ^ (bc2 &^ bc1) - a[1] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc1 = bits.RotateLeft64(t, 36) - t = a[11] ^ d1 - bc2 = bits.RotateLeft64(t, 10) - t = a[17] ^ d2 - bc3 = bits.RotateLeft64(t, 15) - t = a[23] ^ d3 - bc4 = bits.RotateLeft64(t, 56) - t = a[4] ^ d4 - bc0 = bits.RotateLeft64(t, 27) - a[5] = bc0 ^ (bc2 &^ bc1) - a[11] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc3 = bits.RotateLeft64(t, 41) - t = a[21] ^ d1 - bc4 = bits.RotateLeft64(t, 2) - t = a[2] ^ d2 - bc0 = bits.RotateLeft64(t, 62) - t = a[8] ^ d3 - bc1 = bits.RotateLeft64(t, 55) - t = a[14] ^ d4 - bc2 = bits.RotateLeft64(t, 39) - a[15] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - // Round 2 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[16] ^ d1 - bc1 = bits.RotateLeft64(t, 44) - t = a[7] ^ d2 - bc2 = bits.RotateLeft64(t, 43) - t = a[23] ^ d3 - bc3 = bits.RotateLeft64(t, 21) - t = a[14] ^ d4 - bc4 = bits.RotateLeft64(t, 14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1] - a[16] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc2 = bits.RotateLeft64(t, 3) - t = a[11] ^ d1 - bc3 = bits.RotateLeft64(t, 45) - t = a[2] ^ d2 - bc4 = bits.RotateLeft64(t, 61) - t = a[18] ^ d3 - bc0 = bits.RotateLeft64(t, 28) - t = a[9] ^ d4 - bc1 = bits.RotateLeft64(t, 20) - a[20] = bc0 ^ (bc2 &^ bc1) - a[11] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc4 = bits.RotateLeft64(t, 18) - t = a[6] ^ d1 - bc0 = bits.RotateLeft64(t, 1) - t = a[22] ^ d2 - bc1 = bits.RotateLeft64(t, 6) - t = a[13] ^ d3 - bc2 = bits.RotateLeft64(t, 25) - t = a[4] ^ d4 - bc3 = bits.RotateLeft64(t, 8) - a[15] = bc0 ^ (bc2 &^ bc1) - a[6] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc1 = bits.RotateLeft64(t, 36) - t = a[1] ^ d1 - bc2 = bits.RotateLeft64(t, 10) - t = a[17] ^ d2 - bc3 = bits.RotateLeft64(t, 15) - t = a[8] ^ d3 - bc4 = bits.RotateLeft64(t, 56) - t = a[24] ^ d4 - bc0 = bits.RotateLeft64(t, 27) - a[10] = bc0 ^ (bc2 &^ bc1) - a[1] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc3 = bits.RotateLeft64(t, 41) - t = a[21] ^ d1 - bc4 = bits.RotateLeft64(t, 2) - t = a[12] ^ d2 - bc0 = bits.RotateLeft64(t, 62) - t = a[3] ^ d3 - bc1 = bits.RotateLeft64(t, 55) - t = a[19] ^ d4 - bc2 = bits.RotateLeft64(t, 39) - a[5] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - // Round 3 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[11] ^ d1 - bc1 = bits.RotateLeft64(t, 44) - t = a[22] ^ d2 - bc2 = bits.RotateLeft64(t, 43) - t = a[8] ^ d3 - bc3 = bits.RotateLeft64(t, 21) - t = a[19] ^ d4 - bc4 = bits.RotateLeft64(t, 14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2] - a[11] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc2 = bits.RotateLeft64(t, 3) - t = a[1] ^ d1 - bc3 = bits.RotateLeft64(t, 45) - t = a[12] ^ d2 - bc4 = bits.RotateLeft64(t, 61) - t = a[23] ^ d3 - bc0 = bits.RotateLeft64(t, 28) - t = a[9] ^ d4 - bc1 = bits.RotateLeft64(t, 20) - a[15] = bc0 ^ (bc2 &^ bc1) - a[1] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc4 = bits.RotateLeft64(t, 18) - t = a[16] ^ d1 - bc0 = bits.RotateLeft64(t, 1) - t = a[2] ^ d2 - bc1 = bits.RotateLeft64(t, 6) - t = a[13] ^ d3 - bc2 = bits.RotateLeft64(t, 25) - t = a[24] ^ d4 - bc3 = bits.RotateLeft64(t, 8) - a[5] = bc0 ^ (bc2 &^ bc1) - a[16] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc1 = bits.RotateLeft64(t, 36) - t = a[6] ^ d1 - bc2 = bits.RotateLeft64(t, 10) - t = a[17] ^ d2 - bc3 = bits.RotateLeft64(t, 15) - t = a[3] ^ d3 - bc4 = bits.RotateLeft64(t, 56) - t = a[14] ^ d4 - bc0 = bits.RotateLeft64(t, 27) - a[20] = bc0 ^ (bc2 &^ bc1) - a[6] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc3 = bits.RotateLeft64(t, 41) - t = a[21] ^ d1 - bc4 = bits.RotateLeft64(t, 2) - t = a[7] ^ d2 - bc0 = bits.RotateLeft64(t, 62) - t = a[18] ^ d3 - bc1 = bits.RotateLeft64(t, 55) - t = a[4] ^ d4 - bc2 = bits.RotateLeft64(t, 39) - a[10] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - // Round 4 - bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] - bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] - bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] - bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] - bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] - d0 = bc4 ^ (bc1<<1 | bc1>>63) - d1 = bc0 ^ (bc2<<1 | bc2>>63) - d2 = bc1 ^ (bc3<<1 | bc3>>63) - d3 = bc2 ^ (bc4<<1 | bc4>>63) - d4 = bc3 ^ (bc0<<1 | bc0>>63) - - bc0 = a[0] ^ d0 - t = a[1] ^ d1 - bc1 = bits.RotateLeft64(t, 44) - t = a[2] ^ d2 - bc2 = bits.RotateLeft64(t, 43) - t = a[3] ^ d3 - bc3 = bits.RotateLeft64(t, 21) - t = a[4] ^ d4 - bc4 = bits.RotateLeft64(t, 14) - a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3] - a[1] = bc1 ^ (bc3 &^ bc2) - a[2] = bc2 ^ (bc4 &^ bc3) - a[3] = bc3 ^ (bc0 &^ bc4) - a[4] = bc4 ^ (bc1 &^ bc0) - - t = a[5] ^ d0 - bc2 = bits.RotateLeft64(t, 3) - t = a[6] ^ d1 - bc3 = bits.RotateLeft64(t, 45) - t = a[7] ^ d2 - bc4 = bits.RotateLeft64(t, 61) - t = a[8] ^ d3 - bc0 = bits.RotateLeft64(t, 28) - t = a[9] ^ d4 - bc1 = bits.RotateLeft64(t, 20) - a[5] = bc0 ^ (bc2 &^ bc1) - a[6] = bc1 ^ (bc3 &^ bc2) - a[7] = bc2 ^ (bc4 &^ bc3) - a[8] = bc3 ^ (bc0 &^ bc4) - a[9] = bc4 ^ (bc1 &^ bc0) - - t = a[10] ^ d0 - bc4 = bits.RotateLeft64(t, 18) - t = a[11] ^ d1 - bc0 = bits.RotateLeft64(t, 1) - t = a[12] ^ d2 - bc1 = bits.RotateLeft64(t, 6) - t = a[13] ^ d3 - bc2 = bits.RotateLeft64(t, 25) - t = a[14] ^ d4 - bc3 = bits.RotateLeft64(t, 8) - a[10] = bc0 ^ (bc2 &^ bc1) - a[11] = bc1 ^ (bc3 &^ bc2) - a[12] = bc2 ^ (bc4 &^ bc3) - a[13] = bc3 ^ (bc0 &^ bc4) - a[14] = bc4 ^ (bc1 &^ bc0) - - t = a[15] ^ d0 - bc1 = bits.RotateLeft64(t, 36) - t = a[16] ^ d1 - bc2 = bits.RotateLeft64(t, 10) - t = a[17] ^ d2 - bc3 = bits.RotateLeft64(t, 15) - t = a[18] ^ d3 - bc4 = bits.RotateLeft64(t, 56) - t = a[19] ^ d4 - bc0 = bits.RotateLeft64(t, 27) - a[15] = bc0 ^ (bc2 &^ bc1) - a[16] = bc1 ^ (bc3 &^ bc2) - a[17] = bc2 ^ (bc4 &^ bc3) - a[18] = bc3 ^ (bc0 &^ bc4) - a[19] = bc4 ^ (bc1 &^ bc0) - - t = a[20] ^ d0 - bc3 = bits.RotateLeft64(t, 41) - t = a[21] ^ d1 - bc4 = bits.RotateLeft64(t, 2) - t = a[22] ^ d2 - bc0 = bits.RotateLeft64(t, 62) - t = a[23] ^ d3 - bc1 = bits.RotateLeft64(t, 55) - t = a[24] ^ d4 - bc2 = bits.RotateLeft64(t, 39) - a[20] = bc0 ^ (bc2 &^ bc1) - a[21] = bc1 ^ (bc3 &^ bc2) - a[22] = bc2 ^ (bc4 &^ bc3) - a[23] = bc3 ^ (bc0 &^ bc4) - a[24] = bc4 ^ (bc1 &^ bc0) - } -} diff --git a/vendor/golang.org/x/crypto/sha3/shake.go b/vendor/golang.org/x/crypto/sha3/shake.go deleted file mode 100644 index 6f3f70c2656..00000000000 --- a/vendor/golang.org/x/crypto/sha3/shake.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sha3 - -import ( - "crypto/sha3" - "hash" - "io" -) - -// ShakeHash defines the interface to hash functions that support -// arbitrary-length output. When used as a plain [hash.Hash], it -// produces minimum-length outputs that provide full-strength generic -// security. -type ShakeHash interface { - hash.Hash - - // Read reads more output from the hash; reading affects the hash's - // state. (ShakeHash.Read is thus very different from Hash.Sum.) - // It never returns an error, but subsequent calls to Write or Sum - // will panic. - io.Reader - - // Clone returns a copy of the ShakeHash in its current state. - Clone() ShakeHash -} - -// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. -// Its generic security strength is 128 bits against all attacks if at -// least 32 bytes of its output are used. -func NewShake128() ShakeHash { - return &shakeWrapper{sha3.NewSHAKE128(), 32, false, sha3.NewSHAKE128} -} - -// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. -// Its generic security strength is 256 bits against all attacks if -// at least 64 bytes of its output are used. -func NewShake256() ShakeHash { - return &shakeWrapper{sha3.NewSHAKE256(), 64, false, sha3.NewSHAKE256} -} - -// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, -// a customizable variant of SHAKE128. -// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is -// desired. S is a customization byte string used for domain separation - two cSHAKE -// computations on same input with different S yield unrelated outputs. -// When N and S are both empty, this is equivalent to NewShake128. -func NewCShake128(N, S []byte) ShakeHash { - return &shakeWrapper{sha3.NewCSHAKE128(N, S), 32, false, func() *sha3.SHAKE { - return sha3.NewCSHAKE128(N, S) - }} -} - -// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, -// a customizable variant of SHAKE256. -// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is -// desired. S is a customization byte string used for domain separation - two cSHAKE -// computations on same input with different S yield unrelated outputs. -// When N and S are both empty, this is equivalent to NewShake256. -func NewCShake256(N, S []byte) ShakeHash { - return &shakeWrapper{sha3.NewCSHAKE256(N, S), 64, false, func() *sha3.SHAKE { - return sha3.NewCSHAKE256(N, S) - }} -} - -// ShakeSum128 writes an arbitrary-length digest of data into hash. -func ShakeSum128(hash, data []byte) { - h := NewShake128() - h.Write(data) - h.Read(hash) -} - -// ShakeSum256 writes an arbitrary-length digest of data into hash. -func ShakeSum256(hash, data []byte) { - h := NewShake256() - h.Write(data) - h.Read(hash) -} - -// shakeWrapper adds the Size, Sum, and Clone methods to a sha3.SHAKE -// to implement the ShakeHash interface. -type shakeWrapper struct { - *sha3.SHAKE - outputLen int - squeezing bool - newSHAKE func() *sha3.SHAKE -} - -func (w *shakeWrapper) Read(p []byte) (n int, err error) { - w.squeezing = true - return w.SHAKE.Read(p) -} - -func (w *shakeWrapper) Clone() ShakeHash { - s := w.newSHAKE() - b, err := w.MarshalBinary() - if err != nil { - panic(err) // unreachable - } - if err := s.UnmarshalBinary(b); err != nil { - panic(err) // unreachable - } - return &shakeWrapper{s, w.outputLen, w.squeezing, w.newSHAKE} -} - -func (w *shakeWrapper) Size() int { return w.outputLen } - -func (w *shakeWrapper) Sum(b []byte) []byte { - if w.squeezing { - panic("sha3: Sum after Read") - } - out := make([]byte, w.outputLen) - // Clone the state so that we don't affect future Write calls. - s := w.Clone() - s.Read(out) - return append(b, out...) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1fd840037dc..ddbe2c74276 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# cyphar.com/go-pathrs v0.2.1 +# cyphar.com/go-pathrs v0.2.4 ## explicit; go 1.18 cyphar.com/go-pathrs cyphar.com/go-pathrs/internal/fdutils @@ -75,23 +75,11 @@ github.com/containerd/stargz-snapshotter/estargz/errorutil # github.com/containerd/typeurl/v2 v2.2.3 ## explicit; go 1.21 github.com/containerd/typeurl/v2 -# github.com/containernetworking/cni v1.3.0 -## explicit; go 1.21 -github.com/containernetworking/cni/libcni -github.com/containernetworking/cni/pkg/invoke -github.com/containernetworking/cni/pkg/types -github.com/containernetworking/cni/pkg/types/020 -github.com/containernetworking/cni/pkg/types/040 -github.com/containernetworking/cni/pkg/types/100 -github.com/containernetworking/cni/pkg/types/create -github.com/containernetworking/cni/pkg/types/internal -github.com/containernetworking/cni/pkg/utils -github.com/containernetworking/cni/pkg/version # github.com/containernetworking/plugins v1.9.0 ## explicit; go 1.24.2 github.com/containernetworking/plugins/pkg/ns -# github.com/containers/buildah v1.42.1-0.20260216192603-e473f9d26ec6 -## explicit; go 1.24.6 +# github.com/containers/buildah v1.42.1-0.20260216192603-e473f9d26ec6 => github.com/lsm5/buildah v0.0.0-20260317084505-caaea7f2d096 +## explicit; go 1.25.5 github.com/containers/buildah github.com/containers/buildah/bind github.com/containers/buildah/chroot @@ -175,7 +163,7 @@ github.com/containers/psgo/internal/process ## explicit; go 1.19 github.com/containers/winquit/pkg/winquit github.com/containers/winquit/pkg/winquit/win32 -# github.com/coreos/go-oidc/v3 v3.16.0 +# github.com/coreos/go-oidc/v3 v3.17.0 ## explicit; go 1.24.0 github.com/coreos/go-oidc/v3/oidc # github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f @@ -235,23 +223,6 @@ github.com/distribution/reference ## explicit github.com/docker/distribution/registry/api/errcode github.com/docker/distribution/registry/api/v2 -# github.com/docker/docker v28.5.2+incompatible -## explicit -github.com/docker/docker/api/types/blkiodev -github.com/docker/docker/api/types/common -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/api/types/network -github.com/docker/docker/api/types/registry -github.com/docker/docker/api/types/storage -github.com/docker/docker/api/types/strslice -github.com/docker/docker/api/types/swarm -github.com/docker/docker/api/types/swarm/runtime -github.com/docker/docker/api/types/versions -github.com/docker/docker/pkg/homedir -github.com/docker/docker/pkg/jsonmessage -github.com/docker/docker/pkg/stdcopy # github.com/docker/docker-credential-helpers v0.9.5 ## explicit; go 1.21 github.com/docker/docker-credential-helpers/client @@ -282,8 +253,8 @@ github.com/felixge/httpsnoop ## explicit; go 1.17 github.com/fsnotify/fsnotify github.com/fsnotify/fsnotify/internal -# github.com/fsouza/go-dockerclient v1.12.3 -## explicit; go 1.24.0 +# github.com/fsouza/go-dockerclient v1.13.0 +## explicit; go 1.25.0 github.com/fsouza/go-dockerclient # github.com/go-jose/go-jose/v4 v4.1.3 ## explicit; go 1.24.0 @@ -320,8 +291,8 @@ github.com/google/go-cmp/cmp/internal/diff github.com/google/go-cmp/cmp/internal/flags github.com/google/go-cmp/cmp/internal/function github.com/google/go-cmp/cmp/internal/value -# github.com/google/go-containerregistry v0.20.6 -## explicit; go 1.24 +# github.com/google/go-containerregistry v0.20.7 +## explicit; go 1.24.0 github.com/google/go-containerregistry/pkg/name github.com/google/go-containerregistry/pkg/v1 github.com/google/go-containerregistry/pkg/v1/types @@ -428,8 +399,8 @@ github.com/miekg/pkcs11 # github.com/mistifyio/go-zfs/v4 v4.0.0 ## explicit; go 1.14 github.com/mistifyio/go-zfs/v4 -# github.com/moby/buildkit v0.26.3 -## explicit; go 1.24.3 +# github.com/moby/buildkit v0.28.0 +## explicit; go 1.25.5 github.com/moby/buildkit/frontend/dockerfile/command github.com/moby/buildkit/frontend/dockerfile/parser github.com/moby/buildkit/frontend/dockerfile/shell @@ -437,7 +408,7 @@ github.com/moby/buildkit/util/stack # github.com/moby/docker-image-spec v1.3.1 ## explicit; go 1.18 github.com/moby/docker-image-spec/specs-go/v1 -# github.com/moby/go-archive v0.1.0 +# github.com/moby/go-archive v0.2.0 ## explicit; go 1.23.0 github.com/moby/go-archive github.com/moby/go-archive/compression @@ -445,6 +416,7 @@ github.com/moby/go-archive/tarheader # github.com/moby/moby/api v1.54.0 ## explicit; go 1.24.0 github.com/moby/moby/api +github.com/moby/moby/api/pkg/stdcopy github.com/moby/moby/api/types github.com/moby/moby/api/types/blkiodev github.com/moby/moby/api/types/build @@ -467,7 +439,11 @@ github.com/moby/moby/api/types/volume github.com/moby/moby/client github.com/moby/moby/client/internal github.com/moby/moby/client/internal/timestamp +github.com/moby/moby/client/pkg/jsonmessage github.com/moby/moby/client/pkg/versions +# github.com/moby/moby/v2 v2.0.0-beta.6 +## explicit; go 1.25.0 +github.com/moby/moby/v2/pkg/homedir # github.com/moby/patternmatcher v0.6.0 ## explicit; go 1.19 github.com/moby/patternmatcher @@ -496,9 +472,6 @@ github.com/modern-go/concurrent # github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee ## explicit; go 1.12 github.com/modern-go/reflect2 -# github.com/morikuni/aec v1.0.0 -## explicit -github.com/morikuni/aec # github.com/nxadm/tail v1.4.11 ## explicit; go 1.13 github.com/nxadm/tail @@ -561,7 +534,7 @@ github.com/opencontainers/go-digest ## explicit; go 1.18 github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 -# github.com/opencontainers/runc v1.4.0 +# github.com/opencontainers/runc v1.4.1 ## explicit; go 1.24.0 github.com/opencontainers/runc/internal/linux github.com/opencontainers/runc/internal/pathrs @@ -639,15 +612,15 @@ github.com/shirou/gopsutil/v4/internal/common github.com/shirou/gopsutil/v4/mem github.com/shirou/gopsutil/v4/net github.com/shirou/gopsutil/v4/process -# github.com/sigstore/fulcio v1.8.1 -## explicit; go 1.24.6 +# github.com/sigstore/fulcio v1.8.5 +## explicit; go 1.25.0 github.com/sigstore/fulcio/pkg/api github.com/sigstore/fulcio/pkg/certificate # github.com/sigstore/protobuf-specs v0.5.0 ## explicit; go 1.22.0 github.com/sigstore/protobuf-specs/gen/pb-go/common/v1 -# github.com/sigstore/sigstore v1.9.6-0.20251111174640-d8ab8afb1326 -## explicit; go 1.24.0 +# github.com/sigstore/sigstore v1.10.4 +## explicit; go 1.25.0 github.com/sigstore/sigstore/pkg/cryptoutils github.com/sigstore/sigstore/pkg/oauth github.com/sigstore/sigstore/pkg/oauthflow @@ -761,7 +734,7 @@ go.opentelemetry.io/otel/trace go.opentelemetry.io/otel/trace/embedded go.opentelemetry.io/otel/trace/internal/telemetry go.opentelemetry.io/otel/trace/noop -# go.podman.io/common v0.67.1-0.20260313003550-7415b6a27ee6 +# go.podman.io/common v0.67.1-0.20260316162257-e70c309aabae ## explicit; go 1.25.0 go.podman.io/common/internal go.podman.io/common/internal/attributedstring @@ -770,7 +743,6 @@ go.podman.io/common/libimage/define go.podman.io/common/libimage/filter go.podman.io/common/libimage/manifests go.podman.io/common/libimage/platform -go.podman.io/common/libnetwork/cni go.podman.io/common/libnetwork/etchosts go.podman.io/common/libnetwork/internal/rootlessnetns go.podman.io/common/libnetwork/internal/util @@ -829,7 +801,7 @@ go.podman.io/common/pkg/umask go.podman.io/common/pkg/util go.podman.io/common/pkg/version go.podman.io/common/version -# go.podman.io/image/v5 v5.39.2-0.20260313003550-7415b6a27ee6 +# go.podman.io/image/v5 v5.39.2-0.20260316162257-e70c309aabae ## explicit; go 1.25.0 go.podman.io/image/v5/copy go.podman.io/image/v5/directory @@ -906,7 +878,7 @@ go.podman.io/image/v5/transports go.podman.io/image/v5/transports/alltransports go.podman.io/image/v5/types go.podman.io/image/v5/version -# go.podman.io/storage v1.62.1-0.20260313003550-7415b6a27ee6 +# go.podman.io/storage v1.62.1-0.20260316162257-e70c309aabae ## explicit; go 1.25.0 go.podman.io/storage go.podman.io/storage/drivers @@ -985,7 +957,6 @@ golang.org/x/crypto/pbkdf2 golang.org/x/crypto/ripemd160 golang.org/x/crypto/salsa20/salsa golang.org/x/crypto/scrypt -golang.org/x/crypto/sha3 golang.org/x/crypto/ssh golang.org/x/crypto/ssh/agent golang.org/x/crypto/ssh/internal/bcrypt_pbkdf @@ -1208,3 +1179,4 @@ tags.cncf.io/container-device-interface/pkg/parser # tags.cncf.io/container-device-interface/specs-go v1.1.0 ## explicit; go 1.19 tags.cncf.io/container-device-interface/specs-go +# github.com/containers/buildah => github.com/lsm5/buildah v0.0.0-20260317084505-caaea7f2d096 From 857df44c454df4e34ea7ffc6eafe3d37fea27478 Mon Sep 17 00:00:00 2001 From: Lokesh Mandvekar Date: Wed, 4 Mar 2026 16:57:10 +0530 Subject: [PATCH 2/6] Remove CNI references from comments Update comments that reference CNI as a network backend since it has been removed. Signed-off-by: Lokesh Mandvekar --- cmd/rootlessport/main.go | 6 +++--- contrib/tmpfile/podman.conf | 1 - libpod/container.go | 6 +++--- libpod/container_internal_common.go | 2 +- libpod/networking_linux.go | 5 ++--- test/e2e/network_create_test.go | 4 ++-- test/e2e/run_networking_test.go | 6 +++--- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/cmd/rootlessport/main.go b/cmd/rootlessport/main.go index c1486d8402d..f60a321640c 100644 --- a/cmd/rootlessport/main.go +++ b/cmd/rootlessport/main.go @@ -14,12 +14,12 @@ import ( "path/filepath" "strings" - "github.com/containernetworking/plugins/pkg/ns" rkport "github.com/rootless-containers/rootlesskit/v2/pkg/port" rkbuiltin "github.com/rootless-containers/rootlesskit/v2/pkg/port/builtin" rkportutil "github.com/rootless-containers/rootlesskit/v2/pkg/port/portutil" "github.com/sirupsen/logrus" "go.podman.io/common/libnetwork/types" + "go.podman.io/common/pkg/netns" "go.podman.io/common/pkg/rootlessport" "golang.org/x/sys/unix" ) @@ -137,11 +137,11 @@ func parent() error { cmd.Stdout = &logrusWriter{prefix: "child"} cmd.Stderr = cmd.Stdout cmd.Env = append(os.Environ(), reexecChildEnvOpaque+"="+string(opaqueJSON)) - childNS, err := ns.GetNS(cfg.NetNSPath) + childNS, err := netns.GetNS(cfg.NetNSPath) if err != nil { return err } - if err := childNS.Do(func(_ ns.NetNS) error { + if err := childNS.Do(func(_ netns.NetNS) error { logrus.Infof("Starting child driver in child netns (%q %v)", cmd.Path, cmd.Args) return cmd.Start() }); err != nil { diff --git a/contrib/tmpfile/podman.conf b/contrib/tmpfile/podman.conf index afb3d5bb2b6..42fe0ca3f58 100644 --- a/contrib/tmpfile/podman.conf +++ b/contrib/tmpfile/podman.conf @@ -13,7 +13,6 @@ x /tmp/run-*/libpod R! /tmp/run-*/libpod D! /var/lib/containers/storage/tmp 0700 root root D! /run/podman 0700 root root -D! /var/lib/cni/networks # Remove /var/tmp/container_images* podman temporary directories on each # boot which are created when pulling or saving images. R! /var/tmp/container_images* diff --git a/libpod/container.go b/libpod/container.go index 68e22468063..bc664fda2d4 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -1465,9 +1465,9 @@ func (c *Container) NetworkMode() string { if ns.Path != "" { networkMode = fmt.Sprintf("ns:%s", ns.Path) } else { - // We're making a network ns, but not - // configuring with Slirp or CNI. That - // means it's --net=none + // We're making a network ns, but not + // configuring with Slirp. That means + // it's --net=none networkMode = "none" } break diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index 1ffeaceb661..cb22ea440cb 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -1600,7 +1600,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti perNetOpts.StaticIPs = append(perNetOpts.StaticIPs, netAddress.IPNet.IP) } } - // Normally interfaces have a length of 1, only for some special cni configs we could get more. + // Normally interfaces have a length of 1, only for some special configs we could get more. // For now just use the first interface to get the ips this should be good enough for most cases. break } diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 759100ef77f..034d090a1e1 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -6,7 +6,6 @@ import ( "fmt" "net" - "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/podman/v6/libpod/define" "github.com/containers/podman/v6/pkg/rootless" "github.com/opencontainers/runtime-spec/specs-go" @@ -173,7 +172,7 @@ func getContainerNetIO(ctr *Container) (map[string]define.ContainerNetworkStats, return nil, nil } - err := ns.WithNetNSPath(netNSPath, func(_ ns.NetNS) error { + err := netns.WithNetNSPath(netNSPath, func(_ netns.NetNS) error { links, err := netlink.LinkList() if err != nil { return fmt.Errorf("retrieving all network interfaces: %w", err) @@ -218,7 +217,7 @@ func (c *Container) joinedNetworkNSPath() (string, bool) { func (c *Container) inspectJoinedNetworkNS(networkns string) (q types.StatusBlock, retErr error) { var result types.StatusBlock - err := ns.WithNetNSPath(networkns, func(_ ns.NetNS) error { + err := netns.WithNetNSPath(networkns, func(_ netns.NetNS) error { ifaces, err := net.Interfaces() if err != nil { return err diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index fdeed23ebde..132c7696f63 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -624,7 +624,7 @@ var _ = Describe("Podman network create", func() { // can only check this as root if !isRootless() { - // make sure cni/netavark created bridge with expected name + // make sure netavark created bridge with expected name bridge, err := net.InterfaceByName(bridgeName) Expect(err).ToNot(HaveOccurred()) Expect(bridge.Name).To(Equal(bridgeName)) @@ -656,7 +656,7 @@ var _ = Describe("Podman network create", func() { containerIP, _, err := net.ParseCIDR(try.OutputToString()) Expect(err).ToNot(HaveOccurred()) - // Note as of today (June 2023) we always get the first ip from netavark and cni but let's not depend on that. + // Note as of today (June 2023) we always get the first ip from netavark but let's not depend on that. // All we care about is the ip is from the range which allows for both. Expect(containerIP.String()).To(Or(Equal("10.11.16.11"), Equal("10.11.16.12")), "ip address must be in --ip-range") }) diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index bdaf048479a..931227267b5 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -13,12 +13,12 @@ import ( "sync" "syscall" - "github.com/containernetworking/plugins/pkg/ns" . "github.com/containers/podman/v6/test/utils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" "github.com/vishvananda/netlink" + "go.podman.io/common/pkg/netns" "go.podman.io/storage/pkg/stringid" ) @@ -790,7 +790,7 @@ EXPOSE 2004-2005/tcp`, ALPINE) }) It("podman run --uidmap /etc/hosts contains --hostname", func() { - SkipIfRootless("uidmap population of cninetworks not supported for rootless users") + SkipIfRootless("uidmap population of networks not supported for rootless users") session := podmanTest.Podman([]string{"run", "--uidmap", "0:100000:1000", "--rm", "--hostname", "foohostname", ALPINE, "grep", "foohostname", "/etc/hosts"}) session.WaitWithDefaultTimeout() Expect(session).Should(ExitCleanly()) @@ -884,7 +884,7 @@ EXPOSE 2004-2005/tcp`, ALPINE) } setupNetworkNs := func(networkNSName string) { - _ = ns.WithNetNSPath("/run/netns/"+networkNSName, func(_ ns.NetNS) error { + _ = netns.WithNetNSPath("/run/netns/"+networkNSName, func(_ netns.NetNS) error { loopbackup() linkup("eth0", "46:7f:45:6e:4f:c8", []string{"10.25.40.0/24", "fd04:3e42:4a4e:3381::/64"}) linkup("eth1", "56:6e:35:5d:3e:a8", []string{"10.88.0.0/16"}) From c63f29245dcdd957489bde7421f61b0442307b32 Mon Sep 17 00:00:00 2001 From: Lokesh Mandvekar Date: Wed, 4 Mar 2026 17:01:09 +0530 Subject: [PATCH 3/6] test: remove CNI_CONFIG_DIR env var handling The CNI_CONFIG_DIR environment variable is no longer relevant now that CNI support has been removed. Signed-off-by: Lokesh Mandvekar --- pkg/bindings/test/common_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go index 0bf60309d8c..7a8a1cbfa66 100644 --- a/pkg/bindings/test/common_test.go +++ b/pkg/bindings/test/common_test.go @@ -83,10 +83,6 @@ func (b *bindingTest) runPodman(command []string) *Session { if ok { cmd = append(cmd, "--cgroup-manager", val) } - val, ok = os.LookupEnv("CNI_CONFIG_DIR") - if ok { - cmd = append(cmd, "--network-config-dir", val) - } val, ok = os.LookupEnv("CONMON") if ok { cmd = append(cmd, "--conmon", val) From 9d98b6b4e5e50bcdeb2e7da6fadd7016961bf2b7 Mon Sep 17 00:00:00 2001 From: Lokesh Mandvekar Date: Wed, 4 Mar 2026 17:01:32 +0530 Subject: [PATCH 4/6] Makefile: remove FreeBSD CNI build tag The cni build tag for FreeBSD is no longer needed now that CNI support has been removed from the codebase. Signed-off-by: Lokesh Mandvekar --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index 41e80d32c2a..a2d0bb3fae0 100644 --- a/Makefile +++ b/Makefile @@ -80,8 +80,6 @@ ifeq ($(NATIVE_GOOS),freebsd) SED=gsed GREP=ggrep MAN_L= mandoc -# FreeBSD needs CNI until netavark is supported -BUILDTAGS += cni else SED=sed GREP=grep From c2feff8f99de1d60a76892173a3afe479dbf21f9 Mon Sep 17 00:00:00 2001 From: Lokesh Mandvekar Date: Tue, 17 Mar 2026 15:52:22 +0530 Subject: [PATCH 5/6] docs: remove rootless CNI troubleshooting section Signed-off-by: Lokesh Mandvekar --- troubleshooting.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/troubleshooting.md b/troubleshooting.md index e7be7bc77e6..35418d9defd 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -779,25 +779,6 @@ And now this should work: $ podman-remote info ``` -### 29) Rootless CNI networking fails in RHEL with Podman v2.2.1 to v3.0.1. - -A failure is encountered when trying to use networking on a rootless -container in Podman v2.2.1 through v3.0.1 on RHEL. This error does not -occur on other Linux distributions. - -#### Symptom - -A rootless container is created using a CNI network, but the `podman run` command -returns an error that an image must be built. - -#### Solution - -In order to use a CNI network in a rootless container on RHEL, -an Infra container image for CNI-in-slirp4netns must be created. The -instructions for building the Infra container image can be found for -v2.2.1 [here](https://github.com/containers/podman/tree/v2.2.1-rhel/contrib/rootless-cni-infra), -and for v3.0.1 [here](https://github.com/containers/podman/tree/v3.0.1-rhel/contrib/rootless-cni-infra). - ### 30) Container related firewall rules are lost after reloading firewalld Container network can't be reached after `firewall-cmd --reload` and `systemctl restart firewalld` Running `podman network reload` will fix it but it has to be done manually. From 52bf07157cdb3a06e7012747ab1057f78830970c Mon Sep 17 00:00:00 2001 From: Lokesh Mandvekar Date: Tue, 17 Mar 2026 14:26:46 +0530 Subject: [PATCH 6/6] test: skip build-conflicting-isolation-chroot-and-network on remote The BUILDAH_ISOLATION env var is not propagated to the server via podman-remote. The buildah bud test (added in buildah PR #6697) sets BUILDAH_ISOLATION=chroot to verify the --network conflict, which silently has no effect on remote, causing the test to fail. Ref: https://github.com/containers/buildah/pull/6697 Signed-off-by: Lokesh Mandvekar --- test/buildah-bud/apply-podman-deltas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas index 3595352987b..6729be2c764 100755 --- a/test/buildah-bud/apply-podman-deltas +++ b/test/buildah-bud/apply-podman-deltas @@ -282,6 +282,9 @@ skip_if_remote "http_proxy env is not sent via remote API" \ skip_if_remote "--metadata-file not supported in remote mode" \ "bud cache by format" +skip_if_remote "BUILDAH_ISOLATION env var not propagated via podman-remote" \ + "build-conflicting-isolation-chroot-and-network" + ############################################################################### # BEGIN tests which are skipped due to actual podman or podman-remote bugs.