mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
Major rework of --volumes-from flag
The flag should be substantially more durable, and no longer relies on the create artifact. This should allow it to properly handle our new named volume implementation. Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
@ -182,6 +182,8 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
|
|||||||
return nil, errors.Wrapf(err, "error retrieving named volume %s for new container", vol.Name)
|
return nil, errors.Wrapf(err, "error retrieving named volume %s for new container", vol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("Creating new volume %s for container", vol.Name)
|
||||||
|
|
||||||
// The volume does not exist, so we need to create it.
|
// The volume does not exist, so we need to create it.
|
||||||
newVol, err := r.newVolume(ctx, WithVolumeName(vol.Name), withSetCtrSpecific(),
|
newVol, err := r.newVolume(ctx, WithVolumeName(vol.Name), withSetCtrSpecific(),
|
||||||
WithVolumeUID(ctr.RootUID()), WithVolumeGID(ctr.RootGID()))
|
WithVolumeUID(ctr.RootUID()), WithVolumeGID(ctr.RootGID()))
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package createconfig
|
package createconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@ -256,6 +255,8 @@ func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, e
|
|||||||
mount.Source = "tmpfs"
|
mount.Source = "tmpfs"
|
||||||
mount.Options = append(mount.Options, "tmpcopyup")
|
mount.Options = append(mount.Options, "tmpcopyup")
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: Move support for this and tmpfs into libpod
|
||||||
|
// Should tmpfs also be handled as named volumes? Wouldn't be hard
|
||||||
// This will cause a new local Volume to be created on your system
|
// This will cause a new local Volume to be created on your system
|
||||||
mount.Source = stringid.GenerateNonCryptoID()
|
mount.Source = stringid.GenerateNonCryptoID()
|
||||||
mount.Options = append(mount.Options, "bind")
|
mount.Options = append(mount.Options, "bind")
|
||||||
@ -269,13 +270,12 @@ func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, e
|
|||||||
// GetVolumesFrom reads the create-config artifact of the container to get volumes from
|
// GetVolumesFrom reads the create-config artifact of the container to get volumes from
|
||||||
// and adds it to c.Volumes of the current container.
|
// and adds it to c.Volumes of the current container.
|
||||||
func (c *CreateConfig) GetVolumesFrom() error {
|
func (c *CreateConfig) GetVolumesFrom() error {
|
||||||
var options string
|
|
||||||
|
|
||||||
if os.Geteuid() != 0 {
|
if os.Geteuid() != 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, vol := range c.VolumesFrom {
|
for _, vol := range c.VolumesFrom {
|
||||||
|
options := ""
|
||||||
splitVol := strings.SplitN(vol, ":", 2)
|
splitVol := strings.SplitN(vol, ":", 2)
|
||||||
if len(splitVol) == 2 {
|
if len(splitVol) == 2 {
|
||||||
options = splitVol[1]
|
options = splitVol[1]
|
||||||
@ -284,41 +284,60 @@ func (c *CreateConfig) GetVolumesFrom() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error looking up container %q", splitVol[0])
|
return errors.Wrapf(err, "error looking up container %q", splitVol[0])
|
||||||
}
|
}
|
||||||
inspect, err := ctr.Inspect(false)
|
|
||||||
if err != nil {
|
logrus.Debugf("Adding volumes from container %s", ctr.ID())
|
||||||
return errors.Wrapf(err, "error inspecting %q", splitVol[0])
|
|
||||||
|
// Look up the container's user volumes. This gets us the
|
||||||
|
// destinations of all mounts the user added to the container.
|
||||||
|
userVolumesArr := ctr.UserVolumes()
|
||||||
|
|
||||||
|
// We're going to need to access them a lot, so convert to a map
|
||||||
|
// to reduce looping.
|
||||||
|
// We'll also use the map to indicate if we missed any volumes along the way.
|
||||||
|
userVolumes := make(map[string]bool)
|
||||||
|
for _, dest := range userVolumesArr {
|
||||||
|
userVolumes[dest] = false
|
||||||
}
|
}
|
||||||
var createArtifact CreateConfig
|
|
||||||
artifact, err := ctr.GetArtifact("create-config")
|
// Now we get the container's spec and loop through its volumes
|
||||||
if err != nil {
|
// and append them in if we can find them.
|
||||||
return errors.Wrapf(err, "error getting create-config artifact for %q", splitVol[0])
|
spec := ctr.Spec()
|
||||||
|
if spec == nil {
|
||||||
|
return errors.Errorf("error retrieving container %s spec", ctr.ID())
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(artifact, &createArtifact); err != nil {
|
for _, mnt := range spec.Mounts {
|
||||||
return err
|
if mnt.Type != "bind" {
|
||||||
}
|
continue
|
||||||
for key := range createArtifact.BuiltinImgVolumes {
|
}
|
||||||
for _, m := range inspect.Mounts {
|
if _, exists := userVolumes[mnt.Destination]; exists {
|
||||||
if m.Destination == key {
|
userVolumes[mnt.Destination] = true
|
||||||
c.LocalVolumes = append(c.LocalVolumes, m)
|
localOptions := options
|
||||||
break
|
if localOptions == "" {
|
||||||
|
localOptions = strings.Join(mnt.Options, ",")
|
||||||
}
|
}
|
||||||
|
c.Volumes = append(c.Volumes, fmt.Sprintf("%s:%s:%s", mnt.Source, mnt.Destination, localOptions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, i := range createArtifact.Volumes {
|
// We're done with the spec mounts. Add named volumes.
|
||||||
// Volumes format is host-dir:ctr-dir[:options], so get the host and ctr dir
|
// Add these unconditionally - none of them are automatically
|
||||||
// and add on the options given by the user to the flag.
|
// part of the container, as some spec mounts are.
|
||||||
spliti := strings.SplitN(i, ":", 3)
|
namedVolumes := ctr.NamedVolumes()
|
||||||
// Throw error if mounting volume from container with Z option (private label)
|
for _, namedVol := range namedVolumes {
|
||||||
// Override this by adding 'z' to options.
|
if _, exists := userVolumes[namedVol.Dest]; exists {
|
||||||
if len(spliti) > 2 && strings.Contains(spliti[2], "Z") && !strings.Contains(options, "z") {
|
userVolumes[namedVol.Dest] = true
|
||||||
return errors.Errorf("volume mounted with private option 'Z' in %q. Use option 'z' to mount in current container", ctr.ID())
|
|
||||||
}
|
}
|
||||||
if options == "" {
|
localOptions := options
|
||||||
// Mount the volumes with the default options
|
if localOptions == "" {
|
||||||
c.Volumes = append(c.Volumes, createArtifact.Volumes...)
|
localOptions = strings.Join(namedVol.Options, ",")
|
||||||
} else {
|
}
|
||||||
c.Volumes = append(c.Volumes, spliti[0]+":"+spliti[1]+":"+options)
|
c.Volumes = append(c.Volumes, fmt.Sprintf("%s:%s:%s", namedVol.Name, namedVol.Dest, localOptions))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we missed any volumes
|
||||||
|
for volDest, found := range userVolumes {
|
||||||
|
if !found {
|
||||||
|
logrus.Warnf("Unable to match volume %s from container %s for volumes-from", volDest, ctr.ID())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -418,7 +437,13 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime, pod *l
|
|||||||
// others, if they are included
|
// others, if they are included
|
||||||
volumes := make([]string, 0, len(c.Volumes))
|
volumes := make([]string, 0, len(c.Volumes))
|
||||||
for _, vol := range c.Volumes {
|
for _, vol := range c.Volumes {
|
||||||
volumes = append(volumes, strings.SplitN(vol, ":", 2)[0])
|
// We always want the volume destination
|
||||||
|
splitVol := strings.SplitN(vol, ":", 3)
|
||||||
|
if len(splitVol) > 1 {
|
||||||
|
volumes = append(volumes, splitVol[1])
|
||||||
|
} else {
|
||||||
|
volumes = append(volumes, splitVol[0])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
options = append(options, libpod.WithUserVolumes(volumes))
|
options = append(options, libpod.WithUserVolumes(volumes))
|
||||||
|
@ -611,7 +611,6 @@ USER mail`
|
|||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
Expect(session.OutputToString()).To(ContainSubstring("data"))
|
Expect(session.OutputToString()).To(ContainSubstring("data"))
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman run --volumes flag with multiple volumes", func() {
|
It("podman run --volumes flag with multiple volumes", func() {
|
||||||
|
Reference in New Issue
Block a user