mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-08-05 00:15:44 +00:00
pkg/domain: return an error instead of nil on remote event parse failure
In remote mode `podman events --format json` could print the literal "null" instead of an event object. The remote client converts each event received from the server with ConvertToLibpodEvent, which returned nil when it could not parse the server result (an unknown status or type, or an invalid containerExitCode). The tunnel forwarded that nil as an event with no error set, so the CLI marshalled a nil event and printed "null". Return a descriptive error from ConvertToLibpodEvent and send it on the event channel, which the CLI already handles, instead of forwarding a nil event. Signed-off-by: ROKUMATE <rohitkumawat0110@gmail.com>
This commit is contained in:
parent
f6afcfaf26
commit
3d9e8fd2d3
3 changed files with 86 additions and 6 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package entities
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
|
@ -12,22 +13,22 @@ import (
|
|||
type Event = types.Event
|
||||
|
||||
// ConvertToLibpodEvent converts an entities event to a libpod one.
|
||||
func ConvertToLibpodEvent(e Event) *libpodEvents.Event {
|
||||
func ConvertToLibpodEvent(e Event) (*libpodEvents.Event, error) {
|
||||
var exitCode int
|
||||
if ec, ok := e.Actor.Attributes["containerExitCode"]; ok {
|
||||
var err error
|
||||
exitCode, err = strconv.Atoi(ec)
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, fmt.Errorf("parsing containerExitCode %q: %w", ec, err)
|
||||
}
|
||||
}
|
||||
status, err := libpodEvents.StringToStatus(string(e.Action))
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, err
|
||||
}
|
||||
t, err := libpodEvents.StringToType(string(e.Type))
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
oomKilled bool
|
||||
|
|
@ -71,7 +72,7 @@ func ConvertToLibpodEvent(e Event) *libpodEvents.Event {
|
|||
if hasOOM {
|
||||
newEvent.OOMKilled = &oomKilled
|
||||
}
|
||||
return newEvent
|
||||
return newEvent, nil
|
||||
}
|
||||
|
||||
// ConvertToEntitiesEvent converts a libpod event to an entities one.
|
||||
|
|
|
|||
74
pkg/domain/entities/events_test.go
Normal file
74
pkg/domain/entities/events_test.go
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
package entities
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
dockerEvents "github.com/moby/moby/api/types/events"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
libpodEvents "go.podman.io/podman/v6/libpod/events"
|
||||
)
|
||||
|
||||
func newTestEvent(typ, action string, attrs map[string]string) Event {
|
||||
if attrs == nil {
|
||||
attrs = map[string]string{}
|
||||
}
|
||||
return Event{
|
||||
Message: dockerEvents.Message{
|
||||
Type: dockerEvents.Type(typ),
|
||||
Action: dockerEvents.Action(action),
|
||||
Actor: dockerEvents.Actor{ID: "abc123", Attributes: attrs},
|
||||
TimeNano: 1700000000000000000,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToLibpodEvent(t *testing.T) {
|
||||
e := newTestEvent("container", "start", map[string]string{
|
||||
"image": "alpine",
|
||||
"name": "c1",
|
||||
"network": "podman1",
|
||||
"podId": "pod123",
|
||||
"containerExitCode": "137",
|
||||
"custom": "value",
|
||||
})
|
||||
event, err := ConvertToLibpodEvent(e)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, event)
|
||||
assert.Equal(t, libpodEvents.Container, event.Type)
|
||||
assert.Equal(t, libpodEvents.Start, event.Status)
|
||||
assert.Equal(t, "abc123", event.ID)
|
||||
assert.Equal(t, "alpine", event.Image)
|
||||
assert.Equal(t, "c1", event.Name)
|
||||
assert.Equal(t, "podman1", event.Network)
|
||||
assert.Equal(t, time.Unix(0, 1700000000000000000), event.Time)
|
||||
require.NotNil(t, event.ContainerExitCode)
|
||||
assert.Equal(t, 137, *event.ContainerExitCode)
|
||||
assert.Equal(t, "pod123", event.Details.PodID)
|
||||
assert.Equal(t, "value", event.Details.Attributes["custom"])
|
||||
}
|
||||
|
||||
// Previously a server result that failed to parse was silently turned into a
|
||||
// nil event, which surfaced to the user as the literal JSON "null". It must now
|
||||
// return an error instead. See https://github.com/containers/podman/issues/28325
|
||||
func TestConvertToLibpodEventReturnsError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
typ string
|
||||
action string
|
||||
attrs map[string]string
|
||||
}{
|
||||
{name: "unknown status", typ: "container", action: "bogus-status"},
|
||||
{name: "empty action", typ: "container", action: ""},
|
||||
{name: "empty type", typ: "", action: "start"},
|
||||
{name: "invalid containerExitCode", typ: "container", action: "start", attrs: map[string]string{"containerExitCode": "not-a-number"}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event, err := ConvertToLibpodEvent(newTestEvent(tt.typ, tt.action, tt.attrs))
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, event)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,12 @@ func (ic *ContainerEngine) Events(_ context.Context, opts entities.EventsOptions
|
|||
binChan := make(chan entities.Event)
|
||||
go func() {
|
||||
for e := range binChan {
|
||||
opts.EventChan <- events.ReadResult{Event: entities.ConvertToLibpodEvent(e)}
|
||||
event, err := entities.ConvertToLibpodEvent(e)
|
||||
if err != nil {
|
||||
opts.EventChan <- events.ReadResult{Error: fmt.Errorf("converting event from server: %w", err)}
|
||||
continue
|
||||
}
|
||||
opts.EventChan <- events.ReadResult{Event: event}
|
||||
}
|
||||
close(opts.EventChan)
|
||||
}()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue