properly implement pull-error event status

Commit 03f6589f3 added basic support for pull-error event from libimage
but it contains several problems:
1. storing the error as error type prevents it from being unmarshalled,
   thus change it to a string
2. the error was never propagated from the libimage event to the podman
   event struct
3. the error message was not wired into the cli and API

This commit fixes these problems.

Fixes #21458

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger
2024-03-04 18:36:07 +01:00
parent 3e1d2ab874
commit 9ee96a9569
10 changed files with 57 additions and 24 deletions

View File

@ -1420,10 +1420,10 @@ func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete strin
events.Exited.String(), events.Export.String(), events.Import.String(), events.Init.String(), events.Kill.String(),
events.LoadFromArchive.String(), events.Mount.String(), events.NetworkConnect.String(),
events.NetworkDisconnect.String(), events.Pause.String(), events.Prune.String(), events.Pull.String(),
events.Push.String(), events.Refresh.String(), events.Remove.String(), events.Rename.String(),
events.Renumber.String(), events.Restart.String(), events.Restore.String(), events.Save.String(),
events.Start.String(), events.Stop.String(), events.Sync.String(), events.Tag.String(), events.Unmount.String(),
events.Unpause.String(), events.Untag.String(),
events.PullError.String(), events.Push.String(), events.Refresh.String(), events.Remove.String(),
events.Rename.String(), events.Renumber.String(), events.Restart.String(), events.Restore.String(),
events.Save.String(), events.Start.String(), events.Stop.String(), events.Sync.String(), events.Tag.String(),
events.Unmount.String(), events.Unpause.String(), events.Untag.String(),
}, cobra.ShellCompDirectiveNoFileComp
}
eventTypes := func(_ string) ([]string, cobra.ShellCompDirective) {

View File

@ -71,6 +71,8 @@ type Event struct {
Type events.Type
// Health status of the current container
HealthStatus string `json:"health_status,omitempty"`
// Error code for certain events involving errors.
Error string `json:",omitempty"`
events.Details
}
@ -88,6 +90,7 @@ func newEventFromLibpodEvent(e *events.Event) Event {
HealthStatus: e.HealthStatus,
Details: e.Details,
TimeNano: e.Time.UnixNano(),
Error: e.Error,
}
}

View File

@ -61,6 +61,7 @@ The *image* event type reports the following statuses:
* loadFromArchive,
* mount
* pull
* pull-error
* push
* remove
* save
@ -104,21 +105,22 @@ In the case where an ID is used, the ID may be in its full or shortened form. T
Format the output to JSON Lines or using the given Go template.
| **Placeholder** | **Description** |
|-------------------------|----------------------------------------------- ---|
| .Attributes ... | created_at, _by, labels, and more (map[]) |
| .ContainerExitCode | Exit code (int) |
| .ContainerInspectData | Payload of the container's inspect |
| .HealthStatus | Health Status (string) |
| .ID | Container ID (full 64-bit SHA) |
| .Image | Name of image being run (string) |
| .Name | Container name (string) |
| .Network | Name of network being used (string) |
| .PodID | ID of pod associated with container, if any |
| .Status | Event status (e.g., create, start, died, ...) |
| .Time | Event timestamp (string) |
| .TimeNano | Event timestamp with nanosecond precision (int64) |
| .Type | Event type (e.g., image, container, pod, ...) |
| **Placeholder** | **Description** |
| --------------------- | -------------------------------------------------------------------- |
| .Attributes ... | created_at, _by, labels, and more (map[]) |
| .ContainerExitCode | Exit code (int) |
| .ContainerInspectData | Payload of the container's inspect |
| .Error | Error message in case the event status is an error (e.g. pull-error) |
| .HealthStatus | Health Status (string) |
| .ID | Container ID (full 64-bit SHA) |
| .Image | Name of image being run (string) |
| .Name | Container name (string) |
| .Network | Name of network being used (string) |
| .PodID | ID of pod associated with container, if any |
| .Status | Event status (e.g., create, start, died, ...) |
| .Time | Event timestamp (string) |
| .TimeNano | Event timestamp with nanosecond precision (int64) |
| .Type | Event type (e.g., image, container, pod, ...) |
#### **--help**

View File

@ -42,7 +42,7 @@ type Event struct {
// Health status of the current container
HealthStatus string `json:"health_status,omitempty"`
// Error code for certain events involving errors.
Error error `json:"error,omitempty"`
Error string `json:"error,omitempty"`
Details
}

View File

