Files
kata-containers/src/runtime/virtcontainers/remote.go
Lei Li c3e6b66051 runtime: Support privileged containers in peer pod VM
This patch fixes the issue of running containers
with privileged as true.

See the discussion at this URL for the details.
https://github.com/confidential-containers/cloud-api-adaptor/issues/111

Author:    Lei Li <cdlleili@cn.ibm.com>
Signed-off-by: Yohei Ueda <yohei@jp.ibm.com>
2022-09-09 11:07:34 +09:00

299 lines
7.3 KiB
Go

// (C) Copyright IBM Corp. 2022.
// SPDX-License-Identifier: Apache-2.0
package virtcontainers
import (
"context"
"fmt"
"net"
"os"
"time"
cri "github.com/containerd/containerd/pkg/cri/annotations"
"github.com/containerd/ttrpc"
persistapi "github.com/kata-containers/kata-containers/src/runtime/pkg/hypervisors"
pb "github.com/kata-containers/kata-containers/src/runtime/protocols/hypervisor"
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const defaultMinTimeout = 60
type remoteHypervisor struct {
sandboxID remoteHypervisorSandboxID
agentSocketPath string
config HypervisorConfig
}
type remoteHypervisorSandboxID string
type remoteService struct {
conn net.Conn
client pb.HypervisorService
}
func openRemoteService(socketPath string) (*remoteService, error) {
conn, err := net.Dial("unix", socketPath)
if err != nil {
return nil, fmt.Errorf("failed to connect to remote hypervisor socket: %w", err)
}
ttrpcClient := ttrpc.NewClient(conn)
client := pb.NewHypervisorClient(ttrpcClient)
s := &remoteService{
conn: conn,
client: client,
}
return s, nil
}
func (s *remoteService) Close() error {
return s.conn.Close()
}
func (rh *remoteHypervisor) CreateVM(ctx context.Context, id string, network Network, hypervisorConfig *HypervisorConfig) error {
rh.sandboxID = remoteHypervisorSandboxID(id)
if err := rh.setConfig(hypervisorConfig); err != nil {
return err
}
s, err := openRemoteService(hypervisorConfig.RemoteHypervisorSocket)
if err != nil {
return err
}
defer s.Close()
annotations := map[string]string{}
annotations[cri.SandboxName] = hypervisorConfig.SandboxName
annotations[cri.SandboxNamespace] = hypervisorConfig.SandboxNamespace
req := &pb.CreateVMRequest{
Id: id,
Annotations: annotations,
NetworkNamespacePath: network.NetworkID(),
}
res, err := s.client.CreateVM(context.Background(), req)
if err != nil {
return fmt.Errorf("remote hypervisor call failed: %w", err)
}
if res.AgentSocketPath == "" {
return errors.New("remote hypervisor does not return tunnel socket path")
}
rh.agentSocketPath = res.AgentSocketPath
return nil
}
func (rh *remoteHypervisor) StartVM(ctx context.Context, timeout int) error {
minTimeout := defaultMinTimeout
if rh.config.RemoteHypervisorTimeout > 0 {
minTimeout = int(rh.config.RemoteHypervisorTimeout)
}
if timeout < minTimeout {
timeout = minTimeout
}
s, err := openRemoteService(rh.config.RemoteHypervisorSocket)
if err != nil {
return err
}
defer s.Close()
req := &pb.StartVMRequest{
Id: string(rh.sandboxID),
}
ctx2, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
defer cancel()
logrus.Printf("calling remote hypervisor StartVM (timeout: %d)", timeout)
if _, err := s.client.StartVM(ctx2, req); err != nil {
return fmt.Errorf("remote hypervisor call failed: %w", err)
}
return nil
}
func (rh *remoteHypervisor) AttestVM(ctx context.Context) error {
return nil
}
func (rh *remoteHypervisor) StopVM(ctx context.Context, waitOnly bool) error {
s, err := openRemoteService(rh.config.RemoteHypervisorSocket)
if err != nil {
return err
}
defer s.Close()
req := &pb.StopVMRequest{
Id: string(rh.sandboxID),
}
if _, err := s.client.StopVM(context.Background(), req); err != nil {
return fmt.Errorf("remote hypervisor call failed: %w", err)
}
return nil
}
func (rh *remoteHypervisor) GenerateSocket(id string) (interface{}, error) {
socketPath := rh.agentSocketPath
if len(socketPath) == 0 {
return nil, errors.New("failed to generate remote sock: TunnelSocketPath is not set")
}
remoteSock := types.RemoteSock{
SandboxID: id,
TunnelSocketPath: socketPath,
}
return remoteSock, nil
}
func notImplemented(name string) error {
err := errors.Errorf("%s: not implemented", name)
logrus.Errorf(err.Error())
if tracer, ok := err.(interface{ StackTrace() errors.StackTrace }); ok {
for _, f := range tracer.StackTrace() {
logrus.Errorf("%+s:%d\n", f, f)
}
}
return err
}
func (rh *remoteHypervisor) PauseVM(ctx context.Context) error {
panic(notImplemented("PauseVM"))
}
func (rh *remoteHypervisor) SaveVM() error {
panic(notImplemented("SaveVM"))
}
func (rh *remoteHypervisor) ResumeVM(ctx context.Context) error {
panic(notImplemented("ResumeVM"))
}
func (rh *remoteHypervisor) AddDevice(ctx context.Context, devInfo interface{}, devType DeviceType) error {
// TODO
logrus.Printf("addDevice: deviceType=%v devInfo=%#v", devType, devInfo)
return nil
}
func (rh *remoteHypervisor) HotplugAddDevice(ctx context.Context, devInfo interface{}, devType DeviceType) (interface{}, error) {
logrus.Printf("HotplugAddDevice: devInfo=%#v", devInfo)
return "HotplugAddDevice is not implemented", nil
}
func (rh *remoteHypervisor) HotplugRemoveDevice(ctx context.Context, devInfo interface{}, devType DeviceType) (interface{}, error) {
logrus.Printf("HotplugRemoveDevice: devInfo=%#v", devInfo)
return "HotplugRemoveDevice is not implemented", nil
}
func (rh *remoteHypervisor) ResizeMemory(ctx context.Context, memMB uint32, memoryBlockSizeMB uint32, probe bool) (uint32, MemoryDevice, error) {
// TODO
return memMB, MemoryDevice{}, nil
}
func (rh *remoteHypervisor) GetTotalMemoryMB(ctx context.Context) uint32 {
return rh.config.MemorySize
}
func (rh *remoteHypervisor) ResizeVCPUs(ctx context.Context, vcpus uint32) (uint32, uint32, error) {
// TODO
return vcpus, vcpus, nil
}
func (rh *remoteHypervisor) GetVMConsole(ctx context.Context, sandboxID string) (string, string, error) {
panic(notImplemented("GetVMConsole"))
}
func (rh *remoteHypervisor) Disconnect(ctx context.Context) {
// TODO
panic(notImplemented("Disconnect"))
}
func (rh *remoteHypervisor) Capabilities(ctx context.Context) types.Capabilities {
var caps types.Capabilities
caps.SetBlockDeviceHotplugSupport()
return caps
}
func (rh *remoteHypervisor) HypervisorConfig() HypervisorConfig {
return rh.config
}
func (rh *remoteHypervisor) GetThreadIDs(ctx context.Context) (VcpuThreadIDs, error) {
// TODO
return VcpuThreadIDs{vcpus: make(map[int]int)}, nil
}
func (rh *remoteHypervisor) Cleanup(ctx context.Context) error {
// TODO
return nil
}
func (rh *remoteHypervisor) setConfig(config *HypervisorConfig) error {
// Create a Validator specific for remote hypervisor
rh.config = *config
return nil
}
func (rh *remoteHypervisor) GetPids() []int {
// TODO: meanwhile let's use shim pid as it used by crio to fetch start time
return []int{os.Getpid()}
}
func (rh *remoteHypervisor) GetVirtioFsPid() *int {
panic(notImplemented("GetVirtioFsPid"))
}
func (rh *remoteHypervisor) fromGrpc(ctx context.Context, hypervisorConfig *HypervisorConfig, j []byte) error {
panic(notImplemented("fromGrpc"))
}
func (rh *remoteHypervisor) toGrpc(ctx context.Context) ([]byte, error) {
panic(notImplemented("toGrpc"))
}
func (rh *remoteHypervisor) Check() error {
//TODO
return nil
}
func (rh *remoteHypervisor) Save() persistapi.HypervisorState {
// TODO
// called from Sandbox.dumpHypervisor
return persistapi.HypervisorState{}
}
func (rh *remoteHypervisor) Load(persistapi.HypervisorState) {
// TODO
// called from Sandbox.loadHypervisor
}
func (rh *remoteHypervisor) IsRateLimiterBuiltin() bool {
// TODO
return true
}