Merge pull request #12372 from Luap99/syslog-netavark

Make sure netavark output is logged to the syslog
This commit is contained in:
OpenShift Merge Robot 2021-11-22 16:39:12 +01:00 committed by GitHub
commit bfc929efc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 9 deletions

View File

@ -3,6 +3,7 @@ package netavark
import (
"encoding/json"
"errors"
"io"
"os"
"os/exec"
"strconv"
@ -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()
@ -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
@ -95,7 +122,9 @@ 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)
}
@ -103,7 +132,9 @@ func execNetavark(binary string, args []string, stdin, result interface{}) error
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) {

View File

@ -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
@ -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.
@ -122,6 +130,7 @@ func NewNetworkInterface(conf InitConfig) (types.ContainerNetwork, error) {
defaultSubnet: defaultNet,
isMachine: conf.IsMachine,
lock: lock,
syslog: conf.Syslog,
}
return n, nil

View File

@ -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)
@ -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

View File

@ -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() {
@ -109,6 +113,8 @@ var _ = Describe("run netavark", func() {
netns.UnmountNS(netNSContainer)
netNSContainer.Close()
_ = os.Unsetenv("NETAVARK_FW")
})
It("test basic setup", func() {

View File

@ -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 {

View File

@ -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
@ -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")

View File

@ -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 {