Merge pull request #11792 from mheon/340_final

Backports + release notes for v3.4.0 final
This commit is contained in:
OpenShift Merge Robot 2021-09-30 08:35:07 -04:00 • committed by GitHub
commit d8bdbf5b66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 464 additions and 148 deletions

View file

@ -18,10 +18,12 @@
- Volumes created by `podman volume create` now support setting quotas when run atop XFS. The `size` and `inode` options allow the maximum size and maximum number of inodes consumed by a volume to be limited.
- The `podman info` command now outputs information on what log drivers, network drivers, and volume plugins are available for use ([#11265](https://github.com/containers/podman/issues/11265)).
- The `podman info` command now outputs the current log driver in use, and the variant and codename of the distribution in use.
- The parameters of the VM created by `podman machine init` (amount of disk space, memory, CPUs) can now be set in `containers.conf`.
- The `podman machine ls` command now shows additional information (CPUs, memory, disk size) about VMs managed by `podman machine`.
- The `podman ps` command now includes healthcheck status in container state for containers that have healthchecks ([#11527](https://github.com/containers/podman/issues/11527)).
### Changes
- The `podman build` command has a new alias, `podman buildx`, to improve compatibility with Docker. We have already added support for many `docker buildx` flags to `podman build` and aim to continue to do so.
- Podman commands run as root now ignore `XDG_RUNTIME_DIR` when determining where to place temporary files, which should resolve a number of issues including [#10745](https://github.com/containers/podman/issues/10745) and [#10806](https://github.com/containers/podman/issues/10806).
- Cases where Podman is run without a user session or a writable temporary files directory will now produce better error messages.
- The default log driver has been changed from `file` to `journald`. The `file` driver did not properly support log rotation, so this should lead to a better experience. If journald is not available on the system, Podman will automatically revert to the `file`.
- Podman no longer depends on `ip` for removing networks ([#11403](https://github.com/containers/podman/issues/11403)).
@ -51,6 +53,7 @@
- Fixed a bug where the `podman logs -f` command could hang when a container exited ([#11461](https://github.com/containers/podman/issues/11461)).
- Fixed a bug where the `podman generate systemd` command could not be used on containers that specified a restart policy ([#11438](https://github.com/containers/podman/issues/11438)).
- Fixed a bug where the remote Podman client's `podman build` command would fail to build containers if the UID and GID on the client were higher than 65536 ([#11474](https://github.com/containers/podman/issues/11474)).
- Fixed a bug where the remote Podman client's `podman build` command would fail to build containers if the context directory was a symlink ([#11732](https://github.com/containers/podman/issues/11732)).
- Fixed a bug where the `--network` flag to `podman play kube` was not properly parsed when a non-bridge network configuration was specified.
- Fixed a bug where the `podman inspect` command could error when the container being inspected was removed as it was being inspected ([#11392](https://github.com/containers/podman/issues/11392)).
- Fixed a bug where the `podman play kube` command ignored the default pod infra image specified in `containers.conf`.
@ -68,6 +71,11 @@
- Fixed a bug where the `--filter` option to `podman ps` did not properly handle filtering by healthcheck status ([#11687](https://github.com/containers/podman/issues/11687)).
- Fixed a bug where the `podman run` and `podman start --attach` commands could race when retrieving the exit code of a container that had already been removed resulting in an error (e.g. by an external `podman rm -f`) ([#11633](https://github.com/containers/podman/issues/11633)).
- Fixed a bug where the `podman generate kube` command would add default environment variables to generated YAML.
- Fixed a bug where the `podman generate kube` command would add the default CMD from the image to generated YAML ([#11672](https://github.com/containers/podman/issues/11672)).
- Fixed a bug where the `podman rm --storage` command could fail to remove containers under some circumstances ([#11207](https://github.com/containers/podman/issues/11207)).
- Fixed a bug where the `podman machine ssh` command could fail when run on Linux ([#11731](https://github.com/containers/podman/issues/11731)).
- Fixed a bug where the `podman stop` command would error when used on a container that was already stopped ([#11740](https://github.com/containers/podman/issues/11740)).
- Fixed a bug where renaming a container in a pod using the `podman rename` command, then removing the pod using `podman pod rm`, could cause Podman to believe the new name of the container was permanently in use, despite the container being removed ([#11750](https://github.com/containers/podman/issues/11750)).
### API
- The Libpod Pull endpoint for Images now has a new query parameter, `quiet`, which (when set to true) suppresses image pull progress reports ([#10612](https://github.com/containers/podman/issues/10612)).

View file

@ -193,21 +193,14 @@ func getImages(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellComp
} else {
// suggested "registry.fedoraproject.org/f29/httpd:latest" as
// - "registry.fedoraproject.org/f29/httpd:latest"
// - "registry.fedoraproject.org/f29/httpd"
// - "f29/httpd:latest"
// - "f29/httpd"
// - "httpd:latest"
// - "httpd"
paths := strings.Split(repo, "/")
for i := range paths {
suggestionWithTag := strings.Join(paths[i:], "/")
if strings.HasPrefix(suggestionWithTag, toComplete) {
suggestions = append(suggestions, suggestionWithTag)
}
suggestionWithoutTag := strings.SplitN(strings.SplitN(suggestionWithTag, ":", 2)[0], "@", 2)[0]
if strings.HasPrefix(suggestionWithoutTag, toComplete) {
suggestions = append(suggestions, suggestionWithoutTag)
}
}
}
}

View file

@ -375,6 +375,10 @@ func (l psReporter) State() string {
// Status is a synonym for State()
func (l psReporter) Status() string {
hc := l.ListContainer.Status
if hc != "" {
return l.State() + " (" + hc + ")"
}
return l.State()
}

View file

@ -11,7 +11,7 @@ var (
// Command: podman _generate_
generateCmd = &cobra.Command{
Use: "generate",
Short: "Generate structured data based on containers, pods or volumes.",
Short: "Generate structured data based on containers, pods or volumes",
Long: "Generate structured data (e.g., Kubernetes YAML or systemd units) based on containers, pods or volumes.",
RunE: validate.SubCommandExists,
}

View file

@ -80,7 +80,7 @@ func prune(cmd *cobra.Command, args []string) error {
func createPruneWarningMessage(pruneOpts entities.ImagePruneOptions) string {
question := "Are you sure you want to continue? [y/N] "
if pruneOpts.All {
return "WARNING! This will remove all images without at least one container associated to them.\n" + question
return "WARNING! This command removes all images without at least one container associated with them.\n" + question
}
return "WARNING! This will remove all dangling images.\n" + question
return "WARNING! This command removes all dangling images.\n" + question
}

View file

@ -40,10 +40,13 @@ type listFlagType struct {
}
type machineReporter struct {
Name string
Created string
LastUp string
VMType string
Name string
Created string
LastUp string
VMType string
CPUs uint64
Memory string
DiskSize string
}
func init() {
@ -54,7 +57,7 @@ func init() {
flags := lsCmd.Flags()
formatFlagName := "format"
flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\n", "Format volume output using Go template")
flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\t{{.CPUs}}\t{{.Memory}}\t{{.DiskSize}}\n", "Format volume output using Go template")
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, completion.AutocompleteNone)
flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers")
}
@ -85,8 +88,11 @@ func list(cmd *cobra.Command, args []string) error {
func outputTemplate(cmd *cobra.Command, responses []*machineReporter) error {
headers := report.Headers(machineReporter{}, map[string]string{
"LastUp": "LAST UP",
"VmType": "VM TYPE",
"LastUp": "LAST UP",
"VmType": "VM TYPE",
"CPUs": "CPUS",
"Memory": "MEMORY",
"DiskSize": "DISK SIZE",
})
row := report.NormalizeFormat(listFlag.format)
@ -136,6 +142,9 @@ func toHumanFormat(vms []*machine.ListResponse) ([]*machineReporter, error) {
}
response.Created = units.HumanDuration(time.Since(vm.CreatedAt)) + " ago"
response.VMType = vm.VMType
response.CPUs = vm.CPUs
response.Memory = units.HumanSize(float64(vm.Memory) * units.MiB)
response.DiskSize = units.HumanSize(float64(vm.DiskSize) * units.GiB)
humanResponses = append(humanResponses, response)
}

View file

@ -10,7 +10,7 @@ var (
// Command: podman _play_
playCmd = &cobra.Command{
Use: "play",
Short: "Play containers, pods or volumes from a structured file.",
Short: "Play containers, pods or volumes from a structured file",
Long: "Play structured data (e.g., Kubernetes YAML) based on containers, pods or volumes.",
RunE: validate.SubCommandExists,
}

View file

@ -89,12 +89,7 @@ func newPodmanConfig() {
// use for the containers.conf configuration file.
func setXdgDirs() error {
if !rootless.IsRootless() {
// unset XDG_RUNTIME_DIR for root
// Sometimes XDG_RUNTIME_DIR is set to /run/user/0 sometimes it is unset,
// the inconsistency is causing issues for the dnsname plugin.
// It is already set to an empty string for conmon so lets do the same
// for podman. see #10806 and #10745
return os.Unsetenv("XDG_RUNTIME_DIR")
return nil
}
// Setup XDG_RUNTIME_DIR

View file

@ -92,6 +92,11 @@ func Execute() {
if registry.GetExitCode() == 0 {
registry.SetExitCode(define.ExecErrorCodeGeneric)
}
if registry.IsRemote() {
if strings.Contains(err.Error(), "unable to connect to Podman") {
fmt.Fprintln(os.Stderr, "Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM")
}
}
fmt.Fprintln(os.Stderr, formatError(err))
}
os.Exit(registry.GetExitCode())

View file

@ -113,15 +113,15 @@ func prune(cmd *cobra.Command, args []string) error {
func createPruneWarningMessage(pruneOpts entities.SystemPruneOptions) string {
if pruneOpts.All {
return `WARNING! This will remove:
return `WARNING! This command removes:
- all stopped containers
- all networks not used by at least one container%s
- all images without at least one container associated to them
- all images without at least one container associated with them
- all build cache
%s`
}
return `WARNING! This will remove:
return `WARNING! This command removes:
- all stopped containers
- all networks not used by at least one container%s
- all dangling images

View file

@ -64,8 +64,10 @@ discarded when writing images in Docker formats.
#### **--arch**=*arch*
Set the ARCH of the image to the provided value instead of the architecture of
the host.
Set the architecture of the image to be built, and that of the base image to be
pulled, if the build uses one, to the provided value instead of using the
architecture of the build host. (Examples: arm, arm64, 386, amd64, ppc64le,
s390x)
#### **--authfile**=*path*
@ -321,7 +323,8 @@ Pass through HTTP Proxy environment variables.
#### **--iidfile**=*ImageIDfile*
Write the image ID to the file.
Write the built image's ID to the file. When `--platform` is specified more
than once, attempting to use this option will trigger an error.
#### **--ignorefile**
@ -389,6 +392,7 @@ Name of the manifest list to which the image will be added. Creates the manifest
if it does not exist. This option is useful for building multi architecture images.
#### **--memory**, **-m**=*LIMIT*
Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes),
m (megabytes), or g (gigabytes))
@ -430,8 +434,9 @@ with a new set of cached layers.
#### **--os**=*string*
Set the OS to the provided value instead of the current operating system of the
host.
Set the OS of the image to be built, and that of the base image to be pulled,
if the build uses one, instead of using the current operating system of the
build host.
#### **--pid**=*pid*
@ -442,11 +447,28 @@ that the PID namespace in which `podman` itself is being run should be reused,
or it can be the path to a PID namespace which is already in use by another
process.
#### **--platform**="Linux"
#### **--platform**="OS/ARCH[/VARIANT][,...]"
This option has no effect on the build. Other container engines use this option
to control the execution platform for the build (e.g., Windows, Linux) which is
not required for Buildah as it supports only Linux.
Set the OS/ARCH of the built image (and its base image, if your build uses one)
to the provided value instead of using the current operating system and
architecture of the host (for example `linux/arm`). If `--platform` is set,
then the values of the `--arch`, `--os`, and `--variant` options will be
overridden.
The `--platform` flag can be specified more than once, or given a
comma-separated list of values as its argument. When more than one platform is
specified, the `--manifest` option should be used instead of the `--tag`
option.
OS/ARCH pairs are those used by the Go Programming Language. In several cases
the ARCH value for a platform differs from one produced by other tools such as
the `arch` command. Valid OS and architecture name combinations are listed as
values for $GOOS and $GOARCH at https://golang.org/doc/install/source#environment,
and can also be found by running `go tool dist list`.
While `podman build` is happy to use base images and build images for any
platform that exists, `RUN` instructions will not be able to succeed without
the help of emulation provided by packages like `qemu-user-static`.
#### **--pull**
@ -486,7 +508,6 @@ commands specified by the **RUN** instruction.
Note: You can also override the default runtime by setting the BUILDAH\_RUNTIME
environment variable. `export BUILDAH_RUNTIME=/usr/local/bin/runc`
#### **--secret**=**id=id,src=path**
Pass secret information to be used in the Containerfile for building images
@ -497,7 +518,6 @@ To later use the secret, use the --mount flag in a `RUN` instruction within a `C
`RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret`
#### **--security-opt**=*option*
Security Options
@ -697,7 +717,9 @@ process.
#### **--variant**=""
Set the architecture variant of the image to be pulled.
Set the architecture variant of the image to be built, and that of the base
image to be pulled, if the build uses one, to the provided value instead of
using the architecture variant of the build host.
#### **--volume**, **-v**[=*[HOST-DIR:CONTAINER-DIR[:OPTIONS]]*]
@ -858,7 +880,7 @@ $ podman build --layers --force-rm -t imageName .
$ podman build --no-cache --rm=false -t imageName .
```
### Building an multi-architecture image using a --manifest option (Requires emulation software)
### Building a multi-architecture image using the --manifest option (requires emulation software)
```
$ podman build --arch arm --manifest myimage /tmp/mysrc
@ -866,6 +888,10 @@ $ podman build --arch arm --manifest myimage /tmp/mysrc
$ podman build --arch amd64 --manifest myimage /tmp/mysrc
$ podman build --arch s390x --manifest myimage /tmp/mysrc
$ podman build --platform linux/s390x,linux/ppc64le,linux/amd64 --manifest myimage /tmp/mysrc
$ podman build --platform linux/arm64 --platform linux/amd64 --manifest myimage /tmp/mysrc
```
### Building an image using a URL, Git repo, or archive

View file

@ -1756,6 +1756,23 @@ func (s *BoltState) SafeRewriteContainerConfig(ctr *Container, oldName, newName
if err := allCtrsBkt.Put([]byte(ctr.ID()), []byte(newName)); err != nil {
return errors.Wrapf(err, "error renaming container %s in all containers bucket in DB", ctr.ID())
}
if ctr.config.Pod != "" {
podsBkt, err := getPodBucket(tx)
if err != nil {
return err
}
podBkt := podsBkt.Bucket([]byte(ctr.config.Pod))
if podBkt == nil {
return errors.Wrapf(define.ErrInternal, "bucket for pod %s does not exist", ctr.config.Pod)
}
podCtrBkt := podBkt.Bucket(containersBkt)
if podCtrBkt == nil {
return errors.Wrapf(define.ErrInternal, "pod %s does not have a containers bucket", ctr.config.Pod)
}
if err := podCtrBkt.Put([]byte(ctr.ID()), []byte(newName)); err != nil {
return errors.Wrapf(err, "error renaming container %s in pod %s members bucket", ctr.ID(), ctr.config.Pod)
}
}
}
}

View file

@ -174,7 +174,7 @@ func (c *Container) copyToArchive(ctx context.Context, path string, writer io.Wr
// getContainerUser returns the specs.User and ID mappings of the container.
func getContainerUser(container *Container, mountPoint string) (specs.User, error) {
userspec := container.Config().User
userspec := container.config.User
uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
u := specs.User{

View file

@ -982,12 +982,11 @@ func (c *Container) checkDependenciesRunning() ([]string, error) {
}
// Check the status
conf := depCtr.Config()
state, err := depCtr.State()
if err != nil {
return nil, errors.Wrapf(err, "error retrieving state of dependency %s of container %s", dep, c.ID())
}
if state != define.ContainerStateRunning && !conf.IsInfra {
if state != define.ContainerStateRunning && !depCtr.config.IsInfra {
notRunning = append(notRunning, dep)
}
depCtrs[dep] = depCtr
@ -1063,7 +1062,7 @@ func (c *Container) cniHosts() string {
var hosts string
if len(c.state.NetworkStatus) > 0 && len(c.state.NetworkStatus[0].IPs) > 0 {
ipAddress := strings.Split(c.state.NetworkStatus[0].IPs[0].Address.String(), "/")[0]
hosts += fmt.Sprintf("%s\t%s %s\n", ipAddress, c.Hostname(), c.Config().Name)
hosts += fmt.Sprintf("%s\t%s %s\n", ipAddress, c.Hostname(), c.config.Name)
}
return hosts
}
@ -2127,7 +2126,7 @@ func (c *Container) canWithPrevious() error {
// JSON files for later export
func (c *Container) prepareCheckpointExport() error {
// save live config
if _, err := metadata.WriteJSONFile(c.Config(), c.bundlePath(), metadata.ConfigDumpFile); err != nil {
if _, err := metadata.WriteJSONFile(c.config, c.bundlePath(), metadata.ConfigDumpFile); err != nil {
return err
}

View file

@ -112,7 +112,7 @@ func (c *Container) resolvePath(mountPoint string, containerPath string) (string
func findVolume(c *Container, containerPath string) (*Volume, error) {
runtime := c.Runtime()
cleanedContainerPath := filepath.Clean(containerPath)
for _, vol := range c.Config().NamedVolumes {
for _, vol := range c.config.NamedVolumes {
if cleanedContainerPath == filepath.Clean(vol.Dest) {
return runtime.GetVolume(vol.Name)
}
@ -124,7 +124,7 @@ func findVolume(c *Container, containerPath string) (*Volume, error) {
// Volume's destination.
func isPathOnVolume(c *Container, containerPath string) bool {
cleanedContainerPath := filepath.Clean(containerPath)
for _, vol := range c.Config().NamedVolumes {
for _, vol := range c.config.NamedVolumes {
if cleanedContainerPath == filepath.Clean(vol.Dest) {
return true
}
@ -141,7 +141,7 @@ func isPathOnVolume(c *Container, containerPath string) bool {
// path of a Mount. Returns a matching Mount or nil.
func findBindMount(c *Container, containerPath string) *specs.Mount {
cleanedPath := filepath.Clean(containerPath)
for _, m := range c.Config().Spec.Mounts {
for _, m := range c.config.Spec.Mounts {
if m.Type != "bind" {
continue
}
@ -157,7 +157,7 @@ func findBindMount(c *Container, containerPath string) *specs.Mount {
// Mount's destination.
func isPathOnBindMount(c *Container, containerPath string) bool {
cleanedContainerPath := filepath.Clean(containerPath)
for _, m := range c.Config().Spec.Mounts {
for _, m := range c.config.Spec.Mounts {
if cleanedContainerPath == filepath.Clean(m.Destination) {
return true
}

View file

@ -1,9 +1,11 @@
package libpod
import (
"context"
"fmt"
"math/rand"
"os"
"reflect"
"sort"
"strconv"
"strings"
@ -27,14 +29,14 @@ import (
// GenerateForKube takes a slice of libpod containers and generates
// one v1.Pod description that includes just a single container.
func GenerateForKube(ctrs []*Container) (*v1.Pod, error) {
func GenerateForKube(ctx context.Context, ctrs []*Container) (*v1.Pod, error) {
// Generate the v1.Pod yaml description
return simplePodWithV1Containers(ctrs)
return simplePodWithV1Containers(ctx, ctrs)
}
// GenerateForKube takes a slice of libpod containers and generates
// one v1.Pod description
func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) {
func (p *Pod) GenerateForKube(ctx context.Context) (*v1.Pod, []v1.ServicePort, error) {
// Generate the v1.Pod yaml description
var (
ports []v1.ContainerPort //nolint
@ -78,7 +80,7 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) {
servicePorts = containerPortsToServicePorts(ports)
hostNetwork = infraContainer.NetworkMode() == string(namespaces.NetworkMode(specgen.Host))
}
pod, err := p.podWithContainers(allContainers, ports, hostNetwork)
pod, err := p.podWithContainers(ctx, allContainers, ports, hostNetwork)
if err != nil {
return nil, servicePorts, err
}
@ -88,7 +90,7 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) {
// so set it at here
for _, ctr := range allContainers {
if !ctr.IsInfra() {
switch ctr.Config().RestartPolicy {
switch ctr.config.RestartPolicy {
case define.RestartPolicyAlways:
pod.Spec.RestartPolicy = v1.RestartPolicyAlways
case define.RestartPolicyOnFailure:
@ -218,7 +220,7 @@ func containersToServicePorts(containers []v1.Container) []v1.ServicePort {
return sps
}
func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPort, hostNetwork bool) (*v1.Pod, error) {
func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, ports []v1.ContainerPort, hostNetwork bool) (*v1.Pod, error) {
deDupPodVolumes := make(map[string]*v1.Volume)
first := true
podContainers := make([]v1.Container, 0, len(containers))
@ -239,7 +241,7 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
isInit := ctr.IsInitCtr()
ctr, volumes, _, err := containerToV1Container(ctr)
ctr, volumes, _, err := containerToV1Container(ctx, ctr)
if err != nil {
return nil, err
}
@ -251,7 +253,9 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
// We add the original port declarations from the libpod infra container
// to the first kubernetes container description because otherwise we loose
// the original container/port bindings.
if first && len(ports) > 0 {
// Add the port configuration to the first regular container or the first
// init container if only init containers have been created in the pod.
if first && len(ports) > 0 && (!isInit || len(containers) == 2) {
ctr.Ports = ports
first = false
}
@ -267,7 +271,7 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
deDupPodVolumes[vol.Name] = &vol
}
} else {
_, _, infraDNS, err := containerToV1Container(ctr)
_, _, infraDNS, err := containerToV1Container(ctx, ctr)
if err != nil {
return nil, err
}
@ -337,7 +341,7 @@ func newPodObject(podName string, annotations map[string]string, initCtrs, conta
// simplePodWithV1Containers is a function used by inspect when kube yaml needs to be generated
// for a single container. we "insert" that container description in a pod.
func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) {
func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod, error) {
kubeCtrs := make([]v1.Container, 0, len(ctrs))
kubeInitCtrs := []v1.Container{}
kubeVolumes := make([]v1.Volume, 0)
@ -355,7 +359,7 @@ func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) {
if !ctr.HostNetwork() {
hostNetwork = false
}
kubeCtr, kubeVols, ctrDNS, err := containerToV1Container(ctr)
kubeCtr, kubeVols, ctrDNS, err := containerToV1Container(ctx, ctr)
if err != nil {
return nil, err
}
@ -411,7 +415,7 @@ func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) {
// containerToV1Container converts information we know about a libpod container
// to a V1.Container specification.
func containerToV1Container(c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, error) {
func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, error) {
kubeContainer := v1.Container{}
kubeVolumes := []v1.Volume{}
kubeSec, err := generateKubeSecurityContext(c)
@ -463,6 +467,17 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, *v1.PodDNS
_, image := c.Image()
kubeContainer.Image = image
kubeContainer.Stdin = c.Stdin()
img, _, err := c.runtime.libimageRuntime.LookupImage(image, nil)
if err != nil {
return kubeContainer, kubeVolumes, nil, err
}
imgData, err := img.Inspect(ctx, false)
if err != nil {
return kubeContainer, kubeVolumes, nil, err
}
if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) {
kubeContainer.Command = nil
}
kubeContainer.WorkingDir = c.WorkingDir()
kubeContainer.Ports = ports

View file

@ -30,6 +30,7 @@ import (
"github.com/containernetworking/cni/pkg/invoke"
"github.com/containernetworking/cni/pkg/version"
"github.com/containers/podman/v3/pkg/rootless"
)
type cniExec struct {
@ -67,6 +68,17 @@ func (e *cniExec) ExecPlugin(ctx context.Context, pluginPath string, stdinData [
c.Stdout = stdout
c.Stderr = stderr
// The dnsname plugin tries to use XDG_RUNTIME_DIR to store files.
// podman run will have XDG_RUNTIME_DIR set and thus the cni plugin can use
// it. The problem is that XDG_RUNTIME_DIR is unset for the conmon process
// for rootful users. This causes issues since the cleanup process is spawned
// by conmon and thus not have XDG_RUNTIME_DIR set to same value as podman run.
// Because of it dnsname will not find the config files and cannot correctly cleanup.
// To fix this we should also unset XDG_RUNTIME_DIR for the cni plugins as rootful.
if !rootless.IsRootless() {
c.Env = append(c.Env, "XDG_RUNTIME_DIR=")
}
err := c.Run()
if err != nil {
return nil, annotatePluginError(err, pluginPath, stdout.Bytes(), stderr.Bytes())

View file

@ -222,7 +222,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
defer errorhandling.CloseQuiet(syncR)
defer errorhandling.CloseQuiet(syncW)
havePortMapping := len(ctr.Config().PortMappings) > 0
havePortMapping := len(ctr.config.PortMappings) > 0
logPath := filepath.Join(ctr.runtime.config.Engine.TmpDir, fmt.Sprintf("slirp4netns-%s.log", ctr.config.ID))
ctrNetworkSlipOpts := []string{}

View file

@ -1148,7 +1148,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
if ctr.config.NetMode.IsSlirp4netns() || rootless.IsRootless() {
if ctr.config.PostConfigureNetNS {
havePortMapping := len(ctr.Config().PortMappings) > 0
havePortMapping := len(ctr.config.PortMappings) > 0
if havePortMapping {
ctr.rootlessPortSyncR, ctr.rootlessPortSyncW, err = os.Pipe()
if err != nil {

View file

@ -104,8 +104,7 @@ func (p *Pod) PidMode() string {
if err != nil {
return ""
}
conf := infra.Config()
ctrSpec := conf.Spec
ctrSpec := infra.config.Spec
if ctrSpec != nil && ctrSpec.Linux != nil {
for _, ns := range ctrSpec.Linux.Namespaces {
if ns.Type == specs.PIDNamespace {
@ -126,8 +125,7 @@ func (p *Pod) UserNSMode() string {
if err != nil {
return ""
}
conf := infra.Config()
ctrSpec := conf.Spec
ctrSpec := infra.config.Spec
if ctrSpec != nil && ctrSpec.Linux != nil {
for _, ns := range ctrSpec.Linux.Namespaces {
if ns.Type == specs.UserNamespace {

View file

@ -34,7 +34,7 @@ func (p *Pod) startInitContainers(ctx context.Context) error {
}
// If the container is a once init container, we need to remove it
// after it runs
if initCon.Config().InitContainerType == define.OneShotInitContainer {
if initCon.config.InitContainerType == define.OneShotInitContainer {
icLock := initCon.lock
icLock.Lock()
if err := p.runtime.removeContainer(ctx, initCon, false, false, true); err != nil {
@ -588,37 +588,37 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
return nil, err
}
infraConfig = new(define.InspectPodInfraConfig)
infraConfig.HostNetwork = !infra.Config().ContainerNetworkConfig.UseImageHosts
infraConfig.StaticIP = infra.Config().ContainerNetworkConfig.StaticIP
infraConfig.NoManageResolvConf = infra.Config().UseImageResolvConf
infraConfig.NoManageHosts = infra.Config().UseImageHosts
infraConfig.HostNetwork = !infra.config.ContainerNetworkConfig.UseImageHosts
infraConfig.StaticIP = infra.config.ContainerNetworkConfig.StaticIP
infraConfig.NoManageResolvConf = infra.config.UseImageResolvConf
infraConfig.NoManageHosts = infra.config.UseImageHosts
infraConfig.PidNS = p.PidMode()
infraConfig.UserNS = p.UserNSMode()
if len(infra.Config().ContainerNetworkConfig.DNSServer) > 0 {
infraConfig.DNSServer = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSServer))
for _, entry := range infra.Config().ContainerNetworkConfig.DNSServer {
if len(infra.config.ContainerNetworkConfig.DNSServer) > 0 {
infraConfig.DNSServer = make([]string, 0, len(infra.config.ContainerNetworkConfig.DNSServer))
for _, entry := range infra.config.ContainerNetworkConfig.DNSServer {
infraConfig.DNSServer = append(infraConfig.DNSServer, entry.String())
}
}
if len(infra.Config().ContainerNetworkConfig.DNSSearch) > 0 {
infraConfig.DNSSearch = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSSearch))
infraConfig.DNSSearch = append(infraConfig.DNSSearch, infra.Config().ContainerNetworkConfig.DNSSearch...)
if len(infra.config.ContainerNetworkConfig.DNSSearch) > 0 {
infraConfig.DNSSearch = make([]string, 0, len(infra.config.ContainerNetworkConfig.DNSSearch))
infraConfig.DNSSearch = append(infraConfig.DNSSearch, infra.config.ContainerNetworkConfig.DNSSearch...)
}
if len(infra.Config().ContainerNetworkConfig.DNSOption) > 0 {
infraConfig.DNSOption = make([]string, 0, len(infra.Config().ContainerNetworkConfig.DNSOption))
infraConfig.DNSOption = append(infraConfig.DNSOption, infra.Config().ContainerNetworkConfig.DNSOption...)
if len(infra.config.ContainerNetworkConfig.DNSOption) > 0 {
infraConfig.DNSOption = make([]string, 0, len(infra.config.ContainerNetworkConfig.DNSOption))
infraConfig.DNSOption = append(infraConfig.DNSOption, infra.config.ContainerNetworkConfig.DNSOption...)
}
if len(infra.Config().HostAdd) > 0 {
infraConfig.HostAdd = make([]string, 0, len(infra.Config().HostAdd))
infraConfig.HostAdd = append(infraConfig.HostAdd, infra.Config().HostAdd...)
if len(infra.config.HostAdd) > 0 {
infraConfig.HostAdd = make([]string, 0, len(infra.config.HostAdd))
infraConfig.HostAdd = append(infraConfig.HostAdd, infra.config.HostAdd...)
}
if len(infra.Config().ContainerNetworkConfig.Networks) > 0 {
infraConfig.Networks = make([]string, 0, len(infra.Config().ContainerNetworkConfig.Networks))
infraConfig.Networks = append(infraConfig.Networks, infra.Config().ContainerNetworkConfig.Networks...)
if len(infra.config.ContainerNetworkConfig.Networks) > 0 {
infraConfig.Networks = make([]string, 0, len(infra.config.ContainerNetworkConfig.Networks))
infraConfig.Networks = append(infraConfig.Networks, infra.config.ContainerNetworkConfig.Networks...)
}
infraConfig.NetworkOptions = infra.Config().ContainerNetworkConfig.NetworkOptions
infraConfig.PortBindings = makeInspectPortBindings(infra.Config().ContainerNetworkConfig.PortMappings, nil)
infraConfig.NetworkOptions = infra.config.ContainerNetworkConfig.NetworkOptions
infraConfig.PortBindings = makeInspectPortBindings(infra.config.ContainerNetworkConfig.PortMappings, nil)
}
inspectData := define.InspectPodData{

View file

@ -106,18 +106,18 @@ func (r *Runtime) removeStorageContainer(idOrName string, force bool) error {
logrus.Infof("Storage for container %s already removed", ctr.ID)
return nil
}
return errors.Wrapf(err, "error looking up container %q mounts", idOrName)
logrus.Warnf("Checking if container %q is mounted, attempting to delete: %v", idOrName, err)
}
if timesMounted > 0 {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %q is mounted and cannot be removed without using force", idOrName)
}
} else if _, err := r.store.Unmount(ctr.ID, true); err != nil {
if errors.Cause(err) == storage.ErrContainerUnknown {
if errors.Is(err, storage.ErrContainerUnknown) {
// Container again gone, no error
logrus.Infof("Storage for container %s already removed", ctr.ID)
return nil
}
return errors.Wrapf(err, "error unmounting container %q", idOrName)
logrus.Warnf("Unmounting container %q while attempting to delete storage: %v", idOrName, err)
}
if err := r.store.DeleteContainer(ctr.ID); err != nil {

View file

@ -112,12 +112,12 @@ func NewConnectionWithIdentity(ctx context.Context, uri string, identity string)
return nil, errors.Errorf("unable to create connection. %q is not a supported schema", _url.Scheme)
}
if err != nil {
return nil, errors.Wrapf(err, "failed to create %sClient", _url.Scheme)
return nil, errors.Wrapf(err, "unable to connect to Podman. failed to create %sClient", _url.Scheme)
}
ctx = context.WithValue(ctx, clientKey, &connection)
if err := pingNewConnection(ctx); err != nil {
return nil, errors.Wrap(err, "cannot connect to the Podman socket, please verify the connection to the Linux system, or use `podman machine` to create/start a Linux VM.")
return nil, errors.Wrap(err, "unable to connect to Podman socket")
}
return ctx, nil
}

View file

@ -230,6 +230,9 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
params.Add("platform", platform)
}
}
if contextDir, err := filepath.EvalSymlinks(options.ContextDirectory); err == nil {
options.ContextDirectory = contextDir
}
params.Set("pullpolicy", options.PullPolicy.String())

View file

@ -169,6 +169,10 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
logrus.Debugf("Container %s is already stopped", c.ID())
case options.All && errors.Cause(err) == define.ErrCtrStateInvalid:
logrus.Debugf("Container %s is not running, could not stop", c.ID())
// container never created in OCI runtime
// docker parity: do nothing just return container id
case errors.Cause(err) == define.ErrCtrStateInvalid:
logrus.Debugf("Container %s is either not created on runtime or is in a invalid state", c.ID())
default:
return err
}

View file

@ -107,7 +107,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
// Generate kube pods and services from pods.
if len(pods) >= 1 {
pos, svcs, err := getKubePods(pods, options.Service)
pos, svcs, err := getKubePods(ctx, pods, options.Service)
if err != nil {
return nil, err
}
@ -120,7 +120,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
// Generate the kube pods from containers.
if len(ctrs) >= 1 {
po, err := libpod.GenerateForKube(ctrs)
po, err := libpod.GenerateForKube(ctx, ctrs)
if err != nil {
return nil, err
}
@ -153,12 +153,12 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string,
}
// getKubePods returns kube pod and service YAML files from podman pods.
func getKubePods(pods []*libpod.Pod, getService bool) ([][]byte, [][]byte, error) {
func getKubePods(ctx context.Context, pods []*libpod.Pod, getService bool) ([][]byte, [][]byte, error) {
pos := [][]byte{}
svcs := [][]byte{}
for _, p := range pods {
po, sp, err := p.GenerateForKube()
po, sp, err := p.GenerateForKube(ctx)
if err != nil {
return nil, nil, err
}

View file

@ -58,6 +58,9 @@ type ListResponse struct {
LastUp time.Time
Running bool
VMType string
CPUs uint64
Memory uint64
DiskSize uint64
}
type SSHOptions struct {

View file

@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
)
/*
@ -80,6 +81,7 @@ func NewIgnitionFile(ign DynamicIgnition) error {
// so a listening host knows it can being interacting with it
ready := `[Unit]
Requires=dev-virtio\\x2dports-%s.device
After=remove-moby.service
OnFailure=emergency.target
OnFailureJobMode=isolate
[Service]
@ -89,6 +91,23 @@ ExecStart=/bin/sh -c '/usr/bin/echo Ready >/dev/%s'
[Install]
RequiredBy=multi-user.target
`
deMoby := `[Unit]
Description=Remove moby-engine
# Run once for the machine
After=systemd-machine-id-commit.service
Before=zincati.service
ConditionPathExists=!/var/lib/%N.stamp
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/rpm-ostree override remove moby-engine
ExecStart=/usr/bin/rpm-ostree ex apply-live --allow-replacement
ExecStartPost=/bin/touch /var/lib/%N.stamp
[Install]
WantedBy=multi-user.target
`
_ = ready
ignSystemd := Systemd{
Units: []Unit{
@ -101,6 +120,21 @@ RequiredBy=multi-user.target
Name: "ready.service",
Contents: strToPtr(fmt.Sprintf(ready, "vport1p1", "vport1p1")),
},
{
Enabled: boolToPtr(false),
Name: "docker.service",
Mask: boolToPtr(true),
},
{
Enabled: boolToPtr(false),
Name: "docker.socket",
Mask: boolToPtr(true),
},
{
Enabled: boolToPtr(true),
Name: "remove-moby.service",
Contents: &deMoby,
},
}}
ignConfig := Config{
Ignition: ignVersion,
@ -161,6 +195,22 @@ func getFiles(usrName string) []File {
var (
files []File
)
lingerExample := `[Unit]
Description=A systemd user unit demo
After=network-online.target
Wants=network-online.target podman.socket
[Service]
ExecStart=/usr/bin/sleep infinity
`
containers := `[containers]
netns="bridge"
rootless_networking="cni"
`
rootContainers := `[engine]
machine_enabled=true
`
// Add a fake systemd service to get the user socket rolling
files = append(files, File{
Node: Node{
@ -171,7 +221,7 @@ func getFiles(usrName string) []File {
FileEmbedded1: FileEmbedded1{
Append: nil,
Contents: Resource{
Source: strToPtr("data:,%5BUnit%5D%0ADescription%3DA%20systemd%20user%20unit%20demo%0AAfter%3Dnetwork-online.target%0AWants%3Dnetwork-online.target%20podman.socket%0A%5BService%5D%0AExecStart%3D%2Fusr%2Fbin%2Fsleep%20infinity%0A"),
Source: encodeDataURLPtr(lingerExample),
},
Mode: intToPtr(0744),
},
@ -188,7 +238,7 @@ func getFiles(usrName string) []File {
FileEmbedded1: FileEmbedded1{
Append: nil,
Contents: Resource{
Source: strToPtr("data:,%5Bcontainers%5D%0D%0Anetns%3D%22bridge%22%0D%0Arootless_networking%3D%22cni%22"),
Source: encodeDataURLPtr(containers),
},
Mode: intToPtr(0744),
},
@ -213,7 +263,7 @@ func getFiles(usrName string) []File {
FileEmbedded1: FileEmbedded1{
Append: nil,
Contents: Resource{
Source: strToPtr("data:,%5Bengine%5D%0Amachine_enabled%3Dtrue%0A"),
Source: encodeDataURLPtr(rootContainers),
},
Mode: intToPtr(0644),
},
@ -233,7 +283,22 @@ func getFiles(usrName string) []File {
FileEmbedded1: FileEmbedded1{
Append: nil,
Contents: Resource{
Source: strToPtr("data:,unqualified-search-registries%3D%5B%22docker.io%22%5D"),
Source: encodeDataURLPtr("unqualified-search-registries=[\"docker.io\"]\n"),
},
Mode: intToPtr(0644),
},
})
files = append(files, File{
Node: Node{
Path: "/etc/tmpfiles.d/podman-docker.conf",
},
FileEmbedded1: FileEmbedded1{
Append: nil,
// Create a symlink from the docker socket to the podman socket.
// Taken from https://github.com/containers/podman/blob/main/contrib/systemd/system/podman-docker.conf
Contents: Resource{
Source: encodeDataURLPtr("L+ /run/docker.sock - - - - /run/podman/podman.sock\n"),
},
Mode: intToPtr(0644),
},
@ -253,5 +318,20 @@ func getLinks(usrName string) []Link {
Hard: boolToPtr(false),
Target: "/home/" + usrName + "/.config/systemd/user/linger-example.service",
},
}, {
Node: Node{
Group: getNodeGrp("root"),
Path: "/usr/local/bin/docker",
Overwrite: boolToPtr(true),
User: getNodeUsr("root"),
},
LinkEmbedded1: LinkEmbedded1{
Hard: boolToPtr(false),
Target: "/usr/bin/podman",
},
}}
}
func encodeDataURLPtr(contents string) *string {
return strToPtr(fmt.Sprintf("data:,%s", url.PathEscape(contents)))
}

View file

@ -17,6 +17,8 @@ type MachineVM struct {
ImagePath string
// Memory in megabytes assigned to the vm
Memory uint64
// Disk size in gigabytes assigned to the vm
DiskSize uint64
// Name of the vm
Name string
// SSH port for user networking

View file

@ -64,6 +64,7 @@ func NewMachine(opts machine.InitOptions) (machine.VM, error) {
vm.CPUs = opts.CPUS
vm.Memory = opts.Memory
vm.DiskSize = opts.DiskSize
// Look up the executable
execPath, err := exec.LookPath(QemuCommand)
@ -574,6 +575,9 @@ func GetVMInfos() ([]*machine.ListResponse, error) {
listEntry.Name = vm.Name
listEntry.VMType = "qemu"
listEntry.CPUs = vm.CPUs
listEntry.Memory = vm.Memory
listEntry.DiskSize = vm.DiskSize
fi, err := os.Stat(fullPath)
if err != nil {
return err

View file

@ -241,6 +241,13 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
UTS: uts,
}
}
if hc, err := ctr.HealthCheckStatus(); err == nil {
ps.Status = hc
} else {
logrus.Debug(err)
}
return ps, nil
}

View file

@ -212,6 +212,7 @@ can_use_shortcut ()
continue;
if (strcmp (argv[argc], "mount") == 0
|| strcmp (argv[argc], "machine") == 0
|| strcmp (argv[argc], "search") == 0
|| (strcmp (argv[argc], "system") == 0 && argv[argc+1] && strcmp (argv[argc+1], "service") != 0))
{

View file

@ -792,6 +792,45 @@ var _ = Describe("Podman generate kube", func() {
Expect(containers[0].Args).To(Equal([]string{"10s"}))
})
It("podman generate kube - no command", func() {
session := podmanTest.Podman([]string{"create", "--name", "test", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
kube := podmanTest.Podman([]string{"generate", "kube", "test"})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))
// Now make sure that the container's command is not set to the
// entrypoint and it's arguments to "10s".
pod := new(v1.Pod)
err := yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
containers := pod.Spec.Containers
Expect(len(containers)).To(Equal(1))
Expect(len(containers[0].Command)).To(Equal(0))
cmd := []string{"echo", "hi"}
session = podmanTest.Podman(append([]string{"create", "--name", "test1", ALPINE}, cmd...))
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
kube = podmanTest.Podman([]string{"generate", "kube", "test1"})
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))
// Now make sure that the container's command is not set to the
// entrypoint and it's arguments to "10s".
pod = new(v1.Pod)
err = yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
containers = pod.Spec.Containers
Expect(len(containers)).To(Equal(1))
Expect(containers[0].Command).To(Equal(cmd))
})
It("podman generate kube - use entrypoint from image", func() {
// Build an image with an entrypoint.
containerfile := `FROM quay.io/libpod/alpine:latest

View file

@ -80,6 +80,11 @@ var _ = Describe("Podman healthcheck run", func() {
time.Sleep(1 * time.Second)
}
Expect(exitCode).To(Equal(0))
ps := podmanTest.Podman([]string{"ps"})
ps.WaitWithDefaultTimeout()
Expect(ps).Should(Exit(0))
Expect(ps.OutputToString()).To(ContainSubstring("(healthy)"))
})
It("podman healthcheck that should fail", func() {

View file

@ -111,4 +111,29 @@ var _ = Describe("podman rename", func() {
Expect(ps).Should(Exit(0))
Expect(ps.OutputToString()).To(ContainSubstring(newName))
})
It("Rename a container that is part of a pod", func() {
podName := "testPod"
infraName := "infra1"
pod := podmanTest.Podman([]string{"pod", "create", "--name", podName, "--infra-name", infraName})
pod.WaitWithDefaultTimeout()
Expect(pod).Should(Exit(0))
infraName2 := "infra2"
rename := podmanTest.Podman([]string{"rename", infraName, infraName2})
rename.WaitWithDefaultTimeout()
Expect(rename).Should(Exit(0))
remove := podmanTest.Podman([]string{"pod", "rm", "-f", podName})
remove.WaitWithDefaultTimeout()
Expect(remove).Should(Exit(0))
create := podmanTest.Podman([]string{"create", "--name", infraName2, ALPINE, "top"})
create.WaitWithDefaultTimeout()
Expect(create).Should(Exit(0))
create2 := podmanTest.Podman([]string{"create", "--name", infraName, ALPINE, "top"})
create2.WaitWithDefaultTimeout()
Expect(create2).Should(Exit(0))
})
})

View file

@ -234,6 +234,17 @@ var _ = Describe("Podman stop", func() {
Expect(strings.TrimSpace(finalCtrs.OutputToString())).To(Equal(""))
})
It("podman stop should return silent success on stopping configured containers", func() {
// following container is not created on OCI runtime
// so we return success and assume that is is stopped
session2 := podmanTest.Podman([]string{"create", "--name", "stopctr", ALPINE, "/bin/sh"})
session2.WaitWithDefaultTimeout()
Expect(session2).Should(Exit(0))
session3 := podmanTest.Podman([]string{"stop", "stopctr"})
session3.WaitWithDefaultTimeout()
Expect(session3).Should(Exit(0))
})
It("podman stop --cidfile", func() {
tmpDir, err := ioutil.TempDir("", "")

View file

@ -135,31 +135,38 @@ function _log_test_until() {
s_after="after_$(random_string)_${driver}"
before=$(date --iso-8601=seconds)
sleep 5
sleep 1
run_podman run --log-driver=$driver -d --name test $IMAGE sh -c \
"echo $s_before; trap 'echo $s_after; exit' SIGTERM; while :; do sleep 1; done"
# sleep a second to make sure the date is after the first echo
sleep 1
run_podman stop test
# sleep for 20 seconds to get the proper after time
sleep 20
run_podman wait test
run_podman logs test
is "$output" \
"$s_before
# Sigh. Stupid journald has a lag. Wait a few seconds for it to catch up.
retries=20
s_both="$s_before
$s_after"
while [[ $retries -gt 0 ]]; do
run_podman logs test
if [[ "$output" = "$s_both" ]]; then
break
fi
retries=$((retries - 1))
sleep 0.1
done
if [[ $retries -eq 0 ]]; then
die "Timed out waiting for before&after in podman logs: $output"
fi
run_podman logs --until $before test
is "$output" \
""
is "$output" "" "podman logs --until before"
after=$(date --iso-8601=seconds)
after=$(date --date='+1 second' --iso-8601=seconds)
run_podman logs --until $after test
is "$output" \
"$s_before
$s_after"
is "$output" "$s_both" "podman logs --until after"
run_podman rm -f test
}

View file

@ -90,10 +90,18 @@ load helpers
is "${#lines[@]}" "1" "setup check: no storage containers at start of test"
# Force a buildah timeout; this leaves a buildah container behind
local t0=$SECONDS
PODMAN_TIMEOUT=5 run_podman 124 build -t thiswillneverexist - <<EOF
FROM $IMAGE
RUN sleep 30
EOF
local t1=$SECONDS
local delta_t=$((t1 - t0))
if [[ $delta_t -gt 10 ]]; then
# FIXME FIXME FIXME: when buildah issue 3544 gets fixed and vendored,
# change 'echo' to 'die'
echo "podman build did not get killed within 10 seconds (actual time: $delta_t seconds)"
fi
run_podman ps -a
is "${#lines[@]}" "1" "podman ps -a does not see buildah container"

View file

@ -125,6 +125,7 @@ load helpers
run_podman exec $cid find /image-mount/etc/
# Clean up
run_podman stop -t 0 $cid
run_podman rm -f $cid
}
@ -147,6 +148,7 @@ load helpers
run_podman inspect --format "{{(index .Mounts 0).RW}}" $cid
is "$output" "true" "inspect data includes image mount source"
run_podman stop -t 0 $cid
run_podman rm -f $cid
}

View file

@ -256,6 +256,7 @@ load helpers
"
# From RUNNING container
local -a destcontainers=()
while read id src dest dest_fullname description; do
# dest may be "''" for empty table cells
if [[ $dest == "''" ]];then
@ -265,26 +266,25 @@ load helpers
# To RUNNING container
run_podman run -d $IMAGE sleep infinity
destcontainer="$output"
destcontainers+=($destcontainer)
run_podman cp cpcontainer:$src $destcontainer:"/$dest"
run_podman exec $destcontainer cat "/$dest_fullname"
is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
run_podman kill $destcontainer
run_podman rm -f $destcontainer
# To CREATED container
run_podman create $IMAGE sleep infinity
destcontainer="$output"
destcontainers+=($destcontainer)
run_podman cp cpcontainer:$src $destcontainer:"/$dest"
run_podman start $destcontainer
run_podman exec $destcontainer cat "/$dest_fullname"
is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
run_podman kill $destcontainer
run_podman rm -f $destcontainer
done < <(parse_table "$tests")
run_podman kill cpcontainer
run_podman rm -f cpcontainer
run_podman kill cpcontainer ${destcontainers[@]}
run_podman rm -f cpcontainer ${destcontainers[@]}
# From CREATED container
destcontainers=()
run_podman create --name cpcontainer --workdir=/srv $cpimage
while read id src dest dest_fullname description; do
# dest may be "''" for empty table cells
@ -295,23 +295,21 @@ load helpers
# To RUNNING container
run_podman run -d $IMAGE sleep infinity
destcontainer="$output"
destcontainers+=($destcontainer)
run_podman cp cpcontainer:$src $destcontainer:"/$dest"
run_podman exec $destcontainer cat "/$dest_fullname"
is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
run_podman kill $destcontainer
run_podman rm -f $destcontainer
# To CREATED container
run_podman create $IMAGE sleep infinity
destcontainer="$output"
destcontainers+=($destcontainer)
run_podman cp cpcontainer:$src $destcontainer:"/$dest"
run_podman start $destcontainer
run_podman exec $destcontainer cat "/$dest_fullname"
is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
run_podman kill $destcontainer
run_podman rm -f $destcontainer
done < <(parse_table "$tests")
run_podman rm -f cpcontainer
run_podman kill ${destcontainers[@]}
run_podman rm -f cpcontainer ${destcontainers[@]}
run_podman rmi -f $cpimage
}
@ -496,6 +494,7 @@ load helpers
"
# From RUNNING container
local -a destcontainers=()
while read src dest dest_fullname description; do
if [[ $src == "''" ]];then
unset src
@ -510,28 +509,27 @@ load helpers
# To RUNNING container
run_podman run -d $IMAGE sleep infinity
destcontainer="$output"
destcontainers+=($destcontainer)
run_podman cp cpcontainer:$src $destcontainer:"/$dest"
run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1"
is "$output" "${randomcontent[0]}
${randomcontent[1]}" "$description"
run_podman kill $destcontainer
run_podman rm -f $destcontainer
# To CREATED container
run_podman create $IMAGE sleep infinity
destcontainer="$output"
destcontainers+=($destcontainer)
run_podman cp cpcontainer:$src $destcontainer:"/$dest"
run_podman start $destcontainer
run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1"
is "$output" "${randomcontent[0]}
${randomcontent[1]}" "$description"
run_podman kill $destcontainer
run_podman rm -f $destcontainer
done < <(parse_table "$tests")
run_podman kill cpcontainer
run_podman rm -f cpcontainer
run_podman kill cpcontainer ${destcontainers[@]}
run_podman rm -f cpcontainer ${destcontainers[@]}
# From CREATED container
destcontainers=()
run_podman create --name cpcontainer --workdir=/srv $cpimage
while read src dest dest_fullname description; do
if [[ $src == "''" ]];then
@ -547,26 +545,25 @@ ${randomcontent[1]}" "$description"
# To RUNNING container
run_podman run -d $IMAGE sleep infinity
destcontainer="$output"
destcontainers+=($destcontainer)
run_podman cp cpcontainer:$src $destcontainer:"/$dest"
run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1"
is "$output" "${randomcontent[0]}
${randomcontent[1]}" "$description"
run_podman kill $destcontainer
run_podman rm -f $destcontainer
# To CREATED container
run_podman create $IMAGE sleep infinity
destcontainer="$output"
destcontainers+=($destcontainer)
run_podman start $destcontainer
run_podman cp cpcontainer:$src $destcontainer:"/$dest"
run_podman exec $destcontainer cat "/$dest_fullname/containerfile0" "/$dest_fullname/containerfile1"
is "$output" "${randomcontent[0]}
${randomcontent[1]}" "$description"
run_podman kill $destcontainer
run_podman rm -f $destcontainer
done < <(parse_table "$tests")
run_podman rm -f cpcontainer
run_podman kill ${destcontainers[@]}
run_podman rm -f cpcontainer ${destcontainers[@]}
run_podman rmi -f $cpimage
}

View file

@ -956,6 +956,15 @@ EOF
run_podman build -t build_test $tmpdir
}
@test "podman build build context is a symlink to a directory" {
tmpdir=$PODMAN_TMPDIR/build-test
mkdir -p $tmpdir/target
ln -s target $tmpdir/link
echo FROM $IMAGE > $tmpdir/link/Dockerfile
echo RUN echo hello >> $tmpdir/link/Dockerfile
run_podman build -t build_test $tmpdir/link
}
function teardown() {
# A timeout or other error in 'build' can leave behind stale images
# that podman can't even see and which will cascade into subsequent

View file

@ -48,6 +48,7 @@ load helpers
# would imply that the container never paused.
is "$max_delta" "[3456]" "delta t between paused and restarted"
run_podman stop -t 0 $cname
run_podman rm -f $cname
# Pause/unpause on nonexistent name or id - these should all fail
@ -73,6 +74,7 @@ load helpers
is "$output" "$cid" "podman unpause output"
run_podman ps --format '{{.ID}} {{.Names}} {{.Status}}'
is "$output" "${cid:0:12} $cname Up.*" "podman ps on resumed container"
run_podman stop -t 0 $cname
run_podman rm -f $cname
run_podman rm -f notrunning
}

View file

@ -108,6 +108,7 @@ Log[-1].Output |
is "$output" "unhealthy" "output from 'podman healthcheck run'"
# Clean up
run_podman stop -t 0 healthcheck_c
run_podman rm -f healthcheck_c
run_podman rmi healthcheck_i
}

View file

@ -69,26 +69,36 @@ function teardown() {
@test "podman system service - socket activation - no container" {
run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping
is "$output" "OK" "podman service responses normally"
is "$output" "OK" "podman service responds normally"
}
@test "podman system service - socket activation - exist container " {
run_podman run $IMAGE sleep 90
@test "podman system service - socket activation - existing container" {
run_podman run -d $IMAGE sleep 90
cid="$output"
run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping
is "$output" "OK" "podman service responses normally"
is "$output" "OK" "podman service responds normally"
run_podman stop -t 0 $cid
run_podman rm -f $cid
}
@test "podman system service - socket activation - kill rootless pause " {
@test "podman system service - socket activation - kill rootless pause" {
if ! is_rootless; then
skip "root podman no need pause process"
fi
run_podman run $IMAGE sleep 90
run_podman run -d $IMAGE sleep 90
cid="$output"
local pause_pid="$XDG_RUNTIME_DIR/libpod/tmp/pause.pid"
if [ -f $pause_pid ]; then
kill -9 $(cat $pause_pid) 2> /dev/null
fi
run curl -s --max-time 3 --unix-socket $SERVICE_SOCK_ADDR http://podman/libpod/_ping
is "$output" "OK" "podman service responses normally"
is "$output" "OK" "podman service responds normally"
run_podman stop -t 0 $cid
run_podman rm -f $cid
}
# vim: filetype=sh

View file

@ -110,12 +110,10 @@ function check_shell_completion() {
is "$output" ".*localhost/$random_image_name:$random_image_tag${nl}" \
"$* $cmd: actual image listed in suggestions"
# check that we complete the image with and without tag after at least one char is typed
# check that we complete the image with tag after at least one char is typed
run_completion "$@" $cmd "${extra_args[@]}" "${random_image_name:0:1}"
is "$output" ".*$random_image_name:$random_image_tag${nl}" \
"$* $cmd: image name:tag included in suggestions"
is "$output" ".*$random_image_name${nl}" \
"$* $cmd: image name(w/o tag) included in suggestions"
# check that we complete the image id after at least two chars are typed
run_completion "$@" $cmd "${extra_args[@]}" "${random_image_id:0:2}"

View file

@ -69,11 +69,15 @@ RELABEL="system_u:object_r:container_file_t:s0"
TESTDIR=$PODMAN_TMPDIR/testdir
mkdir -p $TESTDIR
echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml
run_podman play kube - < $PODMAN_TMPDIR/test.yaml
if [ -e /usr/sbin/selinuxenabled -a /usr/sbin/selinuxenabled ]; then
run ls -Zd $TESTDIR
is "$output" ${RELABEL} "selinux relabel should have happened"
fi
run_podman stop -a -t 0
run_podman pod stop test_pod
run_podman pod rm -f test_pod
}
@ -86,6 +90,9 @@ RELABEL="system_u:object_r:container_file_t:s0"
run ls -Zd $TESTDIR
is "$output" ${RELABEL} "selinux relabel should have happened"
fi
run_podman stop -a -t 0
run_podman pod stop test_pod
run_podman pod rm -f test_pod
}
@ -102,12 +109,19 @@ RELABEL="system_u:object_r:container_file_t:s0"
infraID="$output"
run_podman container inspect --format "{{.HostConfig.NetworkMode}}" $infraID
is "$output" "slirp4netns" "network mode slirp4netns is set for the container"
run_podman stop -a -t 0
run_podman pod stop test_pod
run_podman pod rm -f test_pod
run_podman play kube --network none $PODMAN_TMPDIR/test.yaml
run_podman pod inspect --format {{.InfraContainerID}} "${lines[1]}"
infraID="$output"
run_podman container inspect --format "{{.HostConfig.NetworkMode}}" $infraID
is "$output" "none" "network mode none is set for the container"
run_podman stop -a -t 0
run_podman pod stop test_pod
run_podman pod rm -f test_pod
}
@ -149,6 +163,9 @@ _EOF
run_podman play kube --start=false $PODMAN_TMPDIR/test.yaml
run_podman inspect --format "{{ .Config.User }}" test_pod-test
is "$output" bin "expect container within pod to run as the bin user"
run_podman stop -a -t 0
run_podman pod stop test_pod
run_podman pod rm -f test_pod
run_podman rmi -f userimage:latest
}