virtcontainers: Start network monitor from virtcontainers

This patch enables the code responsible for starting and stopping
the network monitor.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2018-09-05 09:50:16 -07:00
parent 29e2fa0fed
commit 1406d99aba
5 changed files with 231 additions and 0 deletions

96
virtcontainers/netmon.go Normal file
View File

@ -0,0 +1,96 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"fmt"
"os/exec"
"syscall"
"github.com/sirupsen/logrus"
)
// NetmonConfig is the structure providing specific configuration
// for the network monitor.
type NetmonConfig struct {
Path string
Debug bool
Enable bool
}
// netmonParams is the structure providing specific parameters needed
// for the execution of the network monitor binary.
type netmonParams struct {
netmonPath string
debug bool
logLevel string
runtime string
sandboxID string
}
func netmonLogger() *logrus.Entry {
return virtLog.WithField("subsystem", "netmon")
}
func prepareNetMonParams(params netmonParams) ([]string, error) {
if params.netmonPath == "" {
return []string{}, fmt.Errorf("Netmon path is empty")
}
if params.runtime == "" {
return []string{}, fmt.Errorf("Netmon runtime path is empty")
}
if params.sandboxID == "" {
return []string{}, fmt.Errorf("Netmon sandbox ID is empty")
}
args := []string{params.netmonPath,
"-r", params.runtime,
"-s", params.sandboxID,
}
if params.debug {
args = append(args, "-d")
}
if params.logLevel != "" {
args = append(args, []string{"-log", params.logLevel}...)
}
return args, nil
}
func startNetmon(params netmonParams) (int, error) {
args, err := prepareNetMonParams(params)
if err != nil {
return -1, err
}
cmd := exec.Command(args[0], args[1:]...)
if err := cmd.Start(); err != nil {
return -1, err
}
return cmd.Process.Pid, nil
}
func stopNetmon(pid int) error {
if pid <= 0 {
return nil
}
sig := syscall.SIGKILL
netmonLogger().WithFields(
logrus.Fields{
"netmon-pid": pid,
"netmon-signal": sig,
}).Info("Stopping netmon")
if err := syscall.Kill(pid, sig); err != nil && err != syscall.ESRCH {
return err
}
return nil
}

View File

@ -0,0 +1,61 @@
// Copyright (c) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
const (
testNetmonPath = "/foo/bar/netmon"
testRuntimePath = "/foo/bar/runtime"
)
func TestNetmonLogger(t *testing.T) {
got := netmonLogger()
expected := virtLog.WithField("subsystem", "netmon")
assert.True(t, reflect.DeepEqual(expected, got),
"Got %+v\nExpected %+v", got, expected)
}
func TestPrepareNetMonParams(t *testing.T) {
// Empty netmon path
params := netmonParams{}
got, err := prepareNetMonParams(params)
assert.NotNil(t, err)
assert.Equal(t, got, []string{})
// Empty runtime path
params.netmonPath = testNetmonPath
got, err = prepareNetMonParams(params)
assert.NotNil(t, err)
assert.Equal(t, got, []string{})
// Empty sandbox ID
params.runtime = testRuntimePath
got, err = prepareNetMonParams(params)
assert.NotNil(t, err)
assert.Equal(t, got, []string{})
// Successful case
params.sandboxID = testSandboxID
got, err = prepareNetMonParams(params)
assert.Nil(t, err)
expected := []string{testNetmonPath,
"-r", testRuntimePath,
"-s", testSandboxID}
assert.True(t, reflect.DeepEqual(expected, got),
"Got %+v\nExpected %+v", got, expected)
}
func TestStopNetmon(t *testing.T) {
pid := -1
err := stopNetmon(pid)
assert.Nil(t, err)
}

View File

@ -142,6 +142,7 @@ type NetworkInterfacePair struct {
type NetworkConfig struct { type NetworkConfig struct {
NetNSPath string NetNSPath string
NetNsCreated bool NetNsCreated bool
NetmonConfig NetmonConfig
InterworkingModel NetInterworkingModel InterworkingModel NetInterworkingModel
} }
@ -474,6 +475,7 @@ type NetworkNamespace struct {
NetNsPath string NetNsPath string
NetNsCreated bool NetNsCreated bool
Endpoints []Endpoint Endpoints []Endpoint
NetmonPID int
} }
// TypedJSONEndpoint is used as an intermediate representation for // TypedJSONEndpoint is used as an intermediate representation for

