Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure netavark output is logged to the syslog #12372

Merged
merged 2 commits into from
Nov 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions libpod/network/netavark/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package netavark
import (
"encoding/json"
"errors"
"io"
"os"
"os/exec"
"strconv"
Expand Down Expand Up @@ -45,6 +46,15 @@ func newNetavarkError(msg string, err error) error {
}
}

// Type to implement io.Writer interface
// This will write the logrus at info level
type logrusNetavarkWriter struct{}

func (l *logrusNetavarkWriter) Write(b []byte) (int, error) {
logrus.Info("netavark: ", string(b))
return len(b), nil
}

// getRustLogEnv returns the RUST_LOG env var based on the current logrus level
func getRustLogEnv() string {
level := logrus.GetLevel().String()
Expand All @@ -63,26 +73,43 @@ func getRustLogEnv() string {
// used to marshal the netavark output into it. This can be nil.
// All errors return by this function should be of the type netavarkError
// to provide a helpful error message.
func execNetavark(binary string, args []string, stdin, result interface{}) error {
func (n *netavarkNetwork) execNetavark(args []string, stdin, result interface{}) error {
stdinR, stdinW, err := os.Pipe()
if err != nil {
return newNetavarkError("failed to create stdin pipe", err)
}
defer stdinR.Close()
stdinWClosed := false
defer func() {
stdinR.Close()
if !stdinWClosed {
stdinW.Close()
}
}()

stdoutR, stdoutW, err := os.Pipe()
if err != nil {
return newNetavarkError("failed to create stdout pipe", err)
}
defer stdoutR.Close()
defer stdoutW.Close()
stdoutWClosed := false
defer func() {
stdoutR.Close()
if !stdoutWClosed {
stdoutW.Close()
}
}()

cmd := exec.Command(binary, args...)
// connect stderr to the podman stderr for logging
var logWriter io.Writer = os.Stderr
if n.syslog {
// connect logrus to stderr as well so that the logs will be written to the syslog as well
logWriter = io.MultiWriter(logWriter, &logrusNetavarkWriter{})
}

cmd := exec.Command(n.netavarkBinary, args...)
// connect the pipes to stdin and stdout
cmd.Stdin = stdinR
cmd.Stdout = stdoutW
// connect stderr to the podman stderr for logging
cmd.Stderr = os.Stderr
cmd.Stderr = logWriter
// set the netavark log level to the same as the podman
cmd.Env = append(os.Environ(), getRustLogEnv())
// if we run with debug log level lets also set RUST_BACKTRACE=1 so we can get the full stack trace in case of panics
Expand All @@ -95,15 +122,19 @@ func execNetavark(binary string, args []string, stdin, result interface{}) error
return newNetavarkError("failed to start process", err)
}
err = json.NewEncoder(stdinW).Encode(stdin)
// we have to close stdinW so netavark gets the EOF and does not hang forever
stdinW.Close()
stdinWClosed = true
if err != nil {
return newNetavarkError("failed to encode stdin data", err)
}

dec := json.NewDecoder(stdoutR)

err = cmd.Wait()
// we have to close stdoutW so we can decode the json without hanging forever
stdoutW.Close()
stdoutWClosed = true
if err != nil {
exitError := &exec.ExitError{}
if errors.As(err, &exitError) {
Expand Down
9 changes: 9 additions & 0 deletions libpod/network/netavark/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ type netavarkNetwork struct {
// isMachine describes whenever podman runs in a podman machine environment.
isMachine bool

// syslog describes whenever the netavark debbug output should be log to the syslog as well.
// This will use logrus to do so, make sure logrus is set up to log to the syslog.
syslog bool

// lock is a internal lock for critical operations
lock lockfile.Locker

Expand Down Expand Up @@ -68,6 +72,10 @@ type InitConfig struct {

// LockFile is the path to lock file.
LockFile string

// Syslog describes whenever the netavark debbug output should be log to the syslog as well.
// This will use logrus to do so, make sure logrus is set up to log to the syslog.
Syslog bool
}

// NewNetworkInterface creates the ContainerNetwork interface for the netavark backend.
Expand Down Expand Up @@ -122,6 +130,7 @@ func NewNetworkInterface(conf InitConfig) (types.ContainerNetwork, error) {
defaultSubnet: defaultNet,
isMachine: conf.IsMachine,
lock: lock,
syslog: conf.Syslog,
}

return n, nil
Expand Down
4 changes: 2 additions & 2 deletions libpod/network/netavark/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (n *netavarkNetwork) Setup(namespacePath string, options types.SetupOptions
}

result := map[string]types.StatusBlock{}
err = execNetavark(n.netavarkBinary, []string{"setup", namespacePath}, netavarkOpts, &result)
err = n.execNetavark([]string{"setup", namespacePath}, netavarkOpts, &result)

if len(result) != len(options.Networks) {
logrus.Errorf("unexpected netavark result: %v", result)
Expand Down Expand Up @@ -86,7 +86,7 @@ func (n *netavarkNetwork) Teardown(namespacePath string, options types.TeardownO
return errors.Wrap(err, "failed to convert net opts")
}

retErr := execNetavark(n.netavarkBinary, []string{"teardown", namespacePath}, netavarkOpts, nil)
retErr := n.execNetavark([]string{"teardown", namespacePath}, netavarkOpts, nil)

// when netavark returned an error we still free the used ips
// otherwise we could end up in a state where block the ips forever
Expand Down
6 changes: 6 additions & 0 deletions libpod/network/netavark/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ var _ = Describe("run netavark", func() {
if err != nil {
Fail("Failed to create netns")
}

// Force iptables driver, firewalld is broken inside the extra
// namespace because it still connects to firewalld on the host.
_ = os.Setenv("NETAVARK_FW", "iptables")
})

JustBeforeEach(func() {
Expand All @@ -109,6 +113,8 @@ var _ = Describe("run netavark", func() {

netns.UnmountNS(netNSContainer)
netNSContainer.Close()

_ = os.Unsetenv("NETAVARK_FW")
})

It("test basic setup", func() {
Expand Down
8 changes: 8 additions & 0 deletions libpod/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,14 @@ func WithEnableSDNotify() RuntimeOption {
}
}

// WithSyslog sets a runtime option so we know that we have to log to the syslog as well
func WithSyslog() RuntimeOption {
return func(rt *Runtime) error {
rt.syslog = true
return nil
}
}

// WithRuntimeFlags adds the global runtime flags to the container config
func WithRuntimeFlags(runtimeFlags []string) RuntimeOption {
return func(rt *Runtime) error {
Expand Down
6 changes: 6 additions & 0 deletions libpod/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ type Runtime struct {
libimageEventsShutdown chan bool
lockManager lock.Manager

// syslog describes whenever logrus should log to the syslog as well.
// Note that the syslog hook will be enabled early in cmd/podman/syslog_linux.go
// This bool is just needed so that we can set it for netavark interface.
syslog bool

// doRenumber indicates that the runtime should perform a lock renumber
// during initialization.
// Once the runtime has been initialized and returned, this variable is
Expand Down Expand Up @@ -517,6 +522,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
DefaultSubnet: runtime.config.Network.DefaultSubnet,
IsMachine: runtime.config.Engine.MachineEnabled,
LockFile: filepath.Join(runtime.config.Network.NetworkConfigDir, "netavark.lock"),
Syslog: runtime.syslog,
})
if err != nil {
return errors.Wrapf(err, "could not create network interface")
Expand Down
5 changes: 5 additions & 0 deletions pkg/domain/infra/runtime_libpod.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
options = append(options, libpod.WithRegistriesConf(cfg.RegistriesConf))
}

// no need to handle the error, it will return false anyway
if syslog, _ := fs.GetBool("syslog"); syslog {
options = append(options, libpod.WithSyslog())
}

// TODO flag to set CNI plugins dir?

if !opts.withFDS {
Expand Down