mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-09-10 01:27:54 +00:00
commit
f40474521b
16 changed files with 336 additions and 15 deletions
|
|
@ -5,7 +5,7 @@
|
|||
Podman (the POD MANager) is a tool for managing containers and images, volumes mounted into those containers, and pods made from groups of containers.
|
||||
Podman is based on libpod, a library for container lifecycle management that is also contained in this repository. The libpod library provides APIs for managing containers, pods, container images, and volumes.
|
||||
|
||||
* [Latest Version: 4.0.3](https://github.com/containers/podman/releases/tag/v4.0.3)
|
||||
* [Latest Version: 4.1.0](https://github.com/containers/podman/releases/tag/v4.1.0)
|
||||
* Latest Remote client for Windows
|
||||
* Latest Remote client for macOS
|
||||
* Latest Static Remote client for Linux
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## 4.1.0
|
||||
### Features
|
||||
- Podman now supports Docker Compose v2.2 and higher ([#11822](https://github.com/containers/podman/issues/11822)).
|
||||
- Podman now supports Docker Compose v2.2 and higher ([#11822](https://github.com/containers/podman/issues/11822)). Please note that it may be necessary to disable the use of Buildkit by setting the environment variable `DOCKER_BUILDKIT=0`.
|
||||
- A new container command has been added, `podman container clone`. This command makes a copy of an existing container, with the ability to change some settings (e.g. resource limits) while doing so.
|
||||
- A new machine command has been added, `podman machine inspect`. This command provides details on the configuration of machine VMs.
|
||||
- The `podman machine set` command can now change the CPUs, memory, and disk space available to machines after they were initially created, using the new `--cpus`, `--disk-size`, and `--memory` options ([#13633](https://github.com/containers/podman/issues/13633)).
|
||||
|
|
@ -52,12 +52,14 @@
|
|||
- Fixed a bug where containers created by the `podman play kube` command did not record the raw image name used to create containers.
|
||||
- Fixed a bug where VMs created by `podman machine` could not start containers which forwarded ports when run on a host with a proxy configured ([#13628](https://github.com/containers/podman/issues/13628)).
|
||||
- Fixed a bug where VMs created by the `podman machine` command could not be connected to when the username of the current user was sufficiently long ([#12751](https://github.com/containers/podman/issues/12751)).
|
||||
- Fixed a bug where the `podman system reset` command on Linux did not fully remove virtual machines created by `podman machine`.
|
||||
- Fixed a bug where the `podman machine rm` command would error when removing a VM that was never started ([#13834](https://github.com/containers/podman/issues/13834)).
|
||||
- Fixed a bug where the remote Podman client's `podman manifest push` command could not push to registries that required authentication ([#13629](https://github.com/containers/podman/issues/13629)).
|
||||
- Fixed a bug where containers joining a pod with volumes did not have the pod's volumes added ([#13548](https://github.com/containers/podman/issues/13548)).
|
||||
- Fixed a bug where the `podman version --format` command could not return the OS of the server ([#13690](https://github.com/containers/podman/issues/13690)).
|
||||
- Fixed a bug where the `podman play kube` command would error when a volume specified by a `configMap` already existed ([#13715](https://github.com/containers/podman/issues/13715)).
|
||||
- Fixed a bug where the `podman play kube` command did not respect the `hostNetwork` setting in Pod YAML ([#14015](https://github.com/containers/podman/issues/14015)).
|
||||
- Fixed a bug where the `podman play kube` command would, when the `--log-driver` flag was not specified, ignore Podman's default log driver ([#13781](https://github.com/containers/podman/issues/13781)).
|
||||
- Fixed a bug where the `podman generate kube` command could generate YAML with too-long labels ([#13962](https://github.com/containers/podman/issues/13962)).
|
||||
- Fixed a bug where the `podman logs --tail=1` command would fail when the log driver was `journald` and the container was restarted ([#13098](https://github.com/containers/podman/issues/13098)).
|
||||
- Fixed a bug where containers created from images with a healthcheck that did not specify an interval would never run their healthchecks ([#13912](https://github.com/containers/podman/issues/13912)).
|
||||
|
|
@ -65,6 +67,7 @@
|
|||
- Fixed a bug where the `--tls-verify option to the `remote Podman client's `podman build` command was nonfunctional.
|
||||
- Fixed a bug where the `podman pod inspect` command incorrectly reported whether the pod used the host's network ([#14028](https://github.com/containers/podman/issues/14028)).
|
||||
- Fixed a bug where Podman would, when run on WSL2, ports specified without an IP address (e.g. `-p 8080:8080`) would be bound to IPv6 addresses ([#12292](https://github.com/containers/podman/issues/12292)).
|
||||
- Fixed a bug where the remote Podman client's `podman info` could report an incorrect path to the socket used to access the Podman service ([#12023](https://github.com/containers/podman/issues/12023)).
|
||||
|
||||
### API
|
||||
- Containers created via the Libpod Create API that set a memory limit, but not a swap limit, will automatically have a swap limit set ([#13145](https://github.com/containers/podman/issues/13145)).
|
||||
|
|
@ -77,6 +80,10 @@
|
|||
### Misc
|
||||
- A number of dependencies have been pruned from the project, resulting in a significant reduction in the size of the Podman binary.
|
||||
- Using `podman play kube` on a YAML that only includes `configMap` objects (and no pods or deployments) now prints a much clearer error message.
|
||||
- Updated Buildah to v1.26.1
|
||||
- Updated the containers/storage library to v1.40.2
|
||||
- Updated the containers/image library to v5.21.1
|
||||
- Updated the containers/common library to v0.48.0
|
||||
|
||||
## 4.0.3
|
||||
### Security
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
|
|||
logDriverFlagName := "log-driver"
|
||||
createFlags.StringVar(
|
||||
&cf.LogDriver,
|
||||
logDriverFlagName, logDriver(),
|
||||
logDriverFlagName, LogDriver(),
|
||||
"Logging driver for the container",
|
||||
)
|
||||
_ = cmd.RegisterFlagCompletionFunc(logDriverFlagName, AutocompleteLogDriver)
|
||||
|
|
|
|||
|
|
@ -530,7 +530,7 @@ func volumes() []string {
|
|||
return nil
|
||||
}
|
||||
|
||||
func logDriver() string {
|
||||
func LogDriver() string {
|
||||
if !registry.IsRemote() {
|
||||
return containerConfig.Containers.LogDriver
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ func init() {
|
|||
_ = kubeCmd.RegisterFlagCompletionFunc(staticIPFlagName, completion.AutocompleteNone)
|
||||
|
||||
logDriverFlagName := "log-driver"
|
||||
flags.StringVar(&kubeOptions.LogDriver, logDriverFlagName, "", "Logging driver for the container")
|
||||
flags.StringVar(&kubeOptions.LogDriver, logDriverFlagName, common.LogDriver(), "Logging driver for the container")
|
||||
_ = kubeCmd.RegisterFlagCompletionFunc(logDriverFlagName, common.AutocompleteLogDriver)
|
||||
|
||||
logOptFlagName := "log-opt"
|
||||
|
|
|
|||
|
|
@ -288,6 +288,15 @@ func (c *Container) Config() *ContainerConfig {
|
|||
return nil
|
||||
}
|
||||
|
||||
if c != nil {
|
||||
networks, err := c.networks()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
returnConfig.Networks = networks
|
||||
}
|
||||
|
||||
return returnConfig
|
||||
}
|
||||
|
||||
|
|
@ -1260,7 +1269,10 @@ func (c *Container) NetworkMode() string {
|
|||
|
||||
// Unlocked accessor for networks
|
||||
func (c *Container) networks() (map[string]types.PerNetworkOptions, error) {
|
||||
return c.runtime.state.GetNetworks(c)
|
||||
if c != nil && c.runtime != nil && c.runtime.state != nil { // can fail if c.networks is called from the tests
|
||||
return c.runtime.state.GetNetworks(c)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// getInterfaceByName returns a formatted interface name for a given
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v4/libpod/define"
|
||||
|
|
@ -259,7 +260,7 @@ func redirectResponseToOutputStreams(outputStream, errorStream io.Writer, writeO
|
|||
}
|
||||
}
|
||||
}
|
||||
if er == io.EOF {
|
||||
if errors.Is(er, io.EOF) || errors.Is(er, syscall.ECONNRESET) {
|
||||
break
|
||||
}
|
||||
if er != nil {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,16 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
|
|||
password = authConf.Password
|
||||
}
|
||||
|
||||
logDriver := query.LogDriver
|
||||
if logDriver == "" {
|
||||
config, err := runtime.GetConfig()
|
||||
if err != nil {
|
||||
utils.Error(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
query.LogDriver = config.Containers.LogDriver
|
||||
}
|
||||
|
||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||
options := entities.PlayKubeOptions{
|
||||
Annotations: query.Annotations,
|
||||
|
|
|
|||
|
|
@ -1548,6 +1548,12 @@ func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts enti
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if len(spec.Networks) > 0 && pod.SharesNet() {
|
||||
logrus.Warning("resetting network config, cannot specify a network other than the pod's when sharing the net namespace")
|
||||
spec.Networks = nil
|
||||
spec.NetworkOptions = nil
|
||||
}
|
||||
|
||||
allNamespaces := []struct {
|
||||
isShared bool
|
||||
value *specgen.Namespace
|
||||
|
|
|
|||
76
pkg/domain/utils/utils_test.go
Normal file
76
pkg/domain/utils/utils_test.go
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestToLibpodFilters(t *testing.T) {
|
||||
good := url.Values{}
|
||||
good.Set("apple", "red")
|
||||
good.Set("banana", "yellow")
|
||||
good.Set("pear", "")
|
||||
goodResult := []string{"apple=red", "banana=yellow", "pear="}
|
||||
sort.Strings(goodResult)
|
||||
|
||||
empty := url.Values{}
|
||||
type args struct {
|
||||
f url.Values
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantFilters []string
|
||||
}{
|
||||
{
|
||||
name: "GoodURLValue",
|
||||
args: args{
|
||||
f: good,
|
||||
},
|
||||
wantFilters: goodResult,
|
||||
},
|
||||
{
|
||||
name: "Empty",
|
||||
args: args{
|
||||
f: empty,
|
||||
},
|
||||
wantFilters: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.ElementsMatchf(t, ToLibpodFilters(tt.args.f), tt.wantFilters, "ToLibpodFilters() = %v, want %v", ToLibpodFilters(tt.args.f), tt.wantFilters)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToURLValues(t *testing.T) {
|
||||
good := url.Values{}
|
||||
good.Set("apple", "red")
|
||||
good.Set("banana", "yellow")
|
||||
good.Set("pear", "")
|
||||
goodResult := []string{"apple=red", "banana=yellow", "pear="}
|
||||
|
||||
type args struct {
|
||||
f []string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantFilters url.Values
|
||||
}{
|
||||
{
|
||||
name: "Good",
|
||||
args: args{goodResult},
|
||||
wantFilters: good,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.EqualValuesf(t, ToURLValues(tt.args.f), tt.wantFilters, "ToURLValues() = %v, want %v", ToURLValues(tt.args.f), tt.wantFilters)
|
||||
})
|
||||
}
|
||||
}
|
||||
162
pkg/env/env_test.go
vendored
Normal file
162
pkg/env/env_test.go
vendored
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
package env
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSlice(t *testing.T) {
|
||||
goodMap := make(map[string]string, 0)
|
||||
goodMap["apple"] = "red"
|
||||
goodMap["banana"] = "yellow"
|
||||
goodMap["pear"] = ""
|
||||
goodResult := []string{"apple=red", "banana=yellow", "pear"}
|
||||
type args struct {
|
||||
m map[string]string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "Good",
|
||||
args: args{
|
||||
m: goodMap,
|
||||
},
|
||||
want: goodResult,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.ElementsMatchf(t, Slice(tt.args.m), tt.want, "Slice() = %v, want %v", Slice(tt.args.m), tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJoin(t *testing.T) {
|
||||
firstMap := make(map[string]string, 0)
|
||||
firstMap["apple"] = "red"
|
||||
secondMap := make(map[string]string, 0)
|
||||
secondMap["banana"] = "yellow"
|
||||
goodResult := make(map[string]string, 0)
|
||||
goodResult["apple"] = "red"
|
||||
goodResult["banana"] = "yellow"
|
||||
overrideResult := make(map[string]string, 0)
|
||||
overrideResult["apple"] = "green"
|
||||
overrideResult["banana"] = "yellow"
|
||||
overrideMap := make(map[string]string, 0)
|
||||
overrideMap["banana"] = "yellow"
|
||||
overrideMap["apple"] = "green"
|
||||
type args struct {
|
||||
base map[string]string
|
||||
override map[string]string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
name: "GoodJoin",
|
||||
args: args{
|
||||
base: firstMap,
|
||||
override: secondMap,
|
||||
},
|
||||
want: goodResult,
|
||||
},
|
||||
{
|
||||
name: "GoodOverride",
|
||||
args: args{
|
||||
base: firstMap,
|
||||
override: overrideMap,
|
||||
},
|
||||
want: overrideResult,
|
||||
},
|
||||
{
|
||||
name: "EmptyOverride",
|
||||
args: args{
|
||||
base: firstMap,
|
||||
override: nil,
|
||||
},
|
||||
want: firstMap,
|
||||
},
|
||||
{
|
||||
name: "EmptyBase",
|
||||
args: args{
|
||||
base: nil,
|
||||
override: firstMap,
|
||||
},
|
||||
want: firstMap,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Join(tt.args.base, tt.args.override)
|
||||
assert.EqualValuesf(t, got, tt.want, "Join() = %v, want %v", got, tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseEnv(t *testing.T) {
|
||||
good := make(map[string]string)
|
||||
|
||||
type args struct {
|
||||
env map[string]string
|
||||
line string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Good",
|
||||
args: args{
|
||||
env: good,
|
||||
line: "apple=red",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "GoodNoValue",
|
||||
args: args{
|
||||
env: good,
|
||||
line: "apple=",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "GoodNoKeyNoValue",
|
||||
args: args{
|
||||
env: good,
|
||||
line: "=",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "BadNoKey",
|
||||
args: args{
|
||||
env: good,
|
||||
line: "=foobar",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "BadOnlyDelim",
|
||||
args: args{
|
||||
env: good,
|
||||
line: "=",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := parseEnv(tt.args.env, tt.args.line); (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseEnv() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -501,6 +501,8 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID s
|
|||
_, mounts := c.SortUserVolumes(c.Spec())
|
||||
specg.Mounts = mounts
|
||||
specg.HostDeviceList = conf.DeviceHostSrc
|
||||
specg.Networks = conf.Networks
|
||||
|
||||
mapSecurityConfig(conf, specg)
|
||||
|
||||
if c.IsInfra() { // if we are creating this spec for a pod's infra ctr, map the compatible options
|
||||
|
|
|
|||
|
|
@ -175,13 +175,15 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
|
|||
return nil, nil, nil, errors.New("the given container could not be retrieved")
|
||||
}
|
||||
conf := c.Config()
|
||||
out, err := json.Marshal(conf.Spec.Linux)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
err = json.Unmarshal(out, runtimeSpec.Linux)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
if conf != nil && conf.Spec != nil && conf.Spec.Linux != nil {
|
||||
out, err := json.Marshal(conf.Spec.Linux)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
err = json.Unmarshal(out, runtimeSpec.Linux)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
if s.ResourceLimits != nil {
|
||||
switch {
|
||||
|
|
|
|||
|
|
@ -266,4 +266,30 @@ var _ = Describe("Podman container clone", func() {
|
|||
Expect(clone).ToNot(Exit(0))
|
||||
|
||||
})
|
||||
|
||||
It("podman container clone network passing", func() {
|
||||
networkCreate := podmanTest.Podman([]string{"network", "create", "testing123"})
|
||||
networkCreate.WaitWithDefaultTimeout()
|
||||
defer podmanTest.removeNetwork("testing123")
|
||||
Expect(networkCreate).To(Exit(0))
|
||||
run := podmanTest.Podman([]string{"run", "--network", "bridge", "-dt", ALPINE})
|
||||
run.WaitWithDefaultTimeout()
|
||||
Expect(run).To(Exit(0))
|
||||
|
||||
connect := podmanTest.Podman([]string{"network", "connect", "testing123", run.OutputToString()})
|
||||
connect.WaitWithDefaultTimeout()
|
||||
Expect(connect).To(Exit(0))
|
||||
|
||||
clone := podmanTest.Podman([]string{"container", "clone", run.OutputToString()})
|
||||
clone.WaitWithDefaultTimeout()
|
||||
Expect(clone).To(Exit(0))
|
||||
|
||||
inspect := podmanTest.Podman([]string{"inspect", clone.OutputToString()})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect).To(Exit(0))
|
||||
Expect(inspect.InspectContainerToJSON()[0].NetworkSettings.Networks).To(HaveLen(2))
|
||||
_, ok := inspect.InspectContainerToJSON()[0].NetworkSettings.Networks["testing123"]
|
||||
Expect(ok).To(BeTrue())
|
||||
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -278,3 +278,20 @@ status: {}
|
|||
run_podman 125 play kube - < $PODMAN_TMPDIR/test.yaml
|
||||
assert "$output" =~ "invalid annotation \"test\"=\"$RANDOMSTRING\"" "Expected to fail with annotation length greater than 63"
|
||||
}
|
||||
|
||||
@test "podman play kube - default log driver" {
|
||||
TESTDIR=$PODMAN_TMPDIR/testdir
|
||||
mkdir -p $TESTDIR
|
||||
echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml
|
||||
# Get the default log driver
|
||||
run_podman info --format "{{.Host.LogDriver}}"
|
||||
default_driver=$output
|
||||
|
||||
# Make sure that the default log driver is used
|
||||
run_podman play kube $PODMAN_TMPDIR/test.yaml
|
||||
run_podman inspect --format "{{.HostConfig.LogConfig.Type}}" test_pod-test
|
||||
is "$output" "$default_driver" "play kube uses default log driver"
|
||||
|
||||
run_podman stop -a -t 0
|
||||
run_podman pod rm -t 0 -f test_pod
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const (
|
|||
// NOTE: remember to bump the version at the top
|
||||
// of the top-level README.md file when this is
|
||||
// bumped.
|
||||
var Version = semver.MustParse("4.1.0-dev")
|
||||
var Version = semver.MustParse("4.1.1-dev")
|
||||
|
||||
// See https://docs.docker.com/engine/api/v1.40/
|
||||
// libpod compat handlers are expected to honor docker API versions
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue