virtcontainers: add watchconsole for no_proxy type

For no proxy type, we also need the feature
of watch hypervisor's console to help debug.

Fixes:#1932

Signed-off-by: lifupan <lifupan@gmail.com>
This commit is contained in:
lifupan 2019-08-06 11:54:40 +08:00
parent 00e0aaa6e4
commit 31ddb4d452
5 changed files with 104 additions and 127 deletions

View File

@ -1044,7 +1044,7 @@ func LoadConfiguration(configPath string, ignoreLogging, builtIn bool) (resolved
if config.HypervisorConfig.UseVSock { if config.HypervisorConfig.UseVSock {
kataUtilsLogger.Info("VSOCK supported, configure to not use proxy") kataUtilsLogger.Info("VSOCK supported, configure to not use proxy")
config.ProxyType = vc.NoProxyType config.ProxyType = vc.NoProxyType
config.ProxyConfig = vc.ProxyConfig{} config.ProxyConfig = vc.ProxyConfig{Debug: config.Debug}
} }
config.DisableNewNetNs = tomlConf.Runtime.DisableNewNetNs config.DisableNewNetNs = tomlConf.Runtime.DisableNewNetNs

View File

@ -5,27 +5,12 @@
package virtcontainers package virtcontainers
import ( import "fmt"
"bufio"
"fmt"
"io"
"net"
"github.com/sirupsen/logrus"
)
var buildinProxyConsoleProto = consoleProtoUnix
// This is a kata builtin proxy implementation of the proxy interface. Kata proxy // This is a kata builtin proxy implementation of the proxy interface. Kata proxy
// functionality is implemented inside the virtcontainers library. // functionality is implemented inside the virtcontainers library.
type kataBuiltInProxy struct { type kataBuiltInProxy struct {
sandboxID string proxyBuiltin
conn net.Conn
}
// check if the proxy has watched the vm console.
func (p *kataBuiltInProxy) consoleWatched() bool {
return p.conn != nil
} }
func (p *kataBuiltInProxy) validateParams(params proxyParams) error { func (p *kataBuiltInProxy) validateParams(params proxyParams) error {
@ -33,10 +18,6 @@ func (p *kataBuiltInProxy) validateParams(params proxyParams) error {
return fmt.Errorf("Invalid proxy parameters %+v", params) return fmt.Errorf("Invalid proxy parameters %+v", params)
} }
if params.logger == nil {
return fmt.Errorf("Invalid proxy parameter: proxy logger is not set")
}
return nil return nil
} }
@ -48,76 +29,5 @@ func (p *kataBuiltInProxy) start(params proxyParams) (int, string, error) {
return -1, "", err return -1, "", err
} }
if p.consoleWatched() { return p.proxyBuiltin.start(params)
return -1, "", fmt.Errorf("kata builtin proxy running for sandbox %s", params.id)
}
params.logger.Debug("Starting builtin kata proxy")
p.sandboxID = params.id
if params.debug {
err := p.watchConsole(buildinProxyConsoleProto, params.consoleURL, params.logger)
if err != nil {
p.sandboxID = ""
return -1, "", err
}
}
return params.hid, params.agentURL, nil
}
// stop is the proxy stop implementation for kata builtin proxy.
func (p *kataBuiltInProxy) stop(pid int) error {
if p.conn != nil {
p.conn.Close()
p.conn = nil
p.sandboxID = ""
}
return nil
}
func (p *kataBuiltInProxy) watchConsole(proto, console string, logger *logrus.Entry) (err error) {
var (
scanner *bufio.Scanner
conn net.Conn
)
switch proto {
case consoleProtoUnix:
conn, err = net.Dial("unix", console)
if err != nil {
return err
}
// TODO: add pty console support for kvmtools
case consoleProtoPty:
fallthrough
default:
return fmt.Errorf("unknown console proto %s", proto)
}
p.conn = conn
go func() {
scanner = bufio.NewScanner(conn)
for scanner.Scan() {
logger.WithFields(logrus.Fields{
"sandbox": p.sandboxID,
"vmconsole": scanner.Text(),
}).Debug("reading guest console")
}
if err := scanner.Err(); err != nil {
if err == io.EOF {
logger.Info("console watcher quits")
} else {
logger.WithError(err).WithFields(logrus.Fields{
"console-protocol": proto,
"console-socket": console,
}).Error("Failed to read agent logs")
}
}
}()
return nil
} }

View File

