Merge pull request #2104 from devimc/topic/virtcontainers/fcAgentLogs

virtcontainers: set agent's logs vsock port
This commit is contained in:
GabyCT 2019-10-07 13:23:37 -05:00 committed by GitHub
commit 238f3cec56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 32 deletions

4
Gopkg.lock generated
View File

@ -397,7 +397,7 @@
revision = "8cba5a8e5f2816f26f9dc34b8ea968279a5a76eb" revision = "8cba5a8e5f2816f26f9dc34b8ea968279a5a76eb"
[[projects]] [[projects]]
digest = "1:54e0385cece7064d8afd967e0987e52cd8b261c8c7e22d84e8b25719d7379e74" digest = "1:903bfb87f41dc18a533d327b5b03fd2f562f34deafcbd0db93d4be3fa8d6099c"
name = "github.com/kata-containers/agent" name = "github.com/kata-containers/agent"
packages = [ packages = [
"pkg/types", "pkg/types",
@ -405,7 +405,7 @@
"protocols/grpc", "protocols/grpc",
] ]
pruneopts = "NUT" pruneopts = "NUT"
revision = "3ffb7ca1067565a45ee9fbfcb109eb85e7e899af" revision = "32c87e75c2e4c014961f104c3c59b87f2aee3384"
[[projects]] [[projects]]
branch = "master" branch = "master"

View File

@ -52,7 +52,7 @@
[[constraint]] [[constraint]]
name = "github.com/kata-containers/agent" name = "github.com/kata-containers/agent"
revision = "3ffb7ca1067565a45ee9fbfcb109eb85e7e899af" revision = "32c87e75c2e4c014961f104c3c59b87f2aee3384"
[[constraint]] [[constraint]]
name = "github.com/containerd/cri-containerd" name = "github.com/containerd/cri-containerd"

View File