@ -90,6 +90,9 @@ func (e *Event) ToHumanReadable(truncate bool) string {
humanFormat = fmt.Sprintf("%s %s %s %s (container=%s, name=%s)", e.Time, e.Type, e.Status, id, id, e.Network)
case Image:
humanFormat = fmt.Sprintf("%s %s %s %s %s", e.Time, e.Type, e.Status, id, e.Name)
if e.Error != "" {
humanFormat += " " + e.Error
}
case System:
if e.Name != "" {
humanFormat = fmt.Sprintf("%s %s %s %s", e.Time, e.Type, e.Status, e.Name)

View File

@ -43,8 +43,8 @@ func (e EventJournalD) Write(ee Event) error {
case Image:
m["PODMAN_NAME"] = ee.Name
m["PODMAN_ID"] = ee.ID
if ee.Error != nil {
m["ERROR"] = ee.Error.Error()
if ee.Error != "" {
m["ERROR"] = ee.Error
}
case Container, Pod:
m["PODMAN_IMAGE"] = ee.Image
@ -231,8 +231,8 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) {
newEvent.Network = entry.Fields["PODMAN_NETWORK_NAME"]
case Image:
newEvent.ID = entry.Fields["PODMAN_ID"]
if _, ok := entry.Fields["ERROR"]; ok {
newEvent.Error = errors.New(entry.Fields["ERROR"])
if val, ok := entry.Fields["ERROR"]; ok {
newEvent.Error = val
}
}
return &newEvent, nil

View File

@ -737,6 +737,9 @@ func (r *Runtime) libimageEvents() {
Time: libimageEvent.Time,
Type: events.Image,
}
if libimageEvent.Error != nil {
e.Error = libimageEvent.Error.Error()
}
if err := r.eventer.Write(e); err != nil {
logrus.Errorf("Unable to write image event: %q", err)
}

View File

@ -33,11 +33,13 @@ func ConvertToLibpodEvent(e Event) *libpodEvents.Event {
name := e.Actor.Attributes["name"]
network := e.Actor.Attributes["network"]
podID := e.Actor.Attributes["podId"]
errorString := e.Actor.Attributes["error"]
details := e.Actor.Attributes
delete(details, "image")
delete(details, "name")
delete(details, "network")
delete(details, "podId")
delete(details, "error")
delete(details, "containerExitCode")
return &libpodEvents.Event{
ContainerExitCode: &exitCode,
@ -49,6 +51,7 @@ func ConvertToLibpodEvent(e Event) *libpodEvents.Event {
Time: time.Unix(0, e.TimeNano),
Type: t,
HealthStatus: e.HealthStatus,
Error: errorString,
Details: libpodEvents.Details{
PodID: podID,
Attributes: details,
@ -71,6 +74,9 @@ func ConvertToEntitiesEvent(e libpodEvents.Event) *types.Event {
if e.Network != "" {
attributes["network"] = e.Network
}
if e.Error != "" {
attributes["error"] = e.Error
}
message := dockerEvents.Message{
// Compatibility with clients that still look for deprecated API elements
Status: e.Status.String(),

View File

@ -343,4 +343,14 @@ t GET libpod/images/no-alias-for-sure/resolve 200 \
t GET libpod/images/noCAPITALcharAllowed/resolve 400 \
.cause="repository name must be lowercase"
START=$(date +%s.%N)
# test pull-error API response
podman pull --retry 0 localhost:5000/idonotexist || true
t GET "libpod/events?stream=false&since=$START" 200 \
.status=pull-error \
.Action=pull-error \
.Actor.Attributes.name="localhost:5000/idonotexist" \
.Actor.Attributes.error~".*connection refused"
# vim: filetype=sh

View File

@ -4,6 +4,7 @@
#
load helpers
load helpers.network
# bats test_tags=distro-integration
@test "events with a filter by label" {
@ -57,12 +58,15 @@ load helpers
t0=$(date --iso-8601=seconds)
tag=registry.com/$(random_string 10 | tr A-Z a-z)
bogus_image="localhost:$(random_free_port)/bogus"
# Force using the file backend since the journal backend is eating events
# (see containers/podman/pull/10219#issuecomment-842325032).
run_podman --events-backend=file push $IMAGE dir:$pushedDir
run_podman --events-backend=file save $IMAGE -o $tarball
run_podman --events-backend=file load -i $tarball
run_podman --events-backend=file pull docker-archive:$tarball
run_podman 125 --events-backend=file pull --retry 0 $bogus_image
run_podman --events-backend=file tag $IMAGE $tag
run_podman --events-backend=file untag $IMAGE $tag
run_podman --events-backend=file tag $IMAGE $tag
@ -74,6 +78,7 @@ load helpers
.*image save $imageID $tarball
.*image loadfromarchive $imageID $tarball
.*image pull $imageID docker-archive:$tarball
.*image pull-error $bogus_image .*pinging container registry localhost.*connection refused
.*image tag $imageID $tag
.*image untag $imageID $tag:latest
.*image tag $imageID $tag
@ -87,6 +92,7 @@ load helpers
"save--$tarball"
"loadfromarchive--$tarball"
"pull--docker-archive:$tarball"
"pull-error--$bogus_image"
"tag--$tag"
"untag--$tag:latest"
"tag--$tag"