mirror of
https://github.com/containers/podman.git
synced 2025-12-02 11:08:36 +08:00
migrate Podman to containers/common/libimage
Migrate the Podman code base over to `common/libimage` which replaces `libpod/image` and a lot of glue code entirely. Note that I tried to leave bread crumbs for changed tests. Miscellaneous changes: * Some errors yield different messages which required to alter some tests. * I fixed some pre-existing issues in the code. Others were marked as `//TODO`s to prevent the PR from exploding. * The `NamesHistory` of an image is returned as is from the storage. Previously, we did some filtering which I think is undesirable. Instead we should return the data as stored in the storage. * Touched handlers use the ABI interfaces where possible. * Local image resolution: previously Podman would match "foo" on "myfoo". This behaviour has been changed and Podman will now only match on repository boundaries such that "foo" would match "my/foo" but not "myfoo". I consider the old behaviour to be a bug, at the very least an exotic corner case. * Futhermore, "foo:none" does *not* resolve to a local image "foo" without tag anymore. It's a hill I am (almost) willing to die on. * `image prune` prints the IDs of pruned images. Previously, in some cases, the names were printed instead. The API clearly states ID, so we should stick to it. * Compat endpoint image removal with _force_ deletes the entire not only the specified tag. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
239
vendor/github.com/containers/buildah/run_linux.go
generated
vendored
239
vendor/github.com/containers/buildah/run_linux.go
generated
vendored
@@ -246,10 +246,17 @@ rootless=%d
|
||||
bindFiles["/run/.containerenv"] = containerenvPath
|
||||
}
|
||||
|
||||
err = b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, b.CommonBuildOpts.Volumes, b.CommonBuildOpts.ShmSize, namespaceOptions)
|
||||
runMountTargets, err := b.setupMounts(mountPoint, spec, path, options.Mounts, bindFiles, volumes, b.CommonBuildOpts.Volumes, b.CommonBuildOpts.ShmSize, namespaceOptions, options.Secrets, options.RunMounts)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error resolving mountpoints for container %q", b.ContainerID)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := cleanupRunMounts(runMountTargets, mountPoint); err != nil {
|
||||
logrus.Errorf("unabe to cleanup run mounts %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
defer b.cleanupTempVolumes()
|
||||
|
||||
if options.CNIConfigDir == "" {
|
||||
@@ -341,16 +348,16 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
|
||||
// Add temporary copies of the contents of volume locations at the
|
||||
// volume locations, unless we already have something there.
|
||||
for _, volume := range builtinVolumes {
|
||||
subdir := digest.Canonical.FromString(volume).Hex()
|
||||
volumePath := filepath.Join(containerDir, "buildah-volumes", subdir)
|
||||
srcPath := filepath.Join(mountPoint, volume)
|
||||
volumePath := filepath.Join(containerDir, "buildah-volumes", digest.Canonical.FromString(volume).Hex())
|
||||
initializeVolume := false
|
||||
// If we need to, initialize the volume path's initial contents.
|
||||
// If we need to, create the directory that we'll use to hold
|
||||
// the volume contents. If we do need to create it, then we'll
|
||||
// need to populate it, too, so make a note of that.
|
||||
if _, err := os.Stat(volumePath); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Debugf("setting up built-in volume at %q", volumePath)
|
||||
logrus.Debugf("setting up built-in volume path at %q for %q", volumePath, volume)
|
||||
if err = os.MkdirAll(volumePath, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -359,28 +366,25 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
|
||||
}
|
||||
initializeVolume = true
|
||||
}
|
||||
// Check if srcPath is a symlink
|
||||
stat, err := os.Lstat(srcPath)
|
||||
// If srcPath is a symlink, follow the link and ensure the destination exists
|
||||
if err == nil && stat != nil && (stat.Mode()&os.ModeSymlink != 0) {
|
||||
srcPath, err = copier.Eval(mountPoint, volume, copier.EvalOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "evaluating symlink %q", srcPath)
|
||||
}
|
||||
// Stat the destination of the evaluated symlink
|
||||
stat, err = os.Stat(srcPath)
|
||||
}
|
||||
// Make sure the volume exists in the rootfs and read its attributes.
|
||||
createDirPerms := os.FileMode(0755)
|
||||
err := copier.Mkdir(mountPoint, filepath.Join(mountPoint, volume), copier.MkdirOptions{
|
||||
ChownNew: &hostOwner,
|
||||
ChmodNew: &createDirPerms,
|
||||
})
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
if err = idtools.MkdirAllAndChownNew(srcPath, 0755, hostOwner); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if stat, err = os.Stat(srcPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errors.Wrapf(err, "ensuring volume path %q", filepath.Join(mountPoint, volume))
|
||||
}
|
||||
srcPath, err := copier.Eval(mountPoint, filepath.Join(mountPoint, volume), copier.EvalOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "evaluating path %q", srcPath)
|
||||
}
|
||||
stat, err := os.Stat(srcPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
// If we need to populate the mounted volume's contents with
|
||||
// content from the rootfs, set it up now.
|
||||
if initializeVolume {
|
||||
if err = os.Chmod(volumePath, stat.Mode().Perm()); err != nil {
|
||||
return nil, err
|
||||
@@ -388,6 +392,7 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
|
||||
if err = os.Chown(volumePath, int(stat.Sys().(*syscall.Stat_t).Uid), int(stat.Sys().(*syscall.Stat_t).Gid)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Debugf("populating directory %q for volume %q using contents of %q", volumePath, volume, srcPath)
|
||||
if err = extractWithTar(mountPoint, srcPath, volumePath); err != nil && !os.IsNotExist(errors.Cause(err)) {
|
||||
return nil, errors.Wrapf(err, "error populating directory %q for volume %q using contents of %q", volumePath, volume, srcPath)
|
||||
}
|
||||
@@ -403,7 +408,7 @@ func runSetupBuiltinVolumes(mountLabel, mountPoint, containerDir string, builtin
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath string, optionMounts []specs.Mount, bindFiles map[string]string, builtinVolumes, volumeMounts []string, shmSize string, namespaceOptions define.NamespaceOptions) error {
|
||||
func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath string, optionMounts []specs.Mount, bindFiles map[string]string, builtinVolumes, volumeMounts []string, shmSize string, namespaceOptions define.NamespaceOptions, secrets map[string]string, runFileMounts []string) (runMountTargets []string, err error) {
|
||||
// Start building a new list of mounts.
|
||||
var mounts []specs.Mount
|
||||
haveMount := func(destination string) bool {
|
||||
@@ -497,39 +502,45 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st
|
||||
// After this point we need to know the per-container persistent storage directory.
|
||||
cdir, err := b.store.ContainerDirectory(b.ContainerID)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error determining work directory for container %q", b.ContainerID)
|
||||
return nil, errors.Wrapf(err, "error determining work directory for container %q", b.ContainerID)
|
||||
}
|
||||
|
||||
// Figure out which UID and GID to tell the subscriptions package to use
|
||||
// for files that it creates.
|
||||
rootUID, rootGID, err := util.GetHostRootIDs(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the list of subscriptions mounts.
|
||||
secretMounts := subscriptions.MountsWithUIDGID(b.MountLabel, cdir, b.DefaultMountsFilePath, mountPoint, int(rootUID), int(rootGID), unshare.IsRootless(), false)
|
||||
subscriptionMounts := subscriptions.MountsWithUIDGID(b.MountLabel, cdir, b.DefaultMountsFilePath, mountPoint, int(rootUID), int(rootGID), unshare.IsRootless(), false)
|
||||
|
||||
// Get the list of mounts that are just for this Run() call.
|
||||
runMounts, runTargets, err := runSetupRunMounts(runFileMounts, secrets, b.MountLabel, cdir, spec.Linux.UIDMappings, spec.Linux.GIDMappings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add temporary copies of the contents of volume locations at the
|
||||
// volume locations, unless we already have something there.
|
||||
builtins, err := runSetupBuiltinVolumes(b.MountLabel, mountPoint, cdir, builtinVolumes, int(rootUID), int(rootGID))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get host UID and GID of the container process.
|
||||
processUID, processGID, err := util.GetHostIDs(spec.Linux.UIDMappings, spec.Linux.GIDMappings, spec.Process.User.UID, spec.Process.User.GID)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the list of explicitly-specified volume mounts.
|
||||
volumes, err := b.runSetupVolumeMounts(spec.Linux.MountLabel, volumeMounts, optionMounts, int(rootUID), int(rootGID), int(processUID), int(processGID))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allMounts := util.SortMounts(append(append(append(append(append(volumes, builtins...), secretMounts...), bindFileMounts...), specMounts...), sysfsMount...))
|
||||
allMounts := util.SortMounts(append(append(append(append(append(append(volumes, builtins...), runMounts...), subscriptionMounts...), bindFileMounts...), specMounts...), sysfsMount...))
|
||||
// Add them all, in the preferred order, except where they conflict with something that was previously added.
|
||||
for _, mount := range allMounts {
|
||||
if haveMount(mount.Destination) {
|
||||
@@ -542,7 +553,7 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, bundlePath st
|
||||
|
||||
// Set the list in the spec.
|
||||
spec.Mounts = mounts
|
||||
return nil
|
||||
return runTargets, nil
|
||||
}
|
||||
|
||||
// addNetworkConfig copies files from host and sets them up to bind mount into container
|
||||
@@ -818,7 +829,7 @@ func runUsingRuntime(isolation define.Isolation, options RunOptions, configureNe
|
||||
logrus.Debugf("Running %q", create.Args)
|
||||
err = create.Run()
|
||||
if err != nil {
|
||||
return 1, errors.Wrapf(err, "error creating container for %v: %s", pargs, runCollectOutput(errorFds, closeBeforeReadingErrorFds))
|
||||
return 1, errors.Wrapf(err, "error from %s creating container for %v: %s", runtime, pargs, runCollectOutput(errorFds, closeBeforeReadingErrorFds))
|
||||
}
|
||||
defer func() {
|
||||
err2 := del.Run()
|
||||
@@ -826,7 +837,7 @@ func runUsingRuntime(isolation define.Isolation, options RunOptions, configureNe
|
||||
if err == nil {
|
||||
err = errors.Wrapf(err2, "error deleting container")
|
||||
} else {
|
||||
logrus.Infof("error deleting container: %v", err2)
|
||||
logrus.Infof("error from %s deleting container: %v", runtime, err2)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -879,13 +890,13 @@ func runUsingRuntime(isolation define.Isolation, options RunOptions, configureNe
|
||||
logrus.Debugf("Running %q", start.Args)
|
||||
err = start.Run()
|
||||
if err != nil {
|
||||
return 1, errors.Wrapf(err, "error starting container")
|
||||
return 1, errors.Wrapf(err, "error from %s starting container", runtime)
|
||||
}
|
||||
stopped := false
|
||||
defer func() {
|
||||
if !stopped {
|
||||
if err2 := kill.Run(); err2 != nil {
|
||||
logrus.Infof("error stopping container: %v", err2)
|
||||
logrus.Infof("error from %s stopping container: %v", runtime, err2)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -900,10 +911,10 @@ func runUsingRuntime(isolation define.Isolation, options RunOptions, configureNe
|
||||
stat.Stderr = os.Stderr
|
||||
stateOutput, err := stat.Output()
|
||||
if err != nil {
|
||||
return 1, errors.Wrapf(err, "error reading container state (got output: %q)", string(stateOutput))
|
||||
return 1, errors.Wrapf(err, "error reading container state from %s (got output: %q)", runtime, string(stateOutput))
|
||||
}
|
||||
if err = json.Unmarshal(stateOutput, &state); err != nil {
|
||||
return 1, errors.Wrapf(err, "error parsing container state %q", string(stateOutput))
|
||||
return 1, errors.Wrapf(err, "error parsing container state %q from %s", string(stateOutput), runtime)
|
||||
}
|
||||
switch state.Status {
|
||||
case "running":
|
||||
@@ -2248,3 +2259,149 @@ type runUsingRuntimeSubprocOptions struct {
|
||||
func init() {
|
||||
reexec.Register(runUsingRuntimeCommand, runUsingRuntimeMain)
|
||||
}
|
||||
|
||||
// runSetupRunMounts sets up mounts that exist only in this RUN, not in subsequent runs
|
||||
func runSetupRunMounts(mounts []string, secrets map[string]string, mountlabel string, containerWorkingDir string, uidmap []spec.LinuxIDMapping, gidmap []spec.LinuxIDMapping) ([]spec.Mount, []string, error) {
|
||||
mountTargets := make([]string, 0, 10)
|
||||
finalMounts := make([]specs.Mount, 0, len(mounts))
|
||||
for _, mount := range mounts {
|
||||
arr := strings.SplitN(mount, ",", 2)
|
||||
if len(arr) < 2 {
|
||||
return nil, nil, errors.New("invalid mount syntax")
|
||||
}
|
||||
|
||||
kv := strings.Split(arr[0], "=")
|
||||
if len(kv) != 2 || kv[0] != "type" {
|
||||
return nil, nil, errors.New("invalid mount type")
|
||||
}
|
||||
|
||||
tokens := strings.Split(arr[1], ",")
|
||||
// For now, we only support type secret.
|
||||
switch kv[1] {
|
||||
case "secret":
|
||||
mount, err := getSecretMount(tokens, secrets, mountlabel, containerWorkingDir, uidmap, gidmap)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if mount != nil {
|
||||
finalMounts = append(finalMounts, *mount)
|
||||
mountTargets = append(mountTargets, mount.Destination)
|
||||
|
||||
}
|
||||
default:
|
||||
return nil, nil, errors.Errorf("invalid filesystem type %q", kv[1])
|
||||
}
|
||||
}
|
||||
return finalMounts, mountTargets, nil
|
||||
}
|
||||
|
||||
func getSecretMount(tokens []string, secrets map[string]string, mountlabel string, containerWorkingDir string, uidmap []spec.LinuxIDMapping, gidmap []spec.LinuxIDMapping) (*spec.Mount, error) {
|
||||
errInvalidSyntax := errors.New("secret should have syntax id=id[,target=path,required=bool,mode=uint,uid=uint,gid=uint")
|
||||
|
||||
var err error
|
||||
var id, target string
|
||||
var required bool
|
||||
var uid, gid uint32
|
||||
var mode uint32 = 400
|
||||
for _, val := range tokens {
|
||||
kv := strings.SplitN(val, "=", 2)
|
||||
switch kv[0] {
|
||||
case "id":
|
||||
id = kv[1]
|
||||
case "target":
|
||||
target = kv[1]
|
||||
case "required":
|
||||
required, err = strconv.ParseBool(kv[1])
|
||||
if err != nil {
|
||||
return nil, errInvalidSyntax
|
||||
}
|
||||
case "mode":
|
||||
mode64, err := strconv.ParseUint(kv[1], 8, 32)
|
||||
if err != nil {
|
||||
return nil, errInvalidSyntax
|
||||
}
|
||||
mode = uint32(mode64)
|
||||
case "uid":
|
||||
uid64, err := strconv.ParseUint(kv[1], 10, 32)
|
||||
if err != nil {
|
||||
return nil, errInvalidSyntax
|
||||
}
|
||||
uid = uint32(uid64)
|
||||
case "gid":
|
||||
gid64, err := strconv.ParseUint(kv[1], 10, 32)
|
||||
if err != nil {
|
||||
return nil, errInvalidSyntax
|
||||
}
|
||||
gid = uint32(gid64)
|
||||
default:
|
||||
return nil, errInvalidSyntax
|
||||
}
|
||||
}
|
||||
|
||||
if id == "" {
|
||||
return nil, errInvalidSyntax
|
||||
}
|
||||
// Default location for secretis is /run/secrets/id
|
||||
if target == "" {
|
||||
target = "/run/secrets/" + id
|
||||
}
|
||||
|
||||
src, ok := secrets[id]
|
||||
if !ok {
|
||||
if required {
|
||||
return nil, errors.Errorf("secret required but no secret with id %s found", id)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Copy secrets to container working dir, since we need to chmod, chown and relabel it
|
||||
// for the container user and we don't want to mess with the original file
|
||||
ctrFileOnHost := filepath.Join(containerWorkingDir, "secrets", id)
|
||||
_, err = os.Stat(ctrFileOnHost)
|
||||
if os.IsNotExist(err) {
|
||||
data, err := ioutil.ReadFile(src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(ctrFileOnHost), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ioutil.WriteFile(ctrFileOnHost, data, 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := label.Relabel(ctrFileOnHost, mountlabel, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hostUID, hostGID, err := util.GetHostIDs(uidmap, gidmap, uid, gid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.Lchown(ctrFileOnHost, int(hostUID), int(hostGID)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.Chmod(ctrFileOnHost, os.FileMode(mode)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newMount := specs.Mount{
|
||||
Destination: target,
|
||||
Type: "bind",
|
||||
Source: ctrFileOnHost,
|
||||
Options: []string{"bind", "rprivate", "ro"},
|
||||
}
|
||||
return &newMount, nil
|
||||
}
|
||||
|
||||
func cleanupRunMounts(paths []string, mountpoint string) error {
|
||||
opts := copier.RemoveOptions{
|
||||
All: true,
|
||||
}
|
||||
for _, path := range paths {
|
||||
err := copier.Remove(mountpoint, path, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user