summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/auto-update.go97
-rw-r--r--docs/source/markdown/podman-auto-update.1.md24
-rw-r--r--libpod/oci_conmon_exec_linux.go3
-rw-r--r--pkg/autoupdate/autoupdate.go238
-rw-r--r--pkg/bindings/containers/attach.go19
-rw-r--r--pkg/domain/entities/auto-update.go15
-rw-r--r--pkg/domain/entities/engine_container.go2
-rw-r--r--pkg/domain/infra/abi/auto-update.go5
-rw-r--r--pkg/domain/infra/tunnel/auto-update.go2
-rw-r--r--test/apiv2/20-containers.at8
-rw-r--r--test/apiv2/30-volumes.at7
-rw-r--r--test/system/075-exec.bats2
-rw-r--r--test/system/250-systemd.bats2
-rw-r--r--test/system/255-auto-update.bats13
-rw-r--r--test/system/500-networking.bats1
15 files changed, 302 insertions, 136 deletions
diff --git a/cmd/podman/auto-update.go b/cmd/podman/auto-update.go
index 99226790f..6ccf4e167 100644
--- a/cmd/podman/auto-update.go
+++ b/cmd/podman/auto-update.go
@@ -1,10 +1,15 @@
package main
import (
+ "encoding/json"
"fmt"
+ "os"
+ "strings"
"github.com/containers/common/pkg/auth"
"github.com/containers/common/pkg/completion"
+ "github.com/containers/common/pkg/report"
+ "github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/errorhandling"
@@ -12,8 +17,13 @@ import (
"github.com/spf13/cobra"
)
+type cliAutoUpdateOptions struct {
+ entities.AutoUpdateOptions
+ format string
+}
+
var (
- autoUpdateOptions = entities.AutoUpdateOptions{}
+ autoUpdateOptions = cliAutoUpdateOptions{}
autoUpdateDescription = `Auto update containers according to their auto-update policy.
Auto-update policies are specified with the "io.containers.autoupdate" label.
@@ -42,6 +52,9 @@ func init() {
authfileFlagName := "authfile"
flags.StringVar(&autoUpdateOptions.Authfile, authfileFlagName, auth.GetDefaultAuthFile(), "Path to the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
_ = autoUpdateCommand.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault)
+
+ flags.StringVar(&autoUpdateOptions.format, "format", "", "Change the output format to JSON or a Go template")
+ _ = autoUpdateCommand.RegisterFlagCompletionFunc("format", common.AutocompleteFormat(autoUpdateOutput{}))
}
func autoUpdate(cmd *cobra.Command, args []string) error {
@@ -49,11 +62,83 @@ func autoUpdate(cmd *cobra.Command, args []string) error {
// Backwards compat. System tests expect this error string.
return errors.Errorf("`%s` takes no arguments", cmd.CommandPath())
}
- report, failures := registry.ContainerEngine().AutoUpdate(registry.GetContext(), autoUpdateOptions)
- if report != nil {
- for _, unit := range report.Units {
- fmt.Println(unit)
- }
+
+ allReports, failures := registry.ContainerEngine().AutoUpdate(registry.GetContext(), autoUpdateOptions.AutoUpdateOptions)
+ if allReports == nil {
+ return errorhandling.JoinErrors(failures)
+ }
+
+ if err := writeTemplate(allReports, autoUpdateOptions.format); err != nil {
+ failures = append(failures, err)
}
+
return errorhandling.JoinErrors(failures)
}
+
+type autoUpdateOutput struct {
+ Unit string
+ Container string
+ ContainerName string
+ ContainerID string
+ Image string
+ Policy string
+ Updated string
+}
+
+func reportsToOutput(allReports []*entities.AutoUpdateReport) []autoUpdateOutput {
+ output := make([]autoUpdateOutput, len(allReports))
+ for i, r := range allReports {
+ output[i] = autoUpdateOutput{
+ Unit: r.SystemdUnit,
+ Container: fmt.Sprintf("%s (%s)", r.ContainerID[:12], r.ContainerName),
+ ContainerName: r.ContainerName,
+ ContainerID: r.ContainerID,
+ Image: r.ImageName,
+ Policy: r.Policy,
+ Updated: r.Updated,
+ }
+ }
+ return output
+}
+
+func writeTemplate(allReports []*entities.AutoUpdateReport, inputFormat string) error {
+ var format string
+ var printHeader bool
+
+ output := reportsToOutput(allReports)
+ switch inputFormat {
+ case "":
+ rows := []string{"{{.Unit}}", "{{.Container}}", "{{.Image}}", "{{.Policy}}", "{{.Updated}}"}
+ format = "{{range . }}" + strings.Join(rows, "\t") + "\n{{end -}}"
+ printHeader = true
+ case "json":
+ prettyJSON, err := json.MarshalIndent(output, "", " ")
+ if err != nil {
+ return err
+ }
+ fmt.Println(string(prettyJSON))
+ return nil
+ default:
+ format = "{{range . }}" + inputFormat + "\n{{end -}}"
+ }
+
+ tmpl, err := report.NewTemplate("auto-update").Parse(format)
+ if err != nil {
+ return err
+ }
+
+ w, err := report.NewWriterDefault(os.Stdout)
+ if err != nil {
+ return err
+ }
+ defer w.Flush()
+
+ if printHeader {
+ headers := report.Headers(autoUpdateOutput{}, nil)
+ if err := tmpl.Execute(w, headers); err != nil {
+ return err
+ }
+ }
+
+ return tmpl.Execute(w, output)
+}
diff --git a/docs/source/markdown/podman-auto-update.1.md b/docs/source/markdown/podman-auto-update.1.md
index 24b910470..4f2608be4 100644
--- a/docs/source/markdown/podman-auto-update.1.md
+++ b/docs/source/markdown/podman-auto-update.1.md
@@ -41,6 +41,22 @@ If the authorization state is not found there, `$HOME/.docker/config.json` is ch
Note: There is also the option to override the default path of the authentication file by setting the `REGISTRY_AUTH_FILE` environment variable. This can be done with **export REGISTRY_AUTH_FILE=_path_**.
+#### **--format**=*format*
+
+Change the default output format. This can be of a supported type like 'json' or a Go template.
+Valid placeholders for the Go template are listed below:
+
+| **Placeholder** | **Description** |
+| --------------- | -------------------------------------- |
+| .Unit | Name of the systemd unit |
+| .ContainerName | Name of the container |
+| .ContainerID | ID of the container |
+| .Container | ID and name of the container |
+| .Image | Name of the image |
+| .Policy | Auto-update policy of the container |
+| .Updated | Update status: true,false,failed |
+
+
## EXAMPLES
Autoupdate with registry policy
@@ -53,7 +69,7 @@ bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d
### Generate a systemd unit for this container
$ podman generate systemd --new --files bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d
-/home/user/containers/libpod/container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service
+/home/user/container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service
### Load the new systemd unit and start it
$ mv ./container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service ~/.config/systemd/user
@@ -67,7 +83,7 @@ $ systemctl --user start container-bc219740a210455fa27deacc96d50a9e20516492f1417
### Auto-update the container
$ podman auto-update
-container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service
+[...]
```
Autoupdate with local policy
@@ -80,7 +96,7 @@ be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338
### Generate a systemd unit for this container
$ podman generate systemd --new --files be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338
-/home/user/containers/libpod/container-be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338.service
+/home/user/container-be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338.service
### Load the new systemd unit and start it
$ mv ./container-be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338.service ~/.config/systemd/user
@@ -102,7 +118,7 @@ $ podman commit --change CMD=/bin/bash inspiring_galileo busybox:latest
### Auto-update the container
$ podman auto-update
-container-be0889fd06f252a2e5141b37072c6bada68563026cb2b2649f53394d87ccc338.service
+[...]
```
## SEE ALSO
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
index 09d3d1833..05a4e19b0 100644
--- a/libpod/oci_conmon_exec_linux.go
+++ b/libpod/oci_conmon_exec_linux.go
@@ -610,6 +610,9 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp
_, err := utils.CopyDetachable(conn, httpBuf, detachKeys)
logrus.Debugf("STDIN copy completed")
stdinChan <- err
+ if connErr := conn.CloseWrite(); connErr != nil {
+ logrus.Errorf("Unable to close conn: %v", connErr)
+ }
}()
}
diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go
index 0a13e7e74..fd95c319c 100644
--- a/pkg/autoupdate/autoupdate.go
+++ b/pkg/autoupdate/autoupdate.go
@@ -9,12 +9,13 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
- "github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/systemd"
systemdDefine "github.com/containers/podman/v3/pkg/systemd/define"
+ "github.com/coreos/go-systemd/v22/dbus"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -119,7 +120,7 @@ func ValidateImageReference(imageName string) error {
//
// It returns a slice of successfully restarted systemd units and a slice of
// errors encountered during auto update.
-func AutoUpdate(runtime *libpod.Runtime, options Options) ([]string, []error) {
+func AutoUpdate(ctx context.Context, runtime *libpod.Runtime, options Options) ([]*entities.AutoUpdateReport, []error) {
// Create a map from `image ID -> []*Container`.
containerMap, errs := imageContainersMap(runtime)
if len(containerMap) == 0 {
@@ -130,7 +131,7 @@ func AutoUpdate(runtime *libpod.Runtime, options Options) ([]string, []error) {
listOptions := &libimage.ListImagesOptions{
Filters: []string{"readonly=false"},
}
- imagesSlice, err := runtime.LibimageRuntime().ListImages(context.Background(), nil, listOptions)
+ imagesSlice, err := runtime.LibimageRuntime().ListImages(ctx, nil, listOptions)
if err != nil {
return nil, []error{err}
}
@@ -147,8 +148,8 @@ func AutoUpdate(runtime *libpod.Runtime, options Options) ([]string, []error) {
}
defer conn.Close()
- // Update images.
- containersToRestart := []*libpod.Container{}
+ // Update all images/container according to their auto-update policy.
+ var allReports []*entities.AutoUpdateReport
updatedRawImages := make(map[string]bool)
for imageID, policyMapper := range containerMap {
image, exists := imageMap[imageID]
@@ -156,76 +157,139 @@ func AutoUpdate(runtime *libpod.Runtime, options Options) ([]string, []error) {
errs = append(errs, errors.Errorf("container image ID %q not found in local storage", imageID))
return nil, errs
}
- // Now we have to check if the image of any containers must be updated.
- // Note that the image ID is NOT enough for this check as a given image
- // may have multiple tags.
- for _, registryCtr := range policyMapper[PolicyRegistryImage] {
- cid := registryCtr.ID()
- rawImageName := registryCtr.RawImageName()
- if rawImageName == "" {
- errs = append(errs, errors.Errorf("error registry auto-updating container %q: raw-image name is empty", cid))
- }
- readAuthenticationPath(registryCtr, options)
- needsUpdate, err := newerRemoteImageAvailable(runtime, image, rawImageName, options)
+
+ for _, ctr := range policyMapper[PolicyRegistryImage] {
+ report, err := autoUpdateRegistry(ctx, image, ctr, updatedRawImages, &options, conn, runtime)
if err != nil {
- errs = append(errs, errors.Wrapf(err, "error registry auto-updating container %q: image check for %q failed", cid, rawImageName))
- continue
+ errs = append(errs, err)
}
-
- if needsUpdate {
- logrus.Infof("Auto-updating container %q using registry image %q", cid, rawImageName)
- if _, updated := updatedRawImages[rawImageName]; !updated {
- _, err = updateImage(runtime, rawImageName, options)
- if err != nil {
- errs = append(errs, errors.Wrapf(err, "error registry auto-updating container %q: image update for %q failed", cid, rawImageName))
- continue
- }
- updatedRawImages[rawImageName] = true
- }
- containersToRestart = append(containersToRestart, registryCtr)
+ if report != nil {
+ allReports = append(allReports, report)
}
}
- for _, localCtr := range policyMapper[PolicyLocalImage] {
- cid := localCtr.ID()
- rawImageName := localCtr.RawImageName()
- if rawImageName == "" {
- errs = append(errs, errors.Errorf("error locally auto-updating container %q: raw-image name is empty", cid))
- }
- // This avoids restarting containers unnecessarily.
- needsUpdate, err := newerLocalImageAvailable(runtime, image, rawImageName)
+ for _, ctr := range policyMapper[PolicyLocalImage] {
+ report, err := autoUpdateLocally(ctx, image, ctr, &options, conn, runtime)
if err != nil {
- errs = append(errs, errors.Wrapf(err, "error locally auto-updating container %q: image check for %q failed", cid, rawImageName))
- continue
+ errs = append(errs, err)
}
-
- if needsUpdate {
- logrus.Infof("Auto-updating container %q using local image %q", cid, rawImageName)
- containersToRestart = append(containersToRestart, localCtr)
+ if report != nil {
+ allReports = append(allReports, report)
}
}
}
- // Restart containers.
- updatedUnits := []string{}
- for _, ctr := range containersToRestart {
- labels := ctr.Labels()
- unit, exists := labels[systemdDefine.EnvVariable]
- if !exists {
- // Shouldn't happen but let's be sure of it.
- errs = append(errs, errors.Errorf("error auto-updating container %q: no %s label found", ctr.ID(), systemdDefine.EnvVariable))
- continue
- }
- _, err := conn.RestartUnit(unit, "replace", nil)
- if err != nil {
- errs = append(errs, errors.Wrapf(err, "error auto-updating container %q: restarting systemd unit %q failed", ctr.ID(), unit))
- continue
+ return allReports, errs
+}
+
+// autoUpdateRegistry updates the image/container according to the "registry" policy.
+func autoUpdateRegistry(ctx context.Context, image *libimage.Image, ctr *libpod.Container, updatedRawImages map[string]bool, options *Options, conn *dbus.Conn, runtime *libpod.Runtime) (*entities.AutoUpdateReport, error) {
+ cid := ctr.ID()
+ rawImageName := ctr.RawImageName()
+ if rawImageName == "" {
+ return nil, errors.Errorf("error registry auto-updating container %q: raw-image name is empty", cid)
+ }
+
+ labels := ctr.Labels()
+ unit, exists := labels[systemdDefine.EnvVariable]
+ if !exists {
+ return nil, errors.Errorf("error auto-updating container %q: no %s label found", ctr.ID(), systemdDefine.EnvVariable)
+ }
+
+ report := &entities.AutoUpdateReport{
+ ContainerID: cid,
+ ContainerName: ctr.Name(),
+ ImageName: rawImageName,
+ Policy: PolicyRegistryImage,
+ SystemdUnit: unit,
+ Updated: "failed",
+ }
+
+ if _, updated := updatedRawImages[rawImageName]; updated {
+ logrus.Infof("Auto-updating container %q using registry image %q", cid, rawImageName)
+ if err := restartSystemdUnit(ctr, unit, conn); err != nil {
+ return report, err
}
- logrus.Infof("Successfully restarted systemd unit %q", unit)
- updatedUnits = append(updatedUnits, unit)
+ report.Updated = "true"
+ return report, nil
+ }
+
+ authfile := getAuthfilePath(ctr, options)
+ needsUpdate, err := newerRemoteImageAvailable(ctx, runtime, image, rawImageName, authfile)
+ if err != nil {
+ return report, errors.Wrapf(err, "error registry auto-updating container %q: image check for %q failed", cid, rawImageName)
+ }
+
+ if !needsUpdate {
+ report.Updated = "false"
+ return report, nil
+ }
+
+ if _, err := updateImage(ctx, runtime, rawImageName, options); err != nil {
+ return report, errors.Wrapf(err, "error registry auto-updating container %q: image update for %q failed", cid, rawImageName)
+ }
+ updatedRawImages[rawImageName] = true
+
+ logrus.Infof("Auto-updating container %q using registry image %q", cid, rawImageName)
+ if err := restartSystemdUnit(ctr, unit, conn); err != nil {
+ return report, err
}
- return updatedUnits, errs
+ report.Updated = "true"
+ return report, nil
+}
+
+// autoUpdateRegistry updates the image/container according to the "local" policy.
+func autoUpdateLocally(ctx context.Context, image *libimage.Image, ctr *libpod.Container, options *Options, conn *dbus.Conn, runtime *libpod.Runtime) (*entities.AutoUpdateReport, error) {
+ cid := ctr.ID()
+ rawImageName := ctr.RawImageName()
+ if rawImageName == "" {
+ return nil, errors.Errorf("error locally auto-updating container %q: raw-image name is empty", cid)
+ }
+
+ labels := ctr.Labels()
+ unit, exists := labels[systemdDefine.EnvVariable]
+ if !exists {
+ return nil, errors.Errorf("error auto-updating container %q: no %s label found", ctr.ID(), systemdDefine.EnvVariable)
+ }
+
+ report := &entities.AutoUpdateReport{
+ ContainerID: cid,
+ ContainerName: ctr.Name(),
+ ImageName: rawImageName,
+ Policy: PolicyLocalImage,
+ SystemdUnit: unit,
+ Updated: "failed",
+ }
+
+ needsUpdate, err := newerLocalImageAvailable(runtime, image, rawImageName)
+ if err != nil {
+ return report, errors.Wrapf(err, "error locally auto-updating container %q: image check for %q failed", cid, rawImageName)
+ }
+
+ if !needsUpdate {
+ report.Updated = "false"
+ return report, nil
+ }
+
+ logrus.Infof("Auto-updating container %q using local image %q", cid, rawImageName)
+ if err := restartSystemdUnit(ctr, unit, conn); err != nil {
+ return report, err
+ }
+
+ report.Updated = "true"
+ return report, nil
+}
+
+// restartSystemdUnit restarts the systemd unit the container is running in.
+func restartSystemdUnit(ctr *libpod.Container, unit string, conn *dbus.Conn) error {
+ _, err := conn.RestartUnit(unit, "replace", nil)
+ if err != nil {
+ return errors.Wrapf(err, "error auto-updating container %q: restarting systemd unit %q failed", ctr.ID(), unit)
+ }
+
+ logrus.Infof("Successfully restarted systemd unit %q of container %q", unit, ctr.ID())
+ return nil
}
// imageContainersMap generates a map[image ID] -> [containers using the image]
@@ -280,52 +344,25 @@ func imageContainersMap(runtime *libpod.Runtime) (map[string]policyMapper, []err
return containerMap, errors
}
-// readAuthenticationPath reads a container's labels and reads authentication path into options
-func readAuthenticationPath(ctr *libpod.Container, options Options) {
+// getAuthfilePath returns an authfile path, if set. The authfile label in the
+// container, if set, as precedence over the one set in the options.
+func getAuthfilePath(ctr *libpod.Container, options *Options) string {
labels := ctr.Labels()
authFilePath, exists := labels[AuthfileLabel]
if exists {
- options.Authfile = authFilePath
+ return authFilePath
}
+ return options.Authfile
}
// newerRemoteImageAvailable returns true if there corresponding image on the remote
// registry is newer.
-func newerRemoteImageAvailable(runtime *libpod.Runtime, img *libimage.Image, origName string, options Options) (bool, error) {
+func newerRemoteImageAvailable(ctx context.Context, runtime *libpod.Runtime, img *libimage.Image, origName string, authfile string) (bool, error) {
remoteRef, err := docker.ParseReference("//" + origName)
if err != nil {
return false, err
}
-
- data, err := img.Inspect(context.Background(), false)
- if err != nil {
- return false, err
- }
-
- sys := runtime.SystemContext()
- sys.AuthFilePath = options.Authfile
-
- // We need to account for the arch that the image uses. It seems
- // common on ARM to tweak this option to pull the correct image. See
- // github.com/containers/podman/issues/6613.
- sys.ArchitectureChoice = data.Architecture
-
- remoteImg, err := remoteRef.NewImage(context.Background(), sys)
- if err != nil {
- return false, err
- }
-
- rawManifest, _, err := remoteImg.Manifest(context.Background())
- if err != nil {
- return false, err
- }
-
- remoteDigest, err := manifest.Digest(rawManifest)
- if err != nil {
- return false, err
- }
-
- return img.Digest().String() != remoteDigest.String(), nil
+ return img.HasDifferentDigest(ctx, remoteRef)
}
// newerLocalImageAvailable returns true if the container and local image have different digests
@@ -334,21 +371,16 @@ func newerLocalImageAvailable(runtime *libpod.Runtime, img *libimage.Image, rawI
if err != nil {
return false, err
}
-
- localDigest := localImg.Digest().String()
-
- ctrDigest := img.Digest().String()
-
- return localDigest != ctrDigest, nil
+ return localImg.Digest().String() != img.Digest().String(), nil
}
// updateImage pulls the specified image.
-func updateImage(runtime *libpod.Runtime, name string, options Options) (*libimage.Image, error) {
+func updateImage(ctx context.Context, runtime *libpod.Runtime, name string, options *Options) (*libimage.Image, error) {
pullOptions := &libimage.PullOptions{}
pullOptions.AuthFilePath = options.Authfile
pullOptions.Writer = os.Stderr
- pulledImages, err := runtime.LibimageRuntime().Pull(context.Background(), name, config.PullPolicyAlways, pullOptions)
+ pulledImages, err := runtime.LibimageRuntime().Pull(ctx, name, config.PullPolicyAlways, pullOptions)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index cc12c8ab7..01c14d350 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -25,6 +25,12 @@ import (
"golang.org/x/crypto/ssh/terminal"
)
+// The CloseWriter interface is used to determine whether we can do a one-sided
+// close of a hijacked connection.
+type CloseWriter interface {
+ CloseWrite() error
+}
+
// Attach attaches to a running container
func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool, options *AttachOptions) error {
if options == nil {
@@ -161,6 +167,12 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri
logrus.Error("failed to write input to service: " + err.Error())
}
stdinChan <- err
+
+ if closeWrite, ok := socket.(CloseWriter); ok {
+ if err := closeWrite.CloseWrite(); err != nil {
+ logrus.Warnf("Failed to close STDIN for writing: %v", err)
+ }
+ }
}()
}
@@ -485,6 +497,13 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar
if err != nil {
logrus.Error("failed to write input to service: " + err.Error())
}
+
+ if closeWrite, ok := socket.(CloseWriter); ok {
+ logrus.Debugf("Closing STDIN")
+ if err := closeWrite.CloseWrite(); err != nil {
+ logrus.Warnf("Failed to close STDIN for writing: %v", err)
+ }
+ }
}()
}
diff --git a/pkg/domain/entities/auto-update.go b/pkg/domain/entities/auto-update.go
index c51158816..d74462b86 100644
--- a/pkg/domain/entities/auto-update.go
+++ b/pkg/domain/entities/auto-update.go
@@ -8,6 +8,17 @@ type AutoUpdateOptions struct {
// AutoUpdateReport contains the results from running auto-update.
type AutoUpdateReport struct {
- // Units - the restarted systemd units during auto-update.
- Units []string
+ // ID of the container *before* an update.
+ ContainerID string
+ // Name of the container *before* an update.
+ ContainerName string
+ // Name of the image.
+ ImageName string
+ // The configured auto-update policy.
+ Policy string
+ // SystemdUnit running a container configured for auto updates.
+ SystemdUnit string
+ // Indicates whether the image was updated and the container (and
+ // systemd unit) restarted.
+ Updated string
}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 28e5160db..62e83fab3 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -14,7 +14,7 @@ import (
type ContainerCopyFunc func() error
type ContainerEngine interface {
- AutoUpdate(ctx context.Context, options AutoUpdateOptions) (*AutoUpdateReport, []error)
+ AutoUpdate(ctx context.Context, options AutoUpdateOptions) ([]*AutoUpdateReport, []error)
Config(ctx context.Context) (*config.Config, error)
ContainerAttach(ctx context.Context, nameOrID string, options AttachOptions) error
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
diff --git a/pkg/domain/infra/abi/auto-update.go b/pkg/domain/infra/abi/auto-update.go
index c9d7f2130..daa882ecf 100644
--- a/pkg/domain/infra/abi/auto-update.go
+++ b/pkg/domain/infra/abi/auto-update.go
@@ -7,11 +7,10 @@ import (
"github.com/containers/podman/v3/pkg/domain/entities"
)
-func (ic *ContainerEngine) AutoUpdate(ctx context.Context, options entities.AutoUpdateOptions) (*entities.AutoUpdateReport, []error) {
+func (ic *ContainerEngine) AutoUpdate(ctx context.Context, options entities.AutoUpdateOptions) ([]*entities.AutoUpdateReport, []error) {
// Convert the entities options to the autoupdate ones. We can't use
// them in the entities package as low-level packages must not leak
// into the remote client.
autoOpts := autoupdate.Options{Authfile: options.Authfile}
- units, failures := autoupdate.AutoUpdate(ic.Libpod, autoOpts)
- return &entities.AutoUpdateReport{Units: units}, failures
+ return autoupdate.AutoUpdate(ctx, ic.Libpod, autoOpts)
}
diff --git a/pkg/domain/infra/tunnel/auto-update.go b/pkg/domain/infra/tunnel/auto-update.go
index 41165cc74..038c60537 100644
--- a/pkg/domain/infra/tunnel/auto-update.go
+++ b/pkg/domain/infra/tunnel/auto-update.go
@@ -7,6 +7,6 @@ import (
"github.com/pkg/errors"
)
-func (ic *ContainerEngine) AutoUpdate(ctx context.Context, options entities.AutoUpdateOptions) (*entities.AutoUpdateReport, []error) {
+func (ic *ContainerEngine) AutoUpdate(ctx context.Context, options entities.AutoUpdateOptions) ([]*entities.AutoUpdateReport, []error) {
return nil, []error{errors.New("not implemented")}
}
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index ef51757c9..c5b2f5ec1 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -211,15 +211,11 @@ t GET containers/$cid/json 200 \
t POST containers/create Image=$IMAGE Entrypoint='["top"]' 201 \
.Id~[0-9a-f]\\{64\\}
cid_top=$(jq -r '.Id' <<<"$output")
-network_expect="{}"
-if root; then
- network_expect='.podman.NetworkID=podman'
-fi
t GET containers/${cid_top}/json 200 \
.Config.Entrypoint[0]="top" \
.Config.Cmd='[]' \
- .Path="top"
- .NetworkSettings.Networks="$network_expect"
+ .Path="top" \
+ .NetworkSettings.Networks.podman.NetworkID=podman
t POST containers/${cid_top}/start 204
# make sure the container is running
t GET containers/${cid_top}/json 200 \
diff --git a/test/apiv2/30-volumes.at b/test/apiv2/30-volumes.at
index 5feceea7b..b639e05f9 100644
--- a/test/apiv2/30-volumes.at
+++ b/test/apiv2/30-volumes.at
@@ -13,13 +13,14 @@ t POST libpod/volumes/create name=foo1 201 \
.CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
.Labels={} \
.Options={}
+# TODO(mwhahaha): there might be a bug here since options is null and not {}
t POST volumes/create 201 \
- .Name~[0-9a-f]\\{64\\}
+ .Name~[0-9a-f]\\{64\\} \
.Driver=local \
- .Mountpoint=$volumepath/~[0-9a-f]\\{64\\}/_data \
+ .Mountpoint~$volumepath/[0-9a-f]\\{64\\}/_data \
.CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
.Labels={} \
- .Options={}
+ .Options=null
t POST libpod/volumes/create 201
t POST libpod/volumes/create \
Name=foo2 \
diff --git a/test/system/075-exec.bats b/test/system/075-exec.bats
index badf44c49..3e8c3c1ea 100644
--- a/test/system/075-exec.bats
+++ b/test/system/075-exec.bats
@@ -59,8 +59,6 @@ load helpers
# Issue #4785 - piping to exec statement - fixed in #4818
# Issue #5046 - piping to exec truncates results (actually a conmon issue)
@test "podman exec - cat from stdin" {
- skip_if_remote "FIXME: pending #7360"
-
run_podman run -d $IMAGE sh -c 'while [ ! -e /stop ]; do sleep 0.1;done'
cid="$output"
diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats
index 4ea192009..aafe385c8 100644
--- a/test/system/250-systemd.bats
+++ b/test/system/250-systemd.bats
@@ -119,7 +119,7 @@ function service_cleanup() {
# Run auto-update and check that it restarted the container
run_podman commit --change "CMD=/bin/bash" $cname $IMAGE
run_podman auto-update
- is $output $SERVICE_NAME "autoupdate local restarted container"
+ is "$output" ".*$SERVICE_NAME.*" "autoupdate local restarted container"
# All good. Stop service, clean up.
service_cleanup
diff --git a/test/system/255-auto-update.bats b/test/system/255-auto-update.bats
index 3713243d5..4959bb6aa 100644
--- a/test/system/255-auto-update.bats
+++ b/test/system/255-auto-update.bats
@@ -121,8 +121,10 @@ function _confirm_update() {
generate_service alpine image
_wait_service_ready container-$cname.service
- run_podman auto-update
+ run_podman auto-update --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
is "$output" "Trying to pull.*" "Image is updated."
+ is "$output" ".*container-$cname.service,quay.io/libpod/alpine:latest,true,registry.*" "Image is updated."
+
_confirm_update $cname $ori_image
}
@@ -151,10 +153,15 @@ function _confirm_update() {
@test "podman auto-update - label io.containers.autoupdate=local" {
generate_service localtest local
- podman commit --change CMD=/bin/bash $cname quay.io/libpod/localtest:latest
+ image=quay.io/libpod/localtest:latest
+ podman commit --change CMD=/bin/bash $cname $image
+ podman image inspect --format "{{.ID}}" $image
+ imageID="$output"
_wait_service_ready container-$cname.service
- run_podman auto-update
+ run_podman auto-update --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
+ is "$output" ".*container-$cname.service,quay.io/libpod/localtest:latest,true,local.*" "Image is updated."
+
_confirm_update $cname $ori_image
}
diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats
index d55a786f7..4feb57807 100644
--- a/test/system/500-networking.bats
+++ b/test/system/500-networking.bats
@@ -20,7 +20,6 @@ load helpers
# Copied from tsweeney's https://github.com/containers/podman/issues/4827
@test "podman networking: port on localhost" {
- skip_if_remote "FIXME: reevaluate this one after #7360 is fixed"
random_1=$(random_string 30)
random_2=$(random_string 30)