summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--cmd/podman/volumes/export.go6
-rw-r--r--cmd/podman/volumes/import.go7
-rw-r--r--contrib/systemd/system/podman-restart.service.in3
-rw-r--r--docs/source/markdown/podman-volume-import.1.md6
-rw-r--r--docs/source/markdown/podman-volume.1.md2
-rw-r--r--go.mod1
-rw-r--r--go.sum3
-rw-r--r--libpod/container_config.go4
-rw-r--r--pkg/machine/config.go27
-rw-r--r--pkg/machine/e2e/inspect_test.go2
-rw-r--r--pkg/machine/fcos.go7
-rw-r--r--pkg/machine/qemu/machine.go24
-rw-r--r--pkg/specgenutil/specgen.go15
-rw-r--r--test/e2e/checkpoint_test.go4
-rw-r--r--test/e2e/logs_test.go12
-rw-r--r--test/e2e/volume_create_test.go17
-rw-r--r--test/system/030-run.bats11
-rw-r--r--vendor/gopkg.in/yaml.v3/decode.go78
-rw-r--r--vendor/gopkg.in/yaml.v3/parserc.go11
-rw-r--r--vendor/modules.txt3
21 files changed, 183 insertions, 62 deletions
diff --git a/Makefile b/Makefile
index fb9eb057d..2995aed65 100644
--- a/Makefile
+++ b/Makefile
@@ -295,7 +295,7 @@ $(SRCBINDIR)/podman$(BINSFX): $(SRCBINDIR) $(SOURCES) go.mod go.sum
$(SRCBINDIR)/podman-remote-static: $(SRCBINDIR) $(SOURCES) go.mod go.sum
CGO_ENABLED=0 \
- GOOS=$(GOOS) \
+ GOOS=linux \
GOARCH=$(GOARCH) \
$(GO) build \
$(BUILDFLAGS) \
diff --git a/cmd/podman/volumes/export.go b/cmd/podman/volumes/export.go
index 5086323f9..113f79a0b 100644
--- a/cmd/podman/volumes/export.go
+++ b/cmd/podman/volumes/export.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/containers/podman/v4/pkg/errorhandling"
"github.com/containers/podman/v4/utils"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -58,10 +59,13 @@ func export(cmd *cobra.Command, args []string) error {
return errors.New("expects output path, use --output=[path]")
}
inspectOpts.Type = common.VolumeType
- volumeData, _, err := containerEngine.VolumeInspect(ctx, args, inspectOpts)
+ volumeData, errs, err := containerEngine.VolumeInspect(ctx, args, inspectOpts)
if err != nil {
return err
}
+ if len(errs) > 0 {
+ return errorhandling.JoinErrors(errs)
+ }
if len(volumeData) < 1 {
return errors.New("no volume data found")
}
diff --git a/cmd/podman/volumes/import.go b/cmd/podman/volumes/import.go
index 988c5536d..76a311643 100644
--- a/cmd/podman/volumes/import.go
+++ b/cmd/podman/volumes/import.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/parse"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/containers/podman/v4/pkg/errorhandling"
"github.com/containers/podman/v4/utils"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -60,10 +61,14 @@ func importVol(cmd *cobra.Command, args []string) error {
}
inspectOpts.Type = common.VolumeType
- volumeData, _, err := containerEngine.VolumeInspect(ctx, volumes, inspectOpts)
+ inspectOpts.Type = common.VolumeType
+ volumeData, errs, err := containerEngine.VolumeInspect(ctx, volumes, inspectOpts)
if err != nil {
return err
}
+ if len(errs) > 0 {
+ return errorhandling.JoinErrors(errs)
+ }
if len(volumeData) < 1 {
return errors.New("no volume data found")
}
diff --git a/contrib/systemd/system/podman-restart.service.in b/contrib/systemd/system/podman-restart.service.in
index 1f13e57e1..de0249381 100644
--- a/contrib/systemd/system/podman-restart.service.in
+++ b/contrib/systemd/system/podman-restart.service.in
@@ -2,12 +2,15 @@
Description=Podman Start All Containers With Restart Policy Set To Always
Documentation=man:podman-start(1)
StartLimitIntervalSec=0
+Wants=network-online.target
+After=network-online.target
[Service]
Type=oneshot
RemainAfterExit=true
Environment=LOGGING="--log-level=info"
ExecStart=@@PODMAN@@ $LOGGING start --all --filter restart-policy=always
+ExecStop=/bin/sh -c '@@PODMAN@@ $LOGGING stop $(@@PODMAN@@ container ls --filter restart-policy=always -q)'
[Install]
WantedBy=default.target
diff --git a/docs/source/markdown/podman-volume-import.1.md b/docs/source/markdown/podman-volume-import.1.md
index 71956f43a..4ae9ae1e2 100644
--- a/docs/source/markdown/podman-volume-import.1.md
+++ b/docs/source/markdown/podman-volume-import.1.md
@@ -1,7 +1,7 @@
% podman-volume-import(1)
## NAME
-podman\-volume\-import - Import tarball contents into a podman volume
+podman\-volume\-import - Import tarball contents into an existing podman volume
## SYNOPSIS
**podman volume import** *volume* [*source*]
@@ -11,9 +11,9 @@ podman\-volume\-import - Import tarball contents into a podman volume
**podman volume import** imports the contents of a tarball into the podman volume's mount point.
**podman volume import** can consume piped input when using `-` as source path.
-Note: Following command is not supported by podman-remote.
+The given volume must already exist and will not be created by podman volume import.
-**podman volume import VOLUME [SOURCE]**
+Note: Following command is not supported by podman-remote.
#### **--help**
diff --git a/docs/source/markdown/podman-volume.1.md b/docs/source/markdown/podman-volume.1.md
index d05f007c8..476d58591 100644
--- a/docs/source/markdown/podman-volume.1.md
+++ b/docs/source/markdown/podman-volume.1.md
@@ -16,7 +16,7 @@ podman volume is a set of subcommands that manage volumes.
| create | [podman-volume-create(1)](podman-volume-create.1.md) | Create a new volume. |
| exists | [podman-volume-exists(1)](podman-volume-exists.1.md) | Check if the given volume exists. |
| export | [podman-volume-export(1)](podman-volume-export.1.md) | Exports volume to external tar. |
-| import | [podman-volume-import(1)](podman-volume-import.1.md) | Import tarball contents into a podman volume. |
+| import | [podman-volume-import(1)](podman-volume-import.1.md) | Import tarball contents into an existing podman volume. |
| inspect | [podman-volume-inspect(1)](podman-volume-inspect.1.md) | Get detailed information on one or more volumes. |
| ls | [podman-volume-ls(1)](podman-volume-ls.1.md) | List all the available volumes. |
| mount | [podman-volume-mount(1)](podman-volume-mount.1.md) | Mount a volume filesystem. |
diff --git a/go.mod b/go.mod
index 1880134e9..14aea5f3d 100644
--- a/go.mod
+++ b/go.mod
@@ -72,4 +72,5 @@ require (
google.golang.org/protobuf v1.28.0
gopkg.in/inf.v0 v0.9.1
gopkg.in/yaml.v2 v2.4.0
+ gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 47c842744..59eb31f9f 100644
--- a/go.sum
+++ b/go.sum
@@ -2047,8 +2047,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
diff --git a/libpod/container_config.go b/libpod/container_config.go
index ae3bc5865..30b84adcf 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -243,12 +243,12 @@ type ContainerNetworkConfig struct {
// This cannot be set unless CreateNetNS is set.
// If not set, the container will be dynamically assigned an IP by CNI.
// Deprecated: Do no use this anymore, this is only for DB backwards compat.
- StaticIP net.IP `json:"staticIP"`
+ StaticIP net.IP `json:"staticIP,omitempty"`
// StaticMAC is a static MAC to request for the container.
// This cannot be set unless CreateNetNS is set.
// If not set, the container will be dynamically assigned a MAC by CNI.
// Deprecated: Do no use this anymore, this is only for DB backwards compat.
- StaticMAC types.HardwareAddr `json:"staticMAC"`
+ StaticMAC types.HardwareAddr `json:"staticMAC,omitempty"`
// PortMappings are the ports forwarded to the container's network
// namespace
// These are not used unless CreateNetNS is true
diff --git a/pkg/machine/config.go b/pkg/machine/config.go
index d34776714..abbebc9f9 100644
--- a/pkg/machine/config.go
+++ b/pkg/machine/config.go
@@ -138,14 +138,15 @@ type DistributionDownload interface {
Get() *Download
}
type InspectInfo struct {
- ConfigPath VMFile
- Created time.Time
- Image ImageConfig
- LastUp time.Time
- Name string
- Resources ResourceConfig
- SSHConfig SSHConfig
- State Status
+ ConfigPath VMFile
+ ConnectionInfo ConnectionConfig
+ Created time.Time
+ Image ImageConfig
+ LastUp time.Time
+ Name string
+ Resources ResourceConfig
+ SSHConfig SSHConfig
+ State Status
}
func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url.URL {
@@ -286,11 +287,11 @@ func NewMachineFile(path string, symlink *string) (*VMFile, error) {
// makeSymlink for macOS creates a symlink in $HOME/.podman/
// for a machinefile like a socket
func (m *VMFile) makeSymlink(symlink *string) error {
- homedir, err := os.UserHomeDir()
+ homeDir, err := os.UserHomeDir()
if err != nil {
return err
}
- sl := filepath.Join(homedir, ".podman", *symlink)
+ sl := filepath.Join(homeDir, ".podman", *symlink)
// make the symlink dir and throw away if it already exists
if err := os.MkdirAll(filepath.Dir(sl), 0700); err != nil && !errors2.Is(err, os.ErrNotExist) {
return err
@@ -335,3 +336,9 @@ type SSHConfig struct {
// RemoteUsername of the vm user
RemoteUsername string
}
+
+// ConnectionConfig contains connections like sockets, etc.
+type ConnectionConfig struct {
+ // PodmanSocket is the exported podman service socket
+ PodmanSocket *VMFile `json:"PodmanSocket"`
+}
diff --git a/pkg/machine/e2e/inspect_test.go b/pkg/machine/e2e/inspect_test.go
index 2c9de5664..cdf13bb1a 100644
--- a/pkg/machine/e2e/inspect_test.go
+++ b/pkg/machine/e2e/inspect_test.go
@@ -2,6 +2,7 @@ package e2e
import (
"encoding/json"
+ "strings"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/qemu"
@@ -86,6 +87,7 @@ var _ = Describe("podman machine stop", func() {
var inspectInfo []machine.InspectInfo
err = jsoniter.Unmarshal(inspectSession.Bytes(), &inspectInfo)
Expect(err).To(BeNil())
+ Expect(strings.HasSuffix(inspectInfo[0].ConnectionInfo.PodmanSocket.GetPath(), "podman.sock"))
inspect := new(inspectMachine)
inspect = inspect.withFormat("{{.Name}}")
diff --git a/pkg/machine/fcos.go b/pkg/machine/fcos.go
index df58b8a1e..77427139a 100644
--- a/pkg/machine/fcos.go
+++ b/pkg/machine/fcos.go
@@ -146,13 +146,6 @@ func GetFCOSDownload(imageStream string) (*FcosDownloadInfo, error) { //nolint:s
streamType string
)
- // This is being hard set to testing. Once podman4 is in the
- // fcos trees, we should remove it and re-release at least on
- // macs.
- // TODO: remove when podman4.0 is in coreos
-
- imageStream = "podman-testing" //nolint:staticcheck
-
switch imageStream {
case "podman-testing":
streamType = "podman-testing"
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index eb650c91e..b9f23662e 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -1472,16 +1472,22 @@ func (v *MachineVM) Inspect() (*machine.InspectInfo, error) {
if err != nil {
return nil, err
}
-
+ connInfo := new(machine.ConnectionConfig)
+ podmanSocket, err := v.forwardSocketPath()
+ if err != nil {
+ return nil, err
+ }
+ connInfo.PodmanSocket = podmanSocket
return &machine.InspectInfo{
- ConfigPath: v.ConfigPath,
- Created: v.Created,
- Image: v.ImageConfig,
- LastUp: v.LastUp,
- Name: v.Name,
- Resources: v.ResourceConfig,
- SSHConfig: v.SSHConfig,
- State: state,
+ ConfigPath: v.ConfigPath,
+ ConnectionInfo: *connInfo,
+ Created: v.Created,
+ Image: v.ImageConfig,
+ LastUp: v.LastUp,
+ Name: v.Name,
+ Resources: v.ResourceConfig,
+ SSHConfig: v.SSHConfig,
+ State: state,
}, nil
}
diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go
index 9cb2f200b..efaade9cd 100644
--- a/pkg/specgenutil/specgen.go
+++ b/pkg/specgenutil/specgen.go
@@ -622,7 +622,14 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
if opt == "no-new-privileges" {
s.ContainerSecurityConfig.NoNewPrivileges = true
} else {
- con := strings.SplitN(opt, "=", 2)
+ // Docker deprecated the ":" syntax but still supports it,
+ // so we need to as well
+ var con []string
+ if strings.Contains(opt, "=") {
+ con = strings.SplitN(opt, "=", 2)
+ } else {
+ con = strings.SplitN(opt, ":", 2)
+ }
if len(con) != 2 {
return fmt.Errorf("invalid --security-opt 1: %q", opt)
}
@@ -650,6 +657,12 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
}
case "unmask":
s.ContainerSecurityConfig.Unmask = append(s.ContainerSecurityConfig.Unmask, con[1:]...)
+ case "no-new-privileges":
+ noNewPrivileges, err := strconv.ParseBool(con[1])
+ if err != nil {
+ return fmt.Errorf("invalid --security-opt 2: %q", opt)
+ }
+ s.ContainerSecurityConfig.NoNewPrivileges = noNewPrivileges
default:
return fmt.Errorf("invalid --security-opt 2: %q", opt)
}
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index 787178cd3..1da199714 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -676,8 +676,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint and restore container with root file-system changes using --ignore-rootfs during restore", func() {
// Start the container
- localRunString := getRunString([]string{"--rm", ALPINE, "top"})
- session := podmanTest.Podman(localRunString)
+ // test that restore works without network namespace (https://github.com/containers/podman/issues/14389)
+ session := podmanTest.Podman([]string{"run", "--network=none", "-d", "--rm", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index 4e6dcb8af..0d24a7e17 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -102,12 +102,12 @@ var _ = Describe("Podman logs", func() {
It("tail 99 lines: "+log, func() {
skipIfJournaldInContainer()
- logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
+ name := "test1"
+ logc := podmanTest.Podman([]string{"run", "--name", name, "--log-driver", log, ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
- cid := logc.OutputToString()
- results := podmanTest.Podman([]string{"logs", "--tail", "99", cid})
+ results := podmanTest.Podman([]string{"logs", "--tail", "99", name})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(3))
@@ -116,11 +116,17 @@ var _ = Describe("Podman logs", func() {
It("tail 800 lines: "+log, func() {
skipIfJournaldInContainer()
+ // this uses -d so that we do not have 1000 unnecessary lines printed in every test log
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
+ // make sure we wait for the container to finish writing its output
+ wait := podmanTest.Podman([]string{"wait", cid})
+ wait.WaitWithDefaultTimeout()
+ Expect(wait).To(Exit(0))
+
results := podmanTest.Podman([]string{"logs", "--tail", "800", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go
index 0bf5acbf1..499283cab 100644
--- a/test/e2e/volume_create_test.go
+++ b/test/e2e/volume_create_test.go
@@ -110,15 +110,24 @@ var _ = Describe("Podman volume create", func() {
Expect(session.OutputToString()).To(ContainSubstring("hello"))
})
- It("podman import volume should fail", func() {
+ It("podman import/export volume should fail", func() {
// try import on volume or source which does not exists
- if podmanTest.RemoteTest {
- Skip("Volume export check does not work with a remote client")
- }
+ SkipIfRemote("Volume export check does not work with a remote client")
session := podmanTest.Podman([]string{"volume", "import", "notfound", "notfound.tar"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring("open notfound.tar: no such file or directory"))
+
+ session = podmanTest.Podman([]string{"volume", "import", "notfound", "-"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring("no such volume notfound"))
+
+ session = podmanTest.Podman([]string{"volume", "export", "notfound"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring("no such volume notfound"))
})
It("podman create volume with bad volume option", func() {
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 283c3aea9..241831257 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -855,4 +855,15 @@ EOF
run_podman rmi $test_image
}
+@test "podman create --security-opt" {
+ run_podman create --security-opt no-new-privileges=true $IMAGE
+ run_podman rm $output
+ run_podman create --security-opt no-new-privileges:true $IMAGE
+ run_podman rm $output
+ run_podman create --security-opt no-new-privileges=false $IMAGE
+ run_podman rm $output
+ run_podman create --security-opt no-new-privileges $IMAGE
+ run_podman rm $output
+}
+
# vim: filetype=sh
diff --git a/vendor/gopkg.in/yaml.v3/decode.go b/vendor/gopkg.in/yaml.v3/decode.go
index df36e3a30..0173b6982 100644
--- a/vendor/gopkg.in/yaml.v3/decode.go
+++ b/vendor/gopkg.in/yaml.v3/decode.go
@@ -100,7 +100,10 @@ func (p *parser) peek() yaml_event_type_t {
if p.event.typ != yaml_NO_EVENT {
return p.event.typ
}
- if !yaml_parser_parse(&p.parser, &p.event) {
+ // It's curious choice from the underlying API to generally return a
+ // positive result on success, but on this case return true in an error
+ // scenario. This was the source of bugs in the past (issue #666).
+ if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR {
p.fail()
}
return p.event.typ
@@ -320,6 +323,8 @@ type decoder struct {
decodeCount int
aliasCount int
aliasDepth int
+
+ mergedFields map[interface{}]bool
}
var (
@@ -808,6 +813,11 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
}
}
+ mergedFields := d.mergedFields
+ d.mergedFields = nil
+
+ var mergeNode *Node
+
mapIsNew := false
if out.IsNil() {
out.Set(reflect.MakeMap(outt))
@@ -815,11 +825,18 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
}
for i := 0; i < l; i += 2 {
if isMerge(n.Content[i]) {
- d.merge(n.Content[i+1], out)
+ mergeNode = n.Content[i+1]
continue
}
k := reflect.New(kt).Elem()
if d.unmarshal(n.Content[i], k) {
+ if mergedFields != nil {
+ ki := k.Interface()
+ if mergedFields[ki] {
+ continue
+ }
+ mergedFields[ki] = true
+ }
kkind := k.Kind()
if kkind == reflect.Interface {
kkind = k.Elem().Kind()
@@ -833,6 +850,12 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
}
}
}
+
+ d.mergedFields = mergedFields
+ if mergeNode != nil {
+ d.merge(n, mergeNode, out)
+ }
+
d.stringMapType = stringMapType
d.generalMapType = generalMapType
return true
@@ -844,7 +867,8 @@ func isStringMap(n *Node) bool {
}
l := len(n.Content)
for i := 0; i < l; i += 2 {
- if n.Content[i].ShortTag() != strTag {
+ shortTag := n.Content[i].ShortTag()
+ if shortTag != strTag && shortTag != mergeTag {
return false
}
}
@@ -861,7 +885,6 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
var elemType reflect.Type
if sinfo.InlineMap != -1 {
inlineMap = out.Field(sinfo.InlineMap)
- inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
elemType = inlineMap.Type().Elem()
}
@@ -870,6 +893,9 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
d.prepare(n, field)
}
+ mergedFields := d.mergedFields
+ d.mergedFields = nil
+ var mergeNode *Node
var doneFields []bool
if d.uniqueKeys {
doneFields = make([]bool, len(sinfo.FieldsList))
@@ -879,13 +905,20 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
for i := 0; i < l; i += 2 {
ni := n.Content[i]
if isMerge(ni) {
- d.merge(n.Content[i+1], out)
+ mergeNode = n.Content[i+1]
continue
}
if !d.unmarshal(ni, name) {
continue
}
- if info, ok := sinfo.FieldsMap[name.String()]; ok {
+ sname := name.String()
+ if mergedFields != nil {
+ if mergedFields[sname] {
+ continue
+ }
+ mergedFields[sname] = true
+ }
+ if info, ok := sinfo.FieldsMap[sname]; ok {
if d.uniqueKeys {
if doneFields[info.Id] {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
@@ -911,6 +944,11 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
}
}
+
+ d.mergedFields = mergedFields
+ if mergeNode != nil {
+ d.merge(n, mergeNode, out)
+ }
return true
}
@@ -918,19 +956,29 @@ func failWantMap() {
failf("map merge requires map or sequence of maps as the value")
}
-func (d *decoder) merge(n *Node, out reflect.Value) {
- switch n.Kind {
+func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) {
+ mergedFields := d.mergedFields
+ if mergedFields == nil {
+ d.mergedFields = make(map[interface{}]bool)
+ for i := 0; i < len(parent.Content); i += 2 {
+ k := reflect.New(ifaceType).Elem()
+ if d.unmarshal(parent.Content[i], k) {
+ d.mergedFields[k.Interface()] = true
+ }
+ }
+ }
+
+ switch merge.Kind {
case MappingNode:
- d.unmarshal(n, out)
+ d.unmarshal(merge, out)
case AliasNode:
- if n.Alias != nil && n.Alias.Kind != MappingNode {
+ if merge.Alias != nil && merge.Alias.Kind != MappingNode {
failWantMap()
}
- d.unmarshal(n, out)
+ d.unmarshal(merge, out)
case SequenceNode:
- // Step backwards as earlier nodes take precedence.
- for i := len(n.Content) - 1; i >= 0; i-- {
- ni := n.Content[i]
+ for i := 0; i < len(merge.Content); i++ {
+ ni := merge.Content[i]
if ni.Kind == AliasNode {
if ni.Alias != nil && ni.Alias.Kind != MappingNode {
failWantMap()
@@ -943,6 +991,8 @@ func (d *decoder) merge(n *Node, out reflect.Value) {
default:
failWantMap()
}
+
+ d.mergedFields = mergedFields
}
func isMerge(n *Node) bool {
diff --git a/vendor/gopkg.in/yaml.v3/parserc.go b/vendor/gopkg.in/yaml.v3/parserc.go
index ac66fccc0..268558a0d 100644
--- a/vendor/gopkg.in/yaml.v3/parserc.go
+++ b/vendor/gopkg.in/yaml.v3/parserc.go
@@ -687,6 +687,9 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i
func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
+ if token == nil {
+ return false
+ }
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
@@ -786,7 +789,7 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
}
token := peek_token(parser)
- if token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
+ if token == nil || token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN {
return
}
@@ -813,6 +816,9 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) {
func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
+ if token == nil {
+ return false
+ }
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
@@ -922,6 +928,9 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev
func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool {
if first {
token := peek_token(parser)
+ if token == nil {
+ return false
+ }
parser.marks = append(parser.marks, token.start_mark)
skip_token(parser)
}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index e28d91bde..9bd500ee8 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -864,7 +864,8 @@ gopkg.in/tomb.v1
# gopkg.in/yaml.v2 v2.4.0
## explicit
gopkg.in/yaml.v2
-# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
+# gopkg.in/yaml.v3 v3.0.1
+## explicit
gopkg.in/yaml.v3
# sigs.k8s.io/yaml v1.3.0
sigs.k8s.io/yaml