diff options
author | Jhon Honce <jhonce@redhat.com> | 2022-04-04 13:04:40 -0700 |
---|---|---|
committer | Jhon Honce <jhonce@redhat.com> | 2022-05-03 13:49:01 -0700 |
commit | 8da5f3f733273245dd4e86324ca88bf8e4ede37a (patch) | |
tree | 2c87e85d53cf01763fec61464e5a208b18de83ae /cmd/podman/machine/machine.go | |
parent | 1e0c50df38ff955011f7ebb83a0268f3f1cd2841 (diff) | |
download | podman-8da5f3f733273245dd4e86324ca88bf8e4ede37a.tar.gz podman-8da5f3f733273245dd4e86324ca88bf8e4ede37a.tar.bz2 podman-8da5f3f733273245dd4e86324ca88bf8e4ede37a.zip |
Add podman machine events
Signed-off-by: Jhon Honce <jhonce@redhat.com>
Diffstat (limited to 'cmd/podman/machine/machine.go')
-rw-r--r-- | cmd/podman/machine/machine.go | 132 |
1 files changed, 127 insertions, 5 deletions
diff --git a/cmd/podman/machine/machine.go b/cmd/podman/machine/machine.go index d3775f022..4c566b11f 100644 --- a/cmd/podman/machine/machine.go +++ b/cmd/podman/machine/machine.go @@ -4,25 +4,39 @@ package machine import ( + "errors" + "net" + "os" + "path/filepath" + "regexp" "strings" + "sync" + "time" "github.com/containers/podman/v4/cmd/podman/registry" "github.com/containers/podman/v4/cmd/podman/validate" + "github.com/containers/podman/v4/libpod/events" "github.com/containers/podman/v4/pkg/machine" + "github.com/containers/podman/v4/pkg/util" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) var ( - noOp = func(cmd *cobra.Command, args []string) error { - return nil - } + // Pull in configured json library + json = registry.JSONLibrary() + + sockPaths []string // Paths to unix domain sockets for publishing + openEventSock sync.Once // Singleton support for opening sockets as needed + sockets []net.Conn // Opened sockets, if any + // Command: podman _machine_ machineCmd = &cobra.Command{ Use: "machine", Short: "Manage a virtual machine", Long: "Manage a virtual machine. Virtual machines are used to run Podman.", - PersistentPreRunE: noOp, - PersistentPostRunE: noOp, + PersistentPreRunE: initMachineEvents, + PersistentPostRunE: closeMachineEvents, RunE: validate.SubCommandExists, } ) @@ -64,3 +78,111 @@ func getMachines(toComplete string) ([]string, cobra.ShellCompDirective) { } return suggestions, cobra.ShellCompDirectiveNoFileComp } + +func initMachineEvents(cmd *cobra.Command, _ []string) error { + logrus.Debugf("Called machine %s.PersistentPreRunE(%s)", cmd.Name(), strings.Join(os.Args, " ")) + + sockPaths, err := resolveEventSock() + if err != nil { + return err + } + + // No sockets found, so no need to publish events... + if len(sockPaths) == 0 { + return nil + } + + for _, path := range sockPaths { + conn, err := (&net.Dialer{}).DialContext(registry.Context(), "unix", path) + if err != nil { + logrus.Warnf("Failed to open event socket %q: %v", path, err) + continue + } + logrus.Debugf("Machine event socket %q found", path) + sockets = append(sockets, conn) + } + return nil +} + +func resolveEventSock() ([]string, error) { + // Used mostly for testing + if sock, found := os.LookupEnv("PODMAN_MACHINE_EVENTS_SOCK"); found { + return []string{sock}, nil + } + + xdg, err := util.GetRuntimeDir() + if err != nil { + logrus.Warnf("Failed to get runtime dir, machine events will not be published: %s", err) + return nil, nil + } + + re := regexp.MustCompile(`machine_events.*\.sock`) + sockPaths := make([]string, 0) + fn := func(path string, info os.DirEntry, err error) error { + switch { + case err != nil: + return err + case info.IsDir(): + return nil + case info.Type() != os.ModeSocket: + return nil + case !re.MatchString(info.Name()): + return nil + } + + logrus.Debugf("Machine events will be published on: %q", path) + sockPaths = append(sockPaths, path) + return nil + } + + if err := filepath.WalkDir(filepath.Join(xdg, "podman"), fn); err != nil { + if errors.Is(err, os.ErrNotExist) { + return nil, nil + } + return nil, err + } + return sockPaths, nil +} + +func newMachineEvent(status events.Status, event events.Event) { + openEventSock.Do(func() { + // No sockets where found, so no need to publish events... + if len(sockPaths) == 0 { + return + } + + for _, path := range sockPaths { + conn, err := (&net.Dialer{}).DialContext(registry.Context(), "unix", path) + if err != nil { + logrus.Warnf("Failed to open event socket %q: %v", path, err) + continue + } + logrus.Debugf("Machine event socket %q found", path) + sockets = append(sockets, conn) + } + }) + + event.Status = status + event.Time = time.Now() + event.Type = events.Machine + + payload, err := json.Marshal(event) + if err != nil { + logrus.Errorf("Unable to format machine event: %q", err) + return + } + + for _, sock := range sockets { + if _, err := sock.Write(payload); err != nil { + logrus.Errorf("Unable to write machine event: %q", err) + } + } +} + +func closeMachineEvents(cmd *cobra.Command, _ []string) error { + logrus.Debugf("Called machine %s.PersistentPostRunE(%s)", cmd.Name(), strings.Join(os.Args, " ")) + for _, sock := range sockets { + _ = sock.Close() + } + return nil +} |