Skip to content

Commit d8f07dc

Browse files
Merge pull request #21784 from Luap99/events
make podman events json output more docker compatible
2 parents b338364 + 4078a44 commit d8f07dc

File tree

7 files changed

+95
-36
lines changed

7 files changed

+95
-36
lines changed

cmd/podman/system/events.go

+51-3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,53 @@ var (
4949
noTrunc bool
5050
)
5151

52+
type Event struct {
53+
// containerExitCode is for storing the exit code of a container which can
54+
// be used for "internal" event notification
55+
ContainerExitCode *int `json:",omitempty"`
56+
// ID can be for the container, image, volume, etc
57+
ID string `json:",omitempty"`
58+
// Image used where applicable
59+
Image string `json:",omitempty"`
60+
// Name where applicable
61+
Name string `json:",omitempty"`
62+
// Network is the network name in a network event
63+
Network string `json:"network,omitempty"`
64+
// Status describes the event that occurred
65+
Status events.Status
66+
// Time the event occurred
67+
Time int64 `json:"time,omitempty"`
68+
// timeNano the event occurred in nanoseconds
69+
TimeNano int64 `json:"timeNano,omitempty"`
70+
// Type of event that occurred
71+
Type events.Type
72+
// Health status of the current container
73+
HealthStatus string `json:"health_status,omitempty"`
74+
75+
events.Details
76+
}
77+
78+
func newEventFromLibpodEvent(e *events.Event) Event {
79+
return Event{
80+
ContainerExitCode: e.ContainerExitCode,
81+
ID: e.ID,
82+
Image: e.Image,
83+
Name: e.Name,
84+
Network: e.Network,
85+
Status: e.Status,
86+
Time: e.Time.Unix(),
87+
Type: e.Type,
88+
HealthStatus: e.HealthStatus,
89+
Details: e.Details,
90+
TimeNano: e.Time.UnixNano(),
91+
}
92+
}
93+
94+
func (e *Event) ToJSONString() (string, error) {
95+
b, err := json.Marshal(e)
96+
return string(b), err
97+
}
98+
5299
func init() {
53100
registry.Commands = append(registry.Commands, registry.CliCommand{
54101
Command: systemEventsCommand,
@@ -70,7 +117,7 @@ func eventsFlags(cmd *cobra.Command) {
70117

71118
formatFlagName := "format"
72119
flags.StringVar(&eventFormat, formatFlagName, "", "format the output using a Go template")
73-
_ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&events.Event{}))
120+
_ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(&Event{}))
74121

75122
flags.BoolVar(&eventOptions.Stream, "stream", true, "stream events and do not exit when returning the last known event")
76123

@@ -125,13 +172,14 @@ func eventsCmd(cmd *cobra.Command, _ []string) error {
125172
}
126173
switch {
127174
case doJSON:
128-
jsonStr, err := event.ToJSONString()
175+
e := newEventFromLibpodEvent(event)
176+
jsonStr, err := e.ToJSONString()
129177
if err != nil {
130178
return err
131179
}
132180
fmt.Println(jsonStr)
133181
case cmd.Flags().Changed("format"):
134-
if err := rpt.Execute(event); err != nil {
182+
if err := rpt.Execute(newEventFromLibpodEvent(event)); err != nil {
135183
return err
136184
}
137185
default:

docs/source/markdown/podman-events.1.md

+15-15
Original file line numberDiff line numberDiff line change
@@ -104,21 +104,21 @@ In the case where an ID is used, the ID may be in its full or shortened form. T
104104

105105
Format the output to JSON Lines or using the given Go template.
106106

107-
| **Placeholder** | **Description** |
108-
|-------------------------|-----------------------------------------------|
109-
| .Attributes ... | created_at, _by, labels, and more (map[]) |
110-
| .ContainerExitCode | Exit code (int) |
111-
| .ContainerInspectData | Payload of the container's inspect |
112-
| .HealthStatus | Health Status (string) |
113-
| .ID | Container ID (full 64-bit SHA) |
114-
| .Image | Name of image being run (string) |
115-
| .Name | Container name (string) |
116-
| .Network | Name of network being used (string) |
117-
| .PodID | ID of pod associated with container, if any |
118-
| .Status | Event status (e.g., create, start, died, ...) |
119-
| .Time ... | Event timestamp (string) |
120-
| .ToHumanReadable *bool* | If true, truncates CID in output |
121-
| .Type | Event type (e.g., image, container, pod, ...) |
107+
| **Placeholder** | **Description** |
108+
|-------------------------|----------------------------------------------- ---|
109+
| .Attributes ... | created_at, _by, labels, and more (map[]) |
110+
| .ContainerExitCode | Exit code (int) |
111+
| .ContainerInspectData | Payload of the container's inspect |
112+
| .HealthStatus | Health Status (string) |
113+
| .ID | Container ID (full 64-bit SHA) |
114+
| .Image | Name of image being run (string) |
115+
| .Name | Container name (string) |
116+
| .Network | Name of network being used (string) |
117+
| .PodID | ID of pod associated with container, if any |
118+
| .Status | Event status (e.g., create, start, died, ...) |
119+
| .Time | Event timestamp (string) |
120+
| .TimeNano | Event timestamp with nanosecond precision (int64) |
121+
| .Type | Event type (e.g., image, container, pod, ...) |
122122

123123
#### **--help**
124124

libpod/events.go

-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ func (c *Container) newContainerEventWithInspectData(status events.Status, inspe
4343
e.Type = events.Container
4444

4545
e.Details = events.Details{
46-
ID: e.ID,
4746
PodID: c.PodID(),
4847
Attributes: c.Labels(),
4948
}
@@ -99,7 +98,6 @@ func (c *Container) newContainerExitedEvent(exitCode int32) {
9998
e.ContainerExitCode = &intExitCode
10099

101100
e.Details = events.Details{
102-
ID: e.ID,
103101
Attributes: c.Labels(),
104102
}
105103

@@ -121,7 +119,6 @@ func (c *Container) newExecDiedEvent(sessionID string, exitCode int) {
121119
e.Attributes["execID"] = sessionID
122120

123121
e.Details = events.Details{
124-
ID: e.ID,
125122
Attributes: c.Labels(),
126123
}
127124

libpod/events/config.go

-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ type Event struct {
4848
// Details describes specifics about certain events, specifically around
4949
// container events
5050
type Details struct {
51-
// ID is the event ID
52-
ID string
5351
// ContainerInspectData includes the payload of the container's inspect
5452
// data. Only set when events_container_create_inspect_data is set true
5553
// in containers.conf.

test/apiv2/27-containersEvents.at

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ t GET "events?stream=false&since=$START" 200 \
2929
'select(.status | contains("die")).Actor.Attributes.exitCode=1'
3030

3131
t GET "events?stream=false&since=$START&type=remove" 200 \
32-
'select(.status| contains("remove")).Action=remove' \
32+
'select(.status | contains("remove")).Action=remove' \
3333
'select(.status | contains("remove")).Actor.Attributes.containerExitCode=1'
3434

3535
# vim: filetype=sh

test/e2e/events_test.go

+21-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"sync"
88
"time"
99

10-
"github.com/containers/podman/v5/libpod/events"
10+
"github.com/containers/podman/v5/cmd/podman/system"
1111
. "github.com/containers/podman/v5/test/utils"
1212
"github.com/containers/storage/pkg/stringid"
1313
. "github.com/onsi/ginkgo/v2"
@@ -119,7 +119,10 @@ var _ = Describe("Podman events", func() {
119119
})
120120

121121
It("podman events format", func() {
122-
_, ec, _ := podmanTest.RunLsContainer("")
122+
start := time.Now()
123+
ctrName := "testCtr"
124+
_, ec, _ := podmanTest.RunLsContainer(ctrName)
125+
end := time.Now()
123126
Expect(ec).To(Equal(0))
124127

125128
test := podmanTest.Podman([]string{"events", "--stream=false", "--format", "json"})
@@ -129,21 +132,34 @@ var _ = Describe("Podman events", func() {
129132
jsonArr := test.OutputToStringArray()
130133
Expect(test.OutputToStringArray()).ShouldNot(BeEmpty())
131134

132-
event := events.Event{}
135+
event := system.Event{}
133136
err := json.Unmarshal([]byte(jsonArr[0]), &event)
134137
Expect(err).ToNot(HaveOccurred())
135138

136-
test = podmanTest.Podman([]string{"events", "--stream=false", "--format", "{{json.}}"})
139+
test = podmanTest.Podman([]string{
140+
"events",
141+
"--stream=false",
142+
"--since", strconv.FormatInt(start.Unix(), 10),
143+
"--filter", fmt.Sprintf("container=%s", ctrName),
144+
"--format", "{{json .}}",
145+
})
146+
137147
test.WaitWithDefaultTimeout()
138148
Expect(test).To(ExitCleanly())
139149

140150
jsonArr = test.OutputToStringArray()
141151
Expect(test.OutputToStringArray()).ShouldNot(BeEmpty())
142152

143-
event = events.Event{}
153+
event = system.Event{}
144154
err = json.Unmarshal([]byte(jsonArr[0]), &event)
145155
Expect(err).ToNot(HaveOccurred())
146156

157+
Expect(event.Time).To(BeNumerically(">=", start.Unix()))
158+
Expect(event.Time).To(BeNumerically("<=", end.Unix()))
159+
Expect(event.TimeNano).To(BeNumerically(">=", start.UnixNano()))
160+
Expect(event.TimeNano).To(BeNumerically("<=", end.UnixNano()))
161+
Expect(time.Unix(0, event.TimeNano).Unix()).To(BeEquivalentTo(event.Time))
162+
147163
test = podmanTest.Podman([]string{"events", "--stream=false", "--filter=type=container", "--format", "ID: {{.ID}}"})
148164
test.WaitWithDefaultTimeout()
149165
Expect(test).To(ExitCleanly())

test/system/090-events.bats

+7-7
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,9 @@ EOF
223223
# same amount of events. We checked the contents before.
224224
CONTAINERS_CONF_OVERRIDE=$containersConf run_podman events --stream=false --since="2022-03-06T11:26:42.723667984+02:00" --format=json
225225
assert "${#lines[@]}" = 52 "Number of events returned"
226-
is "${lines[0]}" "{\"Name\":\"$eventsFile\",\"Status\":\"log-rotation\",\"Time\":\".*\",\"Type\":\"system\",\"Attributes\":{\"io.podman.event.rotate\":\"begin\"}}"
227-
is "${lines[-2]}" "{\"Name\":\"$eventsFile\",\"Status\":\"log-rotation\",\"Time\":\".*\",\"Type\":\"system\",\"Attributes\":{\"io.podman.event.rotate\":\"end\"}}"
228-
is "${lines[-1]}" "{\"ID\":\"$ctrID\",\"Image\":\"$IMAGE\",\"Name\":\".*\",\"Status\":\"remove\",\"Time\":\".*\",\"Type\":\"container\",\"Attributes\":{.*}}"
226+
is "${lines[0]}" "{\"Name\":\"$eventsFile\",\"Status\":\"log-rotation\",\"time\":[0-9]\+,\"timeNano\":[0-9]\+,\"Type\":\"system\",\"Attributes\":{\"io.podman.event.rotate\":\"begin\"}}"
227+
is "${lines[-2]}" "{\"Name\":\"$eventsFile\",\"Status\":\"log-rotation\",\"time\":[0-9]\+,\"timeNano\":[0-9]\+,\"Type\":\"system\",\"Attributes\":{\"io.podman.event.rotate\":\"end\"}}"
228+
is "${lines[-1]}" "{\"ID\":\"$ctrID\",\"Image\":\"$IMAGE\",\"Name\":\".*\",\"Status\":\"remove\",\"time\":[0-9]\+,\"timeNano\":[0-9]\+,\"Type\":\"container\",\"Attributes\":{.*}}"
229229
}
230230

231231
@test "events log-file no duplicates" {
@@ -292,10 +292,10 @@ EOF
292292
# Make sure that the JSON stream looks as expected. That means it has all
293293
# events and no duplicates.
294294
run cat $eventsJSON
295-
is "${lines[0]}" "{\"Name\":\"busybox\",\"Status\":\"pull\",\"Time\":\"2022-04-06T11:26:42.7236679+02:00\",\"Type\":\"image\",\"Attributes\":null}"
296-
is "${lines[99]}" "{\"Name\":\"busybox\",\"Status\":\"pull\",\"Time\":\"2022-04-06T11:26:42.723667999+02:00\",\"Type\":\"image\",\"Attributes\":null}"
297-
is "${lines[100]}" "{\"Name\":\"$eventsFile\",\"Status\":\"log-rotation\",\"Time\":\".*\",\"Type\":\"system\",\"Attributes\":{\"io.podman.event.rotate\":\"end\"}}"
298-
is "${lines[103]}" "{\"ID\":\"$ctrID\",\"Image\":\"$IMAGE\",\"Name\":\".*\",\"Status\":\"remove\",\"Time\":\".*\",\"Type\":\"container\",\"Attributes\":{.*}}"
295+
is "${lines[0]}" "{\"Name\":\"busybox\",\"Status\":\"pull\",\"time\":1649237202,\"timeNano\":1649237202723[0-9]\+,\"Type\":\"image\",\"Attributes\":null}"
296+
is "${lines[99]}" "{\"Name\":\"busybox\",\"Status\":\"pull\",\"time\":1649237202,\"timeNano\":1649237202723[0-9]\+,\"Type\":\"image\",\"Attributes\":null}"
297+
is "${lines[100]}" "{\"Name\":\"$eventsFile\",\"Status\":\"log-rotation\",\"time\":[0-9]\+,\"timeNano\":[0-9]\+,\"Type\":\"system\",\"Attributes\":{\"io.podman.event.rotate\":\"end\"}}"
298+
is "${lines[103]}" "{\"ID\":\"$ctrID\",\"Image\":\"$IMAGE\",\"Name\":\".*\",\"Status\":\"remove\",\"time\":[0-9]\+,\"timeNano\":[0-9]\+,\"Type\":\"container\",\"Attributes\":{.*}}"
299299
}
300300

301301
# Prior to #15633, container labels would not appear in 'die' log events

0 commit comments

Comments
 (0)