Add "create" and "remove" events for secrets.

This commit adds the "secret" Event type and emits
"create" and "remove" events for this Event type
when Secret is created or removed.

This can be used for example by podman interfaces to
view and manage secrets.

Fixes: #24030

Signed-off-by: Jan Kaluza <jkaluza@redhat.com>
This commit is contained in:
Jan Kaluza
2025-02-28 11:04:36 +01:00
parent 350429cc3c
commit 20523152f8
8 changed files with 42 additions and 2 deletions

View File

@ -1522,7 +1522,7 @@ func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete strin
} }
eventTypes := func(_ string) ([]string, cobra.ShellCompDirective) { eventTypes := func(_ string) ([]string, cobra.ShellCompDirective) {
return []string{events.Container.String(), events.Image.String(), events.Network.String(), return []string{events.Container.String(), events.Image.String(), events.Network.String(),
events.Pod.String(), events.System.String(), events.Volume.String(), events.Pod.String(), events.System.String(), events.Volume.String(), events.Secret.String(),
}, cobra.ShellCompDirectiveNoFileComp }, cobra.ShellCompDirectiveNoFileComp
} }
kv := keyValueCompletion{ kv := keyValueCompletion{

View File

@ -79,6 +79,10 @@ The *volume* type reports the following statuses:
* prune * prune
* remove * remove
The *secret* type reports the following statuses:
* create
* remove
#### Verbose Create Events #### Verbose Create Events
Setting `events_container_create_inspect_data=true` in containers.conf(5) instructs Podman to create more verbose container-create events which include a JSON payload with detailed information about the containers. The JSON payload is identical to the one of podman-container-inspect(1). The associated field in journald is named `PODMAN_CONTAINER_INSPECT_DATA`. Setting `events_container_create_inspect_data=true` in containers.conf(5) instructs Podman to create more verbose container-create events which include a JSON payload with detailed information about the containers. The JSON payload is identical to the one of podman-container-inspect(1). The associated field in journald is named `PODMAN_CONTAINER_INSPECT_DATA`.

View File

@ -191,6 +191,16 @@ func (v *Volume) newVolumeEvent(status events.Status) {
} }
} }
// NewSecretEvent creates a new event for a libpod secret
func (r *Runtime) NewSecretEvent(status events.Status, secretID string) {
e := events.NewEvent(status)
e.ID = secretID
e.Type = events.Secret
if err := r.eventer.Write(e); err != nil {
logrus.Errorf("Unable to write secret event: %q", err)
}
}
// Events is a wrapper function for everyone to begin tailing the events log // Events is a wrapper function for everyone to begin tailing the events log
// with options // with options
func (r *Runtime) Events(ctx context.Context, options events.ReadOptions) error { func (r *Runtime) Events(ctx context.Context, options events.ReadOptions) error {

View File

@ -131,6 +131,8 @@ const (
Volume Type = "volume" Volume Type = "volume"
// Machine - event is related to machine VM's // Machine - event is related to machine VM's
Machine Type = "machine" Machine Type = "machine"
// Secret - event is related to secrets
Secret Type = "secret"
// Attach ... // Attach ...
Attach Status = "attach" Attach Status = "attach"

View File

@ -92,6 +92,8 @@ func (e *Event) ToHumanReadable(truncate bool) string {
} }
case Volume, Machine: case Volume, Machine:
humanFormat = fmt.Sprintf("%s %s %s %s", e.Time, e.Type, e.Status, e.Name) humanFormat = fmt.Sprintf("%s %s %s %s", e.Time, e.Type, e.Status, e.Name)
case Secret:
humanFormat = fmt.Sprintf("%s %s %s %s", e.Time, e.Type, e.Status, id)
} }
return humanFormat return humanFormat
} }
@ -133,6 +135,8 @@ func StringToType(name string) (Type, error) {
return System, nil return System, nil
case Volume.String(): case Volume.String():
return Volume, nil return Volume, nil
case Secret.String():
return Secret, nil
case "": case "":
return "", ErrEventTypeBlank return "", ErrEventTypeBlank
} }

View File

@ -173,7 +173,7 @@ func (e EventLogFile) Read(ctx context.Context, options ReadOptions) error {
continue continue
} }
switch event.Type { switch event.Type {
case Image, Volume, Pod, Container, Network: case Image, Volume, Pod, Container, Network, Secret:
// no-op // no-op
case System: case System:
begin, end, err := e.readRotateEvent(event) begin, end, err := e.readRotateEvent(event)

View File

@ -11,6 +11,7 @@ import (
"strings" "strings"
"github.com/containers/common/pkg/secrets" "github.com/containers/common/pkg/secrets"
"github.com/containers/podman/v5/libpod/events"
"github.com/containers/podman/v5/pkg/domain/entities" "github.com/containers/podman/v5/pkg/domain/entities"
"github.com/containers/podman/v5/pkg/domain/utils" "github.com/containers/podman/v5/pkg/domain/utils"
) )
@ -56,6 +57,8 @@ func (ic *ContainerEngine) SecretCreate(ctx context.Context, name string, reader
return nil, err return nil, err
} }
ic.Libpod.NewSecretEvent(events.Create, secretID)
return &entities.SecretCreateReport{ return &entities.SecretCreateReport{
ID: secretID, ID: secretID,
}, nil }, nil
@ -146,6 +149,9 @@ func (ic *ContainerEngine) SecretRm(ctx context.Context, nameOrIDs []string, opt
continue continue
} }
reports = append(reports, &entities.SecretRmReport{Err: err, ID: deletedID}) reports = append(reports, &entities.SecretRmReport{Err: err, ID: deletedID})
if err == nil {
ic.Libpod.NewSecretEvent(events.Remove, deletedID)
}
} }
return reports, nil return reports, nil

View File

@ -29,6 +29,13 @@ var _ = Describe("Podman secret", func() {
secrID := session.OutputToString() secrID := session.OutputToString()
Expect(session).Should(ExitCleanly()) Expect(session).Should(ExitCleanly())
result := podmanTest.Podman([]string{"events", "--stream=false"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
events := result.OutputToStringArray()
Expect(events).ToNot(BeEmpty(), "Number of events")
Expect(events).To(ContainElement(ContainSubstring(" secret create %s", secrID)))
inspect := podmanTest.Podman([]string{"secret", "inspect", "--format", "{{.ID}}", secrID}) inspect := podmanTest.Podman([]string{"secret", "inspect", "--format", "{{.ID}}", secrID})
inspect.WaitWithDefaultTimeout() inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(ExitCleanly()) Expect(inspect).Should(ExitCleanly())
@ -305,6 +312,13 @@ var _ = Describe("Podman secret", func() {
Expect(removed).Should(ExitCleanly()) Expect(removed).Should(ExitCleanly())
Expect(removed.OutputToString()).To(Equal(secrID)) Expect(removed.OutputToString()).To(Equal(secrID))
result := podmanTest.Podman([]string{"events", "--stream=false"})
result.WaitWithDefaultTimeout()
Expect(result).Should(ExitCleanly())
events := result.OutputToStringArray()
Expect(events).ToNot(BeEmpty(), "Number of events")
Expect(events).To(ContainElement(ContainSubstring(" secret remove %s", secrID)))
session = podmanTest.Podman([]string{"secret", "ls"}) session = podmanTest.Podman([]string{"secret", "ls"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly()) Expect(session).Should(ExitCleanly())