From 09103756cc6038df41eb2075fd89ae97dbbf5d6a Mon Sep 17 00:00:00 2001 From: Ashley Cui Date: Tue, 28 Apr 2026 10:22:31 -0400 Subject: [PATCH] Vendor container-libs main Mostly for libnetwork changes in c/common Signed-off-by: Ashley Cui --- go.mod | 8 +- go.sum | 16 +- vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md | 9 + vendor/github.com/onsi/ginkgo/v2/README.md | 2 +- .../onsi/ginkgo/v2/ginkgo/command/program.go | 164 ++++++++ .../github.com/onsi/ginkgo/v2/ginkgo/main.go | 1 + .../github.com/onsi/ginkgo/v2/ginkgo_t_dsl.go | 4 + .../internal/testingtproxy/testing_t_proxy.go | 9 + .../github.com/onsi/ginkgo/v2/types/config.go | 3 + .../github.com/onsi/ginkgo/v2/types/flags.go | 18 + .../onsi/ginkgo/v2/types/version.go | 2 +- .../common/libnetwork/internal/util/create.go | 57 --- .../common/libnetwork/netavark/config.go | 354 ++++-------------- .../common/libnetwork/netavark/exec.go | 4 - .../common/libnetwork/netavark/network.go | 18 +- .../go.podman.io/common/pkg/config/config.go | 4 +- vendor/modules.txt | 8 +- 17 files changed, 312 insertions(+), 369 deletions(-) delete mode 100644 vendor/go.podman.io/common/libnetwork/internal/util/create.go diff --git a/go.mod b/go.mod index 1b10fdcdd1..b32a0f25c5 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/moby/sys/user v0.4.0 github.com/moby/term v0.5.2 github.com/nxadm/tail v1.4.11 - github.com/onsi/ginkgo/v2 v2.28.1 + github.com/onsi/ginkgo/v2 v2.28.2 github.com/onsi/gomega v1.39.1 github.com/opencontainers/cgroups v0.0.6 github.com/opencontainers/go-digest v1.0.0 @@ -64,9 +64,9 @@ require ( github.com/vbauerster/mpb/v8 v8.12.0 github.com/vishvananda/netlink v1.3.1 go.podman.io/buildah v1.42.1-0.20260421143840-0acb6b8cca85 - go.podman.io/common v0.67.2-0.20260427104901-081c2519fc6a - go.podman.io/image/v5 v5.39.3-0.20260427104901-081c2519fc6a - go.podman.io/storage v1.62.1-0.20260427104901-081c2519fc6a + go.podman.io/common v0.67.2-0.20260428163628-e3b0c9aa788d + go.podman.io/image/v5 v5.39.3-0.20260428163628-e3b0c9aa788d + go.podman.io/storage v1.62.1-0.20260428163628-e3b0c9aa788d golang.org/x/crypto v0.50.0 golang.org/x/net v0.53.0 golang.org/x/sync v0.20.0 diff --git a/go.sum b/go.sum index 66154b9bb5..0f5988ad4b 100644 --- a/go.sum +++ b/go.sum @@ -281,8 +281,8 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 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= -github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= +github.com/onsi/ginkgo/v2 v2.28.2 h1:DTrMfpqxiNUyQ3Y0zhn1n3cOO2euFgQPYIpkWwxVFps= +github.com/onsi/ginkgo/v2 v2.28.2/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= github.com/opencontainers/cgroups v0.0.6 h1:tfZFWTIIGaUUFImTyuTg+Mr5x8XRiSdZESgEBW7UxuI= @@ -431,12 +431,12 @@ go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09 go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= go.podman.io/buildah v1.42.1-0.20260421143840-0acb6b8cca85 h1:rVKRagobPO6kGHOg2NhGNs6xWVgZctiOn4tmxa3cytA= go.podman.io/buildah v1.42.1-0.20260421143840-0acb6b8cca85/go.mod h1:JjFirF1zlILz55ZkVYYhLRnted7mPlmoS2w2ihYw8iw= -go.podman.io/common v0.67.2-0.20260427104901-081c2519fc6a h1:cWMyBIJJe5g67dRtnzstL/tneqk2zUFDOrWHuX88tfg= -go.podman.io/common v0.67.2-0.20260427104901-081c2519fc6a/go.mod h1:dxkgre+xzxpAUuDsXBeAgTcNR4jN8d/00oHYt8QcNHs= -go.podman.io/image/v5 v5.39.3-0.20260427104901-081c2519fc6a h1:8tXwkOe3xho4XKZcsGu8PPMZi80bwQ/IR0Blr8dH69I= -go.podman.io/image/v5 v5.39.3-0.20260427104901-081c2519fc6a/go.mod h1:sAszAH18v4KPpzPZdav9ovjEBcIDkmqdhbJV9SmnzfE= -go.podman.io/storage v1.62.1-0.20260427104901-081c2519fc6a h1:i1Imee48BwEq66Kkwb2TAUnwDTOeGNLkUsXyjcdYHeA= -go.podman.io/storage v1.62.1-0.20260427104901-081c2519fc6a/go.mod h1:13aOBf6782/fbAzH7QNEqlVzFu+X4sS4MxDM/VdJGZU= +go.podman.io/common v0.67.2-0.20260428163628-e3b0c9aa788d h1:/oR7Ke8lxnw/pTcQ3mcjKLPI0gn0xc/wGPKXGpq+/gM= +go.podman.io/common v0.67.2-0.20260428163628-e3b0c9aa788d/go.mod h1:3Dn8ywd1MInft7FIPMBcLOvVWgAhiLFCwsNxCTc9QhM= +go.podman.io/image/v5 v5.39.3-0.20260428163628-e3b0c9aa788d h1:mm8baBK0FvElAxfI6Z9knY0PcnjX4wVvlI+/H4lg1kI= +go.podman.io/image/v5 v5.39.3-0.20260428163628-e3b0c9aa788d/go.mod h1:c1ged4R93jqNgA1E1Quywv65YAZvPZm4bOEqFMOi1OE= +go.podman.io/storage v1.62.1-0.20260428163628-e3b0c9aa788d h1:V1Tk7mksAafNAjdDEdJ8IFKkKceYoWXDuOqO5RJw/OI= +go.podman.io/storage v1.62.1-0.20260428163628-e3b0c9aa788d/go.mod h1:13aOBf6782/fbAzH7QNEqlVzFu+X4sS4MxDM/VdJGZU= 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/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md index 70050f35d1..2233136e60 100644 --- a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md +++ b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md @@ -1,3 +1,12 @@ +## 2.28.2 + +- Add ArtifactDir() to support Go 1.26 testing.TB interface [f3a36b6] +- Implement shell completion [94151c8] +- Add asan CLI option mirroring msan implementation [4d21dbb] +- Bump uri from 1.0.3 to 1.0.4 in /docs (#1630) [c102161] +- fix aspect ratio [9619647] +- update logos [5779304] + ## 2.28.1 Update all dependencies. This auto-updated the required version of Go to 1.24, consistent with the fact that Go 1.23 has been out of support for almost six months. diff --git a/vendor/github.com/onsi/ginkgo/v2/README.md b/vendor/github.com/onsi/ginkgo/v2/README.md index b4c3ce0ad2..6d36e377eb 100644 --- a/vendor/github.com/onsi/ginkgo/v2/README.md +++ b/vendor/github.com/onsi/ginkgo/v2/README.md @@ -120,6 +120,6 @@ Sponsors commit to a [sponsorship](https://github.com/sponsors/onsi) for a year.

Browser testing via - +

diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go index c3f6d3a11e..53114904ca 100644 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/command/program.go @@ -1,9 +1,13 @@ package command import ( + "bufio" "fmt" "io" + "maps" "os" + "path/filepath" + "slices" "strings" "github.com/onsi/ginkgo/v2/formatter" @@ -158,6 +162,166 @@ func (p Program) handleHelpRequestsAndExit(writer io.Writer, args []string) { } } +type completionOptions = struct { + Complete bool + Install bool +} + +func (p *Program) BuildCompletionCommand() Command { + opts := completionOptions{} + flags, err := types.NewGinkgoFlagSet( + types.GinkgoFlags{ + {Name: "complete", KeyPath: "Complete", Usage: "Generate completion for arguments after --"}, + {Name: "install", KeyPath: "Install", Usage: "Install shell completion script into $XDG_DATA_HOME, ~/.local/share"}, + }, + &opts, + types.GinkgoFlagSections{}, + ) + if err != nil { + panic(err) + } + return Command{ + Name: "completion", + Usage: "ginkgo completion [-- ]", + Flags: flags, + ShortDoc: "Generate shell completion", + Documentation: `To use install completion script for your shell (bash, fish, zsh). +Or load completion code by: {{bold}}source <(ginkgo completion ){{/}}.`, + Command: func(args []string, completeArgs []string) { + p.handleCompletionAndExit(args, completeArgs, opts) + }, + } +} + +func (p Program) generateShellCompletionScript(shell string) (scriptPath string, script string) { + switch shell { + case "bash": + scriptPath = fmt.Sprintf("bash-completion/completions/%s", p.Name) + script = fmt.Sprintf(`__%s_complete_bash() { + mapfile -t COMPREPLY < <("${COMP_WORDS[0]}" completion --complete bash -- "${COMP_WORDS[@]:1:COMP_CWORD}") +} +complete -o bashdefault -o default -F __%[1]s_complete_bash %[1]s +`, p.Name) + + case "fish": + scriptPath = fmt.Sprintf("fish/vendor_completions.d/%s.fish", p.Name) + script = fmt.Sprintf(`function __fish_%[1]s_complete + set -l args (commandline -opc) (commandline -ct) + set -e args[1] + %[1]s completion --complete fish -- $args +end +complete -c %[1]s -a "(__fish_%[1]s_complete)" +`, p.Name) + + case "zsh": + scriptPath = fmt.Sprintf("zsh/site-functions/_%s", p.Name) + script = fmt.Sprintf(`#compdef %[1]s +_%[1]s() { + local -a completions + completions=(${(f)"$("${words[1]}" completion --complete zsh -- "${words[@]:1:$((CURRENT-1))}")"}) + if (( ${#completions[@]} )); then + _describe 'completions' completions + else + _default + fi +} +compdef _%[1]s %[1]s +if [ "$funcstack[1]" = "_%[1]s" ]; then + _%[1]s +fi +`, p.Name) + + case "": + AbortWithUsage("Shell is not specified") + default: + AbortWith("Shell %q is not supported yet. Choose: bash, fish, zsh", shell) + } + + return scriptPath, script +} + +func (p Program) handleCompletionAndExit(args, completeArgs []string, opts completionOptions) { + writer := p.OutWriter + if writer == nil { + writer = os.Stdout + } + buffer := bufio.NewWriter(writer) + defer buffer.Flush() + + var shell string + if len(args) > 0 { + shell = args[0] + } + + if !opts.Complete { + scriptPath, script := p.generateShellCompletionScript(shell) + if opts.Install { + dataHomeDir := os.Getenv("XDG_DATA_HOME") + if dataHomeDir == "" { + userHomeDir, err := os.UserHomeDir() + AbortIfError("Failed to find home", err) + dataHomeDir = filepath.Join(userHomeDir, ".local/share") + } + scriptPath = filepath.Join(dataHomeDir, scriptPath) + fmt.Fprintf(buffer, "Installing completion script: %v\n", scriptPath) + err := os.WriteFile(scriptPath, []byte(script), 0644) + AbortIfError("Failed to install completion script", err) + } else { + buffer.Write([]byte(script)) + } + Abort(AbortDetails{}) + } + + var lastArg string + var result map[string]string + if len(completeArgs) > 0 { + lastArg = completeArgs[len(completeArgs)-1] + } + + if delim := slices.Index(completeArgs, "--"); delim >= 0 && delim != len(completeArgs)-1 { + // No completion for pass-through arguments after "--" + } else if len(lastArg) > 0 && lastArg[0] == '-' { + // Complete flags + cmd := &p.DefaultCommand + for i := range p.Commands { + if p.Commands[i].Name == completeArgs[0] { + cmd = &p.Commands[i] + break + } + } + result = cmd.Flags.Completion(lastArg) + } else if len(completeArgs) <= 1 { + // Complete commands + result = make(map[string]string, len(p.Commands)+1) + for _, cmd := range append(p.Commands, p.DefaultCommand) { + if strings.HasPrefix(cmd.Name, lastArg) { + result[cmd.Name] = cmd.Usage + } + } + } + + width := 0 + for suggest := range result { + width = max(width, len(suggest)) + } + + for _, suggest := range slices.Sorted(maps.Keys(result)) { + usage := result[suggest] + switch { + case shell == "bash" && usage != "" && len(result) > 1: + fmt.Fprintf(buffer, "%*s (%s)\n", -width-2, suggest, usage) + case shell == "fish": + fmt.Fprintf(buffer, "%s\t%s\n", suggest, usage) + case shell == "zsh": + fmt.Fprintf(buffer, "%s:%s\n", suggest, usage) + default: + fmt.Fprintln(buffer, suggest) + } + } + + Abort(AbortDetails{}) +} + func (p Program) EmitUsage(writer io.Writer) { fmt.Fprintln(writer, formatter.F(p.Heading)) fmt.Fprintln(writer, formatter.F("{{gray}}%s{{/}}", strings.Repeat("-", len(p.Heading)))) diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go index 419589b48c..596c210cf1 100644 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/main.go @@ -41,6 +41,7 @@ func main() { {Name: "nodot", Deprecation: types.Deprecations.Nodot()}, }, } + program.Commands = append(program.Commands, program.BuildCompletionCommand()) program.RunAndExit(os.Args) } diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo_t_dsl.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo_t_dsl.go index 40d1e1ab5c..db3e248470 100644 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo_t_dsl.go +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo_t_dsl.go @@ -72,6 +72,7 @@ type GinkgoTInterface interface { TempDir() string Attr(key, value string) Output() io.Writer + ArtifactDir() string } /* @@ -196,3 +197,6 @@ func (g *GinkgoTBWrapper) Attr(key, value string) { func (g *GinkgoTBWrapper) Output() io.Writer { return g.GinkgoT.Output() } +func (g *GinkgoTBWrapper) ArtifactDir() string { + return g.GinkgoT.ArtifactDir() +} diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/testingtproxy/testing_t_proxy.go b/vendor/github.com/onsi/ginkgo/v2/internal/testingtproxy/testing_t_proxy.go index 5704f0fdf9..e6fbaee416 100644 --- a/vendor/github.com/onsi/ginkgo/v2/internal/testingtproxy/testing_t_proxy.go +++ b/vendor/github.com/onsi/ginkgo/v2/internal/testingtproxy/testing_t_proxy.go @@ -181,6 +181,15 @@ func (t *ginkgoTestingTProxy) TempDir() string { return tmpDir } +func (t *ginkgoTestingTProxy) ArtifactDir() string { + artifactDir, err := os.MkdirTemp("", "ginkgo") + if err != nil { + t.fail(fmt.Sprintf("Failed to create artifact directory: %v", err), 1) + return "" + } + return artifactDir +} + // FullGinkgoTInterface func (t *ginkgoTestingTProxy) AddReportEntryVisibilityAlways(name string, args ...any) { finalArgs := []any{internal.Offset(1), types.ReportEntryVisibilityAlways} diff --git a/vendor/github.com/onsi/ginkgo/v2/types/config.go b/vendor/github.com/onsi/ginkgo/v2/types/config.go index f847036046..ca64acb27a 100644 --- a/vendor/github.com/onsi/ginkgo/v2/types/config.go +++ b/vendor/github.com/onsi/ginkgo/v2/types/config.go @@ -215,6 +215,7 @@ type GoFlagsConfig struct { N bool ModFile string ModCacheRW bool + ASan bool MSan bool PkgDir string Tags string @@ -570,6 +571,8 @@ var GoBuildFlags = GinkgoFlags{ Usage: "leave newly-created directories in the module cache read-write instead of making them read-only."}, {KeyPath: "Go.ModFile", Name: "modfile", UsageArgument: "file", SectionKey: "go-build", Usage: `in module aware mode, read (and possibly write) an alternate go.mod file instead of the one in the module root directory. A file named go.mod must still be present in order to determine the module root directory, but it is not accessed. When -modfile is specified, an alternate go.sum file is also used: its path is derived from the -modfile flag by trimming the ".mod" extension and appending ".sum".`}, + {KeyPath: "Go.ASan", Name: "asan", SectionKey: "go-build", + Usage: "enable interoperation with address sanitizer."}, {KeyPath: "Go.MSan", Name: "msan", SectionKey: "go-build", Usage: "enable interoperation with memory sanitizer. Supported only on linux/amd64, linux/arm64 and only with Clang/LLVM as the host C compiler. On linux/arm64, pie build mode will be used."}, {KeyPath: "Go.N", Name: "n", SectionKey: "go-build", diff --git a/vendor/github.com/onsi/ginkgo/v2/types/flags.go b/vendor/github.com/onsi/ginkgo/v2/types/flags.go index 8409653f97..eb04c3e78a 100644 --- a/vendor/github.com/onsi/ginkgo/v2/types/flags.go +++ b/vendor/github.com/onsi/ginkgo/v2/types/flags.go @@ -212,6 +212,24 @@ func (f GinkgoFlagSet) IsZero() bool { return f.flagSet == nil } +func (f GinkgoFlagSet) Completion(arg string) map[string]string { + if f.IsZero() { + return nil + } + prefix := strings.TrimLeft(arg, "-") + dash := arg[:len(arg)-len(prefix)] + if len(dash) < 1 || len(dash) > 3 { + return nil + } + result := make(map[string]string, len(f.flags)) + for _, flag := range f.flags { + if flag.Name != "" && strings.HasPrefix(flag.Name, prefix) { + result[dash+flag.Name] = flag.Usage + } + } + return result +} + func (f GinkgoFlagSet) WasSet(name string) bool { found := false f.flagSet.Visit(func(f *flag.Flag) { diff --git a/vendor/github.com/onsi/ginkgo/v2/types/version.go b/vendor/github.com/onsi/ginkgo/v2/types/version.go index 1df09be005..6874270ac2 100644 --- a/vendor/github.com/onsi/ginkgo/v2/types/version.go +++ b/vendor/github.com/onsi/ginkgo/v2/types/version.go @@ -1,3 +1,3 @@ package types -const VERSION = "2.28.1" +const VERSION = "2.28.2" diff --git a/vendor/go.podman.io/common/libnetwork/internal/util/create.go b/vendor/go.podman.io/common/libnetwork/internal/util/create.go deleted file mode 100644 index 5096987dd0..0000000000 --- a/vendor/go.podman.io/common/libnetwork/internal/util/create.go +++ /dev/null @@ -1,57 +0,0 @@ -package util - -import ( - "fmt" - - "github.com/sirupsen/logrus" - "go.podman.io/common/libnetwork/types" -) - -func CommonNetworkCreate(n NetUtil, network *types.Network) error { - if network.Labels == nil { - network.Labels = map[string]string{} - } - if network.Options == nil { - network.Options = map[string]string{} - } - if network.IPAMOptions == nil { - network.IPAMOptions = map[string]string{} - } - - var name string - var err error - // validate the name when given - if network.Name != "" { - if !types.NameRegex.MatchString(network.Name) { - return fmt.Errorf("network name %s invalid: %w", network.Name, types.ErrInvalidName) - } - if _, err := n.Network(network.Name); err == nil { - return fmt.Errorf("network name %s already used: %w", network.Name, types.ErrNetworkExists) - } - } else { - name, err = GetFreeDeviceName(n) - if err != nil { - return err - } - network.Name = name - // also use the name as interface name when we create a bridge network - if network.Driver == types.BridgeNetworkDriver && network.NetworkInterface == "" { - network.NetworkInterface = name - } - } - - // Validate interface name if specified - if network.NetworkInterface != "" { - if err := ValidateInterfaceName(network.NetworkInterface); err != nil { - return fmt.Errorf("network interface name %s invalid: %w", network.NetworkInterface, err) - } - } - return nil -} - -func IpamNoneDisableDNS(network *types.Network) { - if network.IPAMOptions[types.Driver] == types.NoneIPAMDriver { - logrus.Debugf("dns disabled for network %q because ipam driver is set to none", network.Name) - network.DNSEnabled = false - } -} diff --git a/vendor/go.podman.io/common/libnetwork/netavark/config.go b/vendor/go.podman.io/common/libnetwork/netavark/config.go index f8631d2895..3b78544352 100644 --- a/vendor/go.podman.io/common/libnetwork/netavark/config.go +++ b/vendor/go.podman.io/common/libnetwork/netavark/config.go @@ -10,11 +10,11 @@ import ( "os" "path/filepath" "slices" - "strconv" - "time" + "strings" internalutil "go.podman.io/common/libnetwork/internal/util" "go.podman.io/common/libnetwork/types" + "go.podman.io/common/pkg/config" "go.podman.io/storage/pkg/stringid" ) @@ -100,13 +100,14 @@ func (n *netavarkNetwork) NetworkCreate(net types.Network, options *types.Networ if err != nil { return types.Network{}, err } + + if options != nil && options.IgnoreIfExists { + if network, ok := n.networks[net.Name]; ok { + return *network, nil + } + } 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, nil - } - } return types.Network{}, err } // add the new network to the map @@ -139,251 +140,86 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo return nil, errors.New("failed to create random network ID") } } + if newNetwork.Name == "" { + name, err := internalutil.GetFreeDeviceName(n) + if err != nil { + return nil, err + } + newNetwork.Name = name + } - err := internalutil.CommonNetworkCreate(n, newNetwork) + usedSubnets, err := internalutil.GetUsedSubnets(n) if err != nil { return nil, err } - err = validateIPAMDriver(newNetwork) + usedNames := make(map[string]string, len(n.networks)) + for name, network := range n.networks { + usedNames[name] = network.ID + } + + type Used struct { + Interfaces []string `json:"interfaces"` + Names map[string]string `json:"names"` + Subnets []types.IPNet `json:"subnets"` + } + + type ConfigOpts struct { + SubnetPools []config.SubnetPool `json:"subnet_pools"` + DefaultInterfaceName string `json:"default_interface_name"` + CheckUsedSubnets bool `json:"check_used_subnets"` + } + + type CreateConfigOptions struct { + Network types.Network `json:"network"` + Used Used `json:"used"` + Options ConfigOpts `json:"options"` + } + + subnets := make([]types.IPNet, len(usedSubnets)) + for i, subnet := range usedSubnets { + subnets[i] = types.IPNet{IPNet: *subnet} + } + + opts := CreateConfigOptions{ + Network: *newNetwork, + Used: Used{ + Interfaces: internalutil.GetBridgeInterfaceNames(n), + Names: usedNames, + Subnets: subnets, + }, + Options: ConfigOpts{ + SubnetPools: n.defaultsubnetPools, + DefaultInterfaceName: n.DefaultInterfaceName(), + CheckUsedSubnets: !defaultNet, + }, + } + var needsPlugin bool + if !slices.Contains(builtinDrivers, newNetwork.Driver) { + needsPlugin = true + } + var result *types.Network + err = n.execNetavark([]string{"create"}, needsPlugin, &opts, &result) if err != nil { + if strings.Contains(err.Error(), "network already exists") { + return nil, fmt.Errorf("%w%.0w", err, types.ErrNetworkExists) + } 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 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. - 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) - - checkBridgeConflict := true - // validate the given options, - for key, value := range newNetwork.Options { - switch key { - case types.MTUOption: - _, err = internalutil.ParseMTU(value) - if err != nil { - return nil, err - } - - case types.VLANOption: - _, err = internalutil.ParseVlan(value) - if err != nil { - return nil, err - } - // Unset used networks here to ensure that when using vlan networks - // we do not error if the subnet is already in use on the host. - // https://github.com/containers/podman/issues/25736 - usedNetworks = nil - // If there is no vlan there should be no other config with the same bridge. - // However with vlan we want to allow that so that you can have different - // configs on the same bridge but different vlans - // https://github.com/containers/common/issues/2095 - checkBridgeConflict = false - - case types.IsolateOption: - val, err := internalutil.ParseIsolate(value) - if err != nil { - return nil, err - } - newNetwork.Options[types.IsolateOption] = val - case types.MetricOption: - _, err := strconv.ParseUint(value, 10, 32) - if err != nil { - return nil, err - } - case types.NoDefaultRoute: - val, err := strconv.ParseBool(value) - if err != nil { - return nil, err - } - // rust only support "true" or "false" while go can parse 1 and 0 as well so we need to change it - newNetwork.Options[types.NoDefaultRoute] = strconv.FormatBool(val) - case types.VRFOption: - if len(value) == 0 { - return nil, errors.New("invalid vrf name") - } - case types.ModeOption: - switch value { - case types.BridgeModeManaged: - case types.BridgeModeUnmanaged: - // Unset used networks here to ensure that when using unmanaged networks - // we do not error if the subnet is already in use on the host. - // https://github.com/containers/common/issues/2322 - usedNetworks = nil - // Also make sure we don't error if the bridge name is already used as well. - checkBridgeConflict = false - default: - return nil, fmt.Errorf("unknown bridge mode %q", value) - } - default: - return nil, fmt.Errorf("unsupported bridge network option %s", key) - } - } - - err = internalutil.CreateBridge(n, newNetwork, usedNetworks, n.defaultsubnetPools, checkBridgeConflict) - if err != nil { - return nil, err - } - - case types.MacVLANNetworkDriver, types.IPVLANNetworkDriver: - err = createIpvlanOrMacvlan(newNetwork) - if err != nil { - return nil, err - } - default: - net, err := n.createPlugin(newNetwork) - if err != nil { - return nil, err - } - newNetwork = net - } - - // when we do not have ipam we must disable dns - internalutil.IpamNoneDisableDNS(newNetwork) - - // process NetworkDNSServers - if len(newNetwork.NetworkDNSServers) > 0 && !newNetwork.DNSEnabled { - return nil, fmt.Errorf("cannot set NetworkDNSServers if DNS is not enabled for the network: %w", types.ErrInvalidArg) - } - // validate ip address - for _, dnsServer := range newNetwork.NetworkDNSServers { - if net.ParseIP(dnsServer) == nil { - return nil, fmt.Errorf("unable to parse ip %s specified in NetworkDNSServers: %w", dnsServer, types.ErrInvalidArg) - } - } - - // add gateway when not internal or dns enabled - addGateway := !newNetwork.Internal || newNetwork.DNSEnabled - err = internalutil.ValidateSubnets(newNetwork, addGateway, usedNetworks) - if err != nil { + // normalize network fields + if err := parseNetwork(result); err != nil { return nil, err } - // validate routes - err = internalutil.ValidateRoutes(newNetwork.Routes) - if err != nil { - return nil, err - } - - newNetwork.Created = time.Now() - if !defaultNet { - err = n.commitNetwork(newNetwork) + err := n.commitNetwork(result) if err != nil { return nil, err } } - return newNetwork, nil -} - -// ipvlan shares the same mac address so supporting DHCP is not really possible. -var errIpvlanNoDHCP = errors.New("ipam driver dhcp is not supported with ipvlan") - -func createIpvlanOrMacvlan(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) - } - } - - driver := network.Driver - isMacVlan := driver != types.IPVLANNetworkDriver - - // always turn dns off with macvlan, it is not implemented in netavark - // and makes little sense to support with macvlan - // see https://github.com/containers/netavark/pull/467 - network.DNSEnabled = false - - // we already validated the drivers before so we just have to set the default here - switch network.IPAMOptions[types.Driver] { - case "": - if len(network.Subnets) == 0 { - // if no subnets and no driver choose dhcp - network.IPAMOptions[types.Driver] = types.DHCPIPAMDriver - if !isMacVlan { - return errIpvlanNoDHCP - } - } else { - network.IPAMOptions[types.Driver] = types.HostLocalIPAMDriver - } - case types.HostLocalIPAMDriver: - if len(network.Subnets) == 0 { - return fmt.Errorf("%s driver needs at least one subnet specified when the host-local ipam driver is set", driver) - } - case types.DHCPIPAMDriver: - if !isMacVlan { - return errIpvlanNoDHCP - } - if len(network.Subnets) > 0 { - return errors.New("ipam driver dhcp set but subnets are set") - } - } - - // validate the given options, we do not need them but just check to make sure they are valid - for key, value := range network.Options { - switch key { - case types.ModeOption: - if isMacVlan { - if !slices.Contains(types.ValidMacVLANModes, value) { - return fmt.Errorf("unknown macvlan mode %q", value) - } - } else { - if !slices.Contains(types.ValidIPVLANModes, value) { - return fmt.Errorf("unknown ipvlan mode %q", value) - } - } - case types.MetricOption: - _, err := strconv.ParseUint(value, 10, 32) - if err != nil { - return err - } - case types.MTUOption: - _, err := internalutil.ParseMTU(value) - if err != nil { - return err - } - case types.NoDefaultRoute: - val, err := strconv.ParseBool(value) - if err != nil { - return err - } - // rust only support "true" or "false" while go can parse 1 and 0 as well so we need to change it - network.Options[types.NoDefaultRoute] = strconv.FormatBool(val) - case types.BclimOption: - if isMacVlan { - _, err := strconv.ParseInt(value, 10, 32) - if err != nil { - return fmt.Errorf("failed to parse %q option: %w", key, err) - } - // do not fallthrough for macvlan - break - } - // bclim is only valid for macvlan not ipvlan so fallthrough to error case - fallthrough - default: - return fmt.Errorf("unsupported %s network option %s", driver, key) - } - } - return nil + return result, nil } // NetworkRemove will remove the Network with the given name or ID. @@ -461,45 +297,6 @@ func (n *netavarkNetwork) NetworkInspect(nameOrID string) (types.Network, error) return *network, nil } -func validateIPAMDriver(n *types.Network) error { - ipamDriver := n.IPAMOptions[types.Driver] - switch ipamDriver { - case "", types.HostLocalIPAMDriver, types.DHCPIPAMDriver: - case types.NoneIPAMDriver: - if len(n.Subnets) > 0 { - return errors.New("none ipam driver is set but subnets are given") - } - default: - return fmt.Errorf("unsupported ipam driver %q", ipamDriver) - } - return nil -} - -var errInvalidPluginResult = errors.New("invalid plugin result") - -func (n *netavarkNetwork) createPlugin(net *types.Network) (*types.Network, error) { - path, err := getPlugin(net.Driver, n.pluginDirs) - if err != nil { - return nil, err - } - result := new(types.Network) - err = n.execPlugin(path, []string{"create"}, net, result) - if err != nil { - return nil, fmt.Errorf("plugin %s failed: %w", path, err) - } - // now make sure that neither the name, ID, driver were changed by the plugin - if net.Name != result.Name { - return nil, fmt.Errorf("%w: changed network name", errInvalidPluginResult) - } - if net.ID != result.ID { - return nil, fmt.Errorf("%w: changed network ID", errInvalidPluginResult) - } - if net.Driver != result.Driver { - return nil, fmt.Errorf("%w: changed network driver", errInvalidPluginResult) - } - return result, nil -} - func getAllPlugins(dirs []string) []string { var plugins []string for _, dir := range dirs { @@ -515,14 +312,3 @@ func getAllPlugins(dirs []string) []string { } return plugins } - -func getPlugin(name string, dirs []string) (string, error) { - for _, dir := range dirs { - fullpath := filepath.Join(dir, name) - st, err := os.Stat(fullpath) - if err == nil && st.Mode().IsRegular() { - return fullpath, nil - } - } - return "", fmt.Errorf("failed to find driver or plugin %q", name) -} diff --git a/vendor/go.podman.io/common/libnetwork/netavark/exec.go b/vendor/go.podman.io/common/libnetwork/netavark/exec.go index 88b40bbf98..27ae896db6 100644 --- a/vendor/go.podman.io/common/libnetwork/netavark/exec.go +++ b/vendor/go.podman.io/common/libnetwork/netavark/exec.go @@ -101,10 +101,6 @@ func (n *netavarkNetwork) execNetavark(args []string, needPlugin bool, stdin, re return n.execBinary(n.netavarkBinary, append(n.getCommonNetavarkOptions(needPlugin), args...), stdin, result, env) } -func (n *netavarkNetwork) execPlugin(path string, args []string, stdin, result any) error { - return n.execBinary(path, args, stdin, result, nil) -} - func (n *netavarkNetwork) execBinary(path string, args []string, stdin, result any, env []string) error { stdinR, stdinW, err := os.Pipe() if err != nil { diff --git a/vendor/go.podman.io/common/libnetwork/netavark/network.go b/vendor/go.podman.io/common/libnetwork/netavark/network.go index 3a35b2af82..e1021309a2 100644 --- a/vendor/go.podman.io/common/libnetwork/netavark/network.go +++ b/vendor/go.podman.io/common/libnetwork/netavark/network.go @@ -296,17 +296,27 @@ func parseNetwork(network *types.Network) error { } func (n *netavarkNetwork) createDefaultNetwork() (*types.Network, error) { - net := types.Network{ + network := &types.Network{ Name: n.defaultNetwork, NetworkInterface: defaultBridgeName + "0", // Important do not change this ID - ID: "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9", - Driver: types.BridgeNetworkDriver, + ID: "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9", + Driver: types.BridgeNetworkDriver, + Created: time.Now(), Subnets: []types.Subnet{ {Subnet: n.defaultSubnet}, }, + IPAMOptions: map[string]string{ + "driver": types.HostLocalIPAMDriver, + }, } - return n.networkCreate(&net, true) + + // Normalize network fields (initializes nil maps, adds gateway, validates, etc.) + if err := parseNetwork(network); err != nil { + return nil, err + } + + return network, nil } // getNetwork will lookup a network by name or ID. It returns an diff --git a/vendor/go.podman.io/common/pkg/config/config.go b/vendor/go.podman.io/common/pkg/config/config.go index 2ab2613495..eb21a3895a 100644 --- a/vendor/go.podman.io/common/pkg/config/config.go +++ b/vendor/go.podman.io/common/pkg/config/config.go @@ -635,10 +635,10 @@ type NetworkConfig struct { type SubnetPool struct { // Base is a bigger subnet which will be used to allocate a subnet with // the given size. - Base *types.IPNet `toml:"base,omitempty"` + Base *types.IPNet `toml:"base,omitempty" json:"base,omitempty"` // Size is the CIDR for the new subnet. It must be equal or small // than the CIDR from the base subnet. - Size int `toml:"size,omitempty"` + Size int `toml:"size,omitempty" json:"size,omitempty"` } // SecretConfig represents the "secret" TOML config table. diff --git a/vendor/modules.txt b/vendor/modules.txt index 8b51a50758..d33e24a564 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -443,7 +443,7 @@ github.com/nxadm/tail/ratelimiter github.com/nxadm/tail/util github.com/nxadm/tail/watch github.com/nxadm/tail/winfile -# github.com/onsi/ginkgo/v2 v2.28.1 +# github.com/onsi/ginkgo/v2 v2.28.2 ## explicit; go 1.24.0 github.com/onsi/ginkgo/v2 github.com/onsi/ginkgo/v2/config @@ -736,7 +736,7 @@ go.podman.io/buildah/pkg/sshagent go.podman.io/buildah/pkg/util go.podman.io/buildah/pkg/volumes go.podman.io/buildah/util -# go.podman.io/common v0.67.2-0.20260427104901-081c2519fc6a +# go.podman.io/common v0.67.2-0.20260428163628-e3b0c9aa788d ## explicit; go 1.25.6 go.podman.io/common/internal go.podman.io/common/libimage @@ -802,7 +802,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.3-0.20260427104901-081c2519fc6a +# go.podman.io/image/v5 v5.39.3-0.20260428163628-e3b0c9aa788d ## explicit; go 1.25.6 go.podman.io/image/v5/copy go.podman.io/image/v5/directory @@ -879,7 +879,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.20260427104901-081c2519fc6a +# go.podman.io/storage v1.62.1-0.20260428163628-e3b0c9aa788d ## explicit; go 1.25.0 go.podman.io/storage go.podman.io/storage/drivers