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