@ -32,12 +32,9 @@ func TestKataBuiltinProxy(t *testing.T) {
params.consoleURL = "foobarconsole" params.consoleURL = "foobarconsole"
err = p.validateParams(params) err = p.validateParams(params)
assert.NotNil(err)
params.logger = logrus.WithField("proxy", params.id)
err = p.validateParams(params)
assert.Nil(err) assert.Nil(err)
params.logger = logrus.WithField("proxy", params.id)
buildinProxyConsoleProto = "foobarproto" buildinProxyConsoleProto = "foobarproto"
_, _, err = p.start(params) _, _, err = p.start(params)
assert.NotNil(err) assert.NotNil(err)

View File

@ -5,10 +5,6 @@
package virtcontainers package virtcontainers
import (
"fmt"
)
// This is the no proxy implementation of the proxy interface. This // This is the no proxy implementation of the proxy interface. This
// is a generic implementation for any case (basically any agent), // is a generic implementation for any case (basically any agent),
// where no actual proxy is needed. This happens when the combination // where no actual proxy is needed. This happens when the combination
@ -20,29 +16,5 @@ import (
// is to provide both shim and runtime the correct URL to connect // is to provide both shim and runtime the correct URL to connect
// directly to the VM. // directly to the VM.
type noProxy struct { type noProxy struct {
} proxyBuiltin
// start is noProxy start implementation for proxy interface.
func (p *noProxy) start(params proxyParams) (int, string, error) {
if params.logger == nil {
return -1, "", fmt.Errorf("proxy logger is not set")
}
params.logger.Debug("No proxy started because of no-proxy implementation")
if params.agentURL == "" {
return -1, "", fmt.Errorf("AgentURL cannot be empty")
}
return params.hid, params.agentURL, nil
}
// stop is noProxy stop implementation for proxy interface.
func (p *noProxy) stop(pid int) error {
return nil
}
// The noproxy doesn't need to watch the vm console, thus return false always.
func (p *noProxy) consoleWatched() bool {
return false
} }

View File

@ -6,13 +6,23 @@
package virtcontainers package virtcontainers
import ( import (
"bufio"
"fmt" "fmt"
"io"
"net"
"path/filepath" "path/filepath"
"github.com/kata-containers/runtime/virtcontainers/store" "github.com/kata-containers/runtime/virtcontainers/store"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var buildinProxyConsoleProto = consoleProtoUnix
type proxyBuiltin struct {
sandboxID string
conn net.Conn
}
// ProxyConfig is a structure storing information needed from any // ProxyConfig is a structure storing information needed from any
// proxy in order to be properly initialized. // proxy in order to be properly initialized.
type ProxyConfig struct { type ProxyConfig struct {
@ -161,3 +171,91 @@ type proxy interface {
//check if the proxy has watched the vm console. //check if the proxy has watched the vm console.
consoleWatched() bool consoleWatched() bool
} }
func (p *proxyBuiltin) watchConsole(proto, console string, logger *logrus.Entry) (err error) {
var (
scanner *bufio.Scanner
conn net.Conn
)
switch proto {
case consoleProtoUnix:
conn, err = net.Dial("unix", console)
if err != nil {
return err
}
// TODO: please see
// https://github.com/kata-containers/runtime/issues/1940.
case consoleProtoPty:
fallthrough
default:
return fmt.Errorf("unknown console proto %s", proto)
}
p.conn = conn
go func() {
scanner = bufio.NewScanner(conn)
for scanner.Scan() {
logger.WithFields(logrus.Fields{
"sandbox": p.sandboxID,
"vmconsole": scanner.Text(),
}).Debug("reading guest console")
}
if err := scanner.Err(); err != nil {
if err == io.EOF {
logger.Info("console watcher quits")
} else {
logger.WithError(err).WithFields(logrus.Fields{
"console-protocol": proto,
"console-socket": console,
}).Error("Failed to read agent logs")
}
}
}()
return nil
}
// check if the proxy has watched the vm console.
func (p *proxyBuiltin) consoleWatched() bool {
return p.conn != nil
}
// start is the proxy start implementation for builtin proxy.
// It starts the console watcher for the guest.
// It returns agentURL to let agent connect directly.
func (p *proxyBuiltin) start(params proxyParams) (int, string, error) {
if params.logger == nil {
return -1, "", fmt.Errorf("Invalid proxy parameter: proxy logger is not set")
}
if p.consoleWatched() {
return -1, "", fmt.Errorf("The console has been watched for sandbox %s", params.id)
}
params.logger.Debug("Start to watch the console")
p.sandboxID = params.id
if params.debug {
err := p.watchConsole(buildinProxyConsoleProto, params.consoleURL, params.logger)
if err != nil {
p.sandboxID = ""
return -1, "", err
}
}
return params.hid, params.agentURL, nil
}
// stop is the proxy stop implementation for builtin proxy.
func (p *proxyBuiltin) stop(pid int) error {
if p.conn != nil {
p.conn.Close()
p.conn = nil
p.sandboxID = ""
}
return nil
}