@ -27,9 +27,9 @@ import (
) )
const ( const (
unixSocketScheme = "unix" UnixSocketScheme = "unix"
vsockSocketScheme = "vsock" VSockSocketScheme = "vsock"
hybridVSockScheme = "hvsock" HybridVSockScheme = "hvsock"
) )
var defaultDialTimeout = 15 * time.Second var defaultDialTimeout = 15 * time.Second
@ -142,7 +142,7 @@ func parse(sock string) (string, *url.URL, error) {
var grpcAddr string var grpcAddr string
// validate more // validate more
switch addr.Scheme { switch addr.Scheme {
case vsockSocketScheme: case VSockSocketScheme:
if addr.Hostname() == "" || addr.Port() == "" || addr.Path != "" { if addr.Hostname() == "" || addr.Port() == "" || addr.Path != "" {
return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid vsock scheme: %s", sock) return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid vsock scheme: %s", sock)
} }
@ -152,19 +152,19 @@ func parse(sock string) (string, *url.URL, error) {
if _, err := strconv.ParseUint(addr.Port(), 10, 32); err != nil { if _, err := strconv.ParseUint(addr.Port(), 10, 32); err != nil {
return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid vsock port: %s", sock) return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid vsock port: %s", sock)
} }
grpcAddr = vsockSocketScheme + ":" + addr.Host grpcAddr = VSockSocketScheme + ":" + addr.Host
case unixSocketScheme: case UnixSocketScheme:
fallthrough fallthrough
case "": case "":
if (addr.Host == "" && addr.Path == "") || addr.Port() != "" { if (addr.Host == "" && addr.Path == "") || addr.Port() != "" {
return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid unix scheme: %s", sock) return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid unix scheme: %s", sock)
} }
if addr.Host == "" { if addr.Host == "" {
grpcAddr = unixSocketScheme + ":///" + addr.Path grpcAddr = UnixSocketScheme + ":///" + addr.Path
} else { } else {
grpcAddr = unixSocketScheme + ":///" + addr.Host + "/" + addr.Path grpcAddr = UnixSocketScheme + ":///" + addr.Host + "/" + addr.Path
} }
case hybridVSockScheme: case HybridVSockScheme:
if addr.Path == "" { if addr.Path == "" {
return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid hybrid vsock scheme: %s", sock) return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid hybrid vsock scheme: %s", sock)
} }
@ -178,7 +178,7 @@ func parse(sock string) (string, *url.URL, error) {
return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid hybrid vsock port %s: %v", sock, err) return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid hybrid vsock port %s: %v", sock, err)
} }
hybridVSockPort = uint32(port) hybridVSockPort = uint32(port)
grpcAddr = hybridVSockScheme + ":" + hvsocket[0] grpcAddr = HybridVSockScheme + ":" + hvsocket[0]
default: default:
return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid scheme: %s", sock) return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid scheme: %s", sock)
} }
@ -209,11 +209,11 @@ func heartBeat(session *yamux.Session) {
func agentDialer(addr *url.URL, enableYamux bool) dialer { func agentDialer(addr *url.URL, enableYamux bool) dialer {
var d dialer var d dialer
switch addr.Scheme { switch addr.Scheme {
case vsockSocketScheme: case VSockSocketScheme:
d = vsockDialer d = vsockDialer
case hybridVSockScheme: case HybridVSockScheme:
d = hybridVSockDialer d = HybridVSockDialer
case unixSocketScheme: case UnixSocketScheme:
fallthrough fallthrough
default: default:
d = unixDialer d = unixDialer
@ -281,7 +281,7 @@ func parseGrpcVsockAddr(sock string) (uint32, uint32, error) {
if len(sp) != 3 { if len(sp) != 3 {
return 0, 0, grpcStatus.Errorf(codes.InvalidArgument, "Invalid vsock address: %s", sock) return 0, 0, grpcStatus.Errorf(codes.InvalidArgument, "Invalid vsock address: %s", sock)
} }
if sp[0] != vsockSocketScheme { if sp[0] != VSockSocketScheme {
return 0, 0, grpcStatus.Errorf(codes.InvalidArgument, "Invalid vsock URL scheme: %s", sp[0]) return 0, 0, grpcStatus.Errorf(codes.InvalidArgument, "Invalid vsock URL scheme: %s", sp[0])
} }
@ -297,16 +297,26 @@ func parseGrpcVsockAddr(sock string) (uint32, uint32, error) {
return uint32(cid), uint32(port), nil return uint32(cid), uint32(port), nil
} }
func parseGrpcHybridVSockAddr(sock string) (string, error) { func parseGrpcHybridVSockAddr(sock string) (string, uint32, error) {
sp := strings.Split(sock, ":") sp := strings.Split(sock, ":")
if len(sp) != 2 { // scheme and host are required
return "", grpcStatus.Errorf(codes.InvalidArgument, "Invalid hybrid vsock address: %s", sock) if len(sp) < 2 {
return "", 0, grpcStatus.Errorf(codes.InvalidArgument, "Invalid hybrid vsock address: %s", sock)
} }
if sp[0] != hybridVSockScheme { if sp[0] != HybridVSockScheme {
return "", grpcStatus.Errorf(codes.InvalidArgument, "Invalid hybrid vsock URL scheme: %s", sock) return "", 0, grpcStatus.Errorf(codes.InvalidArgument, "Invalid hybrid vsock URL scheme: %s", sock)
} }
return sp[1], nil port := uint32(0)
// the third is the port
if len(sp) == 3 {
p, err := strconv.ParseUint(sp[2], 10, 32)
if err == nil {
port = uint32(p)
}
}
return sp[1], port, nil
} }
// This would bypass the grpc dialer backoff strategy and handle dial timeout // This would bypass the grpc dialer backoff strategy and handle dial timeout
@ -371,8 +381,9 @@ func vsockDialer(sock string, timeout time.Duration) (net.Conn, error) {
return commonDialer(timeout, dialFunc, timeoutErr) return commonDialer(timeout, dialFunc, timeoutErr)
} }
func hybridVSockDialer(sock string, timeout time.Duration) (net.Conn, error) { // HybridVSockDialer dials to a hybrid virtio socket
udsPath, err := parseGrpcHybridVSockAddr(sock) func HybridVSockDialer(sock string, timeout time.Duration) (net.Conn, error) {
udsPath, port, err := parseGrpcHybridVSockAddr(sock)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -382,10 +393,16 @@ func hybridVSockDialer(sock string, timeout time.Duration) (net.Conn, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if port == 0 {
// use the port read at parse()
port = hybridVSockPort
}
// Once the connection is opened, the following command MUST BE sent, // Once the connection is opened, the following command MUST BE sent,
// the hypervisor needs to know the port number where the agent is listening in order to // the hypervisor needs to know the port number where the agent is listening in order to
// create the connection // create the connection
if _, err = conn.Write([]byte(fmt.Sprintf("CONNECT %d\n", hybridVSockPort))); err != nil { if _, err = conn.Write([]byte(fmt.Sprintf("CONNECT %d\n", port))); err != nil {
conn.Close() conn.Close()
return nil, err return nil, err
} }

View File

@ -21,6 +21,7 @@ import (
httptransport "github.com/go-openapi/runtime/client" httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt" "github.com/go-openapi/strfmt"
kataclient "github.com/kata-containers/agent/protocols/client"
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api" persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
"github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client" "github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client"
models "github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client/models" models "github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client/models"
@ -83,6 +84,9 @@ var fcKernelParams = append(commonVirtioblkKernelRootParams, []Param{
// Firecracker doesn't support ACPI // Firecracker doesn't support ACPI
// Fix kernel error "ACPI BIOS Error (bug)" // Fix kernel error "ACPI BIOS Error (bug)"
{"acpi", "off"}, {"acpi", "off"},
// Tell agent where to send the logs
{"agent.log_vport", fmt.Sprintf("%d", vSockLogsPort)},
}...) }...)
func (s vmmState) String() string { func (s vmmState) String() string {
@ -977,11 +981,8 @@ func (fc *firecracker) hotplugRemoveDevice(devInfo interface{}, devType deviceTy
// getSandboxConsole builds the path of the console where we can read // getSandboxConsole builds the path of the console where we can read
// logs coming from the sandbox. // logs coming from the sandbox.
//
// we can get logs from firecracker itself; WIP on enabling. Who needs
// logs when you're just hacking?
func (fc *firecracker) getSandboxConsole(id string) (string, error) { func (fc *firecracker) getSandboxConsole(id string) (string, error) {
return "", nil return fmt.Sprintf("%s://%s:%d", kataclient.HybridVSockScheme, filepath.Join(fc.jailerRoot, defaultHybridVSocketName), vSockLogsPort), nil
} }
func (fc *firecracker) disconnect() { func (fc *firecracker) disconnect() {

View File

@ -69,6 +69,10 @@ const (
// CAP_NET_BIND_SERVICE capability may bind to these port numbers. // CAP_NET_BIND_SERVICE capability may bind to these port numbers.
vSockPort = 1024 vSockPort = 1024
// Port where the agent will send the logs. Logs are sent through the vsock in cases
// where the hypervisor has no console.sock, i.e firecracker
vSockLogsPort = 1025
// MinHypervisorMemory is the minimum memory required for a VM. // MinHypervisorMemory is the minimum memory required for a VM.
MinHypervisorMemory = 256 MinHypervisorMemory = 256
) )

View File

@ -11,7 +11,9 @@ import (
"io" "io"
"net" "net"
"path/filepath" "path/filepath"
"strings"
kataclient "github.com/kata-containers/agent/protocols/client"
"github.com/kata-containers/runtime/virtcontainers/store" "github.com/kata-containers/runtime/virtcontainers/store"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -241,7 +243,8 @@ func (p *proxyBuiltin) start(params proxyParams) (int, string, error) {
// For firecracker, it hasn't support the console watching and it's consoleURL // For firecracker, it hasn't support the console watching and it's consoleURL
// will be set empty. // will be set empty.
if params.debug && params.consoleURL != "" { // TODO: add support for hybrid vsocks, see https://github.com/kata-containers/runtime/issues/2098
if params.debug && params.consoleURL != "" && !strings.HasPrefix(params.consoleURL, kataclient.HybridVSockScheme) {
err := p.watchConsole(buildinProxyConsoleProto, params.consoleURL, params.logger) err := p.watchConsole(buildinProxyConsoleProto, params.consoleURL, params.logger)
if err != nil { if err != nil {
p.sandboxID = "" p.sandboxID = ""