Add podman machine events
Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
parent
1e0c50df38
commit
8da5f3f733
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/containers/common/pkg/completion"
|
"github.com/containers/common/pkg/completion"
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
|
"github.com/containers/podman/v4/libpod/events"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -145,11 +146,14 @@ func initMachine(cmd *cobra.Command, args []string) error {
|
||||||
// Finished = *, err != nil - Exit with an error message
|
// Finished = *, err != nil - Exit with an error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
newMachineEvent(events.Init, events.Event{Name: initOpts.Name})
|
||||||
fmt.Println("Machine init complete")
|
fmt.Println("Machine init complete")
|
||||||
|
|
||||||
if now {
|
if now {
|
||||||
err = vm.Start(initOpts.Name, machine.StartOptions{})
|
err = vm.Start(initOpts.Name, machine.StartOptions{})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("Machine %q started successfully\n", initOpts.Name)
|
fmt.Printf("Machine %q started successfully\n", initOpts.Name)
|
||||||
|
newMachineEvent(events.Start, events.Event{Name: initOpts.Name})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
extra := ""
|
extra := ""
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/containers/podman/v4/cmd/podman/common"
|
"github.com/containers/podman/v4/cmd/podman/common"
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
|
@ -4,25 +4,39 @@
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
"github.com/containers/podman/v4/cmd/podman/validate"
|
"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/machine"
|
||||||
|
"github.com/containers/podman/v4/pkg/util"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
noOp = func(cmd *cobra.Command, args []string) error {
|
// Pull in configured json library
|
||||||
return nil
|
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_
|
// Command: podman _machine_
|
||||||
machineCmd = &cobra.Command{
|
machineCmd = &cobra.Command{
|
||||||
Use: "machine",
|
Use: "machine",
|
||||||
Short: "Manage a virtual machine",
|
Short: "Manage a virtual machine",
|
||||||
Long: "Manage a virtual machine. Virtual machines are used to run Podman.",
|
Long: "Manage a virtual machine. Virtual machines are used to run Podman.",
|
||||||
PersistentPreRunE: noOp,
|
PersistentPreRunE: initMachineEvents,
|
||||||
PersistentPostRunE: noOp,
|
PersistentPostRunE: closeMachineEvents,
|
||||||
RunE: validate.SubCommandExists,
|
RunE: validate.SubCommandExists,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -64,3 +78,111 @@ func getMachines(toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
}
|
}
|
||||||
return suggestions, cobra.ShellCompDirectiveNoFileComp
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
|
"github.com/containers/podman/v4/libpod/events"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -50,7 +51,7 @@ func init() {
|
||||||
flags.BoolVar(&destroyOptions.SaveImage, imageFlagName, false, "Do not delete the image file")
|
flags.BoolVar(&destroyOptions.SaveImage, imageFlagName, false, "Do not delete the image file")
|
||||||
}
|
}
|
||||||
|
|
||||||
func rm(cmd *cobra.Command, args []string) error {
|
func rm(_ *cobra.Command, args []string) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
vm machine.VM
|
vm machine.VM
|
||||||
|
@ -83,5 +84,10 @@ func rm(cmd *cobra.Command, args []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return remove()
|
err = remove()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newMachineEvent(events.Remove, events.Event{Name: vmName})
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
|
"github.com/containers/podman/v4/libpod/events"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -31,7 +32,7 @@ func init() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func start(cmd *cobra.Command, args []string) error {
|
func start(_ *cobra.Command, args []string) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
vm machine.VM
|
vm machine.VM
|
||||||
|
@ -62,5 +63,6 @@ func start(cmd *cobra.Command, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Machine %q started successfully\n", vmName)
|
fmt.Printf("Machine %q started successfully\n", vmName)
|
||||||
|
newMachineEvent(events.Start, events.Event{Name: vmName})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containers/podman/v4/cmd/podman/registry"
|
"github.com/containers/podman/v4/cmd/podman/registry"
|
||||||
|
"github.com/containers/podman/v4/libpod/events"
|
||||||
"github.com/containers/podman/v4/pkg/machine"
|
"github.com/containers/podman/v4/pkg/machine"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -49,5 +50,6 @@ func stop(cmd *cobra.Command, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Machine %q stopped successfully\n", vmName)
|
fmt.Printf("Machine %q stopped successfully\n", vmName)
|
||||||
|
newMachineEvent(events.Stop, events.Event{Name: vmName})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
_ "github.com/containers/podman/v4/cmd/podman/secrets"
|
_ "github.com/containers/podman/v4/cmd/podman/secrets"
|
||||||
_ "github.com/containers/podman/v4/cmd/podman/system"
|
_ "github.com/containers/podman/v4/cmd/podman/system"
|
||||||
_ "github.com/containers/podman/v4/cmd/podman/system/connection"
|
_ "github.com/containers/podman/v4/cmd/podman/system/connection"
|
||||||
|
"github.com/containers/podman/v4/cmd/podman/validate"
|
||||||
_ "github.com/containers/podman/v4/cmd/podman/volumes"
|
_ "github.com/containers/podman/v4/cmd/podman/volumes"
|
||||||
"github.com/containers/podman/v4/pkg/domain/entities"
|
"github.com/containers/podman/v4/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v4/pkg/rootless"
|
"github.com/containers/podman/v4/pkg/rootless"
|
||||||
|
@ -64,8 +65,8 @@ func parseCommands() *cobra.Command {
|
||||||
c.Command.Hidden = true
|
c.Command.Hidden = true
|
||||||
|
|
||||||
// overwrite persistent pre/post function to skip setup
|
// overwrite persistent pre/post function to skip setup
|
||||||
c.Command.PersistentPostRunE = noop
|
c.Command.PersistentPostRunE = validate.NoOp
|
||||||
c.Command.PersistentPreRunE = noop
|
c.Command.PersistentPreRunE = validate.NoOp
|
||||||
addCommand(c)
|
addCommand(c)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -120,7 +121,3 @@ func addCommand(c registry.CliCommand) {
|
||||||
c.Command.SetUsageTemplate(usageTemplate)
|
c.Command.SetUsageTemplate(usageTemplate)
|
||||||
c.Command.DisableFlagsInUseLine = true
|
c.Command.DisableFlagsInUseLine = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func noop(cmd *cobra.Command, args []string) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,18 +7,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Skip creating engines since this command will obtain connection information to said engines
|
// ConnectionCmd skips creating engines (PersistentPreRunE/PersistentPostRunE are No-Op's) since
|
||||||
noOp = func(cmd *cobra.Command, args []string) error {
|
// sub-commands will obtain connection information to said engines
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionCmd = &cobra.Command{
|
ConnectionCmd = &cobra.Command{
|
||||||
Use: "connection",
|
Use: "connection",
|
||||||
Short: "Manage remote ssh destinations",
|
Short: "Manage remote API service destinations",
|
||||||
Long: `Manage ssh destination information in podman configuration`,
|
Long: `Manage remote API service destination information in podman configuration`,
|
||||||
PersistentPreRunE: noOp,
|
PersistentPreRunE: validate.NoOp,
|
||||||
RunE: validate.SubCommandExists,
|
RunE: validate.SubCommandExists,
|
||||||
PersistentPostRunE: noOp,
|
PersistentPostRunE: validate.NoOp,
|
||||||
TraverseChildren: false,
|
TraverseChildren: false,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package validate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NoOp(_ *cobra.Command, _ []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -17,6 +17,8 @@ const (
|
||||||
Journald EventerType = iota
|
Journald EventerType = iota
|
||||||
// Null is a no-op events logger. It does not read or write events.
|
// Null is a no-op events logger. It does not read or write events.
|
||||||
Null EventerType = iota
|
Null EventerType = iota
|
||||||
|
// Memory indicates the event logger will hold events in memory
|
||||||
|
Memory EventerType = iota
|
||||||
)
|
)
|
||||||
|
|
||||||
// Event describes the attributes of a libpod event
|
// Event describes the attributes of a libpod event
|
||||||
|
@ -55,7 +57,7 @@ type Details struct {
|
||||||
// EventerOptions describe options that need to be passed to create
|
// EventerOptions describe options that need to be passed to create
|
||||||
// an eventer
|
// an eventer
|
||||||
type EventerOptions struct {
|
type EventerOptions struct {
|
||||||
// EventerType describes whether to use journald or a file
|
// EventerType describes whether to use journald, file or memory
|
||||||
EventerType string
|
EventerType string
|
||||||
// LogFilePath is the path to where the log file should reside if using
|
// LogFilePath is the path to where the log file should reside if using
|
||||||
// the file logger
|
// the file logger
|
||||||
|
@ -110,6 +112,8 @@ const (
|
||||||
System Type = "system"
|
System Type = "system"
|
||||||
// Volume - event is related to volumes
|
// Volume - event is related to volumes
|
||||||
Volume Type = "volume"
|
Volume Type = "volume"
|
||||||
|
// Machine - event is related to machine VM's
|
||||||
|
Machine Type = "machine"
|
||||||
|
|
||||||
// Attach ...
|
// Attach ...
|
||||||
Attach Status = "attach"
|
Attach Status = "attach"
|
||||||
|
|
|
@ -20,6 +20,8 @@ func (et EventerType) String() string {
|
||||||
return "file"
|
return "file"
|
||||||
case Journald:
|
case Journald:
|
||||||
return "journald"
|
return "journald"
|
||||||
|
case Memory:
|
||||||
|
return "memory"
|
||||||
case Null:
|
case Null:
|
||||||
return "none"
|
return "none"
|
||||||
default:
|
default:
|
||||||
|
@ -34,6 +36,8 @@ func IsValidEventer(eventer string) bool {
|
||||||
return true
|
return true
|
||||||
case Journald.String():
|
case Journald.String():
|
||||||
return true
|
return true
|
||||||
|
case Memory.String():
|
||||||
|
return true
|
||||||
case Null.String():
|
case Null.String():
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
|
@ -41,7 +45,7 @@ func IsValidEventer(eventer string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEvent creates a event struct and populates with
|
// NewEvent creates an event struct and populates with
|
||||||
// the given status and time.
|
// the given status and time.
|
||||||
func NewEvent(status Status) Event {
|
func NewEvent(status Status) Event {
|
||||||
return Event{
|
return Event{
|
||||||
|
@ -63,7 +67,7 @@ func (e *Event) ToJSONString() (string, error) {
|
||||||
return string(b), err
|
return string(b), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToHumanReadable returns human readable event as a formatted string
|
// ToHumanReadable returns human-readable event as a formatted string
|
||||||
func (e *Event) ToHumanReadable(truncate bool) string {
|
func (e *Event) ToHumanReadable(truncate bool) string {
|
||||||
var humanFormat string
|
var humanFormat string
|
||||||
id := e.ID
|
id := e.ID
|
||||||
|
@ -90,7 +94,7 @@ func (e *Event) ToHumanReadable(truncate bool) string {
|
||||||
} else {
|
} else {
|
||||||
humanFormat = fmt.Sprintf("%s %s %s", e.Time, e.Type, e.Status)
|
humanFormat = fmt.Sprintf("%s %s %s", e.Time, e.Type, e.Status)
|
||||||
}
|
}
|
||||||
case Volume:
|
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)
|
||||||
}
|
}
|
||||||
return humanFormat
|
return humanFormat
|
||||||
|
@ -99,19 +103,19 @@ func (e *Event) ToHumanReadable(truncate bool) string {
|
||||||
// NewEventFromString takes stringified json and converts
|
// NewEventFromString takes stringified json and converts
|
||||||
// it to an event
|
// it to an event
|
||||||
func newEventFromJSONString(event string) (*Event, error) {
|
func newEventFromJSONString(event string) (*Event, error) {
|
||||||
e := Event{}
|
e := new(Event)
|
||||||
if err := json.Unmarshal([]byte(event), &e); err != nil {
|
if err := json.Unmarshal([]byte(event), e); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToString converts a Type to a string
|
// String converts a Type to a string
|
||||||
func (t Type) String() string {
|
func (t Type) String() string {
|
||||||
return string(t)
|
return string(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToString converts a status to a string
|
// String converts a status to a string
|
||||||
func (s Status) String() string {
|
func (s Status) String() string {
|
||||||
return string(s)
|
return string(s)
|
||||||
}
|
}
|
||||||
|
@ -123,6 +127,8 @@ func StringToType(name string) (Type, error) {
|
||||||
return Container, nil
|
return Container, nil
|
||||||
case Image.String():
|
case Image.String():
|
||||||
return Image, nil
|
return Image, nil
|
||||||
|
case Machine.String():
|
||||||
|
return Machine, nil
|
||||||
case Network.String():
|
case Network.String():
|
||||||
return Network, nil
|
return Network, nil
|
||||||
case Pod.String():
|
case Pod.String():
|
||||||
|
|
|
@ -21,6 +21,8 @@ func NewEventer(options EventerOptions) (Eventer, error) {
|
||||||
return EventLogFile{options}, nil
|
return EventLogFile{options}, nil
|
||||||
case strings.ToUpper(Null.String()):
|
case strings.ToUpper(Null.String()):
|
||||||
return NewNullEventer(), nil
|
return NewNullEventer(), nil
|
||||||
|
case strings.ToUpper(Memory.String()):
|
||||||
|
return NewMemoryEventer(), nil
|
||||||
default:
|
default:
|
||||||
return nil, errors.Errorf("unknown event logger type: %s", strings.ToUpper(options.EventerType))
|
return nil, errors.Errorf("unknown event logger type: %s", strings.ToUpper(options.EventerType))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package events
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventMemory is the structure for event writing to a channel. It contains the eventer
|
||||||
|
// options and the event itself. Methods for reading and writing are also defined from it.
|
||||||
|
type EventMemory struct {
|
||||||
|
options EventerOptions
|
||||||
|
elements chan *Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write event to memory queue
|
||||||
|
func (e EventMemory) Write(event Event) (err error) {
|
||||||
|
e.elements <- &event
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read event(s) from memory queue
|
||||||
|
func (e EventMemory) Read(ctx context.Context, options ReadOptions) (err error) {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case event := <-e.elements:
|
||||||
|
options.EventChannel <- event
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns eventer type
|
||||||
|
func (e EventMemory) String() string {
|
||||||
|
return e.options.EventerType
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMemoryEventer returns configured MemoryEventer
|
||||||
|
func NewMemoryEventer() Eventer {
|
||||||
|
return EventMemory{
|
||||||
|
options: EventerOptions{
|
||||||
|
EventerType: Memory.String(),
|
||||||
|
},
|
||||||
|
elements: make(chan *Event, 100),
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -1063,3 +1064,36 @@ func digShort(container, lookupName string, matchNames []string, p *PodmanTestIn
|
||||||
}
|
}
|
||||||
Fail("dns is not responding")
|
Fail("dns is not responding")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WaitForFile to be created in defaultWaitTimeout seconds, returns false if file not created
|
||||||
|
func WaitForFile(path string) (err error) {
|
||||||
|
until := time.Now().Add(time.Duration(defaultWaitTimeout) * time.Second)
|
||||||
|
for i := 1; time.Now().Before(until); i++ {
|
||||||
|
_, err = os.Stat(path)
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
return nil
|
||||||
|
case errors.Is(err, os.ErrNotExist):
|
||||||
|
time.Sleep(time.Duration(i) * time.Second)
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForService blocks, waiting for some service listening on given host:port
|
||||||
|
func WaitForService(address url.URL) {
|
||||||
|
// Wait for podman to be ready
|
||||||
|
var conn net.Conn
|
||||||
|
var err error
|
||||||
|
for i := 1; i <= 5; i++ {
|
||||||
|
conn, err = net.Dial("tcp", address.Host)
|
||||||
|
if err != nil {
|
||||||
|
// Podman not available yet...
|
||||||
|
time.Sleep(time.Duration(i) * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
|
|
@ -122,22 +122,6 @@ var _ = Describe("podman system service", func() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// WaitForService blocks, waiting for some service listening on given host:port
|
|
||||||
func WaitForService(address url.URL) {
|
|
||||||
// Wait for podman to be ready
|
|
||||||
var conn net.Conn
|
|
||||||
var err error
|
|
||||||
for i := 1; i <= 5; i++ {
|
|
||||||
conn, err = net.Dial("tcp", address.Host)
|
|
||||||
if err != nil {
|
|
||||||
// Podman not available yet...
|
|
||||||
time.Sleep(time.Duration(i) * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// randomPort leans on the go net library to find an available port...
|
// randomPort leans on the go net library to find an available port...
|
||||||
func randomPort() string {
|
func randomPort() string {
|
||||||
port, err := utils.GetRandomPort()
|
port, err := utils.GetRandomPort()
|
||||||
|
|
Loading…
Reference in New Issue