summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml16
-rw-r--r--.github/workflows/check_cirrus_cron.yml3
-rw-r--r--.github/workflows/issue-labeler.yml6
-rw-r--r--.github/workflows/pr-title.yml5
-rwxr-xr-xcontrib/cirrus/cirrus_yaml_test.py3
-rw-r--r--libpod/container_config.go23
-rw-r--r--libpod/container_inspect.go6
-rw-r--r--libpod/container_internal.go4
-rw-r--r--libpod/kube.go2
-rw-r--r--libpod/pod_api.go4
-rw-r--r--pkg/bindings/images/build.go9
-rw-r--r--pkg/domain/infra/abi/containers.go2
-rw-r--r--pkg/machine/wsl/machine.go30
-rw-r--r--pkg/specgen/container_validate.go4
-rw-r--r--pkg/specgen/generate/container.go43
-rw-r--r--pkg/specgen/generate/container_create.go33
-rw-r--r--pkg/specgen/generate/oci.go4
-rw-r--r--pkg/specgenutil/volumes.go12
-rw-r--r--test/e2e/build_test.go66
-rw-r--r--test/e2e/common_test.go15
-rw-r--r--test/e2e/libpod_suite_remote_test.go73
-rw-r--r--test/e2e/pod_create_test.go4
-rw-r--r--test/e2e/run_test.go5
-rw-r--r--test/e2e/run_volume_test.go7
-rw-r--r--test/utils/utils.go4
25 files changed, 242 insertions, 141 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index beb871c23..772843dd7 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -38,7 +38,7 @@ env:
UBUNTU_NAME: "ubuntu-2110"
# Google-cloud VM Images
- IMAGE_SUFFIX: "c6261670816251904"
+ IMAGE_SUFFIX: "c6464310661611520"
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${IMAGE_SUFFIX}"
@@ -741,7 +741,7 @@ upgrade_test_task:
always: *logs_artifacts
-image_build_task:
+image_build_task: &image-build
name: "Build multi-arch $CTXDIR"
alias: image_build
# Some of these container images take > 1h to build, limit
@@ -774,6 +774,18 @@ image_build_task:
- main.sh $CIRRUS_REPO_CLONE_URL $CTXDIR
+test_image_build_task:
+ <<: *image-build
+ # Allow this to run inside a PR
+ only_if: $CI == $CI
+ # This takes a LONG time, only run when requested. N/B: Any task
+ # made to depend on this one will block FOREVER unless triggered.
+ trigger_type: manual
+ # Overwrite all 'env', don't push anything, just do the build.
+ env:
+ DRYRUN: 1
+
+
# This task is critical. It updates the "last-used by" timestamp stored
# in metadata for all VM images. This mechanism functions in tandem with
# an out-of-band pruning operation to remove disused VM images.
diff --git a/.github/workflows/check_cirrus_cron.yml b/.github/workflows/check_cirrus_cron.yml
index 5704b0b9d..bca77e4d9 100644
--- a/.github/workflows/check_cirrus_cron.yml
+++ b/.github/workflows/check_cirrus_cron.yml
@@ -25,6 +25,9 @@ env:
# (must be in $GITHUB_WORKSPACE/artifacts/)
NAME_ID_FILEPATH: './artifacts/name_id.txt'
+permissions:
+ contents: read
+
jobs:
cron_failures:
runs-on: ubuntu-latest
diff --git a/.github/workflows/issue-labeler.yml b/.github/workflows/issue-labeler.yml
index 18fff7f7c..afebc7fca 100644
--- a/.github/workflows/issue-labeler.yml
+++ b/.github/workflows/issue-labeler.yml
@@ -3,8 +3,14 @@ on:
issues:
types: [opened, edited]
+permissions:
+ contents: read
+
jobs:
triage:
+ permissions:
+ contents: read # for github/issue-labeler to get repo contents
+ issues: write # for github/issue-labeler to create or remove labels
runs-on: ubuntu-latest
steps:
- uses: github/issue-labeler@3ae0e4623c1fda729347ae0d8f1c2e52302ef4c6 # v2.0
diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml
index 2b57392ce..66599a86d 100644
--- a/.github/workflows/pr-title.yml
+++ b/.github/workflows/pr-title.yml
@@ -7,8 +7,13 @@ on:
branches:
- "!master" # causes errors; reason unknown
+permissions:
+ contents: read
+
jobs:
update_pr:
+ permissions:
+ pull-requests: write # for tzkhan/pr-update-action to update PRs
runs-on: ubuntu-latest
steps:
- uses: tzkhan/pr-update-action@bbd4c9395df8a9c4ef075b8b7fe29f2ca76cdca9 # v2
diff --git a/contrib/cirrus/cirrus_yaml_test.py b/contrib/cirrus/cirrus_yaml_test.py
index b424c3ee6..a7fff8d3f 100755
--- a/contrib/cirrus/cirrus_yaml_test.py
+++ b/contrib/cirrus/cirrus_yaml_test.py
@@ -26,7 +26,8 @@ class TestCaseBase(unittest.TestCase):
class TestDependsOn(TestCaseBase):
ALL_TASK_NAMES = None
- SUCCESS_DEPS_EXCLUDE = set(['success', 'artifacts', 'release', 'release_test'])
+ SUCCESS_DEPS_EXCLUDE = set(['success', 'artifacts',
+ 'test_image_build', 'release', 'release_test'])
def setUp(self):
super().setUp()
diff --git a/libpod/container_config.go b/libpod/container_config.go
index 0d9cd5723..ea644764c 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/common/pkg/secrets"
"github.com/containers/image/v5/manifest"
"github.com/containers/podman/v4/pkg/namespaces"
+ "github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/storage"
spec "github.com/opencontainers/runtime-spec/specs-go"
)
@@ -405,13 +406,19 @@ type ContainerMiscConfig struct {
InitContainerType string `json:"init_container_type,omitempty"`
}
+// InfraInherit contains the compatible options inheritable from the infra container
type InfraInherit struct {
- InfraSecurity ContainerSecurityConfig
- InfraLabels []string `json:"labelopts,omitempty"`
- InfraVolumes []*ContainerNamedVolume `json:"namedVolumes,omitempty"`
- InfraOverlay []*ContainerOverlayVolume `json:"overlayVolumes,omitempty"`
- InfraImageVolumes []*ContainerImageVolume `json:"ctrImageVolumes,omitempty"`
- InfraUserVolumes []string `json:"userVolumes,omitempty"`
- InfraResources *spec.LinuxResources `json:"resources,omitempty"`
- InfraDevices []spec.LinuxDevice `json:"device_host_src,omitempty"`
+ ApparmorProfile string `json:"apparmor_profile,omitempty"`
+ CapAdd []string `json:"cap_add,omitempty"`
+ CapDrop []string `json:"cap_drop,omitempty"`
+ HostDeviceList []spec.LinuxDevice `json:"host_device_list,omitempty"`
+ ImageVolumes []*specgen.ImageVolume `json:"image_volumes,omitempty"`
+ InfraResources *spec.LinuxResources `json:"resource_limits,omitempty"`
+ Mounts []spec.Mount `json:"mounts,omitempty"`
+ NoNewPrivileges bool `json:"no_new_privileges,omitempty"`
+ OverlayVolumes []*specgen.OverlayVolume `json:"overlay_volumes,omitempty"`
+ SeccompPolicy string `json:"seccomp_policy,omitempty"`
+ SeccompProfilePath string `json:"seccomp_profile_path,omitempty"`
+ SelinuxOpts []string `json:"selinux_opts,omitempty"`
+ Volumes []*specgen.NamedVolume `json:"volumes,omitempty"`
}
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 5fb32bd90..f2a2c2d16 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -103,8 +103,8 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
}
}
- namedVolumes, mounts := c.sortUserVolumes(ctrSpec)
- inspectMounts, err := c.GetInspectMounts(namedVolumes, c.config.ImageVolumes, mounts)
+ namedVolumes, mounts := c.SortUserVolumes(ctrSpec)
+ inspectMounts, err := c.GetMounts(namedVolumes, c.config.ImageVolumes, mounts)
if err != nil {
return nil, err
}
@@ -222,7 +222,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *define.Driver
// Get inspect-formatted mounts list.
// Only includes user-specified mounts. Only includes bind mounts and named
// volumes, not tmpfs volumes.
-func (c *Container) GetInspectMounts(namedVolumes []*ContainerNamedVolume, imageVolumes []*ContainerImageVolume, mounts []spec.Mount) ([]define.InspectMount, error) {
+func (c *Container) GetMounts(namedVolumes []*ContainerNamedVolume, imageVolumes []*ContainerImageVolume, mounts []spec.Mount) ([]define.InspectMount, error) {
inspectMounts := []define.InspectMount{}
// No mounts, return early
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 0db59f2fe..f1f467879 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -2235,9 +2235,9 @@ func (c *Container) prepareCheckpointExport() error {
return nil
}
-// sortUserVolumes sorts the volumes specified for a container
+// SortUserVolumes sorts the volumes specified for a container
// between named and normal volumes
-func (c *Container) sortUserVolumes(ctrSpec *spec.Spec) ([]*ContainerNamedVolume, []spec.Mount) {
+func (c *Container) SortUserVolumes(ctrSpec *spec.Spec) ([]*ContainerNamedVolume, []spec.Mount) {
namedUserVolumes := []*ContainerNamedVolume{}
userMounts := []spec.Mount{}
diff --git a/libpod/kube.go b/libpod/kube.go
index a193df2cb..22fbb5f9f 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -773,7 +773,7 @@ func libpodEnvVarsToKubeEnvVars(envs []string, imageEnvs []string) ([]v1.EnvVar,
// libpodMountsToKubeVolumeMounts converts the containers mounts to a struct kube understands
func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, map[string]string, error) {
- namedVolumes, mounts := c.sortUserVolumes(c.config.Spec)
+ namedVolumes, mounts := c.SortUserVolumes(c.config.Spec)
vms := make([]v1.VolumeMount, 0, len(mounts))
vos := make([]v1.Volume, 0, len(mounts))
annotations := make(map[string]string)
diff --git a/libpod/pod_api.go b/libpod/pod_api.go
index be726d8d1..48049798b 100644
--- a/libpod/pod_api.go
+++ b/libpod/pod_api.go
@@ -602,8 +602,8 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
infraConfig.CPUSetCPUs = p.ResourceLim().CPU.Cpus
infraConfig.PidNS = p.PidMode()
infraConfig.UserNS = p.UserNSMode()
- namedVolumes, mounts := infra.sortUserVolumes(infra.config.Spec)
- inspectMounts, err = infra.GetInspectMounts(namedVolumes, infra.config.ImageVolumes, mounts)
+ namedVolumes, mounts := infra.SortUserVolumes(infra.config.Spec)
+ inspectMounts, err = infra.GetMounts(namedVolumes, infra.config.ImageVolumes, mounts)
infraSecurity = infra.GetSecurityOptions()
if err != nil {
return nil, err
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index f6739b7ca..ab562377f 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -367,20 +367,20 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
return nil, err
}
- // Check if Containerfile is in the context directory, if so truncate the contextdirectory off path
+ // Check if Containerfile is in the context directory, if so truncate the context directory off path
// Do NOT add to tarfile
if strings.HasPrefix(containerfile, contextDir+string(filepath.Separator)) {
containerfile = strings.TrimPrefix(containerfile, contextDir+string(filepath.Separator))
dontexcludes = append(dontexcludes, "!"+containerfile)
} else {
- // If Containerfile does not exists assume it is in context directory, do Not add to tarfile
+ // If Containerfile does not exist, assume it is in context directory and do Not add to tarfile
if _, err := os.Lstat(containerfile); err != nil {
if !os.IsNotExist(err) {
return nil, err
}
containerfile = c
} else {
- // If Containerfile does exists but is not in context directory add it to the tarfile
+ // If Containerfile does exist and not in the context directory, add it to the tarfile
tarContent = append(tarContent, containerfile)
}
}
@@ -586,6 +586,9 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) {
return errors.Wrapf(err, "error checking if %q is excluded", name)
}
if excluded {
+ // Note: filepath.SkipDir is not possible to use given .dockerignore semantics.
+ // An exception to exclusions may include an excluded directory, therefore we
+ // are required to visit all files. :(
return nil
}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index f45bdeba5..a2933a267 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1491,7 +1491,7 @@ func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string,
func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts entities.ContainerCloneOptions) (*entities.ContainerCreateReport, error) {
spec := specgen.NewSpecGenerator(ctrCloneOpts.Image, ctrCloneOpts.CreateOpts.RootFS)
var c *libpod.Container
- c, err := generate.ConfigToSpec(ic.Libpod, spec, ctrCloneOpts.ID)
+ c, _, err := generate.ConfigToSpec(ic.Libpod, spec, ctrCloneOpts.ID)
if err != nil {
return nil, err
}
diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go
index 5128fa313..fdda45ca6 100644
--- a/pkg/machine/wsl/machine.go
+++ b/pkg/machine/wsl/machine.go
@@ -145,6 +145,8 @@ http://docs.microsoft.com/en-us/windows/wsl/install\
const (
winSShProxy = "win-sshproxy.exe"
winSshProxyTid = "win-sshproxy.tid"
+ pipePrefix = "npipe:////./pipe/"
+ globalPipe = "docker_engine"
)
type Provider struct{}
@@ -801,16 +803,15 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
}
func launchWinProxy(v *MachineVM) (bool, string, error) {
- globalName := true
- pipeName := "docker_engine"
- if !pipeAvailable(pipeName) {
- pipeName = toDist(v.Name)
- globalName = false
- if !pipeAvailable(pipeName) {
- return globalName, "", errors.Errorf("could not start api proxy since expected pipe is not available: %s", pipeName)
- }
+ machinePipe := toDist(v.Name)
+ if !pipeAvailable(machinePipe) {
+ return false, "", errors.Errorf("could not start api proxy since expected pipe is not available: %s", machinePipe)
+ }
+
+ globalName := false
+ if pipeAvailable(globalPipe) {
+ globalName = true
}
- fullPipeName := "npipe:////./pipe/" + pipeName
exe, err := os.Executable()
if err != nil {
@@ -829,12 +830,19 @@ func launchWinProxy(v *MachineVM) (bool, string, error) {
}
dest := fmt.Sprintf("ssh://root@localhost:%d/run/podman/podman.sock", v.Port)
- cmd := exec.Command(command, v.Name, stateDir, fullPipeName, dest, v.IdentityPath)
+ args := []string{v.Name, stateDir, pipePrefix + machinePipe, dest, v.IdentityPath}
+ waitPipe := machinePipe
+ if globalName {
+ args = append(args, pipePrefix+globalPipe, dest, v.IdentityPath)
+ waitPipe = globalPipe
+ }
+
+ cmd := exec.Command(command, args...)
if err := cmd.Start(); err != nil {
return globalName, "", err
}
- return globalName, fullPipeName, waitPipeExists(pipeName, 30, func() error {
+ return globalName, pipePrefix + waitPipe, waitPipeExists(waitPipe, 30, func() error {
active, exitCode := getProcessState(cmd.Process.Pid)
if !active {
return errors.Errorf("win-sshproxy.exe failed to start, exit code: %d (see windows event logs)", exitCode)
diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go
index e71eafb75..42b70e334 100644
--- a/pkg/specgen/container_validate.go
+++ b/pkg/specgen/container_validate.go
@@ -83,10 +83,6 @@ func (s *SpecGenerator) Validate() error {
//
// ContainerSecurityConfig
//
- // capadd and privileged are exclusive
- if len(s.CapAdd) > 0 && s.Privileged {
- return exclusiveOptions("CapAdd", "privileged")
- }
// userns and idmappings conflict
if s.UserNS.IsPrivate() && s.IDMappings == nil {
return errors.Wrap(ErrInvalidSpecConfig, "IDMappings are required when not creating a User namespace")
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 118d80e2c..b38b0e695 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -337,11 +337,11 @@ func FinishThrottleDevices(s *specgen.SpecGenerator) error {
return nil
}
-// ConfigToSpec takes a completed container config and converts it back into a specgenerator for purposes of cloning an existing container
-func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, containerID string) (*libpod.Container, error) {
- c, err := rt.LookupContainer(containerID)
+// ConfigToSpec takes a completed container config and converts it back into a specgenerator for purposes of cloning an exisiting container
+func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID string) (*libpod.Container, *libpod.InfraInherit, error) {
+ c, err := rt.LookupContainer(contaierID)
if err != nil {
- return nil, err
+ return nil, nil, err
}
conf := c.Config()
@@ -351,17 +351,22 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, containerID
conf.Systemd = nil
conf.Mounts = []string{}
+ if specg == nil {
+ specg = &specgen.SpecGenerator{}
+ }
+
specg.Pod = conf.Pod
matching, err := json.Marshal(conf)
if err != nil {
- return nil, err
+ return nil, nil, err
}
err = json.Unmarshal(matching, specg)
if err != nil {
- return nil, err
+ return nil, nil, err
}
+
conf.Systemd = tmpSystemd
conf.Mounts = tmpMounts
@@ -481,7 +486,29 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, containerID
}
}
specg.OverlayVolumes = overlay
- specg.Mounts = conf.Spec.Mounts
+ _, mounts := c.SortUserVolumes(c.Spec())
+ specg.Mounts = mounts
specg.HostDeviceList = conf.DeviceHostSrc
- return c, nil
+ mapSecurityConfig(conf, specg)
+
+ if c.IsInfra() { // if we are creating this spec for a pod's infra ctr, map the compatible options
+ spec, err := json.Marshal(specg)
+ if err != nil {
+ return nil, nil, err
+ }
+ infraInherit := &libpod.InfraInherit{}
+ err = json.Unmarshal(spec, infraInherit)
+ return c, infraInherit, err
+ }
+ // else just return the container
+ return c, nil, nil
+}
+
+// mapSecurityConfig takes a libpod.ContainerSecurityConfig and converts it to a specgen.ContinerSecurityConfig
+func mapSecurityConfig(c *libpod.ContainerConfig, s *specgen.SpecGenerator) {
+ s.Privileged = c.Privileged
+ s.SelinuxOpts = append(s.SelinuxOpts, c.LabelOpts...)
+ s.User = c.User
+ s.Groups = c.Groups
+ s.HostUsers = c.HostUsers
}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index a014f5047..6a611e854 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -49,7 +49,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
compatibleOptions := &libpod.InfraInherit{}
var infraSpec *spec.Spec
if infra != nil {
- options, infraSpec, compatibleOptions, err = Inherit(*infra)
+ options, infraSpec, compatibleOptions, err = Inherit(*infra, s, rt)
if err != nil {
return nil, nil, nil, err
}
@@ -152,8 +152,8 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, nil, nil, err
}
- infraVolumes := (len(compatibleOptions.InfraVolumes) > 0 || len(compatibleOptions.InfraUserVolumes) > 0 || len(compatibleOptions.InfraImageVolumes) > 0)
- opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command, infraVolumes, *compatibleOptions)
+ infraVol := (len(compatibleOptions.Mounts) > 0 || len(compatibleOptions.Volumes) > 0 || len(compatibleOptions.ImageVolumes) > 0 || len(compatibleOptions.OverlayVolumes) > 0)
+ opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, imageData, command, infraVol, *compatibleOptions)
if err != nil {
return nil, nil, nil, err
}
@@ -446,7 +446,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
if len(s.SelinuxOpts) > 0 {
options = append(options, libpod.WithSecLabels(s.SelinuxOpts))
} else {
- if pod != nil && len(compatibleOptions.InfraLabels) == 0 {
+ if pod != nil && len(compatibleOptions.SelinuxOpts) == 0 {
// duplicate the security options from the pod
processLabel, err := pod.ProcessLabel()
if err != nil {
@@ -544,32 +544,23 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
return options, nil
}
-func Inherit(infra libpod.Container) (opts []libpod.CtrCreateOption, infraS *spec.Spec, compat *libpod.InfraInherit, err error) {
+func Inherit(infra libpod.Container, s *specgen.SpecGenerator, rt *libpod.Runtime) (opts []libpod.CtrCreateOption, infraS *spec.Spec, compat *libpod.InfraInherit, err error) {
+ inheritSpec := &specgen.SpecGenerator{}
+ _, compatibleOptions, err := ConfigToSpec(rt, inheritSpec, infra.ID())
+ if err != nil {
+ return nil, nil, nil, err
+ }
options := []libpod.CtrCreateOption{}
- compatibleOptions := &libpod.InfraInherit{}
infraConf := infra.Config()
infraSpec := infraConf.Spec
- config, err := json.Marshal(infraConf)
+ compatByte, err := json.Marshal(compatibleOptions)
if err != nil {
return nil, nil, nil, err
}
- err = json.Unmarshal(config, compatibleOptions)
+ err = json.Unmarshal(compatByte, s)
if err != nil {
return nil, nil, nil, err
}
- if infraSpec.Linux != nil && infraSpec.Linux.Resources != nil {
- resources, err := json.Marshal(infraSpec.Linux.Resources)
- if err != nil {
- return nil, nil, nil, err
- }
- err = json.Unmarshal(resources, &compatibleOptions.InfraResources)
- if err != nil {
- return nil, nil, nil, err
- }
- }
- if compatibleOptions != nil {
- options = append(options, libpod.WithInfraConfig(*compatibleOptions))
- }
return options, infraSpec, compatibleOptions, nil
}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index 1cc3a463f..961cea933 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -352,8 +352,8 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
return nil, err
}
}
- if len(compatibleOptions.InfraDevices) > 0 && len(s.Devices) == 0 {
- userDevices = compatibleOptions.InfraDevices
+ if len(compatibleOptions.HostDeviceList) > 0 && len(s.Devices) == 0 {
+ userDevices = compatibleOptions.HostDeviceList
} else {
userDevices = s.Devices
}
diff --git a/pkg/specgenutil/volumes.go b/pkg/specgenutil/volumes.go
index 2bd79b186..8a861077a 100644
--- a/pkg/specgenutil/volumes.go
+++ b/pkg/specgenutil/volumes.go
@@ -28,7 +28,7 @@ var (
// TODO: handle options parsing/processing via containers/storage/pkg/mount
func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bool) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, []*specgen.ImageVolume, error) {
// Get mounts from the --mounts flag.
- unifiedMounts, unifiedVolumes, unifiedImageVolumes, err := getMounts(mountFlag)
+ unifiedMounts, unifiedVolumes, unifiedImageVolumes, err := Mounts(mountFlag)
if err != nil {
return nil, nil, nil, nil, err
}
@@ -167,12 +167,12 @@ func findMountType(input string) (mountType string, tokens []string, err error)
return
}
-// getMounts takes user-provided input from the --mount flag and creates OCI
+// Mounts takes user-provided input from the --mount flag and creates OCI
// spec mounts and Libpod named volumes.
// podman run --mount type=bind,src=/etc/resolv.conf,target=/etc/resolv.conf ...
// podman run --mount type=tmpfs,target=/dev/shm ...
// podman run --mount type=volume,source=test-volume, ...
-func getMounts(mountFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, map[string]*specgen.ImageVolume, error) {
+func Mounts(mountFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, map[string]*specgen.ImageVolume, error) {
finalMounts := make(map[string]spec.Mount)
finalNamedVolumes := make(map[string]*specgen.NamedVolume)
finalImageVolumes := make(map[string]*specgen.ImageVolume)
@@ -518,7 +518,7 @@ func getDevptsMount(args []string) (spec.Mount, error) {
func getNamedVolume(args []string) (*specgen.NamedVolume, error) {
newVolume := new(specgen.NamedVolume)
- var setSource, setDest, setRORW, setSuid, setDev, setExec, setOwnership bool
+ var setDest, setRORW, setSuid, setDev, setExec, setOwnership bool
for _, val := range args {
kv := strings.SplitN(val, "=", 2)
@@ -554,7 +554,6 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) {
return nil, errors.Wrapf(optionArgError, kv[0])
}
newVolume.Name = kv[1]
- setSource = true
case "target", "dst", "destination":
if len(kv) == 1 {
return nil, errors.Wrapf(optionArgError, kv[0])
@@ -585,9 +584,6 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) {
}
}
- if !setSource {
- return nil, errors.Errorf("must set source volume")
- }
if !setDest {
return nil, noDestError
}
diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go
index 096c98727..0c665687d 100644
--- a/test/e2e/build_test.go
+++ b/test/e2e/build_test.go
@@ -1,9 +1,11 @@
package integration
import (
+ "bytes"
"fmt"
"io/ioutil"
"os"
+ "os/exec"
"path/filepath"
"runtime"
"strings"
@@ -493,14 +495,64 @@ subdir**`
Expect(output).NotTo(ContainSubstring("/testfilter/subdir"))
})
+ // See https://github.com/containers/podman/issues/13535
+ It("Remote build .containerignore filtering embedded directory (#13535)", func() {
+ SkipIfNotRemote("Testing remote .containerignore file filtering")
+ podmanTest.RestartRemoteService()
+
+ // Switch to temp dir and restore it afterwards
+ cwd, err := os.Getwd()
+ Expect(err).ToNot(HaveOccurred())
+
+ podmanTest.AddImageToRWStore(ALPINE)
+
+ contents := bytes.Buffer{}
+ contents.WriteString("FROM " + ALPINE + "\n")
+ contents.WriteString("ADD . /testfilter/\n")
+ contents.WriteString("RUN find /testfilter/ -print\n")
+
+ containerfile := filepath.Join(tempdir, "Containerfile")
+ Expect(ioutil.WriteFile(containerfile, contents.Bytes(), 0644)).ToNot(HaveOccurred())
+
+ contextDir, err := CreateTempDirInTempDir()
+ Expect(err).ToNot(HaveOccurred())
+ defer os.RemoveAll(contextDir)
+
+ Expect(ioutil.WriteFile(filepath.Join(contextDir, "expected"), contents.Bytes(), 0644)).
+ ToNot(HaveOccurred())
+
+ subdirPath := filepath.Join(contextDir, "subdir")
+ Expect(os.MkdirAll(subdirPath, 0755)).ToNot(HaveOccurred())
+ Expect(ioutil.WriteFile(filepath.Join(subdirPath, "extra"), contents.Bytes(), 0644)).
+ ToNot(HaveOccurred())
+ randomFile := filepath.Join(subdirPath, "randomFile")
+ dd := exec.Command("dd", "if=/dev/random", "of="+randomFile, "bs=1G", "count=1")
+ ddSession, err := Start(dd, GinkgoWriter, GinkgoWriter)
+ Expect(err).ToNot(HaveOccurred())
+ Eventually(ddSession).Should(Exit(0))
+
+ // make cwd as context root path
+ Expect(os.Chdir(contextDir)).ToNot(HaveOccurred())
+ defer os.Chdir(cwd)
+
+ By("Test .containerignore filtering subdirectory")
+ err = ioutil.WriteFile(filepath.Join(contextDir, ".containerignore"), []byte(`subdir/`), 0644)
+ Expect(err).ToNot(HaveOccurred())
+
+ session := podmanTest.Podman([]string{"build", "-f", containerfile, contextDir})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+
+ output := session.OutputToString()
+ Expect(output).To(ContainSubstring("Containerfile"))
+ Expect(output).To(ContainSubstring("/testfilter/expected"))
+ Expect(output).NotTo(ContainSubstring("subdir"))
+ })
+
It("podman remote test context dir contains empty dirs and symlinks", func() {
- if IsRemote() {
- podmanTest.StopRemoteService()
- podmanTest.StartRemoteService()
- } else {
- Skip("Only valid at remote test")
- }
- // Given
+ SkipIfNotRemote("Testing remote contextDir empty")
+ podmanTest.RestartRemoteService()
+
// Switch to temp dir and restore it afterwards
cwd, err := os.Getwd()
Expect(err).To(BeNil())
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index cb6574f23..620494b34 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -20,6 +20,7 @@ import (
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/inspect"
"github.com/containers/podman/v4/pkg/rootless"
+ "github.com/containers/podman/v4/pkg/util"
. "github.com/containers/podman/v4/test/utils"
"github.com/containers/storage"
"github.com/containers/storage/pkg/reexec"
@@ -500,14 +501,12 @@ func (p *PodmanTestIntegration) BuildImageWithLabel(dockerfile, imageName string
// PodmanPID execs podman and returns its PID
func (p *PodmanTestIntegration) PodmanPID(args []string) (*PodmanSessionIntegration, int) {
podmanOptions := p.MakeOptions(args, false, false)
- if p.RemoteTest {
- podmanOptions = append([]string{"--remote", "--url", p.RemoteSocket}, podmanOptions...)
- }
fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " "))
+
command := exec.Command(p.PodmanBinary, podmanOptions...)
session, err := Start(command, GinkgoWriter, GinkgoWriter)
if err != nil {
- Fail(fmt.Sprintf("unable to run podman command: %s", strings.Join(podmanOptions, " ")))
+ Fail("unable to run podman command: " + strings.Join(podmanOptions, " "))
}
podmanSession := &PodmanSession{Session: session}
return &PodmanSessionIntegration{podmanSession}, command.Process.Pid
@@ -843,11 +842,13 @@ func (p *PodmanTestIntegration) PodmanNoEvents(args []string) *PodmanSessionInte
// MakeOptions assembles all the podman main options
func (p *PodmanTestIntegration) makeOptions(args []string, noEvents, noCache bool) []string {
if p.RemoteTest {
+ if !util.StringInSlice("--remote", args) {
+ return append([]string{"--remote", "--url", p.RemoteSocket}, args...)
+ }
return args
}
- var (
- debug string
- )
+
+ var debug string
if _, ok := os.LookupEnv("DEBUG"); ok {
debug = "--log-level=debug --syslog=true "
}
diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go
index b4a59c54d..dddcf5c14 100644
--- a/test/e2e/libpod_suite_remote_test.go
+++ b/test/e2e/libpod_suite_remote_test.go
@@ -4,7 +4,6 @@
package integration
import (
- "bytes"
"errors"
"fmt"
"io/ioutil"
@@ -25,31 +24,28 @@ func IsRemote() bool {
// Podman is the exec call to podman on the filesystem
func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration {
- var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
- remoteArgs = append(remoteArgs, args...)
- podmanSession := p.PodmanBase(remoteArgs, false, false)
+ args = p.makeOptions(args, false, false)
+ podmanSession := p.PodmanBase(args, false, false)
return &PodmanSessionIntegration{podmanSession}
}
// PodmanSystemdScope runs the podman command in a new systemd scope
func (p *PodmanTestIntegration) PodmanSystemdScope(args []string) *PodmanSessionIntegration {
- var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
- remoteArgs = append(remoteArgs, args...)
+ args = p.makeOptions(args, false, false)
wrapper := []string{"systemd-run", "--scope"}
if rootless.IsRootless() {
wrapper = []string{"systemd-run", "--scope", "--user"}
}
- podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, wrapper, nil)
+ podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, wrapper, nil)
return &PodmanSessionIntegration{podmanSession}
}
// PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files
func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration {
- var remoteArgs = []string{"--remote", "--url", p.RemoteSocket}
- remoteArgs = append(remoteArgs, args...)
- podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, nil, extraFiles)
+ args = p.makeOptions(args, false, false)
+ podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, nil, extraFiles)
return &PodmanSessionIntegration{podmanSession}
}
@@ -96,57 +92,39 @@ func (p *PodmanTestIntegration) StartRemoteService() {
command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
p.RemoteCommand = command
p.RemoteSession = command.Process
- err := p.DelayForService()
- p.RemoteStartErr = err
+ p.RemoteStartErr = p.DelayForService()
}
func (p *PodmanTestIntegration) StopRemoteService() {
- var out bytes.Buffer
- var pids []int
- remoteSession := p.RemoteSession
-
if !rootless.IsRootless() {
- if err := remoteSession.Kill(); err != nil {
+ if err := p.RemoteSession.Kill(); err != nil {
fmt.Fprintf(os.Stderr, "error on remote stop-kill %q", err)
}
- if _, err := remoteSession.Wait(); err != nil {
+ if _, err := p.RemoteSession.Wait(); err != nil {
fmt.Fprintf(os.Stderr, "error on remote stop-wait %q", err)
}
} else {
- parentPid := fmt.Sprintf("%d", p.RemoteSession.Pid)
- pgrep := exec.Command("pgrep", "-P", parentPid)
- fmt.Printf("running: pgrep %s\n", parentPid)
- pgrep.Stdout = &out
- err := pgrep.Run()
- if err != nil {
- fmt.Fprint(os.Stderr, "unable to find remote pid")
- }
-
- for _, s := range strings.Split(out.String(), "\n") {
- if len(s) == 0 {
- continue
- }
- p, err := strconv.Atoi(s)
- if err != nil {
- fmt.Fprintf(os.Stderr, "unable to convert %s to int", s)
- }
- if p != 0 {
- pids = append(pids, p)
+ // Stop any children of `podman system service`
+ pkill := exec.Command("pkill", "-P", strconv.Itoa(p.RemoteSession.Pid), "-15")
+ if err := pkill.Run(); err != nil {
+ exitErr := err.(*exec.ExitError)
+ if exitErr.ExitCode() != 1 {
+ fmt.Fprintf(os.Stderr, "pkill unable to clean up service %d children, exit code %d\n",
+ p.RemoteSession.Pid, exitErr.ExitCode())
}
}
-
- pids = append(pids, p.RemoteSession.Pid)
- for _, pid := range pids {
- syscall.Kill(pid, syscall.SIGKILL)
+ if err := p.RemoteSession.Kill(); err != nil {
+ fmt.Fprintf(os.Stderr, "unable to clean up service %d, %v\n", p.RemoteSession.Pid, err)
}
}
+
socket := strings.Split(p.RemoteSocket, ":")[1]
- if err := os.Remove(socket); err != nil {
- fmt.Println(err)
+ if err := os.Remove(socket); err != nil && !errors.Is(err, os.ErrNotExist) {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
}
if p.RemoteSocketLock != "" {
- if err := os.Remove(p.RemoteSocketLock); err != nil {
- fmt.Println(err)
+ if err := os.Remove(p.RemoteSocketLock); err != nil && !errors.Is(err, os.ErrNotExist) {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
}
}
}
@@ -185,8 +163,9 @@ func (p *PodmanTestIntegration) RestoreArtifact(image string) error {
}
func (p *PodmanTestIntegration) DelayForService() error {
+ var session *PodmanSessionIntegration
for i := 0; i < 5; i++ {
- session := p.Podman([]string{"info"})
+ session = p.Podman([]string{"info"})
session.WaitWithDefaultTimeout()
if session.ExitCode() == 0 {
return nil
@@ -195,5 +174,5 @@ func (p *PodmanTestIntegration) DelayForService() error {
}
time.Sleep(2 * time.Second)
}
- return errors.New("Service not detected")
+ return fmt.Errorf("service not detected, exit code(%d)", session.ExitCode())
}
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index 04e8cfd07..8def80213 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -874,6 +874,10 @@ ENTRYPOINT ["sleep","99999"]
ctr3 := podmanTest.Podman([]string{"run", "--pod", podName, ALPINE, "cat", "/tmp1/test"})
ctr3.WaitWithDefaultTimeout()
Expect(ctr3.OutputToString()).To(ContainSubstring("hello"))
+
+ ctr4 := podmanTest.Podman([]string{"run", "--pod", podName, ALPINE, "touch", "/tmp1/testing.txt"})
+ ctr4.WaitWithDefaultTimeout()
+ Expect(ctr4).Should(Exit(0))
})
It("podman pod create --device", func() {
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 6f3aabd3f..4c399dc2b 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -535,6 +535,11 @@ var _ = Describe("Podman run", func() {
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring("0000000000000000"))
+ session = podmanTest.Podman([]string{"run", "--user=1:1", "--cap-add=DAC_OVERRIDE", "--rm", ALPINE, "grep", "CapEff", "/proc/self/status"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("0000000000000002"))
+
if os.Geteuid() > 0 {
if os.Getenv("SKIP_USERNS") != "" {
Skip("Skip userns tests.")
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index d23c5dc14..471b3a342 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -778,6 +778,13 @@ VOLUME /test/`, ALPINE)
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).Should(Equal("888:888"))
+ // anonymous volume mount
+ vol = "type=volume," + "dst=" + dest
+ session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(Equal("888:888"))
+
// named volume mount
namedVolume := podmanTest.Podman([]string{"volume", "create", "foo"})
namedVolume.WaitWithDefaultTimeout()
diff --git a/test/utils/utils.go b/test/utils/utils.go
index a6295cd19..57f002130 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -100,9 +100,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string
if p.NetworkBackend == Netavark {
runCmd = append(runCmd, []string{"--network-backend", "netavark"}...)
}
- if p.RemoteTest {
- podmanOptions = append([]string{"--remote", "--url", p.RemoteSocket}, podmanOptions...)
- }
+
if env == nil {
fmt.Printf("Running: %s %s\n", strings.Join(runCmd, " "), strings.Join(podmanOptions, " "))
} else {