diff --git a/src/agent/src/rpc.rs b/src/agent/src/rpc.rs index 4af13be90a..cab703b439 100644 --- a/src/agent/src/rpc.rs +++ b/src/agent/src/rpc.rs @@ -1989,6 +1989,38 @@ fn do_copy_file(req: &CopyFileRequest) -> Result<()> { std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(req.dir_mode))?; + let sflag = stat::SFlag::from_bits_truncate(req.file_mode); + + if sflag.contains(stat::SFlag::S_IFDIR) { + fs::create_dir(path.clone()).or_else(|e| { + if e.kind() != std::io::ErrorKind::AlreadyExists { + return Err(e); + } + Ok(()) + })?; + + std::fs::set_permissions(path.clone(), std::fs::Permissions::from_mode(req.file_mode))?; + + unistd::chown( + &path, + Some(Uid::from_raw(req.uid as u32)), + Some(Gid::from_raw(req.gid as u32)), + )?; + + return Ok(()); + } + + if sflag.contains(stat::SFlag::S_IFLNK) { + let src = PathBuf::from(String::from_utf8(req.data.clone()).unwrap()); + + unistd::symlinkat(&src, None, &path)?; + let path_str = CString::new(path.to_str().unwrap())?; + let ret = unsafe { libc::lchown(path_str.as_ptr(), req.uid as u32, req.gid as u32) }; + Errno::result(ret).map(drop)?; + + return Ok(()); + } + let mut tmpfile = path.clone(); tmpfile.set_extension("tmp"); diff --git a/src/runtime/cmd/kata-runtime/kata-check_amd64.go b/src/runtime/cmd/kata-runtime/kata-check_amd64.go index 09f5bfe179..77d6b6ce78 100644 --- a/src/runtime/cmd/kata-runtime/kata-check_amd64.go +++ b/src/runtime/cmd/kata-runtime/kata-check_amd64.go @@ -304,6 +304,8 @@ func archHostCanCreateVMContainer(hypervisorType vc.HypervisorType) error { return kvmIsUsable() case "acrn": return acrnIsUsable() + case "remote": + return nil case "mock": return nil default: diff --git a/src/runtime/cmd/kata-runtime/kata-check_arm64.go b/src/runtime/cmd/kata-runtime/kata-check_arm64.go index 66d81c71c3..933c977609 100644 --- a/src/runtime/cmd/kata-runtime/kata-check_arm64.go +++ b/src/runtime/cmd/kata-runtime/kata-check_arm64.go @@ -86,6 +86,9 @@ func checkKVMExtensions() error { } func archHostCanCreateVMContainer(hypervisorType vc.HypervisorType) error { + if hypervisorType == "remote" { + return nil + } if err := kvmIsUsable(); err != nil { return err } diff --git a/src/runtime/cmd/kata-runtime/kata-check_ppc64le.go b/src/runtime/cmd/kata-runtime/kata-check_ppc64le.go index 7c5e7453ac..de34f9614f 100644 --- a/src/runtime/cmd/kata-runtime/kata-check_ppc64le.go +++ b/src/runtime/cmd/kata-runtime/kata-check_ppc64le.go @@ -61,6 +61,9 @@ func setCPUtype(hypervisorType vc.HypervisorType) error { } func archHostCanCreateVMContainer(hypervisorType vc.HypervisorType) error { + if hypervisorType == "remote" { + return nil + } return kvmIsUsable() } diff --git a/src/runtime/cmd/kata-runtime/kata-check_s390x.go b/src/runtime/cmd/kata-runtime/kata-check_s390x.go index c9b1578b43..8ee51b7e5c 100644 --- a/src/runtime/cmd/kata-runtime/kata-check_s390x.go +++ b/src/runtime/cmd/kata-runtime/kata-check_s390x.go @@ -55,6 +55,9 @@ func kvmIsUsable() error { } func archHostCanCreateVMContainer(hypervisorType vc.HypervisorType) error { + if hypervisorType == "remote" { + return nil + } return kvmIsUsable() } diff --git a/src/runtime/hack/update-generated-hypervisor-proto.sh b/src/runtime/hack/update-generated-hypervisor-proto.sh new file mode 100755 index 0000000000..df32974044 --- /dev/null +++ b/src/runtime/hack/update-generated-hypervisor-proto.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# (C) Copyright IBM Corp. 2022. +# SPDX-License-Identifier: Apache-2.0 + +set -o errexit -o pipefail -o nounset + +cd "$(dirname "${BASH_SOURCE[0]}")/.." + +protoc --gogottrpc_out=protocols/hypervisor \ + --gogottrpc_opt=plugins=ttrpc+fieldpath,paths=source_relative \ + -Iprotocols/hypervisor \ + -I../libs/protocols/protos/gogo/protobuf \ + protocols/hypervisor/hypervisor.proto diff --git a/src/runtime/pkg/katautils/config.go b/src/runtime/pkg/katautils/config.go index 1ec4993754..77582f2c34 100644 --- a/src/runtime/pkg/katautils/config.go +++ b/src/runtime/pkg/katautils/config.go @@ -52,6 +52,7 @@ const ( qemuHypervisorTableType = "qemu" acrnHypervisorTableType = "acrn" dragonballHypervisorTableType = "dragonball" + remoteHypervisorTableType = "remote" // the maximum amount of PCI bridges that can be cold plugged in a VM maxPCIBridges uint32 = 5 @@ -106,6 +107,7 @@ type hypervisor struct { GuestPreAttestationSecretType string `toml:"guest_pre_attestation_secret_type"` SEVCertChainPath string `toml:"sev_cert_chain"` BlockDeviceAIO string `toml:"block_device_aio"` + RemoteHypervisorSocket string `toml:"remote_hypervisor_socket"` HypervisorPathList []string `toml:"valid_hypervisor_paths"` JailerPathList []string `toml:"valid_jailer_paths"` CtlPathList []string `toml:"valid_ctlpaths"` @@ -137,6 +139,7 @@ type hypervisor struct { PCIeRootPort uint32 `toml:"pcie_root_port"` GuestPreAttestationGRPCTimeout uint32 `toml:"guest_pre_attestation_grpc_timeout"` SEVGuestPolicy uint32 `toml:"sev_guest_policy"` + RemoteHypervisorTimeout uint32 `toml:"remote_hypervisor_timeout"` NumVCPUs int32 `toml:"default_vcpus"` BlockDeviceCacheSet bool `toml:"block_device_cache_set"` BlockDeviceCacheDirect bool `toml:"block_device_cache_direct"` @@ -1052,6 +1055,17 @@ func newDragonballHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) { }, nil } +func newRemoteHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) { + + return vc.HypervisorConfig{ + RemoteHypervisorSocket: h.RemoteHypervisorSocket, + RemoteHypervisorTimeout: h.RemoteHypervisorTimeout, + + // No valid value so avoid to append block device to list in kata_agent.appendDevices + BlockDeviceDriver: "dummy", + }, nil +} + func newFactoryConfig(f factory) (oci.FactoryConfig, error) { if f.TemplatePath == "" { f.TemplatePath = defaultTemplatePath @@ -1088,6 +1102,9 @@ func updateRuntimeConfigHypervisor(configPath string, tomlConf tomlConfig, confi case dragonballHypervisorTableType: config.HypervisorType = vc.DragonballHypervisor hConfig, err = newDragonballHypervisorConfig(hypervisor) + case remoteHypervisorTableType: + config.HypervisorType = vc.RemoteHypervisor + hConfig, err = newRemoteHypervisorConfig(hypervisor) } if err != nil { @@ -1638,6 +1655,11 @@ func checkFactoryConfig(config oci.RuntimeConfig) error { // checkHypervisorConfig performs basic "sanity checks" on the hypervisor // config. func checkHypervisorConfig(config vc.HypervisorConfig) error { + + if config.RemoteHypervisorSocket != "" { + return nil + } + type image struct { path string initrd bool diff --git a/src/runtime/protocols/hypervisor/hypervisor.pb.go b/src/runtime/protocols/hypervisor/hypervisor.pb.go new file mode 100644 index 0000000000..ba3b7d7786 --- /dev/null +++ b/src/runtime/protocols/hypervisor/hypervisor.pb.go @@ -0,0 +1,1848 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: hypervisor.proto + +package hypervisor + +import ( + context "context" + fmt "fmt" + github_com_containerd_ttrpc "github.com/containerd/ttrpc" + proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type VersionRequest struct { + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *VersionRequest) Reset() { *m = VersionRequest{} } +func (*VersionRequest) ProtoMessage() {} +func (*VersionRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_7b34fdb27c05edf8, []int{0} +} +func (m *VersionRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *VersionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_VersionRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *VersionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_VersionRequest.Merge(m, src) +} +func (m *VersionRequest) XXX_Size() int { + return m.Size() +} +func (m *VersionRequest) XXX_DiscardUnknown() { + xxx_messageInfo_VersionRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_VersionRequest proto.InternalMessageInfo + +type VersionResponse struct { + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *VersionResponse) Reset() { *m = VersionResponse{} } +func (*VersionResponse) ProtoMessage() {} +func (*VersionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_7b34fdb27c05edf8, []int{1} +} +func (m *VersionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *VersionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_VersionResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *VersionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_VersionResponse.Merge(m, src) +} +func (m *VersionResponse) XXX_Size() int { + return m.Size() +} +func (m *VersionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_VersionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_VersionResponse proto.InternalMessageInfo + +type CreateVMRequest struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Annotations map[string]string `protobuf:"bytes,2,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + NetworkNamespacePath string `protobuf:"bytes,3,opt,name=networkNamespacePath,proto3" json:"networkNamespacePath,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateVMRequest) Reset() { *m = CreateVMRequest{} } +func (*CreateVMRequest) ProtoMessage() {} +func (*CreateVMRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_7b34fdb27c05edf8, []int{2} +} +func (m *CreateVMRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateVMRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateVMRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateVMRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateVMRequest.Merge(m, src) +} +func (m *CreateVMRequest) XXX_Size() int { + return m.Size() +} +func (m *CreateVMRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateVMRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateVMRequest proto.InternalMessageInfo + +type CreateVMResponse struct { + AgentSocketPath string `protobuf:"bytes,1,opt,name=agentSocketPath,proto3" json:"agentSocketPath,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateVMResponse) Reset() { *m = CreateVMResponse{} } +func (*CreateVMResponse) ProtoMessage() {} +func (*CreateVMResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_7b34fdb27c05edf8, []int{3} +} +func (m *CreateVMResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CreateVMResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CreateVMResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CreateVMResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateVMResponse.Merge(m, src) +} +func (m *CreateVMResponse) XXX_Size() int { + return m.Size() +} +func (m *CreateVMResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CreateVMResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateVMResponse proto.InternalMessageInfo + +type StartVMRequest struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StartVMRequest) Reset() { *m = StartVMRequest{} } +func (*StartVMRequest) ProtoMessage() {} +func (*StartVMRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_7b34fdb27c05edf8, []int{4} +} +func (m *StartVMRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StartVMRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StartVMRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StartVMRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StartVMRequest.Merge(m, src) +} +func (m *StartVMRequest) XXX_Size() int { + return m.Size() +} +func (m *StartVMRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StartVMRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_StartVMRequest proto.InternalMessageInfo + +type StartVMResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StartVMResponse) Reset() { *m = StartVMResponse{} } +func (*StartVMResponse) ProtoMessage() {} +func (*StartVMResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_7b34fdb27c05edf8, []int{5} +} +func (m *StartVMResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StartVMResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StartVMResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StartVMResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StartVMResponse.Merge(m, src) +} +func (m *StartVMResponse) XXX_Size() int { + return m.Size() +} +func (m *StartVMResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StartVMResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_StartVMResponse proto.InternalMessageInfo + +type StopVMRequest struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StopVMRequest) Reset() { *m = StopVMRequest{} } +func (*StopVMRequest) ProtoMessage() {} +func (*StopVMRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_7b34fdb27c05edf8, []int{6} +} +func (m *StopVMRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StopVMRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StopVMRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StopVMRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StopVMRequest.Merge(m, src) +} +func (m *StopVMRequest) XXX_Size() int { + return m.Size() +} +func (m *StopVMRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StopVMRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_StopVMRequest proto.InternalMessageInfo + +type StopVMResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StopVMResponse) Reset() { *m = StopVMResponse{} } +func (*StopVMResponse) ProtoMessage() {} +func (*StopVMResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_7b34fdb27c05edf8, []int{7} +} +func (m *StopVMResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StopVMResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StopVMResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StopVMResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StopVMResponse.Merge(m, src) +} +func (m *StopVMResponse) XXX_Size() int { + return m.Size() +} +func (m *StopVMResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StopVMResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_StopVMResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*VersionRequest)(nil), "hypervisor.VersionRequest") + proto.RegisterType((*VersionResponse)(nil), "hypervisor.VersionResponse") + proto.RegisterType((*CreateVMRequest)(nil), "hypervisor.CreateVMRequest") + proto.RegisterMapType((map[string]string)(nil), "hypervisor.CreateVMRequest.AnnotationsEntry") + proto.RegisterType((*CreateVMResponse)(nil), "hypervisor.CreateVMResponse") + proto.RegisterType((*StartVMRequest)(nil), "hypervisor.StartVMRequest") + proto.RegisterType((*StartVMResponse)(nil), "hypervisor.StartVMResponse") + proto.RegisterType((*StopVMRequest)(nil), "hypervisor.StopVMRequest") + proto.RegisterType((*StopVMResponse)(nil), "hypervisor.StopVMResponse") +} + +func init() { proto.RegisterFile("hypervisor.proto", fileDescriptor_7b34fdb27c05edf8) } + +var fileDescriptor_7b34fdb27c05edf8 = []byte{ + // 390 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0xcf, 0x4e, 0xf2, 0x40, + 0x14, 0xc5, 0x3b, 0x25, 0x1f, 0x7c, 0x5e, 0x22, 0xad, 0x13, 0x16, 0xb5, 0x98, 0x4a, 0xba, 0x22, + 0x6a, 0x58, 0xe0, 0xc6, 0x18, 0x63, 0x82, 0x7f, 0xa2, 0x1b, 0x89, 0x81, 0x84, 0xfd, 0x08, 0x13, + 0x69, 0xd0, 0x99, 0x3a, 0x1d, 0x30, 0xec, 0x7c, 0x18, 0x1f, 0x86, 0xa5, 0x4b, 0x97, 0xd2, 0xc4, + 0xf7, 0x30, 0xb4, 0xa5, 0xb4, 0x4d, 0x61, 0xd7, 0xb9, 0xf7, 0xcc, 0xe9, 0xef, 0x9e, 0xdc, 0x01, + 0x7d, 0x34, 0x73, 0xa9, 0x98, 0x3a, 0x1e, 0x17, 0x4d, 0x57, 0x70, 0xc9, 0x31, 0xac, 0x2b, 0xf6, + 0x11, 0x54, 0xfa, 0x54, 0x78, 0x0e, 0x67, 0x5d, 0xfa, 0x36, 0xa1, 0x9e, 0xc4, 0x06, 0x94, 0xa6, + 0x61, 0xc5, 0x40, 0x75, 0xd4, 0xd8, 0xe9, 0xae, 0x8e, 0xf6, 0x31, 0x68, 0xb1, 0xd6, 0x73, 0x39, + 0xf3, 0xe8, 0x16, 0xf1, 0x2f, 0x02, 0xed, 0x5a, 0x50, 0x22, 0x69, 0xff, 0x61, 0x65, 0x5d, 0x01, + 0xd5, 0x19, 0x46, 0x42, 0xd5, 0x19, 0xe2, 0x0e, 0x94, 0x09, 0x63, 0x5c, 0x12, 0xe9, 0x70, 0xe6, + 0x19, 0x6a, 0xbd, 0xd0, 0x28, 0xb7, 0x4e, 0x9a, 0x09, 0xe0, 0x8c, 0x43, 0xb3, 0xbd, 0x96, 0xdf, + 0x32, 0x29, 0x66, 0xdd, 0xa4, 0x01, 0x6e, 0x41, 0x95, 0x51, 0xf9, 0xce, 0xc5, 0xb8, 0x43, 0x5e, + 0xa9, 0xe7, 0x92, 0x01, 0x7d, 0x24, 0x72, 0x64, 0x14, 0x82, 0x3f, 0xe6, 0xf6, 0xcc, 0x4b, 0xd0, + 0xb3, 0xa6, 0x58, 0x87, 0xc2, 0x98, 0xce, 0x22, 0xd0, 0xe5, 0x27, 0xae, 0xc2, 0xbf, 0x29, 0x79, + 0x99, 0x50, 0x43, 0x0d, 0x6a, 0xe1, 0xe1, 0x5c, 0x3d, 0x43, 0xf6, 0x05, 0xe8, 0x6b, 0xc8, 0x28, + 0x95, 0x06, 0x68, 0xe4, 0x99, 0x32, 0xd9, 0xe3, 0x83, 0x31, 0x95, 0x01, 0x42, 0xe8, 0x95, 0x2d, + 0xdb, 0x75, 0xa8, 0xf4, 0x24, 0x11, 0x72, 0x63, 0x46, 0xf6, 0x1e, 0x68, 0xb1, 0x22, 0xb4, 0xb7, + 0x0f, 0x61, 0xb7, 0x27, 0xb9, 0xbb, 0xf9, 0x8e, 0xbe, 0x74, 0x0d, 0x05, 0xe1, 0x95, 0xd6, 0xa7, + 0x0a, 0x70, 0x1f, 0xc7, 0x8a, 0xef, 0xe0, 0xff, 0x0a, 0x1a, 0xd7, 0xb6, 0xe4, 0x6d, 0x1e, 0xe4, + 0x37, 0x23, 0x10, 0x05, 0xdf, 0x40, 0x29, 0xa2, 0xc3, 0x66, 0x52, 0x9a, 0x1e, 0xca, 0xac, 0xe5, + 0xf6, 0x62, 0x97, 0x36, 0x14, 0x43, 0x5e, 0xbc, 0x9f, 0x16, 0x26, 0x86, 0x34, 0xcd, 0xbc, 0x56, + 0x12, 0x24, 0xda, 0xcd, 0x34, 0x48, 0x7a, 0xb9, 0xd3, 0x20, 0x99, 0x65, 0xb6, 0x95, 0x2b, 0x63, + 0xbe, 0xb0, 0x94, 0xef, 0x85, 0xa5, 0x7c, 0xf8, 0x16, 0x9a, 0xfb, 0x16, 0xfa, 0xf2, 0x2d, 0xf4, + 0xe3, 0x5b, 0xe8, 0xa9, 0x18, 0x3c, 0x9d, 0xd3, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xc0, + 0xa3, 0xa4, 0x4e, 0x03, 0x00, 0x00, +} + +func (m *VersionRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *VersionRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *VersionRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintHypervisor(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *VersionResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *VersionResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *VersionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintHypervisor(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CreateVMRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CreateVMRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateVMRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.NetworkNamespacePath) > 0 { + i -= len(m.NetworkNamespacePath) + copy(dAtA[i:], m.NetworkNamespacePath) + i = encodeVarintHypervisor(dAtA, i, uint64(len(m.NetworkNamespacePath))) + i-- + dAtA[i] = 0x1a + } + if len(m.Annotations) > 0 { + for k := range m.Annotations { + v := m.Annotations[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintHypervisor(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintHypervisor(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintHypervisor(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = encodeVarintHypervisor(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CreateVMResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CreateVMResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CreateVMResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.AgentSocketPath) > 0 { + i -= len(m.AgentSocketPath) + copy(dAtA[i:], m.AgentSocketPath) + i = encodeVarintHypervisor(dAtA, i, uint64(len(m.AgentSocketPath))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StartVMRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StartVMRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StartVMRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = encodeVarintHypervisor(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StartVMResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StartVMResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StartVMResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + return len(dAtA) - i, nil +} + +func (m *StopVMRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StopVMRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StopVMRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = encodeVarintHypervisor(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StopVMResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StopVMResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StopVMResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + return len(dAtA) - i, nil +} + +func encodeVarintHypervisor(dAtA []byte, offset int, v uint64) int { + offset -= sovHypervisor(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *VersionRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Version) + if l > 0 { + n += 1 + l + sovHypervisor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *VersionResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Version) + if l > 0 { + n += 1 + l + sovHypervisor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *CreateVMRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + sovHypervisor(uint64(l)) + } + if len(m.Annotations) > 0 { + for k, v := range m.Annotations { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovHypervisor(uint64(len(k))) + 1 + len(v) + sovHypervisor(uint64(len(v))) + n += mapEntrySize + 1 + sovHypervisor(uint64(mapEntrySize)) + } + } + l = len(m.NetworkNamespacePath) + if l > 0 { + n += 1 + l + sovHypervisor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *CreateVMResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.AgentSocketPath) + if l > 0 { + n += 1 + l + sovHypervisor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *StartVMRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + sovHypervisor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *StartVMResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *StopVMRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + sovHypervisor(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *StopVMResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovHypervisor(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozHypervisor(x uint64) (n int) { + return sovHypervisor(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *VersionRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&VersionRequest{`, + `Version:` + fmt.Sprintf("%v", this.Version) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *VersionResponse) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&VersionResponse{`, + `Version:` + fmt.Sprintf("%v", this.Version) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *CreateVMRequest) String() string { + if this == nil { + return "nil" + } + keysForAnnotations := make([]string, 0, len(this.Annotations)) + for k, _ := range this.Annotations { + keysForAnnotations = append(keysForAnnotations, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForAnnotations) + mapStringForAnnotations := "map[string]string{" + for _, k := range keysForAnnotations { + mapStringForAnnotations += fmt.Sprintf("%v: %v,", k, this.Annotations[k]) + } + mapStringForAnnotations += "}" + s := strings.Join([]string{`&CreateVMRequest{`, + `Id:` + fmt.Sprintf("%v", this.Id) + `,`, + `Annotations:` + mapStringForAnnotations + `,`, + `NetworkNamespacePath:` + fmt.Sprintf("%v", this.NetworkNamespacePath) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *CreateVMResponse) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CreateVMResponse{`, + `AgentSocketPath:` + fmt.Sprintf("%v", this.AgentSocketPath) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *StartVMRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&StartVMRequest{`, + `Id:` + fmt.Sprintf("%v", this.Id) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *StartVMResponse) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&StartVMResponse{`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *StopVMRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&StopVMRequest{`, + `Id:` + fmt.Sprintf("%v", this.Id) + `,`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func (this *StopVMResponse) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&StopVMResponse{`, + `XXX_unrecognized:` + fmt.Sprintf("%v", this.XXX_unrecognized) + `,`, + `}`, + }, "") + return s +} +func valueToStringHypervisor(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} + +type HypervisorService interface { + CreateVM(ctx context.Context, req *CreateVMRequest) (*CreateVMResponse, error) + StartVM(ctx context.Context, req *StartVMRequest) (*StartVMResponse, error) + StopVM(ctx context.Context, req *StopVMRequest) (*StopVMResponse, error) + Version(ctx context.Context, req *VersionRequest) (*VersionResponse, error) +} + +func RegisterHypervisorService(srv *github_com_containerd_ttrpc.Server, svc HypervisorService) { + srv.Register("hypervisor.Hypervisor", map[string]github_com_containerd_ttrpc.Method{ + "CreateVM": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CreateVMRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.CreateVM(ctx, &req) + }, + "StartVM": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StartVMRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.StartVM(ctx, &req) + }, + "StopVM": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StopVMRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.StopVM(ctx, &req) + }, + "Version": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req VersionRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.Version(ctx, &req) + }, + }) +} + +type hypervisorClient struct { + client *github_com_containerd_ttrpc.Client +} + +func NewHypervisorClient(client *github_com_containerd_ttrpc.Client) HypervisorService { + return &hypervisorClient{ + client: client, + } +} + +func (c *hypervisorClient) CreateVM(ctx context.Context, req *CreateVMRequest) (*CreateVMResponse, error) { + var resp CreateVMResponse + if err := c.client.Call(ctx, "hypervisor.Hypervisor", "CreateVM", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *hypervisorClient) StartVM(ctx context.Context, req *StartVMRequest) (*StartVMResponse, error) { + var resp StartVMResponse + if err := c.client.Call(ctx, "hypervisor.Hypervisor", "StartVM", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *hypervisorClient) StopVM(ctx context.Context, req *StopVMRequest) (*StopVMResponse, error) { + var resp StopVMResponse + if err := c.client.Call(ctx, "hypervisor.Hypervisor", "StopVM", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *hypervisorClient) Version(ctx context.Context, req *VersionRequest) (*VersionResponse, error) { + var resp VersionResponse + if err := c.client.Call(ctx, "hypervisor.Hypervisor", "Version", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} +func (m *VersionRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: VersionRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: VersionRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHypervisor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHypervisor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipHypervisor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHypervisor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *VersionResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: VersionResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: VersionResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHypervisor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHypervisor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipHypervisor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHypervisor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CreateVMRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CreateVMRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CreateVMRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHypervisor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHypervisor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthHypervisor + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthHypervisor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Annotations == nil { + m.Annotations = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthHypervisor + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthHypervisor + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthHypervisor + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthHypervisor + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipHypervisor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHypervisor + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Annotations[mapkey] = mapvalue + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NetworkNamespacePath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHypervisor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHypervisor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NetworkNamespacePath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipHypervisor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHypervisor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CreateVMResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CreateVMResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CreateVMResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AgentSocketPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHypervisor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHypervisor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AgentSocketPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipHypervisor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHypervisor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StartVMRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StartVMRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StartVMRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHypervisor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHypervisor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipHypervisor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHypervisor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StartVMResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StartVMResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StartVMResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipHypervisor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHypervisor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StopVMRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StopVMRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StopVMRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHypervisor + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHypervisor + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipHypervisor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHypervisor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StopVMResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHypervisor + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StopVMResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StopVMResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipHypervisor(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthHypervisor + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipHypervisor(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowHypervisor + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowHypervisor + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowHypervisor + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthHypervisor + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupHypervisor + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthHypervisor + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthHypervisor = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowHypervisor = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupHypervisor = fmt.Errorf("proto: unexpected end of group") +) diff --git a/src/runtime/protocols/hypervisor/hypervisor.proto b/src/runtime/protocols/hypervisor/hypervisor.proto new file mode 100644 index 0000000000..0342e8ba4f --- /dev/null +++ b/src/runtime/protocols/hypervisor/hypervisor.proto @@ -0,0 +1,46 @@ +// (C) Copyright IBM Corp. 2022. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package hypervisor; + +service Hypervisor { + rpc CreateVM(CreateVMRequest) returns (CreateVMResponse) {} + rpc StartVM(StartVMRequest) returns (StartVMResponse) {} + rpc StopVM(StopVMRequest) returns (StopVMResponse) {} + rpc Version(VersionRequest) returns (VersionResponse) {} +} + + +message VersionRequest { + string version = 1; +} + +message VersionResponse { + string version = 1; +} + +message CreateVMRequest { + string id = 1; + map annotations = 2; + string networkNamespacePath = 3; +} + +message CreateVMResponse { + string agentSocketPath = 1; +} + +message StartVMRequest { + string id = 1; +} + +message StartVMResponse { +} + +message StopVMRequest { + string id = 1; +} + +message StopVMResponse { +} diff --git a/src/runtime/virtcontainers/fs_share_linux.go b/src/runtime/virtcontainers/fs_share_linux.go index 2e80bfcc96..e7296bf4e7 100644 --- a/src/runtime/virtcontainers/fs_share_linux.go +++ b/src/runtime/virtcontainers/fs_share_linux.go @@ -11,6 +11,7 @@ import ( "context" "encoding/hex" "fmt" + "io/fs" "os" "path/filepath" "sync" @@ -239,23 +240,43 @@ func (f *FilesystemShare) ShareFile(ctx context.Context, c *Container, m *Mount) if !caps.IsFsSharingSupported() { f.Logger().Debug("filesystem sharing is not supported, files will be copied") - fileInfo, err := os.Stat(m.Source) - if err != nil { - return nil, err + var ignored bool + srcRoot := filepath.Clean(m.Source) + + walk := func(srcPath string, d fs.DirEntry, err error) error { + + if err != nil { + return err + } + + info, err := d.Info() + if err != nil { + return err + } + + if !(info.Mode().IsRegular() || info.Mode().IsDir() || (info.Mode()&os.ModeSymlink) == os.ModeSymlink) { + f.Logger().WithField("ignored-file", srcPath).Debug("Ignoring non-regular file as FS sharing not supported") + if srcPath == srcRoot { + // Ignore the mount if this is not a regular file (excludes socket, device, ...) as it cannot be handled by + // a simple copy. But this should not be treated as an error, only as a limitation. + ignored = true + return filepath.SkipDir + } + return nil + } + + dstPath := filepath.Join(guestPath, srcPath[len(srcRoot):]) + + return f.sandbox.agent.copyFile(ctx, srcPath, dstPath) } - // Ignore the mount if this is not a regular file (excludes - // directory, socket, device, ...) as it cannot be handled by - // a simple copy. But this should not be treated as an error, - // only as a limitation. - if !fileInfo.Mode().IsRegular() { - f.Logger().WithField("ignored-file", m.Source).Debug("Ignoring non-regular file as FS sharing not supported") + if err := filepath.WalkDir(srcRoot, walk); err != nil { + c.Logger().WithField("failed-file", m.Source).Debugf("failed to copy file to sandbox: %v", err) + return nil, err + } + if ignored { return nil, nil } - - if err := f.sandbox.agent.copyFile(ctx, m.Source, guestPath); err != nil { - return nil, err - } } else { // These mounts are created in the shared dir mountDest := filepath.Join(getMountPath(f.sandbox.ID()), filename) diff --git a/src/runtime/virtcontainers/hypervisor.go b/src/runtime/virtcontainers/hypervisor.go index 0fb1a49278..d6f3b5086b 100644 --- a/src/runtime/virtcontainers/hypervisor.go +++ b/src/runtime/virtcontainers/hypervisor.go @@ -49,6 +49,9 @@ const ( // DragonballHypervisor is the Dragonball hypervisor. DragonballHypervisor HypervisorType = "dragonball" + // RemoteHypervisor is the Remote hypervisor. + RemoteHypervisor HypervisorType = "remote" + // MockHypervisor is a mock hypervisor for testing purposes MockHypervisor HypervisorType = "mock" @@ -175,6 +178,9 @@ func (hType *HypervisorType) Set(value string) error { case "dragonball": *hType = DragonballHypervisor return nil + case "remote": + *hType = RemoteHypervisor + return nil case "mock": *hType = MockHypervisor return nil @@ -194,6 +200,8 @@ func (hType *HypervisorType) String() string { return string(AcrnHypervisor) case ClhHypervisor: return string(ClhHypervisor) + case RemoteHypervisor: + return string(RemoteHypervisor) case MockHypervisor: return string(MockHypervisor) default: @@ -279,6 +287,9 @@ type HypervisorConfig struct { GuestPreAttestationSecretType string SEVCertChainPath string BlockDeviceAIO string + RemoteHypervisorSocket string + SandboxName string + SandboxNamespace string JailerPathList []string EntropySourceList []string VirtioFSDaemonList []string @@ -316,6 +327,7 @@ type HypervisorConfig struct { SEVGuestPolicy uint32 PCIeRootPort uint32 NumVCPUs uint32 + RemoteHypervisorTimeout uint32 IOMMUPlatform bool EnableIOThreads bool Debug bool diff --git a/src/runtime/virtcontainers/hypervisor_config_darwin.go b/src/runtime/virtcontainers/hypervisor_config_darwin.go index e074d59ea6..e0dafb912a 100644 --- a/src/runtime/virtcontainers/hypervisor_config_darwin.go +++ b/src/runtime/virtcontainers/hypervisor_config_darwin.go @@ -11,6 +11,10 @@ import ( func validateHypervisorConfig(conf *HypervisorConfig) error { + if conf.RemoteHypervisorSocket != "" { + return nil + } + if conf.KernelPath == "" { return fmt.Errorf("Missing kernel path") } diff --git a/src/runtime/virtcontainers/hypervisor_config_linux.go b/src/runtime/virtcontainers/hypervisor_config_linux.go index f1f20d3151..4a2d33e202 100644 --- a/src/runtime/virtcontainers/hypervisor_config_linux.go +++ b/src/runtime/virtcontainers/hypervisor_config_linux.go @@ -13,6 +13,10 @@ import ( func validateHypervisorConfig(conf *HypervisorConfig) error { + if conf.RemoteHypervisorSocket != "" { + return nil + } + if conf.KernelPath == "" { return fmt.Errorf("Missing kernel path") } diff --git a/src/runtime/virtcontainers/hypervisor_linux.go b/src/runtime/virtcontainers/hypervisor_linux.go index 3d81c1ada0..bff4d96df1 100644 --- a/src/runtime/virtcontainers/hypervisor_linux.go +++ b/src/runtime/virtcontainers/hypervisor_linux.go @@ -39,6 +39,8 @@ func NewHypervisor(hType HypervisorType) (Hypervisor, error) { return &cloudHypervisor{}, nil case DragonballHypervisor: return &mockHypervisor{}, nil + case RemoteHypervisor: + return &remoteHypervisor{}, nil case MockHypervisor: return &mockHypervisor{}, nil default: diff --git a/src/runtime/virtcontainers/kata_agent.go b/src/runtime/virtcontainers/kata_agent.go index f649e63b60..275433f62f 100644 --- a/src/runtime/virtcontainers/kata_agent.go +++ b/src/runtime/virtcontainers/kata_agent.go @@ -10,6 +10,7 @@ import ( "encoding/json" "errors" "fmt" + "io/ioutil" "os" "path/filepath" "strconv" @@ -73,9 +74,13 @@ const ( kernelParamDebugConsoleVPortValue = "1026" ) +type customRequestTimeoutKeyType struct{} + var ( checkRequestTimeout = 30 * time.Second defaultRequestTimeout = 60 * time.Second + remoteRequestTimeout = 300 * time.Second + customRequestTimeoutKey = customRequestTimeoutKeyType(struct{}{}) errorMissingOCISpec = errors.New("Missing OCI specification") defaultKataHostSharedDir = "/run/kata-containers/shared/sandboxes/" defaultKataGuestSharedDir = "/run/kata-containers/shared/containers/" @@ -362,6 +367,8 @@ func (k *kataAgent) agentURL() (string, error) { return s.String(), nil case types.HybridVSock: return s.String(), nil + case types.RemoteSock: + return s.String(), nil case types.MockHybridVSock: return s.String(), nil default: @@ -412,6 +419,7 @@ func (k *kataAgent) configure(ctx context.Context, h Hypervisor, id, sharePath s if err != nil { return err } + case types.RemoteSock: case types.MockHybridVSock: default: return types.ErrInvalidConfigType @@ -716,30 +724,38 @@ func (k *kataAgent) startSandbox(ctx context.Context, sandbox *Sandbox) error { return err } - // Check grpc server is serving - if err = k.check(ctx); err != nil { - return err - } + var kmodules []*grpc.KernelModule - // Setup network interfaces and routes - interfaces, routes, neighs, err := generateVCNetworkStructures(ctx, sandbox.network) - if err != nil { - return err - } - if err = k.updateInterfaces(ctx, interfaces); err != nil { - return err - } - if _, err = k.updateRoutes(ctx, routes); err != nil { - return err - } - if err = k.addARPNeighbors(ctx, neighs); err != nil { - return err + if sandbox.config.HypervisorType == RemoteHypervisor { + ctx = context.WithValue(ctx, customRequestTimeoutKey, remoteRequestTimeout) + } else { + // TODO: Enable the following features for remote hypervisor if necessary + + // Check grpc server is serving + if err = k.check(ctx); err != nil { + return err + } + + // Setup network interfaces and routes + interfaces, routes, neighs, err := generateVCNetworkStructures(ctx, sandbox.network) + if err != nil { + return err + } + if err = k.updateInterfaces(ctx, interfaces); err != nil { + return err + } + if _, err = k.updateRoutes(ctx, routes); err != nil { + return err + } + if err = k.addARPNeighbors(ctx, neighs); err != nil { + return err + } + + kmodules = setupKernelModules(k.kmodules) } storages := setupStorages(ctx, sandbox) - kmodules := setupKernelModules(k.kmodules) - req := &grpc.CreateSandboxRequest{ Hostname: hostname, Dns: dns, @@ -1118,7 +1134,7 @@ func (k *kataAgent) appendDevices(deviceList []*grpc.Device, c *Container) []*gr kataDevice = k.appendVfioDevice(dev, device, c) } - if kataDevice == nil { + if kataDevice == nil || kataDevice.Type == "" { continue } @@ -1993,7 +2009,12 @@ func (k *kataAgent) getReqContext(ctx context.Context, reqName string) (newCtx c case grpcCheckRequest: newCtx, cancel = context.WithTimeout(ctx, checkRequestTimeout) default: - newCtx, cancel = context.WithTimeout(ctx, defaultRequestTimeout) + var requestTimeout = defaultRequestTimeout + + if timeout, ok := ctx.Value(customRequestTimeoutKey).(time.Duration); ok { + requestTimeout = timeout + } + newCtx, cancel = context.WithTimeout(ctx, requestTimeout) } return newCtx, cancel @@ -2099,40 +2120,57 @@ func (k *kataAgent) setGuestDateTime(ctx context.Context, tv time.Time) error { func (k *kataAgent) copyFile(ctx context.Context, src, dst string) error { var st unix.Stat_t - err := unix.Stat(src, &st) + err := unix.Lstat(src, &st) if err != nil { return fmt.Errorf("Could not get file %s information: %v", src, err) } - b, err := os.ReadFile(src) - if err != nil { - return fmt.Errorf("Could not read file %s: %v", src, err) + cpReq := &grpc.CopyFileRequest{ + Path: dst, + DirMode: uint32(DirMode), + FileMode: st.Mode, + Uid: int32(st.Uid), + Gid: int32(st.Gid), } - fileSize := int64(len(b)) + var b []byte + + switch sflag := st.Mode & unix.S_IFMT; sflag { + case unix.S_IFREG: + var err error + // TODO: Support incrementail file copying instead of loading whole file into memory + b, err = ioutil.ReadFile(src) + if err != nil { + return fmt.Errorf("Could not read file %s: %v", src, err) + } + cpReq.FileSize = int64(len(b)) + + case unix.S_IFDIR: + + case unix.S_IFLNK: + symlink, err := os.Readlink(src) + if err != nil { + return fmt.Errorf("Could not read symlink %s: %v", src, err) + } + cpReq.Data = []byte(symlink) + + default: + return fmt.Errorf("Unsupported file type: %o", sflag) + } k.Logger().WithFields(logrus.Fields{ "source": src, "dest": dst, }).Debugf("Copying file from host to guest") - cpReq := &grpc.CopyFileRequest{ - Path: dst, - DirMode: uint32(DirMode), - FileMode: uint32(st.Mode), - FileSize: fileSize, - Uid: int32(st.Uid), - Gid: int32(st.Gid), - } - // Handle the special case where the file is empty - if fileSize == 0 { - _, err = k.sendReq(ctx, cpReq) + if cpReq.FileSize == 0 { + _, err := k.sendReq(ctx, cpReq) return err } // Copy file by parts if it's needed - remainingBytes := fileSize + remainingBytes := cpReq.FileSize offset := int64(0) for remainingBytes > 0 { bytesToCopy := int64(len(b)) diff --git a/src/runtime/virtcontainers/pkg/agent/protocols/client/client.go b/src/runtime/virtcontainers/pkg/agent/protocols/client/client.go index 5728c89331..5aee043ab1 100644 --- a/src/runtime/virtcontainers/pkg/agent/protocols/client/client.go +++ b/src/runtime/virtcontainers/pkg/agent/protocols/client/client.go @@ -34,6 +34,7 @@ import ( const ( VSockSocketScheme = "vsock" HybridVSockScheme = "hvsock" + RemoteSockScheme = "remote" MockHybridVSockScheme = "mock" ) @@ -237,6 +238,11 @@ func parse(sock string) (string, *url.URL, error) { } hybridVSockPort = uint32(port) grpcAddr = HybridVSockScheme + ":" + hvsocket[0] + case RemoteSockScheme: + if addr.Host != "" { + return "", nil, grpcStatus.Errorf(codes.InvalidArgument, "Invalid remote sock scheme: host address must be empty: %s", sock) + } + grpcAddr = RemoteSockScheme + ":" + addr.Path // just for tests use. case MockHybridVSockScheme: if addr.Path == "" { @@ -257,6 +263,8 @@ func agentDialer(addr *url.URL) dialer { return VsockDialer case HybridVSockScheme: return HybridVSockDialer + case RemoteSockScheme: + return RemoteSockDialer case MockHybridVSockScheme: return MockHybridVSockDialer default: @@ -437,6 +445,31 @@ func HybridVSockDialer(sock string, timeout time.Duration) (net.Conn, error) { return commonDialer(timeout, dialFunc, timeoutErr) } +// RemoteSockDialer dials to an agent in a remote hypervisor sandbox +func RemoteSockDialer(sock string, timeout time.Duration) (net.Conn, error) { + + s := strings.Split(sock, ":") + if !(len(s) == 2 && s[0] == RemoteSockScheme) { + return nil, fmt.Errorf("failed to parse remote sock: %q", sock) + } + socketPath := s[1] + + logrus.Printf("Dialing remote sock: %q %q", socketPath, sock) + + dialFunc := func() (net.Conn, error) { + conn, err := net.Dial("unix", socketPath) + if err != nil { + logrus.Errorf("failed to dial remote sock %q: %v", socketPath, err) + return nil, err + } + return conn, nil + } + + timeoutErr := grpcStatus.Errorf(codes.DeadlineExceeded, "timed out connecting to remote sock: %s", socketPath) + + return commonDialer(timeout, dialFunc, timeoutErr) +} + // just for tests use. func MockHybridVSockDialer(sock string, timeout time.Duration) (net.Conn, error) { sock = strings.TrimPrefix(sock, "mock:") diff --git a/src/runtime/virtcontainers/remote.go b/src/runtime/virtcontainers/remote.go new file mode 100644 index 0000000000..9f1f92bfea --- /dev/null +++ b/src/runtime/virtcontainers/remote.go @@ -0,0 +1,298 @@ +// (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 +} diff --git a/src/runtime/virtcontainers/sandbox.go b/src/runtime/virtcontainers/sandbox.go index cb0d57d632..8122fff5e6 100644 --- a/src/runtime/virtcontainers/sandbox.go +++ b/src/runtime/virtcontainers/sandbox.go @@ -27,6 +27,8 @@ import ( "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + cri "github.com/containerd/containerd/pkg/cri/annotations" + crio "github.com/containers/podman/v4/pkg/annotations" "github.com/kata-containers/kata-containers/src/runtime/pkg/device/api" "github.com/kata-containers/kata-containers/src/runtime/pkg/device/config" "github.com/kata-containers/kata-containers/src/runtime/pkg/device/drivers" @@ -592,6 +594,21 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor return nil, err } + if len(sandboxConfig.Containers) > 0 { + // These values are required by remove hypervisor + for _, a := range []string{cri.SandboxName, crio.SandboxName} { + if value, ok := sandboxConfig.Containers[0].Annotations[a]; ok { + sandboxConfig.HypervisorConfig.SandboxName = value + } + } + + for _, a := range []string{cri.SandboxNamespace, crio.Namespace} { + if value, ok := sandboxConfig.Containers[0].Annotations[a]; ok { + sandboxConfig.HypervisorConfig.SandboxNamespace = value + } + } + } + // store doesn't require hypervisor to be stored immediately if err = s.hypervisor.CreateVM(ctx, s.id, s.network, &sandboxConfig.HypervisorConfig); err != nil { return nil, err diff --git a/src/runtime/virtcontainers/types/sandbox.go b/src/runtime/virtcontainers/types/sandbox.go index 5149b04232..29c909c977 100644 --- a/src/runtime/virtcontainers/types/sandbox.go +++ b/src/runtime/virtcontainers/types/sandbox.go @@ -7,6 +7,7 @@ package types import ( "fmt" + "net" "os" "strings" @@ -37,6 +38,7 @@ const ( HybridVSockScheme = "hvsock" MockHybridVSockScheme = "mock" VSockScheme = "vsock" + RemoteSockScheme = "remote" ) // SandboxState is a sandbox state structure @@ -210,6 +212,16 @@ func (s *HybridVSock) String() string { return fmt.Sprintf("%s://%s:%d", HybridVSockScheme, s.UdsPath, s.Port) } +type RemoteSock struct { + Conn net.Conn + SandboxID string + TunnelSocketPath string +} + +func (s *RemoteSock) String() string { + return fmt.Sprintf("%s://%s", RemoteSockScheme, s.TunnelSocketPath) +} + // MockHybridVSock defines a mock hybrid vsocket for tests only. type MockHybridVSock struct { UdsPath string