View File

@ -961,6 +961,40 @@ func (s *Sandbox) Delete() error {
return s.storage.deleteSandboxResources(s.id, nil) return s.storage.deleteSandboxResources(s.id, nil)
} }
func (s *Sandbox) startNetworkMonitor() error {
span, _ := s.trace("startNetworkMonitor")
defer span.Finish()
binPath, err := os.Executable()
if err != nil {
return err
}
logLevel := "info"
if s.config.NetworkConfig.NetmonConfig.Debug {
logLevel = "debug"
}
params := netmonParams{
netmonPath: s.config.NetworkConfig.NetmonConfig.Path,
debug: s.config.NetworkConfig.NetmonConfig.Debug,
logLevel: logLevel,
runtime: binPath,
sandboxID: s.id,
}
return s.network.run(s.networkNS.NetNsPath, func() error {
pid, err := startNetmon(params)
if err != nil {
return err
}
s.networkNS.NetmonPID = pid
return nil
})
}
func (s *Sandbox) createNetwork() error { func (s *Sandbox) createNetwork() error {
span, _ := s.trace("createNetwork") span, _ := s.trace("createNetwork")
defer span.Finish() defer span.Finish()
@ -983,6 +1017,12 @@ func (s *Sandbox) createNetwork() error {
} }
} }
if s.config.NetworkConfig.NetmonConfig.Enable {
if err := s.startNetworkMonitor(); err != nil {
return err
}
}
// Store the network // Store the network
return s.storage.storeSandboxNetwork(s.id, s.networkNS) return s.storage.storeSandboxNetwork(s.id, s.networkNS)
} }
@ -991,6 +1031,12 @@ func (s *Sandbox) removeNetwork() error {
span, _ := s.trace("removeNetwork") span, _ := s.trace("removeNetwork")
defer span.Finish() defer span.Finish()
if s.config.NetworkConfig.NetmonConfig.Enable {
if err := stopNetmon(s.networkNS.NetmonPID); err != nil {
return err
}
}
// In case there is a factory, the network has been handled through // In case there is a factory, the network has been handled through
// some API calls to hotplug some interfaces and routes. This means // some API calls to hotplug some interfaces and routes. This means
// the removal of the network should follow the same logic. // the removal of the network should follow the same logic.

View File

@ -11,6 +11,7 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"reflect" "reflect"
"sync" "sync"
@ -23,6 +24,7 @@ import (
"github.com/kata-containers/runtime/virtcontainers/device/drivers" "github.com/kata-containers/runtime/virtcontainers/device/drivers"
"github.com/kata-containers/runtime/virtcontainers/device/manager" "github.com/kata-containers/runtime/virtcontainers/device/manager"
"github.com/kata-containers/runtime/virtcontainers/pkg/annotations" "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
"golang.org/x/sys/unix"
) )
func newHypervisorConfig(kernelParams []Param, hParams []Param) HypervisorConfig { func newHypervisorConfig(kernelParams []Param, hParams []Param) HypervisorConfig {
@ -1722,3 +1724,27 @@ func TestGetNetNs(t *testing.T) {
netNs = s.GetNetNs() netNs = s.GetNetNs()
assert.Equal(t, netNs, expected) assert.Equal(t, netNs, expected)
} }
func TestStartNetworkMonitor(t *testing.T) {
trueBinPath, err := exec.LookPath("true")
assert.Nil(t, err)
assert.NotEmpty(t, trueBinPath)
s := &Sandbox{
id: testSandboxID,
config: &SandboxConfig{
NetworkConfig: NetworkConfig{
NetmonConfig: NetmonConfig{
Path: trueBinPath,
},
},
},
network: &defNetwork{},
networkNS: NetworkNamespace{
NetNsPath: fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid()),
},
}
err = s.startNetworkMonitor()
assert.Nil(t, err)
}